mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00: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 envData = require('./config/env.json');
|
||||||
const {
|
const {
|
||||||
buildChallenges,
|
buildChallenges,
|
||||||
replaceChallengeNode,
|
replaceChallengeNodes,
|
||||||
localeChallengesRootDir
|
localeChallengesRootDir
|
||||||
} = require('./utils/build-challenges');
|
} = require('./utils/build-challenges');
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ module.exports = {
|
|||||||
options: {
|
options: {
|
||||||
name: 'challenges',
|
name: 'challenges',
|
||||||
source: buildChallenges,
|
source: buildChallenges,
|
||||||
onSourceChange: replaceChallengeNode(curriculumLocale),
|
onSourceChange: replaceChallengeNodes(curriculumLocale),
|
||||||
curriculumPath: localeChallengesRootDir
|
curriculumPath: localeChallengesRootDir
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ const {
|
|||||||
getBlockCreator
|
getBlockCreator
|
||||||
} = require('../../curriculum/build-curriculum');
|
} = require('../../curriculum/build-curriculum');
|
||||||
const { getBlockStructure } = require('../../curriculum/file-handler');
|
const { getBlockStructure } = require('../../curriculum/file-handler');
|
||||||
|
const { getSuperblocks } = require('../../curriculum/build-curriculum');
|
||||||
|
|
||||||
const { curriculumLocale } = envData;
|
const { curriculumLocale } = envData;
|
||||||
|
|
||||||
@@ -17,21 +18,27 @@ exports.localeChallengesRootDir = getContentDir(curriculumLocale);
|
|||||||
|
|
||||||
const blockCreator = getBlockCreator(curriculumLocale);
|
const blockCreator = getBlockCreator(curriculumLocale);
|
||||||
|
|
||||||
exports.replaceChallengeNode = () => {
|
exports.replaceChallengeNodes = () => {
|
||||||
return async function replaceChallengeNode(filePath) {
|
return async function replaceChallengeNodes(filePath) {
|
||||||
const parentDir = path.dirname(filePath);
|
const parentDir = path.dirname(filePath);
|
||||||
const block = path.basename(parentDir);
|
const block = path.basename(parentDir);
|
||||||
const filename = path.basename(filePath);
|
const filename = path.basename(filePath);
|
||||||
|
|
||||||
console.log(`Replacing challenge node for ${filePath}`);
|
console.log(`Replacing challenge node for ${filePath}`);
|
||||||
const meta = getBlockStructure(block);
|
const meta = getBlockStructure(block);
|
||||||
|
const superblocks = getSuperblocks(block);
|
||||||
|
|
||||||
return await blockCreator.createChallenge({
|
const challenge = await blockCreator.createChallenge({
|
||||||
filename,
|
filename,
|
||||||
block,
|
block,
|
||||||
meta,
|
meta,
|
||||||
isAudited: true
|
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) {
|
async function buildCurriculum(lang, filters) {
|
||||||
const contentDir = getContentDir(lang);
|
const contentDir = getContentDir(lang);
|
||||||
const builder = new SuperblockCreator({
|
const builder = new SuperblockCreator({
|
||||||
@@ -289,5 +307,6 @@ module.exports = {
|
|||||||
getBlockStructure,
|
getBlockStructure,
|
||||||
getSuperblockStructure,
|
getSuperblockStructure,
|
||||||
createCommentMap,
|
createCommentMap,
|
||||||
superBlockToFilename
|
superBlockToFilename,
|
||||||
|
getSuperblocks
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
|
jest.mock('./file-handler');
|
||||||
|
|
||||||
const path = require('node:path');
|
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', () => {
|
describe('createCommentMap', () => {
|
||||||
const dictionaryDir = path.resolve(__dirname, '__fixtures__', 'dictionaries');
|
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 =>
|
watcher.on('change', filePath =>
|
||||||
/\.md?$/.test(filePath)
|
/\.md?$/.test(filePath)
|
||||||
? onSourceChange(filePath)
|
? onSourceChange(filePath)
|
||||||
.then(challenge => {
|
.then(challenges => {
|
||||||
reporter.info(
|
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 =>
|
.catch(e =>
|
||||||
reporter.error(`fcc-replace-challenge
|
reporter.error(`fcc-replace-challenge
|
||||||
@@ -74,13 +76,15 @@ File changed at ${filePath}, replacing challengeNode id ${challenge.id}
|
|||||||
const { path: siblingPath } = entry;
|
const { path: siblingPath } = entry;
|
||||||
const relativePath = path.join(blockPath, siblingPath);
|
const relativePath = path.join(blockPath, siblingPath);
|
||||||
onSourceChange(relativePath)
|
onSourceChange(relativePath)
|
||||||
.then(challenge => {
|
.then(challenges => {
|
||||||
reporter.info(
|
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 =>
|
.catch(e =>
|
||||||
reporter.error(`fcc-replace-challenge
|
reporter.error(`fcc-replace-challenge
|
||||||
|
|||||||
Reference in New Issue
Block a user