refactor: top-down curriculum build (#61459)

This commit is contained in:
Oliver Eyton-Williams
2025-08-26 12:37:26 +02:00
committed by GitHub
parent 45c098d506
commit a801d503bc
14264 changed files with 4300 additions and 3151 deletions

View File

@@ -18,9 +18,13 @@ const globalConfigPath = path.resolve(__dirname, '../../../shared/config');
// We are defaulting to English because the ids for the challenges are same
// across all languages.
void getChallengesForLang('english')
.then((result: Record<string, unknown>) => {
buildExtCurriculumDataV1(result as CurriculumV1<CurriculumPropsV1>);
buildExtCurriculumDataV2(result as CurriculumV2<CurriculumPropsV2>);
.then(result => {
buildExtCurriculumDataV1(
result as unknown as CurriculumV1<CurriculumPropsV1>
);
buildExtCurriculumDataV2(
result as unknown as CurriculumV2<CurriculumPropsV2>
);
return result;
})
.then(JSON.stringify)

View File

@@ -1,5 +1,6 @@
import { mkdirSync, writeFileSync, readFileSync } from 'fs';
import { resolve, dirname } from 'path';
import { omit } from 'lodash';
import { submitTypes } from '../../../shared/config/challenge-types';
import { type ChallengeNode } from '../../../client/src/redux/prop-types';
import { SuperBlocks } from '../../../shared/config/curriculum';
@@ -110,11 +111,20 @@ export function buildExtCurriculumDataV1(
Block<Record<string, unknown>>
>{};
superBlock[superBlockKey]['blocks'][blockName]['desc'] =
intros[superBlockKey]['blocks'][blockName]['intro'];
const block = intros[superBlockKey]['blocks'][blockName];
superBlock[superBlockKey]['blocks'][blockName]['challenges'] =
curriculum[superBlockKey]['blocks'][blockName]['meta'];
if (!block) {
throw Error(
`Block ${blockName} not found in intros for ${superBlockKey}`
);
}
superBlock[superBlockKey]['blocks'][blockName]['desc'] = block['intro'];
superBlock[superBlockKey]['blocks'][blockName]['challenges'] = omit(
curriculum[superBlockKey]['blocks'][blockName]['meta'],
['chapter', 'module']
);
const blockChallenges =
curriculum[superBlockKey]['blocks'][blockName]['challenges'];

View File

@@ -1,10 +1,11 @@
import { mkdirSync, writeFileSync, readFileSync } from 'fs';
import { resolve, dirname } from 'path';
import { omit } from 'lodash';
import { submitTypes } from '../../../shared/config/challenge-types';
import { type ChallengeNode } from '../../../client/src/redux/prop-types';
import { SuperBlocks } from '../../../shared/config/curriculum';
import fullStackSuperBlockStructure from '../../../curriculum/superblock-structure/full-stack.json';
import type { Chapter } from '../../../shared/config/chapters';
import { getSuperblockStructure } from '../../../curriculum/build-curriculum';
export type CurriculumIntros =
| BlockBasedCurriculumIntros
@@ -282,7 +283,9 @@ export function buildExtCurriculumDataV2(
}
function buildChapterBasedCurriculum(superBlockKey: SuperBlocks) {
const chapters: Chapter[] = fullStackSuperBlockStructure.chapters;
const { chapters } = getSuperblockStructure('full-stack-developer') as {
chapters: Chapter[];
};
const blocksWithData = curriculum[superBlockKey].blocks;
const superBlockIntros = intros[
@@ -308,12 +311,12 @@ export function buildExtCurriculumDataV2(
: module.blocks
// Upcoming blocks aren't included in blocksWithData
// and thus they have no metadata and need to be filtered out.
.filter(block => blocksWithData[block.dashedName])
.filter(block => blocksWithData[block])
.map(block => {
const blockData = blocksWithData[block.dashedName];
const blockData = blocksWithData[block];
return {
intro: superBlockIntros.blocks[block.dashedName].intro,
meta: blockData.meta
intro: superBlockIntros.blocks[block].intro,
meta: omit(blockData.meta, ['chapter', 'module'])
};
})
}))

View File

@@ -20,11 +20,7 @@ const blockSchema = Joi.object({}).keys({
'Euler',
'Rosetta'
).required(),
order: Joi.number().when('superBlock', {
is: 'full-stack-developer',
then: Joi.forbidden(),
otherwise: Joi.required()
}),
order: Joi.number().required(),
template: Joi.string().allow(''),
required: Joi.array(),
superBlock: Joi.string().required(),

View File

@@ -25,11 +25,7 @@ const blockSchema = Joi.object().keys({
'Euler',
'Rosetta'
).required(),
order: Joi.number().when('superBlock', {
is: chapterBasedSuperBlocks,
then: Joi.forbidden(),
otherwise: Joi.required()
}),
order: Joi.number().required(),
template: Joi.string().allow(''),
required: Joi.array(),
superBlock: Joi.string().required(),