UNPKG

@intlayer/chokidar

Version:

Uses chokidar to scan and build Intlayer declaration files into dictionaries based on Intlayer configuration.

120 lines (118 loc) 5.57 kB
import { writeFileIfChanged } from "../writeFileIfChanged.mjs"; import { getPathHash } from "../utils/getPathHash.mjs"; import { mkdir } from "node:fs/promises"; import { basename, extname, join, relative } from "node:path"; import fg from "fast-glob"; import { kebabCaseToCamelCase, normalizePath } from "@intlayer/config/utils"; //#region src/createType/createModuleAugmentation.ts const getTypeName = (key) => `${kebabCaseToCamelCase(key)}Content`; /** Returns lines like: [Locales.FRENCH]: 1; */ const formatLocales = (locales) => locales.map((locale) => ` "${locale}": 1;`).join("\n"); const zodToTsString = (schema) => { if (!schema) return "any"; const def = schema._def ?? schema.def ?? schema; switch (def.typeName ?? def.type) { case "ZodString": case "string": return "string"; case "ZodNumber": case "number": return "number"; case "ZodBoolean": case "boolean": return "boolean"; case "ZodNull": case "null": return "null"; case "ZodUndefined": case "undefined": return "undefined"; case "ZodArray": case "array": return `${zodToTsString(def.type ?? def.element)}[]`; case "ZodObject": case "object": { const shape = typeof def.shape === "function" ? def.shape() : def.shape; if (!shape) return "Record<string, any>"; return `{\n${Object.entries(shape).map(([k, v]) => ` "${k}": ${zodToTsString(v)};`).join("\n")}\n }`; } case "ZodOptional": case "optional": return `${zodToTsString(def.innerType ?? def.wrapped)} | undefined`; case "ZodNullable": case "nullable": return `${zodToTsString(def.innerType ?? def.wrapped)} | null`; case "ZodUnion": case "union": return (def.options ?? []).map(zodToTsString).join(" | "); case "ZodIntersection": case "intersection": return `${zodToTsString(def.left)} & ${zodToTsString(def.right)}`; case "ZodEnum": case "enum": return (def.values ?? []).map((v) => `"${v}"`).join(" | "); case "ZodLiteral": case "literal": { const value = def.value; return typeof value === "string" ? `"${value}"` : String(value); } default: return "any"; } }; /** Generate the content of the module augmentation file */ const generateTypeIndexContent = (typeFiles, configuration, zodToTsFns) => { const { internationalization, system, editor } = configuration; const { moduleAugmentationDir } = system; const { enabled } = editor; const { locales, requiredLocales, strictMode } = internationalization; let fileContent = "import \"intlayer\";\n"; const dictionariesRef = typeFiles.map((dictionaryPath) => ({ relativePath: `./${relative(moduleAugmentationDir, dictionaryPath)}`, id: basename(dictionaryPath, extname(dictionaryPath)), hash: `_${getPathHash(dictionaryPath)}` })); for (const dictionary of dictionariesRef) fileContent += `import ${dictionary.hash} from '${dictionary.relativePath}';\n`; fileContent += "\n"; const formattedDictionaryMap = dictionariesRef.map((dictionary) => ` "${dictionary.id}": typeof ${dictionary.hash};`).join("\n"); const declared = locales; const requiredSanitized = requiredLocales?.length ? requiredLocales.filter((requiredLocales) => declared.includes(requiredLocales)) : declared; const formattedDeclaredLocales = formatLocales(declared); const formattedRequiredLocales = formatLocales(requiredSanitized); const schemas = configuration.schemas ?? {}; const formattedSchemas = Object.entries(schemas).map(([key, schema]) => { let typeStr = "any"; if (schema) try { if (zodToTsFns) { const { node } = zodToTsFns.zodToTs(schema, { auxiliaryTypeStore: zodToTsFns.createAuxiliaryTypeStore() }); if (node.kind !== 133) typeStr = zodToTsFns.printNode(node); else typeStr = zodToTsString(schema); } else typeStr = zodToTsString(schema); } catch (_e) { typeStr = zodToTsString(schema); } return ` "${key}": ${typeStr};`; }).join("\n"); const strictKey = strictMode === "strict" ? "strict" : strictMode === "inclusive" ? "inclusive" : "loose"; /** * Module augmentation that ONLY adds keys to registries. * No types/aliases redefined here—avoids merge conflicts. */ fileContent += `declare module 'intlayer' {\n`; fileContent += ` interface __DictionaryRegistry {\n${formattedDictionaryMap}\n }\n\n`; fileContent += ` interface __DeclaredLocalesRegistry {\n${formattedDeclaredLocales}\n }\n\n`; fileContent += ` interface __RequiredLocalesRegistry {\n${formattedRequiredLocales}\n }\n\n`; fileContent += ` interface __SchemaRegistry {\n${formattedSchemas}\n }\n\n`; fileContent += ` interface __StrictModeRegistry { mode: '${strictKey}' }\n\n`; fileContent += ` interface __EditorRegistry { enabled : ${enabled} } \n`; fileContent += `}\n`; return fileContent; }; /** Generate the index file merging all the types */ const createModuleAugmentation = async (configuration) => { const { moduleAugmentationDir, typesDir } = configuration.system; await mkdir(moduleAugmentationDir, { recursive: true }); const dictionariesTypesDefinitions = await fg(normalizePath(`${typesDir}/*.ts`), { ignore: ["**/*.d.ts"] }); let zodToTsFns = null; try { const mod = await import("zod-to-ts"); zodToTsFns = { zodToTs: mod.zodToTs, printNode: mod.printNode, createAuxiliaryTypeStore: mod.createAuxiliaryTypeStore }; } catch {} const tsContent = generateTypeIndexContent(dictionariesTypesDefinitions, configuration, zodToTsFns); await writeFileIfChanged(join(moduleAugmentationDir, "intlayer.d.ts"), tsContent); }; //#endregion export { createModuleAugmentation, getTypeName }; //# sourceMappingURL=createModuleAugmentation.mjs.map