mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
refactor(tools,client): remove head and tail logic (#66524)
This commit is contained in:
@@ -97,8 +97,6 @@ function formatChallengeData({
|
|||||||
name: 'script',
|
name: 'script',
|
||||||
ext: 'js',
|
ext: 'js',
|
||||||
contents: javascript.challengeFiles[0].contents,
|
contents: javascript.challengeFiles[0].contents,
|
||||||
head: '',
|
|
||||||
tail: '',
|
|
||||||
path: '',
|
path: '',
|
||||||
history: ['script.js'],
|
history: ['script.js'],
|
||||||
fileKey: 'scriptjs'
|
fileKey: 'scriptjs'
|
||||||
@@ -123,9 +121,7 @@ function formatChallengeData({
|
|||||||
ext: 'py',
|
ext: 'py',
|
||||||
name: 'main',
|
name: 'main',
|
||||||
contents: python.challengeFiles[0].contents,
|
contents: python.challengeFiles[0].contents,
|
||||||
head: '',
|
|
||||||
path: '',
|
path: '',
|
||||||
tail: '',
|
|
||||||
editableRegionBoundaries: [],
|
editableRegionBoundaries: [],
|
||||||
history: ['main.py']
|
history: ['main.py']
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,7 +211,6 @@ export type ChallengeNode = {
|
|||||||
fields: Fields;
|
fields: Fields;
|
||||||
fillInTheBlank: FillInTheBlank;
|
fillInTheBlank: FillInTheBlank;
|
||||||
forumTopicId: number;
|
forumTopicId: number;
|
||||||
head: string[];
|
|
||||||
hasEditableBoundaries: boolean;
|
hasEditableBoundaries: boolean;
|
||||||
helpCategory: string;
|
helpCategory: string;
|
||||||
hooks?: Hooks;
|
hooks?: Hooks;
|
||||||
@@ -245,7 +244,6 @@ export type ChallengeNode = {
|
|||||||
sourceInstanceName: string;
|
sourceInstanceName: string;
|
||||||
superOrder: number;
|
superOrder: number;
|
||||||
superBlock: SuperBlocks;
|
superBlock: SuperBlocks;
|
||||||
tail: string[];
|
|
||||||
template: string;
|
template: string;
|
||||||
tests: Test[];
|
tests: Test[];
|
||||||
title: string;
|
title: string;
|
||||||
@@ -548,11 +546,9 @@ export type ExperienceData = {
|
|||||||
export type FileKeyChallenge = {
|
export type FileKeyChallenge = {
|
||||||
contents: string;
|
contents: string;
|
||||||
ext: Ext;
|
ext: Ext;
|
||||||
head: string;
|
|
||||||
id: string;
|
id: string;
|
||||||
key: string;
|
key: string;
|
||||||
name: string;
|
name: string;
|
||||||
tail: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ChallengeFiles = ChallengeFile[] | null;
|
export type ChallengeFiles = ChallengeFile[] | null;
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ const jsChallenge = {
|
|||||||
fileKey: 'jsFileKey',
|
fileKey: 'jsFileKey',
|
||||||
name: 'name',
|
name: 'name',
|
||||||
ext: 'js' as const,
|
ext: 'js' as const,
|
||||||
head: 'head',
|
|
||||||
tail: 'tail',
|
|
||||||
history: [],
|
history: [],
|
||||||
seed: 'original js contents',
|
seed: 'original js contents',
|
||||||
path: 'index.js'
|
path: 'index.js'
|
||||||
@@ -22,8 +20,6 @@ const cssChallenge = {
|
|||||||
fileKey: 'cssFileKey',
|
fileKey: 'cssFileKey',
|
||||||
name: 'name',
|
name: 'name',
|
||||||
ext: 'css' as const,
|
ext: 'css' as const,
|
||||||
head: 'head',
|
|
||||||
tail: 'tail',
|
|
||||||
history: [],
|
history: [],
|
||||||
seed: 'original css contents',
|
seed: 'original css contents',
|
||||||
path: 'styles.css'
|
path: 'styles.css'
|
||||||
@@ -34,8 +30,6 @@ const htmlChallenge = {
|
|||||||
fileKey: 'htmlFileKey',
|
fileKey: 'htmlFileKey',
|
||||||
name: 'name',
|
name: 'name',
|
||||||
ext: 'html' as const,
|
ext: 'html' as const,
|
||||||
head: 'head',
|
|
||||||
tail: 'tail',
|
|
||||||
history: [],
|
history: [],
|
||||||
seed: 'original html contents',
|
seed: 'original html contents',
|
||||||
path: 'index.html'
|
path: 'index.html'
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ const defaultProps = {
|
|||||||
fields: {} as Fields,
|
fields: {} as Fields,
|
||||||
forumTopicId: 12345,
|
forumTopicId: 12345,
|
||||||
guideUrl: 'https://mockurl.com',
|
guideUrl: 'https://mockurl.com',
|
||||||
head: ['mockHead'],
|
|
||||||
hasEditableBoundaries: false,
|
hasEditableBoundaries: false,
|
||||||
helpCategory: 'mockHelpCategory',
|
helpCategory: 'mockHelpCategory',
|
||||||
id: 'mockId',
|
id: 'mockId',
|
||||||
@@ -70,7 +69,6 @@ const defaultProps = {
|
|||||||
sourceInstanceName: 'mockSourceInstanceName',
|
sourceInstanceName: 'mockSourceInstanceName',
|
||||||
superOrder: 1,
|
superOrder: 1,
|
||||||
superBlock: SuperBlocks.FullStackDeveloperV9,
|
superBlock: SuperBlocks.FullStackDeveloperV9,
|
||||||
tail: ['mockTail'],
|
|
||||||
template: 'mockTemplate',
|
template: 'mockTemplate',
|
||||||
tests: [] as Test[],
|
tests: [] as Test[],
|
||||||
title: 'mockTitle',
|
title: 'mockTitle',
|
||||||
|
|||||||
@@ -5,12 +5,10 @@ export const challengeFiles: ChallengeFile[] = [
|
|||||||
contents: 'some ts',
|
contents: 'some ts',
|
||||||
error: null,
|
error: null,
|
||||||
ext: 'ts',
|
ext: 'ts',
|
||||||
head: '',
|
|
||||||
history: ['index.ts'],
|
history: ['index.ts'],
|
||||||
fileKey: 'indexts',
|
fileKey: 'indexts',
|
||||||
name: 'index',
|
name: 'index',
|
||||||
seed: 'some ts',
|
seed: 'some ts',
|
||||||
tail: '',
|
|
||||||
editableRegionBoundaries: [],
|
editableRegionBoundaries: [],
|
||||||
usesMultifileEditor: true,
|
usesMultifileEditor: true,
|
||||||
path: 'index.ts'
|
path: 'index.ts'
|
||||||
@@ -19,12 +17,10 @@ export const challengeFiles: ChallengeFile[] = [
|
|||||||
contents: 'some css',
|
contents: 'some css',
|
||||||
error: null,
|
error: null,
|
||||||
ext: 'css',
|
ext: 'css',
|
||||||
head: '',
|
|
||||||
history: ['styles.css'],
|
history: ['styles.css'],
|
||||||
fileKey: 'stylescss',
|
fileKey: 'stylescss',
|
||||||
name: 'styles',
|
name: 'styles',
|
||||||
seed: 'some css',
|
seed: 'some css',
|
||||||
tail: '',
|
|
||||||
editableRegionBoundaries: [],
|
editableRegionBoundaries: [],
|
||||||
usesMultifileEditor: true,
|
usesMultifileEditor: true,
|
||||||
path: 'styles.css'
|
path: 'styles.css'
|
||||||
@@ -33,12 +29,10 @@ export const challengeFiles: ChallengeFile[] = [
|
|||||||
contents: 'some html',
|
contents: 'some html',
|
||||||
error: null,
|
error: null,
|
||||||
ext: 'html',
|
ext: 'html',
|
||||||
head: '',
|
|
||||||
history: ['index.html'],
|
history: ['index.html'],
|
||||||
fileKey: 'indexhtml',
|
fileKey: 'indexhtml',
|
||||||
name: 'index',
|
name: 'index',
|
||||||
seed: 'some html',
|
seed: 'some html',
|
||||||
tail: '',
|
|
||||||
editableRegionBoundaries: [],
|
editableRegionBoundaries: [],
|
||||||
usesMultifileEditor: true,
|
usesMultifileEditor: true,
|
||||||
path: 'index.html'
|
path: 'index.html'
|
||||||
@@ -47,12 +41,10 @@ export const challengeFiles: ChallengeFile[] = [
|
|||||||
contents: 'some js',
|
contents: 'some js',
|
||||||
error: null,
|
error: null,
|
||||||
ext: 'js',
|
ext: 'js',
|
||||||
head: '',
|
|
||||||
history: ['script.js'],
|
history: ['script.js'],
|
||||||
fileKey: 'scriptjs',
|
fileKey: 'scriptjs',
|
||||||
name: 'script',
|
name: 'script',
|
||||||
seed: 'some js',
|
seed: 'some js',
|
||||||
tail: '',
|
|
||||||
editableRegionBoundaries: [],
|
editableRegionBoundaries: [],
|
||||||
usesMultifileEditor: true,
|
usesMultifileEditor: true,
|
||||||
path: 'script.js'
|
path: 'script.js'
|
||||||
@@ -61,12 +53,10 @@ export const challengeFiles: ChallengeFile[] = [
|
|||||||
contents: 'some jsx',
|
contents: 'some jsx',
|
||||||
error: null,
|
error: null,
|
||||||
ext: 'jsx',
|
ext: 'jsx',
|
||||||
head: '',
|
|
||||||
history: ['index.jsx'],
|
history: ['index.jsx'],
|
||||||
fileKey: 'indexjsx',
|
fileKey: 'indexjsx',
|
||||||
name: 'index',
|
name: 'index',
|
||||||
seed: 'some jsx',
|
seed: 'some jsx',
|
||||||
tail: '',
|
|
||||||
editableRegionBoundaries: [],
|
editableRegionBoundaries: [],
|
||||||
usesMultifileEditor: true,
|
usesMultifileEditor: true,
|
||||||
path: 'index.jsx'
|
path: 'index.jsx'
|
||||||
@@ -75,12 +65,10 @@ export const challengeFiles: ChallengeFile[] = [
|
|||||||
contents: 'some tsx',
|
contents: 'some tsx',
|
||||||
error: null,
|
error: null,
|
||||||
ext: 'tsx',
|
ext: 'tsx',
|
||||||
head: '',
|
|
||||||
history: ['index.tsx'],
|
history: ['index.tsx'],
|
||||||
fileKey: 'indextsx',
|
fileKey: 'indextsx',
|
||||||
name: 'index',
|
name: 'index',
|
||||||
seed: 'some tsx',
|
seed: 'some tsx',
|
||||||
tail: '',
|
|
||||||
editableRegionBoundaries: [],
|
editableRegionBoundaries: [],
|
||||||
usesMultifileEditor: true,
|
usesMultifileEditor: true,
|
||||||
path: 'index.tsx'
|
path: 'index.tsx'
|
||||||
@@ -89,12 +77,10 @@ export const challengeFiles: ChallengeFile[] = [
|
|||||||
contents: '{\n "compilerOptions": {}\n}',
|
contents: '{\n "compilerOptions": {}\n}',
|
||||||
error: null,
|
error: null,
|
||||||
ext: 'json',
|
ext: 'json',
|
||||||
head: '',
|
|
||||||
history: ['tsconfig.json'],
|
history: ['tsconfig.json'],
|
||||||
fileKey: 'tsconfigjson',
|
fileKey: 'tsconfigjson',
|
||||||
name: 'tsconfig',
|
name: 'tsconfig',
|
||||||
seed: '{\n "compilerOptions": {}\n}',
|
seed: '{\n "compilerOptions": {}\n}',
|
||||||
tail: '',
|
|
||||||
editableRegionBoundaries: [],
|
editableRegionBoundaries: [],
|
||||||
usesMultifileEditor: true,
|
usesMultifileEditor: true,
|
||||||
path: 'tsconfig.json'
|
path: 'tsconfig.json'
|
||||||
|
|||||||
@@ -242,12 +242,6 @@ exports[`challenge schema > should not be changed without informing the mobile t
|
|||||||
"fileKey": {
|
"fileKey": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
"head": {
|
|
||||||
"allow": [
|
|
||||||
"",
|
|
||||||
],
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"history": {
|
"history": {
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
@@ -277,12 +271,6 @@ exports[`challenge schema > should not be changed without informing the mobile t
|
|||||||
],
|
],
|
||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
"tail": {
|
|
||||||
"allow": [
|
|
||||||
"",
|
|
||||||
],
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
},
|
},
|
||||||
@@ -2050,12 +2038,6 @@ exports[`challenge schema > should not be changed without informing the mobile t
|
|||||||
"fileKey": {
|
"fileKey": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
"head": {
|
|
||||||
"allow": [
|
|
||||||
"",
|
|
||||||
],
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"history": {
|
"history": {
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
@@ -2085,12 +2067,6 @@ exports[`challenge schema > should not be changed without informing the mobile t
|
|||||||
],
|
],
|
||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
"tail": {
|
|
||||||
"allow": [
|
|
||||||
"",
|
|
||||||
],
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ const fileJoi = Joi.object().keys({
|
|||||||
editableRegionBoundaries: [Joi.array().items(Joi.number())],
|
editableRegionBoundaries: [Joi.array().items(Joi.number())],
|
||||||
path: Joi.string(),
|
path: Joi.string(),
|
||||||
error: Joi.valid(null),
|
error: Joi.valid(null),
|
||||||
head: Joi.string().allow(''),
|
|
||||||
tail: Joi.string().allow(''),
|
|
||||||
seed: Joi.string().allow(''),
|
seed: Joi.string().allow(''),
|
||||||
contents: Joi.string().allow(''),
|
contents: Joi.string().allow(''),
|
||||||
id: Joi.string().allow(''),
|
id: Joi.string().allow(''),
|
||||||
|
|||||||
@@ -100,19 +100,14 @@ const dummyChallenge = {
|
|||||||
name: 'file1',
|
name: 'file1',
|
||||||
ext: 'js',
|
ext: 'js',
|
||||||
history: [],
|
history: [],
|
||||||
contents: 'console.log("Hello")',
|
contents: 'console.log("Hello")'
|
||||||
// head and tail should not be required, but they currently are
|
|
||||||
head: '',
|
|
||||||
tail: ''
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
spuriousProp: '2',
|
spuriousProp: '2',
|
||||||
name: 'file2',
|
name: 'file2',
|
||||||
ext: 'css',
|
ext: 'css',
|
||||||
history: [],
|
history: [],
|
||||||
contents: 'body { background: red; }',
|
contents: 'body { background: red; }'
|
||||||
head: '',
|
|
||||||
tail: ''
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -277,12 +277,7 @@ async function buildJSChallenge(
|
|||||||
challengeType,
|
challengeType,
|
||||||
build: toBuild
|
build: toBuild
|
||||||
.reduce(
|
.reduce(
|
||||||
(body, challengeFile) => [
|
(body, challengeFile) => [...body, challengeFile.contents],
|
||||||
...body,
|
|
||||||
challengeFile.head,
|
|
||||||
challengeFile.contents,
|
|
||||||
challengeFile.tail
|
|
||||||
],
|
|
||||||
[] as string[]
|
[] as string[]
|
||||||
)
|
)
|
||||||
.join('\n'),
|
.join('\n'),
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ import {
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
transformContents,
|
transformContents,
|
||||||
transformHeadTailAndContents,
|
|
||||||
compileHeadTail,
|
|
||||||
createSource
|
createSource
|
||||||
} from '@freecodecamp/shared/utils/polyvinyl';
|
} from '@freecodecamp/shared/utils/polyvinyl';
|
||||||
import { version } from '@freecodecamp/browser-scripts/package.json';
|
import { version } from '@freecodecamp/browser-scripts/package.json';
|
||||||
@@ -115,20 +113,14 @@ const getJSTranspiler = loopProtectOptions => async challengeFile => {
|
|||||||
await loadBabel();
|
await loadBabel();
|
||||||
await loadPresetEnv();
|
await loadPresetEnv();
|
||||||
const babelOptions = getBabelOptions(presetsJS, loopProtectOptions);
|
const babelOptions = getBabelOptions(presetsJS, loopProtectOptions);
|
||||||
return transformHeadTailAndContents(
|
return transformContents(babelTransformCode(babelOptions), challengeFile);
|
||||||
babelTransformCode(babelOptions),
|
|
||||||
challengeFile
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getJSXTranspiler = loopProtectOptions => async challengeFile => {
|
const getJSXTranspiler = loopProtectOptions => async challengeFile => {
|
||||||
await loadBabel();
|
await loadBabel();
|
||||||
await loadPresetReact();
|
await loadPresetReact();
|
||||||
const babelOptions = getBabelOptions(presetsJSX, loopProtectOptions);
|
const babelOptions = getBabelOptions(presetsJSX, loopProtectOptions);
|
||||||
return transformHeadTailAndContents(
|
return transformContents(babelTransformCode(babelOptions), challengeFile);
|
||||||
babelTransformCode(babelOptions),
|
|
||||||
challengeFile
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getJSXModuleTranspiler = loopProtectOptions => async challengeFile => {
|
const getJSXModuleTranspiler = loopProtectOptions => async challengeFile => {
|
||||||
@@ -147,8 +139,8 @@ const getTSTranspiler = loopProtectOptions => async challengeFile => {
|
|||||||
await loadBabel();
|
await loadBabel();
|
||||||
const babelOptions = getBabelOptions(presetsJS, loopProtectOptions);
|
const babelOptions = getBabelOptions(presetsJS, loopProtectOptions);
|
||||||
return flow(
|
return flow(
|
||||||
partial(transformHeadTailAndContents, compileTypeScriptCode),
|
partial(transformContents, compileTypeScriptCode),
|
||||||
partial(transformHeadTailAndContents, babelTransformCode(babelOptions))
|
partial(transformContents, babelTransformCode(babelOptions))
|
||||||
)(challengeFile);
|
)(challengeFile);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -162,8 +154,8 @@ const getTSXModuleTranspiler = loopProtectOptions => async challengeFile => {
|
|||||||
moduleId: 'index' // TODO: this should be dynamic
|
moduleId: 'index' // TODO: this should be dynamic
|
||||||
};
|
};
|
||||||
return flow(
|
return flow(
|
||||||
partial(transformHeadTailAndContents, compileTypeScriptCode),
|
partial(transformContents, compileTypeScriptCode),
|
||||||
partial(transformHeadTailAndContents, babelTransformCode(babelOptions))
|
partial(transformContents, babelTransformCode(babelOptions))
|
||||||
)(challengeFile);
|
)(challengeFile);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -413,8 +405,7 @@ const getHtmlTranspiler = scriptOptions =>
|
|||||||
export const getTransformers = loopProtectOptions => [
|
export const getTransformers = loopProtectOptions => [
|
||||||
createSource,
|
createSource,
|
||||||
replaceNBSP,
|
replaceNBSP,
|
||||||
createTranspiler(loopProtectOptions),
|
createTranspiler(loopProtectOptions)
|
||||||
partial(compileHeadTail, '')
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export const getMultifileJSXTransformers = loopProtectOptions => [
|
export const getMultifileJSXTransformers = loopProtectOptions => [
|
||||||
@@ -423,8 +414,4 @@ export const getMultifileJSXTransformers = loopProtectOptions => [
|
|||||||
createModuleTransformer(loopProtectOptions)
|
createModuleTransformer(loopProtectOptions)
|
||||||
];
|
];
|
||||||
|
|
||||||
export const getPythonTransformers = () => [
|
export const getPythonTransformers = () => [createSource, replaceNBSP];
|
||||||
createSource,
|
|
||||||
replaceNBSP,
|
|
||||||
partial(compileHeadTail, '')
|
|
||||||
];
|
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ export interface IncompleteChallengeFile {
|
|||||||
ext: Ext;
|
ext: Ext;
|
||||||
name: string;
|
name: string;
|
||||||
contents: string;
|
contents: string;
|
||||||
head?: string;
|
|
||||||
tail?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ChallengeFile extends IncompleteChallengeFile {
|
export interface ChallengeFile extends IncompleteChallengeFile {
|
||||||
@@ -15,8 +13,6 @@ export interface ChallengeFile extends IncompleteChallengeFile {
|
|||||||
editableContents?: string;
|
editableContents?: string;
|
||||||
usesMultifileEditor?: boolean;
|
usesMultifileEditor?: boolean;
|
||||||
error?: unknown;
|
error?: unknown;
|
||||||
head: string;
|
|
||||||
tail: string;
|
|
||||||
seed?: string;
|
seed?: string;
|
||||||
source?: string;
|
source?: string;
|
||||||
path: string;
|
path: string;
|
||||||
@@ -71,8 +67,6 @@ export function isPoly(poly: unknown): poly is ChallengeFile {
|
|||||||
'name' in poly &&
|
'name' in poly &&
|
||||||
'ext' in poly &&
|
'ext' in poly &&
|
||||||
'fileKey' in poly &&
|
'fileKey' in poly &&
|
||||||
'head' in poly &&
|
|
||||||
'tail' in poly &&
|
|
||||||
'history' in poly
|
'history' in poly
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -82,8 +76,6 @@ export function isPoly(poly: unknown): poly is ChallengeFile {
|
|||||||
typeof poly.name === 'string' &&
|
typeof poly.name === 'string' &&
|
||||||
exts.includes(poly.ext as Ext) &&
|
exts.includes(poly.ext as Ext) &&
|
||||||
typeof poly.fileKey === 'string' &&
|
typeof poly.fileKey === 'string' &&
|
||||||
typeof poly.head === 'string' &&
|
|
||||||
typeof poly.tail === 'string' &&
|
|
||||||
Array.isArray(poly.history);
|
Array.isArray(poly.history);
|
||||||
|
|
||||||
return hasProperties(poly) && hasCorrectTypes(poly);
|
return hasProperties(poly) && hasCorrectTypes(poly);
|
||||||
@@ -111,33 +103,11 @@ export function setContent(
|
|||||||
// database.
|
// database.
|
||||||
export function regenerateMissingProperties(file: IncompleteChallengeFile) {
|
export function regenerateMissingProperties(file: IncompleteChallengeFile) {
|
||||||
const newPath = file.name + '.' + file.ext;
|
const newPath = file.name + '.' + file.ext;
|
||||||
const newFile = {
|
return {
|
||||||
...file,
|
...file,
|
||||||
path: newPath,
|
path: newPath,
|
||||||
history: [newPath],
|
history: [newPath]
|
||||||
head: file.head ?? '',
|
|
||||||
tail: file.tail ?? ''
|
|
||||||
};
|
};
|
||||||
return newFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function clearHeadTail(polyP: Promise<ChallengeFile>) {
|
|
||||||
const poly = await polyP;
|
|
||||||
checkPoly(poly);
|
|
||||||
return {
|
|
||||||
...poly,
|
|
||||||
head: '',
|
|
||||||
tail: ''
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function compileHeadTail(padding = '', poly: ChallengeFile) {
|
|
||||||
return clearHeadTail(
|
|
||||||
transformContents(
|
|
||||||
() => [poly.head, poly.contents, poly.tail].join(padding),
|
|
||||||
poly
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Wrapper = (x: string) => Promise<string> | string;
|
type Wrapper = (x: string) => Promise<string> | string;
|
||||||
@@ -154,21 +124,6 @@ export async function transformContents(
|
|||||||
return newPoly;
|
return newPoly;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function transformHeadTailAndContents(
|
|
||||||
wrap: Wrapper,
|
|
||||||
polyP: ChallengeFile | Promise<ChallengeFile>
|
|
||||||
) {
|
|
||||||
const poly = await polyP;
|
|
||||||
const contents = await transformContents(wrap, poly);
|
|
||||||
const head = await wrap(poly.head);
|
|
||||||
const tail = await wrap(poly.tail);
|
|
||||||
return {
|
|
||||||
...contents,
|
|
||||||
head,
|
|
||||||
tail
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// createSource(poly: PolyVinyl) => PolyVinyl
|
// createSource(poly: PolyVinyl) => PolyVinyl
|
||||||
export function createSource<Rest>(
|
export function createSource<Rest>(
|
||||||
poly: Pick<ChallengeFile, 'contents' | 'source'> & Rest
|
poly: Pick<ChallengeFile, 'contents' | 'source'> & Rest
|
||||||
|
|||||||
@@ -10,11 +10,9 @@ const props = {
|
|||||||
contents: '',
|
contents: '',
|
||||||
editableRegionBoundaries: [0, 2],
|
editableRegionBoundaries: [0, 2],
|
||||||
ext: 'html',
|
ext: 'html',
|
||||||
head: '',
|
|
||||||
id: '',
|
id: '',
|
||||||
key: 'indexhtml',
|
key: 'indexhtml',
|
||||||
name: 'index',
|
name: 'index'
|
||||||
tail: ''
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
stepNum: 5,
|
stepNum: 5,
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ export interface ChallengeSeed {
|
|||||||
contents: string;
|
contents: string;
|
||||||
ext: string;
|
ext: string;
|
||||||
editableRegionBoundaries: number[];
|
editableRegionBoundaries: number[];
|
||||||
head?: string;
|
|
||||||
tail?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the base markdown for a step
|
// Build the base markdown for a step
|
||||||
@@ -56,20 +54,8 @@ function getStepTemplate({
|
|||||||
})
|
})
|
||||||
.join('\n');
|
.join('\n');
|
||||||
|
|
||||||
const seedHeads = challengeSeeds
|
|
||||||
.filter(({ head }) => head)
|
|
||||||
.map(({ ext, head }) => getCodeBlock(ext, head))
|
|
||||||
.join('\n');
|
|
||||||
|
|
||||||
const seedTails = challengeSeeds
|
|
||||||
.filter(({ tail }) => tail)
|
|
||||||
.map(({ ext, tail }) => getCodeBlock(ext, tail))
|
|
||||||
.join('\n');
|
|
||||||
|
|
||||||
const stepDescription = `step ${stepNum} instructions`;
|
const stepDescription = `step ${stepNum} instructions`;
|
||||||
const seedChallengeSection = getSeedSection(seedTexts, 'seed-contents');
|
const seedChallengeSection = getSeedSection(seedTexts, 'seed-contents');
|
||||||
const seedHeadSection = getSeedSection(seedHeads, 'before-user-code');
|
|
||||||
const seedTailSection = getSeedSection(seedTails, 'after-user-code');
|
|
||||||
|
|
||||||
const demoString = isFirstChallenge
|
const demoString = isFirstChallenge
|
||||||
? `
|
? `
|
||||||
@@ -99,10 +85,7 @@ ${stepDescription}
|
|||||||
Test 1
|
Test 1
|
||||||
|
|
||||||
${getCodeBlock('js')}
|
${getCodeBlock('js')}
|
||||||
# --seed--` +
|
# --seed--` + seedChallengeSection
|
||||||
seedChallengeSection +
|
|
||||||
seedHeadSection +
|
|
||||||
seedTailSection
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,12 +65,6 @@ assert(
|
|||||||
|
|
||||||
# --seed--
|
# --seed--
|
||||||
|
|
||||||
## --before-user-code--
|
|
||||||
|
|
||||||
```js
|
|
||||||
// this runs before the user's code is evaluated.
|
|
||||||
```
|
|
||||||
|
|
||||||
## --seed-contents--
|
## --seed-contents--
|
||||||
|
|
||||||
::id{#html-key}
|
::id{#html-key}
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
# --description--
|
|
||||||
|
|
||||||
Paragraph 1
|
|
||||||
|
|
||||||
```html
|
|
||||||
code example
|
|
||||||
```
|
|
||||||
|
|
||||||
# --instructions--
|
|
||||||
|
|
||||||
Paragraph 0
|
|
||||||
|
|
||||||
```html
|
|
||||||
code example 0
|
|
||||||
```
|
|
||||||
|
|
||||||
# --hints--
|
|
||||||
|
|
||||||
First hint
|
|
||||||
|
|
||||||
```js
|
|
||||||
// test code
|
|
||||||
```
|
|
||||||
|
|
||||||
Second hint with <code>code</code>
|
|
||||||
|
|
||||||
```js
|
|
||||||
// more test code
|
|
||||||
```
|
|
||||||
|
|
||||||
Third *hint* with <code>code</code> and `inline code`
|
|
||||||
|
|
||||||
```js
|
|
||||||
// more test code
|
|
||||||
if(let x of xs) {
|
|
||||||
console.log(x);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
# --seed--
|
|
||||||
|
|
||||||
## --before-user-code--
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
etc: ''
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!-- comment -->
|
|
||||||
```
|
|
||||||
|
|
||||||
## --seed-contents--
|
|
||||||
|
|
||||||
```html
|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: green;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
var x = 'y';
|
|
||||||
```
|
|
||||||
|
|
||||||
## --after-user-code--
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: blue;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
function teardown(params) {
|
|
||||||
// after
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
# --solutions--
|
|
||||||
|
|
||||||
::id{#html-key}
|
|
||||||
|
|
||||||
```html
|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
var x = 'y';
|
|
||||||
```
|
|
||||||
@@ -1,17 +1,5 @@
|
|||||||
# --seed--
|
# --seed--
|
||||||
|
|
||||||
## --before-user-code--
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
etc: ''
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!-- comment -->
|
|
||||||
```
|
|
||||||
|
|
||||||
## --seed-contents--
|
## --seed-contents--
|
||||||
|
|
||||||
```html
|
```html
|
||||||
@@ -31,20 +19,6 @@ body {
|
|||||||
var x = 'y';
|
var x = 'y';
|
||||||
```
|
```
|
||||||
|
|
||||||
## --after-user-code--
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: blue;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
function teardown(params) {
|
|
||||||
// after
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
# --solutions--
|
# --solutions--
|
||||||
|
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
# --description--
|
|
||||||
|
|
||||||
Paragraph 1
|
|
||||||
|
|
||||||
```html
|
|
||||||
code example
|
|
||||||
```
|
|
||||||
|
|
||||||
# --instructions--
|
|
||||||
|
|
||||||
Paragraph 0
|
|
||||||
|
|
||||||
```html
|
|
||||||
code example 0
|
|
||||||
```
|
|
||||||
|
|
||||||
# --hints--
|
|
||||||
|
|
||||||
First hint
|
|
||||||
|
|
||||||
```js
|
|
||||||
// test code
|
|
||||||
```
|
|
||||||
|
|
||||||
Second hint with <code>code</code>
|
|
||||||
|
|
||||||
```js
|
|
||||||
// more test code
|
|
||||||
```
|
|
||||||
|
|
||||||
Third *hint* with <code>code</code> and `inline code`
|
|
||||||
|
|
||||||
```js
|
|
||||||
// more test code
|
|
||||||
if(let x of xs) {
|
|
||||||
console.log(x);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
# --seed--
|
|
||||||
|
|
||||||
## --before-user-code--
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
etc: ''
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!-- comment -->
|
|
||||||
```
|
|
||||||
|
|
||||||
## --seed-contents--
|
|
||||||
|
|
||||||
```html
|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: green;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
var x = 'y';
|
|
||||||
```
|
|
||||||
|
|
||||||
## --after-user-code--
|
|
||||||
|
|
||||||
|
|
||||||
# --solutions--
|
|
||||||
|
|
||||||
::id{#html-key}
|
|
||||||
|
|
||||||
```html
|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
var x = 'y';
|
|
||||||
```
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# --description--
|
|
||||||
|
|
||||||
Paragraph 1
|
|
||||||
|
|
||||||
```html
|
|
||||||
code example
|
|
||||||
```
|
|
||||||
|
|
||||||
# --before-all--
|
|
||||||
|
|
||||||
# --hints--
|
|
||||||
|
|
||||||
First hint
|
|
||||||
|
|
||||||
```js
|
|
||||||
// test code
|
|
||||||
```
|
|
||||||
|
|
||||||
Second hint with <code>code</code>
|
|
||||||
|
|
||||||
```js
|
|
||||||
// more test code
|
|
||||||
```
|
|
||||||
|
|
||||||
Third *hint* with <code>code</code> and `inline code`
|
|
||||||
|
|
||||||
```js
|
|
||||||
// more test code
|
|
||||||
if(let x of xs) {
|
|
||||||
console.log(x);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
# --description--
|
|
||||||
|
|
||||||
Paragraph 1
|
|
||||||
|
|
||||||
```html
|
|
||||||
code example
|
|
||||||
```
|
|
||||||
|
|
||||||
# --instructions--
|
|
||||||
|
|
||||||
Paragraph 0
|
|
||||||
|
|
||||||
```html
|
|
||||||
code example 0
|
|
||||||
```
|
|
||||||
|
|
||||||
# --hints--
|
|
||||||
|
|
||||||
First hint
|
|
||||||
|
|
||||||
```js
|
|
||||||
// test code
|
|
||||||
```
|
|
||||||
|
|
||||||
Second hint with <code>code</code>
|
|
||||||
|
|
||||||
```js
|
|
||||||
// more test code
|
|
||||||
```
|
|
||||||
|
|
||||||
Third *hint* with <code>code</code> and `inline code`
|
|
||||||
|
|
||||||
```js
|
|
||||||
// more test code
|
|
||||||
if(let x of xs) {
|
|
||||||
console.log(x);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
# --seed--
|
|
||||||
|
|
||||||
## --before-user-code--
|
|
||||||
|
|
||||||
## --seed-contents--
|
|
||||||
|
|
||||||
```html
|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: green;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
var x = 'y';
|
|
||||||
```
|
|
||||||
|
|
||||||
## --after-user-code--
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: blue;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
function teardown(params) {
|
|
||||||
// after
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
# --solutions--
|
|
||||||
|
|
||||||
::id{#html-key}
|
|
||||||
|
|
||||||
```html
|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
var x = 'y';
|
|
||||||
```
|
|
||||||
@@ -39,31 +39,7 @@ if(let x of xs) {
|
|||||||
|
|
||||||
# --seed--
|
# --seed--
|
||||||
|
|
||||||
## --before-user-code--
|
This section intentionally has no `## --seed-contents--`.
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
etc: ''
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!-- comment -->
|
|
||||||
```
|
|
||||||
|
|
||||||
## --after-user-code--
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: blue;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
function teardown(params) {
|
|
||||||
// after
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
# --solutions--
|
# --solutions--
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
# --description--
|
|
||||||
|
|
||||||
Paragraph 1
|
|
||||||
|
|
||||||
```html
|
|
||||||
code example
|
|
||||||
```
|
|
||||||
|
|
||||||
# --instructions--
|
|
||||||
|
|
||||||
Paragraph 0
|
|
||||||
|
|
||||||
```html
|
|
||||||
code example 0
|
|
||||||
```
|
|
||||||
|
|
||||||
# --hints--
|
|
||||||
|
|
||||||
First hint
|
|
||||||
|
|
||||||
```js
|
|
||||||
// test code
|
|
||||||
```
|
|
||||||
|
|
||||||
Second hint with <code>code</code>
|
|
||||||
|
|
||||||
```js
|
|
||||||
// more test code
|
|
||||||
```
|
|
||||||
|
|
||||||
Third *hint* with <code>code</code> and `inline code`
|
|
||||||
|
|
||||||
```js
|
|
||||||
// more test code
|
|
||||||
if(let x of xs) {
|
|
||||||
console.log(x);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
# --seed--
|
|
||||||
|
|
||||||
## --before-user-code--
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
etc: ''
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!-- comment -->
|
|
||||||
```
|
|
||||||
|
|
||||||
## --seed-contents--
|
|
||||||
|
|
||||||
```html
|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: green;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
var x = 'y';
|
|
||||||
```
|
|
||||||
|
|
||||||
## --after-user-code--
|
|
||||||
|
|
||||||
```css
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
function teardown(params) {
|
|
||||||
// after
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
# --solutions--
|
|
||||||
|
|
||||||
::id{#html-key}
|
|
||||||
|
|
||||||
```html
|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
var x = 'y';
|
|
||||||
```
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
# --description--
|
|
||||||
|
|
||||||
Paragraph 1
|
|
||||||
|
|
||||||
```html
|
|
||||||
code example
|
|
||||||
```
|
|
||||||
|
|
||||||
# --instructions--
|
|
||||||
|
|
||||||
Paragraph 0
|
|
||||||
|
|
||||||
```html
|
|
||||||
code example 0
|
|
||||||
```
|
|
||||||
|
|
||||||
# --hints--
|
|
||||||
|
|
||||||
First hint
|
|
||||||
|
|
||||||
```js
|
|
||||||
// test code
|
|
||||||
```
|
|
||||||
|
|
||||||
Second hint with <code>code</code>
|
|
||||||
|
|
||||||
```js
|
|
||||||
// more test code
|
|
||||||
```
|
|
||||||
|
|
||||||
Third *hint* with <code>code</code> and `inline code`
|
|
||||||
|
|
||||||
```js
|
|
||||||
// more test code
|
|
||||||
if(let x of xs) {
|
|
||||||
console.log(x);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
# --seed--
|
|
||||||
|
|
||||||
## --before-user-code--
|
|
||||||
|
|
||||||
```css
|
|
||||||
```
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!-- comment -->
|
|
||||||
```
|
|
||||||
|
|
||||||
## --seed-contents--
|
|
||||||
|
|
||||||
```html
|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: green;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
var x = 'y';
|
|
||||||
```
|
|
||||||
|
|
||||||
## --after-user-code--
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: blue;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
function teardown(params) {
|
|
||||||
// after
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
# --solutions--
|
|
||||||
|
|
||||||
::id{#html-key}
|
|
||||||
|
|
||||||
```html
|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
var x = 'y';
|
|
||||||
```
|
|
||||||
@@ -1,17 +1,5 @@
|
|||||||
# --seed--
|
# --seed--
|
||||||
|
|
||||||
## --before-user-code--
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
etc: ''
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!-- comment -->
|
|
||||||
```
|
|
||||||
|
|
||||||
## --seed-contents--
|
## --seed-contents--
|
||||||
|
|
||||||
```html
|
```html
|
||||||
@@ -31,20 +19,6 @@ body {
|
|||||||
var x = 'y';
|
var x = 'y';
|
||||||
```
|
```
|
||||||
|
|
||||||
## --after-user-code--
|
|
||||||
|
|
||||||
```css
|
|
||||||
body {
|
|
||||||
background: blue;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
function teardown(params) {
|
|
||||||
// after
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
# --solutions--
|
# --solutions--
|
||||||
|
|
||||||
|
|||||||
@@ -27,17 +27,3 @@ const Button = () => {
|
|||||||
return <button> {/* another comment! */} text </button>;
|
return <button> {/* another comment! */} text </button>;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## --before-user-code--
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
function setup() {}
|
|
||||||
```
|
|
||||||
|
|
||||||
## --after-user-code--
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
function teardown(params) {
|
|
||||||
// after
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -11,10 +11,8 @@ exports[`challenge parser > should import md from other files 1`] = `
|
|||||||
</html>",
|
</html>",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "html",
|
"ext": "html",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "index",
|
"name": "index",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "body {
|
"contents": "body {
|
||||||
@@ -22,10 +20,8 @@ exports[`challenge parser > should import md from other files 1`] = `
|
|||||||
}",
|
}",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "css",
|
"ext": "css",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "styles",
|
"name": "styles",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "var x = 'y';
|
"contents": "var x = 'y';
|
||||||
@@ -35,10 +31,8 @@ for (let index = 0; index < array.length; index++) {
|
|||||||
}",
|
}",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "js",
|
"ext": "js",
|
||||||
"head": "",
|
|
||||||
"id": "custom-name",
|
"id": "custom-name",
|
||||||
"name": "script",
|
"name": "script",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"description": "<section id="description">
|
"description": "<section id="description">
|
||||||
@@ -76,10 +70,8 @@ exports[`challenge parser > should not mix other YAML with the frontmatter 1`] =
|
|||||||
</html>",
|
</html>",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "html",
|
"ext": "html",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "index",
|
"name": "index",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "body {
|
"contents": "body {
|
||||||
@@ -87,19 +79,15 @@ exports[`challenge parser > should not mix other YAML with the frontmatter 1`] =
|
|||||||
}",
|
}",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "css",
|
"ext": "css",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "styles",
|
"name": "styles",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "var x = 'y';",
|
"contents": "var x = 'y';",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "js",
|
"ext": "js",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "script",
|
"name": "script",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"description": "<section id="description">
|
"description": "<section id="description">
|
||||||
@@ -183,10 +171,8 @@ exports[`challenge parser > should parse a more realistic md file 1`] = `
|
|||||||
23,
|
23,
|
||||||
],
|
],
|
||||||
"ext": "html",
|
"ext": "html",
|
||||||
"head": "",
|
|
||||||
"id": "html-key",
|
"id": "html-key",
|
||||||
"name": "index",
|
"name": "index",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "body {
|
"contents": "body {
|
||||||
@@ -206,19 +192,15 @@ a {
|
|||||||
9,
|
9,
|
||||||
],
|
],
|
||||||
"ext": "css",
|
"ext": "css",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "styles",
|
"name": "styles",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "var x = 'y';",
|
"contents": "var x = 'y';",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "js",
|
"ext": "js",
|
||||||
"head": " // this runs before the user's code is evaluated.",
|
|
||||||
"id": "final-key",
|
"id": "final-key",
|
||||||
"name": "script",
|
"name": "script",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"description": "<section id="description">
|
"description": "<section id="description">
|
||||||
@@ -265,10 +247,8 @@ a {
|
|||||||
</body>
|
</body>
|
||||||
</html>",
|
</html>",
|
||||||
"ext": "html",
|
"ext": "html",
|
||||||
"head": "",
|
|
||||||
"id": "html-key",
|
"id": "html-key",
|
||||||
"name": "index",
|
"name": "index",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "body {
|
"contents": "body {
|
||||||
@@ -284,18 +264,14 @@ a {
|
|||||||
color: green;
|
color: green;
|
||||||
}",
|
}",
|
||||||
"ext": "css",
|
"ext": "css",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "styles",
|
"name": "styles",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "var x = 'y';",
|
"contents": "var x = 'y';",
|
||||||
"ext": "js",
|
"ext": "js",
|
||||||
"head": "",
|
|
||||||
"id": "final-key",
|
"id": "final-key",
|
||||||
"name": "script",
|
"name": "script",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
@@ -349,10 +325,8 @@ exports[`challenge parser > should parse a simple md file 1`] = `
|
|||||||
</html>",
|
</html>",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "html",
|
"ext": "html",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "index",
|
"name": "index",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "body {
|
"contents": "body {
|
||||||
@@ -360,19 +334,15 @@ exports[`challenge parser > should parse a simple md file 1`] = `
|
|||||||
}",
|
}",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "css",
|
"ext": "css",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "styles",
|
"name": "styles",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "var x = 'y';",
|
"contents": "var x = 'y';",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "js",
|
"ext": "js",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "script",
|
"name": "script",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "{
|
"contents": "{
|
||||||
@@ -382,10 +352,8 @@ exports[`challenge parser > should parse a simple md file 1`] = `
|
|||||||
}",
|
}",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "json",
|
"ext": "json",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "tsconfig",
|
"name": "tsconfig",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"description": "<section id="description">
|
"description": "<section id="description">
|
||||||
@@ -406,28 +374,22 @@ exports[`challenge parser > should parse a simple md file 1`] = `
|
|||||||
</body>
|
</body>
|
||||||
</html>",
|
</html>",
|
||||||
"ext": "html",
|
"ext": "html",
|
||||||
"head": "",
|
|
||||||
"id": "html-key",
|
"id": "html-key",
|
||||||
"name": "index",
|
"name": "index",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "body {
|
"contents": "body {
|
||||||
background: white;
|
background: white;
|
||||||
}",
|
}",
|
||||||
"ext": "css",
|
"ext": "css",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "styles",
|
"name": "styles",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "var x = 'y';",
|
"contents": "var x = 'y';",
|
||||||
"ext": "js",
|
"ext": "js",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "script",
|
"name": "script",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
@@ -462,10 +424,8 @@ exports[`challenge parser > should parse frontmatter 1`] = `
|
|||||||
</html>",
|
</html>",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "html",
|
"ext": "html",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "index",
|
"name": "index",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "body {
|
"contents": "body {
|
||||||
@@ -473,19 +433,15 @@ exports[`challenge parser > should parse frontmatter 1`] = `
|
|||||||
}",
|
}",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "css",
|
"ext": "css",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "styles",
|
"name": "styles",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "var x = 'y';",
|
"contents": "var x = 'y';",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "js",
|
"ext": "js",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "script",
|
"name": "script",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"challengeType": 0,
|
"challengeType": 0,
|
||||||
@@ -524,10 +480,8 @@ exports[`challenge parser > should parse gfm strikethrough and frontmatter 1`] =
|
|||||||
</html>",
|
</html>",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "html",
|
"ext": "html",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "index",
|
"name": "index",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "body {
|
"contents": "body {
|
||||||
@@ -535,19 +489,15 @@ exports[`challenge parser > should parse gfm strikethrough and frontmatter 1`] =
|
|||||||
}",
|
}",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "css",
|
"ext": "css",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "styles",
|
"name": "styles",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "var x = 'y';",
|
"contents": "var x = 'y';",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "js",
|
"ext": "js",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "script",
|
"name": "script",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"description": "<section id="description">
|
"description": "<section id="description">
|
||||||
@@ -582,28 +532,22 @@ exports[`challenge parser > should parse gfm strikethrough and frontmatter 1`] =
|
|||||||
</body>
|
</body>
|
||||||
</html>",
|
</html>",
|
||||||
"ext": "html",
|
"ext": "html",
|
||||||
"head": "",
|
|
||||||
"id": "html-key",
|
"id": "html-key",
|
||||||
"name": "index",
|
"name": "index",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "body {
|
"contents": "body {
|
||||||
background: white;
|
background: white;
|
||||||
}",
|
}",
|
||||||
"ext": "css",
|
"ext": "css",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "styles",
|
"name": "styles",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "var x = 'y';",
|
"contents": "var x = 'y';",
|
||||||
"ext": "js",
|
"ext": "js",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "script",
|
"name": "script",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|||||||
-2
@@ -6,8 +6,6 @@ type ChallengeFile = {
|
|||||||
contents: string;
|
contents: string;
|
||||||
ext: string;
|
ext: string;
|
||||||
editableRegionBoundaries: number[];
|
editableRegionBoundaries: number[];
|
||||||
head?: string;
|
|
||||||
tail?: string;
|
|
||||||
};
|
};
|
||||||
export interface ParsedChallenge {
|
export interface ParsedChallenge {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -10,10 +10,8 @@ exports[`add-seed plugin > should have an output to match the snapshot 1`] = `
|
|||||||
</html>",
|
</html>",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "html",
|
"ext": "html",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "index",
|
"name": "index",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "body {
|
"contents": "body {
|
||||||
@@ -21,19 +19,15 @@ exports[`add-seed plugin > should have an output to match the snapshot 1`] = `
|
|||||||
}",
|
}",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "css",
|
"ext": "css",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "styles",
|
"name": "styles",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "var x = 'y';",
|
"contents": "var x = 'y';",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "js",
|
"ext": "js",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "script",
|
"name": "script",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "{
|
"contents": "{
|
||||||
@@ -43,10 +37,8 @@ exports[`add-seed plugin > should have an output to match the snapshot 1`] = `
|
|||||||
}",
|
}",
|
||||||
"editableRegionBoundaries": [],
|
"editableRegionBoundaries": [],
|
||||||
"ext": "json",
|
"ext": "json",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "tsconfig",
|
"name": "tsconfig",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,28 +10,22 @@ exports[`add solution plugin > should have an output to match the snapshot 1`] =
|
|||||||
</body>
|
</body>
|
||||||
</html>",
|
</html>",
|
||||||
"ext": "html",
|
"ext": "html",
|
||||||
"head": "",
|
|
||||||
"id": "html-key",
|
"id": "html-key",
|
||||||
"name": "index",
|
"name": "index",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "body {
|
"contents": "body {
|
||||||
background: white;
|
background: white;
|
||||||
}",
|
}",
|
||||||
"ext": "css",
|
"ext": "css",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "styles",
|
"name": "styles",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contents": "var x = 'y';",
|
"contents": "var x = 'y';",
|
||||||
"ext": "js",
|
"ext": "js",
|
||||||
"head": "",
|
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "script",
|
"name": "script",
|
||||||
"tail": "",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -38,22 +38,17 @@ function addSeeds() {
|
|||||||
// processing in these cases.
|
// processing in these cases.
|
||||||
if (isEmpty(seedTree.children)) return;
|
if (isEmpty(seedTree.children)) return;
|
||||||
const contentsTree = root(getSection(seedTree, `--seed-contents--`));
|
const contentsTree = root(getSection(seedTree, `--seed-contents--`));
|
||||||
const headTree = root(getSection(seedTree, `--before-user-code--`));
|
|
||||||
const tailTree = root(getSection(seedTree, `--after-user-code--`));
|
|
||||||
const seeds = {};
|
const seeds = {};
|
||||||
|
|
||||||
// While before and after code are optional, the contents are not
|
// Seed contents are required.
|
||||||
if (isEmpty(contentsTree.children))
|
if (isEmpty(contentsTree.children))
|
||||||
throw Error('## --seed-contents-- must appear in # --seed-- sections');
|
throw Error('## --seed-contents-- must appear in # --seed-- sections');
|
||||||
|
|
||||||
const visitForContents = visitChildren(
|
const visitForContents = visitChildren(
|
||||||
getFileVisitor(seeds, 'contents', validateEditableMarkers)
|
getFileVisitor(seeds, 'contents', validateEditableMarkers)
|
||||||
);
|
);
|
||||||
const visitForHead = visitChildren(getFileVisitor(seeds, 'head'));
|
|
||||||
const visitForTail = visitChildren(getFileVisitor(seeds, 'tail'));
|
|
||||||
visitForContents(contentsTree);
|
visitForContents(contentsTree);
|
||||||
visitForHead(headTree);
|
|
||||||
visitForTail(tailTree);
|
|
||||||
const seedVals = Object.values(seeds);
|
const seedVals = Object.values(seeds);
|
||||||
file.data = {
|
file.data = {
|
||||||
...file.data,
|
...file.data,
|
||||||
|
|||||||
@@ -7,14 +7,9 @@ import addSeed from './add-seed';
|
|||||||
describe('add-seed plugin', () => {
|
describe('add-seed plugin', () => {
|
||||||
let adjacentKeysAST,
|
let adjacentKeysAST,
|
||||||
withSeedKeysAST,
|
withSeedKeysAST,
|
||||||
withBeforeAfterAST,
|
|
||||||
cCodeAST,
|
cCodeAST,
|
||||||
withErmsOnOneLineAST,
|
withErmsOnOneLineAST,
|
||||||
withEmptyAfterAST,
|
|
||||||
withEmptyBeforeAST,
|
|
||||||
withEmptyContentsAST,
|
withEmptyContentsAST,
|
||||||
withInvalidBeforeAST,
|
|
||||||
withInvalidAfterAST,
|
|
||||||
simpleAST,
|
simpleAST,
|
||||||
withEditableMarkersAST,
|
withEditableMarkersAST,
|
||||||
withSeedKeysOrphanAST,
|
withSeedKeysOrphanAST,
|
||||||
@@ -27,16 +22,11 @@ describe('add-seed plugin', () => {
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
adjacentKeysAST = await parseFixture('with-seed-keys-adjacent.md');
|
adjacentKeysAST = await parseFixture('with-seed-keys-adjacent.md');
|
||||||
withSeedKeysAST = await parseFixture('with-seed-keys.md');
|
withSeedKeysAST = await parseFixture('with-seed-keys.md');
|
||||||
withBeforeAfterAST = await parseFixture('with-before-and-after.md');
|
|
||||||
cCodeAST = await parseFixture('with-c-code.md');
|
cCodeAST = await parseFixture('with-c-code.md');
|
||||||
withErmsOnOneLineAST = await parseFixture(
|
withErmsOnOneLineAST = await parseFixture(
|
||||||
'with-editable-markers-on-one-line.md'
|
'with-editable-markers-on-one-line.md'
|
||||||
);
|
);
|
||||||
withEmptyAfterAST = await parseFixture('with-empty-after.md');
|
|
||||||
withEmptyBeforeAST = await parseFixture('with-empty-before.md');
|
|
||||||
withEmptyContentsAST = await parseFixture('with-empty-contents.md');
|
withEmptyContentsAST = await parseFixture('with-empty-contents.md');
|
||||||
withInvalidBeforeAST = await parseFixture('with-invalid-before.md');
|
|
||||||
withInvalidAfterAST = await parseFixture('with-invalid-after.md');
|
|
||||||
simpleAST = await parseFixture('simple.md');
|
simpleAST = await parseFixture('simple.md');
|
||||||
withEditableMarkersAST = await parseFixture('with-editable-markers.md');
|
withEditableMarkersAST = await parseFixture('with-editable-markers.md');
|
||||||
withSeedKeysOrphanAST = await parseFixture('with-seed-keys-orphan.md');
|
withSeedKeysOrphanAST = await parseFixture('with-seed-keys-orphan.md');
|
||||||
@@ -65,23 +55,19 @@ describe('add-seed plugin', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('adds test objects to the challengeFiles array following a schema', () => {
|
it('adds test objects to the challengeFiles array following a schema', () => {
|
||||||
expect.assertions(15);
|
expect.assertions(11);
|
||||||
plugin(simpleAST, file);
|
plugin(simpleAST, file);
|
||||||
const {
|
const {
|
||||||
data: { challengeFiles }
|
data: { challengeFiles }
|
||||||
} = file;
|
} = file;
|
||||||
const testObject = challengeFiles.find(x => x.ext === 'js');
|
const testObject = challengeFiles.find(x => x.ext === 'js');
|
||||||
expect(Object.keys(testObject).length).toEqual(7);
|
expect(Object.keys(testObject).length).toEqual(5);
|
||||||
expect(testObject).toHaveProperty('ext');
|
expect(testObject).toHaveProperty('ext');
|
||||||
expect(typeof testObject['ext']).toBe('string');
|
expect(typeof testObject['ext']).toBe('string');
|
||||||
expect(testObject).toHaveProperty('name');
|
expect(testObject).toHaveProperty('name');
|
||||||
expect(typeof testObject['name']).toBe('string');
|
expect(typeof testObject['name']).toBe('string');
|
||||||
expect(testObject).toHaveProperty('contents');
|
expect(testObject).toHaveProperty('contents');
|
||||||
expect(typeof testObject['contents']).toBe('string');
|
expect(typeof testObject['contents']).toBe('string');
|
||||||
expect(testObject).toHaveProperty('head');
|
|
||||||
expect(typeof testObject['head']).toBe('string');
|
|
||||||
expect(testObject).toHaveProperty('tail');
|
|
||||||
expect(typeof testObject['tail']).toBe('string');
|
|
||||||
expect(testObject).toHaveProperty('id');
|
expect(testObject).toHaveProperty('id');
|
||||||
expect(typeof testObject['id']).toBe('string');
|
expect(typeof testObject['id']).toBe('string');
|
||||||
expect(testObject).toHaveProperty('editableRegionBoundaries');
|
expect(testObject).toHaveProperty('editableRegionBoundaries');
|
||||||
@@ -155,96 +141,14 @@ describe('add-seed plugin', () => {
|
|||||||
expect(file).toEqual(fileTwo);
|
expect(file).toEqual(fileTwo);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gets the before-user-code for each language', () => {
|
|
||||||
expect.assertions(3);
|
|
||||||
plugin(withBeforeAfterAST, file);
|
|
||||||
const {
|
|
||||||
data: { challengeFiles }
|
|
||||||
} = file;
|
|
||||||
const scriptjs = challengeFiles.find(x => x.ext === 'js');
|
|
||||||
const indexhtml = challengeFiles.find(x => x.ext === 'html');
|
|
||||||
const stylescss = challengeFiles.find(x => x.ext === 'css');
|
|
||||||
|
|
||||||
expect(scriptjs.head).toBe('');
|
|
||||||
expect(indexhtml.head).toBe(`<!-- comment -->`);
|
|
||||||
expect(stylescss.head).toBe(`body {
|
|
||||||
etc: ''
|
|
||||||
}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('gets the after-user-code for each language', () => {
|
|
||||||
expect.assertions(3);
|
|
||||||
plugin(withBeforeAfterAST, file);
|
|
||||||
const {
|
|
||||||
data: { challengeFiles }
|
|
||||||
} = file;
|
|
||||||
const scriptjs = challengeFiles.find(x => x.ext === 'js');
|
|
||||||
const indexhtml = challengeFiles.find(x => x.ext === 'html');
|
|
||||||
const stylescss = challengeFiles.find(x => x.ext === 'css');
|
|
||||||
|
|
||||||
expect(scriptjs.tail).toBe(`function teardown(params) {
|
|
||||||
// after
|
|
||||||
}`);
|
|
||||||
expect(indexhtml.tail).toBe('');
|
|
||||||
expect(stylescss.tail).toBe(`body {
|
|
||||||
background: blue;
|
|
||||||
}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throws an error if there is any code of an unsupported language', () => {
|
it('throws an error if there is any code of an unsupported language', () => {
|
||||||
expect.assertions(1);
|
expect.assertions(1);
|
||||||
expect(() => plugin(cCodeAST, file)).toThrow(
|
expect(() => plugin(cCodeAST, file)).toThrow(
|
||||||
"On line 30 'c' is not a supported language.\n" +
|
"On line 18 'c' is not a supported language.\n" +
|
||||||
' Please use one of js, css, html, jsx, ts, tsx or py'
|
' Please use one of js, css, html, jsx, ts, tsx or py'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws if there is before/after code with empty blocks', () => {
|
|
||||||
expect.assertions(2);
|
|
||||||
expect(() => plugin(withInvalidBeforeAST, file)).toThrow(
|
|
||||||
'Empty code block in --before-user-code-- section'
|
|
||||||
);
|
|
||||||
expect(() => plugin(withInvalidAfterAST, file)).toThrow(
|
|
||||||
'Empty code block in --after-user-code-- section'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('quietly ignores empty before sections', () => {
|
|
||||||
expect.assertions(6);
|
|
||||||
plugin(withEmptyBeforeAST, file);
|
|
||||||
const {
|
|
||||||
data: { challengeFiles }
|
|
||||||
} = file;
|
|
||||||
const scriptjs = challengeFiles.find(x => x.ext === 'js');
|
|
||||||
const indexhtml = challengeFiles.find(x => x.ext === 'html');
|
|
||||||
const stylescss = challengeFiles.find(x => x.ext === 'css');
|
|
||||||
|
|
||||||
expect(scriptjs.head).toBe('');
|
|
||||||
expect(scriptjs.tail).toBe('function teardown(params) {\n // after\n}');
|
|
||||||
expect(indexhtml.head).toBe('');
|
|
||||||
expect(indexhtml.tail).toBe('');
|
|
||||||
expect(stylescss.head).toBe('');
|
|
||||||
expect(stylescss.tail).toBe('body {\n background: blue;\n}');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('quietly ignores empty after sections', () => {
|
|
||||||
expect.assertions(6);
|
|
||||||
plugin(withEmptyAfterAST, file);
|
|
||||||
const {
|
|
||||||
data: { challengeFiles }
|
|
||||||
} = file;
|
|
||||||
const scriptjs = challengeFiles.find(x => x.ext === 'js');
|
|
||||||
const indexhtml = challengeFiles.find(x => x.ext === 'html');
|
|
||||||
const stylescss = challengeFiles.find(x => x.ext === 'css');
|
|
||||||
|
|
||||||
expect(scriptjs.head).toBe('');
|
|
||||||
expect(scriptjs.tail).toBe('');
|
|
||||||
expect(indexhtml.head).toBe('<!-- comment -->');
|
|
||||||
expect(indexhtml.tail).toBe('');
|
|
||||||
expect(stylescss.head).toBe("body {\n etc: ''\n}");
|
|
||||||
expect(stylescss.tail).toBe('');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throws an error (with line number) if 2 markers appear on 1 line', () => {
|
it('throws an error (with line number) if 2 markers appear on 1 line', () => {
|
||||||
expect.assertions(1);
|
expect.assertions(1);
|
||||||
expect(() => plugin(withErmsOnOneLineAST, file)).toThrow(
|
expect(() => plugin(withErmsOnOneLineAST, file)).toThrow(
|
||||||
@@ -253,17 +157,13 @@ describe('add-seed plugin', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('handles jsx', () => {
|
it('handles jsx', () => {
|
||||||
expect.assertions(3);
|
expect.assertions(1);
|
||||||
plugin(withSeedKeysJSXAST, file);
|
plugin(withSeedKeysJSXAST, file);
|
||||||
const {
|
const {
|
||||||
data: { challengeFiles }
|
data: { challengeFiles }
|
||||||
} = file;
|
} = file;
|
||||||
const indexjsx = challengeFiles.find(x => x.ext === 'jsx');
|
const indexjsx = challengeFiles.find(x => x.ext === 'jsx');
|
||||||
|
|
||||||
expect(indexjsx.head).toBe(`function setup() {}`);
|
|
||||||
expect(indexjsx.tail).toBe(`function teardown(params) {
|
|
||||||
// after
|
|
||||||
}`);
|
|
||||||
expect(indexjsx.contents).toBe(`var x = 'y';
|
expect(indexjsx.contents).toBe(`var x = 'y';
|
||||||
|
|
||||||
/* comment */
|
/* comment */
|
||||||
|
|||||||
@@ -40,23 +40,19 @@ describe('add solution plugin', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('adds solution objects to the challengeFiles array following a schema', () => {
|
it('adds solution objects to the challengeFiles array following a schema', () => {
|
||||||
expect.assertions(13);
|
expect.assertions(9);
|
||||||
plugin(mockAST, file);
|
plugin(mockAST, file);
|
||||||
const {
|
const {
|
||||||
data: { solutions }
|
data: { solutions }
|
||||||
} = file;
|
} = file;
|
||||||
const testObject = solutions[0].find(solution => solution.ext === 'js');
|
const testObject = solutions[0].find(solution => solution.ext === 'js');
|
||||||
expect(Object.keys(testObject).length).toEqual(6);
|
expect(Object.keys(testObject).length).toEqual(4);
|
||||||
expect(testObject).toHaveProperty('ext');
|
expect(testObject).toHaveProperty('ext');
|
||||||
expect(typeof testObject['ext']).toBe('string');
|
expect(typeof testObject['ext']).toBe('string');
|
||||||
expect(testObject).toHaveProperty('name');
|
expect(testObject).toHaveProperty('name');
|
||||||
expect(typeof testObject['name']).toBe('string');
|
expect(typeof testObject['name']).toBe('string');
|
||||||
expect(testObject).toHaveProperty('contents');
|
expect(testObject).toHaveProperty('contents');
|
||||||
expect(typeof testObject['contents']).toBe('string');
|
expect(typeof testObject['contents']).toBe('string');
|
||||||
expect(testObject).toHaveProperty('head');
|
|
||||||
expect(typeof testObject['head']).toBe('string');
|
|
||||||
expect(testObject).toHaveProperty('tail');
|
|
||||||
expect(typeof testObject['tail']).toBe('string');
|
|
||||||
expect(testObject).toHaveProperty('id');
|
expect(testObject).toHaveProperty('id');
|
||||||
expect(typeof testObject['id']).toBe('string');
|
expect(typeof testObject['id']).toBe('string');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,10 +4,6 @@ const position = require('unist-util-position');
|
|||||||
|
|
||||||
const getId = require('./get-id');
|
const getId = require('./get-id');
|
||||||
|
|
||||||
const keyToSection = {
|
|
||||||
head: 'before-user-code',
|
|
||||||
tail: 'after-user-code'
|
|
||||||
};
|
|
||||||
const supportedLanguages = [
|
const supportedLanguages = [
|
||||||
'js',
|
'js',
|
||||||
'css',
|
'css',
|
||||||
@@ -29,8 +25,6 @@ function defaultFile(lang, id) {
|
|||||||
ext: lang,
|
ext: lang,
|
||||||
name: getFilenames(lang),
|
name: getFilenames(lang),
|
||||||
contents: '',
|
contents: '',
|
||||||
head: '',
|
|
||||||
tail: '',
|
|
||||||
id
|
id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -74,11 +68,6 @@ function codeToData(node, seeds, seedKey, validate) {
|
|||||||
if (!seeds[fileId]) {
|
if (!seeds[fileId]) {
|
||||||
seeds[fileId] = defaultFile(shortLang, id);
|
seeds[fileId] = defaultFile(shortLang, id);
|
||||||
}
|
}
|
||||||
if (isEmpty(node.value) && seedKey !== 'contents') {
|
|
||||||
const section = keyToSection[seedKey];
|
|
||||||
throw Error(`Empty code block in --${section}-- section`);
|
|
||||||
}
|
|
||||||
|
|
||||||
seeds[fileId][seedKey] = isEmpty(seeds[fileId][seedKey])
|
seeds[fileId][seedKey] = isEmpty(seeds[fileId][seedKey])
|
||||||
? node.value
|
? node.value
|
||||||
: seeds[fileId][seedKey] + '\n' + node.value;
|
: seeds[fileId][seedKey] + '\n' + node.value;
|
||||||
|
|||||||
@@ -30,9 +30,6 @@ const VALID_MARKERS = [
|
|||||||
'## --sentence--',
|
'## --sentence--',
|
||||||
'## --text--',
|
'## --text--',
|
||||||
'## --video-solution--',
|
'## --video-solution--',
|
||||||
// TODO: Remove these two markers when https://github.com/freeCodeCamp/freeCodeCamp/issues/57107 is resolved
|
|
||||||
'## --after-user-code--',
|
|
||||||
'## --before-user-code--',
|
|
||||||
|
|
||||||
// Level 3
|
// Level 3
|
||||||
'### --audio-id--',
|
'### --audio-id--',
|
||||||
|
|||||||
@@ -299,8 +299,6 @@ exports.createPagesStatefully = async function ({ graphql, actions }) {
|
|||||||
name
|
name
|
||||||
ext
|
ext
|
||||||
contents
|
contents
|
||||||
head
|
|
||||||
tail
|
|
||||||
history
|
history
|
||||||
fileKey
|
fileKey
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user