Files
freeCodeCamp/curriculum/schema/intro-schema.js
2026-03-17 15:43:14 +00:00

70 lines
2.1 KiB
JavaScript

const Joi = require('joi');
const blockIntroSchema = Joi.object()
.keys({
title: Joi.string().trim().min(1).required(),
intro: Joi.array().items(Joi.string().allow('')).required()
})
.unknown(true);
const superBlockIntroSchema = Joi.object()
.keys({
title: Joi.string().trim().min(1).required(),
intro: Joi.array().items(Joi.string().allow('')).required(),
blocks: Joi.object().pattern(Joi.string(), blockIntroSchema).required()
})
.unknown(true);
function createIntroSchema(expectedBlocksBySuperblock) {
return Joi.object()
.unknown(true)
.custom((intros, helpers) => {
for (const [superblock, blocks] of Object.entries(
expectedBlocksBySuperblock
)) {
const superBlockIntro = intros[superblock];
if (!superBlockIntro) {
return helpers.error('any.custom', {
message: `Missing intro.json entry for superblock "${superblock}"`
});
}
const { error: superBlockError } =
superBlockIntroSchema.validate(superBlockIntro);
if (superBlockError) {
return helpers.error('any.custom', {
message: `Invalid intro.json shape for superblock "${superblock}": ${superBlockError.message}`
});
}
for (const block of blocks) {
const blockIntro = superBlockIntro.blocks?.[block];
if (!blockIntro) {
return helpers.error('any.custom', {
message: `Missing intro.json block title entry for "${superblock}/${block}"`
});
}
const { error: blockError } = blockIntroSchema.validate(blockIntro);
if (blockError) {
return helpers.error('any.custom', {
message: `Invalid intro.json block entry for "${superblock}/${block}": ${blockError.message}`
});
}
}
}
return intros;
}, 'intro block coverage validation')
.messages({
'any.custom': '{{#message}}'
});
}
exports.validateIntroSchema = (intros, expectedBlocksBySuperblock) => {
return createIntroSchema(expectedBlocksBySuperblock).validate(intros, {
abortEarly: false
});
};