mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-03-28 23:01:57 -04:00
178 lines
4.9 KiB
TypeScript
178 lines
4.9 KiB
TypeScript
import fs from 'fs/promises';
|
|
import path, { join } from 'path';
|
|
import { input } from '@inquirer/prompts';
|
|
import { format } from 'prettier';
|
|
|
|
import { IntroJson, parseIntroJson } from './helpers/parse-json';
|
|
import { withTrace } from './helpers/utils';
|
|
import { getAllBlocks, validateBlockName } from './utils';
|
|
import {
|
|
getBlockStructure,
|
|
getBlockStructurePath,
|
|
getSuperblockStructure,
|
|
writeBlockStructure,
|
|
writeSuperblockStructure,
|
|
getContentConfig,
|
|
getCurriculumStructure
|
|
} from '@freecodecamp/curriculum/file-handler';
|
|
|
|
interface RenameBlockArgs {
|
|
newBlock: string;
|
|
oldBlock: string;
|
|
newName: string;
|
|
}
|
|
|
|
const introJsonPath = path.resolve(
|
|
__dirname,
|
|
'../../client/i18n/locales/english/intro.json'
|
|
);
|
|
|
|
function getBlockTitleFromIntro(intro: IntroJson, block: string) {
|
|
for (const superBlockInfo of Object.values(intro)) {
|
|
const blockInfo = superBlockInfo.blocks[block];
|
|
if (blockInfo?.title) return blockInfo.title;
|
|
}
|
|
}
|
|
|
|
function renameBlockInSimpleStructure(
|
|
blocks: string[] | undefined,
|
|
oldBlock: string,
|
|
newBlock: string
|
|
) {
|
|
if (!blocks) return false;
|
|
const blockIndex = blocks.findIndex(block => block === oldBlock);
|
|
if (blockIndex === -1) return false;
|
|
blocks[blockIndex] = newBlock;
|
|
return true;
|
|
}
|
|
|
|
function renameBlockInChapterStructure(
|
|
chapters:
|
|
| {
|
|
modules: {
|
|
blocks: string[];
|
|
}[];
|
|
}[]
|
|
| undefined,
|
|
oldBlock: string,
|
|
newBlock: string
|
|
) {
|
|
if (!chapters) return false;
|
|
let updated = false;
|
|
for (const chapter of chapters) {
|
|
for (const module of chapter.modules) {
|
|
const blockIndex = module.blocks.findIndex(block => block === oldBlock);
|
|
if (blockIndex !== -1) {
|
|
module.blocks[blockIndex] = newBlock;
|
|
updated = true;
|
|
}
|
|
}
|
|
}
|
|
return updated;
|
|
}
|
|
|
|
function renameBlockInIntro(
|
|
intro: IntroJson,
|
|
superblock: string,
|
|
oldBlock: string,
|
|
newBlock: string,
|
|
newName: string
|
|
) {
|
|
const superBlockIntro = intro[superblock];
|
|
if (!superBlockIntro) return false;
|
|
|
|
const introBlocks = Object.entries(superBlockIntro.blocks);
|
|
const blockIntroIndex = introBlocks.findIndex(
|
|
([block]) => block === oldBlock
|
|
);
|
|
if (blockIntroIndex === -1) return false;
|
|
|
|
const currentBlockInfo = introBlocks[blockIntroIndex]?.[1];
|
|
if (!currentBlockInfo) return false;
|
|
|
|
introBlocks[blockIntroIndex] = [
|
|
newBlock,
|
|
{ ...currentBlockInfo, title: newName }
|
|
];
|
|
superBlockIntro.blocks = Object.fromEntries(introBlocks);
|
|
|
|
return true;
|
|
}
|
|
|
|
async function renameBlock({ newBlock, newName, oldBlock }: RenameBlockArgs) {
|
|
const blockStructure = getBlockStructure(oldBlock);
|
|
const blockStructurePath = getBlockStructurePath(oldBlock);
|
|
blockStructure.dashedName = newBlock;
|
|
await writeBlockStructure(newBlock, blockStructure);
|
|
await fs.rm(blockStructurePath);
|
|
console.log('New block structure .json written.');
|
|
|
|
const { blockContentDir } = getContentConfig('english');
|
|
const oldBlockContentDir = join(blockContentDir, oldBlock);
|
|
const newBlockContentDir = join(blockContentDir, newBlock);
|
|
await fs.rename(oldBlockContentDir, newBlockContentDir);
|
|
console.log('Block challenges moved to new directory.');
|
|
|
|
const newIntro = await parseIntroJson(introJsonPath);
|
|
let didUpdateIntro = false;
|
|
|
|
const { superblocks } = getCurriculumStructure();
|
|
console.log('Updating superblocks containing renamed block.');
|
|
for (const superblock of superblocks) {
|
|
const superblockStructure = getSuperblockStructure(superblock);
|
|
const didUpdateSuperblock =
|
|
renameBlockInSimpleStructure(
|
|
superblockStructure.blocks,
|
|
oldBlock,
|
|
newBlock
|
|
) ||
|
|
renameBlockInChapterStructure(
|
|
superblockStructure.chapters,
|
|
oldBlock,
|
|
newBlock
|
|
);
|
|
|
|
if (didUpdateSuperblock) {
|
|
await writeSuperblockStructure(superblock, superblockStructure);
|
|
console.log(`Updated superblock .json file written for ${superblock}.`);
|
|
|
|
didUpdateIntro =
|
|
renameBlockInIntro(newIntro, superblock, oldBlock, newBlock, newName) ||
|
|
didUpdateIntro;
|
|
}
|
|
}
|
|
|
|
if (didUpdateIntro) {
|
|
await withTrace(
|
|
fs.writeFile,
|
|
introJsonPath,
|
|
await format(JSON.stringify(newIntro), { parser: 'json' })
|
|
);
|
|
console.log('Updated locale intro.json file written.');
|
|
}
|
|
}
|
|
|
|
void getAllBlocks().then(async existingBlocks => {
|
|
const intro = await parseIntroJson(introJsonPath);
|
|
|
|
const oldBlock = await input({
|
|
message: 'What is the dashed name of block to rename?',
|
|
validate: (block: string) =>
|
|
existingBlocks.includes(block) || 'Block not found in existing blocks.'
|
|
});
|
|
|
|
const newName = await input({
|
|
message: 'What is the new name?',
|
|
default: getBlockTitleFromIntro(intro, oldBlock) ?? oldBlock
|
|
});
|
|
|
|
const newBlock = await input({
|
|
message: 'What is the new dashed name (in kebab-case)?',
|
|
validate: (block: string) => validateBlockName(block, existingBlocks)
|
|
});
|
|
|
|
await renameBlock({ newBlock, newName, oldBlock });
|
|
|
|
console.log('All set. Refresh the page to see the changes.');
|
|
});
|