diff --git a/client/gatsby-node.js b/client/gatsby-node.js
index d1adc1805e..173c7e2a73 100644
--- a/client/gatsby-node.js
+++ b/client/gatsby-node.js
@@ -244,17 +244,11 @@ exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions;
const typeDefs = `
type ChallengeNode implements Node {
- files: ChallengeFile
+ challengeFiles: [FileContents]
url: String
}
- type ChallengeFile {
- indexcss: FileContents
- indexhtml: FileContents
- indexjs: FileContents
- indexjsx: FileContents
- }
type FileContents {
- key: String
+ fileKey: String
ext: String
name: String
contents: String
diff --git a/client/src/client-only-routes/show-project-links.tsx b/client/src/client-only-routes/show-project-links.tsx
index 29ca8ffdef..28a370ffb4 100644
--- a/client/src/client-only-routes/show-project-links.tsx
+++ b/client/src/client-only-routes/show-project-links.tsx
@@ -5,7 +5,7 @@ import { Trans, useTranslation } from 'react-i18next';
import ProjectModal from '../components/SolutionViewer/ProjectModal';
import { Spacer, Link } from '../components/helpers';
import {
- ChallengeFileType,
+ ChallengeFiles,
CompletedChallenge,
UserType
} from '../redux/prop-types';
@@ -24,14 +24,14 @@ interface IShowProjectLinksProps {
type SolutionStateType = {
projectTitle: string;
- files?: ChallengeFileType[] | null;
+ challengeFiles: ChallengeFiles;
solution: CompletedChallenge['solution'];
isOpen: boolean;
};
const initSolutionState: SolutionStateType = {
projectTitle: '',
- files: null,
+ challengeFiles: null,
solution: null,
isOpen: false
};
@@ -56,16 +56,16 @@ const ShowProjectLinks = (props: IShowProjectLinksProps): JSX.Element => {
return null;
}
- const { solution, githubLink, files } = completedProject;
+ const { solution, githubLink, challengeFiles } = completedProject;
const onClickHandler = () =>
setSolutionState({
projectTitle,
- files,
+ challengeFiles,
solution,
isOpen: true
});
- if (files?.length) {
+ if (challengeFiles?.length) {
return (
",
"solutions": Array [
- Object {},
+ Array [],
],
"tests": Array [],
}
@@ -44,7 +44,7 @@ Object {
",
},
"solutions": Array [
- Object {},
+ Array [],
],
"tests": Array [],
}
@@ -52,38 +52,33 @@ Object {
exports[`challenge parser should import md from other files 1`] = `
Object {
- "description": "
-Paragraph 1
-code example
-
-",
- "files": Object {
- "indexcss": Object {
- "contents": "body {
- background: green;
-}",
- "editableRegionBoundaries": Array [],
- "ext": "css",
- "head": "",
- "id": "",
- "key": "indexcss",
- "name": "index",
- "tail": "",
- },
- "indexhtml": Object {
+ "challengeFiles": Array [
+ Object {
"contents": "
",
"editableRegionBoundaries": Array [],
"ext": "html",
+ "fileKey": "indexhtml",
"head": "",
"id": "",
- "key": "indexhtml",
"name": "index",
"tail": "",
},
- "indexjs": Object {
+ Object {
+ "contents": "body {
+ background: green;
+}",
+ "editableRegionBoundaries": Array [],
+ "ext": "css",
+ "fileKey": "indexcss",
+ "head": "",
+ "id": "",
+ "name": "index",
+ "tail": "",
+ },
+ Object {
"contents": "var x = 'y';
for (let index = 0; index < array.length; index++) {
const element = array[index];
@@ -91,20 +86,25 @@ for (let index = 0; index < array.length; index++) {
}",
"editableRegionBoundaries": Array [],
"ext": "js",
+ "fileKey": "indexjs",
"head": "",
"id": "custom-name",
- "key": "indexjs",
"name": "index",
"tail": "",
},
- },
+ ],
+ "description": "
+Paragraph 1
+code example
+
+",
"instructions": "
Paragraph 0
code example 0
",
"solutions": Array [
- Object {},
+ Array [],
],
"tests": Array [
Object {
@@ -121,6 +121,43 @@ for (let index = 0; index < array.length; index++) {
exports[`challenge parser should not mix other YAML with the frontmatter 1`] = `
Object {
+ "challengeFiles": Array [
+ Object {
+ "contents": "
+
+
+",
+ "editableRegionBoundaries": Array [],
+ "ext": "html",
+ "fileKey": "indexhtml",
+ "head": "",
+ "id": "",
+ "name": "index",
+ "tail": "",
+ },
+ Object {
+ "contents": "body {
+ background: green;
+}",
+ "editableRegionBoundaries": Array [],
+ "ext": "css",
+ "fileKey": "indexcss",
+ "head": "",
+ "id": "",
+ "name": "index",
+ "tail": "",
+ },
+ Object {
+ "contents": "var x = 'y';",
+ "editableRegionBoundaries": Array [],
+ "ext": "js",
+ "fileKey": "indexjs",
+ "head": "",
+ "id": "",
+ "name": "index",
+ "tail": "",
+ },
+ ],
"description": "
Paragraph 1
code example
@@ -130,50 +167,13 @@ Object {
anothersubkey: another value
",
- "files": Object {
- "indexcss": Object {
- "contents": "body {
- background: green;
-}",
- "editableRegionBoundaries": Array [],
- "ext": "css",
- "head": "",
- "id": "",
- "key": "indexcss",
- "name": "index",
- "tail": "",
- },
- "indexhtml": Object {
- "contents": "
-
-
-",
- "editableRegionBoundaries": Array [],
- "ext": "html",
- "head": "",
- "id": "",
- "key": "indexhtml",
- "name": "index",
- "tail": "",
- },
- "indexjs": Object {
- "contents": "var x = 'y';",
- "editableRegionBoundaries": Array [],
- "ext": "js",
- "head": "",
- "id": "",
- "key": "indexjs",
- "name": "index",
- "tail": "",
- },
- },
"instructions": "
Paragraph 0
code example 0
",
"solutions": Array [
- Object {},
+ Array [],
],
"tests": Array [
Object {
@@ -190,42 +190,8 @@ Object {
exports[`challenge parser should parse a more realistic md file 1`] = `
Object {
- "description": "
-When you add a lower rank heading element to the page, it's implied that you're starting a new subsection.
-After the last h2
element of the second section
element, add an h3
element with the text Things cats love:
.
-
- Some text in a blockquote
-
- Some text in a blockquote, with code
-
-
-",
- "files": Object {
- "indexcss": Object {
- "contents": "body {
- background: white;
-}
-
-h1 {
- font-size: 20px;
-}
-
-
-a {
- color: green;
-}",
- "editableRegionBoundaries": Array [
- 7,
- 9,
- ],
- "ext": "css",
- "head": "",
- "id": "",
- "key": "indexcss",
- "name": "index",
- "tail": "",
- },
- "indexhtml": Object {
+ "challengeFiles": Array [
+ Object {
"contents": "
CatPhotoApp
@@ -256,32 +222,14 @@ a {
23,
],
"ext": "html",
+ "fileKey": "indexhtml",
"head": "",
"id": "html-key",
- "key": "indexhtml",
"name": "index",
"tail": "",
},
- "indexjs": Object {
- "contents": "var x = 'y';",
- "editableRegionBoundaries": Array [],
- "ext": "js",
- "head": " // this runs before the user's code is evaluated.",
- "id": "final-key",
- "key": "indexjs",
- "name": "index",
- "tail": "",
- },
- },
- "instructions": "
-Do something with the code
.
-To test that adjacent tags are handled correctly:
-a bit of code
with more after a space and another pair of elements with a space
-",
- "solutions": Array [
Object {
- "indexcss": Object {
- "contents": "body {
+ "contents": "body {
background: white;
}
@@ -293,14 +241,46 @@ h1 {
a {
color: green;
}",
- "ext": "css",
- "head": "",
- "id": "",
- "key": "indexcss",
- "name": "index",
- "tail": "",
- },
- "indexhtml": Object {
+ "editableRegionBoundaries": Array [
+ 7,
+ 9,
+ ],
+ "ext": "css",
+ "fileKey": "indexcss",
+ "head": "",
+ "id": "",
+ "name": "index",
+ "tail": "",
+ },
+ Object {
+ "contents": "var x = 'y';",
+ "editableRegionBoundaries": Array [],
+ "ext": "js",
+ "fileKey": "indexjs",
+ "head": " // this runs before the user's code is evaluated.",
+ "id": "final-key",
+ "name": "index",
+ "tail": "",
+ },
+ ],
+ "description": "
+When you add a lower rank heading element to the page, it's implied that you're starting a new subsection.
+After the last h2
element of the second section
element, add an h3
element with the text Things cats love:
.
+
+ Some text in a blockquote
+
+ Some text in a blockquote, with code
+
+
+",
+ "instructions": "
+Do something with the code
.
+To test that adjacent tags are handled correctly:
+a bit of code
with more after a space and another pair of elements with a space
+",
+ "solutions": Array [
+ Array [
+ Object {
"contents": "
CatPhotoApp
@@ -327,22 +307,42 @@ a {
",
"ext": "html",
+ "fileKey": "indexhtml",
"head": "",
"id": "html-key",
- "key": "indexhtml",
"name": "index",
"tail": "",
},
- "indexjs": Object {
+ Object {
+ "contents": "body {
+ background: white;
+}
+
+h1 {
+ font-size: 20px;
+}
+
+
+a {
+ color: green;
+}",
+ "ext": "css",
+ "fileKey": "indexcss",
+ "head": "",
+ "id": "",
+ "name": "index",
+ "tail": "",
+ },
+ Object {
"contents": "var x = 'y';",
"ext": "js",
+ "fileKey": "indexjs",
"head": "",
"id": "final-key",
- "key": "indexjs",
"name": "index",
"tail": "",
},
- },
+ ],
],
"tests": Array [
Object {
@@ -385,89 +385,89 @@ assert(
exports[`challenge parser should parse a simple md file 1`] = `
Object {
- "description": "
-Paragraph 1
-code example
-
-",
- "files": Object {
- "indexcss": Object {
- "contents": "body {
- background: green;
-}",
- "editableRegionBoundaries": Array [],
- "ext": "css",
- "head": "",
- "id": "",
- "key": "indexcss",
- "name": "index",
- "tail": "",
- },
- "indexhtml": Object {
+ "challengeFiles": Array [
+ Object {
"contents": "
",
"editableRegionBoundaries": Array [],
"ext": "html",
+ "fileKey": "indexhtml",
"head": "",
"id": "",
- "key": "indexhtml",
"name": "index",
"tail": "",
},
- "indexjs": Object {
+ Object {
+ "contents": "body {
+ background: green;
+}",
+ "editableRegionBoundaries": Array [],
+ "ext": "css",
+ "fileKey": "indexcss",
+ "head": "",
+ "id": "",
+ "name": "index",
+ "tail": "",
+ },
+ Object {
"contents": "var x = 'y';",
"editableRegionBoundaries": Array [],
"ext": "js",
+ "fileKey": "indexjs",
"head": "",
"id": "",
- "key": "indexjs",
"name": "index",
"tail": "",
},
- },
+ ],
+ "description": "
+Paragraph 1
+code example
+
+",
"instructions": "
Paragraph 0
code example 0
",
"solutions": Array [
- Object {
- "indexcss": Object {
- "contents": "body {
- background: white;
-}",
- "ext": "css",
- "head": "",
- "id": "",
- "key": "indexcss",
- "name": "index",
- "tail": "",
- },
- "indexhtml": Object {
+ Array [
+ Object {
"contents": "
",
"ext": "html",
+ "fileKey": "indexhtml",
"head": "",
"id": "html-key",
- "key": "indexhtml",
"name": "index",
"tail": "",
},
- "indexjs": Object {
+ Object {
+ "contents": "body {
+ background: white;
+}",
+ "ext": "css",
+ "fileKey": "indexcss",
+ "head": "",
+ "id": "",
+ "name": "index",
+ "tail": "",
+ },
+ Object {
"contents": "var x = 'y';
\`\`",
"ext": "js",
+ "fileKey": "indexjs",
"head": "",
"id": "",
- "key": "indexjs",
"name": "index",
"tail": "",
},
- },
+ ],
],
"tests": Array [
Object {
@@ -491,54 +491,54 @@ if(let x of xs) {
exports[`challenge parser should parse frontmatter 1`] = `
Object {
- "challengeType": 0,
- "description": "
-Paragraph 1
-code example
-
-",
- "files": Object {
- "indexcss": Object {
- "contents": "body {
- background: green;
-}",
- "editableRegionBoundaries": Array [],
- "ext": "css",
- "head": "",
- "id": "",
- "key": "indexcss",
- "name": "index",
- "tail": "",
- },
- "indexhtml": Object {
+ "challengeFiles": Array [
+ Object {
"contents": "
",
"editableRegionBoundaries": Array [],
"ext": "html",
+ "fileKey": "indexhtml",
"head": "",
"id": "",
- "key": "indexhtml",
"name": "index",
"tail": "",
},
- "indexjs": Object {
+ Object {
+ "contents": "body {
+ background: green;
+}",
+ "editableRegionBoundaries": Array [],
+ "ext": "css",
+ "fileKey": "indexcss",
+ "head": "",
+ "id": "",
+ "name": "index",
+ "tail": "",
+ },
+ Object {
"contents": "var x = 'y';",
"editableRegionBoundaries": Array [],
"ext": "js",
+ "fileKey": "indexjs",
"head": "",
"id": "",
- "key": "indexjs",
"name": "index",
"tail": "",
},
- },
+ ],
+ "challengeType": 0,
+ "description": "
+Paragraph 1
+code example
+
+",
"forumTopicId": 18276,
"id": "bd7123c8c441eddfaeb5bdef",
"isHidden": false,
"solutions": Array [
- Object {},
+ Array [],
],
"tests": Array [
Object {
@@ -557,6 +557,43 @@ Object {
exports[`challenge parser should parse gfm strikethrough and frontmatter 1`] = `
Object {
+ "challengeFiles": Array [
+ Object {
+ "contents": "
+
+
+",
+ "editableRegionBoundaries": Array [],
+ "ext": "html",
+ "fileKey": "indexhtml",
+ "head": "",
+ "id": "",
+ "name": "index",
+ "tail": "",
+ },
+ Object {
+ "contents": "body {
+ background: green;
+}",
+ "editableRegionBoundaries": Array [],
+ "ext": "css",
+ "fileKey": "indexcss",
+ "head": "",
+ "id": "",
+ "name": "index",
+ "tail": "",
+ },
+ Object {
+ "contents": "var x = 'y';",
+ "editableRegionBoundaries": Array [],
+ "ext": "js",
+ "fileKey": "indexjs",
+ "head": "",
+ "id": "",
+ "name": "index",
+ "tail": "",
+ },
+ ],
"description": "
Paragraph 1 Strikethrough text. https://should.not.be.autolinked
code example
@@ -576,84 +613,47 @@ Object {
",
- "files": Object {
- "indexcss": Object {
- "contents": "body {
- background: green;
-}",
- "editableRegionBoundaries": Array [],
- "ext": "css",
- "head": "",
- "id": "",
- "key": "indexcss",
- "name": "index",
- "tail": "",
- },
- "indexhtml": Object {
- "contents": "
-
-
-",
- "editableRegionBoundaries": Array [],
- "ext": "html",
- "head": "",
- "id": "",
- "key": "indexhtml",
- "name": "index",
- "tail": "",
- },
- "indexjs": Object {
- "contents": "var x = 'y';",
- "editableRegionBoundaries": Array [],
- "ext": "js",
- "head": "",
- "id": "",
- "key": "indexjs",
- "name": "index",
- "tail": "",
- },
- },
"instructions": "
Paragraph 0
code example 0
",
"solutions": Array [
- Object {
- "indexcss": Object {
- "contents": "body {
- background: white;
-}",
- "ext": "css",
- "head": "",
- "id": "",
- "key": "indexcss",
- "name": "index",
- "tail": "",
- },
- "indexhtml": Object {
+ Array [
+ Object {
"contents": "
",
"ext": "html",
+ "fileKey": "indexhtml",
"head": "",
"id": "html-key",
- "key": "indexhtml",
"name": "index",
"tail": "",
},
- "indexjs": Object {
+ Object {
+ "contents": "body {
+ background: white;
+}",
+ "ext": "css",
+ "fileKey": "indexcss",
+ "head": "",
+ "id": "",
+ "name": "index",
+ "tail": "",
+ },
+ Object {
"contents": "var x = 'y';
\`\`",
"ext": "js",
+ "fileKey": "indexjs",
"head": "",
"id": "",
- "key": "indexjs",
"name": "index",
"tail": "",
},
- },
+ ],
],
"tests": Array [
Object {
diff --git a/tools/challenge-parser/parser/plugins/__snapshots__/add-seed.test.js.snap b/tools/challenge-parser/parser/plugins/__snapshots__/add-seed.test.js.snap
index 9ee0817a0b..c62776dd8e 100644
--- a/tools/challenge-parser/parser/plugins/__snapshots__/add-seed.test.js.snap
+++ b/tools/challenge-parser/parser/plugins/__snapshots__/add-seed.test.js.snap
@@ -2,42 +2,42 @@
exports[`add-seed plugin should have an output to match the snapshot 1`] = `
Object {
- "files": Object {
- "indexcss": Object {
- "contents": "body {
- background: green;
-}",
- "editableRegionBoundaries": Array [],
- "ext": "css",
- "head": "",
- "id": "",
- "key": "indexcss",
- "name": "index",
- "tail": "",
- },
- "indexhtml": Object {
+ "challengeFiles": Array [
+ Object {
"contents": "
",
"editableRegionBoundaries": Array [],
"ext": "html",
+ "fileKey": "indexhtml",
"head": "",
"id": "",
- "key": "indexhtml",
"name": "index",
"tail": "",
},
- "indexjs": Object {
+ Object {
+ "contents": "body {
+ background: green;
+}",
+ "editableRegionBoundaries": Array [],
+ "ext": "css",
+ "fileKey": "indexcss",
+ "head": "",
+ "id": "",
+ "name": "index",
+ "tail": "",
+ },
+ Object {
"contents": "var x = 'y';",
"editableRegionBoundaries": Array [],
"ext": "js",
+ "fileKey": "indexjs",
"head": "",
"id": "",
- "key": "indexjs",
"name": "index",
"tail": "",
},
- },
+ ],
}
`;
diff --git a/tools/challenge-parser/parser/plugins/__snapshots__/add-solution.test.js.snap b/tools/challenge-parser/parser/plugins/__snapshots__/add-solution.test.js.snap
index cc2a4f00ff..7df32888d3 100644
--- a/tools/challenge-parser/parser/plugins/__snapshots__/add-solution.test.js.snap
+++ b/tools/challenge-parser/parser/plugins/__snapshots__/add-solution.test.js.snap
@@ -3,41 +3,41 @@
exports[`add solution plugin should have an output to match the snapshot 1`] = `
Object {
"solutions": Array [
- Object {
- "indexcss": Object {
- "contents": "body {
- background: white;
-}",
- "ext": "css",
- "head": "",
- "id": "",
- "key": "indexcss",
- "name": "index",
- "tail": "",
- },
- "indexhtml": Object {
+ Array [
+ Object {
"contents": "
",
"ext": "html",
+ "fileKey": "indexhtml",
"head": "",
"id": "html-key",
- "key": "indexhtml",
"name": "index",
"tail": "",
},
- "indexjs": Object {
+ Object {
+ "contents": "body {
+ background: white;
+}",
+ "ext": "css",
+ "fileKey": "indexcss",
+ "head": "",
+ "id": "",
+ "name": "index",
+ "tail": "",
+ },
+ Object {
"contents": "var x = 'y';
\`\`",
"ext": "js",
+ "fileKey": "indexjs",
"head": "",
"id": "",
- "key": "indexjs",
"name": "index",
"tail": "",
},
- },
+ ],
],
}
`;
diff --git a/tools/challenge-parser/parser/plugins/add-seed.js b/tools/challenge-parser/parser/plugins/add-seed.js
index e4f8900083..da016291d9 100644
--- a/tools/challenge-parser/parser/plugins/add-seed.js
+++ b/tools/challenge-parser/parser/plugins/add-seed.js
@@ -7,8 +7,8 @@ const { getFileVisitor } = require('./utils/get-file-visitor');
const editableRegionMarker = '--fcc-editable-region--';
-function findRegionMarkers(file) {
- const lines = file.contents.split('\n');
+function findRegionMarkers(challengeFile) {
+ const lines = challengeFile.contents.split('\n');
const editableLines = lines
.map((line, id) => (line.trim() === editableRegionMarker ? id : -1))
.filter(id => id >= 0);
@@ -55,26 +55,33 @@ function addSeeds() {
visitForContents(contentsTree);
visitForHead(headTree);
visitForTail(tailTree);
+ const seedVals = Object.values(seeds);
file.data = {
...file.data,
- files: seeds
+ challengeFiles: seedVals
};
// process region markers - remove them from content and add them to data
- Object.keys(seeds).forEach(key => {
- const fileData = seeds[key];
- const editRegionMarkers = findRegionMarkers(fileData);
+ const challengeFiles = Object.values(seeds).map(data => {
+ const seed = { ...data };
+ const editRegionMarkers = findRegionMarkers(seed);
if (editRegionMarkers) {
- fileData.contents = removeLines(fileData.contents, editRegionMarkers);
+ seed.contents = removeLines(seed.contents, editRegionMarkers);
if (editRegionMarkers[1] <= editRegionMarkers[0]) {
throw Error('Editable region must be non zero');
}
- fileData.editableRegionBoundaries = editRegionMarkers;
+ seed.editableRegionBoundaries = editRegionMarkers;
} else {
- fileData.editableRegionBoundaries = [];
+ seed.editableRegionBoundaries = [];
}
+ return seed;
});
+
+ file.data = {
+ ...file.data,
+ challengeFiles
+ };
}
return transformer;
diff --git a/tools/challenge-parser/parser/plugins/add-seed.test.js b/tools/challenge-parser/parser/plugins/add-seed.test.js
index a448ef8679..7c91a69479 100644
--- a/tools/challenge-parser/parser/plugins/add-seed.test.js
+++ b/tools/challenge-parser/parser/plugins/add-seed.test.js
@@ -1,4 +1,3 @@
-const { isObject } = require('lodash');
const isArray = require('lodash/isArray');
const adjacentKeysAST = require('../__fixtures__/ast-adjacent-keys.json');
@@ -32,26 +31,26 @@ describe('add-seed plugin', () => {
expect(typeof plugin).toEqual('function');
});
- it('adds a `files` property to `file.data`', () => {
+ it('adds a `challengeFiles` property to `file.data`', () => {
plugin(simpleAST, file);
- expect('files' in file.data).toBe(true);
+ expect('challengeFiles' in file.data).toBe(true);
});
- it('ensures that the `files` property is an object', () => {
+ it('ensures that the `challengeFiles` property is an array', () => {
plugin(simpleAST, file);
- expect(isObject(file.data.files)).toBe(true);
+ expect(isArray(file.data.challengeFiles)).toBe(true);
});
- it('adds test objects to the files array following a schema', () => {
+ it('adds test objects to the challengeFiles array following a schema', () => {
expect.assertions(17);
plugin(simpleAST, file);
const {
- data: { files }
+ data: { challengeFiles }
} = file;
- const testObject = files.indexjs;
+ const testObject = challengeFiles.find(x => x.fileKey === 'indexjs');
expect(Object.keys(testObject).length).toEqual(8);
- expect(testObject).toHaveProperty('key');
- expect(typeof testObject['key']).toBe('string');
+ expect(testObject).toHaveProperty('fileKey');
+ expect(typeof testObject['fileKey']).toBe('string');
expect(testObject).toHaveProperty('ext');
expect(typeof testObject['ext']).toBe('string');
expect(testObject).toHaveProperty('name');
@@ -69,33 +68,32 @@ describe('add-seed plugin', () => {
});
it('parses seeds without ids', () => {
- expect.assertions(6);
+ expect.assertions(3);
plugin(simpleAST, file);
const {
- data: { files }
+ data: { challengeFiles }
} = file;
- const { indexjs, indexhtml, indexcss } = files;
+ const indexjs = challengeFiles.find(x => x.fileKey === 'indexjs');
+ const indexhtml = challengeFiles.find(x => x.fileKey === 'indexhtml');
+ const indexcss = challengeFiles.find(x => x.fileKey === 'indexcss');
expect(indexjs.contents).toBe(`var x = 'y';`);
- expect(indexjs.key).toBe(`indexjs`);
expect(indexhtml.contents).toBe(`
`);
- expect(indexhtml.key).toBe(`indexhtml`);
expect(indexcss.contents).toBe(`body {
background: green;
}`);
- expect(indexcss.key).toBe(`indexcss`);
});
it('removes region markers from contents', () => {
expect.assertions(2);
plugin(withEditableAST, file);
const {
- data: { files }
+ data: { challengeFiles }
} = file;
- const { indexcss } = files;
+ const indexcss = challengeFiles.find(x => x.fileKey === 'indexcss');
expect(indexcss.contents).not.toMatch('--fcc-editable-region--');
expect(indexcss.editableRegionBoundaries).toEqual([1, 4]);
@@ -107,9 +105,11 @@ describe('add-seed plugin', () => {
expect.assertions(3);
plugin(withSeedKeysAST, file);
const {
- data: { files }
+ data: { challengeFiles }
} = file;
- const { indexhtml, indexcss, indexjs } = files;
+ const indexjs = challengeFiles.find(x => x.fileKey === 'indexjs');
+ const indexhtml = challengeFiles.find(x => x.fileKey === 'indexhtml');
+ const indexcss = challengeFiles.find(x => x.fileKey === 'indexcss');
expect(indexhtml.id).toBe('');
expect(indexcss.id).toBe('key-for-css');
@@ -138,9 +138,11 @@ describe('add-seed plugin', () => {
expect.assertions(3);
plugin(withBeforeAfterAST, file);
const {
- data: { files }
+ data: { challengeFiles }
} = file;
- const { indexjs, indexhtml, indexcss } = files;
+ const indexjs = challengeFiles.find(x => x.fileKey === 'indexjs');
+ const indexhtml = challengeFiles.find(x => x.fileKey === 'indexhtml');
+ const indexcss = challengeFiles.find(x => x.fileKey === 'indexcss');
expect(indexjs.head).toBe('');
expect(indexhtml.head).toBe(``);
@@ -153,9 +155,11 @@ describe('add-seed plugin', () => {
expect.assertions(3);
plugin(withBeforeAfterAST, file);
const {
- data: { files }
+ data: { challengeFiles }
} = file;
- const { indexjs, indexhtml, indexcss } = files;
+ const indexjs = challengeFiles.find(x => x.fileKey === 'indexjs');
+ const indexhtml = challengeFiles.find(x => x.fileKey === 'indexhtml');
+ const indexcss = challengeFiles.find(x => x.fileKey === 'indexcss');
expect(indexjs.tail).toBe(`function teardown(params) {
// after
@@ -188,9 +192,11 @@ describe('add-seed plugin', () => {
expect.assertions(6);
plugin(emptyBeforeAST, file);
const {
- data: { files }
+ data: { challengeFiles }
} = file;
- const { indexjs, indexhtml, indexcss } = files;
+ const indexjs = challengeFiles.find(x => x.fileKey === 'indexjs');
+ const indexhtml = challengeFiles.find(x => x.fileKey === 'indexhtml');
+ const indexcss = challengeFiles.find(x => x.fileKey === 'indexcss');
expect(indexjs.head).toBe('');
expect(indexjs.tail).toBe('function teardown(params) {\n // after\n}');
@@ -204,9 +210,11 @@ describe('add-seed plugin', () => {
expect.assertions(6);
plugin(emptyAfterAST, file);
const {
- data: { files }
+ data: { challengeFiles }
} = file;
- const { indexjs, indexhtml, indexcss } = files;
+ const indexjs = challengeFiles.find(x => x.fileKey === 'indexjs');
+ const indexhtml = challengeFiles.find(x => x.fileKey === 'indexhtml');
+ const indexcss = challengeFiles.find(x => x.fileKey === 'indexcss');
expect(indexjs.head).toBe('');
expect(indexjs.tail).toBe('');
@@ -234,9 +242,9 @@ describe('add-seed plugin', () => {
expect.assertions(4);
plugin(jsxSeedAST, file);
const {
- data: { files }
+ data: { challengeFiles }
} = file;
- const { indexjsx } = files;
+ const indexjsx = challengeFiles.find(x => x.fileKey === 'indexjsx');
expect(indexjsx.head).toBe(`function setup() {}`);
expect(indexjsx.tail).toBe(`function teardown(params) {
@@ -248,7 +256,7 @@ describe('add-seed plugin', () => {
const Button = () => {
return {/* another comment! */} text ;
};`);
- expect(indexjsx.key).toBe(`indexjsx`);
+ expect(indexjsx.fileKey).toBe(`indexjsx`);
});
it('combines all the code of a specific language into a single file', () => {
diff --git a/tools/challenge-parser/parser/plugins/add-solution.js b/tools/challenge-parser/parser/plugins/add-solution.js
index 6a373f3a67..af08df35e0 100644
--- a/tools/challenge-parser/parser/plugins/add-solution.js
+++ b/tools/challenge-parser/parser/plugins/add-solution.js
@@ -30,7 +30,7 @@ function createPlugin() {
);
visitForContents(solutionTree);
- solutions.push(solution);
+ solutions.push(Object.values(solution));
});
file.data = {
diff --git a/tools/challenge-parser/parser/plugins/add-solution.test.js b/tools/challenge-parser/parser/plugins/add-solution.test.js
index 281b313991..522deb2386 100644
--- a/tools/challenge-parser/parser/plugins/add-solution.test.js
+++ b/tools/challenge-parser/parser/plugins/add-solution.test.js
@@ -33,16 +33,18 @@ describe('add solution plugin', () => {
expect(file.data.solutions.every(el => isObject(el))).toBe(true);
});
- it('adds solution objects to the files array following a schema', () => {
+ it('adds solution objects to the challengeFiles array following a schema', () => {
expect.assertions(15);
plugin(mockAST, file);
const {
data: { solutions }
} = file;
- const testObject = solutions[0].indexjs;
+ const testObject = solutions[0].find(
+ solution => solution.fileKey === 'indexjs'
+ );
expect(Object.keys(testObject).length).toEqual(7);
- expect(testObject).toHaveProperty('key');
- expect(typeof testObject['key']).toBe('string');
+ expect(testObject).toHaveProperty('fileKey');
+ expect(typeof testObject['fileKey']).toBe('string');
expect(testObject).toHaveProperty('ext');
expect(typeof testObject['ext']).toBe('string');
expect(testObject).toHaveProperty('name');
@@ -64,16 +66,24 @@ describe('add solution plugin', () => {
data: { solutions }
} = file;
expect(solutions.length).toBe(3);
- expect(solutions[0].indexjs.contents).toBe("var x = 'y';");
- expect(solutions[1].indexhtml.contents).toBe(`
+ expect(
+ solutions[0].find(solution => solution.fileKey === 'indexjs').contents
+ ).toBe("var x = 'y';");
+ expect(
+ solutions[1].find(solution => solution.fileKey === 'indexhtml').contents
+ ).toBe(`
solution number two
`);
- expect(solutions[1].indexcss.contents).toBe(`body {
+ expect(
+ solutions[1].find(solution => solution.fileKey === 'indexcss').contents
+ ).toBe(`body {
background: white;
}`);
- expect(solutions[2].indexjs.contents).toBe("var x = 'y3';");
+ expect(
+ solutions[2].find(solution => solution.fileKey === 'indexjs').contents
+ ).toBe("var x = 'y3';");
});
it('should reject solutions with editable region markers', () => {
diff --git a/tools/challenge-parser/parser/plugins/utils/get-file-visitor.js b/tools/challenge-parser/parser/plugins/utils/get-file-visitor.js
index 4f263a55e2..920d41d15c 100644
--- a/tools/challenge-parser/parser/plugins/utils/get-file-visitor.js
+++ b/tools/challenge-parser/parser/plugins/utils/get-file-visitor.js
@@ -12,7 +12,7 @@ const supportedLanguages = ['js', 'css', 'html', 'jsx', 'py'];
function defaultFile(lang, id) {
return {
- key: `index${lang}`,
+ fileKey: `index${lang}`,
ext: lang,
name: 'index',
contents: '',
@@ -43,21 +43,21 @@ function codeToData(node, seeds, seedKey, validate) {
Please use one of js, css, html, jsx or py
`);
- const key = `index${lang}`;
- const id = seeds[key] ? seeds[key].id : '';
+ const fileKey = `index${lang}`;
+ const id = seeds[fileKey] ? seeds[fileKey].id : '';
// the contents will be missing if there is an id preceding this code
// block.
- if (!seeds[key]) {
- seeds[key] = defaultFile(lang, id);
+ if (!seeds[fileKey]) {
+ seeds[fileKey] = defaultFile(lang, id);
}
if (isEmpty(node.value) && seedKey !== 'contents') {
const section = keyToSection[seedKey];
throw Error(`Empty code block in --${section}-- section`);
}
- seeds[key][seedKey] = isEmpty(seeds[key][seedKey])
+ seeds[fileKey][seedKey] = isEmpty(seeds[fileKey][seedKey])
? node.value
- : seeds[key][seedKey] + '\n' + node.value;
+ : seeds[fileKey][seedKey] + '\n' + node.value;
}
function idToData(node, index, parent, seeds) {
@@ -73,9 +73,9 @@ function idToData(node, index, parent, seeds) {
}
const codeNode = parent.children[index + 1];
if (codeNode && is(codeNode, 'code')) {
- const key = `index${codeNode.lang}`;
- if (seeds[key]) throw Error('::id{#id}s must come before code blocks');
- seeds[key] = defaultFile(codeNode.lang, id);
+ const fileKey = `index${codeNode.lang}`;
+ if (seeds[fileKey]) throw Error('::id{#id}s must come before code blocks');
+ seeds[fileKey] = defaultFile(codeNode.lang, id);
} else {
throw Error('::id{#id}s must come before code blocks');
}
diff --git a/tools/challenge-parser/translation-parser/__fixtures__/challenge-objects.js b/tools/challenge-parser/translation-parser/__fixtures__/challenge-objects.js
index a17e7b4f49..81fecf6fab 100644
--- a/tools/challenge-parser/translation-parser/__fixtures__/challenge-objects.js
+++ b/tools/challenge-parser/translation-parser/__fixtures__/challenge-objects.js
@@ -17,7 +17,7 @@ const ENGLISH_CHALLENGE_NO_FILES = {
solutions: ['solution html string'],
description: 'description html string',
instructions: 'instructions html string',
- files: []
+ challengeFiles: []
};
exports.ENGLISH_CHALLENGE_NO_FILES = ENGLISH_CHALLENGE_NO_FILES;
diff --git a/tools/challenge-parser/translation-parser/index.js b/tools/challenge-parser/translation-parser/index.js
index 4b7c3ee459..4283cfd205 100644
--- a/tools/challenge-parser/translation-parser/index.js
+++ b/tools/challenge-parser/translation-parser/index.js
@@ -17,19 +17,19 @@ exports.translateComments = (text, lang, dict, codeLang) => {
exports.translateCommentsInChallenge = (challenge, lang, dict) => {
const challClone = cloneDeep(challenge);
- if (!challClone.files) {
+ if (!challClone.challengeFiles) {
console.warn(`Challenge ${challClone.title} has no seed to translate`);
} else {
- Object.keys(challClone.files).forEach(key => {
- if (challClone.files[key].contents) {
+ challClone.challengeFiles.forEach(challengeFile => {
+ if (challengeFile.contents) {
let { text, commentCounts } = this.translateComments(
- challenge.files[key].contents,
+ challengeFile.contents,
lang,
dict,
- challClone.files[key].ext
+ challengeFile.ext
);
challClone.__commentCounts = commentCounts;
- challClone.files[key].contents = text;
+ challengeFile.contents = text;
}
});
}
diff --git a/utils/__fixtures__/challenges.js b/utils/__fixtures__/challenges.js
index df9d0b54b6..e4dab4e37a 100644
--- a/utils/__fixtures__/challenges.js
+++ b/utils/__fixtures__/challenges.js
@@ -1,50 +1,50 @@
-exports.challengeFiles = {
- indexcss: {
+exports.challengeFiles = [
+ {
contents: 'some css',
error: null,
ext: 'css',
head: '',
history: ['index.css'],
- key: 'indexcss',
+ fileKey: 'indexcss',
name: 'index',
path: 'index.css',
seed: 'some css',
tail: ''
},
- indexhtml: {
+ {
contents: 'some html',
error: null,
ext: 'html',
head: '',
history: ['index.html'],
- key: 'indexhtml',
+ fileKey: 'indexhtml',
name: 'index',
path: 'index.html',
seed: 'some html',
tail: ''
},
- indexjs: {
+ {
contents: 'some js',
error: null,
ext: 'js',
head: '',
history: ['index.js'],
- key: 'indexjs',
+ fileKey: 'indexjs',
name: 'index',
path: 'index.js',
seed: 'some js',
tail: ''
},
- indexjsx: {
+ {
contents: 'some jsx',
error: null,
ext: 'jsx',
head: '',
history: ['index.jsx'],
- key: 'indexjsx',
+ fileKey: 'indexjsx',
name: 'index',
path: 'index.jsx',
seed: 'some jsx',
tail: ''
}
-};
+];
diff --git a/utils/polyvinyl.js b/utils/polyvinyl.js
index 53f973056d..b22f921ee9 100644
--- a/utils/polyvinyl.js
+++ b/utils/polyvinyl.js
@@ -37,7 +37,7 @@ function createPoly({ name, ext, contents, history, ...rest } = {}) {
name,
ext,
path: name + '.' + ext,
- key: name + ext,
+ fileKey: name + ext,
contents,
error: null
};
@@ -81,7 +81,7 @@ function setExt(ext, poly) {
...poly,
ext,
path: poly.name + '.' + ext,
- key: poly.name + ext
+ fileKey: poly.name + ext
};
newPoly.history = [...poly.history, newPoly.path];
return newPoly;
diff --git a/utils/sort-files.js b/utils/sort-files.js
index 443cab4481..433a1a8e4d 100644
--- a/utils/sort-files.js
+++ b/utils/sort-files.js
@@ -1,5 +1,5 @@
exports.toSortedArray = function toSortedArray(challengeFiles) {
- const xs = Object.values(challengeFiles);
+ const xs = challengeFiles;
// TODO: refactor this to use an ext array ['html', 'js', 'css'] and loop over
// that.
xs.sort((a, b) => {
diff --git a/utils/sort-files.test.js b/utils/sort-files.test.js
index 234aff6979..bb17949c7f 100644
--- a/utils/sort-files.test.js
+++ b/utils/sort-files.test.js
@@ -9,14 +9,14 @@ describe('sort-files', () => {
});
it('should not modify the challenges', () => {
const sorted = toSortedArray(challengeFiles);
- const expected = Object.values(challengeFiles);
+ const expected = challengeFiles;
expect(sorted).toEqual(expect.arrayContaining(expected));
expect(sorted.length).toEqual(expected.length);
});
it('should sort the objects into html, js, css order', () => {
- const sorted = toSortedArray(challengeFiles);
- const sortedKeys = sorted.map(({ key }) => key);
+ const sorted = challengeFiles;
+ const sortedKeys = sorted.map(({ fileKey }) => fileKey);
const expected = ['indexhtml', 'indexjsx', 'indexjs', 'indexcss'];
expect(sortedKeys).toStrictEqual(expected);
});