mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-20 12:03:11 -04:00
fix: rebuild challenge pages if source is updated (#62056)
This commit is contained in:
committed by
GitHub
parent
49c64a14b3
commit
e257c2969e
@@ -2,7 +2,7 @@ const path = require('path');
|
||||
const envData = require('./config/env.json');
|
||||
const {
|
||||
buildChallenges,
|
||||
replaceChallengeNode,
|
||||
replaceChallengeNodes,
|
||||
localeChallengesRootDir
|
||||
} = require('./utils/build-challenges');
|
||||
|
||||
@@ -57,7 +57,7 @@ module.exports = {
|
||||
options: {
|
||||
name: 'challenges',
|
||||
source: buildChallenges,
|
||||
onSourceChange: replaceChallengeNode(curriculumLocale),
|
||||
onSourceChange: replaceChallengeNodes(curriculumLocale),
|
||||
curriculumPath: localeChallengesRootDir
|
||||
}
|
||||
},
|
||||
|
||||
@@ -10,6 +10,7 @@ const {
|
||||
getBlockCreator
|
||||
} = require('../../curriculum/build-curriculum');
|
||||
const { getBlockStructure } = require('../../curriculum/file-handler');
|
||||
const { getSuperblocks } = require('../../curriculum/build-curriculum');
|
||||
|
||||
const { curriculumLocale } = envData;
|
||||
|
||||
@@ -17,21 +18,27 @@ exports.localeChallengesRootDir = getContentDir(curriculumLocale);
|
||||
|
||||
const blockCreator = getBlockCreator(curriculumLocale);
|
||||
|
||||
exports.replaceChallengeNode = () => {
|
||||
return async function replaceChallengeNode(filePath) {
|
||||
exports.replaceChallengeNodes = () => {
|
||||
return async function replaceChallengeNodes(filePath) {
|
||||
const parentDir = path.dirname(filePath);
|
||||
const block = path.basename(parentDir);
|
||||
const filename = path.basename(filePath);
|
||||
|
||||
console.log(`Replacing challenge node for ${filePath}`);
|
||||
const meta = getBlockStructure(block);
|
||||
const superblocks = getSuperblocks(block);
|
||||
|
||||
return await blockCreator.createChallenge({
|
||||
const challenge = await blockCreator.createChallenge({
|
||||
filename,
|
||||
block,
|
||||
meta,
|
||||
isAudited: true
|
||||
});
|
||||
|
||||
return superblocks.map(superBlock => ({
|
||||
...challenge,
|
||||
superBlock
|
||||
}));
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -244,6 +244,24 @@ function addBlockStructure(
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all the superblocks that contain the given block
|
||||
* @param {string} block
|
||||
*/
|
||||
function getSuperblocks(
|
||||
block,
|
||||
_addSuperblockStructure = addSuperblockStructure
|
||||
) {
|
||||
const { superblocks } = getCurriculumStructure();
|
||||
const withStructure = _addSuperblockStructure(superblocks);
|
||||
|
||||
return withStructure
|
||||
.filter(({ blocks }) =>
|
||||
blocks.some(({ dashedName }) => dashedName === block)
|
||||
)
|
||||
.map(({ name }) => name);
|
||||
}
|
||||
|
||||
async function buildCurriculum(lang, filters) {
|
||||
const contentDir = getContentDir(lang);
|
||||
const builder = new SuperblockCreator({
|
||||
@@ -289,5 +307,6 @@ module.exports = {
|
||||
getBlockStructure,
|
||||
getSuperblockStructure,
|
||||
createCommentMap,
|
||||
superBlockToFilename
|
||||
superBlockToFilename,
|
||||
getSuperblocks
|
||||
};
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
jest.mock('./file-handler');
|
||||
|
||||
const path = require('node:path');
|
||||
|
||||
const { createCommentMap, addBlockStructure } = require('./build-curriculum');
|
||||
const {
|
||||
createCommentMap,
|
||||
addBlockStructure,
|
||||
getSuperblocks
|
||||
} = require('./build-curriculum');
|
||||
const { getCurriculumStructure } = require('./file-handler');
|
||||
|
||||
const mockGetCurriculumStructure = getCurriculumStructure;
|
||||
|
||||
describe('createCommentMap', () => {
|
||||
const dictionaryDir = path.resolve(__dirname, '__fixtures__', 'dictionaries');
|
||||
@@ -103,3 +112,58 @@ describe('addBlockStructure', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSuperblocks', () => {
|
||||
it('returns an empty array if no superblocks contain the given block', () => {
|
||||
mockGetCurriculumStructure.mockReturnValue({
|
||||
superblocks: ['superblock-1'] // doesn't matter what this is, but must be defined
|
||||
});
|
||||
const mockAddSuperblockStructure = () => [
|
||||
{
|
||||
blocks: [{ dashedName: 'block-1' }],
|
||||
name: 'superblock-1'
|
||||
}
|
||||
];
|
||||
|
||||
expect(
|
||||
getSuperblocks('nonexistent-block', mockAddSuperblockStructure)
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns an array with one superblock if one superblock contains the given block', () => {
|
||||
mockGetCurriculumStructure.mockReturnValue({
|
||||
superblocks: ['superblock-1'] // doesn't matter what this is, but must be defined
|
||||
});
|
||||
const mockAddSuperblockStructure = () => [
|
||||
{
|
||||
blocks: [{ dashedName: 'block-1' }, { dashedName: 'block-2' }],
|
||||
name: 'superblock-1'
|
||||
}
|
||||
];
|
||||
|
||||
expect(getSuperblocks('block-1', mockAddSuperblockStructure)).toEqual([
|
||||
'superblock-1'
|
||||
]);
|
||||
});
|
||||
|
||||
it('returns an array with multiple superblocks if multiple superblocks contain the given block', () => {
|
||||
mockGetCurriculumStructure.mockReturnValue({
|
||||
superblocks: ['superblock-1'] // doesn't matter what this is, but must be defined
|
||||
});
|
||||
const mockAddSuperblockStructure = () => [
|
||||
{
|
||||
blocks: [{ dashedName: 'block-1' }, { dashedName: 'block-2' }],
|
||||
name: 'superblock-1'
|
||||
},
|
||||
{
|
||||
blocks: [{ dashedName: 'block-3' }, { dashedName: 'block-1' }],
|
||||
name: 'superblock-2'
|
||||
}
|
||||
];
|
||||
|
||||
expect(getSuperblocks('block-1', mockAddSuperblockStructure)).toEqual([
|
||||
'superblock-1',
|
||||
'superblock-2'
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -39,13 +39,15 @@ exports.sourceNodes = function sourceChallengesSourceNodes(
|
||||
watcher.on('change', filePath =>
|
||||
/\.md?$/.test(filePath)
|
||||
? onSourceChange(filePath)
|
||||
.then(challenge => {
|
||||
.then(challenges => {
|
||||
reporter.info(
|
||||
`
|
||||
File changed at ${filePath}, replacing challengeNode id ${challenge.id}
|
||||
File changed at ${filePath}, replacing challengeNodes with ids ${challenges.map(({ id }) => id).join(', ')}
|
||||
`
|
||||
);
|
||||
createVisibleChallenge(challenge, { isReloading: true });
|
||||
challenges.forEach(challenge =>
|
||||
createVisibleChallenge(challenge, { isReloading: true })
|
||||
);
|
||||
})
|
||||
.catch(e =>
|
||||
reporter.error(`fcc-replace-challenge
|
||||
@@ -74,13 +76,15 @@ File changed at ${filePath}, replacing challengeNode id ${challenge.id}
|
||||
const { path: siblingPath } = entry;
|
||||
const relativePath = path.join(blockPath, siblingPath);
|
||||
onSourceChange(relativePath)
|
||||
.then(challenge => {
|
||||
.then(challenges => {
|
||||
reporter.info(
|
||||
`
|
||||
File changed at ${relativePath}, replacing challengeNode id ${challenge.id}
|
||||
File changed at ${relativePath}, replacing challengeNodes with ids ${challenges.map(({ id }) => id).join(', ')}
|
||||
`
|
||||
);
|
||||
createVisibleChallenge(challenge);
|
||||
challenges.forEach(challenge =>
|
||||
createVisibleChallenge(challenge)
|
||||
);
|
||||
})
|
||||
.catch(e =>
|
||||
reporter.error(`fcc-replace-challenge
|
||||
|
||||
Reference in New Issue
Block a user