fix(scripts): fix unpack and repack scripts for the new challenge schema
This commit is contained in:
committed by
Kristofer Koishigawa
parent
2edb306ca1
commit
52ed7cfa7e
@ -8,21 +8,21 @@ const hiddenFile = /(^(\.|\/\.))|(.md$)/g;
|
|||||||
|
|
||||||
function getFilesFor(dir) {
|
function getFilesFor(dir) {
|
||||||
let targetDir = path.join(__dirname, dir);
|
let targetDir = path.join(__dirname, dir);
|
||||||
return fs.readdirSync(targetDir)
|
return fs
|
||||||
|
.readdirSync(targetDir)
|
||||||
.filter(file => !hiddenFile.test(file))
|
.filter(file => !hiddenFile.test(file))
|
||||||
.map(function(file) {
|
.map(function(file) {
|
||||||
let superBlock;
|
let superBlock;
|
||||||
if (fs.statSync(path.join(targetDir, file)).isFile()) {
|
if (fs.statSync(path.join(targetDir, file)).isFile()) {
|
||||||
return {file: file};
|
return { file: file };
|
||||||
}
|
}
|
||||||
superBlock = file;
|
superBlock = file;
|
||||||
return getFilesFor(path.join(dir, superBlock))
|
return getFilesFor(path.join(dir, superBlock)).map(function(data) {
|
||||||
.map(function(data) {
|
return {
|
||||||
return {
|
file: path.join(superBlock, data.file),
|
||||||
file: path.join(superBlock, data.file),
|
superBlock: superBlock
|
||||||
superBlock: superBlock
|
};
|
||||||
};
|
});
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.reduce(function(files, entry) {
|
.reduce(function(files, entry) {
|
||||||
return files.concat(entry);
|
return files.concat(entry);
|
||||||
@ -33,7 +33,7 @@ function superblockInfo(filePath) {
|
|||||||
let parts = (filePath || '').split('-');
|
let parts = (filePath || '').split('-');
|
||||||
let order = parseInt(parts[0], 10);
|
let order = parseInt(parts[0], 10);
|
||||||
if (isNaN(order)) {
|
if (isNaN(order)) {
|
||||||
return {order: 0, name: filePath};
|
return { order: 0, name: filePath };
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
order: order,
|
order: order,
|
||||||
@ -46,31 +46,26 @@ module.exports = function getChallenges(challengesDir) {
|
|||||||
if (!challengesDir) {
|
if (!challengesDir) {
|
||||||
challengesDir = 'challenges';
|
challengesDir = 'challenges';
|
||||||
}
|
}
|
||||||
return getFilesFor(challengesDir)
|
return getFilesFor(challengesDir).map(function(data) {
|
||||||
.map(function(data) {
|
const challengeSpec = require('./' + challengesDir + '/' + data.file);
|
||||||
const challengeSpec = require('./' + challengesDir + '/' + data.file);
|
let superInfo = superblockInfo(data.superBlock);
|
||||||
let superInfo = superblockInfo(data.superBlock);
|
challengeSpec.fileName = data.file;
|
||||||
challengeSpec.fileName = data.file;
|
challengeSpec.superBlock = superInfo.name;
|
||||||
challengeSpec.superBlock = superInfo.name;
|
challengeSpec.superOrder = superInfo.order;
|
||||||
challengeSpec.superOrder = superInfo.order;
|
challengeSpec.challenges = challengeSpec.challenges.map(challenge =>
|
||||||
challengeSpec.challenges = challengeSpec.challenges
|
omit(challenge, [
|
||||||
.map(challenge => omit(
|
'betaSolutions',
|
||||||
challenge,
|
'betaTests',
|
||||||
[
|
'hints',
|
||||||
'betaSolutions',
|
'MDNlinks',
|
||||||
'betaTests',
|
'null',
|
||||||
'hints',
|
'rawSolutions',
|
||||||
'MDNlinks',
|
'react',
|
||||||
'null',
|
'reactRedux',
|
||||||
'rawSolutions',
|
'redux',
|
||||||
'react',
|
'type'
|
||||||
'reactRedux',
|
])
|
||||||
'redux',
|
);
|
||||||
'releasedOn',
|
return challengeSpec;
|
||||||
'translations',
|
});
|
||||||
'type'
|
|
||||||
]
|
|
||||||
));
|
|
||||||
return challengeSpec;
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
@ -4,12 +4,15 @@ Joi.objectId = require('joi-objectid')(Joi);
|
|||||||
const schema = Joi.object().keys({
|
const schema = Joi.object().keys({
|
||||||
block: Joi.string(),
|
block: Joi.string(),
|
||||||
blockId: Joi.objectId(),
|
blockId: Joi.objectId(),
|
||||||
challengeType: Joi.number().min(0).max(9).required(),
|
challengeType: Joi.number()
|
||||||
|
.min(0)
|
||||||
|
.max(9)
|
||||||
|
.required(),
|
||||||
checksum: Joi.number(),
|
checksum: Joi.number(),
|
||||||
dashedName: Joi.string(),
|
dashedName: Joi.string(),
|
||||||
description: Joi.array().items(
|
description: Joi.array()
|
||||||
Joi.string().allow('')
|
.items(Joi.string().allow(''))
|
||||||
).required(),
|
.required(),
|
||||||
fileName: Joi.string(),
|
fileName: Joi.string(),
|
||||||
files: Joi.object().pattern(
|
files: Joi.object().pattern(
|
||||||
/(jsx?|html|css|sass)$/,
|
/(jsx?|html|css|sass)$/,
|
||||||
@ -17,14 +20,8 @@ const schema = Joi.object().keys({
|
|||||||
key: Joi.string(),
|
key: Joi.string(),
|
||||||
ext: Joi.string(),
|
ext: Joi.string(),
|
||||||
name: Joi.string(),
|
name: Joi.string(),
|
||||||
head: [
|
head: [Joi.array().items(Joi.string().allow('')), Joi.string().allow('')],
|
||||||
Joi.array().items(Joi.string().allow('')),
|
tail: [Joi.array().items(Joi.string().allow('')), Joi.string().allow('')],
|
||||||
Joi.string().allow('')
|
|
||||||
],
|
|
||||||
tail: [
|
|
||||||
Joi.array().items(Joi.string().allow('')),
|
|
||||||
Joi.string().allow('')
|
|
||||||
],
|
|
||||||
contents: [
|
contents: [
|
||||||
Joi.array().items(Joi.string().allow('')),
|
Joi.array().items(Joi.string().allow('')),
|
||||||
Joi.string().allow('')
|
Joi.string().allow('')
|
||||||
@ -49,9 +46,8 @@ const schema = Joi.object().keys({
|
|||||||
crossDomain: Joi.bool()
|
crossDomain: Joi.bool()
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
solutions: Joi.array().items(
|
releasedOn: Joi.string().allow(''),
|
||||||
Joi.string().optional()
|
solutions: Joi.array().items(Joi.string().optional()),
|
||||||
),
|
|
||||||
superBlock: Joi.string(),
|
superBlock: Joi.string(),
|
||||||
superOrder: Joi.number(),
|
superOrder: Joi.number(),
|
||||||
suborder: Joi.number(),
|
suborder: Joi.number(),
|
||||||
@ -59,7 +55,9 @@ const schema = Joi.object().keys({
|
|||||||
// public challenges
|
// public challenges
|
||||||
Joi.object().keys({
|
Joi.object().keys({
|
||||||
text: Joi.string().required(),
|
text: Joi.string().required(),
|
||||||
testString: Joi.string().allow('').required()
|
testString: Joi.string()
|
||||||
|
.allow('')
|
||||||
|
.required()
|
||||||
}),
|
}),
|
||||||
// our tests used in certification verification
|
// our tests used in certification verification
|
||||||
Joi.object().keys({
|
Joi.object().keys({
|
||||||
@ -69,7 +67,14 @@ const schema = Joi.object().keys({
|
|||||||
),
|
),
|
||||||
template: Joi.string(),
|
template: Joi.string(),
|
||||||
time: Joi.string().allow(''),
|
time: Joi.string().allow(''),
|
||||||
title: Joi.string().required()
|
title: Joi.string().required(),
|
||||||
|
translations: Joi.object().pattern(
|
||||||
|
/\w+(-\w+)*/,
|
||||||
|
Joi.object().keys({
|
||||||
|
title: Joi.string(),
|
||||||
|
description: Joi.array().items(Joi.string().allow(''))
|
||||||
|
})
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
exports.validateChallenge = function validateChallenge(challenge) {
|
exports.validateChallenge = function validateChallenge(challenge) {
|
||||||
|
@ -34,9 +34,6 @@ class ChallengeFile {
|
|||||||
// todo: make sure it works with encodings
|
// todo: make sure it works with encodings
|
||||||
let data = fs.readFileSync(this.filePath());
|
let data = fs.readFileSync(this.filePath());
|
||||||
let lines = data.toString().split(/(?:\r\n|\r|\n)/g);
|
let lines = data.toString().split(/(?:\r\n|\r|\n)/g);
|
||||||
let chunks = {};
|
|
||||||
let readingChunk = null;
|
|
||||||
let currentParagraph = [];
|
|
||||||
|
|
||||||
function removeLeadingEmptyLines(array) {
|
function removeLeadingEmptyLines(array) {
|
||||||
let emptyString = /^\s*$/;
|
let emptyString = /^\s*$/;
|
||||||
@ -45,69 +42,159 @@ class ChallengeFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lines.forEach(line => {
|
let chunkEnd = /(<!|\/\*)--end--/;
|
||||||
let chunkEnd = /(<!|\/\*)--end--/;
|
let index = 0;
|
||||||
let chunkStart = /(<!|\/\*)--(\w+)--/;
|
|
||||||
|
|
||||||
line = line.toString();
|
function endOfFile() {
|
||||||
|
return index === lines.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextLine() {
|
||||||
|
if (endOfFile()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return lines[index++].toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function readDescription() {
|
||||||
|
let description = [];
|
||||||
|
let currentParagraph = [];
|
||||||
|
|
||||||
function pushParagraph() {
|
function pushParagraph() {
|
||||||
removeLeadingEmptyLines(currentParagraph);
|
removeLeadingEmptyLines(currentParagraph);
|
||||||
chunks[ readingChunk ].push(currentParagraph.join('\n'));
|
description.push(currentParagraph.join('\n'));
|
||||||
currentParagraph = [];
|
currentParagraph = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chunkEnd.test(line)) {
|
while (!endOfFile()) {
|
||||||
if (!readingChunk) {
|
let line = nextLine();
|
||||||
throw 'Encountered --end-- without being in a chunk';
|
if (chunkEnd.test(line)) {
|
||||||
}
|
pushParagraph();
|
||||||
if (currentParagraph.length) {
|
return description;
|
||||||
|
} else if (line === paragraphBreak) {
|
||||||
pushParagraph();
|
pushParagraph();
|
||||||
} else {
|
} else {
|
||||||
removeLeadingEmptyLines(chunks[readingChunk]);
|
|
||||||
}
|
|
||||||
readingChunk = null;
|
|
||||||
} else if (readingChunk === 'description' && line === paragraphBreak) {
|
|
||||||
pushParagraph();
|
|
||||||
} else if (chunkStart.test(line)) {
|
|
||||||
let chunkName = line.match(chunkStart)[ 2 ];
|
|
||||||
if (readingChunk) {
|
|
||||||
throw `Encountered chunk ${chunkName} start `
|
|
||||||
+ `while already reading ${readingChunk}:
|
|
||||||
${line}`;
|
|
||||||
}
|
|
||||||
readingChunk = chunkName;
|
|
||||||
} else if (readingChunk) {
|
|
||||||
if (!chunks[ readingChunk ]) {
|
|
||||||
chunks[ readingChunk ] = [];
|
|
||||||
}
|
|
||||||
if (line.startsWith(jsonLinePrefix)) {
|
|
||||||
line = JSON.parse(line.slice(jsonLinePrefix.length));
|
|
||||||
chunks[ readingChunk ].push(line);
|
|
||||||
} else if (readingChunk === 'description') {
|
|
||||||
currentParagraph.push(line);
|
currentParagraph.push(line);
|
||||||
} else {
|
|
||||||
chunks[ readingChunk ].push(line);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
throw `Unexpected end of the file while reading a description.
|
||||||
|
${this.filePath()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readTranslations() {
|
||||||
|
let translations = {};
|
||||||
|
let langChunk = /<!--(\w+(-\w+)*)-->/;
|
||||||
|
|
||||||
|
while (!endOfFile()) {
|
||||||
|
let line = nextLine();
|
||||||
|
if (chunkEnd.test(line)) {
|
||||||
|
return translations;
|
||||||
|
} else if (langChunk.test(line)) {
|
||||||
|
let langCode = line.match(langChunk)[1];
|
||||||
|
translations[langCode] = readProperties();
|
||||||
|
line = nextLine();
|
||||||
|
if (!chunkEnd.test(line)) {
|
||||||
|
throw `Expected --end--:
|
||||||
|
${line}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw `Unexpected end of the file while reading translations.
|
||||||
|
${this.filePath()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readFiles() {
|
||||||
|
let files = {};
|
||||||
|
let fileChunk = /<!--(\w+)\.(\w+)-->/;
|
||||||
|
while (!endOfFile()) {
|
||||||
|
let line = nextLine();
|
||||||
|
if (chunkEnd.test(line)) {
|
||||||
|
return files;
|
||||||
|
} else if (fileChunk.test(line)) {
|
||||||
|
let name = line.match(fileChunk)[1];
|
||||||
|
let ext = line.match(fileChunk)[2];
|
||||||
|
let key = name + ext;
|
||||||
|
files[key] = {};
|
||||||
|
files[key].key = key;
|
||||||
|
files[key].ext = ext;
|
||||||
|
files[key].name = name;
|
||||||
|
Object.assign(files[key], readProperties());
|
||||||
|
line = nextLine();
|
||||||
|
if (!chunkEnd.test(line)) {
|
||||||
|
throw `Expected --end--:
|
||||||
|
${line}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw `Unexpected end of the file while reading files.
|
||||||
|
${this.filePath()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readProperty() {
|
||||||
|
let property = [];
|
||||||
|
while (!endOfFile()) {
|
||||||
|
let line = nextLine();
|
||||||
|
if (chunkEnd.test(line)) {
|
||||||
|
removeLeadingEmptyLines(property);
|
||||||
|
return property;
|
||||||
|
} else if (line.startsWith(jsonLinePrefix)) {
|
||||||
|
line = JSON.parse(line.slice(jsonLinePrefix.length));
|
||||||
|
property.push(line);
|
||||||
|
} else {
|
||||||
|
property.push(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw `Unexpected end of the file while reading a property.
|
||||||
|
${this.filePath()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readProperties() {
|
||||||
|
let properties = {};
|
||||||
|
let chunkStart = /(<!|\/\*)--(\w+)--/;
|
||||||
|
|
||||||
|
while (!endOfFile()) {
|
||||||
|
let line = nextLine();
|
||||||
|
if (chunkEnd.test(line)) {
|
||||||
|
index--; // must to do step back
|
||||||
|
return properties;
|
||||||
|
} else if (chunkStart.test(line)) {
|
||||||
|
let chunkName = line.match(chunkStart)[2];
|
||||||
|
if (chunkName === 'description') {
|
||||||
|
properties[chunkName] = readDescription();
|
||||||
|
} else if (chunkName === 'translations') {
|
||||||
|
properties[chunkName] = readTranslations();
|
||||||
|
} else if (chunkName === 'files') {
|
||||||
|
properties[chunkName] = readFiles();
|
||||||
|
} else {
|
||||||
|
properties[chunkName] = readProperty();
|
||||||
|
if (chunkName === 'releasedOn' || chunkName === 'title') {
|
||||||
|
properties[chunkName] = properties[chunkName].join('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
let chunks = readProperties();
|
||||||
|
|
||||||
|
if (!endOfFile()) {
|
||||||
|
throw `Unexpected content of file: ${this.filePath()}`;
|
||||||
|
}
|
||||||
|
|
||||||
// hack to deal with solutions field being an array of a single string
|
// hack to deal with solutions field being an array of a single string
|
||||||
// instead of an array of lines like some other fields
|
// instead of an array of lines like some other fields
|
||||||
if (chunks.solutions) {
|
if (chunks.solutions) {
|
||||||
chunks.solutions = [ chunks.solutions.join('\n') ];
|
chunks.solutions = [chunks.solutions.join('\n')];
|
||||||
|
removeLeadingEmptyLines(chunks.solutions);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(chunks).forEach(key => {
|
|
||||||
removeLeadingEmptyLines(chunks[key]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// console.log(JSON.stringify(chunks, null, 2));
|
// console.log(JSON.stringify(chunks, null, 2));
|
||||||
return chunks;
|
return chunks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {ChallengeFile};
|
export { ChallengeFile };
|
||||||
|
|
||||||
class UnpackedChallenge {
|
class UnpackedChallenge {
|
||||||
constructor(targetDir, challengeJson, index) {
|
constructor(targetDir, challengeJson, index) {
|
||||||
@ -130,8 +217,7 @@ class UnpackedChallenge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unpack() {
|
unpack() {
|
||||||
this.challengeFile()
|
this.challengeFile().write(this.unpackedHTML());
|
||||||
.write(this.unpackedHTML());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
challengeFile() {
|
challengeFile() {
|
||||||
@ -140,14 +226,14 @@ class UnpackedChallenge {
|
|||||||
|
|
||||||
baseName() {
|
baseName() {
|
||||||
// eslint-disable-next-line no-nested-ternary
|
// eslint-disable-next-line no-nested-ternary
|
||||||
let prefix = ((this.index < 10) ? '00' : (this.index < 100) ? '0' : '')
|
let prefix =
|
||||||
+ this.index;
|
(this.index < 10 ? '00' : this.index < 100 ? '0' : '') + this.index;
|
||||||
return `${prefix}-${dasherize(this.challenge.title)}-${this.challenge.id}`;
|
return `${prefix}-${dasherize(this.challenge.title)}-${this.challenge.id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
expandedDescription() {
|
expandedDescription(description) {
|
||||||
let out = [];
|
let out = [];
|
||||||
this.challenge.description.forEach(part => {
|
description.forEach(part => {
|
||||||
if (_.isString(part)) {
|
if (_.isString(part)) {
|
||||||
out.push(part.toString());
|
out.push(part.toString());
|
||||||
out.push(paragraphBreak);
|
out.push(paragraphBreak);
|
||||||
@ -167,7 +253,7 @@ class UnpackedChallenge {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (out[ out.length - 1 ] === paragraphBreak) {
|
if (out[out.length - 1] === paragraphBreak) {
|
||||||
out.pop();
|
out.pop();
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
@ -208,42 +294,138 @@ class UnpackedChallenge {
|
|||||||
and run <code>npm run repack</code>
|
and run <code>npm run repack</code>
|
||||||
to incorporate your changes into the challenge database.</p>`);
|
to incorporate your changes into the challenge database.</p>`);
|
||||||
|
|
||||||
|
text.push('<h2>Title</h2>');
|
||||||
|
text.push('<!--title-->');
|
||||||
|
text.push(this.challenge.title);
|
||||||
|
text.push('<!--end-->');
|
||||||
|
|
||||||
text.push('');
|
text.push('');
|
||||||
text.push('<h2>Description</h2>');
|
text.push('<h2>Description</h2>');
|
||||||
text.push('<div class="unpacked description">');
|
text.push('<div class="unpacked description">');
|
||||||
text.push('<!--description-->');
|
text.push('<!--description-->');
|
||||||
if (this.challenge.description.length) {
|
if (this.challenge.description.length) {
|
||||||
text.push(this.expandedDescription().join('\n'));
|
text.push(
|
||||||
|
this.expandedDescription(this.challenge.description).join('\n')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
text.push('<!--end-->');
|
||||||
|
text.push('</div>');
|
||||||
|
text.push('');
|
||||||
|
text.push('<h2>Translations</h2>');
|
||||||
|
text.push(`
|
||||||
|
<p>Format of translation unit:</p>
|
||||||
|
<p>
|
||||||
|
<code>
|
||||||
|
<!--<em>language-code</em>--><br>
|
||||||
|
<!--<em>title</em>--><br>
|
||||||
|
<em>Title</em><br>
|
||||||
|
<!--<em>end</em>--><br>
|
||||||
|
<!--<em>description</em>--><br>
|
||||||
|
<em>Description</em><br>
|
||||||
|
<!--<em>end</em>--><br>
|
||||||
|
<!--<em>end</em>--><br>
|
||||||
|
</code>
|
||||||
|
</p>`);
|
||||||
|
text.push('<div class="unpacked">');
|
||||||
|
text.push('<!--translations-->');
|
||||||
|
if (this.challenge.hasOwnProperty('translations')) {
|
||||||
|
const translations = this.challenge.translations;
|
||||||
|
const keys = Object.keys(translations);
|
||||||
|
if (keys) {
|
||||||
|
keys.forEach(lang => {
|
||||||
|
text.push(`<h2>${lang}</h2>`);
|
||||||
|
text.push(`<!--${lang}-->`);
|
||||||
|
const translation = translations[lang];
|
||||||
|
if (translation.title) {
|
||||||
|
text.push('<h3>Title</h3>');
|
||||||
|
text.push('<!--title-->');
|
||||||
|
text.push(translation.title);
|
||||||
|
text.push('<!--end-->');
|
||||||
|
}
|
||||||
|
if (translation.description && translation.description.length) {
|
||||||
|
text.push('<h3>Description</h3>');
|
||||||
|
text.push('<!--description-->');
|
||||||
|
text.push(
|
||||||
|
this.expandedDescription(translation.description).join('\n')
|
||||||
|
);
|
||||||
|
text.push('<!--end-->');
|
||||||
|
}
|
||||||
|
text.push('<!--end-->');
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
text.push('<!--end-->');
|
text.push('<!--end-->');
|
||||||
text.push('</div>');
|
text.push('</div>');
|
||||||
|
|
||||||
text.push('');
|
text.push('');
|
||||||
text.push('<h2>Seed</h2>');
|
text.push('<h2>Released On</h2>');
|
||||||
text.push('<!--seed--><pre class="unpacked">');
|
text.push('<div class="unpacked">');
|
||||||
if (this.challenge.seed) {
|
text.push('<!--releasedOn-->');
|
||||||
text.push(text, this.challenge.seed.join('\n'));
|
text.push(this.challenge.releasedOn);
|
||||||
}
|
|
||||||
text.push('<!--end-->');
|
text.push('<!--end-->');
|
||||||
text.push('</pre>');
|
text.push('</div>');
|
||||||
|
|
||||||
// Q: What is the difference between 'seed' and 'challengeSeed' ?
|
|
||||||
text.push('');
|
|
||||||
text.push('<h2>Challenge Seed</h2>');
|
|
||||||
text.push('<!--challengeSeed--><pre class="unpacked">');
|
|
||||||
if (this.challenge.challengeSeed) {
|
|
||||||
text.push(text, this.challenge.challengeSeed.join('\n'));
|
|
||||||
}
|
|
||||||
text.push('<!--end-->');
|
|
||||||
text.push('</pre>');
|
|
||||||
|
|
||||||
text.push('');
|
text.push('');
|
||||||
text.push('<h2>Head</h2>');
|
text.push('<h2>Files</h2>');
|
||||||
text.push('<!--head--><script class="unpacked head">');
|
text.push(`
|
||||||
if (this.challenge.head) {
|
<p>Format of file:</p>
|
||||||
text.push(text, this.challenge.head.join('\n'));
|
<p>
|
||||||
|
<code>
|
||||||
|
<!--<em>name.ext</em>--><br>
|
||||||
|
<!--<em>contents</em>--><br>
|
||||||
|
<em>Contents</em><br>
|
||||||
|
<!--<em>end</em>--><br>
|
||||||
|
<!--<em>head</em>--><br>
|
||||||
|
<em>Head</em><br>
|
||||||
|
<!--<em>end</em>--><br>
|
||||||
|
<!--<em>tail</em>--><br>
|
||||||
|
<em>Tail</em><br>
|
||||||
|
<!--<em>end</em>--><br>
|
||||||
|
<!--<em>end</em>--><br>
|
||||||
|
</code>
|
||||||
|
</p>`);
|
||||||
|
text.push('<div class="unpacked">');
|
||||||
|
text.push('<!--files-->');
|
||||||
|
if (this.challenge.files) {
|
||||||
|
Object.keys(this.challenge.files).forEach(key => {
|
||||||
|
let file = this.challenge.files[key];
|
||||||
|
let { contents, head, tail } = file;
|
||||||
|
text.push(`<h3>${file.name + '.' + file.ext}</h3>`);
|
||||||
|
text.push(`<!--${file.name + '.' + file.ext}-->`);
|
||||||
|
text.push('<h4>Contents</h4>');
|
||||||
|
text.push('<pre>');
|
||||||
|
text.push(_.escape(contents.join('\n')));
|
||||||
|
text.push('</pre>');
|
||||||
|
text.push('<pre style="display: none;">');
|
||||||
|
text.push('<!--contents-->');
|
||||||
|
text.push(contents.join('\n'));
|
||||||
|
text.push('<!--end-->');
|
||||||
|
text.push('</pre>');
|
||||||
|
|
||||||
|
text.push('<h4>Head</h4>');
|
||||||
|
text.push('<pre>');
|
||||||
|
text.push(_.escape(head.join('\n')));
|
||||||
|
text.push('</pre>');
|
||||||
|
text.push('<pre style="display: none;">');
|
||||||
|
text.push('<!--head-->');
|
||||||
|
text.push(head.join('\n'));
|
||||||
|
text.push('<!--end-->');
|
||||||
|
text.push('</pre>');
|
||||||
|
|
||||||
|
text.push('<h4>Tail</h4>');
|
||||||
|
text.push('<pre>');
|
||||||
|
text.push(_.escape(tail.join('\n')));
|
||||||
|
text.push('</pre>');
|
||||||
|
text.push('<pre style="display: none;">');
|
||||||
|
text.push('<!--tail-->');
|
||||||
|
text.push(tail.join('\n'));
|
||||||
|
text.push('<!--end-->');
|
||||||
|
text.push('</pre>');
|
||||||
|
text.push('<!--end-->');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
text.push('</script><!--end-->');
|
text.push('<!--end-->');
|
||||||
|
text.push('</div>');
|
||||||
|
|
||||||
text.push('');
|
text.push('');
|
||||||
text.push('<h2>Solution</h2>');
|
text.push('<h2>Solution</h2>');
|
||||||
@ -253,29 +435,24 @@ class UnpackedChallenge {
|
|||||||
// Note: none of the challenges have more than one solution
|
// Note: none of the challenges have more than one solution
|
||||||
// todo: should we deal with multiple solutions or not?
|
// todo: should we deal with multiple solutions or not?
|
||||||
if (this.challenge.solutions && this.challenge.solutions.length > 0) {
|
if (this.challenge.solutions && this.challenge.solutions.length > 0) {
|
||||||
let solution = this.challenge.solutions[ 0 ];
|
let solution = this.challenge.solutions[0];
|
||||||
text.push(solution);
|
text.push(solution);
|
||||||
}
|
}
|
||||||
text.push('</script><!--end-->');
|
text.push('</script><!--end-->');
|
||||||
|
|
||||||
text.push('');
|
|
||||||
text.push('<h2>Tail</h2>');
|
|
||||||
text.push('<!--tail--><script class="unpacked tail">');
|
|
||||||
if (this.challenge.tail) {
|
|
||||||
text.push(text, this.challenge.tail.join('\n'));
|
|
||||||
}
|
|
||||||
text.push('</script><!--end-->');
|
|
||||||
|
|
||||||
text.push('');
|
text.push('');
|
||||||
text.push('<h2>Tests</h2>');
|
text.push('<h2>Tests</h2>');
|
||||||
text.push('<script class="unpacked tests">');
|
text.push('<script class="unpacked tests">');
|
||||||
text.push(`test(\'${this.challenge.title} challenge tests\', ` +
|
text.push(
|
||||||
'function(t) {');
|
`test(\'${this.challenge.title} challenge tests\', ` + 'function(t) {'
|
||||||
|
);
|
||||||
text.push('let assert = addAssertsToTapTest(t);');
|
text.push('let assert = addAssertsToTapTest(t);');
|
||||||
text.push('let code = document.getElementById(\'solution\').innerText;');
|
text.push("let code = document.getElementById('solution').innerText;");
|
||||||
text.push('t.plan(' +
|
text.push(
|
||||||
(this.challenge.tests ? this.challenge.tests.length : 0) +
|
't.plan(' +
|
||||||
');');
|
(this.challenge.tests ? this.challenge.tests.length : 0) +
|
||||||
|
');'
|
||||||
|
);
|
||||||
text.push('/*--tests--*/');
|
text.push('/*--tests--*/');
|
||||||
text.push(this.expandedTests(this.challenge.tests).join('\n'));
|
text.push(this.expandedTests(this.challenge.tests).join('\n'));
|
||||||
text.push('/*--end--*/');
|
text.push('/*--end--*/');
|
||||||
@ -289,5 +466,4 @@ class UnpackedChallenge {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {UnpackedChallenge};
|
export { UnpackedChallenge };
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user