fix: rename superblock to use /2022/ (#44535)

* chore: update superblock properties

* refactor: remove isAudited from certs

It was always defaulting to English, anyway.

* refactor: get superblock from metas, not dirs

* fix: rename responsive-web-design-22

This converts the slugs to /2022/responsive-web-design

* refactor: remove unused export

* test: update test with new curriculum config

* refactor: use key not [key]

* refactor: remove directory reference from test
This commit is contained in:
Oliver Eyton-Williams
2021-12-21 18:35:51 +00:00
committed by GitHub
parent 198150217a
commit ff566d441a
28 changed files with 74 additions and 85 deletions

View File

@ -66,7 +66,7 @@
} }
} }
}, },
"responsive-web-design-22": { "2022/responsive-web-design": {
"title": "Responsive Web Design", "title": "Responsive Web Design",
"intro": [ "intro": [
"In this Responsive Web Design Certification, you'll learn the languages that developers use to build webpages: HTML (Hypertext Markup Language) for content, and CSS (Cascading Style Sheets) for design.", "In this Responsive Web Design Certification, you'll learn the languages that developers use to build webpages: HTML (Hypertext Markup Language) for content, and CSS (Cascading Style Sheets) for design.",

View File

@ -1,6 +1,6 @@
--- ---
title: Responsive Web Design title: Responsive Web Design
superBlock: responsive-web-design-22 superBlock: 2022/responsive-web-design
certification: responsive-web-design certification: responsive-web-design
--- ---

View File

@ -5,7 +5,7 @@ const { showNewCurriculum } = envData;
const responsiveWebBase = const responsiveWebBase =
'/learn/responsive-web-design/responsive-web-design-projects'; '/learn/responsive-web-design/responsive-web-design-projects';
const responsiveWeb22Base = '/learn/responsive-web-design-22'; const responsiveWeb22Base = '/learn/2022/responsive-web-design';
const jsAlgoBase = const jsAlgoBase =
'/learn/javascript-algorithms-and-data-structures/' + '/learn/javascript-algorithms-and-data-structures/' +
'javascript-algorithms-and-data-structures-projects'; 'javascript-algorithms-and-data-structures-projects';

View File

@ -6,7 +6,6 @@ const envData = require('../../config/env.json');
const { const {
getChallengesForLang, getChallengesForLang,
createChallenge, createChallenge,
createCertification,
challengesDir, challengesDir,
getChallengesDirForLang getChallengesDirForLang
} = require('../../curriculum/getChallenges'); } = require('../../curriculum/getChallenges');
@ -26,11 +25,14 @@ exports.replaceChallengeNode = () => {
`../../curriculum/challenges/_meta/${blockName}/meta.json` `../../curriculum/challenges/_meta/${blockName}/meta.json`
); );
delete require.cache[require.resolve(metaPath)]; delete require.cache[require.resolve(metaPath)];
const isCert = path.extname(filePath) === '.yml';
const meta = require(metaPath); const meta = require(metaPath);
return isCert // TODO: reimplement hot-reloading of certifications
? await createCertification(challengesDir, filePath, curriculumLocale) return await createChallenge(
: await createChallenge(challengesDir, filePath, curriculumLocale, meta); challengesDir,
filePath,
curriculumLocale,
meta
);
}; };
}; };

View File

@ -117,7 +117,7 @@ export const superBlockCertTypeMap = {
// post-modern // post-modern
// TODO: use enum // TODO: use enum
'responsive-web-design-22': certTypes.respWebDesign '2022/responsive-web-design': certTypes.respWebDesign
}; };
export const certTypeIdMap = { export const certTypeIdMap = {

View File

@ -5,7 +5,7 @@
"time": "30 hours", "time": "30 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"bd7158d8c242eddfaeb5bd13", "bd7158d8c242eddfaeb5bd13",

View File

@ -5,7 +5,7 @@
"time": "30 hours", "time": "30 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"587d78af367417b2b2512b04", "587d78af367417b2b2512b04",

View File

@ -5,7 +5,7 @@
"time": "30 hours", "time": "30 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"587d78af367417b2b2512b03", "587d78af367417b2b2512b03",

View File

@ -5,7 +5,7 @@
"time": "30 hours", "time": "30 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"587d78b0367417b2b2512b05", "587d78b0367417b2b2512b05",

View File

@ -5,7 +5,7 @@
"time": "30 hours", "time": "30 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"bd7158d8c442eddfaeb5bd18", "bd7158d8c442eddfaeb5bd18",

View File

@ -8,7 +8,7 @@
"time": "5 hours", "time": "5 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"614ccc21ea91ef1736b9b578", "614ccc21ea91ef1736b9b578",

View File

@ -8,7 +8,7 @@
"time": "5 hours", "time": "5 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"isBeta": true, "isBeta": true,
"challengeOrder": [ "challengeOrder": [
[ [

View File

@ -8,7 +8,7 @@
"time": "5 hours", "time": "5 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"6140c7e645d8e905819f1dd4", "6140c7e645d8e905819f1dd4",

View File

@ -8,7 +8,7 @@
"time": "5 hours", "time": "5 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"61537485c4f2a624f18d7794", "61537485c4f2a624f18d7794",

View File

@ -8,7 +8,7 @@
"time": "5 hours", "time": "5 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"61437d575fb98f57fa8f7f36", "61437d575fb98f57fa8f7f36",

View File

@ -8,7 +8,7 @@
"time": "5 hours", "time": "5 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"619665c9abd72906f3ad30f9", "619665c9abd72906f3ad30f9",

View File

@ -8,7 +8,7 @@
"time": "5 hours", "time": "5 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"5d822fd413a79914d39e98c9", "5d822fd413a79914d39e98c9",

View File

@ -8,7 +8,7 @@
"time": "5 hours", "time": "5 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"5dc174fcf86c76b9248c6eb2", "5dc174fcf86c76b9248c6eb2",

View File

@ -8,7 +8,7 @@
"time": "5 hours", "time": "5 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"60eebd07ea685b0e777b5583", "60eebd07ea685b0e777b5583",

View File

@ -8,7 +8,7 @@
"time": "5 hours", "time": "5 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"60b69a66b6ddb80858c51578", "60b69a66b6ddb80858c51578",

View File

@ -8,7 +8,7 @@
"time": "5 hours", "time": "5 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"6193d8081ec2531581ea7b98", "6193d8081ec2531581ea7b98",

View File

@ -8,7 +8,7 @@
"time": "5 hours", "time": "5 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"612e6afc009b450a437940a1", "612e6afc009b450a437940a1",

View File

@ -8,7 +8,7 @@
"time": "5 hours", "time": "5 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"60a3e3396c7b40068ad6996a", "60a3e3396c7b40068ad6996a",

View File

@ -8,7 +8,7 @@
"time": "5 hours", "time": "5 hours",
"template": "", "template": "",
"required": [], "required": [],
"superBlock": "responsive-web-design", "superBlock": "2022/responsive-web-design",
"challengeOrder": [ "challengeOrder": [
[ [
"615f2abbe7d18d49a1e0e1c8", "615f2abbe7d18d49a1e0e1c8",

View File

@ -159,7 +159,7 @@ exports.getChallengesForLang = async function getChallengesForLang(lang) {
const curriculum = await walk( const curriculum = await walk(
root, root,
{}, {},
{ type: 'directories', depth: 1 }, { type: 'directories', depth: 0 },
buildSuperBlocks buildSuperBlocks
); );
const cb = (file, curriculum) => buildChallenges(file, curriculum, lang); const cb = (file, curriculum) => buildChallenges(file, curriculum, lang);
@ -172,57 +172,55 @@ exports.getChallengesForLang = async function getChallengesForLang(lang) {
); );
}; };
async function buildBlocks({ basename: blockName }, curriculum, superBlock) { async function buildBlocks({ basename: blockName }, curriculum, baseDir) {
// TODO: this is a hack to avoid fetching the meta for the certifications.
// Instead, the certifications should be moved from the challenges directory
// and handled separately.
if (superBlock === 'certifications') {
curriculum[superBlock].blocks[blockName] = { challenges: [] };
return;
}
const metaPath = path.resolve( const metaPath = path.resolve(
__dirname, __dirname,
`./challenges/_meta/${blockName}/meta.json` `./challenges/_meta/${blockName}/meta.json`
); );
const blockMeta = require(metaPath); let blockMeta;
const { isUpcomingChange } = blockMeta; try {
if (typeof isUpcomingChange !== 'boolean') { blockMeta = require(metaPath);
throw Error( const { isUpcomingChange } = blockMeta;
`meta file at ${metaPath} is missing 'isUpcomingChange', it must be 'true' or 'false'` if (typeof isUpcomingChange !== 'boolean') {
); throw Error(
} `meta file at ${metaPath} is missing 'isUpcomingChange', it must be 'true' or 'false'`
);
}
if (!isUpcomingChange || showUpcomingChanges) { if (!isUpcomingChange || showUpcomingChanges) {
// add the block to the superBlock // add the block to the superBlock
const blockInfo = { meta: blockMeta, challenges: [] }; const blockInfo = { meta: blockMeta, challenges: [] };
curriculum[superBlock].blocks[blockName] = blockInfo; curriculum[baseDir].blocks[blockName] = blockInfo;
}
} catch (e) {
curriculum['00-certifications'].blocks[blockName] = { challenges: [] };
} }
} }
async function buildSuperBlocks({ path, fullPath }, curriculum) { async function buildSuperBlocks({ path, fullPath }, curriculum) {
const { order, name: superBlock } = superBlockInfo(path); const baseDir = getBaseDir(path);
curriculum[superBlock] = { superBlock, order, blocks: {} }; curriculum[baseDir] = { blocks: {} };
const cb = (file, curriculum) => buildBlocks(file, curriculum, superBlock); const cb = (file, curriculum) => buildBlocks(file, curriculum, baseDir);
return walk(fullPath, curriculum, { depth: 1, type: 'directories' }, cb); return walk(fullPath, curriculum, { depth: 1, type: 'directories' }, cb);
} }
async function buildChallenges({ path: filePath }, curriculum, lang) { async function buildChallenges({ path: filePath }, curriculum, lang) {
// path is relative to getChallengesDirForLang(lang) // path is relative to getChallengesDirForLang(lang)
const block = getBlockNameFromPath(filePath); const block = getBlockNameFromPath(filePath);
const { name: superBlock } = superBlockInfoFromPath(filePath); const baseDir = getBaseDir(filePath);
let challengeBlock; let challengeBlock;
// TODO: this try block and process exit can all go once errors terminate the // TODO: this try block and process exit can all go once errors terminate the
// tests correctly. // tests correctly.
try { try {
challengeBlock = curriculum[superBlock].blocks[block]; challengeBlock = curriculum[baseDir].blocks[block];
if (!challengeBlock) { if (!challengeBlock) {
// this should only happen when a isUpcomingChange block is skipped // this should only happen when a isUpcomingChange block is skipped
return; return;
} }
} catch (e) { } catch (e) {
console.log(`failed to create superBlock ${superBlock}`); console.log(`failed to create superBlock from ${baseDir}`);
// eslint-disable-next-line no-process-exit // eslint-disable-next-line no-process-exit
process.exit(1); process.exit(1);
} }
@ -232,7 +230,7 @@ async function buildChallenges({ path: filePath }, curriculum, lang) {
// of the new curriculum when we don't want it. // of the new curriculum when we don't want it.
if ( if (
process.env.SHOW_NEW_CURRICULUM !== 'true' && process.env.SHOW_NEW_CURRICULUM !== 'true' &&
superBlock === 'responsive-web-design-22' meta?.superBlock === '2022/responsive-web-design'
) { ) {
return; return;
} }
@ -254,15 +252,16 @@ async function parseTranslation(transPath, dict, lang, parse = parseMD) {
: translatedChal; : translatedChal;
} }
// eslint-disable-next-line no-unused-vars
async function createCertification(basePath, filePath, lang) { async function createCertification(basePath, filePath, lang) {
function getFullPath(pathLang) { function getFullPath(pathLang) {
return path.resolve(__dirname, basePath, pathLang, filePath); return path.resolve(__dirname, basePath, pathLang, filePath);
} }
const { name: superBlock } = superBlockInfoFromPath(filePath); // TODO: restart using isAudited() once we can determine a) the superBlocks
const useEnglish = lang === 'english' || !isAuditedCert(lang, superBlock); // (plural) a certification belongs to and b) get that info from the parsed
return useEnglish // certification, rather than the path. ASSUMING that this is used by the
? parseCert(getFullPath('english')) // client. If not, delete this comment and the lang param.
: parseCert(getFullPath(lang)); return parseCert(getFullPath('english'));
} }
async function createChallenge(basePath, filePath, lang, maybeMeta) { async function createChallenge(basePath, filePath, lang, maybeMeta) {
@ -279,7 +278,7 @@ async function createChallenge(basePath, filePath, lang, maybeMeta) {
); );
meta = require(metaPath); meta = require(metaPath);
} }
const { name: superBlock } = superBlockInfoFromPath(filePath); const { superBlock } = meta;
if (!curriculumLangs.includes(lang)) if (!curriculumLangs.includes(lang))
throw Error(`${lang} is not a accepted language. throw Error(`${lang} is not a accepted language.
Trying to parse ${filePath}`); Trying to parse ${filePath}`);
@ -324,7 +323,7 @@ ${getFullPath('english')}
field to track which certification this belongs to. */ field to track which certification this belongs to. */
// TODO: generalize this to all superBlocks // TODO: generalize this to all superBlocks
challenge.certification = challenge.certification =
superBlock === 'responsive-web-design-22' superBlock === '2022/responsive-web-design'
? 'responsive-web-design' ? 'responsive-web-design'
: superBlock; : superBlock;
challenge.superBlock = superBlock; challenge.superBlock = superBlock;
@ -371,22 +370,9 @@ async function hasEnglishSource(basePath, translationPath) {
.catch(() => false); .catch(() => false);
} }
function superBlockInfoFromPath(filePath) { function getBaseDir(filePath) {
const [maybeSuper] = filePath.split(path.sep); const [baseDir] = filePath.split(path.sep);
return superBlockInfo(maybeSuper); return baseDir;
}
function superBlockInfo(fileName) {
const [maybeOrder, ...superBlock] = fileName.split('-');
let order = parseInt(maybeOrder, 10);
if (isNaN(order)) {
return { order: 0, name: fileName };
} else {
return {
order: order,
name: superBlock.join('-')
};
}
} }
function getBlockNameFromPath(filePath) { function getBlockNameFromPath(filePath) {
@ -397,4 +383,3 @@ function getBlockNameFromPath(filePath) {
exports.hasEnglishSource = hasEnglishSource; exports.hasEnglishSource = hasEnglishSource;
exports.parseTranslation = parseTranslation; exports.parseTranslation = parseTranslation;
exports.createChallenge = createChallenge; exports.createChallenge = createChallenge;
exports.createCertification = createCertification;

View File

@ -36,7 +36,7 @@ const superBlockToOrder = {
}; };
const superBlockToNewOrder = { const superBlockToNewOrder = {
'responsive-web-design-22': 0, '2022/responsive-web-design': 0,
'javascript-algorithms-and-data-structures': 1, 'javascript-algorithms-and-data-structures': 1,
'front-end-development-libraries': 2, 'front-end-development-libraries': 2,
'data-visualization': 3, 'data-visualization': 3,

View File

@ -38,7 +38,7 @@ describe('getSuperOrder', () => {
it('returns a different order if passed the option showNewCurriculum: true', () => { it('returns a different order if passed the option showNewCurriculum: true', () => {
expect.assertions(13); expect.assertions(13);
expect( expect(
getSuperOrder('responsive-web-design-22', { showNewCurriculum: true }) getSuperOrder('2022/responsive-web-design', { showNewCurriculum: true })
).toBe(0); ).toBe(0);
expect( expect(
getSuperOrder('javascript-algorithms-and-data-structures', { getSuperOrder('javascript-algorithms-and-data-structures', {

View File

@ -63,10 +63,12 @@ describe('project submission', () => {
{ browser: 'electron' }, { browser: 'electron' },
() => { () => {
cy.fixture('../../config/curriculum.json').then(curriculum => { cy.fixture('../../config/curriculum.json').then(curriculum => {
const { challenges, meta } = const targetBlock =
curriculum[SuperBlocks.JsAlgoDataStruct].blocks[ 'javascript-algorithms-and-data-structures-projects';
'javascript-algorithms-and-data-structures-projects' const javaScriptSuperBlock = Object.values(curriculum).filter(
]; ({ blocks }) => blocks[targetBlock]
)[0];
const { challenges, meta } = javaScriptSuperBlock.blocks[targetBlock];
const projectTitles = meta.challengeOrder.map(([, title]) => title); const projectTitles = meta.challengeOrder.map(([, title]) => title);
const projectsInOrder = projectTitles.map(projectTitle => { const projectsInOrder = projectTitles.map(projectTitle => {