diff --git a/client/i18n/locales/english/intro.json b/client/i18n/locales/english/intro.json index adf20f9b19..402b304486 100644 --- a/client/i18n/locales/english/intro.json +++ b/client/i18n/locales/english/intro.json @@ -66,7 +66,7 @@ } } }, - "responsive-web-design-22": { + "2022/responsive-web-design": { "title": "Responsive Web Design", "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.", diff --git a/client/src/pages/learn/responsive-web-design-22/index.md b/client/src/pages/learn/2022/responsive-web-design/index.md similarity index 97% rename from client/src/pages/learn/responsive-web-design-22/index.md rename to client/src/pages/learn/2022/responsive-web-design/index.md index c317eb6879..fb2f731c14 100644 --- a/client/src/pages/learn/responsive-web-design-22/index.md +++ b/client/src/pages/learn/2022/responsive-web-design/index.md @@ -1,6 +1,6 @@ --- title: Responsive Web Design -superBlock: responsive-web-design-22 +superBlock: 2022/responsive-web-design certification: responsive-web-design --- diff --git a/client/src/resources/cert-and-project-map.ts b/client/src/resources/cert-and-project-map.ts index c654e6bdbf..122a49e89b 100644 --- a/client/src/resources/cert-and-project-map.ts +++ b/client/src/resources/cert-and-project-map.ts @@ -5,7 +5,7 @@ const { showNewCurriculum } = envData; const responsiveWebBase = '/learn/responsive-web-design/responsive-web-design-projects'; -const responsiveWeb22Base = '/learn/responsive-web-design-22'; +const responsiveWeb22Base = '/learn/2022/responsive-web-design'; const jsAlgoBase = '/learn/javascript-algorithms-and-data-structures/' + 'javascript-algorithms-and-data-structures-projects'; diff --git a/client/utils/build-challenges.js b/client/utils/build-challenges.js index 94b496154c..06d8bb882d 100644 --- a/client/utils/build-challenges.js +++ b/client/utils/build-challenges.js @@ -6,7 +6,6 @@ const envData = require('../../config/env.json'); const { getChallengesForLang, createChallenge, - createCertification, challengesDir, getChallengesDirForLang } = require('../../curriculum/getChallenges'); @@ -26,11 +25,14 @@ exports.replaceChallengeNode = () => { `../../curriculum/challenges/_meta/${blockName}/meta.json` ); delete require.cache[require.resolve(metaPath)]; - const isCert = path.extname(filePath) === '.yml'; const meta = require(metaPath); - return isCert - ? await createCertification(challengesDir, filePath, curriculumLocale) - : await createChallenge(challengesDir, filePath, curriculumLocale, meta); + // TODO: reimplement hot-reloading of certifications + return await createChallenge( + challengesDir, + filePath, + curriculumLocale, + meta + ); }; }; diff --git a/config/certification-settings.ts b/config/certification-settings.ts index 4b8cb6d32a..4e1a054726 100644 --- a/config/certification-settings.ts +++ b/config/certification-settings.ts @@ -117,7 +117,7 @@ export const superBlockCertTypeMap = { // post-modern // TODO: use enum - 'responsive-web-design-22': certTypes.respWebDesign + '2022/responsive-web-design': certTypes.respWebDesign }; export const certTypeIdMap = { diff --git a/curriculum/challenges/_meta/build-a-personal-portfolio-webpage-project/meta.json b/curriculum/challenges/_meta/build-a-personal-portfolio-webpage-project/meta.json index e918d82787..be9e3ff533 100644 --- a/curriculum/challenges/_meta/build-a-personal-portfolio-webpage-project/meta.json +++ b/curriculum/challenges/_meta/build-a-personal-portfolio-webpage-project/meta.json @@ -5,7 +5,7 @@ "time": "30 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "bd7158d8c242eddfaeb5bd13", diff --git a/curriculum/challenges/_meta/build-a-product-landing-page-project/meta.json b/curriculum/challenges/_meta/build-a-product-landing-page-project/meta.json index 8c4914320c..66d078be63 100644 --- a/curriculum/challenges/_meta/build-a-product-landing-page-project/meta.json +++ b/curriculum/challenges/_meta/build-a-product-landing-page-project/meta.json @@ -5,7 +5,7 @@ "time": "30 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "587d78af367417b2b2512b04", diff --git a/curriculum/challenges/_meta/build-a-survey-form-project/meta.json b/curriculum/challenges/_meta/build-a-survey-form-project/meta.json index 4ec29f7fc9..11351a3a21 100644 --- a/curriculum/challenges/_meta/build-a-survey-form-project/meta.json +++ b/curriculum/challenges/_meta/build-a-survey-form-project/meta.json @@ -5,7 +5,7 @@ "time": "30 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "587d78af367417b2b2512b03", diff --git a/curriculum/challenges/_meta/build-a-technical-documentation-page-project/meta.json b/curriculum/challenges/_meta/build-a-technical-documentation-page-project/meta.json index 87fd6b3427..feb89e9274 100644 --- a/curriculum/challenges/_meta/build-a-technical-documentation-page-project/meta.json +++ b/curriculum/challenges/_meta/build-a-technical-documentation-page-project/meta.json @@ -5,7 +5,7 @@ "time": "30 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "587d78b0367417b2b2512b05", diff --git a/curriculum/challenges/_meta/build-a-tribute-page-project/meta.json b/curriculum/challenges/_meta/build-a-tribute-page-project/meta.json index 0cd6595ccc..ff0c930a0e 100644 --- a/curriculum/challenges/_meta/build-a-tribute-page-project/meta.json +++ b/curriculum/challenges/_meta/build-a-tribute-page-project/meta.json @@ -5,7 +5,7 @@ "time": "30 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "bd7158d8c442eddfaeb5bd18", diff --git a/curriculum/challenges/_meta/learn-accessibility-by-building-a-quiz/meta.json b/curriculum/challenges/_meta/learn-accessibility-by-building-a-quiz/meta.json index 215661fd51..c6a5935737 100644 --- a/curriculum/challenges/_meta/learn-accessibility-by-building-a-quiz/meta.json +++ b/curriculum/challenges/_meta/learn-accessibility-by-building-a-quiz/meta.json @@ -8,7 +8,7 @@ "time": "5 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "614ccc21ea91ef1736b9b578", diff --git a/curriculum/challenges/_meta/learn-basic-css-by-building-a-cafe-menu/meta.json b/curriculum/challenges/_meta/learn-basic-css-by-building-a-cafe-menu/meta.json index 508484ff52..d20a790147 100644 --- a/curriculum/challenges/_meta/learn-basic-css-by-building-a-cafe-menu/meta.json +++ b/curriculum/challenges/_meta/learn-basic-css-by-building-a-cafe-menu/meta.json @@ -8,7 +8,7 @@ "time": "5 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "isBeta": true, "challengeOrder": [ [ diff --git a/curriculum/challenges/_meta/learn-css-animation-by-building-a-ferris-wheel/meta.json b/curriculum/challenges/_meta/learn-css-animation-by-building-a-ferris-wheel/meta.json index 152ffc00df..8992608ea3 100644 --- a/curriculum/challenges/_meta/learn-css-animation-by-building-a-ferris-wheel/meta.json +++ b/curriculum/challenges/_meta/learn-css-animation-by-building-a-ferris-wheel/meta.json @@ -8,7 +8,7 @@ "time": "5 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "6140c7e645d8e905819f1dd4", diff --git a/curriculum/challenges/_meta/learn-css-flexbox-by-building-a-photo-gallery/meta.json b/curriculum/challenges/_meta/learn-css-flexbox-by-building-a-photo-gallery/meta.json index f9740afcb8..10c17a87f4 100644 --- a/curriculum/challenges/_meta/learn-css-flexbox-by-building-a-photo-gallery/meta.json +++ b/curriculum/challenges/_meta/learn-css-flexbox-by-building-a-photo-gallery/meta.json @@ -8,7 +8,7 @@ "time": "5 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "61537485c4f2a624f18d7794", diff --git a/curriculum/challenges/_meta/learn-css-grid-by-building-a-magazine/meta.json b/curriculum/challenges/_meta/learn-css-grid-by-building-a-magazine/meta.json index 4ac40e9fcd..cd17841303 100644 --- a/curriculum/challenges/_meta/learn-css-grid-by-building-a-magazine/meta.json +++ b/curriculum/challenges/_meta/learn-css-grid-by-building-a-magazine/meta.json @@ -8,7 +8,7 @@ "time": "5 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "61437d575fb98f57fa8f7f36", diff --git a/curriculum/challenges/_meta/learn-css-transforms-by-building-a-penguin/meta.json b/curriculum/challenges/_meta/learn-css-transforms-by-building-a-penguin/meta.json index 0408f93721..a46fba041e 100644 --- a/curriculum/challenges/_meta/learn-css-transforms-by-building-a-penguin/meta.json +++ b/curriculum/challenges/_meta/learn-css-transforms-by-building-a-penguin/meta.json @@ -8,7 +8,7 @@ "time": "5 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "619665c9abd72906f3ad30f9", diff --git a/curriculum/challenges/_meta/learn-css-variables-by-building-a-city-skyline/meta.json b/curriculum/challenges/_meta/learn-css-variables-by-building-a-city-skyline/meta.json index 745a6b264d..51400e1eeb 100644 --- a/curriculum/challenges/_meta/learn-css-variables-by-building-a-city-skyline/meta.json +++ b/curriculum/challenges/_meta/learn-css-variables-by-building-a-city-skyline/meta.json @@ -8,7 +8,7 @@ "time": "5 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "5d822fd413a79914d39e98c9", diff --git a/curriculum/challenges/_meta/learn-html-by-building-a-cat-photo-app/meta.json b/curriculum/challenges/_meta/learn-html-by-building-a-cat-photo-app/meta.json index 666c848edd..73932dfe0b 100644 --- a/curriculum/challenges/_meta/learn-html-by-building-a-cat-photo-app/meta.json +++ b/curriculum/challenges/_meta/learn-html-by-building-a-cat-photo-app/meta.json @@ -8,7 +8,7 @@ "time": "5 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "5dc174fcf86c76b9248c6eb2", diff --git a/curriculum/challenges/_meta/learn-html-forms-by-building-a-registration-form/meta.json b/curriculum/challenges/_meta/learn-html-forms-by-building-a-registration-form/meta.json index 7cee8710a1..c36ad2cf6b 100644 --- a/curriculum/challenges/_meta/learn-html-forms-by-building-a-registration-form/meta.json +++ b/curriculum/challenges/_meta/learn-html-forms-by-building-a-registration-form/meta.json @@ -8,7 +8,7 @@ "time": "5 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "60eebd07ea685b0e777b5583", diff --git a/curriculum/challenges/_meta/learn-intermediate-css-by-building-a-picasso-painting/meta.json b/curriculum/challenges/_meta/learn-intermediate-css-by-building-a-picasso-painting/meta.json index e3fd9540bf..14555f6d11 100644 --- a/curriculum/challenges/_meta/learn-intermediate-css-by-building-a-picasso-painting/meta.json +++ b/curriculum/challenges/_meta/learn-intermediate-css-by-building-a-picasso-painting/meta.json @@ -8,7 +8,7 @@ "time": "5 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "60b69a66b6ddb80858c51578", diff --git a/curriculum/challenges/_meta/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/meta.json b/curriculum/challenges/_meta/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/meta.json index 17afe8cd25..a1e2493018 100644 --- a/curriculum/challenges/_meta/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/meta.json +++ b/curriculum/challenges/_meta/learn-more-about-css-pseudo-selectors-by-building-a-balance-sheet/meta.json @@ -8,7 +8,7 @@ "time": "5 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "6193d8081ec2531581ea7b98", diff --git a/curriculum/challenges/_meta/learn-responsive-web-design-by-building-a-piano/meta.json b/curriculum/challenges/_meta/learn-responsive-web-design-by-building-a-piano/meta.json index 0c2bcb9f36..f6fc54b77f 100644 --- a/curriculum/challenges/_meta/learn-responsive-web-design-by-building-a-piano/meta.json +++ b/curriculum/challenges/_meta/learn-responsive-web-design-by-building-a-piano/meta.json @@ -8,7 +8,7 @@ "time": "5 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "612e6afc009b450a437940a1", diff --git a/curriculum/challenges/_meta/learn-the-css-box-model-by-building-a-rothko-painting/meta.json b/curriculum/challenges/_meta/learn-the-css-box-model-by-building-a-rothko-painting/meta.json index 6f660b77c6..9a26eb1979 100644 --- a/curriculum/challenges/_meta/learn-the-css-box-model-by-building-a-rothko-painting/meta.json +++ b/curriculum/challenges/_meta/learn-the-css-box-model-by-building-a-rothko-painting/meta.json @@ -8,7 +8,7 @@ "time": "5 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "60a3e3396c7b40068ad6996a", diff --git a/curriculum/challenges/_meta/learn-typography-by-building-a-nutrition-label/meta.json b/curriculum/challenges/_meta/learn-typography-by-building-a-nutrition-label/meta.json index 8f6c92c520..cf0d7d963a 100644 --- a/curriculum/challenges/_meta/learn-typography-by-building-a-nutrition-label/meta.json +++ b/curriculum/challenges/_meta/learn-typography-by-building-a-nutrition-label/meta.json @@ -8,7 +8,7 @@ "time": "5 hours", "template": "", "required": [], - "superBlock": "responsive-web-design", + "superBlock": "2022/responsive-web-design", "challengeOrder": [ [ "615f2abbe7d18d49a1e0e1c8", diff --git a/curriculum/getChallenges.js b/curriculum/getChallenges.js index 3b61d57610..8e31e12ddb 100644 --- a/curriculum/getChallenges.js +++ b/curriculum/getChallenges.js @@ -159,7 +159,7 @@ exports.getChallengesForLang = async function getChallengesForLang(lang) { const curriculum = await walk( root, {}, - { type: 'directories', depth: 1 }, + { type: 'directories', depth: 0 }, buildSuperBlocks ); 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) { - // 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; - } +async function buildBlocks({ basename: blockName }, curriculum, baseDir) { const metaPath = path.resolve( __dirname, `./challenges/_meta/${blockName}/meta.json` ); - const blockMeta = require(metaPath); - const { isUpcomingChange } = blockMeta; - if (typeof isUpcomingChange !== 'boolean') { - throw Error( - `meta file at ${metaPath} is missing 'isUpcomingChange', it must be 'true' or 'false'` - ); - } + let blockMeta; + try { + blockMeta = require(metaPath); + const { isUpcomingChange } = blockMeta; + if (typeof isUpcomingChange !== 'boolean') { + throw Error( + `meta file at ${metaPath} is missing 'isUpcomingChange', it must be 'true' or 'false'` + ); + } - if (!isUpcomingChange || showUpcomingChanges) { - // add the block to the superBlock - const blockInfo = { meta: blockMeta, challenges: [] }; - curriculum[superBlock].blocks[blockName] = blockInfo; + if (!isUpcomingChange || showUpcomingChanges) { + // add the block to the superBlock + const blockInfo = { meta: blockMeta, challenges: [] }; + curriculum[baseDir].blocks[blockName] = blockInfo; + } + } catch (e) { + curriculum['00-certifications'].blocks[blockName] = { challenges: [] }; } } async function buildSuperBlocks({ path, fullPath }, curriculum) { - const { order, name: superBlock } = superBlockInfo(path); - curriculum[superBlock] = { superBlock, order, blocks: {} }; + const baseDir = getBaseDir(path); + 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); } async function buildChallenges({ path: filePath }, curriculum, lang) { // path is relative to getChallengesDirForLang(lang) const block = getBlockNameFromPath(filePath); - const { name: superBlock } = superBlockInfoFromPath(filePath); + const baseDir = getBaseDir(filePath); let challengeBlock; // TODO: this try block and process exit can all go once errors terminate the // tests correctly. try { - challengeBlock = curriculum[superBlock].blocks[block]; + challengeBlock = curriculum[baseDir].blocks[block]; if (!challengeBlock) { // this should only happen when a isUpcomingChange block is skipped return; } } catch (e) { - console.log(`failed to create superBlock ${superBlock}`); + console.log(`failed to create superBlock from ${baseDir}`); // eslint-disable-next-line no-process-exit process.exit(1); } @@ -232,7 +230,7 @@ async function buildChallenges({ path: filePath }, curriculum, lang) { // of the new curriculum when we don't want it. if ( process.env.SHOW_NEW_CURRICULUM !== 'true' && - superBlock === 'responsive-web-design-22' + meta?.superBlock === '2022/responsive-web-design' ) { return; } @@ -254,15 +252,16 @@ async function parseTranslation(transPath, dict, lang, parse = parseMD) { : translatedChal; } +// eslint-disable-next-line no-unused-vars async function createCertification(basePath, filePath, lang) { function getFullPath(pathLang) { return path.resolve(__dirname, basePath, pathLang, filePath); } - const { name: superBlock } = superBlockInfoFromPath(filePath); - const useEnglish = lang === 'english' || !isAuditedCert(lang, superBlock); - return useEnglish - ? parseCert(getFullPath('english')) - : parseCert(getFullPath(lang)); + // TODO: restart using isAudited() once we can determine a) the superBlocks + // (plural) a certification belongs to and b) get that info from the parsed + // certification, rather than the path. ASSUMING that this is used by the + // client. If not, delete this comment and the lang param. + return parseCert(getFullPath('english')); } async function createChallenge(basePath, filePath, lang, maybeMeta) { @@ -279,7 +278,7 @@ async function createChallenge(basePath, filePath, lang, maybeMeta) { ); meta = require(metaPath); } - const { name: superBlock } = superBlockInfoFromPath(filePath); + const { superBlock } = meta; if (!curriculumLangs.includes(lang)) throw Error(`${lang} is not a accepted language. Trying to parse ${filePath}`); @@ -324,7 +323,7 @@ ${getFullPath('english')} field to track which certification this belongs to. */ // TODO: generalize this to all superBlocks challenge.certification = - superBlock === 'responsive-web-design-22' + superBlock === '2022/responsive-web-design' ? 'responsive-web-design' : superBlock; challenge.superBlock = superBlock; @@ -371,22 +370,9 @@ async function hasEnglishSource(basePath, translationPath) { .catch(() => false); } -function superBlockInfoFromPath(filePath) { - const [maybeSuper] = filePath.split(path.sep); - return superBlockInfo(maybeSuper); -} - -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 getBaseDir(filePath) { + const [baseDir] = filePath.split(path.sep); + return baseDir; } function getBlockNameFromPath(filePath) { @@ -397,4 +383,3 @@ function getBlockNameFromPath(filePath) { exports.hasEnglishSource = hasEnglishSource; exports.parseTranslation = parseTranslation; exports.createChallenge = createChallenge; -exports.createCertification = createCertification; diff --git a/curriculum/utils.js b/curriculum/utils.js index b2815aa548..f221f67cbc 100644 --- a/curriculum/utils.js +++ b/curriculum/utils.js @@ -36,7 +36,7 @@ const superBlockToOrder = { }; const superBlockToNewOrder = { - 'responsive-web-design-22': 0, + '2022/responsive-web-design': 0, 'javascript-algorithms-and-data-structures': 1, 'front-end-development-libraries': 2, 'data-visualization': 3, diff --git a/curriculum/utils.test.js b/curriculum/utils.test.js index 4698e6ef9e..a143c7fdc4 100644 --- a/curriculum/utils.test.js +++ b/curriculum/utils.test.js @@ -38,7 +38,7 @@ describe('getSuperOrder', () => { it('returns a different order if passed the option showNewCurriculum: true', () => { expect.assertions(13); expect( - getSuperOrder('responsive-web-design-22', { showNewCurriculum: true }) + getSuperOrder('2022/responsive-web-design', { showNewCurriculum: true }) ).toBe(0); expect( getSuperOrder('javascript-algorithms-and-data-structures', { diff --git a/cypress/integration/learn/challenges/projects.js b/cypress/integration/learn/challenges/projects.js index 08d736c8e6..a5a65d516d 100644 --- a/cypress/integration/learn/challenges/projects.js +++ b/cypress/integration/learn/challenges/projects.js @@ -63,10 +63,12 @@ describe('project submission', () => { { browser: 'electron' }, () => { cy.fixture('../../config/curriculum.json').then(curriculum => { - const { challenges, meta } = - curriculum[SuperBlocks.JsAlgoDataStruct].blocks[ - 'javascript-algorithms-and-data-structures-projects' - ]; + const targetBlock = + '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 projectsInOrder = projectTitles.map(projectTitle => {