UNPKG

@intlayer/chokidar

Version:

Scans and builds Intlayer declaration files into dictionaries based on Intlayer configuration.

1 lines 10.9 kB
{"version":3,"file":"createModuleAugmentation.cjs","names":["getPathHash","writeFileIfChanged"],"sources":["../../../src/createType/createModuleAugmentation.ts"],"sourcesContent":["import { mkdir } from 'node:fs/promises';\nimport { basename, extname, join, relative } from 'node:path';\nimport { kebabCaseToCamelCase, normalizePath } from '@intlayer/config/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport fg from 'fast-glob';\nimport { getPathHash } from '../utils';\nimport { writeFileIfChanged } from '../writeFileIfChanged';\n\nexport const getTypeName = (key: string): string =>\n `${kebabCaseToCamelCase(key)}Content`;\n\n/** Returns lines like: [Locales.FRENCH]: 1; */\nconst formatLocales = (locales: Locale[]) =>\n locales.map((locale) => ` \"${locale}\": 1;`).join('\\n');\n\nconst zodToTsString = (schema: any): string => {\n if (!schema) return 'any';\n\n // Support both real Zod objects (_def) and serialized versions (def or nested)\n const def = schema._def ?? schema.def ?? schema;\n\n // Handle serialized type names (sometimes 'type' instead of 'typeName')\n const typeName = def.typeName ?? def.type;\n\n switch (typeName) {\n case 'ZodString':\n case 'string':\n return 'string';\n case 'ZodNumber':\n case 'number':\n return 'number';\n case 'ZodBoolean':\n case 'boolean':\n return 'boolean';\n case 'ZodNull':\n case 'null':\n return 'null';\n case 'ZodUndefined':\n case 'undefined':\n return 'undefined';\n case 'ZodArray':\n case 'array':\n return `${zodToTsString(def.type ?? def.element)}[]`;\n case 'ZodObject':\n case 'object': {\n const shape = typeof def.shape === 'function' ? def.shape() : def.shape;\n if (!shape) return 'Record<string, any>';\n\n const entries = Object.entries(shape)\n .map(([k, v]) => ` \"${k}\": ${zodToTsString(v)};`)\n .join('\\n');\n return `{\\n${entries}\\n }`;\n }\n case 'ZodOptional':\n case 'optional':\n return `${zodToTsString(def.innerType ?? def.wrapped)} | undefined`;\n case 'ZodNullable':\n case 'nullable':\n return `${zodToTsString(def.innerType ?? def.wrapped)} | null`;\n case 'ZodUnion':\n case 'union': {\n const options = def.options ?? [];\n return options.map(zodToTsString).join(' | ');\n }\n case 'ZodIntersection':\n case 'intersection':\n return `${zodToTsString(def.left)} & ${zodToTsString(def.right)}`;\n case 'ZodEnum':\n case 'enum': {\n const values = def.values ?? [];\n return values.map((v: string) => `\"${v}\"`).join(' | ');\n }\n case 'ZodLiteral':\n case 'literal': {\n const value = def.value;\n return typeof value === 'string' ? `\"${value}\"` : String(value);\n }\n default:\n return 'any';\n }\n};\n\ntype ZodToTsFns = {\n zodToTs: (schema: any, opts?: any) => { node: any };\n printNode: (node: any) => string;\n createAuxiliaryTypeStore: () => any;\n};\n\n/** Generate the content of the module augmentation file */\nconst generateTypeIndexContent = (\n typeFiles: string[],\n configuration: IntlayerConfig,\n zodToTsFns: ZodToTsFns | null\n): string => {\n const { internationalization, system, editor, routing } = configuration;\n const { moduleAugmentationDir } = system;\n const { enabled } = editor;\n const { locales, requiredLocales, strictMode, defaultLocale } =\n internationalization;\n\n let fileContent = 'import \"intlayer\";\\n';\n\n // Build dictionary refs\n const dictionariesRef = typeFiles.map((dictionaryPath) => ({\n relativePath: `./${relative(moduleAugmentationDir, dictionaryPath)}`,\n id: basename(dictionaryPath, extname(dictionaryPath)),\n hash: `_${getPathHash(dictionaryPath)}`,\n }));\n\n // Import all dictionaries\n for (const dictionary of dictionariesRef) {\n fileContent += `import ${dictionary.hash} from '${dictionary.relativePath}';\\n`;\n }\n fileContent += '\\n';\n\n // Dictionary map entries (id: typeof <hash>)\n const formattedDictionaryMap: string = dictionariesRef\n .map((dictionary) => ` \"${dictionary.id}\": typeof ${dictionary.hash};`)\n .join('\\n');\n\n // Ensure required ⊆ declared; if empty, default required = declared\n const declared = locales;\n const requiredSanitized = requiredLocales?.length\n ? requiredLocales.filter((requiredLocales) =>\n declared.includes(requiredLocales)\n )\n : declared;\n\n const formattedDeclaredLocales = formatLocales(declared);\n const formattedRequiredLocales = formatLocales(requiredSanitized);\n\n // Build schema registry\n const schemas = configuration.schemas ?? {};\n const formattedSchemas = Object.entries(schemas)\n .map(([key, schema]) => {\n let typeStr = 'any';\n\n if (schema) {\n try {\n if (zodToTsFns) {\n const { node } = zodToTsFns.zodToTs(schema, {\n auxiliaryTypeStore: zodToTsFns.createAuxiliaryTypeStore(),\n });\n // 133 is the kind for AnyKeyword in TypeScript\n if ((node as any).kind !== 133) {\n typeStr = zodToTsFns.printNode(node);\n } else {\n typeStr = zodToTsString(schema);\n }\n } else {\n typeStr = zodToTsString(schema);\n }\n } catch (_e) {\n // Fallback to custom string generator\n typeStr = zodToTsString(schema);\n }\n }\n return ` \"${key}\": ${typeStr};`;\n })\n .join('\\n');\n\n // Choose strict mode registry key\n const strictKey =\n strictMode === 'strict'\n ? 'strict'\n : strictMode === 'inclusive'\n ? 'inclusive'\n : 'loose';\n\n /**\n * Module augmentation that ONLY adds keys to registries.\n * No types/aliases redefined here—avoids merge conflicts.\n */\n fileContent += `declare module 'intlayer' {\\n`;\n // Dictionaries registry\n fileContent += ` interface __DictionaryRegistry {\\n${formattedDictionaryMap}\\n }\\n\\n`;\n // Locales registries\n fileContent += ` interface __DeclaredLocalesRegistry {\\n${formattedDeclaredLocales}\\n }\\n\\n`;\n fileContent += ` interface __RequiredLocalesRegistry {\\n${formattedRequiredLocales}\\n }\\n\\n`;\n // Schema registry\n fileContent += ` interface __SchemaRegistry {\\n${formattedSchemas}\\n }\\n\\n`;\n // Resolved strict mode (narrow the literal at build time)\n fileContent += ` interface __StrictModeRegistry { mode: '${strictKey}' }\\n\\n`;\n // Editor registry\n fileContent += ` interface __EditorRegistry { enabled : ${enabled} }\\n\\n`;\n // Routing registry (mode + defaultLocale narrowed to literals)\n const routingMode = routing?.mode ?? 'prefix-no-default';\n fileContent += ` interface __RoutingRegistry { mode: '${routingMode}'; defaultLocale: '${defaultLocale}' }\\n`;\n fileContent += `}\\n`;\n\n return fileContent;\n};\n\n/** Generate the index file merging all the types */\nexport const createModuleAugmentation = async (\n configuration: IntlayerConfig\n) => {\n const { moduleAugmentationDir, typesDir } = configuration.system;\n\n await mkdir(moduleAugmentationDir, { recursive: true });\n\n const dictionariesTypesDefinitions: string[] = await fg(\n normalizePath(`${typesDir}/*.ts`),\n { ignore: ['**/*.d.ts'] }\n );\n\n let zodToTsFns: ZodToTsFns | null = null;\n try {\n const mod = await import('zod-to-ts');\n zodToTsFns = {\n zodToTs: mod.zodToTs,\n printNode: mod.printNode,\n createAuxiliaryTypeStore: mod.createAuxiliaryTypeStore,\n };\n } catch {\n // typescript peer dep not installed (plain JS project), use fallback\n }\n\n const tsContent = generateTypeIndexContent(\n dictionariesTypesDefinitions,\n configuration,\n zodToTsFns\n );\n\n const tsFilePath = join(moduleAugmentationDir, 'intlayer.d.ts');\n await writeFileIfChanged(tsFilePath, tsContent);\n};\n"],"mappings":"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"}