import { promises as fsp } from 'node:fs'; import path from 'node:path'; import { existsAsync } from './fs-helpers'; import { ResponseContentType, RootAPIHelper } from './root-api'; import { writeFile } from './write-file'; import { CodeDirectoryName, TopLevelDirectoryName } from '../domain/file-names'; export enum CodeTypesFileNames { Root = 'root.d.ts', Moment = 'moment.d.ts', } export enum CodeTypesFileNamesNode24 { Root = 'root-node-24.d.ts', Moment = 'dayjs.d.ts', Zod = 'zod.d.ts', } export enum UnitTestsTypesFileNames { Mocha = 'mocha.d.ts', Chai = 'chai.d.ts', } export enum ProductModuleStack { RootNode24 = 'root-node-24', RootNode20 = 'root-node-20', } export const toProductModuleStack = (value: string | undefined): ProductModuleStack | undefined => { if (value && Object.values(ProductModuleStack).includes(value as ProductModuleStack)) { return value as ProductModuleStack; } return undefined; }; export type TypesFileName = CodeTypesFileNames | UnitTestsTypesFileNames | CodeTypesFileNamesNode24; export interface TypesFile { fileName: TypesFileName; content: string; } export interface CliTypesFiles { code: Array; unitTests: Array; } export const getTypesFiles = async (params: { host: string; stack: ProductModuleStack | undefined; }): Promise => { const { host, stack } = params; const rootApi = new RootAPIHelper({ host }); const codeFilesNames = stack === ProductModuleStack.RootNode24 ? Object.values(CodeTypesFileNamesNode24) : Object.values(CodeTypesFileNames); const [codeTypesFiles, unitTestsTypesFiles] = await Promise.all([ // Code file types Promise.all( codeFilesNames.map(async (fileName) => { return { fileName, content: await rootApi.send({ path: `/cli/static/code/types/${fileName}`, responseContentType: ResponseContentType.Text, }), }; }), ), // Unit tests types Promise.all( Object.values(UnitTestsTypesFileNames).map(async (fileName) => { return { fileName, content: await rootApi.send({ path: `/cli/static/unit-tests/types/${fileName}`, responseContentType: ResponseContentType.Text, }), }; }), ), ]); return { code: codeTypesFiles, unitTests: unitTestsTypesFiles, }; }; const staleTypesFilesForStack = (stack: ProductModuleStack | undefined): string[] => { const filesToRemove = stack === ProductModuleStack.RootNode24 ? Object.values(CodeTypesFileNames) : Object.values(CodeTypesFileNamesNode24); return filesToRemove; }; export const updateTypesFiles = async (params: { directory: string; typesFiles: CliTypesFiles; stack: ProductModuleStack | undefined; }) => { const { directory, typesFiles, stack } = params; const typesFilesPath = path.join(directory, TopLevelDirectoryName.Code, 'types'); const unitTestsTypesFilesPath = path.join( directory, TopLevelDirectoryName.Code, CodeDirectoryName.UnitTests, 'types', ); const updateCodeTypesFiles = async () => { if (!(await existsAsync(typesFilesPath))) { await fsp.mkdir(typesFilesPath, { recursive: true }); } // Remove type files from the other stack to avoid conflicting definitions const staleFiles = staleTypesFilesForStack(stack); await Promise.all( staleFiles.map(async (fileName) => { const filePath = path.join(typesFilesPath, fileName); if (await existsAsync(filePath)) { await fsp.unlink(filePath); } }), ); await Promise.all( typesFiles.code.map(async (typesFile) => { const { fileName, content } = typesFile; await writeFile(path.join(typesFilesPath, fileName), content); }), ); }; const updateUnitTestsTypesFiles = async () => { if (await existsAsync(path.join(directory, TopLevelDirectoryName.Code, CodeDirectoryName.UnitTests))) { if (!(await existsAsync(unitTestsTypesFilesPath))) { await fsp.mkdir(unitTestsTypesFilesPath, { recursive: true }); } await Promise.all( typesFiles.unitTests.map(async (typesFile) => { const { fileName, content } = typesFile; await writeFile(path.join(unitTestsTypesFilesPath, fileName), content); }), ); } }; await Promise.all([updateCodeTypesFiles(), updateUnitTestsTypesFiles()]); };