feat(challenge-md): Parse seed files from md
This commit is contained in:
@ -0,0 +1,23 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`challengeSeed-to-data plugin should have an output to match the snapshot 1`] = `
|
||||||
|
Object {
|
||||||
|
"files": Array [
|
||||||
|
Object {
|
||||||
|
"contents": "function testFunction(arg) {
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
testFunction('hello');
|
||||||
|
",
|
||||||
|
"ext": "js",
|
||||||
|
"head": "console.log('before the test');
|
||||||
|
",
|
||||||
|
"key": "indexjs",
|
||||||
|
"name": "index",
|
||||||
|
"tail": "console.info('after the test');
|
||||||
|
",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`;
|
72
tools/challenge-md-parser/challengeSeed-to-data.js
Normal file
72
tools/challenge-md-parser/challengeSeed-to-data.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
const visit = require('unist-util-visit');
|
||||||
|
const { selectAll, select } = require('hast-util-select');
|
||||||
|
|
||||||
|
const { sectionFilter } = require('./utils');
|
||||||
|
|
||||||
|
const seedRE = /(.+)-seed$/;
|
||||||
|
const headRE = /(.+)-setup$/;
|
||||||
|
const tailRE = /(.+)-teardown$/;
|
||||||
|
|
||||||
|
function defaultFile(lang) {
|
||||||
|
return {
|
||||||
|
key: `index${lang}`,
|
||||||
|
ext: lang,
|
||||||
|
name: 'index',
|
||||||
|
contents: '',
|
||||||
|
head: '',
|
||||||
|
tail: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function createCodeGetter(key, regEx, seeds) {
|
||||||
|
return container => {
|
||||||
|
const {
|
||||||
|
properties: { id }
|
||||||
|
} = container;
|
||||||
|
const lang = id.match(regEx)[1];
|
||||||
|
const code = select('code', container).children[0].value;
|
||||||
|
if (lang in seeds) {
|
||||||
|
seeds[lang] = {
|
||||||
|
...seeds[lang],
|
||||||
|
[key]: code
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
seeds[lang] = {
|
||||||
|
...defaultFile(lang),
|
||||||
|
[key]: code
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPlugin() {
|
||||||
|
return function transformer(tree, file) {
|
||||||
|
function visitor(node) {
|
||||||
|
if (sectionFilter(node, 'challengeSeed')) {
|
||||||
|
let seeds = {};
|
||||||
|
const codeDivs = selectAll('div', node);
|
||||||
|
const seedConatiners = codeDivs.filter(({ properties: { id } }) =>
|
||||||
|
seedRE.test(id)
|
||||||
|
);
|
||||||
|
seedConatiners.forEach(createCodeGetter('contents', seedRE, seeds));
|
||||||
|
|
||||||
|
const headConatiners = codeDivs.filter(({ properties: { id } }) =>
|
||||||
|
headRE.test(id)
|
||||||
|
);
|
||||||
|
headConatiners.forEach(createCodeGetter('head', headRE, seeds));
|
||||||
|
|
||||||
|
const tailConatiners = codeDivs.filter(({ properties: { id } }) =>
|
||||||
|
tailRE.test(id)
|
||||||
|
);
|
||||||
|
tailConatiners.forEach(createCodeGetter('tail', tailRE, seeds));
|
||||||
|
|
||||||
|
file.data = {
|
||||||
|
...file.data,
|
||||||
|
files: Object.keys(seeds).map(lang => seeds[lang])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visit(tree, 'element', visitor);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = createPlugin;
|
59
tools/challenge-md-parser/challengeSeed-to-data.test.js
Normal file
59
tools/challenge-md-parser/challengeSeed-to-data.test.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/* global describe it expect beforeEach */
|
||||||
|
const mockAST = require('./fixtures/challenge-html-ast.json');
|
||||||
|
const challengeSeedToData = require('./challengeSeed-to-data');
|
||||||
|
|
||||||
|
describe('challengeSeed-to-data plugin', () => {
|
||||||
|
const plugin = challengeSeedToData();
|
||||||
|
let file = { data: {} };
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
file = { data: {} };
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns a function', () => {
|
||||||
|
expect(typeof plugin).toEqual('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds a `files` property to `file.data`', () => {
|
||||||
|
plugin(mockAST, file);
|
||||||
|
expect('files' in file.data).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ensures that the `files` property is an array', () => {
|
||||||
|
plugin(mockAST, file);
|
||||||
|
expect(Array.isArray(file.data.files)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds test objects to the files array following a schema', () => {
|
||||||
|
expect.assertions(7);
|
||||||
|
plugin(mockAST, file);
|
||||||
|
const {
|
||||||
|
data: { files }
|
||||||
|
} = file;
|
||||||
|
const testObject = files[0];
|
||||||
|
expect(Object.keys(testObject).length).toEqual(6);
|
||||||
|
expect(testObject).toHaveProperty('key');
|
||||||
|
expect(testObject).toHaveProperty('ext');
|
||||||
|
expect(testObject).toHaveProperty('name');
|
||||||
|
expect(testObject).toHaveProperty('contents');
|
||||||
|
expect(testObject).toHaveProperty('head');
|
||||||
|
expect(testObject).toHaveProperty('tail');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('only adds strings to the `files` object type', () => {
|
||||||
|
expect.assertions(6);
|
||||||
|
plugin(mockAST, file);
|
||||||
|
const {
|
||||||
|
data: { files }
|
||||||
|
} = file;
|
||||||
|
const testObject = files[0];
|
||||||
|
Object.keys(testObject)
|
||||||
|
.map(key => testObject[key])
|
||||||
|
.forEach(value => expect(typeof value).toEqual('string'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have an output to match the snapshot', () => {
|
||||||
|
plugin(mockAST, file);
|
||||||
|
expect(file.data).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
@ -10,6 +10,7 @@ const raw = require('rehype-raw');
|
|||||||
const frontmatterToData = require('./frontmatter-to-data');
|
const frontmatterToData = require('./frontmatter-to-data');
|
||||||
const textToData = require('./text-to-data');
|
const textToData = require('./text-to-data');
|
||||||
const testsToData = require('./tests-to-data');
|
const testsToData = require('./tests-to-data');
|
||||||
|
const challengeSeedToData = require('./challengeSeed-to-data');
|
||||||
|
|
||||||
const processor = unified()
|
const processor = unified()
|
||||||
.use(markdown)
|
.use(markdown)
|
||||||
@ -19,6 +20,7 @@ const processor = unified()
|
|||||||
.use(remark2rehype, { allowDangerousHTML: true })
|
.use(remark2rehype, { allowDangerousHTML: true })
|
||||||
.use(raw)
|
.use(raw)
|
||||||
.use(textToData, ['description', 'instructions'])
|
.use(textToData, ['description', 'instructions'])
|
||||||
|
.use(challengeSeedToData)
|
||||||
// the plugins below are just to stop the processor from throwing
|
// the plugins below are just to stop the processor from throwing
|
||||||
// we need to write a compiler that can create graphql nodes
|
// we need to write a compiler that can create graphql nodes
|
||||||
.use(html);
|
.use(html);
|
||||||
|
64
tools/challenge-md-parser/package-lock.json
generated
64
tools/challenge-md-parser/package-lock.json
generated
@ -821,6 +821,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"bcp-47-match": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-6rzWe2U70JHrYfBqBnhoeV7HykhmCQ6X2RrBcbpkyCwtNpkGadr3m3LF8ZLXpQ7qrsLCOm3eis2lsVemkLsvHg=="
|
||||||
|
},
|
||||||
"bcrypt-pbkdf": {
|
"bcrypt-pbkdf": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
||||||
@ -831,6 +836,11 @@
|
|||||||
"tweetnacl": "0.14.5"
|
"tweetnacl": "0.14.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"boolbase": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
|
||||||
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
@ -1156,6 +1166,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"css-selector-parser": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-1.3.0.tgz",
|
||||||
|
"integrity": "sha1-XxrUPi2O77/cME/NOaUhZklD4+s="
|
||||||
|
},
|
||||||
"cssom": {
|
"cssom": {
|
||||||
"version": "0.3.4",
|
"version": "0.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz",
|
||||||
@ -1330,6 +1345,11 @@
|
|||||||
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
|
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"direction": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/direction/-/direction-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-hSKoz5FBn+zhP9vWKkVQaaxnRDg3/MoPdcg2au54HIUDR8MrP8Ah1jXSJwCXel6SV3Afh5DSzc8Uqv2r1UoQwQ=="
|
||||||
|
},
|
||||||
"domexception": {
|
"domexception": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
|
||||||
@ -2424,6 +2444,11 @@
|
|||||||
"xtend": "4.0.1"
|
"xtend": "4.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"hast-util-has-property": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-DUck5lp8ku3o8n9GIA1Nghdz8UQyis2/b/ro0O4z5HP/y82uzZL6CXehuQmY5re+rLgTP4MVF/YpYDj9YqD0wA=="
|
||||||
|
},
|
||||||
"hast-util-is-element": {
|
"hast-util-is-element": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.0.1.tgz",
|
||||||
@ -2456,6 +2481,27 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"hast-util-select": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-wPnaITEMGvTvzA9GUQhj7qyOVLceQfxol3Zj+2BrhuMQNt7/W1Za76ZDspNeRKAZmT4aFikNa2SwuJ7MaQC6LQ==",
|
||||||
|
"requires": {
|
||||||
|
"bcp-47-match": "1.0.0",
|
||||||
|
"comma-separated-tokens": "1.0.5",
|
||||||
|
"css-selector-parser": "1.3.0",
|
||||||
|
"direction": "1.0.2",
|
||||||
|
"hast-util-has-property": "1.0.1",
|
||||||
|
"hast-util-is-element": "1.0.1",
|
||||||
|
"hast-util-to-string": "1.0.1",
|
||||||
|
"hast-util-whitespace": "1.0.1",
|
||||||
|
"not": "0.1.0",
|
||||||
|
"nth-check": "1.0.1",
|
||||||
|
"property-information": "4.2.0",
|
||||||
|
"space-separated-tokens": "1.1.2",
|
||||||
|
"unist-util-visit": "1.4.0",
|
||||||
|
"zwitch": "1.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"hast-util-to-html": {
|
"hast-util-to-html": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-4.0.1.tgz",
|
||||||
@ -2485,6 +2531,11 @@
|
|||||||
"zwitch": "1.0.3"
|
"zwitch": "1.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"hast-util-to-string": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-EC6awGe0ZMUNYmS2hMVaKZxvjVtQA4RhXjtgE20AxGG49MM7OUUfaHc6VcVYv2YwzNlrZQGe5teimCxW1Rk+fA=="
|
||||||
|
},
|
||||||
"hast-util-whitespace": {
|
"hast-util-whitespace": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.1.tgz",
|
||||||
@ -3923,6 +3974,11 @@
|
|||||||
"remove-trailing-separator": "1.1.0"
|
"remove-trailing-separator": "1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"not": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/not/-/not-0.1.0.tgz",
|
||||||
|
"integrity": "sha1-yWkcF0bFXc++VMvYvU/wQbwrUZ0="
|
||||||
|
},
|
||||||
"npm-run-path": {
|
"npm-run-path": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
|
||||||
@ -3932,6 +3988,14 @@
|
|||||||
"path-key": "2.0.1"
|
"path-key": "2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nth-check": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=",
|
||||||
|
"requires": {
|
||||||
|
"boolbase": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"number-is-nan": {
|
"number-is-nan": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"jest": "^23.6.0"
|
"jest": "^23.6.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"hast-util-select": "^2.1.0",
|
||||||
"hast-util-to-html": "^4.0.1",
|
"hast-util-to-html": "^4.0.1",
|
||||||
"js-yaml": "^3.12.0",
|
"js-yaml": "^3.12.0",
|
||||||
"lodash": "^4.17.11",
|
"lodash": "^4.17.11",
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
const visit = require('unist-util-visit');
|
const visit = require('unist-util-visit');
|
||||||
const toHTML = require('hast-util-to-html');
|
const toHTML = require('hast-util-to-html');
|
||||||
|
|
||||||
const sectionFilter = (
|
const { sectionFilter } = require('./utils')
|
||||||
{ type, tagName, properties: { id = '' } },
|
|
||||||
sectionId
|
|
||||||
) => {
|
|
||||||
return type === 'element' && tagName === 'section' && id === sectionId;
|
|
||||||
};
|
|
||||||
|
|
||||||
function textToData(sectionIds) {
|
function textToData(sectionIds) {
|
||||||
if (!sectionIds || !Array.isArray(sectionIds) || sectionIds.length <= 0) {
|
if (!sectionIds || !Array.isArray(sectionIds) || sectionIds.length <= 0) {
|
||||||
|
6
tools/challenge-md-parser/utils/index.js
Normal file
6
tools/challenge-md-parser/utils/index.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
exports.sectionFilter = (
|
||||||
|
{ type, tagName, properties: { id = '' } },
|
||||||
|
sectionId
|
||||||
|
) => {
|
||||||
|
return type === 'element' && tagName === 'section' && id === sectionId;
|
||||||
|
};
|
Reference in New Issue
Block a user