feat: add block description to mobile curriculum (#45370)

* feat: add block description to mobile curriculum

* feat: add superblock names
This commit is contained in:
Sem Bauke
2022-03-22 20:11:44 +01:00
committed by GitHub
parent caaa416be0
commit 567e99231f
4 changed files with 125 additions and 11 deletions

View File

@ -177,10 +177,15 @@ async function buildBlocks({ basename: blockName }, curriculum, superBlock) {
__dirname, __dirname,
`./challenges/_meta/${blockName}/meta.json` `./challenges/_meta/${blockName}/meta.json`
); );
let blockMeta;
try { if (fs.existsSync(metaPath)) {
blockMeta = require(metaPath); // try to read the file, if the meta path does not exist it should be a certification.
// As they do not have meta files.
const blockMeta = JSON.parse(fs.readFileSync(metaPath));
const { isUpcomingChange } = blockMeta; const { isUpcomingChange } = blockMeta;
if (typeof isUpcomingChange !== 'boolean') { if (typeof isUpcomingChange !== 'boolean') {
throw Error( throw Error(
`meta file at ${metaPath} is missing 'isUpcomingChange', it must be 'true' or 'false'` `meta file at ${metaPath} is missing 'isUpcomingChange', it must be 'true' or 'false'`
@ -192,10 +197,7 @@ async function buildBlocks({ basename: blockName }, curriculum, superBlock) {
const blockInfo = { meta: blockMeta, challenges: [] }; const blockInfo = { meta: blockMeta, challenges: [] };
curriculum[superBlock].blocks[blockName] = blockInfo; curriculum[superBlock].blocks[blockName] = blockInfo;
} }
} catch (e) { } else {
if (e.code !== 'MODULE_NOT_FOUND') {
throw e;
}
curriculum['certifications'].blocks[blockName] = { challenges: [] }; curriculum['certifications'].blocks[blockName] = { challenges: [] };
} }
} }

View File

@ -3,6 +3,10 @@ const path = require('path');
exports.buildMobileCurriculum = function buildMobileCurriculum(json) { exports.buildMobileCurriculum = function buildMobileCurriculum(json) {
const mobileStaticPath = path.resolve(__dirname, '../../../client/static'); const mobileStaticPath = path.resolve(__dirname, '../../../client/static');
const blockIntroPath = path.resolve(
__dirname,
'../../../client/i18n/locales/english/intro.json'
);
fs.mkdirSync(`${mobileStaticPath}/mobile`, { recursive: true }); fs.mkdirSync(`${mobileStaticPath}/mobile`, { recursive: true });
writeAndParseCurriculumJson(json); writeAndParseCurriculumJson(json);
@ -12,7 +16,14 @@ exports.buildMobileCurriculum = function buildMobileCurriculum(json) {
key => key !== 'certifications' key => key !== 'certifications'
); );
writeToFile('availableSuperblocks', { superblocks: superBlockKeys }); writeToFile('availableSuperblocks', {
// removing "/" as it will create an extra sub-path when accessed via an endpoint
superblocks: [
superBlockKeys.map(key => key.replace(/\//, '-')),
getSuperBlockNames(superBlockKeys)
]
});
for (let i = 0; i < superBlockKeys.length; i++) { for (let i = 0; i < superBlockKeys.length; i++) {
const superBlock = {}; const superBlock = {};
@ -25,16 +36,32 @@ exports.buildMobileCurriculum = function buildMobileCurriculum(json) {
for (let j = 0; j < blockNames.length; j++) { for (let j = 0; j < blockNames.length; j++) {
superBlock[superBlockKeys[i]]['blocks'][blockNames[j]] = {}; superBlock[superBlockKeys[i]]['blocks'][blockNames[j]] = {};
superBlock[superBlockKeys[i]]['blocks'][blockNames[j]]['desc'] =
getBlockDescription(superBlockKeys[i], blockNames[j]);
superBlock[superBlockKeys[i]]['blocks'][blockNames[j]]['challenges'] = superBlock[superBlockKeys[i]]['blocks'][blockNames[j]]['challenges'] =
curriculum[superBlockKeys[i]]['blocks'][blockNames[j]]['meta']; curriculum[superBlockKeys[i]]['blocks'][blockNames[j]]['meta'];
} }
writeToFile(superBlockKeys[i], superBlock); writeToFile(superBlockKeys[i].replace(/\//, '-'), superBlock);
} }
} }
function writeToFile(filename, json) { function getBlockDescription(superBlockKey, blockKey) {
const fullPath = `${mobileStaticPath}/mobile/${filename}.json`; const intros = JSON.parse(fs.readFileSync(blockIntroPath));
return intros[superBlockKey]['blocks'][blockKey]['intro'];
}
function getSuperBlockNames(superBlockKeys) {
const superBlocks = JSON.parse(fs.readFileSync(blockIntroPath));
return superBlockKeys.map(key => superBlocks[key].title);
}
function writeToFile(fileName, json) {
const fullPath = `${mobileStaticPath}/mobile/${fileName}.json`;
fs.mkdirSync(path.dirname(fullPath), { recursive: true }); fs.mkdirSync(path.dirname(fullPath), { recursive: true });
fs.writeFileSync(fullPath, JSON.stringify(json, null, 2)); fs.writeFileSync(fullPath, JSON.stringify(json, null, 2));
} }

View File

@ -0,0 +1,53 @@
const path = require('path');
const fs = require('fs');
const { AssertionError } = require('chai');
const { getChallengesForLang } = require('../../../curriculum/getChallenges');
const { buildMobileCurriculum } = require('./build-mobile-curriculum');
const { mobileSchemaValidator } = require('./mobileSchema');
describe('mobile curriculum build', () => {
const mobileStaticPath = path.resolve(__dirname, '../../../client/static');
const blockIntroPath = path.resolve(
__dirname,
'../../../client/i18n/locales/english/intro.json'
);
const validateMobileSuperBlock = mobileSchemaValidator();
let curriculum;
beforeAll(async () => {
curriculum = await getChallengesForLang('english');
await buildMobileCurriculum(curriculum);
}, 20000);
test('the mobile curriculum should have a static folder with multiple files', () => {
expect(fs.existsSync(`${mobileStaticPath}/mobile`)).toBe(true);
expect(fs.readdirSync(`${mobileStaticPath}/mobile`).length).toBeGreaterThan(
0
);
});
test('the mobile curriculum should have access to the intro.json file', () => {
expect(fs.existsSync(blockIntroPath)).toBe(true);
});
test('the files generated should have the correct schema', () => {
const fileArray = fs.readdirSync(`${mobileStaticPath}/mobile`);
fileArray
.filter(fileInArray => fileInArray !== 'availableSuperblocks.json')
.forEach(fileInArray => {
const fileContent = fs.readFileSync(
`${mobileStaticPath}/mobile/${fileInArray}`
);
const result = validateMobileSuperBlock(JSON.parse(fileContent));
if (result.error) {
throw new AssertionError(result.error, `file: ${fileInArray}`);
}
});
});
});

View File

@ -0,0 +1,32 @@
const Joi = require('joi');
const blockSchema = Joi.object({}).keys({
desc: Joi.array().min(1),
challenges: Joi.object({}).keys({
name: Joi.string(),
isUpcomingChange: Joi.bool(),
usesMultifileEditor: Joi.bool().optional(),
hasEditableBoundaries: Joi.bool().optional(),
isBeta: Joi.bool().optional(),
dashedName: Joi.string(),
order: Joi.number(),
time: Joi.string().allow(''),
template: Joi.string().allow(''),
required: Joi.array(),
superBlock: Joi.string(),
challengeOrder: Joi.array().items(Joi.array().min(1))
})
});
const subSchema = Joi.object({}).keys({
blocks: Joi.object({}).pattern(Joi.string(), Joi.object().concat(blockSchema))
});
const schema = Joi.object({}).pattern(
Joi.string(),
Joi.object().concat(subSchema)
);
exports.mobileSchemaValidator = () => {
return superblock => schema.validate(superblock);
};