@intlayer/engine 9.0.0-canary.13 → 9.0.0-canary.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/cjs/createType/createModuleAugmentation.cjs +1 -1
  2. package/dist/cjs/createType/createModuleAugmentation.cjs.map +1 -1
  3. package/dist/cjs/createType/createType.cjs +2 -1
  4. package/dist/cjs/createType/createType.cjs.map +1 -1
  5. package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs +2 -2
  6. package/dist/cjs/loadDictionaries/loadContentDeclaration.cjs.map +1 -1
  7. package/dist/cjs/prepareIntlayer.cjs +11 -7
  8. package/dist/cjs/prepareIntlayer.cjs.map +1 -1
  9. package/dist/cjs/syncPluginKit/createFileAdapter.cjs +119 -0
  10. package/dist/cjs/syncPluginKit/createFileAdapter.cjs.map +1 -0
  11. package/dist/cjs/syncPluginKit/createSyncPlugin.cjs +154 -0
  12. package/dist/cjs/syncPluginKit/createSyncPlugin.cjs.map +1 -0
  13. package/dist/cjs/syncPluginKit/extractKeyAndLocaleFromPath.cjs +37 -0
  14. package/dist/cjs/syncPluginKit/extractKeyAndLocaleFromPath.cjs.map +1 -0
  15. package/dist/cjs/syncPluginKit/filePathPatternHelpers.cjs +20 -0
  16. package/dist/cjs/syncPluginKit/filePathPatternHelpers.cjs.map +1 -0
  17. package/dist/cjs/syncPluginKit/index.cjs +11 -0
  18. package/dist/cjs/syncPluginKit/types.cjs +0 -0
  19. package/dist/cjs/utils/runParallel/index.cjs +2 -2
  20. package/dist/cjs/utils/runParallel/index.cjs.map +1 -1
  21. package/dist/cjs/watcher.cjs +2 -3
  22. package/dist/cjs/watcher.cjs.map +1 -1
  23. package/dist/cjs/writeFileIfChanged.cjs +41 -17
  24. package/dist/cjs/writeFileIfChanged.cjs.map +1 -1
  25. package/dist/esm/createType/createModuleAugmentation.mjs +1 -1
  26. package/dist/esm/createType/createModuleAugmentation.mjs.map +1 -1
  27. package/dist/esm/createType/createType.mjs +3 -2
  28. package/dist/esm/createType/createType.mjs.map +1 -1
  29. package/dist/esm/loadDictionaries/loadContentDeclaration.mjs +2 -2
  30. package/dist/esm/loadDictionaries/loadContentDeclaration.mjs.map +1 -1
  31. package/dist/esm/prepareIntlayer.mjs +11 -7
  32. package/dist/esm/prepareIntlayer.mjs.map +1 -1
  33. package/dist/esm/syncPluginKit/createFileAdapter.mjs +115 -0
  34. package/dist/esm/syncPluginKit/createFileAdapter.mjs.map +1 -0
  35. package/dist/esm/syncPluginKit/createSyncPlugin.mjs +152 -0
  36. package/dist/esm/syncPluginKit/createSyncPlugin.mjs.map +1 -0
  37. package/dist/esm/syncPluginKit/extractKeyAndLocaleFromPath.mjs +35 -0
  38. package/dist/esm/syncPluginKit/extractKeyAndLocaleFromPath.mjs.map +1 -0
  39. package/dist/esm/syncPluginKit/filePathPatternHelpers.mjs +18 -0
  40. package/dist/esm/syncPluginKit/filePathPatternHelpers.mjs.map +1 -0
  41. package/dist/esm/syncPluginKit/index.mjs +6 -0
  42. package/dist/esm/syncPluginKit/types.mjs +0 -0
  43. package/dist/esm/utils/runParallel/index.mjs +2 -2
  44. package/dist/esm/utils/runParallel/index.mjs.map +1 -1
  45. package/dist/esm/watcher.mjs +2 -3
  46. package/dist/esm/watcher.mjs.map +1 -1
  47. package/dist/esm/writeFileIfChanged.mjs +44 -20
  48. package/dist/esm/writeFileIfChanged.mjs.map +1 -1
  49. package/dist/types/createType/createType.d.ts.map +1 -1
  50. package/dist/types/syncPluginKit/createFileAdapter.d.ts +51 -0
  51. package/dist/types/syncPluginKit/createFileAdapter.d.ts.map +1 -0
  52. package/dist/types/syncPluginKit/createSyncPlugin.d.ts +18 -0
  53. package/dist/types/syncPluginKit/createSyncPlugin.d.ts.map +1 -0
  54. package/dist/types/syncPluginKit/extractKeyAndLocaleFromPath.d.ts +20 -0
  55. package/dist/types/syncPluginKit/extractKeyAndLocaleFromPath.d.ts.map +1 -0
  56. package/dist/types/syncPluginKit/filePathPatternHelpers.d.ts +16 -0
  57. package/dist/types/syncPluginKit/filePathPatternHelpers.d.ts.map +1 -0
  58. package/dist/types/syncPluginKit/index.d.ts +6 -0
  59. package/dist/types/syncPluginKit/types.d.ts +149 -0
  60. package/dist/types/syncPluginKit/types.d.ts.map +1 -0
  61. package/dist/types/utils/runParallel/index.d.ts +6 -1
  62. package/dist/types/utils/runParallel/index.d.ts.map +1 -1
  63. package/dist/types/watcher.d.ts.map +1 -1
  64. package/dist/types/writeFileIfChanged.d.ts +30 -6
  65. package/dist/types/writeFileIfChanged.d.ts.map +1 -1
  66. package/package.json +24 -8
@@ -108,7 +108,7 @@ const createModuleAugmentation = async (configuration) => {
108
108
  await (0, node_fs_promises.mkdir)(moduleAugmentationDir, { recursive: true });
109
109
  const dictionariesTypesDefinitions = await (0, fast_glob.default)((0, _intlayer_config_utils.normalizePath)(`${typesDir}/*.ts`), { ignore: ["**/*.d.ts"] });
110
110
  let zodToTsFns = null;
111
- try {
111
+ if (Object.keys(configuration.schemas ?? {}).length > 0) try {
112
112
  const mod = await import("zod-to-ts");
113
113
  zodToTsFns = {
114
114
  zodToTs: mod.zodToTs,
@@ -1 +1 @@
1
- {"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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"}
1
+ {"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\n const hasSchemas = Object.keys(configuration.schemas ?? {}).length > 0;\n\n // zod-to-ts drags in the whole `typescript` package (~300ms import), so\n // only load it when there are schemas to convert.\n if (hasSchemas) {\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\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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"}
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
3
3
  const require_utils_parallelize = require('../utils/parallelize.cjs');
4
+ const require_writeFileIfChanged = require('../writeFileIfChanged.cjs');
4
5
  let node_fs_promises = require("node:fs/promises");
5
6
  let node_path = require("node:path");
6
7
 
@@ -19,7 +20,7 @@ const createTypes = async (dictionaries, configuration) => {
19
20
  if (!dictionary.key) return;
20
21
  const typeDefinition = generateTypeScriptType(dictionary);
21
22
  const outputPath = (0, node_path.resolve)(typesDir, `${dictionary.key}.ts`);
22
- await (0, node_fs_promises.writeFile)(outputPath, typeDefinition);
23
+ await require_writeFileIfChanged.writeFileIfChanged(outputPath, typeDefinition);
23
24
  return outputPath;
24
25
  })).filter(Boolean);
25
26
  };
@@ -1 +1 @@
1
- {"version":3,"file":"createType.cjs","names":["parallelize"],"sources":["../../../src/createType/createType.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type {\n Dictionary,\n QualifiedDictionaryGroup,\n} from '@intlayer/types/dictionary';\nimport { parallelize } from '../utils/parallelize';\n\nexport const generateTypeScriptType = (\n dictionary: Dictionary | QualifiedDictionaryGroup\n) => {\n const jsonString = JSON.stringify(dictionary, null, 2);\n\n return `/* eslint-disable */\\nexport default ${jsonString} as const;\\n`;\n};\n/**\n * This function generates a TypeScript type definition from a JSON object\n */\nexport const createTypes = async (\n dictionaries: (Dictionary | QualifiedDictionaryGroup)[],\n configuration: IntlayerConfig\n): Promise<string[]> => {\n const { system } = configuration;\n const { typesDir } = system;\n\n // Create type folders if they don't exist\n await mkdir(typesDir, { recursive: true });\n\n const results = await parallelize(\n dictionaries,\n async (dictionary): Promise<string | undefined> => {\n if (!dictionary.key) {\n return undefined;\n }\n\n const typeDefinition: string = generateTypeScriptType(dictionary);\n\n const outputPath: string = resolve(typesDir, `${dictionary.key}.ts`);\n\n await writeFile(outputPath, typeDefinition);\n\n return outputPath;\n }\n );\n\n return results.filter(Boolean) as string[];\n};\n"],"mappings":";;;;;;;AASA,MAAa,0BACX,eACG;AAGH,QAAO,wCAFY,KAAK,UAAU,YAAY,MAAM,EAEK,CAAC;;;;;AAK5D,MAAa,cAAc,OACzB,cACA,kBACsB;CACtB,MAAM,EAAE,WAAW;CACnB,MAAM,EAAE,aAAa;AAGrB,mCAAY,UAAU,EAAE,WAAW,MAAM,CAAC;AAmB1C,SAAO,MAjBeA,sCACpB,cACA,OAAO,eAA4C;AACjD,MAAI,CAAC,WAAW,IACd;EAGF,MAAM,iBAAyB,uBAAuB,WAAW;EAEjE,MAAM,oCAA6B,UAAU,GAAG,WAAW,IAAI,KAAK;AAEpE,wCAAgB,YAAY,eAAe;AAE3C,SAAO;GAEV,EAEc,OAAO,QAAQ"}
1
+ {"version":3,"file":"createType.cjs","names":["parallelize","writeFileIfChanged"],"sources":["../../../src/createType/createType.ts"],"sourcesContent":["import { mkdir } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type {\n Dictionary,\n QualifiedDictionaryGroup,\n} from '@intlayer/types/dictionary';\nimport { parallelize } from '../utils/parallelize';\nimport { writeFileIfChanged } from '../writeFileIfChanged';\n\nexport const generateTypeScriptType = (\n dictionary: Dictionary | QualifiedDictionaryGroup\n) => {\n const jsonString = JSON.stringify(dictionary, null, 2);\n\n return `/* eslint-disable */\\nexport default ${jsonString} as const;\\n`;\n};\n/**\n * This function generates a TypeScript type definition from a JSON object\n */\nexport const createTypes = async (\n dictionaries: (Dictionary | QualifiedDictionaryGroup)[],\n configuration: IntlayerConfig\n): Promise<string[]> => {\n const { system } = configuration;\n const { typesDir } = system;\n\n // Create type folders if they don't exist\n await mkdir(typesDir, { recursive: true });\n\n const results = await parallelize(\n dictionaries,\n async (dictionary): Promise<string | undefined> => {\n if (!dictionary.key) {\n return undefined;\n }\n\n const typeDefinition: string = generateTypeScriptType(dictionary);\n\n const outputPath: string = resolve(typesDir, `${dictionary.key}.ts`);\n\n // Skip the write when the type definition is unchanged, so warm\n // rebuilds don't churn mtimes and re-trigger the TS server.\n await writeFileIfChanged(outputPath, typeDefinition);\n\n return outputPath;\n }\n );\n\n return results.filter(Boolean) as string[];\n};\n"],"mappings":";;;;;;;;AAUA,MAAa,0BACX,eACG;AAGH,QAAO,wCAFY,KAAK,UAAU,YAAY,MAAM,EAEK,CAAC;;;;;AAK5D,MAAa,cAAc,OACzB,cACA,kBACsB;CACtB,MAAM,EAAE,WAAW;CACnB,MAAM,EAAE,aAAa;AAGrB,mCAAY,UAAU,EAAE,WAAW,MAAM,CAAC;AAqB1C,SAAO,MAnBeA,sCACpB,cACA,OAAO,eAA4C;AACjD,MAAI,CAAC,WAAW,IACd;EAGF,MAAM,iBAAyB,uBAAuB,WAAW;EAEjE,MAAM,oCAA6B,UAAU,GAAG,WAAW,IAAI,KAAK;AAIpE,QAAMC,8CAAmB,YAAY,eAAe;AAEpD,SAAO;GAEV,EAEc,OAAO,QAAQ"}
@@ -65,8 +65,8 @@ const loadContentDeclaration = async (path, configuration, bundleFilePath, optio
65
65
  banner: { js: [
66
66
  `var __filename = ${JSON.stringify(path)};`,
67
67
  `var __dirname = ${JSON.stringify((0, node_path.dirname)(path))};`,
68
- `globalThis.INTLAYER_FILE_PATH = '${path}';`,
69
- `globalThis.INTLAYER_BASE_DIR = '${configuration.system.baseDir}';`
68
+ `globalThis.INTLAYER_FILE_PATH = ${JSON.stringify(path)};`,
69
+ `globalThis.INTLAYER_BASE_DIR = ${JSON.stringify(configuration.system.baseDir)};`
70
70
  ].join("\n") }
71
71
  },
72
72
  aliases: { intlayer: resolvedBundleFilePath },
@@ -1 +1 @@
1
- {"version":3,"file":"loadContentDeclaration.cjs","names":["getIntlayerBundle","loadMarkdownContentDeclaration","loadYamlContentDeclaration","filterInvalidDictionaries","parallelize","processContentDeclaration"],"sources":["../../../src/loadDictionaries/loadContentDeclaration.ts"],"sourcesContent":["import { readFile, writeFile } from 'node:fs/promises';\nimport { dirname, extname, join, relative } from 'node:path';\nimport { loadExternalFile } from '@intlayer/config/file';\nimport {\n cacheDisk,\n getPackageJsonPath,\n getProjectRequire,\n} from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { processContentDeclaration } from '../buildIntlayerDictionary/processContentDeclaration';\nimport { filterInvalidDictionaries } from '../filterInvalidDictionaries';\nimport { parallelize } from '../utils/parallelize';\nimport { getIntlayerBundle } from './getIntlayerBundle';\nimport type { DictionariesStatus } from './loadDictionaries';\nimport { loadMarkdownContentDeclaration } from './loadMarkdownContentDeclaration';\nimport { loadYamlContentDeclaration } from './loadYamlContentDeclaration';\nimport { logTypeScriptErrors } from './logTypeScriptErrors';\n\nexport const formatLocalDictionaries = (\n dictionariesRecord: Record<string, Dictionary>,\n configuration: IntlayerConfig\n): Dictionary[] =>\n Object.entries(dictionariesRecord).map(([relativePath, dict]) => ({\n ...dict,\n location: dict.location ?? configuration.dictionary?.location ?? 'local',\n localId: `${dict.key}::local::${relativePath}`,\n filePath: relativePath,\n }));\n\nexport const ensureIntlayerBundle = async (\n configuration: IntlayerConfig\n): Promise<string> => {\n const { system } = configuration;\n\n const { set, isValid } = cacheDisk(configuration, ['intlayer-bundle'], {\n ttlMs: 1000 * 60 * 60 * 24 * 5, // 5 days\n });\n\n const filePath = join(system.cacheDir, 'intlayer-bundle.cjs');\n const hasIntlayerBundle = await isValid();\n\n if (!hasIntlayerBundle) {\n const intlayerBundle = await getIntlayerBundle(configuration);\n await writeFile(filePath, intlayerBundle);\n await set('ok');\n }\n\n return filePath;\n};\n\ntype LoadContentDeclarationOptions = {\n logError?: boolean;\n};\n\n// Initialize a module-level cache\nlet cachedExternalDeps: string[] | null = null;\n\n// Helper to fetch and cache the dependencies\nconst getExternalDeps = async (baseDir: string): Promise<string[]> => {\n if (cachedExternalDeps) {\n return cachedExternalDeps; // Return instantly on subsequent calls\n }\n\n try {\n const packageJsonPath = getPackageJsonPath(baseDir);\n\n const packageJSON = await readFile(\n packageJsonPath.packageJsonPath,\n 'utf-8'\n );\n const parsedPackages = JSON.parse(packageJSON);\n const allDependencies = Object.keys({\n ...parsedPackages.dependencies,\n ...parsedPackages.devDependencies,\n });\n\n // Specify the ESM packages to bundle\n const esmPackagesToBundle: string[] = [];\n\n const externalDeps = allDependencies.filter(\n (dep) => !esmPackagesToBundle.includes(dep)\n );\n\n externalDeps.push('esbuild');\n\n // Save to cache\n cachedExternalDeps = externalDeps;\n } catch (error) {\n console.warn(\n 'Could not read package.json for externalizing dependencies, fallback to empty array',\n error\n );\n cachedExternalDeps = ['esbuild'];\n }\n\n return cachedExternalDeps;\n};\n\nexport const loadContentDeclaration = async (\n path: string,\n configuration: IntlayerConfig,\n bundleFilePath?: string,\n options?: LoadContentDeclarationOptions\n): Promise<Dictionary | undefined> => {\n if (extname(path) === '.md' || extname(path) === '.mdx') {\n return loadMarkdownContentDeclaration(path);\n }\n\n if (extname(path) === '.yaml' || extname(path) === '.yml') {\n return loadYamlContentDeclaration(path);\n }\n\n const { build, system } = configuration;\n\n // Call the cached helper\n const externalDeps = await getExternalDeps(system.baseDir);\n\n const resolvedBundleFilePath =\n bundleFilePath ?? (await ensureIntlayerBundle(configuration));\n\n try {\n const dictionary = await loadExternalFile(path, {\n logError: options?.logError,\n projectRequire: build.require ?? getProjectRequire(),\n buildOptions: {\n packages: undefined, // It fixes the import of ESM packages in the content declaration\n external: externalDeps,\n banner: {\n js: [\n `var __filename = ${JSON.stringify(path)};`,\n `var __dirname = ${JSON.stringify(dirname(path))};`,\n // Also set on the VM sandbox's globalThis for VM-internal code.\n // External modules (e.g. @intlayer/core's file()) run in the main\n // Node.js context and are handled by preloadGlobals below.\n `globalThis.INTLAYER_FILE_PATH = '${path}';`,\n `globalThis.INTLAYER_BASE_DIR = '${configuration.system.baseDir}';`,\n ].join('\\n'),\n },\n },\n aliases: {\n intlayer: resolvedBundleFilePath,\n },\n // Temporarily expose these on the main Node.js globalThis so that external\n // modules required inside the VM (e.g. @intlayer/core's file() helper)\n // can resolve relative paths against the correct content declaration path.\n preloadGlobals: {\n INTLAYER_FILE_PATH: path,\n INTLAYER_BASE_DIR: configuration.system.baseDir,\n },\n });\n\n return dictionary;\n } catch (error) {\n console.error(`Error loading content declaration at ${path}:`, error);\n return undefined;\n }\n};\n\nexport const loadContentDeclarations = async (\n contentDeclarationFilePath: string[],\n configuration: IntlayerConfig,\n onStatusUpdate?: (status: DictionariesStatus[]) => void,\n options?: LoadContentDeclarationOptions\n): Promise<Dictionary[]> => {\n const { build, system } = configuration;\n\n // Check for TypeScript warnings before we build\n if (build.checkTypes) {\n logTypeScriptErrors(contentDeclarationFilePath, configuration).catch(\n (e) => {\n console.error('Error during TypeScript validation:', e);\n }\n );\n }\n\n const bundleFilePath = await ensureIntlayerBundle(configuration);\n\n try {\n const dictionariesPromises = contentDeclarationFilePath.map(\n async (path) => {\n const relativePath = relative(system.baseDir, path);\n\n const dictionary = await loadContentDeclaration(\n path,\n configuration,\n bundleFilePath,\n options\n );\n\n return { relativePath, dictionary };\n }\n );\n\n const dictionariesArray = await Promise.all(dictionariesPromises);\n const dictionariesRecord = dictionariesArray.reduce(\n (acc, { relativePath, dictionary }) => {\n if (dictionary) {\n acc[relativePath] = dictionary;\n }\n return acc;\n },\n {} as Record<string, Dictionary>\n );\n\n const contentDeclarations: Dictionary[] = formatLocalDictionaries(\n dictionariesRecord,\n configuration\n ).filter((dictionary) => dictionary.location !== 'remote');\n\n const listFoundDictionaries = contentDeclarations.map((declaration) => ({\n dictionaryKey: declaration.key,\n type: 'local' as const,\n status: 'found' as const,\n }));\n\n onStatusUpdate?.(listFoundDictionaries);\n\n const processedDictionaries = await parallelize(\n contentDeclarations,\n async (contentDeclaration): Promise<Dictionary | undefined> => {\n if (!contentDeclaration) {\n return undefined;\n }\n\n onStatusUpdate?.([\n {\n dictionaryKey: contentDeclaration.key,\n type: 'local',\n status: 'building',\n },\n ]);\n\n const processedContentDeclaration = await processContentDeclaration(\n contentDeclaration as Dictionary,\n configuration\n );\n\n if (!processedContentDeclaration) {\n return undefined;\n }\n\n onStatusUpdate?.([\n {\n dictionaryKey: processedContentDeclaration.key,\n type: 'local',\n status: 'built',\n },\n ]);\n\n return processedContentDeclaration;\n }\n );\n\n return filterInvalidDictionaries(processedDictionaries, configuration, {\n checkSchema: false,\n });\n } catch {\n console.error('Error loading content declarations');\n }\n\n return [];\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"loadContentDeclaration.cjs","names":["getIntlayerBundle","loadMarkdownContentDeclaration","loadYamlContentDeclaration","filterInvalidDictionaries","parallelize","processContentDeclaration"],"sources":["../../../src/loadDictionaries/loadContentDeclaration.ts"],"sourcesContent":["import { readFile, writeFile } from 'node:fs/promises';\nimport { dirname, extname, join, relative } from 'node:path';\nimport { loadExternalFile } from '@intlayer/config/file';\nimport {\n cacheDisk,\n getPackageJsonPath,\n getProjectRequire,\n} from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { processContentDeclaration } from '../buildIntlayerDictionary/processContentDeclaration';\nimport { filterInvalidDictionaries } from '../filterInvalidDictionaries';\nimport { parallelize } from '../utils/parallelize';\nimport { getIntlayerBundle } from './getIntlayerBundle';\nimport type { DictionariesStatus } from './loadDictionaries';\nimport { loadMarkdownContentDeclaration } from './loadMarkdownContentDeclaration';\nimport { loadYamlContentDeclaration } from './loadYamlContentDeclaration';\nimport { logTypeScriptErrors } from './logTypeScriptErrors';\n\nexport const formatLocalDictionaries = (\n dictionariesRecord: Record<string, Dictionary>,\n configuration: IntlayerConfig\n): Dictionary[] =>\n Object.entries(dictionariesRecord).map(([relativePath, dict]) => ({\n ...dict,\n location: dict.location ?? configuration.dictionary?.location ?? 'local',\n localId: `${dict.key}::local::${relativePath}`,\n filePath: relativePath,\n }));\n\nexport const ensureIntlayerBundle = async (\n configuration: IntlayerConfig\n): Promise<string> => {\n const { system } = configuration;\n\n const { set, isValid } = cacheDisk(configuration, ['intlayer-bundle'], {\n ttlMs: 1000 * 60 * 60 * 24 * 5, // 5 days\n });\n\n const filePath = join(system.cacheDir, 'intlayer-bundle.cjs');\n const hasIntlayerBundle = await isValid();\n\n if (!hasIntlayerBundle) {\n const intlayerBundle = await getIntlayerBundle(configuration);\n await writeFile(filePath, intlayerBundle);\n await set('ok');\n }\n\n return filePath;\n};\n\ntype LoadContentDeclarationOptions = {\n logError?: boolean;\n};\n\n// Initialize a module-level cache\nlet cachedExternalDeps: string[] | null = null;\n\n// Helper to fetch and cache the dependencies\nconst getExternalDeps = async (baseDir: string): Promise<string[]> => {\n if (cachedExternalDeps) {\n return cachedExternalDeps; // Return instantly on subsequent calls\n }\n\n try {\n const packageJsonPath = getPackageJsonPath(baseDir);\n\n const packageJSON = await readFile(\n packageJsonPath.packageJsonPath,\n 'utf-8'\n );\n const parsedPackages = JSON.parse(packageJSON);\n const allDependencies = Object.keys({\n ...parsedPackages.dependencies,\n ...parsedPackages.devDependencies,\n });\n\n // Specify the ESM packages to bundle\n const esmPackagesToBundle: string[] = [];\n\n const externalDeps = allDependencies.filter(\n (dep) => !esmPackagesToBundle.includes(dep)\n );\n\n externalDeps.push('esbuild');\n\n // Save to cache\n cachedExternalDeps = externalDeps;\n } catch (error) {\n console.warn(\n 'Could not read package.json for externalizing dependencies, fallback to empty array',\n error\n );\n cachedExternalDeps = ['esbuild'];\n }\n\n return cachedExternalDeps;\n};\n\nexport const loadContentDeclaration = async (\n path: string,\n configuration: IntlayerConfig,\n bundleFilePath?: string,\n options?: LoadContentDeclarationOptions\n): Promise<Dictionary | undefined> => {\n if (extname(path) === '.md' || extname(path) === '.mdx') {\n return loadMarkdownContentDeclaration(path);\n }\n\n if (extname(path) === '.yaml' || extname(path) === '.yml') {\n return loadYamlContentDeclaration(path);\n }\n\n const { build, system } = configuration;\n\n // Call the cached helper\n const externalDeps = await getExternalDeps(system.baseDir);\n\n const resolvedBundleFilePath =\n bundleFilePath ?? (await ensureIntlayerBundle(configuration));\n\n try {\n const dictionary = await loadExternalFile(path, {\n logError: options?.logError,\n projectRequire: build.require ?? getProjectRequire(),\n buildOptions: {\n packages: undefined, // It fixes the import of ESM packages in the content declaration\n external: externalDeps,\n banner: {\n js: [\n `var __filename = ${JSON.stringify(path)};`,\n `var __dirname = ${JSON.stringify(dirname(path))};`,\n // Also set on the VM sandbox's globalThis for VM-internal code.\n // External modules (e.g. @intlayer/core's file()) run in the main\n // Node.js context and are handled by preloadGlobals below.\n `globalThis.INTLAYER_FILE_PATH = ${JSON.stringify(path)};`,\n `globalThis.INTLAYER_BASE_DIR = ${JSON.stringify(configuration.system.baseDir)};`,\n ].join('\\n'),\n },\n },\n aliases: {\n intlayer: resolvedBundleFilePath,\n },\n // Temporarily expose these on the main Node.js globalThis so that external\n // modules required inside the VM (e.g. @intlayer/core's file() helper)\n // can resolve relative paths against the correct content declaration path.\n preloadGlobals: {\n INTLAYER_FILE_PATH: path,\n INTLAYER_BASE_DIR: configuration.system.baseDir,\n },\n });\n\n return dictionary;\n } catch (error) {\n console.error(`Error loading content declaration at ${path}:`, error);\n return undefined;\n }\n};\n\nexport const loadContentDeclarations = async (\n contentDeclarationFilePath: string[],\n configuration: IntlayerConfig,\n onStatusUpdate?: (status: DictionariesStatus[]) => void,\n options?: LoadContentDeclarationOptions\n): Promise<Dictionary[]> => {\n const { build, system } = configuration;\n\n // Check for TypeScript warnings before we build\n if (build.checkTypes) {\n logTypeScriptErrors(contentDeclarationFilePath, configuration).catch(\n (e) => {\n console.error('Error during TypeScript validation:', e);\n }\n );\n }\n\n const bundleFilePath = await ensureIntlayerBundle(configuration);\n\n try {\n const dictionariesPromises = contentDeclarationFilePath.map(\n async (path) => {\n const relativePath = relative(system.baseDir, path);\n\n const dictionary = await loadContentDeclaration(\n path,\n configuration,\n bundleFilePath,\n options\n );\n\n return { relativePath, dictionary };\n }\n );\n\n const dictionariesArray = await Promise.all(dictionariesPromises);\n const dictionariesRecord = dictionariesArray.reduce(\n (acc, { relativePath, dictionary }) => {\n if (dictionary) {\n acc[relativePath] = dictionary;\n }\n return acc;\n },\n {} as Record<string, Dictionary>\n );\n\n const contentDeclarations: Dictionary[] = formatLocalDictionaries(\n dictionariesRecord,\n configuration\n ).filter((dictionary) => dictionary.location !== 'remote');\n\n const listFoundDictionaries = contentDeclarations.map((declaration) => ({\n dictionaryKey: declaration.key,\n type: 'local' as const,\n status: 'found' as const,\n }));\n\n onStatusUpdate?.(listFoundDictionaries);\n\n const processedDictionaries = await parallelize(\n contentDeclarations,\n async (contentDeclaration): Promise<Dictionary | undefined> => {\n if (!contentDeclaration) {\n return undefined;\n }\n\n onStatusUpdate?.([\n {\n dictionaryKey: contentDeclaration.key,\n type: 'local',\n status: 'building',\n },\n ]);\n\n const processedContentDeclaration = await processContentDeclaration(\n contentDeclaration as Dictionary,\n configuration\n );\n\n if (!processedContentDeclaration) {\n return undefined;\n }\n\n onStatusUpdate?.([\n {\n dictionaryKey: processedContentDeclaration.key,\n type: 'local',\n status: 'built',\n },\n ]);\n\n return processedContentDeclaration;\n }\n );\n\n return filterInvalidDictionaries(processedDictionaries, configuration, {\n checkSchema: false,\n });\n } catch {\n console.error('Error loading content declarations');\n }\n\n return [];\n};\n"],"mappings":"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"}
@@ -80,13 +80,17 @@ const prepareIntlayer = async (configuration, options) => {
80
80
  appLogger(["Module augmentation built", (0, _intlayer_config_logger.colorize)(`(${Date.now() - dictionariesBuiltTime}ms)`, _intlayer_config_colors.GREY_DARK)], { isVerbose: true });
81
81
  for await (const plugin of configuration.plugins ?? []) {
82
82
  const { unmergedDictionaries, mergedDictionaries } = dictionariesOutput;
83
- await plugin.afterBuild?.({
84
- dictionaries: {
85
- unmergedDictionaries,
86
- mergedDictionaries
87
- },
88
- configuration
89
- });
83
+ try {
84
+ await plugin.afterBuild?.({
85
+ dictionaries: {
86
+ unmergedDictionaries,
87
+ mergedDictionaries
88
+ },
89
+ configuration
90
+ });
91
+ } catch (error) {
92
+ appLogger([`Plugin ${plugin.name} afterBuild failed:`, error.message], { level: "error" });
93
+ }
90
94
  }
91
95
  appLogger([`Done`, (0, _intlayer_config_logger.colorize)(`${Date.now() - preparationStartMs}ms`, _intlayer_config_colors.GREEN)], {
92
96
  level: "info",
@@ -1 +1 @@
1
- {"version":3,"file":"prepareIntlayer.cjs","names":["packageJson","isCachedConfigurationUpToDate","listDictionariesWithStats","runOnce","cleanOutputDir","ANSIColors","writeConfiguration","loadDictionaries","buildDictionary","writeRemoteDictionary","createTypes","createDictionaryEntryPoint","createModuleAugmentation"],"sources":["../../src/prepareIntlayer.ts"],"sourcesContent":["import { stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport packageJson from '@intlayer/config/package.json' with { type: 'json' };\nimport { cacheDisk } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { buildDictionary } from './buildIntlayerDictionary/buildIntlayerDictionary';\nimport { writeRemoteDictionary } from './buildIntlayerDictionary/writeRemoteDictionary';\nimport { cleanOutputDir } from './cleanOutputDir';\nimport { createDictionaryEntryPoint } from './createDictionaryEntryPoint/createDictionaryEntryPoint';\nimport { createModuleAugmentation, createTypes } from './createType/index';\nimport { listDictionariesWithStats } from './listDictionariesPath';\nimport { loadDictionaries } from './loadDictionaries/loadDictionaries';\nimport { runOnce } from './utils/runOnce';\nimport {\n isCachedConfigurationUpToDate,\n writeConfiguration,\n} from './writeConfiguration';\n\ntype PrepareIntlayerOptions = {\n clean?: boolean;\n env?: 'prod' | 'dev';\n format?: ('cjs' | 'esm')[];\n forceRun?: boolean;\n cacheTimeoutMs?: number;\n onIsCached?: () => void | Promise<void>;\n};\n\nconst DEFAULT_PREPARE_INTLAYER_OPTIONS = {\n clean: false,\n env: 'dev',\n format: ['cjs', 'esm'],\n cacheTimeoutMs: 1000 * 60 * 60, // 1 hour\n} satisfies PrepareIntlayerOptions;\n\nexport const prepareIntlayer = async (\n configuration: IntlayerConfig,\n options?: PrepareIntlayerOptions\n) => {\n const appLogger = getAppLogger(configuration);\n\n const sentinelPath = join(\n configuration.system.cacheDir,\n 'intlayer-prepared.lock'\n );\n // Clean output dir if the intlayer version has changed\n const versionCache = cacheDisk(configuration, ['intlayer-version']);\n const intlayerCacheVersion = await versionCache.get();\n const isCorrectVersion = Boolean(\n intlayerCacheVersion && intlayerCacheVersion === packageJson.version\n );\n\n const isConfigSimilar = await isCachedConfigurationUpToDate(configuration);\n\n // Check if any dictionary has been changed to force a new rebuild\n const dictionariesWithStats = await listDictionariesWithStats(configuration);\n let isDictionaryChanged = false;\n try {\n // Try catch as sentinel file may not exist yet\n const sentinelStats = await stat(sentinelPath);\n isDictionaryChanged = dictionariesWithStats.some(\n (dictionary) =>\n dictionary.stats.mtime.getTime() > sentinelStats.mtime.getTime()\n );\n } catch {}\n\n const resolvedPlugins = await Promise.all(configuration.plugins ?? []);\n const hasPluginLoadDictionaries = resolvedPlugins.some((plugin) =>\n Boolean(plugin.loadDictionaries)\n ); // Disable cache if any plugin because it can have custom behavior\n\n const { clean, format, forceRun, onIsCached, cacheTimeoutMs, env } = {\n ...DEFAULT_PREPARE_INTLAYER_OPTIONS,\n forceRun:\n !isCorrectVersion ||\n !isConfigSimilar ||\n isDictionaryChanged ||\n hasPluginLoadDictionaries,\n ...(options ?? {}),\n };\n\n // Skip preparation if it has already been done recently\n await runOnce(\n sentinelPath,\n async () => {\n // comment because of issue with next and webpack\n // await checkVersionsConsistency(configuration);\n\n if (clean || !isCorrectVersion) {\n await cleanOutputDir(configuration);\n }\n\n await versionCache.set(packageJson.version);\n\n const preparationStartMs = Date.now();\n\n appLogger([\n 'Preparing Intlayer',\n colorize(`(v${packageJson.version})`, ANSIColors.GREY_DARK),\n ]);\n\n await writeConfiguration(configuration);\n\n const configurationWrittenTime = Date.now();\n\n appLogger(\n [\n 'Configuration written',\n colorize(\n `(${configurationWrittenTime - preparationStartMs}ms)`,\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n const contentDeclarationPaths = dictionariesWithStats.map(\n (dictionary) => dictionary.path\n );\n\n const dictionaries = await loadDictionaries(\n contentDeclarationPaths,\n configuration\n );\n\n const dictionariesLoadedTime = Date.now();\n\n appLogger(\n [\n 'Content loaded',\n colorize(\n [\n dictionaries.remoteDictionaries.length +\n dictionaries.pluginDictionaries.length >\n 0\n ? [\n `(Total: ${dictionariesLoadedTime - configurationWrittenTime}ms`,\n dictionaries.localDictionaries.length > 0\n ? ` - Local: ${dictionaries.time.localDictionaries}ms`\n : '',\n dictionaries.remoteDictionaries.length > 0\n ? ` - Remote: ${dictionaries.time.remoteDictionaries}ms`\n : '',\n dictionaries.pluginDictionaries.length > 0\n ? ` - Plugin: ${dictionaries.time.pluginDictionaries}ms`\n : '',\n `)`,\n ].join('')\n : `(${dictionariesLoadedTime - configurationWrittenTime}ms)`,\n ].join(''),\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n // Build local dictionaries\n const dictionariesOutput = await buildDictionary(\n [\n ...dictionaries.localDictionaries,\n ...dictionaries.remoteDictionaries,\n ...dictionaries.pluginDictionaries,\n ],\n configuration,\n { formats: format, importOtherDictionaries: false, env }\n );\n\n // Write remote dictionaries\n // Used as cache for next fetch\n await writeRemoteDictionary(\n dictionaries.remoteDictionaries,\n configuration\n );\n\n const dictionariesToBuild = Object.values(\n dictionariesOutput?.mergedDictionaries ?? {}\n ).map((dictionary) => dictionary.dictionary);\n\n await createTypes(dictionariesToBuild, configuration);\n\n await createDictionaryEntryPoint(configuration, {\n formats: options?.format,\n });\n\n const dictionariesBuiltTime = Date.now();\n\n appLogger([\n 'Dictionaries built',\n colorize(\n `(${dictionariesBuiltTime - preparationStartMs}ms)`,\n ANSIColors.GREY_DARK\n ),\n ]);\n\n await createModuleAugmentation(configuration);\n\n const moduleAugmentationBuiltTime = Date.now();\n\n appLogger(\n [\n 'Module augmentation built',\n colorize(\n `(${moduleAugmentationBuiltTime - dictionariesBuiltTime}ms)`,\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n // Plugin transformation\n // Allow plugins to post-process the final build output (e.g., write back ICU JSON)\n for await (const plugin of configuration.plugins ?? []) {\n const { unmergedDictionaries, mergedDictionaries } = dictionariesOutput;\n\n await plugin.afterBuild?.({\n dictionaries: {\n unmergedDictionaries,\n mergedDictionaries,\n },\n configuration,\n });\n }\n\n const preparationElapsedMs = Date.now() - preparationStartMs;\n appLogger(\n [`Done`, colorize(`${preparationElapsedMs}ms`, ANSIColors.GREEN)],\n {\n level: 'info',\n isVerbose: true,\n }\n );\n },\n {\n forceRun,\n onIsCached,\n cacheTimeoutMs,\n }\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"prepareIntlayer.cjs","names":["packageJson","isCachedConfigurationUpToDate","listDictionariesWithStats","runOnce","cleanOutputDir","ANSIColors","writeConfiguration","loadDictionaries","buildDictionary","writeRemoteDictionary","createTypes","createDictionaryEntryPoint","createModuleAugmentation"],"sources":["../../src/prepareIntlayer.ts"],"sourcesContent":["import { stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport packageJson from '@intlayer/config/package.json' with { type: 'json' };\nimport { cacheDisk } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { buildDictionary } from './buildIntlayerDictionary/buildIntlayerDictionary';\nimport { writeRemoteDictionary } from './buildIntlayerDictionary/writeRemoteDictionary';\nimport { cleanOutputDir } from './cleanOutputDir';\nimport { createDictionaryEntryPoint } from './createDictionaryEntryPoint/createDictionaryEntryPoint';\nimport { createModuleAugmentation, createTypes } from './createType/index';\nimport { listDictionariesWithStats } from './listDictionariesPath';\nimport { loadDictionaries } from './loadDictionaries/loadDictionaries';\nimport { runOnce } from './utils/runOnce';\nimport {\n isCachedConfigurationUpToDate,\n writeConfiguration,\n} from './writeConfiguration';\n\ntype PrepareIntlayerOptions = {\n clean?: boolean;\n env?: 'prod' | 'dev';\n format?: ('cjs' | 'esm')[];\n forceRun?: boolean;\n cacheTimeoutMs?: number;\n onIsCached?: () => void | Promise<void>;\n};\n\nconst DEFAULT_PREPARE_INTLAYER_OPTIONS = {\n clean: false,\n env: 'dev',\n format: ['cjs', 'esm'],\n cacheTimeoutMs: 1000 * 60 * 60, // 1 hour\n} satisfies PrepareIntlayerOptions;\n\nexport const prepareIntlayer = async (\n configuration: IntlayerConfig,\n options?: PrepareIntlayerOptions\n) => {\n const appLogger = getAppLogger(configuration);\n\n const sentinelPath = join(\n configuration.system.cacheDir,\n 'intlayer-prepared.lock'\n );\n // Clean output dir if the intlayer version has changed\n const versionCache = cacheDisk(configuration, ['intlayer-version']);\n const intlayerCacheVersion = await versionCache.get();\n const isCorrectVersion = Boolean(\n intlayerCacheVersion && intlayerCacheVersion === packageJson.version\n );\n\n const isConfigSimilar = await isCachedConfigurationUpToDate(configuration);\n\n // Check if any dictionary has been changed to force a new rebuild\n const dictionariesWithStats = await listDictionariesWithStats(configuration);\n let isDictionaryChanged = false;\n try {\n // Try catch as sentinel file may not exist yet\n const sentinelStats = await stat(sentinelPath);\n isDictionaryChanged = dictionariesWithStats.some(\n (dictionary) =>\n dictionary.stats.mtime.getTime() > sentinelStats.mtime.getTime()\n );\n } catch {}\n\n const resolvedPlugins = await Promise.all(configuration.plugins ?? []);\n const hasPluginLoadDictionaries = resolvedPlugins.some((plugin) =>\n Boolean(plugin.loadDictionaries)\n ); // Disable cache if any plugin because it can have custom behavior\n\n const { clean, format, forceRun, onIsCached, cacheTimeoutMs, env } = {\n ...DEFAULT_PREPARE_INTLAYER_OPTIONS,\n forceRun:\n !isCorrectVersion ||\n !isConfigSimilar ||\n isDictionaryChanged ||\n hasPluginLoadDictionaries,\n ...(options ?? {}),\n };\n\n // Skip preparation if it has already been done recently\n await runOnce(\n sentinelPath,\n async () => {\n // comment because of issue with next and webpack\n // await checkVersionsConsistency(configuration);\n\n if (clean || !isCorrectVersion) {\n await cleanOutputDir(configuration);\n }\n\n await versionCache.set(packageJson.version);\n\n const preparationStartMs = Date.now();\n\n appLogger([\n 'Preparing Intlayer',\n colorize(`(v${packageJson.version})`, ANSIColors.GREY_DARK),\n ]);\n\n await writeConfiguration(configuration);\n\n const configurationWrittenTime = Date.now();\n\n appLogger(\n [\n 'Configuration written',\n colorize(\n `(${configurationWrittenTime - preparationStartMs}ms)`,\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n const contentDeclarationPaths = dictionariesWithStats.map(\n (dictionary) => dictionary.path\n );\n\n const dictionaries = await loadDictionaries(\n contentDeclarationPaths,\n configuration\n );\n\n const dictionariesLoadedTime = Date.now();\n\n appLogger(\n [\n 'Content loaded',\n colorize(\n [\n dictionaries.remoteDictionaries.length +\n dictionaries.pluginDictionaries.length >\n 0\n ? [\n `(Total: ${dictionariesLoadedTime - configurationWrittenTime}ms`,\n dictionaries.localDictionaries.length > 0\n ? ` - Local: ${dictionaries.time.localDictionaries}ms`\n : '',\n dictionaries.remoteDictionaries.length > 0\n ? ` - Remote: ${dictionaries.time.remoteDictionaries}ms`\n : '',\n dictionaries.pluginDictionaries.length > 0\n ? ` - Plugin: ${dictionaries.time.pluginDictionaries}ms`\n : '',\n `)`,\n ].join('')\n : `(${dictionariesLoadedTime - configurationWrittenTime}ms)`,\n ].join(''),\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n // Build local dictionaries\n const dictionariesOutput = await buildDictionary(\n [\n ...dictionaries.localDictionaries,\n ...dictionaries.remoteDictionaries,\n ...dictionaries.pluginDictionaries,\n ],\n configuration,\n { formats: format, importOtherDictionaries: false, env }\n );\n\n // Write remote dictionaries\n // Used as cache for next fetch\n await writeRemoteDictionary(\n dictionaries.remoteDictionaries,\n configuration\n );\n\n const dictionariesToBuild = Object.values(\n dictionariesOutput?.mergedDictionaries ?? {}\n ).map((dictionary) => dictionary.dictionary);\n\n await createTypes(dictionariesToBuild, configuration);\n\n await createDictionaryEntryPoint(configuration, {\n formats: options?.format,\n });\n\n const dictionariesBuiltTime = Date.now();\n\n appLogger([\n 'Dictionaries built',\n colorize(\n `(${dictionariesBuiltTime - preparationStartMs}ms)`,\n ANSIColors.GREY_DARK\n ),\n ]);\n\n await createModuleAugmentation(configuration);\n\n const moduleAugmentationBuiltTime = Date.now();\n\n appLogger(\n [\n 'Module augmentation built',\n colorize(\n `(${moduleAugmentationBuiltTime - dictionariesBuiltTime}ms)`,\n ANSIColors.GREY_DARK\n ),\n ],\n {\n isVerbose: true,\n }\n );\n\n // Plugin transformation\n // Allow plugins to post-process the final build output (e.g., write back ICU JSON)\n for await (const plugin of configuration.plugins ?? []) {\n const { unmergedDictionaries, mergedDictionaries } = dictionariesOutput;\n\n try {\n await plugin.afterBuild?.({\n dictionaries: {\n unmergedDictionaries,\n mergedDictionaries,\n },\n configuration,\n });\n } catch (error) {\n // A failing write-back (e.g. transient network error on a remote\n // target) must not invalidate the dictionaries already built.\n appLogger(\n [\n `Plugin ${plugin.name} afterBuild failed:`,\n (error as Error).message,\n ],\n { level: 'error' }\n );\n }\n }\n\n const preparationElapsedMs = Date.now() - preparationStartMs;\n appLogger(\n [`Done`, colorize(`${preparationElapsedMs}ms`, ANSIColors.GREEN)],\n {\n level: 'info',\n isVerbose: true,\n }\n );\n },\n {\n forceRun,\n onIsCached,\n cacheTimeoutMs,\n }\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
3
+ const require_writeFileIfChanged = require('../writeFileIfChanged.cjs');
4
+ const require_syncPluginKit_extractKeyAndLocaleFromPath = require('./extractKeyAndLocaleFromPath.cjs');
5
+ const require_syncPluginKit_filePathPatternHelpers = require('./filePathPatternHelpers.cjs');
6
+ let node_fs_promises = require("node:fs/promises");
7
+ let node_path = require("node:path");
8
+ let fast_glob = require("fast-glob");
9
+ fast_glob = require_runtime.__toESM(fast_glob);
10
+ let _intlayer_config_utils = require("@intlayer/config/utils");
11
+
12
+ //#region src/syncPluginKit/createFileAdapter.ts
13
+ /**
14
+ * Create a filesystem {@link ContentAdapter} for `createSyncPlugin`.
15
+ *
16
+ * Handles glob discovery of the source pattern, key/locale extraction from
17
+ * paths, base-directory resolution, and change-detected atomic writes.
18
+ */
19
+ const createFileAdapter = (options) => {
20
+ const { source, codec, discovery = "strict" } = options;
21
+ const readEntry = options.readEntry ?? createFileReader(codec.parse);
22
+ let patternMarkerPromise;
23
+ /**
24
+ * Source pattern with `{{key}}` / `{{locale}}` markers kept verbatim,
25
+ * memoized because pattern functions can be asynchronous.
26
+ */
27
+ const getPatternMarker = () => {
28
+ patternMarkerPromise ??= (0, _intlayer_config_utils.parseFilePathPattern)(source, require_syncPluginKit_filePathPatternHelpers.buildFilePathPatternContext("{{key}}", "{{locale}}"));
29
+ return patternMarkerPromise;
30
+ };
31
+ const listMessages = async (context) => {
32
+ const { system, internationalization } = context.configuration;
33
+ const { baseDir } = system;
34
+ const { locales } = internationalization;
35
+ const result = {};
36
+ for (const locale of locales) {
37
+ const globPatternLocale = await (0, _intlayer_config_utils.parseFilePathPattern)(source, require_syncPluginKit_filePathPatternHelpers.buildFilePathPatternContext("**", locale));
38
+ const maskPatternLocale = await (0, _intlayer_config_utils.parseFilePathPattern)(source, require_syncPluginKit_filePathPatternHelpers.buildFilePathPatternContext("{{__KEY__}}", locale));
39
+ if (!globPatternLocale || !maskPatternLocale) continue;
40
+ const files = await (0, fast_glob.default)(globPatternLocale.startsWith("./") ? globPatternLocale.slice(2) : globPatternLocale, { cwd: baseDir });
41
+ const hasLocaleInMask = maskPatternLocale.includes("{{__LOCALE__}}");
42
+ const hasKeyInMask = maskPatternLocale.includes("{{__KEY__}}");
43
+ for (const file of files) {
44
+ let key;
45
+ let extractedLocale;
46
+ if (hasLocaleInMask || hasKeyInMask) {
47
+ const extraction = require_syncPluginKit_extractKeyAndLocaleFromPath.extractKeyAndLocaleFromPath(file, maskPatternLocale, locales, locale);
48
+ if (!extraction) continue;
49
+ key = extraction.key;
50
+ extractedLocale = extraction.locale;
51
+ } else if (discovery === "inclusive") {
52
+ key = "index";
53
+ extractedLocale = locale;
54
+ } else continue;
55
+ const absoluteFoundPath = (0, node_path.isAbsolute)(file) ? file : (0, node_path.resolve)(baseDir, file);
56
+ if (discovery === "strict") {
57
+ const expectedPath = await (0, _intlayer_config_utils.parseFilePathPattern)(source, require_syncPluginKit_filePathPatternHelpers.buildFilePathPatternContext(key, extractedLocale));
58
+ if (absoluteFoundPath !== ((0, node_path.isAbsolute)(expectedPath) ? expectedPath : (0, node_path.resolve)(baseDir, expectedPath))) continue;
59
+ }
60
+ result[extractedLocale] ??= {};
61
+ result[extractedLocale][key] = absoluteFoundPath;
62
+ }
63
+ }
64
+ if (discovery === "inclusive") return result;
65
+ const hasKeyInMask = (await (0, _intlayer_config_utils.parseFilePathPattern)(source, require_syncPluginKit_filePathPatternHelpers.buildFilePathPatternContext("{{__KEY__}}", locales[0]))).includes("{{__KEY__}}");
66
+ const discoveredKeys = /* @__PURE__ */ new Set();
67
+ for (const locale of Object.keys(result)) for (const key of Object.keys(result[locale] ?? {})) discoveredKeys.add(key);
68
+ if (!hasKeyInMask) discoveredKeys.add("index");
69
+ for (const locale of locales) {
70
+ result[locale] ??= {};
71
+ for (const key of discoveredKeys) if (!result[locale][key]) {
72
+ const builtPath = await (0, _intlayer_config_utils.parseFilePathPattern)(source, require_syncPluginKit_filePathPatternHelpers.buildFilePathPatternContext(key, locale));
73
+ result[locale][key] = (0, node_path.isAbsolute)(builtPath) ? builtPath : (0, node_path.resolve)(baseDir, builtPath);
74
+ }
75
+ }
76
+ return result;
77
+ };
78
+ return {
79
+ list: async (context) => {
80
+ const messages = await listMessages(context);
81
+ return Object.entries(messages).flatMap(([locale, keysRecord]) => Object.entries(keysRecord).map(([key, absoluteFilePath]) => ({
82
+ key,
83
+ locale,
84
+ uri: absoluteFilePath,
85
+ filePath: absoluteFilePath
86
+ })));
87
+ },
88
+ read: async (entry, context) => await readEntry(entry.uri, context),
89
+ write: async ({ key, locale }, content, { configuration }) => {
90
+ const builderPath = await (0, _intlayer_config_utils.parseFilePathPattern)(source, require_syncPluginKit_filePathPatternHelpers.buildFilePathPatternContext(key, locale));
91
+ const absoluteFilePath = (0, node_path.resolve)(configuration.system.baseDir, builderPath);
92
+ await (0, node_fs_promises.mkdir)((0, node_path.dirname)(absoluteFilePath), { recursive: true });
93
+ await require_writeFileIfChanged.writeFileIfChanged(absoluteFilePath, codec.serialize(content, { locale }), { tempDir: configuration.system?.tempDir });
94
+ },
95
+ resolveUri: async ({ key, locale }, { configuration }) => {
96
+ const builderPath = await (0, _intlayer_config_utils.parseFilePathPattern)(source, require_syncPluginKit_filePathPatternHelpers.buildFilePathPatternContext(key, locale));
97
+ return (0, node_path.resolve)(configuration.system.baseDir, builderPath);
98
+ },
99
+ getFillPattern: async () => await getPatternMarker(),
100
+ describeSource: async () => await getPatternMarker(),
101
+ detectSplitKeys: async () => !(await getPatternMarker()).includes("{{key}}")
102
+ };
103
+ };
104
+ /**
105
+ * Default `readEntry` implementation: plain utf-8 read followed by the given
106
+ * parser. Returns `undefined` for missing or unreadable files.
107
+ */
108
+ const createFileReader = (parse) => async (absoluteFilePath) => {
109
+ try {
110
+ return parse(await (0, node_fs_promises.readFile)(absoluteFilePath, "utf-8"));
111
+ } catch {
112
+ return;
113
+ }
114
+ };
115
+
116
+ //#endregion
117
+ exports.createFileAdapter = createFileAdapter;
118
+ exports.createFileReader = createFileReader;
119
+ //# sourceMappingURL=createFileAdapter.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createFileAdapter.cjs","names":["buildFilePathPatternContext","extractKeyAndLocaleFromPath","writeFileIfChanged"],"sources":["../../../src/syncPluginKit/createFileAdapter.ts"],"sourcesContent":["import { mkdir, readFile } from 'node:fs/promises';\nimport { dirname, isAbsolute, resolve } from 'node:path';\nimport { parseFilePathPattern } from '@intlayer/config/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { FilePathPattern } from '@intlayer/types/filePathPattern';\nimport fg from 'fast-glob';\nimport { writeFileIfChanged } from '../writeFileIfChanged';\nimport { extractKeyAndLocaleFromPath } from './extractKeyAndLocaleFromPath';\nimport { buildFilePathPatternContext } from './filePathPatternHelpers';\nimport type {\n ContentAdapter,\n ContentEntry,\n FormatCodec,\n SyncContent,\n SyncPluginContext,\n} from './types';\n\n/**\n * Discovery strategy of the file adapter:\n * - `strict`: keep only files whose path rebuilds identically from the source\n * pattern, and fabricate entries for missing locales/keys so every declared\n * locale has a write-back target (sync plugins).\n * - `inclusive`: keep every glob match without fabricating missing entries\n * (read-only load plugins, whose patterns may contain free `**` globs).\n */\nexport type FileAdapterDiscovery = 'strict' | 'inclusive';\n\nexport type CreateFileAdapterOptions = {\n /**\n * Location of the files, as a static string, a templated string\n * (e.g. `./messages/{{locale}}/{{key}}.json`) or a function building the\n * path from the key and locale.\n */\n source: FilePathPattern;\n\n /**\n * Format of the files: string payload ↔ structured content.\n */\n codec: FormatCodec;\n\n /**\n * Optional override of how one file is read and parsed. Defaults to a plain\n * utf-8 read followed by `codec.parse`, returning `undefined` for missing or\n * unreadable files. Adapters needing richer loading (e.g. JSON5 or\n * transpiled TS sources) provide their own implementation here.\n */\n readEntry?: (\n absoluteFilePath: string,\n context: SyncPluginContext\n ) => Promise<SyncContent | undefined>;\n\n /**\n * Discovery strategy. Defaults to `'strict'`.\n */\n discovery?: FileAdapterDiscovery;\n};\n\ntype FilePath = string;\ntype MessagesRecord = Record<Locale, Record<string, FilePath>>;\n\n/**\n * Create a filesystem {@link ContentAdapter} for `createSyncPlugin`.\n *\n * Handles glob discovery of the source pattern, key/locale extraction from\n * paths, base-directory resolution, and change-detected atomic writes.\n */\nexport const createFileAdapter = (\n options: CreateFileAdapterOptions\n): ContentAdapter => {\n const { source, codec, discovery = 'strict' } = options;\n const readEntry = options.readEntry ?? createFileReader(codec.parse);\n\n let patternMarkerPromise: Promise<string> | undefined;\n\n /**\n * Source pattern with `{{key}}` / `{{locale}}` markers kept verbatim,\n * memoized because pattern functions can be asynchronous.\n */\n const getPatternMarker = () => {\n patternMarkerPromise ??= parseFilePathPattern(\n source,\n buildFilePathPatternContext('{{key}}', '{{locale}}')\n );\n\n return patternMarkerPromise;\n };\n\n const listMessages = async (\n context: SyncPluginContext\n ): Promise<MessagesRecord> => {\n const { system, internationalization } = context.configuration;\n const { baseDir } = system;\n const { locales } = internationalization;\n\n const result: MessagesRecord = {} as MessagesRecord;\n\n for (const locale of locales) {\n const globPatternLocale = await parseFilePathPattern(\n source,\n buildFilePathPatternContext('**', locale)\n );\n\n const maskPatternLocale = await parseFilePathPattern(\n source,\n buildFilePathPatternContext('{{__KEY__}}', locale)\n );\n\n if (!globPatternLocale || !maskPatternLocale) {\n continue;\n }\n\n const normalizedGlobPattern = globPatternLocale.startsWith('./')\n ? globPatternLocale.slice(2)\n : globPatternLocale;\n\n const files = await fg(normalizedGlobPattern, {\n cwd: baseDir,\n });\n\n const hasLocaleInMask = maskPatternLocale.includes('{{__LOCALE__}}');\n const hasKeyInMask = maskPatternLocale.includes('{{__KEY__}}');\n\n for (const file of files) {\n let key: string;\n let extractedLocale: Locale;\n\n if (hasLocaleInMask || hasKeyInMask) {\n const extraction = extractKeyAndLocaleFromPath(\n file,\n maskPatternLocale,\n locales,\n locale\n );\n\n if (!extraction) {\n continue;\n }\n\n key = extraction.key;\n extractedLocale = extraction.locale;\n } else if (discovery === 'inclusive') {\n // Mask has no placeholders — the file was found via a concrete\n // locale glob. Attribute it directly to the current loop locale.\n key = 'index';\n extractedLocale = locale;\n } else {\n // Strict mode relies on the fabrication step below to attribute\n // placeholder-free sources to their canonical paths.\n continue;\n }\n\n const absoluteFoundPath = isAbsolute(file)\n ? file\n : resolve(baseDir, file);\n\n if (discovery === 'strict') {\n // Rebuild what the path SHOULD be for this key/locale. A mismatch\n // means the file belongs to another plugin/structure.\n const expectedPath = await parseFilePathPattern(\n source,\n buildFilePathPatternContext(key, extractedLocale)\n );\n\n const absoluteExpectedPath = isAbsolute(expectedPath)\n ? expectedPath\n : resolve(baseDir, expectedPath);\n\n if (absoluteFoundPath !== absoluteExpectedPath) {\n continue;\n }\n }\n\n result[extractedLocale] ??= {};\n result[extractedLocale][key] = absoluteFoundPath;\n }\n }\n\n if (discovery === 'inclusive') {\n // Read-only mode only uses actual discovered files; do not fabricate\n // missing locales or keys, since no outputs are written.\n return result;\n }\n\n // Ensure all declared locales are present even if the file doesn't exist yet\n const maskWithKey = await parseFilePathPattern(\n source,\n buildFilePathPatternContext('{{__KEY__}}', locales[0])\n );\n\n const hasKeyInMask = maskWithKey.includes('{{__KEY__}}');\n const discoveredKeys = new Set<string>();\n\n for (const locale of Object.keys(result) as Locale[]) {\n for (const key of Object.keys(result[locale] ?? {})) {\n discoveredKeys.add(key);\n }\n }\n\n if (!hasKeyInMask) {\n discoveredKeys.add('index');\n }\n\n for (const locale of locales) {\n result[locale] ??= {};\n\n for (const key of discoveredKeys) {\n if (!result[locale][key]) {\n const builtPath = await parseFilePathPattern(\n source,\n buildFilePathPatternContext(key, locale)\n );\n\n result[locale][key] = isAbsolute(builtPath)\n ? builtPath\n : resolve(baseDir, builtPath);\n }\n }\n }\n\n return result;\n };\n\n return {\n list: async (context) => {\n const messages = await listMessages(context);\n\n const entries: ContentEntry[] = (\n Object.entries(messages) as [Locale, Record<string, FilePath>][]\n ).flatMap(([locale, keysRecord]) =>\n Object.entries(keysRecord).map(([key, absoluteFilePath]) => ({\n key,\n locale,\n uri: absoluteFilePath,\n filePath: absoluteFilePath,\n }))\n );\n\n return entries;\n },\n\n read: async (entry, context) => await readEntry(entry.uri, context),\n\n write: async ({ key, locale }, content, { configuration }) => {\n const builderPath = await parseFilePathPattern(\n source,\n buildFilePathPatternContext(key, locale)\n );\n\n const absoluteFilePath = resolve(\n configuration.system.baseDir,\n builderPath\n );\n\n await mkdir(dirname(absoluteFilePath), { recursive: true });\n\n await writeFileIfChanged(\n absoluteFilePath,\n codec.serialize(content, { locale }),\n { tempDir: configuration.system?.tempDir }\n );\n },\n\n resolveUri: async ({ key, locale }, { configuration }) => {\n const builderPath = await parseFilePathPattern(\n source,\n buildFilePathPatternContext(key, locale)\n );\n\n return resolve(configuration.system.baseDir, builderPath);\n },\n\n getFillPattern: async () => await getPatternMarker(),\n\n describeSource: async () => await getPatternMarker(),\n\n detectSplitKeys: async () =>\n !(await getPatternMarker()).includes('{{key}}'),\n };\n};\n\n/**\n * Default `readEntry` implementation: plain utf-8 read followed by the given\n * parser. Returns `undefined` for missing or unreadable files.\n */\nexport const createFileReader =\n (parse: (raw: string) => SyncContent) =>\n async (absoluteFilePath: string): Promise<SyncContent | undefined> => {\n try {\n const raw = await readFile(absoluteFilePath, 'utf-8');\n\n return parse(raw);\n } catch {\n return undefined;\n }\n };\n"],"mappings":"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"}
@@ -0,0 +1,154 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
3
+ let node_path = require("node:path");
4
+ let _intlayer_config_logger = require("@intlayer/config/logger");
5
+
6
+ //#region src/syncPluginKit/createSyncPlugin.ts
7
+ /**
8
+ * Content that carries nothing to persist: `undefined`, `null`, or an object
9
+ * without any own key. Writing it back would erase the target.
10
+ */
11
+ const isEmptyContent = (content) => typeof content === "undefined" || content === null || typeof content === "object" && Object.keys(content).length === 0;
12
+ /**
13
+ * Deep-clone formatted output into plain JSON data, stripping prototypes and
14
+ * non-serializable values before the emptiness check and the write.
15
+ */
16
+ const toPlainContent = (content) => typeof content === "undefined" ? void 0 : JSON.parse(JSON.stringify(content));
17
+ /**
18
+ * Build an Intlayer {@link Plugin} from a transport adapter.
19
+ *
20
+ * The factory implements the three plugin hooks once — ingestion
21
+ * (`loadDictionaries`), content-declaration reformatting (`formatOutput`) and
22
+ * write-back (`afterBuild`) — so adapters only describe *where* content lives
23
+ * (filesystem, TMS such as Crowdin, extra CMS…) and codecs only describe the
24
+ * payload format. Write-back only processes dictionaries whose `location`
25
+ * matches this plugin instance, so adapters never see foreign content.
26
+ */
27
+ const createSyncPlugin = (options) => {
28
+ const { name, adapter, direction = "both", location, priority = 0, format, localeOverride } = options;
29
+ let splitKeysPromise;
30
+ /**
31
+ * `splitKeys` resolution is asynchronous (adapter auto-detection may parse
32
+ * an async source pattern), so it is resolved lazily and memoized.
33
+ */
34
+ const resolveSplitKeys = () => {
35
+ splitKeysPromise ??= (async () => options.splitKeys ?? await adapter.detectSplitKeys?.() ?? false)();
36
+ return splitKeysPromise;
37
+ };
38
+ const loadDictionaries = async ({ configuration }) => {
39
+ const context = { configuration };
40
+ const appLogger = (0, _intlayer_config_logger.getAppLogger)(configuration);
41
+ const entries = await adapter.list(context);
42
+ if (entries.length === 0) appLogger(`[${name}] No dictionaries found at locations matching source pattern: ${(0, _intlayer_config_logger.colorizePath)(await adapter.describeSource?.(context) ?? name)}`, { level: "warn" });
43
+ const shouldSplitByKeys = await resolveSplitKeys();
44
+ const { baseDir } = configuration.system;
45
+ const { defaultLocale } = configuration.internationalization;
46
+ let patternFill;
47
+ if (direction === "both" && adapter.getFillPattern) patternFill = (0, node_path.relative)(baseDir, (0, node_path.resolve)(baseDir, await adapter.getFillPattern(context)));
48
+ const dictionaries = [];
49
+ for (const entry of entries) {
50
+ const content = await adapter.read(entry, context) ?? {};
51
+ const relativeFilePath = entry.filePath ? (0, node_path.relative)(baseDir, entry.filePath) : void 0;
52
+ const usedLocale = localeOverride ?? entry.locale;
53
+ const filled = usedLocale !== defaultLocale ? true : void 0;
54
+ const fill = patternFill ?? relativeFilePath;
55
+ const identifier = relativeFilePath ?? entry.uri;
56
+ if (shouldSplitByKeys) {
57
+ for (const [namespaceKey, namespaceContent] of Object.entries(content)) dictionaries.push({
58
+ key: namespaceKey,
59
+ locale: usedLocale,
60
+ fill,
61
+ format,
62
+ localId: `${namespaceKey}::${location}::${identifier}`,
63
+ location,
64
+ filled,
65
+ content: namespaceContent,
66
+ filePath: relativeFilePath,
67
+ priority
68
+ });
69
+ continue;
70
+ }
71
+ dictionaries.push({
72
+ key: entry.key,
73
+ locale: usedLocale,
74
+ fill,
75
+ format,
76
+ localId: `${entry.key}::${location}::${identifier}`,
77
+ location,
78
+ filled,
79
+ content,
80
+ filePath: relativeFilePath,
81
+ priority
82
+ });
83
+ }
84
+ return dictionaries;
85
+ };
86
+ if (direction === "pull") return {
87
+ name,
88
+ loadDictionaries
89
+ };
90
+ const formatOutput = async ({ dictionary, configuration }) => {
91
+ if (!dictionary.filePath || !dictionary.locale) return dictionary;
92
+ if (await resolveSplitKeys()) return dictionary;
93
+ if (!adapter.resolveUri) return dictionary;
94
+ const canonicalUri = await adapter.resolveUri({
95
+ key: dictionary.key,
96
+ locale: dictionary.locale
97
+ }, { configuration });
98
+ const { baseDir } = configuration.system;
99
+ if ((0, node_path.resolve)(baseDir, canonicalUri) !== (0, node_path.resolve)(baseDir, dictionary.filePath)) return dictionary;
100
+ const { formatDictionaryOutput } = await Promise.resolve().then(() => require("../formatDictionary.cjs"));
101
+ return formatDictionaryOutput(dictionary, format).content;
102
+ };
103
+ const afterBuild = async ({ dictionaries, configuration }) => {
104
+ const { getPerLocaleDictionary } = await import("@intlayer/core/plugins");
105
+ const { formatDictionaryOutput } = await Promise.resolve().then(() => require("../formatDictionary.cjs"));
106
+ const { parallelize } = await Promise.resolve().then(() => require("../utils/parallelize.cjs"));
107
+ const context = { configuration };
108
+ const { locales } = configuration.internationalization;
109
+ const ownedDictionaries = Object.entries(dictionaries.mergedDictionaries).map(([key, result]) => ({
110
+ key,
111
+ dictionary: result.dictionary
112
+ })).filter(({ dictionary }) => dictionary.location === location);
113
+ if (await resolveSplitKeys()) {
114
+ const mergedContentByLocale = {};
115
+ const writeKeyByLocale = {};
116
+ for (const { key, dictionary } of ownedDictionaries) for (const locale of locales) {
117
+ const content = toPlainContent(formatDictionaryOutput(getPerLocaleDictionary(dictionary, locale), format).content);
118
+ if (isEmptyContent(content)) continue;
119
+ mergedContentByLocale[locale] ??= {};
120
+ mergedContentByLocale[locale][key] = content;
121
+ writeKeyByLocale[locale] = key;
122
+ }
123
+ await parallelize(Object.keys(mergedContentByLocale), async (locale) => {
124
+ await adapter.write({
125
+ key: writeKeyByLocale[locale],
126
+ locale
127
+ }, mergedContentByLocale[locale], context);
128
+ });
129
+ return;
130
+ }
131
+ await parallelize(ownedDictionaries.flatMap(({ key, dictionary }) => locales.map((locale) => ({
132
+ key,
133
+ dictionary,
134
+ locale
135
+ }))), async ({ key, dictionary, locale }) => {
136
+ const content = toPlainContent(formatDictionaryOutput(getPerLocaleDictionary(dictionary, locale), format).content);
137
+ if (isEmptyContent(content)) return;
138
+ await adapter.write({
139
+ key,
140
+ locale
141
+ }, content, context);
142
+ });
143
+ };
144
+ return {
145
+ name,
146
+ loadDictionaries,
147
+ formatOutput,
148
+ afterBuild
149
+ };
150
+ };
151
+
152
+ //#endregion
153
+ exports.createSyncPlugin = createSyncPlugin;
154
+ //# sourceMappingURL=createSyncPlugin.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createSyncPlugin.cjs","names":[],"sources":["../../../src/syncPluginKit/createSyncPlugin.ts"],"sourcesContent":["import { relative, resolve } from 'node:path';\nimport { colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { Dictionary, LocalDictionaryId } from '@intlayer/types/dictionary';\nimport type { Plugin } from '@intlayer/types/plugin';\nimport type {\n CreateSyncPluginOptions,\n SyncContent,\n SyncPluginContext,\n} from './types';\n\n/**\n * Content that carries nothing to persist: `undefined`, `null`, or an object\n * without any own key. Writing it back would erase the target.\n */\nconst isEmptyContent = (content: unknown): boolean =>\n typeof content === 'undefined' ||\n content === null ||\n (typeof content === 'object' && Object.keys(content).length === 0);\n\n/**\n * Deep-clone formatted output into plain JSON data, stripping prototypes and\n * non-serializable values before the emptiness check and the write.\n */\nconst toPlainContent = (content: unknown): unknown =>\n typeof content === 'undefined'\n ? undefined\n : JSON.parse(JSON.stringify(content));\n\n/**\n * Build an Intlayer {@link Plugin} from a transport adapter.\n *\n * The factory implements the three plugin hooks once — ingestion\n * (`loadDictionaries`), content-declaration reformatting (`formatOutput`) and\n * write-back (`afterBuild`) — so adapters only describe *where* content lives\n * (filesystem, TMS such as Crowdin, extra CMS…) and codecs only describe the\n * payload format. Write-back only processes dictionaries whose `location`\n * matches this plugin instance, so adapters never see foreign content.\n */\nexport const createSyncPlugin = (options: CreateSyncPluginOptions): Plugin => {\n const {\n name,\n adapter,\n direction = 'both',\n location,\n priority = 0,\n format,\n localeOverride,\n } = options;\n\n let splitKeysPromise: Promise<boolean> | undefined;\n\n /**\n * `splitKeys` resolution is asynchronous (adapter auto-detection may parse\n * an async source pattern), so it is resolved lazily and memoized.\n */\n const resolveSplitKeys = (): Promise<boolean> => {\n splitKeysPromise ??= (async () =>\n options.splitKeys ?? (await adapter.detectSplitKeys?.()) ?? false)();\n\n return splitKeysPromise;\n };\n\n const loadDictionaries: Plugin['loadDictionaries'] = async ({\n configuration,\n }) => {\n const context: SyncPluginContext = { configuration };\n const appLogger = getAppLogger(configuration);\n\n const entries = await adapter.list(context);\n\n if (entries.length === 0) {\n const sourceDescription =\n (await adapter.describeSource?.(context)) ?? name;\n\n appLogger(\n `[${name}] No dictionaries found at locations matching source pattern: ${colorizePath(sourceDescription)}`,\n { level: 'warn' }\n );\n }\n\n const shouldSplitByKeys = await resolveSplitKeys();\n const { baseDir } = configuration.system;\n const { defaultLocale } = configuration.internationalization;\n\n // Sync plugins advertise the source pattern (with {{key}}/{{locale}}\n // markers) as fill target; pull-only plugins fill each entry in place.\n let patternFill: string | undefined;\n\n if (direction === 'both' && adapter.getFillPattern) {\n const fillPattern = await adapter.getFillPattern(context);\n patternFill = relative(baseDir, resolve(baseDir, fillPattern));\n }\n\n const dictionaries: Dictionary[] = [];\n\n for (const entry of entries) {\n const content = (await adapter.read(entry, context)) ?? {};\n\n const relativeFilePath = entry.filePath\n ? relative(baseDir, entry.filePath)\n : undefined;\n\n const usedLocale = (localeOverride ?? entry.locale) as Locale;\n const filled = usedLocale !== defaultLocale ? true : undefined;\n const fill = patternFill ?? relativeFilePath;\n const identifier = relativeFilePath ?? entry.uri;\n\n // One entry groups several namespaces by its first-level keys: emit one\n // dictionary per top-level key (e.g. `Hero`, `Nav`, …).\n if (shouldSplitByKeys) {\n for (const [namespaceKey, namespaceContent] of Object.entries(\n content\n )) {\n dictionaries.push({\n key: namespaceKey,\n locale: usedLocale,\n fill,\n format,\n localId:\n `${namespaceKey}::${location}::${identifier}` as LocalDictionaryId,\n location: location as Dictionary['location'],\n filled,\n content: namespaceContent as SyncContent,\n filePath: relativeFilePath,\n priority,\n } as Dictionary);\n }\n continue;\n }\n\n dictionaries.push({\n key: entry.key,\n locale: usedLocale,\n fill,\n format,\n localId:\n `${entry.key}::${location}::${identifier}` as LocalDictionaryId,\n location: location as Dictionary['location'],\n filled,\n content,\n filePath: relativeFilePath,\n priority,\n } as Dictionary);\n }\n\n return dictionaries;\n };\n\n if (direction === 'pull') {\n return { name, loadDictionaries };\n }\n\n const formatOutput: Plugin['formatOutput'] = async ({\n dictionary,\n configuration,\n }) => {\n if (!dictionary.filePath || !dictionary.locale) return dictionary;\n\n // In split mode several namespaces share the same target; the target is\n // re-assembled in `afterBuild`. Skip here to avoid overwriting the whole\n // target with a single namespace.\n if (await resolveSplitKeys()) return dictionary;\n\n // Ownership check: only reformat declarations this adapter can identify\n // as its own canonical target.\n if (!adapter.resolveUri) return dictionary;\n\n const canonicalUri = await adapter.resolveUri(\n { key: dictionary.key, locale: dictionary.locale as Locale },\n { configuration }\n );\n\n const { baseDir } = configuration.system;\n\n if (\n resolve(baseDir, canonicalUri) !== resolve(baseDir, dictionary.filePath)\n ) {\n return dictionary;\n }\n\n // Lazy import to keep the module graph light when configs are transpiled\n const { formatDictionaryOutput } = await import('../formatDictionary');\n\n return formatDictionaryOutput(dictionary as Dictionary, format).content;\n };\n\n const afterBuild: Plugin['afterBuild'] = async ({\n dictionaries,\n configuration,\n }) => {\n // Lazy imports to keep the module graph light when configs are transpiled\n const { getPerLocaleDictionary } = await import('@intlayer/core/plugins');\n const { formatDictionaryOutput } = await import('../formatDictionary');\n const { parallelize } = await import('../utils/parallelize');\n\n const context: SyncPluginContext = { configuration };\n const { locales } = configuration.internationalization;\n\n // Only ever hand the adapter dictionaries owned by THIS plugin instance.\n const ownedDictionaries = Object.entries(dictionaries.mergedDictionaries)\n .map(([key, result]) => ({\n key,\n dictionary: result.dictionary as Dictionary,\n }))\n .filter(({ dictionary }) => dictionary.location === location);\n\n if (await resolveSplitKeys()) {\n // Split mode: every namespace dictionary writes back into the same\n // per-locale target. Re-assemble them under their top-level key and\n // write each target once, instead of one write per key (which would\n // overwrite).\n const mergedContentByLocale = {} as Record<Locale, SyncContent>;\n const writeKeyByLocale = {} as Record<Locale, string>;\n\n for (const { key, dictionary } of ownedDictionaries) {\n for (const locale of locales) {\n const localizedDictionary = getPerLocaleDictionary(\n dictionary,\n locale\n );\n\n const formattedOutput = formatDictionaryOutput(\n localizedDictionary,\n format\n );\n\n const content = toPlainContent(formattedOutput.content);\n\n if (isEmptyContent(content)) continue;\n\n mergedContentByLocale[locale] ??= {};\n mergedContentByLocale[locale][key] = content;\n writeKeyByLocale[locale] = key;\n }\n }\n\n await parallelize(\n Object.keys(mergedContentByLocale) as Locale[],\n async (locale) => {\n await adapter.write(\n { key: writeKeyByLocale[locale], locale },\n mergedContentByLocale[locale],\n context\n );\n }\n );\n\n return;\n }\n\n const writeTasks = ownedDictionaries.flatMap(({ key, dictionary }) =>\n locales.map((locale) => ({ key, dictionary, locale }))\n );\n\n await parallelize(writeTasks, async ({ key, dictionary, locale }) => {\n const localizedDictionary = getPerLocaleDictionary(dictionary, locale);\n\n const formattedOutput = formatDictionaryOutput(\n localizedDictionary,\n format\n );\n\n const content = toPlainContent(formattedOutput.content);\n\n if (isEmptyContent(content)) return;\n\n await adapter.write({ key, locale }, content as SyncContent, context);\n });\n };\n\n return { name, loadDictionaries, formatOutput, afterBuild };\n};\n"],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ //#region src/syncPluginKit/extractKeyAndLocaleFromPath.ts
4
+ const escapeRegex = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5
+ /**
6
+ * Extract the dictionary key and locale of a file path by matching it against
7
+ * a mask pattern where `{{__KEY__}}` and `{{__LOCALE__}}` mark the positions
8
+ * of the key and locale segments.
9
+ *
10
+ * Returns `null` when the path does not match the mask, or when the mask
11
+ * contains no placeholder at all (no named capture group can be produced).
12
+ * Missing placeholders fall back to `'index'` for the key and to
13
+ * `defaultLocale` for the locale.
14
+ */
15
+ const extractKeyAndLocaleFromPath = (filePath, maskPattern, locales, defaultLocale) => {
16
+ const keyPlaceholder = "{{__KEY__}}";
17
+ const localePlaceholder = "{{__LOCALE__}}";
18
+ const normalize = (path) => path.startsWith("./") ? path.slice(2) : path;
19
+ const normalizedFilePath = normalize(filePath);
20
+ const normalizedMask = normalize(maskPattern);
21
+ const localesAlternation = locales.join("|");
22
+ let regexString = `^${escapeRegex(normalizedMask)}$`;
23
+ regexString = regexString.replace(/\\\*\\\*/g, ".*");
24
+ regexString = regexString.replace(/\\\*/g, "[^/]*");
25
+ regexString = regexString.replace(escapeRegex(localePlaceholder), `(?<locale>${localesAlternation})`);
26
+ if (normalizedMask.includes(keyPlaceholder)) regexString = regexString.replace(escapeRegex(keyPlaceholder), "(?<key>.+)");
27
+ const match = new RegExp(regexString).exec(normalizedFilePath);
28
+ if (!match?.groups) return null;
29
+ return {
30
+ key: match.groups.key ?? "index",
31
+ locale: match.groups.locale ?? defaultLocale
32
+ };
33
+ };
34
+
35
+ //#endregion
36
+ exports.extractKeyAndLocaleFromPath = extractKeyAndLocaleFromPath;
37
+ //# sourceMappingURL=extractKeyAndLocaleFromPath.cjs.map