feat(getChallenges): Get Challenges by Lang
This commit is contained in:
		@@ -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 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) {
 | 
					const supportedLangs = ['english'];
 | 
				
			||||||
  let targetDir = path.join(__dirname, dir);
 | 
					
 | 
				
			||||||
  return fs
 | 
					function validateLang(lang) {
 | 
				
			||||||
    .readdirSync(targetDir)
 | 
					  invariant(lang, 'Please provide a language');
 | 
				
			||||||
    .filter(file => !hiddenFile.test(file))
 | 
					  invariant(
 | 
				
			||||||
    .map(function(file) {
 | 
					    supportedLangs.includes(lang),
 | 
				
			||||||
      let superBlock;
 | 
					    `${lang} is not supported
 | 
				
			||||||
      if (fs.statSync(path.join(targetDir, file)).isFile()) {
 | 
					
 | 
				
			||||||
        return { file: file };
 | 
					  Supported languages: ${JSON.stringify(supportedLangs, null, 2)}
 | 
				
			||||||
      }
 | 
					
 | 
				
			||||||
      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);
 | 
					 | 
				
			||||||
    }, []);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function superblockInfo(filePath) {
 | 
					exports.getChallengesForLang = function getChallengesForLang(lang) {
 | 
				
			||||||
  let parts = (filePath || '').split('-');
 | 
					  validateLang(lang);
 | 
				
			||||||
  let order = parseInt(parts[0], 10);
 | 
					  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(fileName) {
 | 
				
			||||||
 | 
					  const [maybeOrder, ...superBlock] = fileName.split('-');
 | 
				
			||||||
 | 
					  let order = parseInt(maybeOrder, 10);
 | 
				
			||||||
  if (isNaN(order)) {
 | 
					  if (isNaN(order)) {
 | 
				
			||||||
    return { order: 0, name: filePath };
 | 
					    return { order: 0, name: fileName };
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      order: order,
 | 
					      order: order,
 | 
				
			||||||
      name: parts.splice(1).join('-')
 | 
					      name: superBlock.join('-')
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// unpackFlag is an argument passed by the unpack script in unpack.js
 | 
					function getBlockNameFromPath(filePath) {
 | 
				
			||||||
// which allows us to conditionall omit translations when running
 | 
					  const [, block] = filePath.split('/');
 | 
				
			||||||
// the test suite and prevent schema related errors in the main fCC branch
 | 
					  return block;
 | 
				
			||||||
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;
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,7 @@
 | 
				
			|||||||
const gulp = require('gulp');
 | 
					const gulp = require('gulp');
 | 
				
			||||||
const util = require('gulp-util');
 | 
					 | 
				
			||||||
const jsonMinify = require('gulp-json-minify');
 | 
					 | 
				
			||||||
const babel = require('gulp-babel');
 | 
					const babel = require('gulp-babel');
 | 
				
			||||||
const rename = require('gulp-rename');
 | 
					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.task('babel-getChallenges', () =>
 | 
				
			||||||
  gulp.src('./getChallenges.js')
 | 
					  gulp.src('./getChallenges.js')
 | 
				
			||||||
    .pipe(babel({
 | 
					    .pipe(babel({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@ const { omit, findLastIndex } = require('lodash');
 | 
				
			|||||||
const YAML = require('js-yaml');
 | 
					const YAML = require('js-yaml');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { dasherize } = require('./utils');
 | 
					const { dasherize } = require('./utils');
 | 
				
			||||||
const getChallenges = require('./getChallenges');
 | 
					const { getChallenges } = require('./getChallenges');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const blackListedFieldNames = [
 | 
					const blackListedFieldNames = [
 | 
				
			||||||
  'betaSolutions',
 | 
					  'betaSolutions',
 | 
				
			||||||
@@ -22,21 +22,34 @@ const blackListedFieldNames = [
 | 
				
			|||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
getChallenges().forEach(block => {
 | 
					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 blockDashedName = dasherize(name);
 | 
				
			||||||
  const blockMeta = {
 | 
					  const blockMeta = {
 | 
				
			||||||
    name,
 | 
					    name,
 | 
				
			||||||
    dashedName: blockDashedName,
 | 
					    dashedName: blockDashedName,
 | 
				
			||||||
    order,
 | 
					    order,
 | 
				
			||||||
    time,
 | 
					    time,
 | 
				
			||||||
 | 
					    template,
 | 
				
			||||||
 | 
					    required,
 | 
				
			||||||
    superBlock,
 | 
					    superBlock,
 | 
				
			||||||
    superOrder,
 | 
					    superOrder,
 | 
				
			||||||
    challengeOrder: challenges.map(({id, title}) => [id, title])
 | 
					    challengeOrder: challenges.map(({ id, title }) => [id, title]),
 | 
				
			||||||
 | 
					    ...restBlock
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  const superOrderPrefix = `0${superOrder}`;
 | 
					  const superOrderPrefix = `0${superOrder}`;
 | 
				
			||||||
  const outputDir = path.resolve(
 | 
					  const outputDir = path.resolve(
 | 
				
			||||||
    __dirname,
 | 
					    __dirname,
 | 
				
			||||||
    `./challenges/en/${superOrderPrefix}-${superBlock}/${blockDashedName}`
 | 
					    `./challenges/english/${superOrderPrefix}-${superBlock}/${blockDashedName}`
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
  fs.ensureDirSync(outputDir);
 | 
					  fs.ensureDirSync(outputDir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -49,7 +62,7 @@ getChallenges().forEach(block => {
 | 
				
			|||||||
      ...restChallenge
 | 
					      ...restChallenge
 | 
				
			||||||
    } = challenge;
 | 
					    } = challenge;
 | 
				
			||||||
    const challengeMeta = omit(restChallenge, blackListedFieldNames);
 | 
					    const challengeMeta = omit(restChallenge, blackListedFieldNames);
 | 
				
			||||||
    const challengeFileName = `${dasherize(challenge.title)}.en.md`;
 | 
					    const challengeFileName = `${dasherize(challenge.title)}.english.md`;
 | 
				
			||||||
    let description = '';
 | 
					    let description = '';
 | 
				
			||||||
    let instructions = '';
 | 
					    let instructions = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -81,7 +94,7 @@ ${instructions}
 | 
				
			|||||||
<section id='tests'>
 | 
					<section id='tests'>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
\`\`\`yml
 | 
					\`\`\`yml
 | 
				
			||||||
${YAML.dump(tests, { lineWidth: 10000 })}
 | 
					${YAML.dump({ tests }, { lineWidth: 10000 })}
 | 
				
			||||||
\`\`\`
 | 
					\`\`\`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</section>
 | 
					</section>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										69
									
								
								curriculum/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										69
									
								
								curriculum/package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -4600,6 +4600,12 @@
 | 
				
			|||||||
      "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=",
 | 
					      "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "each-limit": {
 | 
				
			||||||
 | 
					      "version": "1.0.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/each-limit/-/each-limit-1.0.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-OAFACDNnqK9kKZvKwV/dWxqXcZY=",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "editor": {
 | 
					    "editor": {
 | 
				
			||||||
      "version": "1.0.0",
 | 
					      "version": "1.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz",
 | 
				
			||||||
@@ -5090,6 +5096,12 @@
 | 
				
			|||||||
      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
 | 
					      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "eventemitter3": {
 | 
				
			||||||
 | 
					      "version": "1.2.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "events": {
 | 
					    "events": {
 | 
				
			||||||
      "version": "2.1.0",
 | 
					      "version": "2.1.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz",
 | 
				
			||||||
@@ -7225,16 +7237,6 @@
 | 
				
			|||||||
        "vinyl-sourcemaps-apply": "0.2.1"
 | 
					        "vinyl-sourcemaps-apply": "0.2.1"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "gulp-json-minify": {
 | 
					 | 
				
			||||||
      "version": "1.2.2",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/gulp-json-minify/-/gulp-json-minify-1.2.2.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha512-8acCNnGiDELUh9qqZVm57eu4KVclibiVM7hXxeMn3nsdcQtEWfHUSpcxvrqTVCL5MchErGMDDDSxmcF6RTFcJQ==",
 | 
					 | 
				
			||||||
      "dev": true,
 | 
					 | 
				
			||||||
      "requires": {
 | 
					 | 
				
			||||||
        "node-json-minify": "1.0.0",
 | 
					 | 
				
			||||||
        "through2": "2.0.3"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "gulp-rename": {
 | 
					    "gulp-rename": {
 | 
				
			||||||
      "version": "1.3.0",
 | 
					      "version": "1.3.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.3.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.3.0.tgz",
 | 
				
			||||||
@@ -7701,7 +7703,6 @@
 | 
				
			|||||||
      "version": "2.2.4",
 | 
					      "version": "2.2.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
 | 
				
			||||||
      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
 | 
					      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
 | 
				
			||||||
      "dev": true,
 | 
					 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "loose-envify": "1.3.1"
 | 
					        "loose-envify": "1.3.1"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -8253,8 +8254,7 @@
 | 
				
			|||||||
    "js-tokens": {
 | 
					    "js-tokens": {
 | 
				
			||||||
      "version": "3.0.2",
 | 
					      "version": "3.0.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
 | 
				
			||||||
      "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
 | 
					      "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
 | 
				
			||||||
      "dev": true
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "js-yaml": {
 | 
					    "js-yaml": {
 | 
				
			||||||
      "version": "3.12.0",
 | 
					      "version": "3.12.0",
 | 
				
			||||||
@@ -9138,6 +9138,18 @@
 | 
				
			|||||||
      "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=",
 | 
					      "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "lodash.isobject": {
 | 
				
			||||||
 | 
					      "version": "3.0.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "lodash.isundefined": {
 | 
				
			||||||
 | 
					      "version": "3.0.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-I+89lTVWUgOmbO/VuDD4SJEa+0g=",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "lodash.kebabcase": {
 | 
					    "lodash.kebabcase": {
 | 
				
			||||||
      "version": "4.1.1",
 | 
					      "version": "4.1.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz",
 | 
				
			||||||
@@ -9347,7 +9359,6 @@
 | 
				
			|||||||
      "version": "1.3.1",
 | 
					      "version": "1.3.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
 | 
				
			||||||
      "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
 | 
					      "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
 | 
				
			||||||
      "dev": true,
 | 
					 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "js-tokens": "3.0.2"
 | 
					        "js-tokens": "3.0.2"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -9826,12 +9837,6 @@
 | 
				
			|||||||
        "is-stream": "1.1.0"
 | 
					        "is-stream": "1.1.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node-json-minify": {
 | 
					 | 
				
			||||||
      "version": "1.0.0",
 | 
					 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/node-json-minify/-/node-json-minify-1.0.0.tgz",
 | 
					 | 
				
			||||||
      "integrity": "sha1-e7NDL5ZYtr6x2ZP9XVOzyinQ15w=",
 | 
					 | 
				
			||||||
      "dev": true
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "normalize-package-data": {
 | 
					    "normalize-package-data": {
 | 
				
			||||||
      "version": "2.4.0",
 | 
					      "version": "2.4.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
 | 
				
			||||||
@@ -11039,6 +11044,17 @@
 | 
				
			|||||||
        "set-immediate-shim": "1.0.1"
 | 
					        "set-immediate-shim": "1.0.1"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "readdirp-walk": {
 | 
				
			||||||
 | 
					      "version": "1.6.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/readdirp-walk/-/readdirp-walk-1.6.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-B1ZfV6uTqWfW3mRPRmPAE1b1oLo=",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "eventemitter3": "1.2.0",
 | 
				
			||||||
 | 
					        "micromatch": "2.3.11",
 | 
				
			||||||
 | 
					        "walk-filtered": "0.8.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "rechoir": {
 | 
					    "rechoir": {
 | 
				
			||||||
      "version": "0.6.2",
 | 
					      "version": "0.6.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
 | 
				
			||||||
@@ -12926,6 +12942,19 @@
 | 
				
			|||||||
      "integrity": "sha512-EqzLchIMYLBjRPoqVsEkZOa/4Vr2RfOWbd58F+I/Gj79AYTrsseMunxbbSkbYfrqZaXSuPBBXNSOhtJgg0PpmA==",
 | 
					      "integrity": "sha512-EqzLchIMYLBjRPoqVsEkZOa/4Vr2RfOWbd58F+I/Gj79AYTrsseMunxbbSkbYfrqZaXSuPBBXNSOhtJgg0PpmA==",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "walk-filtered": {
 | 
				
			||||||
 | 
					      "version": "0.8.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/walk-filtered/-/walk-filtered-0.8.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-RsMaJG7HTO9QwOtLSxVjvHYaAKU=",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "each-limit": "1.0.0",
 | 
				
			||||||
 | 
					        "graceful-fs": "4.1.11",
 | 
				
			||||||
 | 
					        "lodash.isobject": "3.0.2",
 | 
				
			||||||
 | 
					        "lodash.isundefined": "3.0.1",
 | 
				
			||||||
 | 
					        "object-assign": "4.1.1"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "whatwg-fetch": {
 | 
					    "whatwg-fetch": {
 | 
				
			||||||
      "version": "2.0.4",
 | 
					      "version": "2.0.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,11 +12,9 @@
 | 
				
			|||||||
    "url": "https://github.com/freeCodeCamp/curriculum/issues"
 | 
					    "url": "https://github.com/freeCodeCamp/curriculum/issues"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "version": "3.2.1",
 | 
					  "version": "3.2.1",
 | 
				
			||||||
  "main": "dist/index.js",
 | 
					  "main": "getChallenges.js",
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
    "build": "npm run build:js && npm run build:json",
 | 
					    "build": "gulp babel",
 | 
				
			||||||
    "build:js": "gulp babel",
 | 
					 | 
				
			||||||
    "build:json": "gulp json:minify",
 | 
					 | 
				
			||||||
    "precommit": "lint-staged",
 | 
					    "precommit": "lint-staged",
 | 
				
			||||||
    "commit": "git-cz",
 | 
					    "commit": "git-cz",
 | 
				
			||||||
    "commitmsg": "commitlint -e",
 | 
					    "commitmsg": "commitlint -e",
 | 
				
			||||||
@@ -36,7 +34,9 @@
 | 
				
			|||||||
      "config": "commitizen.config.js"
 | 
					      "config": "commitizen.config.js"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {},
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "invariant": "^2.2.4"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@commitlint/cli": "^7.0.0",
 | 
					    "@commitlint/cli": "^7.0.0",
 | 
				
			||||||
    "@commitlint/config-conventional": "^7.0.1",
 | 
					    "@commitlint/config-conventional": "^7.0.1",
 | 
				
			||||||
@@ -64,9 +64,7 @@
 | 
				
			|||||||
    "fs-extra": "^6.0.1",
 | 
					    "fs-extra": "^6.0.1",
 | 
				
			||||||
    "gulp": "^3.9.1",
 | 
					    "gulp": "^3.9.1",
 | 
				
			||||||
    "gulp-babel": "^7.0.1",
 | 
					    "gulp-babel": "^7.0.1",
 | 
				
			||||||
    "gulp-json-minify": "^1.2.2",
 | 
					 | 
				
			||||||
    "gulp-rename": "^1.3.0",
 | 
					    "gulp-rename": "^1.3.0",
 | 
				
			||||||
    "gulp-util": "^3.0.8",
 | 
					 | 
				
			||||||
    "husky": "^0.14.3",
 | 
					    "husky": "^0.14.3",
 | 
				
			||||||
    "joi": "^13.3.0",
 | 
					    "joi": "^13.3.0",
 | 
				
			||||||
    "joi-objectid": "^2.0.0",
 | 
					    "joi-objectid": "^2.0.0",
 | 
				
			||||||
@@ -76,6 +74,7 @@
 | 
				
			|||||||
    "lodash": "^4.17.10",
 | 
					    "lodash": "^4.17.10",
 | 
				
			||||||
    "prettier": "^1.13.5",
 | 
					    "prettier": "^1.13.5",
 | 
				
			||||||
    "prettier-package-json": "^1.6.0",
 | 
					    "prettier-package-json": "^1.6.0",
 | 
				
			||||||
 | 
					    "readdirp-walk": "^1.6.0",
 | 
				
			||||||
    "rx": "^4.1.0",
 | 
					    "rx": "^4.1.0",
 | 
				
			||||||
    "semantic-release": "^15.6.0",
 | 
					    "semantic-release": "^15.6.0",
 | 
				
			||||||
    "tap-spec": "^5.0.0",
 | 
					    "tap-spec": "^5.0.0",
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user