Skip to content

Commit

Permalink
feat(getChallenges): Get Challenges by Lang
Browse files Browse the repository at this point in the history
  • Loading branch information
Bouncey committed Oct 5, 2018
1 parent edd1133 commit 2723a94
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 105 deletions.
140 changes: 77 additions & 63 deletions curriculum/getChallenges.js
Original file line number Diff line number Diff line change
@@ -1,76 +1,90 @@
/* eslint-disable no-self-compare */
// no import here as this runs without babel
const fs = require('fs');
const path = require('path');
const omit = require('lodash/omit');
const { findIndex } = require('lodash');
const invariant = require('invariant');
const readDirP = require('readdirp-walk');

const hiddenFile = /(^(\.|\/\.))|(.md$)/g;
const { parseMarkdown } = require('../tools/challenge-md-parser');

function getFilesFor(dir) {
let targetDir = path.join(__dirname, dir);
return fs
.readdirSync(targetDir)
.filter(file => !hiddenFile.test(file))
.map(function(file) {
let superBlock;
if (fs.statSync(path.join(targetDir, file)).isFile()) {
return { file: file };
}
superBlock = file;
return getFilesFor(path.join(dir, superBlock)).map(function(data) {
return {
file: path.join(superBlock, data.file),
superBlock: superBlock
};
});
})
.reduce(function(files, entry) {
return files.concat(entry);
}, []);
const supportedLangs = ['english'];

function validateLang(lang) {
invariant(lang, 'Please provide a language');
invariant(
supportedLangs.includes(lang),
`${lang} is not supported
Supported languages: ${JSON.stringify(supportedLangs, null, 2)}
`
);
}

exports.getChallengesForLang = function getChallengesForLang(lang) {
validateLang(lang);
let curriculum = {};
return new Promise(resolve =>
readDirP({ root: path.resolve(__dirname, `./challenges/${lang}`) })
.on('data', file => buildCurriculum(file, curriculum))
.on('end', () => resolve(curriculum))
);
};

async function buildCurriculum(file, curriculum) {
const { name, depth, path, fullPath, stat } = file;
if (depth === 1 && stat.isDirectory()) {
// extract the superBlock info
const { order, name: superBlock } = superBlockInfo(name);
curriculum[superBlock] = { superBlock, order, blocks: {} };
return;
}
if (depth === 2 && stat.isDirectory()) {
const blockMeta = require(`${fullPath}/meta.json`);
const { name: superBlock } = superBlockInfoFromPath(path);
const blockInfo = { meta: blockMeta, challenges: [] };
curriculum[superBlock].blocks[name] = blockInfo;
return;
}
if (name === 'meta.json') {
return;
}
const block = getBlockNameFromPath(path);
const { name: superBlock } = superBlockInfoFromPath(path);
const challenge = await parseMarkdown(fullPath);
const challengeBlock = curriculum[superBlock].blocks[block];
const { meta } = challengeBlock;
const challengeOrder = findIndex(
meta.challengeOrder,
([id]) => id === challenge.id
);
const { name: blockName, order, superOrder } = meta;
challenge.block = blockName;
challenge.order = order;
challenge.superOrder = superOrder;
challenge.superBlock = superBlock;
challenge.challengeOrder = challengeOrder;
challengeBlock.challenges = [...challengeBlock.challenges, challenge];
}

function superBlockInfoFromPath(filePath) {
const [maybeSuper] = filePath.split('/');
return superBlockInfo(maybeSuper);
}

function superblockInfo(filePath) {
let parts = (filePath || '').split('-');
let order = parseInt(parts[0], 10);
function superBlockInfo(fileName) {
const [maybeOrder, ...superBlock] = fileName.split('-');
let order = parseInt(maybeOrder, 10);
if (isNaN(order)) {
return { order: 0, name: filePath };
return { order: 0, name: fileName };
} else {
return {
order: order,
name: parts.splice(1).join('-')
name: superBlock.join('-')
};
}
}

// unpackFlag is an argument passed by the unpack script in unpack.js
// which allows us to conditionall omit translations when running
// the test suite and prevent schema related errors in the main fCC branch
module.exports = function getChallenges(challengesDir, unpackFlag) {
if (!challengesDir) {
challengesDir = 'challenges';
}
return getFilesFor(challengesDir).map(function(data) {
const challengeSpec = require('./' + challengesDir + '/' + data.file);
let superInfo = superblockInfo(data.superBlock);
challengeSpec.fileName = data.file;
challengeSpec.superBlock = superInfo.name;
challengeSpec.superOrder = superInfo.order;
challengeSpec.challenges = challengeSpec.challenges.map(challenge =>
omit(challenge, [
'betaSolutions',
'betaTests',
'hints',
'MDNlinks',
'null',
'rawSolutions',
'react',
'reactRedux',
'redux',
'releasedOn',
unpackFlag ? undefined : 'translations',
'type'
])
);
return challengeSpec;
});
};
function getBlockNameFromPath(filePath) {
const [, block] = filePath.split('/');
return block;
}

9 changes: 0 additions & 9 deletions curriculum/gulpfile.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
const gulp = require('gulp');
const util = require('gulp-util');
const jsonMinify = require('gulp-json-minify');
const babel = require('gulp-babel');
const rename = require('gulp-rename');

gulp.task('json:minify', function() {
return gulp.src('./challenges/**/*.json')
.pipe(jsonMinify())
.pipe(gulp.dest('dist/challenges/'))
.on('error', util.log);
});

gulp.task('babel-getChallenges', () =>
gulp.src('./getChallenges.js')
.pipe(babel({
Expand Down
25 changes: 19 additions & 6 deletions curriculum/md-conversion.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const { omit, findLastIndex } = require('lodash');
const YAML = require('js-yaml');

const { dasherize } = require('./utils');
const getChallenges = require('./getChallenges');
const { getChallenges } = require('./getChallenges');

const blackListedFieldNames = [
'betaSolutions',
Expand All @@ -22,21 +22,34 @@ const blackListedFieldNames = [
];

getChallenges().forEach(block => {
const { name, order, challenges, time = '', superBlock, superOrder } = block;
const {
name,
order,
challenges,
time = '',
superBlock,
superOrder,
template = '',
required = [],
...restBlock
} = block;
const blockDashedName = dasherize(name);
const blockMeta = {
name,
dashedName: blockDashedName,
order,
time,
template,
required,
superBlock,
superOrder,
challengeOrder: challenges.map(({id, title}) => [id, title])
challengeOrder: challenges.map(({ id, title }) => [id, title]),
...restBlock
};
const superOrderPrefix = `0${superOrder}`;
const outputDir = path.resolve(
__dirname,
`./challenges/en/${superOrderPrefix}-${superBlock}/${blockDashedName}`
`./challenges/english/${superOrderPrefix}-${superBlock}/${blockDashedName}`
);
fs.ensureDirSync(outputDir);

Expand All @@ -49,7 +62,7 @@ getChallenges().forEach(block => {
...restChallenge
} = challenge;
const challengeMeta = omit(restChallenge, blackListedFieldNames);
const challengeFileName = `${dasherize(challenge.title)}.en.md`;
const challengeFileName = `${dasherize(challenge.title)}.english.md`;
let description = '';
let instructions = '';

Expand Down Expand Up @@ -81,7 +94,7 @@ ${instructions}
<section id='tests'>
\`\`\`yml
${YAML.dump(tests, { lineWidth: 10000 })}
${YAML.dump({ tests }, { lineWidth: 10000 })}
\`\`\`
</section>
Expand Down
69 changes: 49 additions & 20 deletions curriculum/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 2723a94

Please sign in to comment.