feat(curriculum): add project creation tool (#42410)

* refactor: extract help category map as JSON

* refactor: extract block names as json

* feat: add create-project script

* fix: correct case for tsconfig target

Co-authored-by: Shaun Hamilton <shauhami020@gmail.com>

Co-authored-by: Shaun Hamilton <shauhami020@gmail.com>
This commit is contained in:
Oliver Eyton-Williams
2021-06-08 21:27:45 +02:00
committed by GitHub
parent bd88d9f7ce
commit bd4d46915a
13 changed files with 1031 additions and 96 deletions

View File

@ -42,8 +42,7 @@
"files": ["**/*.ts?(x)"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"tsconfigRootDir": "./client",
"project": ["./tsconfig.json"]
"project": ["./client/tsconfig.json", "./tools/challenge-helper-scripts/tsconfig.json"]
},
"extends": [
"plugin:@typescript-eslint/recommended",

View File

@ -76,66 +76,4 @@ exports.submitTypes = {
};
// determine which help forum questions should be posted to
exports.helpCategoryMap = {
'basic-html-and-html5': 'HTML-CSS',
'basic-css': 'HTML-CSS',
'applied-visual-design': 'HTML-CSS',
'applied-accessibility': 'HTML-CSS',
'responsive-web-design-principles': 'HTML-CSS',
'css-flexbox': 'HTML-CSS',
'css-grid': 'HTML-CSS',
'responsive-web-design-projects': 'HTML-CSS',
'basic-javascript': 'JavaScript',
es6: 'JavaScript',
'regular-expressions': 'JavaScript',
debugging: 'JavaScript',
'basic-data-structures': 'JavaScript',
'basic-algorithm-scripting': 'JavaScript',
'object-oriented-programming': 'JavaScript',
'functional-programming': 'JavaScript',
'intermediate-algorithm-scripting': 'JavaScript',
'javascript-algorithms-and-data-structures-projects': 'JavaScript',
bootstrap: 'HTML-CSS',
jquery: 'JavaScript',
sass: 'HTML-CSS',
react: 'JavaScript',
redux: 'JavaScript',
'react-and-redux': 'JavaScript',
'front-end-libraries-projects': 'JavaScript',
'data-visualization-with-d3': 'JavaScript',
'json-apis-and-ajax': 'JavaScript',
'data-visualization-projects': 'JavaScript',
'managing-packages-with-npm': 'JavaScript',
'basic-node-and-express': 'JavaScript',
'mongodb-and-mongoose': 'JavaScript',
'apis-and-microservices-projects': 'JavaScript',
'information-security-with-helmetjs': 'JavaScript',
'quality-assurance-and-testing-with-chai': 'JavaScript',
'advanced-node-and-express': 'JavaScript',
'quality-assurance-projects': 'JavaScript',
'information-security-projects': 'JavaScript',
algorithms: 'JavaScript',
'data-structures': 'JavaScript',
'take-home-projects': 'JavaScript',
'rosetta-code': 'JavaScript',
'project-euler': 'JavaScript',
'scientific-computing-with-python': 'Python',
'scientific-computing-with-python-projects': 'Python',
'data-analysis-with-python': 'Python',
'data-analysis-with-python-projects': 'Python',
'machine-learning-with-python': 'Python',
'machine-learning-with-python-projects': 'Python',
'python-for-everybody': 'Python',
tensorflow: 'Python',
'how-neural-networks-work': 'Python',
numpy: 'Python',
'data-analysis-with-python-course': 'Python',
'python-for-penetration-testing': 'Python',
'basic-html-cat-photo-app': 'HTML-CSS',
'basic-css-cafe-menu': 'HTML-CSS',
'css-variables-skyline': 'HTML-CSS',
'basic-javascript-rpg-game': 'JavaScript',
'functional-programming-spreadsheet': 'JavaScript',
'intermediate-javascript-calorie-counter': 'JavaScript',
'd3-dashboard': 'JavaScript'
};
exports.helpCategoryMap = require('./help-category-map.json');

View File

@ -0,0 +1,63 @@
{
"basic-html-and-html5": "HTML-CSS",
"basic-css": "HTML-CSS",
"applied-visual-design": "HTML-CSS",
"applied-accessibility": "HTML-CSS",
"responsive-web-design-principles": "HTML-CSS",
"css-flexbox": "HTML-CSS",
"css-grid": "HTML-CSS",
"responsive-web-design-projects": "HTML-CSS",
"basic-javascript": "JavaScript",
"es6": "JavaScript",
"regular-expressions": "JavaScript",
"debugging": "JavaScript",
"basic-data-structures": "JavaScript",
"basic-algorithm-scripting": "JavaScript",
"object-oriented-programming": "JavaScript",
"functional-programming": "JavaScript",
"intermediate-algorithm-scripting": "JavaScript",
"javascript-algorithms-and-data-structures-projects": "JavaScript",
"bootstrap": "HTML-CSS",
"jquery": "JavaScript",
"sass": "HTML-CSS",
"react": "JavaScript",
"redux": "JavaScript",
"react-and-redux": "JavaScript",
"front-end-libraries-projects": "JavaScript",
"data-visualization-with-d3": "JavaScript",
"json-apis-and-ajax": "JavaScript",
"data-visualization-projects": "JavaScript",
"managing-packages-with-npm": "JavaScript",
"basic-node-and-express": "JavaScript",
"mongodb-and-mongoose": "JavaScript",
"apis-and-microservices-projects": "JavaScript",
"information-security-with-helmetjs": "JavaScript",
"quality-assurance-and-testing-with-chai": "JavaScript",
"advanced-node-and-express": "JavaScript",
"quality-assurance-projects": "JavaScript",
"information-security-projects": "JavaScript",
"algorithms": "JavaScript",
"data-structures": "JavaScript",
"take-home-projects": "JavaScript",
"rosetta-code": "JavaScript",
"project-euler": "JavaScript",
"scientific-computing-with-python": "Python",
"scientific-computing-with-python-projects": "Python",
"data-analysis-with-python": "Python",
"data-analysis-with-python-projects": "Python",
"machine-learning-with-python": "Python",
"machine-learning-with-python-projects": "Python",
"python-for-everybody": "Python",
"tensorflow": "Python",
"how-neural-networks-work": "Python",
"numpy": "Python",
"data-analysis-with-python-course": "Python",
"python-for-penetration-testing": "Python",
"basic-html-cat-photo-app": "HTML-CSS",
"basic-css-cafe-menu": "HTML-CSS",
"css-variables-skyline": "HTML-CSS",
"basic-javascript-rpg-game": "JavaScript",
"functional-programming-spreadsheet": "JavaScript",
"intermediate-javascript-calorie-counter": "JavaScript",
"d3-dashboard": "JavaScript"
}

View File

@ -0,0 +1,13 @@
{
"name": "",
"isUpcomingChange": true,
"dashedName": "",
"order": 42,
"time": "5 hours",
"template": "",
"required": [],
"superBlock": "",
"superOrder": 1,
"isBeta": true,
"challengeOrder": [["", ""]]
}

View File

@ -0,0 +1,288 @@
import fs from 'fs/promises';
import { existsSync } from 'fs';
import path from 'path';
import { format } from 'prettier';
import { prompt } from 'inquirer';
import { createStepFile } from './utils.js';
import { blockNameify } from '../../utils/block-nameify';
const superBlocks = [
'responsive-web-design',
'javascript-algorithms-and-data-structures',
'front-end-libraries',
'data-visualization',
'apis-and-microservices',
'quality-assurance',
'scientific-computing-with-python',
'data-analysis-with-python',
'information-security',
'machine-learning-with-python',
'coding-interview-prep'
] as const;
type SuperBlock = typeof superBlocks[number];
const helpCategories = ['HTML-CSS', 'JavaScript', 'Python'] as const;
type BlockInfo = {
title: string;
intro: string[];
};
type SuperBlockInfo = {
blocks: Record<string, BlockInfo>;
};
type IntroJson = Record<SuperBlock, SuperBlockInfo>;
type Meta = {
name: string;
isUpcomingChange: boolean;
dashedName: string;
order: number;
time: string;
template: string;
required: string[];
superBlock: string;
superOrder: number;
isBeta: boolean;
challengeOrder: string[][];
};
async function createProject(
superBlock: SuperBlock,
block: string,
helpCategory: string,
order: number,
title?: string
) {
if (!title) {
title = blockNameify(block);
} else if (title !== blockNameify(block)) {
updateBlockNames(block, title).catch(reason => {
throw reason;
});
}
updateIntroJson(superBlock, block, title).catch(reason => {
throw reason;
});
updateHelpCategoryMap(block, helpCategory).catch(reason => {
throw reason;
});
const challengeId = await createFirstChallenge(superBlock, block).catch(
reason => {
throw reason;
}
);
createMetaJson(superBlock, block, title, order, challengeId).catch(reason => {
throw reason;
});
// TODO: remove once we stop relying on markdown in the client.
createIntroMD(superBlock, block, title).catch(reason => {
throw reason;
});
}
async function updateIntroJson(
superBlock: SuperBlock,
block: string,
title: string
) {
const introJsonPath = path.resolve(
__dirname,
'../../client/i18n/locales/english/intro.json'
);
const newIntro = await parseJson<IntroJson>(introJsonPath);
newIntro[superBlock].blocks[block] = {
title,
intro: ['', '']
};
fs.writeFile(
introJsonPath,
format(JSON.stringify(newIntro), { parser: 'json' })
).catch(reason => {
throw reason;
});
}
async function updateHelpCategoryMap(block: string, helpCategory: string) {
const helpCategoryPath = path.resolve(
__dirname,
'../../client/utils/help-category-map.json'
);
const helpMap = await parseJson<Record<string, string>>(helpCategoryPath);
helpMap[block] = helpCategory;
fs.writeFile(
helpCategoryPath,
format(JSON.stringify(helpMap), { parser: 'json' })
).catch(reason => {
throw reason;
});
}
async function updateBlockNames(block: string, title: string) {
const blockNamesPath = path.resolve(
__dirname,
'../../utils/preformatted-block-names.json'
);
const blockNames = await parseJson<Record<string, string>>(blockNamesPath);
blockNames[block] = title;
fs.writeFile(
blockNamesPath,
format(JSON.stringify(blockNames), { parser: 'json' })
).catch(reason => {
throw reason;
});
}
async function createMetaJson(
superBlock: SuperBlock,
block: string,
title: string,
order: number,
challengeId: string
) {
const metaDir = path.resolve(__dirname, '../../curriculum/challenges/_meta');
const newMeta = await parseJson<Meta>('./base-meta.json');
newMeta.name = title;
newMeta.dashedName = block;
newMeta.order = order;
newMeta.superOrder = superBlocks.indexOf(superBlock) + 1;
newMeta.superBlock = superBlock;
newMeta.challengeOrder = [[challengeId, 'Part 1']];
const newMetaDir = path.resolve(metaDir, block);
if (!existsSync(newMetaDir)) {
await fs.mkdir(newMetaDir);
}
fs.writeFile(
path.resolve(metaDir, `${block}/meta.json`),
format(JSON.stringify(newMeta), { parser: 'json' })
).catch(reason => {
throw reason;
});
}
async function createIntroMD(superBlock: string, block: string, title: string) {
const introMD = `---
title: Introduction to the ${title}
block: ${block}
superBlock: Responsive Web Design
isBeta: true
---
## Introduction to the ${title}
This is a test for the new project-based curriculum.`;
const dirPath = path.resolve(
__dirname,
`../../client/src/pages/learn/${superBlock}/${block}/`
);
const filePath = path.resolve(dirPath, 'index.md');
if (!existsSync(dirPath)) {
await fs.mkdir(dirPath);
}
fs.writeFile(filePath, introMD, { encoding: 'utf8' }).catch(reason => {
throw reason;
});
}
async function createFirstChallenge(
superBlock: SuperBlock,
block: string
): Promise<string> {
const superBlockId = (superBlocks.indexOf(superBlock) + 1)
.toString()
.padStart(2, '0');
const newChallengeDir = path.resolve(
__dirname,
`../../curriculum/challenges/english/${superBlockId}-${superBlock}/${block}`
);
if (!existsSync(newChallengeDir)) {
await fs.mkdir(newChallengeDir);
}
// TODO: would be nice if the extension made sense for the challenge, but, at
// least until react I think they're all going to be html anyway.
const challengeSeeds = {
indexhtml: {
contents: '',
ext: 'html',
editableRegionBoundaries: [0, 2]
}
};
// including trailing slash for compatibility with createStepFile
return createStepFile({
projectPath: newChallengeDir + '/',
stepNum: 1,
challengeSeeds,
stepBetween: false
});
}
function parseJson<JsonSchema>(filePath: string) {
return fs
.readFile(filePath, { encoding: 'utf8' })
.then(result => JSON.parse(result) as JsonSchema)
.catch(reason => {
throw reason;
});
}
prompt([
{
name: 'superBlock',
message: 'Which certification does this belong to?',
default: 'responsive-web-design',
type: 'list',
choices: superBlocks
},
{
name: 'block',
message: 'What is the short name (in kebab-case) for this project?',
validate: (block: string) => {
if (!block.length) {
return 'please enter a short name';
}
if (/[^a-z0-9\-]/.test(block)) {
return 'please use alphanumerical characters and kebab case';
}
return true;
},
filter: (block: string) => {
return block.toLowerCase();
}
},
{
name: 'title',
default: ({ block }: { block: string }) => blockNameify(block)
},
{
name: 'helpCategory',
message: 'Choose a help category',
default: 'HTML-CSS',
type: 'list',
choices: helpCategories
},
{
name: 'order',
message: 'Which position does this appear in the certificate?',
default: 42,
validate: (order: string) => {
return parseInt(order, 10) > 0
? true
: 'Order must be an number greater than zero.';
},
filter: (order: string) => {
return parseInt(order, 10);
}
}
])
.then(({ superBlock, block, title, helpCategory, order }) =>
createProject(superBlock, block, helpCategory, order, title)
)
.then(() =>
console.log(
'All set. Now use npm run clean:client in the root and it should be good to go.'
)
)
.catch(console.error);

View File

@ -4,6 +4,85 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@tsconfig/node10": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.7.tgz",
"integrity": "sha512-aBvUmXLQbayM4w3A8TrjwrXs4DZ8iduJnuJLLRGdkWlyakCf1q6uHZJBzXoRA/huAEknG5tcUyQxN3A+In5euQ==",
"dev": true
},
"@tsconfig/node12": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.7.tgz",
"integrity": "sha512-dgasobK/Y0wVMswcipr3k0HpevxFJLijN03A8mYfEPvWvOs14v0ZlYTR4kIgMx8g4+fTyTFv8/jLCIfRqLDJ4A==",
"dev": true
},
"@tsconfig/node14": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.0.tgz",
"integrity": "sha512-RKkL8eTdPv6t5EHgFKIVQgsDapugbuOptNd9OOunN/HAkzmmTnZELx1kNCK0rSdUYGmiFMM3rRQMAWiyp023LQ==",
"dev": true
},
"@tsconfig/node16": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.1.tgz",
"integrity": "sha512-FTgBI767POY/lKNDNbIzgAX6miIDBs6NTCbdlDb8TrWovHsSvaVIZDlTqym29C6UqhzwcJx4CYr+AlrMywA0cA==",
"dev": true
},
"@types/inquirer": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-7.3.1.tgz",
"integrity": "sha512-osD38QVIfcdgsPCT0V3lD7eH0OFurX71Jft18bZrsVQWVRt6TuxRzlr0GJLrxoHZR2V5ph7/qP8se/dcnI7o0g==",
"dev": true,
"requires": {
"@types/through": "*",
"rxjs": "^6.4.0"
}
},
"@types/node": {
"version": "15.12.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.1.tgz",
"integrity": "sha512-zyxJM8I1c9q5sRMtVF+zdd13Jt6RU4r4qfhTd7lQubyThvLfx6yYekWSQjGCGV2Tkecgxnlpl/DNlb6Hg+dmEw==",
"dev": true
},
"@types/through": {
"version": "0.0.30",
"resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.30.tgz",
"integrity": "sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"ansi-escapes": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
"integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
"dev": true,
"requires": {
"type-fest": "^0.21.3"
}
},
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
"dev": true
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@ -13,12 +92,109 @@
"sprintf-js": "~1.0.2"
}
},
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true
},
"bl": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
"dev": true,
"requires": {
"buffer": "^5.5.0",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"bson-objectid": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/bson-objectid/-/bson-objectid-2.0.1.tgz",
"integrity": "sha512-b4D1/G4uP9Yks4rv+nDVsZ4ybT1W5nQYw4lfpfaRP2Q18azlR6Oe2BAuirG1lzrwQFtHnJ0nrK5kWKKZVEMUng==",
"dev": true
},
"buffer": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
"dev": true,
"requires": {
"base64-js": "^1.3.1",
"ieee754": "^1.1.13"
}
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
},
"chalk": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"chardet": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
"dev": true
},
"cli-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
"integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
"dev": true,
"requires": {
"restore-cursor": "^3.1.0"
}
},
"cli-spinners": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.0.tgz",
"integrity": "sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==",
"dev": true
},
"cli-width": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
"integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
"dev": true
},
"clone": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
"dev": true
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"cross-env": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
@ -39,6 +215,33 @@
"which": "^2.0.1"
}
},
"defaults": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
"integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
"dev": true,
"requires": {
"clone": "^1.0.2"
}
},
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
@ -54,6 +257,26 @@
"is-extendable": "^0.1.0"
}
},
"external-editor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
"integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
"dev": true,
"requires": {
"chardet": "^0.7.0",
"iconv-lite": "^0.4.24",
"tmp": "^0.0.33"
}
},
"figures": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
"integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
"dev": true,
"requires": {
"escape-string-regexp": "^1.0.5"
}
},
"gray-matter": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
@ -66,12 +289,79 @@
"strip-bom-string": "^1.0.0"
}
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dev": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"dev": true
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"inquirer": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.1.0.tgz",
"integrity": "sha512-1nKYPoalt1vMBfCMtpomsUc32wmOoWXAoq3kM/5iTfxyQ2f/BxjixQpC+mbZ7BI0JUXHED4/XPXekDVtJNpXYw==",
"dev": true,
"requires": {
"ansi-escapes": "^4.2.1",
"chalk": "^4.1.1",
"cli-cursor": "^3.1.0",
"cli-width": "^3.0.0",
"external-editor": "^3.0.3",
"figures": "^3.0.0",
"lodash": "^4.17.21",
"mute-stream": "0.0.8",
"ora": "^5.3.0",
"run-async": "^2.4.0",
"rxjs": "^6.6.6",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0",
"through": "^2.3.6"
}
},
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
"dev": true
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
"is-interactive": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
"integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
"dev": true
},
"is-unicode-supported": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
"integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
"dev": true
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@ -94,12 +384,132 @@
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true
},
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
"integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
"dev": true,
"requires": {
"chalk": "^4.1.0",
"is-unicode-supported": "^0.1.0"
}
},
"make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true
},
"mute-stream": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
"dev": true
},
"onetime": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
"dev": true,
"requires": {
"mimic-fn": "^2.1.0"
}
},
"ora": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/ora/-/ora-5.4.0.tgz",
"integrity": "sha512-1StwyXQGoU6gdjYkyVcqOLnVlbKj+6yPNNOxJVgpt9t4eksKjiriiHuxktLYkgllwk+D6MbC4ihH84L1udRXPg==",
"dev": true,
"requires": {
"bl": "^4.1.0",
"chalk": "^4.1.0",
"cli-cursor": "^3.1.0",
"cli-spinners": "^2.5.0",
"is-interactive": "^1.0.0",
"is-unicode-supported": "^0.1.0",
"log-symbols": "^4.1.0",
"strip-ansi": "^6.0.0",
"wcwidth": "^1.0.1"
}
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true
},
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true
},
"prettier": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz",
"integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==",
"dev": true
},
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"dev": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"restore-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
"integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
"dev": true,
"requires": {
"onetime": "^5.1.0",
"signal-exit": "^3.0.2"
}
},
"run-async": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
"integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
"dev": true
},
"rxjs": {
"version": "6.6.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
},
"section-matter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
@ -125,18 +535,144 @@
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true
},
"signal-exit": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
"dev": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"source-map-support": {
"version": "0.5.19",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
"integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
"string-width": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.0"
}
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"dev": true,
"requires": {
"safe-buffer": "~5.2.0"
}
},
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.0"
}
},
"strip-bom-string": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
"integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=",
"dev": true
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
"dev": true
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"dev": true,
"requires": {
"os-tmpdir": "~1.0.2"
}
},
"ts-node": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.0.0.tgz",
"integrity": "sha512-ROWeOIUvfFbPZkoDis0L/55Fk+6gFQNZwwKPLinacRl6tsxstTF1DbAcLKkovwnpKMVvOMHP1TIbnwXwtLg1gg==",
"dev": true,
"requires": {
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"source-map-support": "^0.5.17",
"yn": "3.1.1"
}
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
"type-fest": {
"version": "0.21.3",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
"dev": true
},
"typescript": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz",
"integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==",
"dev": true
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true
},
"wcwidth": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
"integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=",
"dev": true,
"requires": {
"defaults": "^1.0.3"
}
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@ -145,6 +681,12 @@
"requires": {
"isexe": "^2.0.0"
}
},
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true
}
}
}

View File

@ -19,11 +19,17 @@
"author": "freeCodeCamp <team@freecodecamp.org>",
"main": "utils.js",
"scripts": {
"test": "mocha --delay --reporter progress --bail"
"test": "mocha --delay --reporter progress --bail",
"create-project": "ts-node create-project"
},
"devDependencies": {
"@types/inquirer": "^7.3.1",
"bson-objectid": "2.0.1",
"cross-env": "7.0.3",
"gray-matter": "4.0.3"
"gray-matter": "4.0.3",
"inquirer": "^8.1.0",
"prettier": "^2.3.1",
"ts-node": "^10.0.0",
"typescript": "^4.3.2"
}
}

View File

@ -0,0 +1,73 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "ES2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
// "module": "es2020", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
// "outDir": "./", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
"noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
/* Module Resolution Options */
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"resolveJsonModule": true, /* Enables direct import of json files */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}
}

View File

@ -0,0 +1,10 @@
type CreateStepOptions = {
projectPath: string;
stepNum: number;
challengeSeeds: Record<string, unknown>;
stepBetween: boolean;
};
export declare function createStepFile(options: CreateStepOptions): string;
// TODO: the rest of the functions

View File

@ -79,10 +79,11 @@ ${seedHeads}`
${seedTails}`
: '';
const challengeId = ObjectID();
const template =
`---
id: ${ObjectID()}
id: ${challengeId}
title: Part ${stepNum}
challengeType: 0
dashedName: part-${stepNum}
@ -107,6 +108,7 @@ Test 1
let finalStepNum = padWithLeadingZeros(stepNum);
finalStepNum += stepBetween ? 'a' : '';
fs.writeFileSync(`${projectPath}part-${finalStepNum}.md`, template);
return challengeId;
};
const reorderSteps = () => {

1
utils/block-nameify.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export declare function blockNameify(phrase: string): string;

View File

@ -1,31 +1,4 @@
const preFormattedBlockNames = {
'api-projects': 'API Projects',
'basic-css': 'Basic CSS',
'basic-html-and-html5': 'Basic HTML and HTML5',
'css-flexbox': 'CSS Flexbox',
'css-grid': 'CSS Grid',
devops: 'DevOps',
es6: 'ES6',
'information-security-with-helmetjs': 'Information Security with HelmetJS',
jquery: 'jQuery',
'json-apis-and-ajax': 'JSON APIs and Ajax',
'mongodb-and-mongoose': 'MongoDB and Mongoose',
'the-dom': 'The DOM',
'apis-and-microservices': 'APIs and Microservices',
'apis-and-microservices-projects': 'APIs and Microservices Projects',
'scientific-computing-with-python': 'Scientific Computing with Python',
'data-analysis-with-python': 'Data Analysis with Python',
'machine-learning-with-python': 'Machine Learning with Python',
tensorflow: 'TensorFlow',
'basic-javascript-rpg-game': 'Basic JavaScript RPG Game',
'basic-html-cat-photo-app': 'HTML Cat Photo App',
'basic-css-cafe-menu': 'CSS Cafe Menu',
'css-variables-skyline': 'CSS Variables Skyline',
'javascript-spreadsheet': 'JavaScript Spreadsheet',
'intermediate-javascript-calorie-counter':
'Intermediate JavaScript Calorie Counter',
'd3-dashboard': 'D3 Dashboard'
};
const preFormattedBlockNames = require('./preformatted-block-names.json');
const noFormatting = ['and', 'for', 'of', 'the', 'up', 'with'];

View File

@ -0,0 +1,27 @@
{
"api-projects": "API Projects",
"basic-css": "Basic CSS",
"basic-html-and-html5": "Basic HTML and HTML5",
"css-flexbox": "CSS Flexbox",
"css-grid": "CSS Grid",
"devops": "DevOps",
"es6": "ES6",
"information-security-with-helmetjs": "Information Security with HelmetJS",
"jquery": "jQuery",
"json-apis-and-ajax": "JSON APIs and Ajax",
"mongodb-and-mongoose": "MongoDB and Mongoose",
"the-dom": "The DOM",
"apis-and-microservices": "APIs and Microservices",
"apis-and-microservices-projects": "APIs and Microservices Projects",
"scientific-computing-with-python": "Scientific Computing with Python",
"data-analysis-with-python": "Data Analysis with Python",
"machine-learning-with-python": "Machine Learning with Python",
"tensorflow": "TensorFlow",
"basic-javascript-rpg-game": "Basic JavaScript RPG Game",
"basic-html-cat-photo-app": "HTML Cat Photo App",
"basic-css-cafe-menu": "CSS Cafe Menu",
"css-variables-skyline": "CSS Variables Skyline",
"javascript-spreadsheet": "JavaScript Spreadsheet",
"intermediate-javascript-calorie-counter": "Intermediate JavaScript Calorie Counter",
"d3-dashboard": "D3 Dashboard"
}