chore: Remove unrequired files/deps/scripts
This commit is contained in:
committed by
mrugesh mohapatra
parent
3edb9d1701
commit
25fd85b321
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "freecodecamp"
|
|
||||||
}
|
|
2795
curriculum/package-lock.json
generated
2795
curriculum/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -17,11 +17,10 @@
|
|||||||
"develop": "gulp",
|
"develop": "gulp",
|
||||||
"format": "prettier --write es5 './**/*.{js,json}' && npm run lint",
|
"format": "prettier --write es5 './**/*.{js,json}' && npm run lint",
|
||||||
"lint": "eslint ./**/*.js --fix",
|
"lint": "eslint ./**/*.js --fix",
|
||||||
"repack": "babel-node ./repack.js",
|
|
||||||
"semantic-release": "semantic-release",
|
"semantic-release": "semantic-release",
|
||||||
"pretest": "cd ../client && npm run build:workers",
|
"pretest": "cd ../client && npm run build:workers",
|
||||||
"test": "mocha --delay --reporter progress --bail",
|
"test": "mocha --delay --reporter progress --bail",
|
||||||
"unpack": "babel-node ./unpack.js"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"invariant": "^2.2.4"
|
"invariant": "^2.2.4"
|
||||||
@ -47,13 +46,7 @@
|
|||||||
"babel-preset-stage-0": "^6.3.13",
|
"babel-preset-stage-0": "^6.3.13",
|
||||||
"babel-preset-stage-3": "^6.24.1",
|
"babel-preset-stage-3": "^6.24.1",
|
||||||
"babel-standalone": "^6.26.0",
|
"babel-standalone": "^6.26.0",
|
||||||
"browserify": "^16.2.3",
|
|
||||||
"chai": "4.2.0",
|
"chai": "4.2.0",
|
||||||
"eslint": "^4.19.1",
|
|
||||||
"eslint-config-freecodecamp": "^1.1.1",
|
|
||||||
"eslint-plugin-import": "^2.11.0",
|
|
||||||
"eslint-plugin-prefer-object-spread": "^1.2.1",
|
|
||||||
"eslint-plugin-react": "^7.7.0",
|
|
||||||
"fs-extra": "^6.0.1",
|
"fs-extra": "^6.0.1",
|
||||||
"gulp": "^4.0.0",
|
"gulp": "^4.0.0",
|
||||||
"joi": "^13.3.0",
|
"joi": "^13.3.0",
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
/* eslint-disable no-eval, no-process-exit */
|
|
||||||
import fs from 'fs-extra';
|
|
||||||
import path from 'path';
|
|
||||||
import {UnpackedChallenge, ChallengeFile} from './unpackedChallenge';
|
|
||||||
|
|
||||||
// Repack all challenges from all
|
|
||||||
// seed/unpacked/00-foo/bar/000-xxx-id.html files
|
|
||||||
// into
|
|
||||||
// seed/challenges/00-foo/bar.json files
|
|
||||||
|
|
||||||
let unpackedRoot = path.join(__dirname, 'unpacked');
|
|
||||||
let seedChallengesRoot = path.join(__dirname, 'challenges');
|
|
||||||
|
|
||||||
function directoriesIn(parentDir) {
|
|
||||||
return fs.readdirSync(parentDir)
|
|
||||||
.filter(entry => fs.statSync(path.join(parentDir, entry)).isDirectory());
|
|
||||||
}
|
|
||||||
|
|
||||||
let superBlocks = directoriesIn(unpackedRoot);
|
|
||||||
superBlocks.forEach(superBlock => {
|
|
||||||
let superBlockPath = path.join(unpackedRoot, superBlock);
|
|
||||||
console.log(`Repacking ${superBlockPath}...`);
|
|
||||||
let blocks = directoriesIn(superBlockPath);
|
|
||||||
blocks.forEach(blockName => {
|
|
||||||
let blockPath = path.join(superBlockPath, blockName);
|
|
||||||
let blockFilePath = path.join(blockPath, blockName + '.json');
|
|
||||||
let block = require(blockFilePath);
|
|
||||||
let index = 0;
|
|
||||||
block.challenges.forEach(challengeJson => {
|
|
||||||
let unpackedChallenge =
|
|
||||||
new UnpackedChallenge(blockPath, challengeJson, index);
|
|
||||||
let unpackedFile = unpackedChallenge.challengeFile();
|
|
||||||
let chunks = unpackedFile.readChunks();
|
|
||||||
|
|
||||||
Object.assign(block.challenges[ index ], chunks);
|
|
||||||
|
|
||||||
index += 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
let outputFilePath =
|
|
||||||
path.join(seedChallengesRoot, superBlock, blockName + '.json');
|
|
||||||
// todo: async
|
|
||||||
fs.writeFileSync(outputFilePath, JSON.stringify(block, null, 2));
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// let challenges = getChallenges();
|
|
||||||
// challenges.forEach(challengeBlock => {
|
|
||||||
// console.log()
|
|
||||||
// });
|
|
@ -1,109 +0,0 @@
|
|||||||
/* eslint-disable no-eval, no-process-exit */
|
|
||||||
import fs from 'fs-extra';
|
|
||||||
import path from 'path';
|
|
||||||
import browserify from 'browserify';
|
|
||||||
import getChallenges from './getChallenges';
|
|
||||||
import { UnpackedChallenge, ChallengeFile } from './unpackedChallenge';
|
|
||||||
|
|
||||||
// Unpack all challenges
|
|
||||||
// from all seed/challenges/00-foo/bar.json files
|
|
||||||
// into seed/unpacked/00-foo/bar/000-id.html files
|
|
||||||
//
|
|
||||||
// todo: use common/app/routes/Challenges/utils/index.js:15 maps
|
|
||||||
// to determine format/style for non-JS tests
|
|
||||||
// todo: figure out embedded images etc. served from elsewhere in the project
|
|
||||||
// todo: prettier/clearer CSS
|
|
||||||
|
|
||||||
let unpackedDir = path.join(__dirname, 'unpacked');
|
|
||||||
|
|
||||||
// bundle up the test-running JS
|
|
||||||
function createUnpackedBundle() {
|
|
||||||
fs.mkdirp(unpackedDir, err => {
|
|
||||||
if (err && err.code !== 'EEXIST') {
|
|
||||||
console.log(err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
|
|
||||||
let unpackedFile = path.join(__dirname, 'unpacked.js');
|
|
||||||
let b = browserify(unpackedFile).bundle();
|
|
||||||
b.on('error', console.error);
|
|
||||||
let unpackedBundleFile = path.join(unpackedDir, 'unpacked-bundle.js');
|
|
||||||
const bundleFileStream = fs.createWriteStream(unpackedBundleFile);
|
|
||||||
bundleFileStream.on('finish', () => {
|
|
||||||
console.log('Wrote bundled JS into ' + unpackedBundleFile);
|
|
||||||
});
|
|
||||||
bundleFileStream.on('pipe', () => {
|
|
||||||
console.log('Writing bundled JS...');
|
|
||||||
});
|
|
||||||
bundleFileStream.on('error', console.error);
|
|
||||||
b.pipe(bundleFileStream);
|
|
||||||
// bundleFileStream.end(); // do not do this prematurely!
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let currentlyUnpackingDir = null;
|
|
||||||
|
|
||||||
async function cleanUnpackedDir(unpackedChallengeBlockDir) {
|
|
||||||
let promiseToDelete = function(filePath) {
|
|
||||||
filePath = path.join(unpackedChallengeBlockDir, filePath);
|
|
||||||
return new Promise(() => fs.unlink(filePath));
|
|
||||||
};
|
|
||||||
let promises = fs
|
|
||||||
.readdirSync(unpackedChallengeBlockDir)
|
|
||||||
.filter(filePath => /\.html$/i.test(filePath))
|
|
||||||
.map(promiseToDelete);
|
|
||||||
await Promise.all(promises);
|
|
||||||
}
|
|
||||||
|
|
||||||
function unpackChallengeBlock(challengeBlock) {
|
|
||||||
let challengeBlockPath = path.parse(challengeBlock.fileName);
|
|
||||||
let unpackedChallengeBlockDir = path.join(
|
|
||||||
unpackedDir,
|
|
||||||
challengeBlockPath.dir,
|
|
||||||
challengeBlockPath.name
|
|
||||||
);
|
|
||||||
|
|
||||||
fs.mkdirp(unpackedChallengeBlockDir, err => {
|
|
||||||
if (err && err.code !== 'EEXIST') {
|
|
||||||
console.log(err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove existing unpacked files
|
|
||||||
cleanUnpackedDir(unpackedChallengeBlockDir);
|
|
||||||
|
|
||||||
if (currentlyUnpackingDir !== challengeBlockPath.dir) {
|
|
||||||
currentlyUnpackingDir = challengeBlockPath.dir;
|
|
||||||
console.log(`Unpacking into ${currentlyUnpackingDir}:`);
|
|
||||||
}
|
|
||||||
console.log(` ${challengeBlock.name}`);
|
|
||||||
|
|
||||||
// write a copy of the challenge block into unpacked dir
|
|
||||||
delete challengeBlock.fileName;
|
|
||||||
delete challengeBlock.superBlock;
|
|
||||||
delete challengeBlock.superOrder;
|
|
||||||
let challengeBlockCopy = new ChallengeFile(
|
|
||||||
unpackedChallengeBlockDir,
|
|
||||||
challengeBlockPath.name,
|
|
||||||
'.json'
|
|
||||||
);
|
|
||||||
challengeBlockCopy.write(JSON.stringify(challengeBlock, null, 2));
|
|
||||||
|
|
||||||
// unpack each challenge into an HTML file
|
|
||||||
let index = 0;
|
|
||||||
challengeBlock.challenges.forEach(challenge => {
|
|
||||||
new UnpackedChallenge(
|
|
||||||
unpackedChallengeBlockDir,
|
|
||||||
challenge,
|
|
||||||
index
|
|
||||||
).unpack();
|
|
||||||
index += 1;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
createUnpackedBundle();
|
|
||||||
let challenges = getChallenges(null, true);
|
|
||||||
challenges.forEach(challengeBlock => {
|
|
||||||
unpackChallengeBlock(challengeBlock);
|
|
||||||
});
|
|
@ -1,22 +0,0 @@
|
|||||||
body {
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
script.unpacked, pre.unpacked {
|
|
||||||
display: block;
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 14px;
|
|
||||||
white-space: pre;
|
|
||||||
border: 1px solid blue;
|
|
||||||
background: #EFEFEF;
|
|
||||||
padding: .5em 1em;
|
|
||||||
margin: 1em;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.unpacked {
|
|
||||||
border: 1px solid black;
|
|
||||||
padding: .5em 1em;
|
|
||||||
margin: 1em;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
/* eslint-disable no-unused-vars,max-len */
|
|
||||||
window._ = require('lodash');
|
|
||||||
window.test = require('tape').test;
|
|
||||||
|
|
||||||
// check for Browser TAP chrome extension, available here:
|
|
||||||
// https://chrome.google.com/webstore/detail/browser-tap/ncfblaiipckncgeipgmpdioedcdmofei?hl=en
|
|
||||||
if (window.tapExtension) {
|
|
||||||
window.test = window.tapExtension(window.test);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addAssertsToTapTest = require('./addAssertsToTapTest');
|
|
||||||
window.$ = require('jquery');
|
|
||||||
|
|
||||||
test('framework', function(t) {
|
|
||||||
t.plan(1);
|
|
||||||
t.equal(1, 1, 'one equals one');
|
|
||||||
});
|
|
||||||
|
|
@ -1,461 +0,0 @@
|
|||||||
/* eslint-disable no-inline-comments */
|
|
||||||
import fs from 'fs-extra';
|
|
||||||
import path from 'path';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import { dasherize } from './utils';
|
|
||||||
|
|
||||||
const jsonLinePrefix = '//--JSON:';
|
|
||||||
const paragraphBreak = '<!--break-->';
|
|
||||||
|
|
||||||
class ChallengeFile {
|
|
||||||
constructor(dir, name, suffix) {
|
|
||||||
this.dir = dir;
|
|
||||||
this.name = name;
|
|
||||||
this.suffix = suffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
filePath() {
|
|
||||||
return path.join(this.dir, this.name + this.suffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
write(contents) {
|
|
||||||
if (_.isArray(contents)) {
|
|
||||||
contents = contents.join('\n');
|
|
||||||
}
|
|
||||||
fs.writeFile(this.filePath(), contents, err => {
|
|
||||||
if (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
readChunks() {
|
|
||||||
// todo: make this work async
|
|
||||||
// todo: make sure it works with encodings
|
|
||||||
let data = fs.readFileSync(this.filePath());
|
|
||||||
let lines = data.toString().split(/(?:\r\n|\r|\n)/g);
|
|
||||||
|
|
||||||
function removeLeadingEmptyLines(array) {
|
|
||||||
let emptyString = /^\s*$/;
|
|
||||||
while (array && Array.isArray(array) && emptyString.test(array[0])) {
|
|
||||||
array.shift();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let chunkEnd = /(<!|\/\*)--end--/;
|
|
||||||
let index = 0;
|
|
||||||
|
|
||||||
function endOfFile() {
|
|
||||||
return index === lines.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
function nextLine() {
|
|
||||||
if (endOfFile()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return lines[index++].toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
function readDescription() {
|
|
||||||
let description = [];
|
|
||||||
let currentParagraph = [];
|
|
||||||
|
|
||||||
function pushParagraph() {
|
|
||||||
removeLeadingEmptyLines(currentParagraph);
|
|
||||||
description.push(currentParagraph.join('\n'));
|
|
||||||
currentParagraph = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!endOfFile()) {
|
|
||||||
let line = nextLine();
|
|
||||||
if (chunkEnd.test(line)) {
|
|
||||||
pushParagraph();
|
|
||||||
return description;
|
|
||||||
} else if (line === paragraphBreak) {
|
|
||||||
pushParagraph();
|
|
||||||
} else {
|
|
||||||
currentParagraph.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
|
|
||||||
// instead of an array of lines like some other fields
|
|
||||||
if (chunks.solutions) {
|
|
||||||
chunks.solutions = [chunks.solutions.join('\n')];
|
|
||||||
removeLeadingEmptyLines(chunks.solutions);
|
|
||||||
}
|
|
||||||
|
|
||||||
// console.log(JSON.stringify(chunks, null, 2));
|
|
||||||
return chunks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { ChallengeFile };
|
|
||||||
|
|
||||||
class UnpackedChallenge {
|
|
||||||
constructor(targetDir, challengeJson, index) {
|
|
||||||
this.targetDir = targetDir;
|
|
||||||
this.index = index;
|
|
||||||
|
|
||||||
// todo: merge challengeJson properties into this object?
|
|
||||||
this.challenge = challengeJson;
|
|
||||||
|
|
||||||
// extract names of block and superblock from path
|
|
||||||
// note: this is a bit redundant with the
|
|
||||||
// fileName,superBlock,superOrder fields
|
|
||||||
// that getChallenges() adds to the challenge JSON
|
|
||||||
let targetDirPath = path.parse(targetDir);
|
|
||||||
let parentDirPath = path.parse(targetDirPath.dir);
|
|
||||||
// superBlockName e.g. "03-front-end-libraries"
|
|
||||||
this.superBlockName = parentDirPath.base;
|
|
||||||
// challengeBlockName e.g. "bootstrap"
|
|
||||||
this.challengeBlockName = targetDirPath.base;
|
|
||||||
}
|
|
||||||
|
|
||||||
unpack() {
|
|
||||||
this.challengeFile().write(this.unpackedHTML());
|
|
||||||
}
|
|
||||||
|
|
||||||
challengeFile() {
|
|
||||||
return new ChallengeFile(this.targetDir, this.baseName(), '.html');
|
|
||||||
}
|
|
||||||
|
|
||||||
baseName() {
|
|
||||||
// eslint-disable-next-line no-nested-ternary
|
|
||||||
let prefix =
|
|
||||||
(this.index < 10 ? '00' : this.index < 100 ? '0' : '') + this.index;
|
|
||||||
return `${prefix}-${dasherize(this.challenge.title)}-${this.challenge.id}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
expandedDescription(description) {
|
|
||||||
let out = [];
|
|
||||||
description.forEach(part => {
|
|
||||||
if (_.isString(part)) {
|
|
||||||
out.push(part.toString());
|
|
||||||
out.push(paragraphBreak);
|
|
||||||
} else {
|
|
||||||
// Descriptions are weird since sometimes they're text and sometimes
|
|
||||||
// they're "steps" which appear one at a time with optional pix and
|
|
||||||
// captions and links, or "questions" with choices and explanations...
|
|
||||||
// For now we preserve non-string descriptions via JSON but this is
|
|
||||||
// not a great solution.
|
|
||||||
// It would be better if "steps" and "description" were separate fields.
|
|
||||||
// For the record, the (unnamed) fields in step are:
|
|
||||||
// 0: image URL
|
|
||||||
// 1: caption
|
|
||||||
// 2: text
|
|
||||||
// 3: link URL
|
|
||||||
out.push(jsonLinePrefix + JSON.stringify(part));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (out[out.length - 1] === paragraphBreak) {
|
|
||||||
out.pop();
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
expandedTests(tests) {
|
|
||||||
if (!tests) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
let out = [];
|
|
||||||
tests.forEach(test => {
|
|
||||||
if (_.isString(test)) {
|
|
||||||
out.push(test);
|
|
||||||
} else {
|
|
||||||
// todo: figure out what to do about these id-title challenge links
|
|
||||||
out.push(jsonLinePrefix + JSON.stringify(test));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
unpackedHTML() {
|
|
||||||
let text = [];
|
|
||||||
text.push('<html>');
|
|
||||||
text.push('<head>');
|
|
||||||
text.push('<link rel="stylesheet" href="../../../unpacked.css">');
|
|
||||||
text.push('<!-- shim to enable running the tests in-browser -->');
|
|
||||||
text.push('<script src="../../unpacked-bundle.js"></script>');
|
|
||||||
text.push('</head>');
|
|
||||||
text.push('<body>');
|
|
||||||
text.push(`<h1>${this.challenge.title}</h1>`);
|
|
||||||
text.push(`<p>This is the <b>unpacked</b> version of
|
|
||||||
<code>${this.superBlockName}/${this.challengeBlockName}</code>
|
|
||||||
(challenge id <code>${this.challenge.id}</code>).</p>`);
|
|
||||||
text.push('<p>Open the JavaScript console to see test results.</p>');
|
|
||||||
|
|
||||||
text.push(`<p>Edit this HTML file (between <!-- marks only!)
|
|
||||||
and run <code>npm run repack</code>
|
|
||||||
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('<h2>Description</h2>');
|
|
||||||
text.push('<div class="unpacked description">');
|
|
||||||
text.push('<!--description-->');
|
|
||||||
if (this.challenge.description.length) {
|
|
||||||
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('</div>');
|
|
||||||
|
|
||||||
text.push('');
|
|
||||||
text.push('<h2>Files</h2>');
|
|
||||||
text.push(`
|
|
||||||
<p>Format of file:</p>
|
|
||||||
<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('<!--end-->');
|
|
||||||
text.push('</div>');
|
|
||||||
|
|
||||||
text.push('');
|
|
||||||
text.push('<h2>Solution</h2>');
|
|
||||||
text.push(
|
|
||||||
'<!--solutions--><script class="unpacked solution" id="solution">'
|
|
||||||
);
|
|
||||||
// Note: none of the challenges have more than one solution
|
|
||||||
// todo: should we deal with multiple solutions or not?
|
|
||||||
if (this.challenge.solutions && this.challenge.solutions.length > 0) {
|
|
||||||
let solution = this.challenge.solutions[0];
|
|
||||||
text.push(solution);
|
|
||||||
}
|
|
||||||
text.push('</script><!--end-->');
|
|
||||||
|
|
||||||
text.push('');
|
|
||||||
text.push('<h2>Tests</h2>');
|
|
||||||
text.push('<script class="unpacked tests">');
|
|
||||||
text.push(
|
|
||||||
`test(\'${this.challenge.title} challenge tests\', ` + 'function(t) {'
|
|
||||||
);
|
|
||||||
text.push('let assert = addAssertsToTapTest(t);');
|
|
||||||
text.push("let code = document.getElementById('solution').innerText;");
|
|
||||||
text.push(
|
|
||||||
't.plan(' +
|
|
||||||
(this.challenge.tests ? this.challenge.tests.length : 0) +
|
|
||||||
');'
|
|
||||||
);
|
|
||||||
text.push('/*--tests--*/');
|
|
||||||
text.push(this.expandedTests(this.challenge.tests).join('\n'));
|
|
||||||
text.push('/*--end--*/');
|
|
||||||
text.push('});');
|
|
||||||
text.push('</script>');
|
|
||||||
|
|
||||||
text.push('');
|
|
||||||
text.push('</body>');
|
|
||||||
text.push('</html>');
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { UnpackedChallenge };
|
|
Reference in New Issue
Block a user