@intlayer/chokidar 8.7.14 → 8.8.0

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 (30) hide show
  1. package/dist/cjs/cleanRemovedContentDeclaration.cjs +2 -2
  2. package/dist/cjs/cleanRemovedContentDeclaration.cjs.map +1 -1
  3. package/dist/cjs/utils/getPathHash.cjs +4 -1
  4. package/dist/cjs/utils/getPathHash.cjs.map +1 -1
  5. package/dist/cjs/watcher.cjs +11 -0
  6. package/dist/cjs/watcher.cjs.map +1 -1
  7. package/dist/cjs/writeContentDeclaration/transformJSFile.cjs +5 -1
  8. package/dist/cjs/writeContentDeclaration/transformJSFile.cjs.map +1 -1
  9. package/dist/esm/cleanRemovedContentDeclaration.mjs +2 -2
  10. package/dist/esm/cleanRemovedContentDeclaration.mjs.map +1 -1
  11. package/dist/esm/utils/getPathHash.mjs +4 -1
  12. package/dist/esm/utils/getPathHash.mjs.map +1 -1
  13. package/dist/esm/watcher.mjs +11 -1
  14. package/dist/esm/watcher.mjs.map +1 -1
  15. package/dist/esm/writeContentDeclaration/transformJSFile.mjs +5 -1
  16. package/dist/esm/writeContentDeclaration/transformJSFile.mjs.map +1 -1
  17. package/dist/types/createDictionaryEntryPoint/createDictionaryEntryPoint.d.ts +2 -2
  18. package/dist/types/createDictionaryEntryPoint/createDictionaryEntryPoint.d.ts.map +1 -1
  19. package/dist/types/createDictionaryEntryPoint/generateDictionaryListContent.d.ts +2 -2
  20. package/dist/types/createDictionaryEntryPoint/generateDictionaryListContent.d.ts.map +1 -1
  21. package/dist/types/formatDictionary.d.ts +19 -20
  22. package/dist/types/formatDictionary.d.ts.map +1 -1
  23. package/dist/types/loadDictionaries/loadRemoteDictionaries.d.ts +2 -2
  24. package/dist/types/loadDictionaries/loadRemoteDictionaries.d.ts.map +1 -1
  25. package/dist/types/utils/getPathHash.d.ts +3 -0
  26. package/dist/types/utils/getPathHash.d.ts.map +1 -1
  27. package/dist/types/watcher.d.ts.map +1 -1
  28. package/dist/types/writeContentDeclaration/transformJSFile.d.ts.map +1 -1
  29. package/package.json +8 -8
  30. package/dist/types/intlayer/dist/types/index.d.ts +0 -3
@@ -75,7 +75,7 @@ const cleanRemovedContentDeclaration = async (filePath, keysToKeep, configuratio
75
75
  }));
76
76
  if (filesToRemove.length > 0 || excludeKeys.length > 0) {
77
77
  await require_createDictionaryEntryPoint_createDictionaryEntryPoint.createDictionaryEntryPoint(configuration, { excludeKeys });
78
- if (filesToRemove.length > 0) await Promise.all(filesToRemove.map(async (path) => {
78
+ if (filesToRemove.length > 0) setTimeout(async () => await Promise.all(filesToRemove.map(async (path) => {
79
79
  const relativePath = (0, node_path.relative)(baseDir, path);
80
80
  try {
81
81
  await (0, node_fs_promises.rm)(path, { force: true });
@@ -83,7 +83,7 @@ const cleanRemovedContentDeclaration = async (filePath, keysToKeep, configuratio
83
83
  } catch {
84
84
  appLogger(`Error while removing file ${(0, _intlayer_config_logger.colorizePath)(relativePath)}`, { isVerbose: true });
85
85
  }
86
- }));
86
+ })), 3e3);
87
87
  }
88
88
  return {
89
89
  changedDictionariesLocalIds,
@@ -1 +1 @@
1
- {"version":3,"file":"cleanRemovedContentDeclaration.cjs","names":["readDictionariesFromDisk","writeJsonIfChanged","createDictionaryEntryPoint"],"sources":["../../src/cleanRemovedContentDeclaration.ts"],"sourcesContent":["import { readFile, rm } from 'node:fs/promises';\nimport { join, normalize, relative } from 'node:path';\nimport { normalizePath } from '@intlayer/config/client';\nimport {\n colorizeKey,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport fg from 'fast-glob';\nimport { createDictionaryEntryPoint } from './createDictionaryEntryPoint';\nimport { readDictionariesFromDisk } from './utils/readDictionariesFromDisk';\nimport { writeJsonIfChanged } from './writeJsonIfChanged';\n\nexport const cleanRemovedContentDeclaration = async (\n filePath: string,\n keysToKeep: string[],\n configuration: IntlayerConfig\n): Promise<{\n changedDictionariesLocalIds: string[];\n excludeKeys: string[];\n hasRebuilt: boolean;\n}> => {\n const appLogger = getAppLogger(configuration);\n\n const unmergedDictionaries = readDictionariesFromDisk<\n Record<string, Dictionary[]>\n >(configuration.system.unmergedDictionariesDir);\n\n const baseDir = configuration.system.baseDir;\n\n const relativeFilePath = relative(baseDir, filePath);\n const flatUnmergedDictionaries = Object.values(unmergedDictionaries).flat();\n\n const filteredUnmergedDictionaries = flatUnmergedDictionaries.filter(\n (dictionary) =>\n dictionary.filePath === relativeFilePath &&\n !keysToKeep.includes(dictionary.key)\n );\n\n // Deduplicate dictionaries by key\n const uniqueUnmergedDictionaries = filteredUnmergedDictionaries.filter(\n (dictionary, index, self) =>\n index === self.findIndex((t) => t.key === dictionary.key)\n );\n\n const changedDictionariesLocalIds: string[] = [];\n const filesToRemove: string[] = [];\n const excludeKeys: string[] = [];\n\n // Identify Unmerged Dictionaries to remove or clean\n await Promise.all(\n uniqueUnmergedDictionaries.map(async (dictionary) => {\n const unmergedFilePath = normalize(\n join(\n configuration.system.unmergedDictionariesDir,\n `${dictionary.key}.json`\n )\n );\n\n try {\n const jsonContent = await readFile(unmergedFilePath, 'utf8');\n const parsedContent = JSON.parse(jsonContent);\n\n if (parsedContent.length === 1) {\n if (parsedContent[0].filePath === relativeFilePath) {\n appLogger(\n `Removing outdated dictionary ${colorizeKey(dictionary.key)}`,\n { isVerbose: true }\n );\n filesToRemove.push(unmergedFilePath);\n excludeKeys.push(dictionary.key);\n }\n } else {\n const filteredContent = parsedContent.filter(\n (content: any) => content.filePath !== relativeFilePath\n );\n await writeJsonIfChanged(unmergedFilePath, filteredContent);\n changedDictionariesLocalIds.push(dictionary.localId!);\n }\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n if (!excludeKeys.includes(dictionary.key)) {\n excludeKeys.push(dictionary.key);\n }\n }\n }\n })\n );\n\n const dictionaries = readDictionariesFromDisk<Record<string, Dictionary>>(\n configuration.system.dictionariesDir\n );\n const flatDictionaries = Object.values(dictionaries) as Dictionary[];\n\n const filteredMergedDictionaries = flatDictionaries?.filter(\n (dictionary) =>\n !keysToKeep.includes(dictionary.key) &&\n dictionary.localIds?.length === 1 &&\n (dictionary.localIds[0] as string).endsWith(\n `::local::${relativeFilePath}`\n )\n );\n\n const uniqueMergedDictionaries = filteredMergedDictionaries.filter(\n (dictionary, index, self) =>\n index === self.findIndex((t) => t.key === dictionary.key)\n );\n\n // Identify Merged Dictionaries, Types, and Dynamic Dictionaries to remove\n await Promise.all(\n uniqueMergedDictionaries.map(async (dictionary) => {\n const mergedFilePath = normalize(\n join(configuration.system.dictionariesDir, `${dictionary.key}.json`)\n );\n\n try {\n const fileContent = await readFile(mergedFilePath, 'utf8');\n const parsedContent = JSON.parse(fileContent) as Dictionary;\n\n if (parsedContent.localIds?.length === 1) {\n if (\n parsedContent.localIds[0].endsWith(`::local::${relativeFilePath}`)\n ) {\n appLogger(\n `Removing outdated unmerged dictionary ${colorizeKey(dictionary.key)}`,\n { isVerbose: true }\n );\n\n // Mark JSON for removal\n filesToRemove.push(mergedFilePath);\n\n // Mark TS Types for removal\n const typesFilePath = normalize(\n join(configuration.system.typesDir, `${dictionary.key}.ts`)\n );\n filesToRemove.push(typesFilePath);\n\n // Mark Dynamic Dictionaries for removal\n // We use glob to catch the loader files (.cjs, .mjs) AND the split locale files (.en.json, etc.)\n const dynamicFilesGlob = join(\n configuration.system.dynamicDictionariesDir,\n `${dictionary.key}.*`\n );\n const dynamicFiles = await fg(normalizePath(dynamicFilesGlob), {\n absolute: true,\n });\n filesToRemove.push(...dynamicFiles);\n\n if (!excludeKeys.includes(dictionary.key)) {\n excludeKeys.push(dictionary.key);\n }\n }\n } else {\n const localIds = parsedContent.localIds?.filter(\n (localeId) => !localeId.endsWith(`::local::${relativeFilePath}`)\n ) as string[];\n const newContent = { ...parsedContent, localIds };\n await writeJsonIfChanged(mergedFilePath, newContent);\n }\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n if (!excludeKeys.includes(dictionary.key)) {\n excludeKeys.push(dictionary.key);\n }\n const typesFilePath = normalize(\n join(configuration.system.typesDir, `${dictionary.key}.ts`)\n );\n filesToRemove.push(typesFilePath);\n }\n }\n })\n );\n\n // Execute Cleanup\n if (filesToRemove.length > 0 || excludeKeys.length > 0) {\n // Update entry points (indexes) first so the app doesn't import dead files\n await createDictionaryEntryPoint(configuration, { excludeKeys });\n\n // Remove the files synchronously (awaited) immediately after.\n if (filesToRemove.length > 0) {\n await Promise.all(\n filesToRemove.map(async (path) => {\n const relativePath = relative(baseDir, path);\n try {\n await rm(path, { force: true });\n\n appLogger(`Deleted artifact: ${colorizePath(relativePath)}`, {\n isVerbose: true,\n });\n } catch {\n appLogger(\n `Error while removing file ${colorizePath(relativePath)}`,\n {\n isVerbose: true,\n }\n );\n }\n })\n );\n }\n }\n\n return {\n changedDictionariesLocalIds,\n excludeKeys,\n hasRebuilt: filesToRemove.length > 0 || excludeKeys.length > 0,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"cleanRemovedContentDeclaration.cjs","names":["readDictionariesFromDisk","writeJsonIfChanged","createDictionaryEntryPoint"],"sources":["../../src/cleanRemovedContentDeclaration.ts"],"sourcesContent":["import { readFile, rm } from 'node:fs/promises';\nimport { join, normalize, relative } from 'node:path';\nimport { normalizePath } from '@intlayer/config/client';\nimport {\n colorizeKey,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport fg from 'fast-glob';\nimport { createDictionaryEntryPoint } from './createDictionaryEntryPoint';\nimport { readDictionariesFromDisk } from './utils/readDictionariesFromDisk';\nimport { writeJsonIfChanged } from './writeJsonIfChanged';\n\nexport const cleanRemovedContentDeclaration = async (\n filePath: string,\n keysToKeep: string[],\n configuration: IntlayerConfig\n): Promise<{\n changedDictionariesLocalIds: string[];\n excludeKeys: string[];\n hasRebuilt: boolean;\n}> => {\n const appLogger = getAppLogger(configuration);\n\n const unmergedDictionaries = readDictionariesFromDisk<\n Record<string, Dictionary[]>\n >(configuration.system.unmergedDictionariesDir);\n\n const baseDir = configuration.system.baseDir;\n\n const relativeFilePath = relative(baseDir, filePath);\n const flatUnmergedDictionaries = Object.values(unmergedDictionaries).flat();\n\n const filteredUnmergedDictionaries = flatUnmergedDictionaries.filter(\n (dictionary) =>\n dictionary.filePath === relativeFilePath &&\n !keysToKeep.includes(dictionary.key)\n );\n\n // Deduplicate dictionaries by key\n const uniqueUnmergedDictionaries = filteredUnmergedDictionaries.filter(\n (dictionary, index, self) =>\n index === self.findIndex((t) => t.key === dictionary.key)\n );\n\n const changedDictionariesLocalIds: string[] = [];\n const filesToRemove: string[] = [];\n const excludeKeys: string[] = [];\n\n // Identify Unmerged Dictionaries to remove or clean\n await Promise.all(\n uniqueUnmergedDictionaries.map(async (dictionary) => {\n const unmergedFilePath = normalize(\n join(\n configuration.system.unmergedDictionariesDir,\n `${dictionary.key}.json`\n )\n );\n\n try {\n const jsonContent = await readFile(unmergedFilePath, 'utf8');\n const parsedContent = JSON.parse(jsonContent);\n\n if (parsedContent.length === 1) {\n if (parsedContent[0].filePath === relativeFilePath) {\n appLogger(\n `Removing outdated dictionary ${colorizeKey(dictionary.key)}`,\n { isVerbose: true }\n );\n filesToRemove.push(unmergedFilePath);\n excludeKeys.push(dictionary.key);\n }\n } else {\n const filteredContent = parsedContent.filter(\n (content: any) => content.filePath !== relativeFilePath\n );\n await writeJsonIfChanged(unmergedFilePath, filteredContent);\n changedDictionariesLocalIds.push(dictionary.localId!);\n }\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n if (!excludeKeys.includes(dictionary.key)) {\n excludeKeys.push(dictionary.key);\n }\n }\n }\n })\n );\n\n const dictionaries = readDictionariesFromDisk<Record<string, Dictionary>>(\n configuration.system.dictionariesDir\n );\n const flatDictionaries = Object.values(dictionaries) as Dictionary[];\n\n const filteredMergedDictionaries = flatDictionaries?.filter(\n (dictionary) =>\n !keysToKeep.includes(dictionary.key) &&\n dictionary.localIds?.length === 1 &&\n (dictionary.localIds[0] as string).endsWith(\n `::local::${relativeFilePath}`\n )\n );\n\n const uniqueMergedDictionaries = filteredMergedDictionaries.filter(\n (dictionary, index, self) =>\n index === self.findIndex((t) => t.key === dictionary.key)\n );\n\n // Identify Merged Dictionaries, Types, and Dynamic Dictionaries to remove\n await Promise.all(\n uniqueMergedDictionaries.map(async (dictionary) => {\n const mergedFilePath = normalize(\n join(configuration.system.dictionariesDir, `${dictionary.key}.json`)\n );\n\n try {\n const fileContent = await readFile(mergedFilePath, 'utf8');\n const parsedContent = JSON.parse(fileContent) as Dictionary;\n\n if (parsedContent.localIds?.length === 1) {\n if (\n parsedContent.localIds[0].endsWith(`::local::${relativeFilePath}`)\n ) {\n appLogger(\n `Removing outdated unmerged dictionary ${colorizeKey(dictionary.key)}`,\n { isVerbose: true }\n );\n\n // Mark JSON for removal\n filesToRemove.push(mergedFilePath);\n\n // Mark TS Types for removal\n const typesFilePath = normalize(\n join(configuration.system.typesDir, `${dictionary.key}.ts`)\n );\n filesToRemove.push(typesFilePath);\n\n // Mark Dynamic Dictionaries for removal\n // We use glob to catch the loader files (.cjs, .mjs) AND the split locale files (.en.json, etc.)\n const dynamicFilesGlob = join(\n configuration.system.dynamicDictionariesDir,\n `${dictionary.key}.*`\n );\n const dynamicFiles = await fg(normalizePath(dynamicFilesGlob), {\n absolute: true,\n });\n filesToRemove.push(...dynamicFiles);\n\n if (!excludeKeys.includes(dictionary.key)) {\n excludeKeys.push(dictionary.key);\n }\n }\n } else {\n const localIds = parsedContent.localIds?.filter(\n (localeId) => !localeId.endsWith(`::local::${relativeFilePath}`)\n ) as string[];\n const newContent = { ...parsedContent, localIds };\n await writeJsonIfChanged(mergedFilePath, newContent);\n }\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n if (!excludeKeys.includes(dictionary.key)) {\n excludeKeys.push(dictionary.key);\n }\n const typesFilePath = normalize(\n join(configuration.system.typesDir, `${dictionary.key}.ts`)\n );\n filesToRemove.push(typesFilePath);\n }\n }\n })\n );\n\n // Execute Cleanup\n if (filesToRemove.length > 0 || excludeKeys.length > 0) {\n // Update entry points (indexes) first so the app doesn't import dead files\n await createDictionaryEntryPoint(configuration, { excludeKeys });\n\n // Remove the files synchronously (awaited) immediately after.\n if (filesToRemove.length > 0) {\n setTimeout(\n async () =>\n await Promise.all(\n filesToRemove.map(async (path) => {\n const relativePath = relative(baseDir, path);\n try {\n await rm(path, { force: true });\n\n appLogger(`Deleted artifact: ${colorizePath(relativePath)}`, {\n isVerbose: true,\n });\n } catch {\n appLogger(\n `Error while removing file ${colorizePath(relativePath)}`,\n {\n isVerbose: true,\n }\n );\n }\n })\n ),\n 3000\n );\n }\n }\n\n return {\n changedDictionariesLocalIds,\n excludeKeys,\n hasRebuilt: filesToRemove.length > 0 || excludeKeys.length > 0,\n };\n};\n"],"mappings":"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"}
@@ -1,6 +1,9 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  //#region src/utils/getPathHash.ts
4
+ /**
5
+ * Fast hashing using cyrb53 algorithm for small unique strings with low collisions risk
6
+ */
4
7
  const getPathHash = (filePath) => {
5
8
  let h1 = 3735928559;
6
9
  let h2 = 1103547991;
@@ -11,7 +14,7 @@ const getPathHash = (filePath) => {
11
14
  }
12
15
  h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
13
16
  h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
14
- return `_${(4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36)}`;
17
+ return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36);
15
18
  };
16
19
 
17
20
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"getPathHash.cjs","names":[],"sources":["../../../src/utils/getPathHash.ts"],"sourcesContent":["export const getPathHash = (filePath: string) => {\n let h1 = 0xdeadbeef;\n let h2 = 0x41c6ce57;\n\n for (let i = 0; i < filePath.length; i++) {\n const ch = filePath.charCodeAt(i);\n h1 = Math.imul(h1 ^ ch, 2654435761);\n h2 = Math.imul(h2 ^ ch, 1597334677);\n }\n\n h1 =\n Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^\n Math.imul(h2 ^ (h2 >>> 13), 3266489909);\n h2 =\n Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^\n Math.imul(h1 ^ (h1 >>> 13), 3266489909);\n\n const hash53 = 4294967296 * (2097151 & h2) + (h1 >>> 0);\n\n // Returns a string ~11 characters long, e.g., \"_1x9z5k2m8p3\"\n return `_${hash53.toString(36)}`;\n};\n"],"mappings":";;;AAAA,MAAa,eAAe,aAAqB;CAC/C,IAAI,KAAK;CACT,IAAI,KAAK;AAET,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;EACxC,MAAM,KAAK,SAAS,WAAW,EAAE;AACjC,OAAK,KAAK,KAAK,KAAK,IAAI,WAAW;AACnC,OAAK,KAAK,KAAK,KAAK,IAAI,WAAW;;AAGrC,MACE,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW,GACvC,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW;AACzC,MACE,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW,GACvC,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW;AAKzC,QAAO,KAHQ,cAAc,UAAU,OAAO,OAAO,IAGnC,SAAS,GAAG"}
1
+ {"version":3,"file":"getPathHash.cjs","names":[],"sources":["../../../src/utils/getPathHash.ts"],"sourcesContent":["/**\n * Fast hashing using cyrb53 algorithm for small unique strings with low collisions risk\n */\nexport const getPathHash = (filePath: string) => {\n let h1 = 0xdeadbeef;\n let h2 = 0x41c6ce57;\n\n for (let i = 0; i < filePath.length; i++) {\n const ch = filePath.charCodeAt(i);\n h1 = Math.imul(h1 ^ ch, 2654435761);\n h2 = Math.imul(h2 ^ ch, 1597334677);\n }\n\n h1 =\n Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^\n Math.imul(h2 ^ (h2 >>> 13), 3266489909);\n h2 =\n Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^\n Math.imul(h1 ^ (h1 >>> 13), 3266489909);\n\n const hash53 = 4294967296 * (2097151 & h2) + (h1 >>> 0);\n\n // Returns a string ~11 characters long, e.g., \"_1x9z5k2m8p3\"\n return hash53.toString(36);\n};\n"],"mappings":";;;;;;AAGA,MAAa,eAAe,aAAqB;CAC/C,IAAI,KAAK;CACT,IAAI,KAAK;AAET,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;EACxC,MAAM,KAAK,SAAS,WAAW,EAAE;AACjC,OAAK,KAAK,KAAK,KAAK,IAAI,WAAW;AACnC,OAAK,KAAK,KAAK,KAAK,IAAI,WAAW;;AAGrC,MACE,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW,GACvC,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW;AACzC,MACE,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW,GACvC,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW;AAKzC,SAHe,cAAc,UAAU,OAAO,OAAO,IAGvC,SAAS,GAAG"}
@@ -11,6 +11,8 @@ let node_path = require("node:path");
11
11
  let _intlayer_config_logger = require("@intlayer/config/logger");
12
12
  let _intlayer_config_node = require("@intlayer/config/node");
13
13
  let _intlayer_config_utils = require("@intlayer/config/utils");
14
+ let _intlayer_config_colors = require("@intlayer/config/colors");
15
+ _intlayer_config_colors = require_runtime.__toESM(_intlayer_config_colors);
14
16
  let chokidar = require("chokidar");
15
17
 
16
18
  //#region src/watcher.ts
@@ -44,6 +46,15 @@ const watch = (options) => {
44
46
  const pathsToWatch = [...fileExtensions.flatMap((ext) => contentDir.map((dir) => `${(0, _intlayer_config_utils.normalizePath)(dir)}/**/*${ext}`.replace("//", "/"))), ...configurationFilePath ? [configurationFilePath] : []];
45
47
  if (!configuration.content.watch) return;
46
48
  appLogger("Watching Intlayer content declarations");
49
+ if (configuration.build.optimize === true) appLogger([
50
+ "Build optimization is forced to true, but watching is enabled too.",
51
+ "It may lead to dev mode performance degradation as well as import errors.",
52
+ "Its recommended to keep the",
53
+ (0, _intlayer_config_logger.colorize)("`build.optimized`", _intlayer_config_colors.BLUE),
54
+ "option",
55
+ (0, _intlayer_config_logger.colorize)("undefined", _intlayer_config_colors.GREY),
56
+ "to get the best dev mode experience"
57
+ ], { level: "warn" });
47
58
  return (0, chokidar.watch)(pathsToWatch, {
48
59
  persistent: isWatchMode,
49
60
  ignoreInitial: true,
@@ -1 +1 @@
1
- {"version":3,"file":"watcher.cjs","names":["handleContentDeclarationFileMoved","writeContentDeclaration","handleAdditionalContentDeclarationFile","prepareIntlayer","handleContentDeclarationFileChange","handleUnlinkedContentDeclarationFile"],"sources":["../../src/watcher.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { basename } from 'node:path';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n getConfigurationAndFilePath,\n} from '@intlayer/config/node';\nimport {\n clearAllCache,\n clearModuleCache,\n normalizePath,\n} from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\n/** @ts-ignore remove error Module '\"chokidar\"' has no exported member 'ChokidarOptions' */\nimport { type ChokidarOptions, watch as chokidarWatch } from 'chokidar';\nimport { handleAdditionalContentDeclarationFile } from './handleAdditionalContentDeclarationFile';\nimport { handleContentDeclarationFileChange } from './handleContentDeclarationFileChange';\nimport { handleContentDeclarationFileMoved } from './handleContentDeclarationFileMoved';\nimport { handleUnlinkedContentDeclarationFile } from './handleUnlinkedContentDeclarationFile';\nimport { prepareIntlayer } from './prepareIntlayer';\nimport { writeContentDeclaration } from './writeContentDeclaration';\n\n// Map to track files that were recently unlinked: oldPath -> { timer, timestamp }\nconst pendingUnlinks = new Map<\n string,\n { timer: NodeJS.Timeout; oldPath: string }\n>();\n\n// Mutex-based task queue for sequential file event processing\nlet processingLock: Promise<void> | null = null;\nconst processEvent = (task: () => Promise<void>) => {\n const run = async () => {\n // Wait for the previous task to finish\n while (processingLock) {\n await processingLock;\n }\n\n let resolve: () => void;\n processingLock = new Promise<void>((r) => {\n resolve = r;\n });\n\n try {\n await task();\n } catch (error) {\n console.error(error);\n } finally {\n processingLock = null;\n resolve!();\n }\n };\n\n run();\n};\n\ntype WatchOptions = ChokidarOptions & {\n configuration?: IntlayerConfig;\n configOptions?: GetConfigurationOptions;\n skipPrepare?: boolean;\n};\n\n// Initialize chokidar watcher (non-persistent)\nexport const watch = (options?: WatchOptions) => {\n const configResult = getConfigurationAndFilePath(options?.configOptions);\n const configurationFilePath = configResult.configurationFilePath;\n let configuration: IntlayerConfig =\n options?.configuration ?? configResult.configuration;\n const appLogger = getAppLogger(configuration);\n\n const {\n watch: isWatchMode,\n fileExtensions,\n contentDir,\n } = configuration.content;\n\n const watchedFilesPatternWithPath = fileExtensions.flatMap((ext) =>\n contentDir.map((dir) =>\n `${normalizePath(dir)}/**/*${ext}`.replace('//', '/')\n )\n );\n\n const pathsToWatch = [\n ...watchedFilesPatternWithPath,\n ...(configurationFilePath ? [configurationFilePath] : []),\n ];\n\n if (!configuration.content.watch) return;\n\n appLogger('Watching Intlayer content declarations');\n\n return chokidarWatch(pathsToWatch, {\n persistent: isWatchMode, // Make the watcher persistent\n ignoreInitial: true, // Process existing files\n awaitWriteFinish: {\n stabilityThreshold: 1000,\n pollInterval: 100,\n },\n ignored: [\n '**/node_modules/**',\n '**/dist/**',\n '**/build/**',\n '**/.intlayer/**',\n ],\n ...options,\n })\n .on('add', async (filePath) => {\n const fileName = basename(filePath);\n let isMove = false;\n\n // Check if this Add corresponds to a pending Unlink (Move/Rename detection)\n // Heuristic:\n // - Priority A: Exact basename match (Moved to different folder)\n // - Priority B: Single entry in pendingUnlinks (Renamed file)\n let matchedOldPath: string | undefined;\n\n // Search for basename match\n for (const [oldPath] of pendingUnlinks) {\n if (basename(oldPath) === fileName) {\n matchedOldPath = oldPath;\n break;\n }\n }\n\n // If no basename match, but exactly one file was recently unlinked, assume it's a rename\n if (!matchedOldPath && pendingUnlinks.size === 1) {\n matchedOldPath = pendingUnlinks.keys().next().value;\n }\n\n if (matchedOldPath) {\n // It is a move! Cancel the unlink handler\n const pending = pendingUnlinks.get(matchedOldPath);\n if (pending) {\n clearTimeout(pending.timer);\n pendingUnlinks.delete(matchedOldPath);\n }\n\n isMove = true;\n appLogger(`File moved from ${matchedOldPath} to ${filePath}`);\n }\n\n processEvent(async () => {\n if (isMove && matchedOldPath) {\n await handleContentDeclarationFileMoved(\n matchedOldPath,\n filePath,\n configuration\n );\n } else {\n const fileContent = await readFile(filePath, 'utf-8');\n const isEmpty = fileContent === '';\n\n // Fill template content declaration file if it is empty\n if (isEmpty) {\n const extensionPattern = fileExtensions\n .map((ext) => ext.replace(/\\./g, '\\\\.'))\n .join('|');\n const name = fileName.replace(\n new RegExp(`(${extensionPattern})$`),\n ''\n );\n\n await writeContentDeclaration(\n {\n key: name,\n content: {},\n filePath,\n },\n configuration\n );\n }\n\n await handleAdditionalContentDeclarationFile(filePath, configuration);\n }\n });\n })\n .on('change', async (filePath) =>\n processEvent(async () => {\n if (configurationFilePath && filePath === configurationFilePath) {\n appLogger('Configuration file changed, repreparing Intlayer');\n\n clearModuleCache(configurationFilePath);\n clearAllCache();\n\n const { configuration: newConfiguration } =\n getConfigurationAndFilePath(options?.configOptions);\n\n configuration = options?.configuration ?? newConfiguration;\n\n await prepareIntlayer(configuration, { clean: false });\n } else {\n // Clear module cache for the changed file to avoid stale require() results\n clearModuleCache(filePath);\n await handleContentDeclarationFileChange(filePath, configuration);\n }\n })\n )\n .on('unlink', async (filePath) => {\n // Delay unlink processing to see if an 'add' event occurs (indicating a move)\n const timer = setTimeout(async () => {\n // If timer fires, the file was genuinely removed\n pendingUnlinks.delete(filePath);\n processEvent(async () =>\n handleUnlinkedContentDeclarationFile(filePath, configuration)\n );\n }, 200); // 200ms window to catch the 'add' event\n\n pendingUnlinks.set(filePath, { timer, oldPath: filePath });\n })\n .on('error', async (error) => {\n appLogger(`Watcher error: ${error}`, {\n level: 'error',\n });\n\n appLogger('Restarting watcher');\n\n await prepareIntlayer(configuration);\n });\n};\n\nexport const buildAndWatchIntlayer = async (options?: WatchOptions) => {\n const { skipPrepare, ...rest } = options ?? {};\n const configuration =\n options?.configuration ?? getConfiguration(options?.configOptions);\n\n if (!skipPrepare) {\n await prepareIntlayer(configuration, { forceRun: true });\n }\n\n if (configuration.content.watch || options?.persistent) {\n watch({ ...rest, configuration });\n }\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"watcher.cjs","names":["ANSIColor","handleContentDeclarationFileMoved","writeContentDeclaration","handleAdditionalContentDeclarationFile","prepareIntlayer","handleContentDeclarationFileChange","handleUnlinkedContentDeclarationFile"],"sources":["../../src/watcher.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { basename } from 'node:path';\nimport * as ANSIColor from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n getConfigurationAndFilePath,\n} from '@intlayer/config/node';\nimport {\n clearAllCache,\n clearModuleCache,\n normalizePath,\n} from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\n/** @ts-ignore remove error Module '\"chokidar\"' has no exported member 'ChokidarOptions' */\nimport { type ChokidarOptions, watch as chokidarWatch } from 'chokidar';\nimport { handleAdditionalContentDeclarationFile } from './handleAdditionalContentDeclarationFile';\nimport { handleContentDeclarationFileChange } from './handleContentDeclarationFileChange';\nimport { handleContentDeclarationFileMoved } from './handleContentDeclarationFileMoved';\nimport { handleUnlinkedContentDeclarationFile } from './handleUnlinkedContentDeclarationFile';\nimport { prepareIntlayer } from './prepareIntlayer';\nimport { writeContentDeclaration } from './writeContentDeclaration';\n\n// Map to track files that were recently unlinked: oldPath -> { timer, timestamp }\nconst pendingUnlinks = new Map<\n string,\n { timer: NodeJS.Timeout; oldPath: string }\n>();\n\n// Mutex-based task queue for sequential file event processing\nlet processingLock: Promise<void> | null = null;\nconst processEvent = (task: () => Promise<void>) => {\n const run = async () => {\n // Wait for the previous task to finish\n while (processingLock) {\n await processingLock;\n }\n\n let resolve: () => void;\n processingLock = new Promise<void>((r) => {\n resolve = r;\n });\n\n try {\n await task();\n } catch (error) {\n console.error(error);\n } finally {\n processingLock = null;\n resolve!();\n }\n };\n\n run();\n};\n\ntype WatchOptions = ChokidarOptions & {\n configuration?: IntlayerConfig;\n configOptions?: GetConfigurationOptions;\n skipPrepare?: boolean;\n};\n\n// Initialize chokidar watcher (non-persistent)\nexport const watch = (options?: WatchOptions) => {\n const configResult = getConfigurationAndFilePath(options?.configOptions);\n const configurationFilePath = configResult.configurationFilePath;\n let configuration: IntlayerConfig =\n options?.configuration ?? configResult.configuration;\n const appLogger = getAppLogger(configuration);\n\n const {\n watch: isWatchMode,\n fileExtensions,\n contentDir,\n } = configuration.content;\n\n const watchedFilesPatternWithPath = fileExtensions.flatMap((ext) =>\n contentDir.map((dir) =>\n `${normalizePath(dir)}/**/*${ext}`.replace('//', '/')\n )\n );\n\n const pathsToWatch = [\n ...watchedFilesPatternWithPath,\n ...(configurationFilePath ? [configurationFilePath] : []),\n ];\n\n if (!configuration.content.watch) return;\n\n appLogger('Watching Intlayer content declarations');\n\n if (configuration.build.optimize === true) {\n appLogger(\n [\n 'Build optimization is forced to true, but watching is enabled too.',\n 'It may lead to dev mode performance degradation as well as import errors.',\n 'Its recommended to keep the',\n colorize('`build.optimized`', ANSIColor.BLUE),\n 'option',\n colorize('undefined', ANSIColor.GREY),\n 'to get the best dev mode experience',\n ],\n {\n level: 'warn',\n }\n );\n }\n\n return chokidarWatch(pathsToWatch, {\n persistent: isWatchMode, // Make the watcher persistent\n ignoreInitial: true, // Process existing files\n awaitWriteFinish: {\n stabilityThreshold: 1000,\n pollInterval: 100,\n },\n ignored: [\n '**/node_modules/**',\n '**/dist/**',\n '**/build/**',\n '**/.intlayer/**',\n ],\n ...options,\n })\n .on('add', async (filePath) => {\n const fileName = basename(filePath);\n let isMove = false;\n\n // Check if this Add corresponds to a pending Unlink (Move/Rename detection)\n // Heuristic:\n // - Priority A: Exact basename match (Moved to different folder)\n // - Priority B: Single entry in pendingUnlinks (Renamed file)\n let matchedOldPath: string | undefined;\n\n // Search for basename match\n for (const [oldPath] of pendingUnlinks) {\n if (basename(oldPath) === fileName) {\n matchedOldPath = oldPath;\n break;\n }\n }\n\n // If no basename match, but exactly one file was recently unlinked, assume it's a rename\n if (!matchedOldPath && pendingUnlinks.size === 1) {\n matchedOldPath = pendingUnlinks.keys().next().value;\n }\n\n if (matchedOldPath) {\n // It is a move! Cancel the unlink handler\n const pending = pendingUnlinks.get(matchedOldPath);\n if (pending) {\n clearTimeout(pending.timer);\n pendingUnlinks.delete(matchedOldPath);\n }\n\n isMove = true;\n appLogger(`File moved from ${matchedOldPath} to ${filePath}`);\n }\n\n processEvent(async () => {\n if (isMove && matchedOldPath) {\n await handleContentDeclarationFileMoved(\n matchedOldPath,\n filePath,\n configuration\n );\n } else {\n const fileContent = await readFile(filePath, 'utf-8');\n const isEmpty = fileContent === '';\n\n // Fill template content declaration file if it is empty\n if (isEmpty) {\n const extensionPattern = fileExtensions\n .map((ext) => ext.replace(/\\./g, '\\\\.'))\n .join('|');\n const name = fileName.replace(\n new RegExp(`(${extensionPattern})$`),\n ''\n );\n\n await writeContentDeclaration(\n {\n key: name,\n content: {},\n filePath,\n },\n configuration\n );\n }\n\n await handleAdditionalContentDeclarationFile(filePath, configuration);\n }\n });\n })\n .on('change', async (filePath) =>\n processEvent(async () => {\n if (configurationFilePath && filePath === configurationFilePath) {\n appLogger('Configuration file changed, repreparing Intlayer');\n\n clearModuleCache(configurationFilePath);\n clearAllCache();\n\n const { configuration: newConfiguration } =\n getConfigurationAndFilePath(options?.configOptions);\n\n configuration = options?.configuration ?? newConfiguration;\n\n await prepareIntlayer(configuration, { clean: false });\n } else {\n // Clear module cache for the changed file to avoid stale require() results\n clearModuleCache(filePath);\n await handleContentDeclarationFileChange(filePath, configuration);\n }\n })\n )\n .on('unlink', async (filePath) => {\n // Delay unlink processing to see if an 'add' event occurs (indicating a move)\n const timer = setTimeout(async () => {\n // If timer fires, the file was genuinely removed\n pendingUnlinks.delete(filePath);\n processEvent(async () =>\n handleUnlinkedContentDeclarationFile(filePath, configuration)\n );\n }, 200); // 200ms window to catch the 'add' event\n\n pendingUnlinks.set(filePath, { timer, oldPath: filePath });\n })\n .on('error', async (error) => {\n appLogger(`Watcher error: ${error}`, {\n level: 'error',\n });\n\n appLogger('Restarting watcher');\n\n await prepareIntlayer(configuration);\n });\n};\n\nexport const buildAndWatchIntlayer = async (options?: WatchOptions) => {\n const { skipPrepare, ...rest } = options ?? {};\n const configuration =\n options?.configuration ?? getConfiguration(options?.configOptions);\n\n if (!skipPrepare) {\n await prepareIntlayer(configuration, { forceRun: true });\n }\n\n if (configuration.content.watch || options?.persistent) {\n watch({ ...rest, configuration });\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAyBA,MAAM,iCAAiB,IAAI,KAGxB;AAGH,IAAI,iBAAuC;AAC3C,MAAM,gBAAgB,SAA8B;CAClD,MAAM,MAAM,YAAY;AAEtB,SAAO,eACL,OAAM;EAGR,IAAI;AACJ,mBAAiB,IAAI,SAAe,MAAM;AACxC,aAAU;IACV;AAEF,MAAI;AACF,SAAM,MAAM;WACL,OAAO;AACd,WAAQ,MAAM,MAAM;YACZ;AACR,oBAAiB;AACjB,YAAU;;;AAId,MAAK;;AAUP,MAAa,SAAS,YAA2B;CAC/C,MAAM,sEAA2C,SAAS,cAAc;CACxE,MAAM,wBAAwB,aAAa;CAC3C,IAAI,gBACF,SAAS,iBAAiB,aAAa;CACzC,MAAM,sDAAyB,cAAc;CAE7C,MAAM,EACJ,OAAO,aACP,gBACA,eACE,cAAc;CAQlB,MAAM,eAAe,CACnB,GAPkC,eAAe,SAAS,QAC1D,WAAW,KAAK,QACd,6CAAiB,IAAI,CAAC,OAAO,MAAM,QAAQ,MAAM,IAAI,CACtD,CAI6B,EAC9B,GAAI,wBAAwB,CAAC,sBAAsB,GAAG,EAAE,CACzD;AAED,KAAI,CAAC,cAAc,QAAQ,MAAO;AAElC,WAAU,yCAAyC;AAEnD,KAAI,cAAc,MAAM,aAAa,KACnC,WACE;EACE;EACA;EACA;wCACS,qBAAqBA,wBAAU,KAAK;EAC7C;wCACS,aAAaA,wBAAU,KAAK;EACrC;EACD,EACD,EACE,OAAO,QACR,CACF;AAGH,4BAAqB,cAAc;EACjC,YAAY;EACZ,eAAe;EACf,kBAAkB;GAChB,oBAAoB;GACpB,cAAc;GACf;EACD,SAAS;GACP;GACA;GACA;GACA;GACD;EACD,GAAG;EACJ,CAAC,CACC,GAAG,OAAO,OAAO,aAAa;EAC7B,MAAM,mCAAoB,SAAS;EACnC,IAAI,SAAS;EAMb,IAAI;AAGJ,OAAK,MAAM,CAAC,YAAY,eACtB,6BAAa,QAAQ,KAAK,UAAU;AAClC,oBAAiB;AACjB;;AAKJ,MAAI,CAAC,kBAAkB,eAAe,SAAS,EAC7C,kBAAiB,eAAe,MAAM,CAAC,MAAM,CAAC;AAGhD,MAAI,gBAAgB;GAElB,MAAM,UAAU,eAAe,IAAI,eAAe;AAClD,OAAI,SAAS;AACX,iBAAa,QAAQ,MAAM;AAC3B,mBAAe,OAAO,eAAe;;AAGvC,YAAS;AACT,aAAU,mBAAmB,eAAe,MAAM,WAAW;;AAG/D,eAAa,YAAY;AACvB,OAAI,UAAU,eACZ,OAAMC,4EACJ,gBACA,UACA,cACD;QACI;AAKL,QAHgB,qCADmB,UAAU,QAAQ,KACrB,IAGnB;KACX,MAAM,mBAAmB,eACtB,KAAK,QAAQ,IAAI,QAAQ,OAAO,MAAM,CAAC,CACvC,KAAK,IAAI;AAMZ,WAAMC,gFACJ;MACE,KAPS,SAAS,QACpB,IAAI,OAAO,IAAI,iBAAiB,IAAI,EACpC,GAKW;MACT,SAAS,EAAE;MACX;MACD,EACD,cACD;;AAGH,UAAMC,sFAAuC,UAAU,cAAc;;IAEvE;GACF,CACD,GAAG,UAAU,OAAO,aACnB,aAAa,YAAY;AACvB,MAAI,yBAAyB,aAAa,uBAAuB;AAC/D,aAAU,mDAAmD;AAE7D,gDAAiB,sBAAsB;AACvC,8CAAe;GAEf,MAAM,EAAE,eAAe,4EACO,SAAS,cAAc;AAErD,mBAAgB,SAAS,iBAAiB;AAE1C,SAAMC,wCAAgB,eAAe,EAAE,OAAO,OAAO,CAAC;SACjD;AAEL,gDAAiB,SAAS;AAC1B,SAAMC,8EAAmC,UAAU,cAAc;;GAEnE,CACH,CACA,GAAG,UAAU,OAAO,aAAa;EAEhC,MAAM,QAAQ,WAAW,YAAY;AAEnC,kBAAe,OAAO,SAAS;AAC/B,gBAAa,YACXC,kFAAqC,UAAU,cAAc,CAC9D;KACA,IAAI;AAEP,iBAAe,IAAI,UAAU;GAAE;GAAO,SAAS;GAAU,CAAC;GAC1D,CACD,GAAG,SAAS,OAAO,UAAU;AAC5B,YAAU,kBAAkB,SAAS,EACnC,OAAO,SACR,CAAC;AAEF,YAAU,qBAAqB;AAE/B,QAAMF,wCAAgB,cAAc;GACpC;;AAGN,MAAa,wBAAwB,OAAO,YAA2B;CACrE,MAAM,EAAE,aAAa,GAAG,SAAS,WAAW,EAAE;CAC9C,MAAM,gBACJ,SAAS,6DAAkC,SAAS,cAAc;AAEpE,KAAI,CAAC,YACH,OAAMA,wCAAgB,eAAe,EAAE,UAAU,MAAM,CAAC;AAG1D,KAAI,cAAc,QAAQ,SAAS,SAAS,WAC1C,OAAM;EAAE,GAAG;EAAM;EAAe,CAAC"}
@@ -74,7 +74,7 @@ const isMultilingualNode = (val) => {
74
74
  const nodeType = (0, _intlayer_core_dictionaryManipulator.getNodeType)(val);
75
75
  if (nodeType === _intlayer_types_nodeType.TRANSLATION) return true;
76
76
  if (nodeType === _intlayer_types_nodeType.MARKDOWN || nodeType === _intlayer_types_nodeType.HTML || nodeType === _intlayer_types_nodeType.INSERTION) return isMultilingualNode(val[nodeType]);
77
- if (nodeType === _intlayer_types_nodeType.ENUMERATION || nodeType === _intlayer_types_nodeType.CONDITION || nodeType === _intlayer_types_nodeType.GENDER) {
77
+ if (nodeType === _intlayer_types_nodeType.ENUMERATION || nodeType === _intlayer_types_nodeType.PLURAL || nodeType === _intlayer_types_nodeType.CONDITION || nodeType === _intlayer_types_nodeType.GENDER) {
78
78
  const data = val[nodeType];
79
79
  if (data && typeof data === "object") return Object.values(data).some((v) => isMultilingualNode(v));
80
80
  }
@@ -89,6 +89,7 @@ const buildNodeForValue = (val, existingNode, fallbackLocale, requiredImports) =
89
89
  if (!(n.Literal.check(unwrappedExisting) || n.StringLiteral.check(unwrappedExisting) || n.NumericLiteral.check(unwrappedExisting) || n.BooleanLiteral.check(unwrappedExisting) || n.TemplateLiteral.check(unwrappedExisting) || n.ObjectExpression.check(unwrappedExisting) || n.ArrayExpression.check(unwrappedExisting) || n.CallExpression.check(unwrappedExisting) && n.Identifier.check(unwrappedExisting.callee) && [
90
90
  "t",
91
91
  "enu",
92
+ "plural",
92
93
  "cond",
93
94
  "gender",
94
95
  "insert",
@@ -164,6 +165,7 @@ const buildNodeForValue = (val, existingNode, fallbackLocale, requiredImports) =
164
165
  if (nodeType && [
165
166
  _intlayer_types_nodeType.TRANSLATION,
166
167
  _intlayer_types_nodeType.ENUMERATION,
168
+ _intlayer_types_nodeType.PLURAL,
167
169
  _intlayer_types_nodeType.CONDITION,
168
170
  _intlayer_types_nodeType.GENDER,
169
171
  _intlayer_types_nodeType.INSERTION,
@@ -183,6 +185,7 @@ const buildNodeForValue = (val, existingNode, fallbackLocale, requiredImports) =
183
185
  let calleeName = "";
184
186
  if (nodeType === _intlayer_types_nodeType.TRANSLATION) calleeName = "t";
185
187
  else if (nodeType === _intlayer_types_nodeType.ENUMERATION) calleeName = "enu";
188
+ else if (nodeType === _intlayer_types_nodeType.PLURAL) calleeName = "plural";
186
189
  else if (nodeType === _intlayer_types_nodeType.CONDITION) calleeName = "cond";
187
190
  else if (nodeType === _intlayer_types_nodeType.GENDER) calleeName = "gender";
188
191
  else if (nodeType === _intlayer_types_nodeType.INSERTION) calleeName = "insert";
@@ -195,6 +198,7 @@ const buildNodeForValue = (val, existingNode, fallbackLocale, requiredImports) =
195
198
  if ([
196
199
  "t",
197
200
  "enu",
201
+ "plural",
198
202
  "cond",
199
203
  "gender"
200
204
  ].includes(calleeName)) {
@@ -1 +1 @@
1
- {"version":3,"file":"transformJSFile.cjs","names":["NodeTypes","babelTsParser"],"sources":["../../../src/writeContentDeclaration/transformJSFile.ts"],"sourcesContent":["import { getNodeType } from '@intlayer/core/dictionaryManipulator';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport * as recast from 'recast';\nimport * as babelTsParser from 'recast/parsers/babel-ts.js';\n\nconst b = recast.types.builders;\nconst n = recast.types.namedTypes;\n\n/**\n * Unwraps TypeScript/Babel expression wrappers (satisfies, as, !, <Type>).\n * Uses string fallbacks to bypass outdated ast-types definitions.\n */\nconst unwrap = (node: any) => {\n while (\n node &&\n (n.TSSatisfiesExpression?.check(node) ||\n n.TSAsExpression?.check(node) ||\n n.TSTypeAssertion?.check(node) ||\n n.TSNonNullExpression?.check(node) ||\n [\n 'TSSatisfiesExpression',\n 'TSAsExpression',\n 'TSTypeAssertion',\n 'TSNonNullExpression',\n ].includes(node.type))\n ) {\n node = node.expression;\n }\n return node;\n};\n\n/**\n * Robustly finds a property in a recast ObjectExpression.\n * Handles quoted (\"key\") or unquoted (key) properties.\n */\nconst getMatchingProperty = (node: any, key: string) => {\n return node.properties.find((prop: any) => {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n if (n.Identifier.check(prop.key) && prop.key.name === key) return true;\n\n if (n.StringLiteral.check(prop.key) && prop.key.value === key)\n return true;\n\n if (n.Literal.check(prop.key) && prop.key.value === key) return true;\n }\n\n return false;\n });\n};\n\n/**\n * Synchronizes numeric suffixes across locales.\n * E.g. \"Hello 1\" -> \"Hello 3\" updates \"Bonjour 1\" to \"Bonjour 3\".\n */\nconst syncNumericSuffixAcrossLocales = (\n existingNode: any,\n fallbackLocaleCode: string,\n newFallbackValue: string\n) => {\n const trailingNumberMatch = newFallbackValue.match(/\\d+(?!.*\\d)/);\n if (!trailingNumberMatch) return;\n const newTrailingNumber = trailingNumberMatch[0];\n\n if (n.ObjectExpression.check(existingNode)) {\n for (const prop of existingNode.properties) {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n let propName = '';\n\n if (n.Identifier.check(prop.key)) propName = prop.key.name;\n else if (\n n.Literal.check(prop.key) &&\n typeof prop.key.value === 'string'\n )\n propName = prop.key.value;\n else if (n.StringLiteral.check(prop.key)) propName = prop.key.value;\n\n if (propName && propName !== fallbackLocaleCode) {\n if (\n n.Literal.check(prop.value) &&\n typeof prop.value.value === 'string'\n ) {\n const currentValue = prop.value.value;\n const currentTrailingNumberMatch =\n currentValue.match(/\\d+(?!.*\\d)/);\n\n if (currentTrailingNumberMatch) {\n prop.value = b.literal(\n currentValue.replace(/(\\d+)(?!.*\\d)/, newTrailingNumber)\n );\n }\n } else if (n.StringLiteral.check(prop.value)) {\n const currentValue = prop.value.value;\n const currentTrailingNumberMatch =\n currentValue.match(/\\d+(?!.*\\d)/);\n\n if (currentTrailingNumberMatch) {\n prop.value = b.stringLiteral(\n currentValue.replace(/(\\d+)(?!.*\\d)/, newTrailingNumber)\n );\n }\n }\n }\n }\n }\n }\n};\n\n/**\n * Checks if a value represents a multilingual Intlayer node.\n * A node is multilingual if it is a Translation node, or if it is a specialized node\n * (Markdown, HTML, etc.) that contains a Translation node.\n */\nconst isMultilingualNode = (val: any): boolean => {\n if (typeof val !== 'object' || val === null || Array.isArray(val)) {\n return false;\n }\n\n const nodeType = getNodeType(val as ContentNode);\n\n if (nodeType === NodeTypes.TRANSLATION) {\n return true;\n }\n\n if (\n nodeType === NodeTypes.MARKDOWN ||\n nodeType === NodeTypes.HTML ||\n nodeType === NodeTypes.INSERTION\n ) {\n return isMultilingualNode((val as any)[nodeType]);\n }\n\n if (\n nodeType === NodeTypes.ENUMERATION ||\n nodeType === NodeTypes.CONDITION ||\n nodeType === NodeTypes.GENDER\n ) {\n const data = (val as any)[nodeType];\n\n if (data && typeof data === 'object') {\n return Object.values(data).some((v) => isMultilingualNode(v));\n }\n }\n\n return false;\n};\n\n/**\n * Recursively builds or updates an AST node for a given dictionary value.\n */\nconst buildNodeForValue = (\n val: any,\n existingNode: any,\n fallbackLocale: string | undefined, // In per-locale mode, this is the locale of the file\n requiredImports: Set<string>\n): any => {\n const unwrappedExisting = unwrap(existingNode);\n\n // --- CRITICAL GUARD: STRICT AST PRESERVATION ---\n // If the existing node is code (JSX, Variables, standard functions), leave it alone.\n // Only allow updates to literals, plain objects, arrays, and Intlayer helpers.\n if (unwrappedExisting) {\n const isUpdatableNode =\n n.Literal.check(unwrappedExisting) ||\n n.StringLiteral.check(unwrappedExisting) ||\n n.NumericLiteral.check(unwrappedExisting) ||\n n.BooleanLiteral.check(unwrappedExisting) ||\n n.TemplateLiteral.check(unwrappedExisting) ||\n n.ObjectExpression.check(unwrappedExisting) ||\n n.ArrayExpression.check(unwrappedExisting) ||\n (n.CallExpression.check(unwrappedExisting) &&\n n.Identifier.check(unwrappedExisting.callee) &&\n [\n 't',\n 'enu',\n 'cond',\n 'gender',\n 'insert',\n 'md',\n 'html',\n 'file',\n 'nest',\n ].includes(unwrappedExisting.callee.name));\n\n if (!isUpdatableNode) {\n return existingNode;\n }\n }\n\n // If we are in per-locale mode (fallbackLocale is set)\n // and the value is not already a complex translation node,\n // we want to store it as a simple literal, NOT wrapped in t().\n if (fallbackLocale && !existingNode && !isMultilingualNode(val)) {\n if (val === null) return b.literal(null);\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n if (typeof val === 'string' && val.includes('\\n')) {\n return b.templateLiteral(\n [b.templateElement({ raw: val, cooked: val }, true)],\n []\n );\n }\n return b.literal(val);\n }\n }\n\n if (fallbackLocale && existingNode && !isMultilingualNode(val)) {\n if (\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === 't'\n ) {\n const arg = unwrap(existingNode.arguments[0]);\n\n if (n.ObjectExpression.check(arg)) {\n if (typeof val === 'string') {\n syncNumericSuffixAcrossLocales(arg, fallbackLocale, val);\n }\n updateObjectLiteral(\n arg,\n { [fallbackLocale]: val },\n fallbackLocale,\n requiredImports\n );\n\n if (!fallbackLocale) {\n requiredImports.add('t');\n }\n\n return existingNode;\n }\n }\n\n if (\n (!val || typeof val !== 'object') &&\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === 'md'\n ) {\n const innerArg = existingNode.arguments[0];\n\n if (\n n.CallExpression.check(innerArg) &&\n n.Identifier.check(innerArg.callee) &&\n innerArg.callee.name === 't'\n ) {\n const tArg = unwrap(innerArg.arguments[0]);\n\n if (n.ObjectExpression.check(tArg)) {\n if (typeof val === 'string') {\n syncNumericSuffixAcrossLocales(tArg, fallbackLocale, val);\n }\n updateObjectLiteral(\n tArg,\n { [fallbackLocale]: val },\n fallbackLocale,\n requiredImports\n );\n requiredImports.add('md');\n requiredImports.add('t');\n\n return existingNode;\n }\n }\n }\n }\n\n // 1. Primitives\n if (val === null) return b.literal(null);\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n if (unwrappedExisting) {\n // Preserve existing template literals (backticks)\n if (\n n.TemplateLiteral.check(unwrappedExisting) &&\n unwrappedExisting.expressions.length === 0\n ) {\n unwrappedExisting.quasis[0].value.raw = String(val);\n unwrappedExisting.quasis[0].value.cooked = String(val);\n return existingNode;\n }\n // Preserve existing standard literals (keeps quote styling)\n if (\n n.Literal.check(unwrappedExisting) ||\n n.StringLiteral.check(unwrappedExisting)\n ) {\n unwrappedExisting.value = val;\n return existingNode;\n }\n }\n\n // Force multiline strings to use Template Literals\n if (typeof val === 'string' && val.includes('\\n')) {\n return b.templateLiteral(\n [b.templateElement({ raw: val, cooked: val }, true)],\n []\n );\n }\n return b.literal(val);\n }\n\n // 2. Arrays\n if (Array.isArray(val)) {\n if (unwrappedExisting && n.ArrayExpression.check(unwrappedExisting)) {\n const elements = [...unwrappedExisting.elements];\n val.forEach((item, i) => {\n elements[i] = buildNodeForValue(\n item,\n elements[i],\n fallbackLocale,\n requiredImports\n );\n });\n\n if (elements.length > val.length) elements.length = val.length;\n unwrappedExisting.elements = elements as any;\n\n return existingNode;\n } else {\n return b.arrayExpression(\n val.map((item) =>\n buildNodeForValue(item, null, fallbackLocale, requiredImports)\n )\n );\n }\n }\n\n // 3. Intlayer Specialized Nodes\n const nodeType =\n val && typeof val === 'object' && !Array.isArray(val)\n ? getNodeType(val as ContentNode)\n : null;\n\n if (\n nodeType &&\n [\n NodeTypes.TRANSLATION,\n NodeTypes.ENUMERATION,\n NodeTypes.CONDITION,\n NodeTypes.GENDER,\n NodeTypes.INSERTION,\n NodeTypes.MARKDOWN,\n NodeTypes.HTML,\n NodeTypes.FILE,\n NodeTypes.NESTED,\n NodeTypes.ARRAY,\n NodeTypes.OBJECT,\n NodeTypes.REACT_NODE,\n NodeTypes.NUMBER,\n NodeTypes.BOOLEAN,\n NodeTypes.NULL,\n NodeTypes.UNKNOWN,\n ].includes(nodeType as any) &&\n nodeType !== NodeTypes.TEXT\n ) {\n const nodeData = (val as any)[nodeType];\n let calleeName = '';\n\n if (nodeType === NodeTypes.TRANSLATION) calleeName = 't';\n else if (nodeType === NodeTypes.ENUMERATION) calleeName = 'enu';\n else if (nodeType === NodeTypes.CONDITION) calleeName = 'cond';\n else if (nodeType === NodeTypes.GENDER) calleeName = 'gender';\n else if (nodeType === NodeTypes.INSERTION) calleeName = 'insert';\n else if (nodeType === NodeTypes.MARKDOWN) calleeName = 'md';\n else if (nodeType === NodeTypes.HTML) calleeName = 'html';\n else if (nodeType === NodeTypes.FILE) calleeName = 'file';\n else if (nodeType === NodeTypes.NESTED) calleeName = 'nest';\n\n if (calleeName) requiredImports.add(calleeName);\n\n const isMatchingCall =\n existingNode &&\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === calleeName;\n\n if (['t', 'enu', 'cond', 'gender'].includes(calleeName)) {\n let objArg: any = null;\n\n if (\n isMatchingCall &&\n existingNode.arguments.length > 0 &&\n n.ObjectExpression.check(existingNode.arguments[0])\n ) {\n objArg = existingNode.arguments[0];\n } else {\n objArg = b.objectExpression([]);\n }\n updateObjectLiteral(objArg, nodeData, fallbackLocale, requiredImports);\n\n return isMatchingCall\n ? existingNode\n : b.callExpression(b.identifier(calleeName), [objArg]);\n }\n\n if (['md', 'html', 'insert', 'file'].includes(calleeName)) {\n const argNode = buildNodeForValue(\n nodeData,\n isMatchingCall && existingNode.arguments.length > 0\n ? existingNode.arguments[0]\n : null,\n fallbackLocale,\n requiredImports\n );\n\n if (isMatchingCall) {\n existingNode.arguments[0] = argNode;\n\n return existingNode;\n }\n\n return b.callExpression(b.identifier(calleeName), [argNode]);\n }\n\n if (calleeName === 'nest') {\n const args = [b.literal(nodeData.dictionaryKey)];\n\n if (nodeData.path) args.push(b.literal(nodeData.path));\n\n if (isMatchingCall) {\n existingNode.arguments = args;\n\n return existingNode;\n }\n\n return b.callExpression(b.identifier('nest'), args);\n }\n }\n\n // 4. Plain Object\n const objNode =\n unwrappedExisting && n.ObjectExpression.check(unwrappedExisting)\n ? unwrappedExisting\n : b.objectExpression([]);\n\n updateObjectLiteral(objNode, val, fallbackLocale, requiredImports);\n\n return existingNode && unwrappedExisting === existingNode\n ? objNode\n : existingNode || objNode;\n};\n\n/**\n * Recursively updates the AST object literal properties.\n */\nconst updateObjectLiteral = (\n node: recast.types.namedTypes.ObjectExpression,\n data: Record<string, any>,\n fallbackLocale: string | undefined,\n requiredImports: Set<string>\n) => {\n for (const [key, val] of Object.entries(data)) {\n if (val === undefined) continue;\n\n const existingProp = getMatchingProperty(node, key);\n\n if (existingProp) {\n existingProp.value = buildNodeForValue(\n val,\n existingProp.value,\n fallbackLocale,\n requiredImports\n );\n } else {\n const isValidId = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key);\n const keyNode = isValidId ? b.identifier(key) : b.literal(key);\n const valueNode = buildNodeForValue(\n val,\n null,\n fallbackLocale,\n requiredImports\n );\n node.properties.push(b.property('init', keyNode, valueNode));\n }\n }\n};\n\n/**\n * Modifies the AST's top-level imports to inject dynamically needed helper utilities seamlessly.\n */\nconst addImports = (ast: any, requiredImports: Set<string>, isESM: boolean) => {\n if (requiredImports.size === 0) return;\n\n const existingCoreImports = new Set<string>();\n let coreImportPath: any = null;\n\n recast.visit(ast, {\n visitImportDeclaration(path) {\n const source = path.node.source.value;\n\n if (source === 'intlayer') {\n coreImportPath = path;\n path.node.specifiers?.forEach((spec) => {\n if (\n n.ImportSpecifier.check(spec) &&\n typeof spec.imported.name === 'string'\n ) {\n existingCoreImports.add(spec.imported.name);\n }\n });\n }\n\n return false;\n },\n visitVariableDeclaration(path) {\n path.node.declarations.forEach((decl) => {\n if (\n n.VariableDeclarator.check(decl) &&\n n.CallExpression.check(decl.init) &&\n n.Identifier.check(decl.init.callee) &&\n decl.init.callee.name === 'require'\n ) {\n const arg = decl.init.arguments[0];\n\n if (n.Literal.check(arg)) {\n if (arg.value === 'intlayer') {\n if (n.ObjectPattern.check(decl.id)) {\n decl.id.properties.forEach((prop) => {\n if (\n n.Property.check(prop) &&\n (n.Identifier.check(prop.key) ||\n n.Identifier.check(prop.value))\n ) {\n const name = n.Identifier.check(prop.key)\n ? prop.key.name\n : (prop.value as any).name;\n existingCoreImports.add(name);\n }\n });\n } else if (n.Identifier.check(decl.id)) {\n // Handle const intlayer = require('intlayer')\n existingCoreImports.add(decl.id.name);\n }\n }\n }\n }\n });\n\n return false;\n },\n });\n\n const missingCore = Array.from(requiredImports).filter(\n (imp) => !existingCoreImports.has(imp)\n );\n\n if (missingCore.length === 0) return;\n\n if (isESM) {\n if (coreImportPath) {\n missingCore.forEach((imp) => {\n coreImportPath.node.specifiers.push(\n b.importSpecifier(b.identifier(imp))\n );\n });\n coreImportPath.node.specifiers.sort((a: any, b: any) =>\n a.imported.name.localeCompare(b.imported.name)\n );\n } else {\n const specifiers = missingCore\n .sort()\n .map((imp) => b.importSpecifier(b.identifier(imp)));\n const newImport = b.importDeclaration(specifiers, b.literal('intlayer'));\n ast.program.body.unshift(newImport);\n }\n } else {\n let insertIndex = 0;\n\n if (\n ast.program.body.length > 0 &&\n n.ExpressionStatement.check(ast.program.body[0]) &&\n n.Literal.check(ast.program.body[0].expression)\n ) {\n insertIndex = 1; // Insert after 'use strict'\n }\n const cjsLines: any[] = [];\n\n const properties = missingCore.sort().map((imp) => {\n const prop = b.property('init', b.identifier(imp), b.identifier(imp));\n prop.shorthand = true;\n\n return prop;\n });\n cjsLines.push(\n b.variableDeclaration('const', [\n b.variableDeclarator(\n b.objectPattern(properties),\n b.callExpression(b.identifier('require'), [b.literal('intlayer')])\n ),\n ])\n );\n\n ast.program.body.splice(insertIndex, 0, ...cjsLines);\n }\n};\n\n/**\n * Updates a JS/TS file seamlessly to map new localization keys, arrays, complex nodes and nested dictionaries gracefully using AST updates via Recast parser.\n */\nexport const transformJSFile = async (\n fileContent: string,\n dictionary: Dictionary,\n fallbackLocale?: Locale,\n noMetadata?: boolean\n): Promise<string> => {\n if (!dictionary || typeof dictionary !== 'object') return fileContent;\n\n let ast: any;\n try {\n ast = recast.parse(fileContent, {\n parser: babelTsParser,\n });\n } catch (error) {\n console.error({ error });\n return fileContent;\n }\n\n let rootObject: any = null;\n let isESM = false;\n\n recast.visit(ast, {\n visitExportDefaultDeclaration() {\n isESM = true;\n\n return false;\n },\n visitImportDeclaration() {\n isESM = true;\n\n return false;\n },\n });\n\n recast.visit(ast, {\n visitExportDefaultDeclaration(path) {\n const decl = path.node.declaration;\n const unwrappedDecl = unwrap(decl);\n\n if (n.ObjectExpression.check(unwrappedDecl)) {\n rootObject = unwrappedDecl;\n } else if (n.Identifier.check(unwrappedDecl)) {\n const varName = unwrappedDecl.name;\n recast.visit(ast, {\n visitVariableDeclarator(vp) {\n const unwrappedInit = unwrap(vp.node.init);\n\n if (\n n.Identifier.check(vp.node.id) &&\n vp.node.id.name === varName &&\n n.ObjectExpression.check(unwrappedInit)\n ) {\n rootObject = unwrappedInit;\n }\n\n return false;\n },\n });\n }\n\n return false;\n },\n visitAssignmentExpression(path) {\n const left = path.node.left;\n\n if (n.MemberExpression.check(left)) {\n if (\n n.Identifier.check(left.object) &&\n left.object.name === 'module' &&\n n.Identifier.check(left.property) &&\n left.property.name === 'exports'\n ) {\n const unwrappedRight = unwrap(path.node.right);\n\n if (n.ObjectExpression.check(unwrappedRight)) {\n rootObject = unwrappedRight;\n }\n }\n\n if (\n n.Identifier.check(left.object) &&\n left.object.name === 'exports' &&\n n.Identifier.check(left.property) &&\n left.property.name === 'default'\n ) {\n const unwrappedRight = unwrap(path.node.right);\n\n if (n.ObjectExpression.check(unwrappedRight)) {\n rootObject = unwrappedRight;\n }\n }\n }\n this.traverse(path);\n },\n });\n\n if (!rootObject) {\n recast.visit(ast, {\n visitVariableDeclarator(path) {\n const unwrappedInit = unwrap(path.node.init);\n\n if (!rootObject && n.ObjectExpression.check(unwrappedInit)) {\n rootObject = unwrappedInit;\n }\n\n return false;\n },\n });\n }\n\n if (!rootObject) return fileContent;\n\n const requiredImports = new Set<string>();\n const effectiveFallbackLocale = (fallbackLocale as string) ?? 'en';\n\n const metadataProperties = [\n 'id',\n 'locale',\n 'filled',\n 'fill',\n 'title',\n 'description',\n 'tags',\n 'version',\n 'priority',\n 'contentAutoTransformation',\n ];\n\n if (noMetadata) {\n // Remove key, content and metadata properties if they exist\n rootObject.properties = rootObject.properties.filter((prop: any) => {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n let propName = '';\n if (n.Identifier.check(prop.key)) propName = prop.key.name;\n else if (n.StringLiteral.check(prop.key)) propName = prop.key.value;\n else if (n.Literal.check(prop.key)) propName = String(prop.key.value);\n\n return !['key', 'content', ...metadataProperties].includes(propName);\n }\n return true;\n });\n\n // Update satisfies type if exists\n recast.visit(ast, {\n visitNode(path) {\n const node = path.node;\n if (\n (n.TSSatisfiesExpression?.check(node) ||\n node.type === 'TSSatisfiesExpression') &&\n (node as any).typeAnnotation &&\n n.TSTypeReference.check((node as any).typeAnnotation) &&\n n.Identifier.check((node as any).typeAnnotation.typeName) &&\n (node as any).typeAnnotation.typeName.name === 'Dictionary'\n ) {\n (node as any).typeAnnotation = b.tsIndexedAccessType(\n b.tsTypeReference(b.identifier('Dictionary')),\n b.tsLiteralType(b.stringLiteral('content'))\n );\n }\n this.traverse(path);\n },\n });\n } else {\n for (const prop of metadataProperties) {\n if ((dictionary as any)[prop] !== undefined) {\n updateObjectLiteral(\n rootObject,\n { [prop]: (dictionary as any)[prop] },\n undefined,\n requiredImports\n );\n }\n }\n }\n\n if (dictionary.content !== undefined) {\n updateObjectLiteral(\n rootObject,\n noMetadata\n ? (dictionary.content as Record<string, any>)\n : { content: dictionary.content },\n effectiveFallbackLocale,\n requiredImports\n );\n }\n\n addImports(ast, requiredImports, isESM);\n\n return recast.print(ast).code;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"transformJSFile.cjs","names":["NodeTypes","babelTsParser"],"sources":["../../../src/writeContentDeclaration/transformJSFile.ts"],"sourcesContent":["import { getNodeType } from '@intlayer/core/dictionaryManipulator';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport * as recast from 'recast';\nimport * as babelTsParser from 'recast/parsers/babel-ts.js';\n\nconst b = recast.types.builders;\nconst n = recast.types.namedTypes;\n\n/**\n * Unwraps TypeScript/Babel expression wrappers (satisfies, as, !, <Type>).\n * Uses string fallbacks to bypass outdated ast-types definitions.\n */\nconst unwrap = (node: any) => {\n while (\n node &&\n (n.TSSatisfiesExpression?.check(node) ||\n n.TSAsExpression?.check(node) ||\n n.TSTypeAssertion?.check(node) ||\n n.TSNonNullExpression?.check(node) ||\n [\n 'TSSatisfiesExpression',\n 'TSAsExpression',\n 'TSTypeAssertion',\n 'TSNonNullExpression',\n ].includes(node.type))\n ) {\n node = node.expression;\n }\n return node;\n};\n\n/**\n * Robustly finds a property in a recast ObjectExpression.\n * Handles quoted (\"key\") or unquoted (key) properties.\n */\nconst getMatchingProperty = (node: any, key: string) => {\n return node.properties.find((prop: any) => {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n if (n.Identifier.check(prop.key) && prop.key.name === key) return true;\n\n if (n.StringLiteral.check(prop.key) && prop.key.value === key)\n return true;\n\n if (n.Literal.check(prop.key) && prop.key.value === key) return true;\n }\n\n return false;\n });\n};\n\n/**\n * Synchronizes numeric suffixes across locales.\n * E.g. \"Hello 1\" -> \"Hello 3\" updates \"Bonjour 1\" to \"Bonjour 3\".\n */\nconst syncNumericSuffixAcrossLocales = (\n existingNode: any,\n fallbackLocaleCode: string,\n newFallbackValue: string\n) => {\n const trailingNumberMatch = newFallbackValue.match(/\\d+(?!.*\\d)/);\n if (!trailingNumberMatch) return;\n const newTrailingNumber = trailingNumberMatch[0];\n\n if (n.ObjectExpression.check(existingNode)) {\n for (const prop of existingNode.properties) {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n let propName = '';\n\n if (n.Identifier.check(prop.key)) propName = prop.key.name;\n else if (\n n.Literal.check(prop.key) &&\n typeof prop.key.value === 'string'\n )\n propName = prop.key.value;\n else if (n.StringLiteral.check(prop.key)) propName = prop.key.value;\n\n if (propName && propName !== fallbackLocaleCode) {\n if (\n n.Literal.check(prop.value) &&\n typeof prop.value.value === 'string'\n ) {\n const currentValue = prop.value.value;\n const currentTrailingNumberMatch =\n currentValue.match(/\\d+(?!.*\\d)/);\n\n if (currentTrailingNumberMatch) {\n prop.value = b.literal(\n currentValue.replace(/(\\d+)(?!.*\\d)/, newTrailingNumber)\n );\n }\n } else if (n.StringLiteral.check(prop.value)) {\n const currentValue = prop.value.value;\n const currentTrailingNumberMatch =\n currentValue.match(/\\d+(?!.*\\d)/);\n\n if (currentTrailingNumberMatch) {\n prop.value = b.stringLiteral(\n currentValue.replace(/(\\d+)(?!.*\\d)/, newTrailingNumber)\n );\n }\n }\n }\n }\n }\n }\n};\n\n/**\n * Checks if a value represents a multilingual Intlayer node.\n * A node is multilingual if it is a Translation node, or if it is a specialized node\n * (Markdown, HTML, etc.) that contains a Translation node.\n */\nconst isMultilingualNode = (val: any): boolean => {\n if (typeof val !== 'object' || val === null || Array.isArray(val)) {\n return false;\n }\n\n const nodeType = getNodeType(val as ContentNode);\n\n if (nodeType === NodeTypes.TRANSLATION) {\n return true;\n }\n\n if (\n nodeType === NodeTypes.MARKDOWN ||\n nodeType === NodeTypes.HTML ||\n nodeType === NodeTypes.INSERTION\n ) {\n return isMultilingualNode((val as any)[nodeType]);\n }\n\n if (\n nodeType === NodeTypes.ENUMERATION ||\n nodeType === NodeTypes.PLURAL ||\n nodeType === NodeTypes.CONDITION ||\n nodeType === NodeTypes.GENDER\n ) {\n const data = (val as any)[nodeType];\n\n if (data && typeof data === 'object') {\n return Object.values(data).some((v) => isMultilingualNode(v));\n }\n }\n\n return false;\n};\n\n/**\n * Recursively builds or updates an AST node for a given dictionary value.\n */\nconst buildNodeForValue = (\n val: any,\n existingNode: any,\n fallbackLocale: string | undefined, // In per-locale mode, this is the locale of the file\n requiredImports: Set<string>\n): any => {\n const unwrappedExisting = unwrap(existingNode);\n\n // --- CRITICAL GUARD: STRICT AST PRESERVATION ---\n // If the existing node is code (JSX, Variables, standard functions), leave it alone.\n // Only allow updates to literals, plain objects, arrays, and Intlayer helpers.\n if (unwrappedExisting) {\n const isUpdatableNode =\n n.Literal.check(unwrappedExisting) ||\n n.StringLiteral.check(unwrappedExisting) ||\n n.NumericLiteral.check(unwrappedExisting) ||\n n.BooleanLiteral.check(unwrappedExisting) ||\n n.TemplateLiteral.check(unwrappedExisting) ||\n n.ObjectExpression.check(unwrappedExisting) ||\n n.ArrayExpression.check(unwrappedExisting) ||\n (n.CallExpression.check(unwrappedExisting) &&\n n.Identifier.check(unwrappedExisting.callee) &&\n [\n 't',\n 'enu',\n 'plural',\n 'cond',\n 'gender',\n 'insert',\n 'md',\n 'html',\n 'file',\n 'nest',\n ].includes(unwrappedExisting.callee.name));\n\n if (!isUpdatableNode) {\n return existingNode;\n }\n }\n\n // If we are in per-locale mode (fallbackLocale is set)\n // and the value is not already a complex translation node,\n // we want to store it as a simple literal, NOT wrapped in t().\n if (fallbackLocale && !existingNode && !isMultilingualNode(val)) {\n if (val === null) return b.literal(null);\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n if (typeof val === 'string' && val.includes('\\n')) {\n return b.templateLiteral(\n [b.templateElement({ raw: val, cooked: val }, true)],\n []\n );\n }\n return b.literal(val);\n }\n }\n\n if (fallbackLocale && existingNode && !isMultilingualNode(val)) {\n if (\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === 't'\n ) {\n const arg = unwrap(existingNode.arguments[0]);\n\n if (n.ObjectExpression.check(arg)) {\n if (typeof val === 'string') {\n syncNumericSuffixAcrossLocales(arg, fallbackLocale, val);\n }\n updateObjectLiteral(\n arg,\n { [fallbackLocale]: val },\n fallbackLocale,\n requiredImports\n );\n\n if (!fallbackLocale) {\n requiredImports.add('t');\n }\n\n return existingNode;\n }\n }\n\n if (\n (!val || typeof val !== 'object') &&\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === 'md'\n ) {\n const innerArg = existingNode.arguments[0];\n\n if (\n n.CallExpression.check(innerArg) &&\n n.Identifier.check(innerArg.callee) &&\n innerArg.callee.name === 't'\n ) {\n const tArg = unwrap(innerArg.arguments[0]);\n\n if (n.ObjectExpression.check(tArg)) {\n if (typeof val === 'string') {\n syncNumericSuffixAcrossLocales(tArg, fallbackLocale, val);\n }\n updateObjectLiteral(\n tArg,\n { [fallbackLocale]: val },\n fallbackLocale,\n requiredImports\n );\n requiredImports.add('md');\n requiredImports.add('t');\n\n return existingNode;\n }\n }\n }\n }\n\n // 1. Primitives\n if (val === null) return b.literal(null);\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n if (unwrappedExisting) {\n // Preserve existing template literals (backticks)\n if (\n n.TemplateLiteral.check(unwrappedExisting) &&\n unwrappedExisting.expressions.length === 0\n ) {\n unwrappedExisting.quasis[0].value.raw = String(val);\n unwrappedExisting.quasis[0].value.cooked = String(val);\n return existingNode;\n }\n // Preserve existing standard literals (keeps quote styling)\n if (\n n.Literal.check(unwrappedExisting) ||\n n.StringLiteral.check(unwrappedExisting)\n ) {\n unwrappedExisting.value = val;\n return existingNode;\n }\n }\n\n // Force multiline strings to use Template Literals\n if (typeof val === 'string' && val.includes('\\n')) {\n return b.templateLiteral(\n [b.templateElement({ raw: val, cooked: val }, true)],\n []\n );\n }\n return b.literal(val);\n }\n\n // 2. Arrays\n if (Array.isArray(val)) {\n if (unwrappedExisting && n.ArrayExpression.check(unwrappedExisting)) {\n const elements = [...unwrappedExisting.elements];\n val.forEach((item, i) => {\n elements[i] = buildNodeForValue(\n item,\n elements[i],\n fallbackLocale,\n requiredImports\n );\n });\n\n if (elements.length > val.length) elements.length = val.length;\n unwrappedExisting.elements = elements as any;\n\n return existingNode;\n } else {\n return b.arrayExpression(\n val.map((item) =>\n buildNodeForValue(item, null, fallbackLocale, requiredImports)\n )\n );\n }\n }\n\n // 3. Intlayer Specialized Nodes\n const nodeType =\n val && typeof val === 'object' && !Array.isArray(val)\n ? getNodeType(val as ContentNode)\n : null;\n\n if (\n nodeType &&\n [\n NodeTypes.TRANSLATION,\n NodeTypes.ENUMERATION,\n NodeTypes.PLURAL,\n NodeTypes.CONDITION,\n NodeTypes.GENDER,\n NodeTypes.INSERTION,\n NodeTypes.MARKDOWN,\n NodeTypes.HTML,\n NodeTypes.FILE,\n NodeTypes.NESTED,\n NodeTypes.ARRAY,\n NodeTypes.OBJECT,\n NodeTypes.REACT_NODE,\n NodeTypes.NUMBER,\n NodeTypes.BOOLEAN,\n NodeTypes.NULL,\n NodeTypes.UNKNOWN,\n ].includes(nodeType as any) &&\n nodeType !== NodeTypes.TEXT\n ) {\n const nodeData = (val as any)[nodeType];\n let calleeName = '';\n\n if (nodeType === NodeTypes.TRANSLATION) calleeName = 't';\n else if (nodeType === NodeTypes.ENUMERATION) calleeName = 'enu';\n else if (nodeType === NodeTypes.PLURAL) calleeName = 'plural';\n else if (nodeType === NodeTypes.CONDITION) calleeName = 'cond';\n else if (nodeType === NodeTypes.GENDER) calleeName = 'gender';\n else if (nodeType === NodeTypes.INSERTION) calleeName = 'insert';\n else if (nodeType === NodeTypes.MARKDOWN) calleeName = 'md';\n else if (nodeType === NodeTypes.HTML) calleeName = 'html';\n else if (nodeType === NodeTypes.FILE) calleeName = 'file';\n else if (nodeType === NodeTypes.NESTED) calleeName = 'nest';\n\n if (calleeName) requiredImports.add(calleeName);\n\n const isMatchingCall =\n existingNode &&\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === calleeName;\n\n if (['t', 'enu', 'plural', 'cond', 'gender'].includes(calleeName)) {\n let objArg: any = null;\n\n if (\n isMatchingCall &&\n existingNode.arguments.length > 0 &&\n n.ObjectExpression.check(existingNode.arguments[0])\n ) {\n objArg = existingNode.arguments[0];\n } else {\n objArg = b.objectExpression([]);\n }\n updateObjectLiteral(objArg, nodeData, fallbackLocale, requiredImports);\n\n return isMatchingCall\n ? existingNode\n : b.callExpression(b.identifier(calleeName), [objArg]);\n }\n\n if (['md', 'html', 'insert', 'file'].includes(calleeName)) {\n const argNode = buildNodeForValue(\n nodeData,\n isMatchingCall && existingNode.arguments.length > 0\n ? existingNode.arguments[0]\n : null,\n fallbackLocale,\n requiredImports\n );\n\n if (isMatchingCall) {\n existingNode.arguments[0] = argNode;\n\n return existingNode;\n }\n\n return b.callExpression(b.identifier(calleeName), [argNode]);\n }\n\n if (calleeName === 'nest') {\n const args = [b.literal(nodeData.dictionaryKey)];\n\n if (nodeData.path) args.push(b.literal(nodeData.path));\n\n if (isMatchingCall) {\n existingNode.arguments = args;\n\n return existingNode;\n }\n\n return b.callExpression(b.identifier('nest'), args);\n }\n }\n\n // 4. Plain Object\n const objNode =\n unwrappedExisting && n.ObjectExpression.check(unwrappedExisting)\n ? unwrappedExisting\n : b.objectExpression([]);\n\n updateObjectLiteral(objNode, val, fallbackLocale, requiredImports);\n\n return existingNode && unwrappedExisting === existingNode\n ? objNode\n : existingNode || objNode;\n};\n\n/**\n * Recursively updates the AST object literal properties.\n */\nconst updateObjectLiteral = (\n node: recast.types.namedTypes.ObjectExpression,\n data: Record<string, any>,\n fallbackLocale: string | undefined,\n requiredImports: Set<string>\n) => {\n for (const [key, val] of Object.entries(data)) {\n if (val === undefined) continue;\n\n const existingProp = getMatchingProperty(node, key);\n\n if (existingProp) {\n existingProp.value = buildNodeForValue(\n val,\n existingProp.value,\n fallbackLocale,\n requiredImports\n );\n } else {\n const isValidId = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key);\n const keyNode = isValidId ? b.identifier(key) : b.literal(key);\n const valueNode = buildNodeForValue(\n val,\n null,\n fallbackLocale,\n requiredImports\n );\n node.properties.push(b.property('init', keyNode, valueNode));\n }\n }\n};\n\n/**\n * Modifies the AST's top-level imports to inject dynamically needed helper utilities seamlessly.\n */\nconst addImports = (ast: any, requiredImports: Set<string>, isESM: boolean) => {\n if (requiredImports.size === 0) return;\n\n const existingCoreImports = new Set<string>();\n let coreImportPath: any = null;\n\n recast.visit(ast, {\n visitImportDeclaration(path) {\n const source = path.node.source.value;\n\n if (source === 'intlayer') {\n coreImportPath = path;\n path.node.specifiers?.forEach((spec) => {\n if (\n n.ImportSpecifier.check(spec) &&\n typeof spec.imported.name === 'string'\n ) {\n existingCoreImports.add(spec.imported.name);\n }\n });\n }\n\n return false;\n },\n visitVariableDeclaration(path) {\n path.node.declarations.forEach((decl) => {\n if (\n n.VariableDeclarator.check(decl) &&\n n.CallExpression.check(decl.init) &&\n n.Identifier.check(decl.init.callee) &&\n decl.init.callee.name === 'require'\n ) {\n const arg = decl.init.arguments[0];\n\n if (n.Literal.check(arg)) {\n if (arg.value === 'intlayer') {\n if (n.ObjectPattern.check(decl.id)) {\n decl.id.properties.forEach((prop) => {\n if (\n n.Property.check(prop) &&\n (n.Identifier.check(prop.key) ||\n n.Identifier.check(prop.value))\n ) {\n const name = n.Identifier.check(prop.key)\n ? prop.key.name\n : (prop.value as any).name;\n existingCoreImports.add(name);\n }\n });\n } else if (n.Identifier.check(decl.id)) {\n // Handle const intlayer = require('intlayer')\n existingCoreImports.add(decl.id.name);\n }\n }\n }\n }\n });\n\n return false;\n },\n });\n\n const missingCore = Array.from(requiredImports).filter(\n (imp) => !existingCoreImports.has(imp)\n );\n\n if (missingCore.length === 0) return;\n\n if (isESM) {\n if (coreImportPath) {\n missingCore.forEach((imp) => {\n coreImportPath.node.specifiers.push(\n b.importSpecifier(b.identifier(imp))\n );\n });\n coreImportPath.node.specifiers.sort((a: any, b: any) =>\n a.imported.name.localeCompare(b.imported.name)\n );\n } else {\n const specifiers = missingCore\n .sort()\n .map((imp) => b.importSpecifier(b.identifier(imp)));\n const newImport = b.importDeclaration(specifiers, b.literal('intlayer'));\n ast.program.body.unshift(newImport);\n }\n } else {\n let insertIndex = 0;\n\n if (\n ast.program.body.length > 0 &&\n n.ExpressionStatement.check(ast.program.body[0]) &&\n n.Literal.check(ast.program.body[0].expression)\n ) {\n insertIndex = 1; // Insert after 'use strict'\n }\n const cjsLines: any[] = [];\n\n const properties = missingCore.sort().map((imp) => {\n const prop = b.property('init', b.identifier(imp), b.identifier(imp));\n prop.shorthand = true;\n\n return prop;\n });\n cjsLines.push(\n b.variableDeclaration('const', [\n b.variableDeclarator(\n b.objectPattern(properties),\n b.callExpression(b.identifier('require'), [b.literal('intlayer')])\n ),\n ])\n );\n\n ast.program.body.splice(insertIndex, 0, ...cjsLines);\n }\n};\n\n/**\n * Updates a JS/TS file seamlessly to map new localization keys, arrays, complex nodes and nested dictionaries gracefully using AST updates via Recast parser.\n */\nexport const transformJSFile = async (\n fileContent: string,\n dictionary: Dictionary,\n fallbackLocale?: Locale,\n noMetadata?: boolean\n): Promise<string> => {\n if (!dictionary || typeof dictionary !== 'object') return fileContent;\n\n let ast: any;\n try {\n ast = recast.parse(fileContent, {\n parser: babelTsParser,\n });\n } catch (error) {\n console.error({ error });\n return fileContent;\n }\n\n let rootObject: any = null;\n let isESM = false;\n\n recast.visit(ast, {\n visitExportDefaultDeclaration() {\n isESM = true;\n\n return false;\n },\n visitImportDeclaration() {\n isESM = true;\n\n return false;\n },\n });\n\n recast.visit(ast, {\n visitExportDefaultDeclaration(path) {\n const decl = path.node.declaration;\n const unwrappedDecl = unwrap(decl);\n\n if (n.ObjectExpression.check(unwrappedDecl)) {\n rootObject = unwrappedDecl;\n } else if (n.Identifier.check(unwrappedDecl)) {\n const varName = unwrappedDecl.name;\n recast.visit(ast, {\n visitVariableDeclarator(vp) {\n const unwrappedInit = unwrap(vp.node.init);\n\n if (\n n.Identifier.check(vp.node.id) &&\n vp.node.id.name === varName &&\n n.ObjectExpression.check(unwrappedInit)\n ) {\n rootObject = unwrappedInit;\n }\n\n return false;\n },\n });\n }\n\n return false;\n },\n visitAssignmentExpression(path) {\n const left = path.node.left;\n\n if (n.MemberExpression.check(left)) {\n if (\n n.Identifier.check(left.object) &&\n left.object.name === 'module' &&\n n.Identifier.check(left.property) &&\n left.property.name === 'exports'\n ) {\n const unwrappedRight = unwrap(path.node.right);\n\n if (n.ObjectExpression.check(unwrappedRight)) {\n rootObject = unwrappedRight;\n }\n }\n\n if (\n n.Identifier.check(left.object) &&\n left.object.name === 'exports' &&\n n.Identifier.check(left.property) &&\n left.property.name === 'default'\n ) {\n const unwrappedRight = unwrap(path.node.right);\n\n if (n.ObjectExpression.check(unwrappedRight)) {\n rootObject = unwrappedRight;\n }\n }\n }\n this.traverse(path);\n },\n });\n\n if (!rootObject) {\n recast.visit(ast, {\n visitVariableDeclarator(path) {\n const unwrappedInit = unwrap(path.node.init);\n\n if (!rootObject && n.ObjectExpression.check(unwrappedInit)) {\n rootObject = unwrappedInit;\n }\n\n return false;\n },\n });\n }\n\n if (!rootObject) return fileContent;\n\n const requiredImports = new Set<string>();\n const effectiveFallbackLocale = (fallbackLocale as string) ?? 'en';\n\n const metadataProperties = [\n 'id',\n 'locale',\n 'filled',\n 'fill',\n 'title',\n 'description',\n 'tags',\n 'version',\n 'priority',\n 'contentAutoTransformation',\n ];\n\n if (noMetadata) {\n // Remove key, content and metadata properties if they exist\n rootObject.properties = rootObject.properties.filter((prop: any) => {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n let propName = '';\n if (n.Identifier.check(prop.key)) propName = prop.key.name;\n else if (n.StringLiteral.check(prop.key)) propName = prop.key.value;\n else if (n.Literal.check(prop.key)) propName = String(prop.key.value);\n\n return !['key', 'content', ...metadataProperties].includes(propName);\n }\n return true;\n });\n\n // Update satisfies type if exists\n recast.visit(ast, {\n visitNode(path) {\n const node = path.node;\n if (\n (n.TSSatisfiesExpression?.check(node) ||\n node.type === 'TSSatisfiesExpression') &&\n (node as any).typeAnnotation &&\n n.TSTypeReference.check((node as any).typeAnnotation) &&\n n.Identifier.check((node as any).typeAnnotation.typeName) &&\n (node as any).typeAnnotation.typeName.name === 'Dictionary'\n ) {\n (node as any).typeAnnotation = b.tsIndexedAccessType(\n b.tsTypeReference(b.identifier('Dictionary')),\n b.tsLiteralType(b.stringLiteral('content'))\n );\n }\n this.traverse(path);\n },\n });\n } else {\n for (const prop of metadataProperties) {\n if ((dictionary as any)[prop] !== undefined) {\n updateObjectLiteral(\n rootObject,\n { [prop]: (dictionary as any)[prop] },\n undefined,\n requiredImports\n );\n }\n }\n }\n\n if (dictionary.content !== undefined) {\n updateObjectLiteral(\n rootObject,\n noMetadata\n ? (dictionary.content as Record<string, any>)\n : { content: dictionary.content },\n effectiveFallbackLocale,\n requiredImports\n );\n }\n\n addImports(ast, requiredImports, isESM);\n\n return recast.print(ast).code;\n};\n"],"mappings":"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"}
@@ -72,7 +72,7 @@ const cleanRemovedContentDeclaration = async (filePath, keysToKeep, configuratio
72
72
  }));
73
73
  if (filesToRemove.length > 0 || excludeKeys.length > 0) {
74
74
  await createDictionaryEntryPoint(configuration, { excludeKeys });
75
- if (filesToRemove.length > 0) await Promise.all(filesToRemove.map(async (path) => {
75
+ if (filesToRemove.length > 0) setTimeout(async () => await Promise.all(filesToRemove.map(async (path) => {
76
76
  const relativePath = relative(baseDir, path);
77
77
  try {
78
78
  await rm(path, { force: true });
@@ -80,7 +80,7 @@ const cleanRemovedContentDeclaration = async (filePath, keysToKeep, configuratio
80
80
  } catch {
81
81
  appLogger(`Error while removing file ${colorizePath(relativePath)}`, { isVerbose: true });
82
82
  }
83
- }));
83
+ })), 3e3);
84
84
  }
85
85
  return {
86
86
  changedDictionariesLocalIds,
@@ -1 +1 @@
1
- {"version":3,"file":"cleanRemovedContentDeclaration.mjs","names":[],"sources":["../../src/cleanRemovedContentDeclaration.ts"],"sourcesContent":["import { readFile, rm } from 'node:fs/promises';\nimport { join, normalize, relative } from 'node:path';\nimport { normalizePath } from '@intlayer/config/client';\nimport {\n colorizeKey,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport fg from 'fast-glob';\nimport { createDictionaryEntryPoint } from './createDictionaryEntryPoint';\nimport { readDictionariesFromDisk } from './utils/readDictionariesFromDisk';\nimport { writeJsonIfChanged } from './writeJsonIfChanged';\n\nexport const cleanRemovedContentDeclaration = async (\n filePath: string,\n keysToKeep: string[],\n configuration: IntlayerConfig\n): Promise<{\n changedDictionariesLocalIds: string[];\n excludeKeys: string[];\n hasRebuilt: boolean;\n}> => {\n const appLogger = getAppLogger(configuration);\n\n const unmergedDictionaries = readDictionariesFromDisk<\n Record<string, Dictionary[]>\n >(configuration.system.unmergedDictionariesDir);\n\n const baseDir = configuration.system.baseDir;\n\n const relativeFilePath = relative(baseDir, filePath);\n const flatUnmergedDictionaries = Object.values(unmergedDictionaries).flat();\n\n const filteredUnmergedDictionaries = flatUnmergedDictionaries.filter(\n (dictionary) =>\n dictionary.filePath === relativeFilePath &&\n !keysToKeep.includes(dictionary.key)\n );\n\n // Deduplicate dictionaries by key\n const uniqueUnmergedDictionaries = filteredUnmergedDictionaries.filter(\n (dictionary, index, self) =>\n index === self.findIndex((t) => t.key === dictionary.key)\n );\n\n const changedDictionariesLocalIds: string[] = [];\n const filesToRemove: string[] = [];\n const excludeKeys: string[] = [];\n\n // Identify Unmerged Dictionaries to remove or clean\n await Promise.all(\n uniqueUnmergedDictionaries.map(async (dictionary) => {\n const unmergedFilePath = normalize(\n join(\n configuration.system.unmergedDictionariesDir,\n `${dictionary.key}.json`\n )\n );\n\n try {\n const jsonContent = await readFile(unmergedFilePath, 'utf8');\n const parsedContent = JSON.parse(jsonContent);\n\n if (parsedContent.length === 1) {\n if (parsedContent[0].filePath === relativeFilePath) {\n appLogger(\n `Removing outdated dictionary ${colorizeKey(dictionary.key)}`,\n { isVerbose: true }\n );\n filesToRemove.push(unmergedFilePath);\n excludeKeys.push(dictionary.key);\n }\n } else {\n const filteredContent = parsedContent.filter(\n (content: any) => content.filePath !== relativeFilePath\n );\n await writeJsonIfChanged(unmergedFilePath, filteredContent);\n changedDictionariesLocalIds.push(dictionary.localId!);\n }\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n if (!excludeKeys.includes(dictionary.key)) {\n excludeKeys.push(dictionary.key);\n }\n }\n }\n })\n );\n\n const dictionaries = readDictionariesFromDisk<Record<string, Dictionary>>(\n configuration.system.dictionariesDir\n );\n const flatDictionaries = Object.values(dictionaries) as Dictionary[];\n\n const filteredMergedDictionaries = flatDictionaries?.filter(\n (dictionary) =>\n !keysToKeep.includes(dictionary.key) &&\n dictionary.localIds?.length === 1 &&\n (dictionary.localIds[0] as string).endsWith(\n `::local::${relativeFilePath}`\n )\n );\n\n const uniqueMergedDictionaries = filteredMergedDictionaries.filter(\n (dictionary, index, self) =>\n index === self.findIndex((t) => t.key === dictionary.key)\n );\n\n // Identify Merged Dictionaries, Types, and Dynamic Dictionaries to remove\n await Promise.all(\n uniqueMergedDictionaries.map(async (dictionary) => {\n const mergedFilePath = normalize(\n join(configuration.system.dictionariesDir, `${dictionary.key}.json`)\n );\n\n try {\n const fileContent = await readFile(mergedFilePath, 'utf8');\n const parsedContent = JSON.parse(fileContent) as Dictionary;\n\n if (parsedContent.localIds?.length === 1) {\n if (\n parsedContent.localIds[0].endsWith(`::local::${relativeFilePath}`)\n ) {\n appLogger(\n `Removing outdated unmerged dictionary ${colorizeKey(dictionary.key)}`,\n { isVerbose: true }\n );\n\n // Mark JSON for removal\n filesToRemove.push(mergedFilePath);\n\n // Mark TS Types for removal\n const typesFilePath = normalize(\n join(configuration.system.typesDir, `${dictionary.key}.ts`)\n );\n filesToRemove.push(typesFilePath);\n\n // Mark Dynamic Dictionaries for removal\n // We use glob to catch the loader files (.cjs, .mjs) AND the split locale files (.en.json, etc.)\n const dynamicFilesGlob = join(\n configuration.system.dynamicDictionariesDir,\n `${dictionary.key}.*`\n );\n const dynamicFiles = await fg(normalizePath(dynamicFilesGlob), {\n absolute: true,\n });\n filesToRemove.push(...dynamicFiles);\n\n if (!excludeKeys.includes(dictionary.key)) {\n excludeKeys.push(dictionary.key);\n }\n }\n } else {\n const localIds = parsedContent.localIds?.filter(\n (localeId) => !localeId.endsWith(`::local::${relativeFilePath}`)\n ) as string[];\n const newContent = { ...parsedContent, localIds };\n await writeJsonIfChanged(mergedFilePath, newContent);\n }\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n if (!excludeKeys.includes(dictionary.key)) {\n excludeKeys.push(dictionary.key);\n }\n const typesFilePath = normalize(\n join(configuration.system.typesDir, `${dictionary.key}.ts`)\n );\n filesToRemove.push(typesFilePath);\n }\n }\n })\n );\n\n // Execute Cleanup\n if (filesToRemove.length > 0 || excludeKeys.length > 0) {\n // Update entry points (indexes) first so the app doesn't import dead files\n await createDictionaryEntryPoint(configuration, { excludeKeys });\n\n // Remove the files synchronously (awaited) immediately after.\n if (filesToRemove.length > 0) {\n await Promise.all(\n filesToRemove.map(async (path) => {\n const relativePath = relative(baseDir, path);\n try {\n await rm(path, { force: true });\n\n appLogger(`Deleted artifact: ${colorizePath(relativePath)}`, {\n isVerbose: true,\n });\n } catch {\n appLogger(\n `Error while removing file ${colorizePath(relativePath)}`,\n {\n isVerbose: true,\n }\n );\n }\n })\n );\n }\n }\n\n return {\n changedDictionariesLocalIds,\n excludeKeys,\n hasRebuilt: filesToRemove.length > 0 || excludeKeys.length > 0,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"cleanRemovedContentDeclaration.mjs","names":[],"sources":["../../src/cleanRemovedContentDeclaration.ts"],"sourcesContent":["import { readFile, rm } from 'node:fs/promises';\nimport { join, normalize, relative } from 'node:path';\nimport { normalizePath } from '@intlayer/config/client';\nimport {\n colorizeKey,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport fg from 'fast-glob';\nimport { createDictionaryEntryPoint } from './createDictionaryEntryPoint';\nimport { readDictionariesFromDisk } from './utils/readDictionariesFromDisk';\nimport { writeJsonIfChanged } from './writeJsonIfChanged';\n\nexport const cleanRemovedContentDeclaration = async (\n filePath: string,\n keysToKeep: string[],\n configuration: IntlayerConfig\n): Promise<{\n changedDictionariesLocalIds: string[];\n excludeKeys: string[];\n hasRebuilt: boolean;\n}> => {\n const appLogger = getAppLogger(configuration);\n\n const unmergedDictionaries = readDictionariesFromDisk<\n Record<string, Dictionary[]>\n >(configuration.system.unmergedDictionariesDir);\n\n const baseDir = configuration.system.baseDir;\n\n const relativeFilePath = relative(baseDir, filePath);\n const flatUnmergedDictionaries = Object.values(unmergedDictionaries).flat();\n\n const filteredUnmergedDictionaries = flatUnmergedDictionaries.filter(\n (dictionary) =>\n dictionary.filePath === relativeFilePath &&\n !keysToKeep.includes(dictionary.key)\n );\n\n // Deduplicate dictionaries by key\n const uniqueUnmergedDictionaries = filteredUnmergedDictionaries.filter(\n (dictionary, index, self) =>\n index === self.findIndex((t) => t.key === dictionary.key)\n );\n\n const changedDictionariesLocalIds: string[] = [];\n const filesToRemove: string[] = [];\n const excludeKeys: string[] = [];\n\n // Identify Unmerged Dictionaries to remove or clean\n await Promise.all(\n uniqueUnmergedDictionaries.map(async (dictionary) => {\n const unmergedFilePath = normalize(\n join(\n configuration.system.unmergedDictionariesDir,\n `${dictionary.key}.json`\n )\n );\n\n try {\n const jsonContent = await readFile(unmergedFilePath, 'utf8');\n const parsedContent = JSON.parse(jsonContent);\n\n if (parsedContent.length === 1) {\n if (parsedContent[0].filePath === relativeFilePath) {\n appLogger(\n `Removing outdated dictionary ${colorizeKey(dictionary.key)}`,\n { isVerbose: true }\n );\n filesToRemove.push(unmergedFilePath);\n excludeKeys.push(dictionary.key);\n }\n } else {\n const filteredContent = parsedContent.filter(\n (content: any) => content.filePath !== relativeFilePath\n );\n await writeJsonIfChanged(unmergedFilePath, filteredContent);\n changedDictionariesLocalIds.push(dictionary.localId!);\n }\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n if (!excludeKeys.includes(dictionary.key)) {\n excludeKeys.push(dictionary.key);\n }\n }\n }\n })\n );\n\n const dictionaries = readDictionariesFromDisk<Record<string, Dictionary>>(\n configuration.system.dictionariesDir\n );\n const flatDictionaries = Object.values(dictionaries) as Dictionary[];\n\n const filteredMergedDictionaries = flatDictionaries?.filter(\n (dictionary) =>\n !keysToKeep.includes(dictionary.key) &&\n dictionary.localIds?.length === 1 &&\n (dictionary.localIds[0] as string).endsWith(\n `::local::${relativeFilePath}`\n )\n );\n\n const uniqueMergedDictionaries = filteredMergedDictionaries.filter(\n (dictionary, index, self) =>\n index === self.findIndex((t) => t.key === dictionary.key)\n );\n\n // Identify Merged Dictionaries, Types, and Dynamic Dictionaries to remove\n await Promise.all(\n uniqueMergedDictionaries.map(async (dictionary) => {\n const mergedFilePath = normalize(\n join(configuration.system.dictionariesDir, `${dictionary.key}.json`)\n );\n\n try {\n const fileContent = await readFile(mergedFilePath, 'utf8');\n const parsedContent = JSON.parse(fileContent) as Dictionary;\n\n if (parsedContent.localIds?.length === 1) {\n if (\n parsedContent.localIds[0].endsWith(`::local::${relativeFilePath}`)\n ) {\n appLogger(\n `Removing outdated unmerged dictionary ${colorizeKey(dictionary.key)}`,\n { isVerbose: true }\n );\n\n // Mark JSON for removal\n filesToRemove.push(mergedFilePath);\n\n // Mark TS Types for removal\n const typesFilePath = normalize(\n join(configuration.system.typesDir, `${dictionary.key}.ts`)\n );\n filesToRemove.push(typesFilePath);\n\n // Mark Dynamic Dictionaries for removal\n // We use glob to catch the loader files (.cjs, .mjs) AND the split locale files (.en.json, etc.)\n const dynamicFilesGlob = join(\n configuration.system.dynamicDictionariesDir,\n `${dictionary.key}.*`\n );\n const dynamicFiles = await fg(normalizePath(dynamicFilesGlob), {\n absolute: true,\n });\n filesToRemove.push(...dynamicFiles);\n\n if (!excludeKeys.includes(dictionary.key)) {\n excludeKeys.push(dictionary.key);\n }\n }\n } else {\n const localIds = parsedContent.localIds?.filter(\n (localeId) => !localeId.endsWith(`::local::${relativeFilePath}`)\n ) as string[];\n const newContent = { ...parsedContent, localIds };\n await writeJsonIfChanged(mergedFilePath, newContent);\n }\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n if (!excludeKeys.includes(dictionary.key)) {\n excludeKeys.push(dictionary.key);\n }\n const typesFilePath = normalize(\n join(configuration.system.typesDir, `${dictionary.key}.ts`)\n );\n filesToRemove.push(typesFilePath);\n }\n }\n })\n );\n\n // Execute Cleanup\n if (filesToRemove.length > 0 || excludeKeys.length > 0) {\n // Update entry points (indexes) first so the app doesn't import dead files\n await createDictionaryEntryPoint(configuration, { excludeKeys });\n\n // Remove the files synchronously (awaited) immediately after.\n if (filesToRemove.length > 0) {\n setTimeout(\n async () =>\n await Promise.all(\n filesToRemove.map(async (path) => {\n const relativePath = relative(baseDir, path);\n try {\n await rm(path, { force: true });\n\n appLogger(`Deleted artifact: ${colorizePath(relativePath)}`, {\n isVerbose: true,\n });\n } catch {\n appLogger(\n `Error while removing file ${colorizePath(relativePath)}`,\n {\n isVerbose: true,\n }\n );\n }\n })\n ),\n 3000\n );\n }\n }\n\n return {\n changedDictionariesLocalIds,\n excludeKeys,\n hasRebuilt: filesToRemove.length > 0 || excludeKeys.length > 0,\n };\n};\n"],"mappings":"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"}
@@ -1,4 +1,7 @@
1
1
  //#region src/utils/getPathHash.ts
2
+ /**
3
+ * Fast hashing using cyrb53 algorithm for small unique strings with low collisions risk
4
+ */
2
5
  const getPathHash = (filePath) => {
3
6
  let h1 = 3735928559;
4
7
  let h2 = 1103547991;
@@ -9,7 +12,7 @@ const getPathHash = (filePath) => {
9
12
  }
10
13
  h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
11
14
  h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
12
- return `_${(4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36)}`;
15
+ return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36);
13
16
  };
14
17
 
15
18
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"getPathHash.mjs","names":[],"sources":["../../../src/utils/getPathHash.ts"],"sourcesContent":["export const getPathHash = (filePath: string) => {\n let h1 = 0xdeadbeef;\n let h2 = 0x41c6ce57;\n\n for (let i = 0; i < filePath.length; i++) {\n const ch = filePath.charCodeAt(i);\n h1 = Math.imul(h1 ^ ch, 2654435761);\n h2 = Math.imul(h2 ^ ch, 1597334677);\n }\n\n h1 =\n Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^\n Math.imul(h2 ^ (h2 >>> 13), 3266489909);\n h2 =\n Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^\n Math.imul(h1 ^ (h1 >>> 13), 3266489909);\n\n const hash53 = 4294967296 * (2097151 & h2) + (h1 >>> 0);\n\n // Returns a string ~11 characters long, e.g., \"_1x9z5k2m8p3\"\n return `_${hash53.toString(36)}`;\n};\n"],"mappings":";AAAA,MAAa,eAAe,aAAqB;CAC/C,IAAI,KAAK;CACT,IAAI,KAAK;AAET,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;EACxC,MAAM,KAAK,SAAS,WAAW,EAAE;AACjC,OAAK,KAAK,KAAK,KAAK,IAAI,WAAW;AACnC,OAAK,KAAK,KAAK,KAAK,IAAI,WAAW;;AAGrC,MACE,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW,GACvC,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW;AACzC,MACE,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW,GACvC,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW;AAKzC,QAAO,KAHQ,cAAc,UAAU,OAAO,OAAO,IAGnC,SAAS,GAAG"}
1
+ {"version":3,"file":"getPathHash.mjs","names":[],"sources":["../../../src/utils/getPathHash.ts"],"sourcesContent":["/**\n * Fast hashing using cyrb53 algorithm for small unique strings with low collisions risk\n */\nexport const getPathHash = (filePath: string) => {\n let h1 = 0xdeadbeef;\n let h2 = 0x41c6ce57;\n\n for (let i = 0; i < filePath.length; i++) {\n const ch = filePath.charCodeAt(i);\n h1 = Math.imul(h1 ^ ch, 2654435761);\n h2 = Math.imul(h2 ^ ch, 1597334677);\n }\n\n h1 =\n Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^\n Math.imul(h2 ^ (h2 >>> 13), 3266489909);\n h2 =\n Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^\n Math.imul(h1 ^ (h1 >>> 13), 3266489909);\n\n const hash53 = 4294967296 * (2097151 & h2) + (h1 >>> 0);\n\n // Returns a string ~11 characters long, e.g., \"_1x9z5k2m8p3\"\n return hash53.toString(36);\n};\n"],"mappings":";;;;AAGA,MAAa,eAAe,aAAqB;CAC/C,IAAI,KAAK;CACT,IAAI,KAAK;AAET,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;EACxC,MAAM,KAAK,SAAS,WAAW,EAAE;AACjC,OAAK,KAAK,KAAK,KAAK,IAAI,WAAW;AACnC,OAAK,KAAK,KAAK,KAAK,IAAI,WAAW;;AAGrC,MACE,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW,GACvC,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW;AACzC,MACE,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW,GACvC,KAAK,KAAK,KAAM,OAAO,IAAK,WAAW;AAKzC,SAHe,cAAc,UAAU,OAAO,OAAO,IAGvC,SAAS,GAAG"}
@@ -6,9 +6,10 @@ import { prepareIntlayer } from "./prepareIntlayer.mjs";
6
6
  import { writeContentDeclaration } from "./writeContentDeclaration/writeContentDeclaration.mjs";
7
7
  import { readFile } from "node:fs/promises";
8
8
  import { basename } from "node:path";
9
- import { getAppLogger } from "@intlayer/config/logger";
9
+ import { colorize, getAppLogger } from "@intlayer/config/logger";
10
10
  import { getConfiguration, getConfigurationAndFilePath } from "@intlayer/config/node";
11
11
  import { clearAllCache, clearModuleCache, normalizePath } from "@intlayer/config/utils";
12
+ import * as ANSIColor from "@intlayer/config/colors";
12
13
  import { watch as watch$1 } from "chokidar";
13
14
 
14
15
  //#region src/watcher.ts
@@ -42,6 +43,15 @@ const watch = (options) => {
42
43
  const pathsToWatch = [...fileExtensions.flatMap((ext) => contentDir.map((dir) => `${normalizePath(dir)}/**/*${ext}`.replace("//", "/"))), ...configurationFilePath ? [configurationFilePath] : []];
43
44
  if (!configuration.content.watch) return;
44
45
  appLogger("Watching Intlayer content declarations");
46
+ if (configuration.build.optimize === true) appLogger([
47
+ "Build optimization is forced to true, but watching is enabled too.",
48
+ "It may lead to dev mode performance degradation as well as import errors.",
49
+ "Its recommended to keep the",
50
+ colorize("`build.optimized`", ANSIColor.BLUE),
51
+ "option",
52
+ colorize("undefined", ANSIColor.GREY),
53
+ "to get the best dev mode experience"
54
+ ], { level: "warn" });
45
55
  return watch$1(pathsToWatch, {
46
56
  persistent: isWatchMode,
47
57
  ignoreInitial: true,
@@ -1 +1 @@
1
- {"version":3,"file":"watcher.mjs","names":["chokidarWatch"],"sources":["../../src/watcher.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { basename } from 'node:path';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n getConfigurationAndFilePath,\n} from '@intlayer/config/node';\nimport {\n clearAllCache,\n clearModuleCache,\n normalizePath,\n} from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\n/** @ts-ignore remove error Module '\"chokidar\"' has no exported member 'ChokidarOptions' */\nimport { type ChokidarOptions, watch as chokidarWatch } from 'chokidar';\nimport { handleAdditionalContentDeclarationFile } from './handleAdditionalContentDeclarationFile';\nimport { handleContentDeclarationFileChange } from './handleContentDeclarationFileChange';\nimport { handleContentDeclarationFileMoved } from './handleContentDeclarationFileMoved';\nimport { handleUnlinkedContentDeclarationFile } from './handleUnlinkedContentDeclarationFile';\nimport { prepareIntlayer } from './prepareIntlayer';\nimport { writeContentDeclaration } from './writeContentDeclaration';\n\n// Map to track files that were recently unlinked: oldPath -> { timer, timestamp }\nconst pendingUnlinks = new Map<\n string,\n { timer: NodeJS.Timeout; oldPath: string }\n>();\n\n// Mutex-based task queue for sequential file event processing\nlet processingLock: Promise<void> | null = null;\nconst processEvent = (task: () => Promise<void>) => {\n const run = async () => {\n // Wait for the previous task to finish\n while (processingLock) {\n await processingLock;\n }\n\n let resolve: () => void;\n processingLock = new Promise<void>((r) => {\n resolve = r;\n });\n\n try {\n await task();\n } catch (error) {\n console.error(error);\n } finally {\n processingLock = null;\n resolve!();\n }\n };\n\n run();\n};\n\ntype WatchOptions = ChokidarOptions & {\n configuration?: IntlayerConfig;\n configOptions?: GetConfigurationOptions;\n skipPrepare?: boolean;\n};\n\n// Initialize chokidar watcher (non-persistent)\nexport const watch = (options?: WatchOptions) => {\n const configResult = getConfigurationAndFilePath(options?.configOptions);\n const configurationFilePath = configResult.configurationFilePath;\n let configuration: IntlayerConfig =\n options?.configuration ?? configResult.configuration;\n const appLogger = getAppLogger(configuration);\n\n const {\n watch: isWatchMode,\n fileExtensions,\n contentDir,\n } = configuration.content;\n\n const watchedFilesPatternWithPath = fileExtensions.flatMap((ext) =>\n contentDir.map((dir) =>\n `${normalizePath(dir)}/**/*${ext}`.replace('//', '/')\n )\n );\n\n const pathsToWatch = [\n ...watchedFilesPatternWithPath,\n ...(configurationFilePath ? [configurationFilePath] : []),\n ];\n\n if (!configuration.content.watch) return;\n\n appLogger('Watching Intlayer content declarations');\n\n return chokidarWatch(pathsToWatch, {\n persistent: isWatchMode, // Make the watcher persistent\n ignoreInitial: true, // Process existing files\n awaitWriteFinish: {\n stabilityThreshold: 1000,\n pollInterval: 100,\n },\n ignored: [\n '**/node_modules/**',\n '**/dist/**',\n '**/build/**',\n '**/.intlayer/**',\n ],\n ...options,\n })\n .on('add', async (filePath) => {\n const fileName = basename(filePath);\n let isMove = false;\n\n // Check if this Add corresponds to a pending Unlink (Move/Rename detection)\n // Heuristic:\n // - Priority A: Exact basename match (Moved to different folder)\n // - Priority B: Single entry in pendingUnlinks (Renamed file)\n let matchedOldPath: string | undefined;\n\n // Search for basename match\n for (const [oldPath] of pendingUnlinks) {\n if (basename(oldPath) === fileName) {\n matchedOldPath = oldPath;\n break;\n }\n }\n\n // If no basename match, but exactly one file was recently unlinked, assume it's a rename\n if (!matchedOldPath && pendingUnlinks.size === 1) {\n matchedOldPath = pendingUnlinks.keys().next().value;\n }\n\n if (matchedOldPath) {\n // It is a move! Cancel the unlink handler\n const pending = pendingUnlinks.get(matchedOldPath);\n if (pending) {\n clearTimeout(pending.timer);\n pendingUnlinks.delete(matchedOldPath);\n }\n\n isMove = true;\n appLogger(`File moved from ${matchedOldPath} to ${filePath}`);\n }\n\n processEvent(async () => {\n if (isMove && matchedOldPath) {\n await handleContentDeclarationFileMoved(\n matchedOldPath,\n filePath,\n configuration\n );\n } else {\n const fileContent = await readFile(filePath, 'utf-8');\n const isEmpty = fileContent === '';\n\n // Fill template content declaration file if it is empty\n if (isEmpty) {\n const extensionPattern = fileExtensions\n .map((ext) => ext.replace(/\\./g, '\\\\.'))\n .join('|');\n const name = fileName.replace(\n new RegExp(`(${extensionPattern})$`),\n ''\n );\n\n await writeContentDeclaration(\n {\n key: name,\n content: {},\n filePath,\n },\n configuration\n );\n }\n\n await handleAdditionalContentDeclarationFile(filePath, configuration);\n }\n });\n })\n .on('change', async (filePath) =>\n processEvent(async () => {\n if (configurationFilePath && filePath === configurationFilePath) {\n appLogger('Configuration file changed, repreparing Intlayer');\n\n clearModuleCache(configurationFilePath);\n clearAllCache();\n\n const { configuration: newConfiguration } =\n getConfigurationAndFilePath(options?.configOptions);\n\n configuration = options?.configuration ?? newConfiguration;\n\n await prepareIntlayer(configuration, { clean: false });\n } else {\n // Clear module cache for the changed file to avoid stale require() results\n clearModuleCache(filePath);\n await handleContentDeclarationFileChange(filePath, configuration);\n }\n })\n )\n .on('unlink', async (filePath) => {\n // Delay unlink processing to see if an 'add' event occurs (indicating a move)\n const timer = setTimeout(async () => {\n // If timer fires, the file was genuinely removed\n pendingUnlinks.delete(filePath);\n processEvent(async () =>\n handleUnlinkedContentDeclarationFile(filePath, configuration)\n );\n }, 200); // 200ms window to catch the 'add' event\n\n pendingUnlinks.set(filePath, { timer, oldPath: filePath });\n })\n .on('error', async (error) => {\n appLogger(`Watcher error: ${error}`, {\n level: 'error',\n });\n\n appLogger('Restarting watcher');\n\n await prepareIntlayer(configuration);\n });\n};\n\nexport const buildAndWatchIntlayer = async (options?: WatchOptions) => {\n const { skipPrepare, ...rest } = options ?? {};\n const configuration =\n options?.configuration ?? getConfiguration(options?.configOptions);\n\n if (!skipPrepare) {\n await prepareIntlayer(configuration, { forceRun: true });\n }\n\n if (configuration.content.watch || options?.persistent) {\n watch({ ...rest, configuration });\n }\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"watcher.mjs","names":["chokidarWatch"],"sources":["../../src/watcher.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { basename } from 'node:path';\nimport * as ANSIColor from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n getConfigurationAndFilePath,\n} from '@intlayer/config/node';\nimport {\n clearAllCache,\n clearModuleCache,\n normalizePath,\n} from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\n/** @ts-ignore remove error Module '\"chokidar\"' has no exported member 'ChokidarOptions' */\nimport { type ChokidarOptions, watch as chokidarWatch } from 'chokidar';\nimport { handleAdditionalContentDeclarationFile } from './handleAdditionalContentDeclarationFile';\nimport { handleContentDeclarationFileChange } from './handleContentDeclarationFileChange';\nimport { handleContentDeclarationFileMoved } from './handleContentDeclarationFileMoved';\nimport { handleUnlinkedContentDeclarationFile } from './handleUnlinkedContentDeclarationFile';\nimport { prepareIntlayer } from './prepareIntlayer';\nimport { writeContentDeclaration } from './writeContentDeclaration';\n\n// Map to track files that were recently unlinked: oldPath -> { timer, timestamp }\nconst pendingUnlinks = new Map<\n string,\n { timer: NodeJS.Timeout; oldPath: string }\n>();\n\n// Mutex-based task queue for sequential file event processing\nlet processingLock: Promise<void> | null = null;\nconst processEvent = (task: () => Promise<void>) => {\n const run = async () => {\n // Wait for the previous task to finish\n while (processingLock) {\n await processingLock;\n }\n\n let resolve: () => void;\n processingLock = new Promise<void>((r) => {\n resolve = r;\n });\n\n try {\n await task();\n } catch (error) {\n console.error(error);\n } finally {\n processingLock = null;\n resolve!();\n }\n };\n\n run();\n};\n\ntype WatchOptions = ChokidarOptions & {\n configuration?: IntlayerConfig;\n configOptions?: GetConfigurationOptions;\n skipPrepare?: boolean;\n};\n\n// Initialize chokidar watcher (non-persistent)\nexport const watch = (options?: WatchOptions) => {\n const configResult = getConfigurationAndFilePath(options?.configOptions);\n const configurationFilePath = configResult.configurationFilePath;\n let configuration: IntlayerConfig =\n options?.configuration ?? configResult.configuration;\n const appLogger = getAppLogger(configuration);\n\n const {\n watch: isWatchMode,\n fileExtensions,\n contentDir,\n } = configuration.content;\n\n const watchedFilesPatternWithPath = fileExtensions.flatMap((ext) =>\n contentDir.map((dir) =>\n `${normalizePath(dir)}/**/*${ext}`.replace('//', '/')\n )\n );\n\n const pathsToWatch = [\n ...watchedFilesPatternWithPath,\n ...(configurationFilePath ? [configurationFilePath] : []),\n ];\n\n if (!configuration.content.watch) return;\n\n appLogger('Watching Intlayer content declarations');\n\n if (configuration.build.optimize === true) {\n appLogger(\n [\n 'Build optimization is forced to true, but watching is enabled too.',\n 'It may lead to dev mode performance degradation as well as import errors.',\n 'Its recommended to keep the',\n colorize('`build.optimized`', ANSIColor.BLUE),\n 'option',\n colorize('undefined', ANSIColor.GREY),\n 'to get the best dev mode experience',\n ],\n {\n level: 'warn',\n }\n );\n }\n\n return chokidarWatch(pathsToWatch, {\n persistent: isWatchMode, // Make the watcher persistent\n ignoreInitial: true, // Process existing files\n awaitWriteFinish: {\n stabilityThreshold: 1000,\n pollInterval: 100,\n },\n ignored: [\n '**/node_modules/**',\n '**/dist/**',\n '**/build/**',\n '**/.intlayer/**',\n ],\n ...options,\n })\n .on('add', async (filePath) => {\n const fileName = basename(filePath);\n let isMove = false;\n\n // Check if this Add corresponds to a pending Unlink (Move/Rename detection)\n // Heuristic:\n // - Priority A: Exact basename match (Moved to different folder)\n // - Priority B: Single entry in pendingUnlinks (Renamed file)\n let matchedOldPath: string | undefined;\n\n // Search for basename match\n for (const [oldPath] of pendingUnlinks) {\n if (basename(oldPath) === fileName) {\n matchedOldPath = oldPath;\n break;\n }\n }\n\n // If no basename match, but exactly one file was recently unlinked, assume it's a rename\n if (!matchedOldPath && pendingUnlinks.size === 1) {\n matchedOldPath = pendingUnlinks.keys().next().value;\n }\n\n if (matchedOldPath) {\n // It is a move! Cancel the unlink handler\n const pending = pendingUnlinks.get(matchedOldPath);\n if (pending) {\n clearTimeout(pending.timer);\n pendingUnlinks.delete(matchedOldPath);\n }\n\n isMove = true;\n appLogger(`File moved from ${matchedOldPath} to ${filePath}`);\n }\n\n processEvent(async () => {\n if (isMove && matchedOldPath) {\n await handleContentDeclarationFileMoved(\n matchedOldPath,\n filePath,\n configuration\n );\n } else {\n const fileContent = await readFile(filePath, 'utf-8');\n const isEmpty = fileContent === '';\n\n // Fill template content declaration file if it is empty\n if (isEmpty) {\n const extensionPattern = fileExtensions\n .map((ext) => ext.replace(/\\./g, '\\\\.'))\n .join('|');\n const name = fileName.replace(\n new RegExp(`(${extensionPattern})$`),\n ''\n );\n\n await writeContentDeclaration(\n {\n key: name,\n content: {},\n filePath,\n },\n configuration\n );\n }\n\n await handleAdditionalContentDeclarationFile(filePath, configuration);\n }\n });\n })\n .on('change', async (filePath) =>\n processEvent(async () => {\n if (configurationFilePath && filePath === configurationFilePath) {\n appLogger('Configuration file changed, repreparing Intlayer');\n\n clearModuleCache(configurationFilePath);\n clearAllCache();\n\n const { configuration: newConfiguration } =\n getConfigurationAndFilePath(options?.configOptions);\n\n configuration = options?.configuration ?? newConfiguration;\n\n await prepareIntlayer(configuration, { clean: false });\n } else {\n // Clear module cache for the changed file to avoid stale require() results\n clearModuleCache(filePath);\n await handleContentDeclarationFileChange(filePath, configuration);\n }\n })\n )\n .on('unlink', async (filePath) => {\n // Delay unlink processing to see if an 'add' event occurs (indicating a move)\n const timer = setTimeout(async () => {\n // If timer fires, the file was genuinely removed\n pendingUnlinks.delete(filePath);\n processEvent(async () =>\n handleUnlinkedContentDeclarationFile(filePath, configuration)\n );\n }, 200); // 200ms window to catch the 'add' event\n\n pendingUnlinks.set(filePath, { timer, oldPath: filePath });\n })\n .on('error', async (error) => {\n appLogger(`Watcher error: ${error}`, {\n level: 'error',\n });\n\n appLogger('Restarting watcher');\n\n await prepareIntlayer(configuration);\n });\n};\n\nexport const buildAndWatchIntlayer = async (options?: WatchOptions) => {\n const { skipPrepare, ...rest } = options ?? {};\n const configuration =\n options?.configuration ?? getConfiguration(options?.configOptions);\n\n if (!skipPrepare) {\n await prepareIntlayer(configuration, { forceRun: true });\n }\n\n if (configuration.content.watch || options?.persistent) {\n watch({ ...rest, configuration });\n }\n};\n"],"mappings":"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"}
@@ -69,7 +69,7 @@ const isMultilingualNode = (val) => {
69
69
  const nodeType = getNodeType(val);
70
70
  if (nodeType === NodeTypes.TRANSLATION) return true;
71
71
  if (nodeType === NodeTypes.MARKDOWN || nodeType === NodeTypes.HTML || nodeType === NodeTypes.INSERTION) return isMultilingualNode(val[nodeType]);
72
- if (nodeType === NodeTypes.ENUMERATION || nodeType === NodeTypes.CONDITION || nodeType === NodeTypes.GENDER) {
72
+ if (nodeType === NodeTypes.ENUMERATION || nodeType === NodeTypes.PLURAL || nodeType === NodeTypes.CONDITION || nodeType === NodeTypes.GENDER) {
73
73
  const data = val[nodeType];
74
74
  if (data && typeof data === "object") return Object.values(data).some((v) => isMultilingualNode(v));
75
75
  }
@@ -84,6 +84,7 @@ const buildNodeForValue = (val, existingNode, fallbackLocale, requiredImports) =
84
84
  if (!(n.Literal.check(unwrappedExisting) || n.StringLiteral.check(unwrappedExisting) || n.NumericLiteral.check(unwrappedExisting) || n.BooleanLiteral.check(unwrappedExisting) || n.TemplateLiteral.check(unwrappedExisting) || n.ObjectExpression.check(unwrappedExisting) || n.ArrayExpression.check(unwrappedExisting) || n.CallExpression.check(unwrappedExisting) && n.Identifier.check(unwrappedExisting.callee) && [
85
85
  "t",
86
86
  "enu",
87
+ "plural",
87
88
  "cond",
88
89
  "gender",
89
90
  "insert",
@@ -159,6 +160,7 @@ const buildNodeForValue = (val, existingNode, fallbackLocale, requiredImports) =
159
160
  if (nodeType && [
160
161
  NodeTypes.TRANSLATION,
161
162
  NodeTypes.ENUMERATION,
163
+ NodeTypes.PLURAL,
162
164
  NodeTypes.CONDITION,
163
165
  NodeTypes.GENDER,
164
166
  NodeTypes.INSERTION,
@@ -178,6 +180,7 @@ const buildNodeForValue = (val, existingNode, fallbackLocale, requiredImports) =
178
180
  let calleeName = "";
179
181
  if (nodeType === NodeTypes.TRANSLATION) calleeName = "t";
180
182
  else if (nodeType === NodeTypes.ENUMERATION) calleeName = "enu";
183
+ else if (nodeType === NodeTypes.PLURAL) calleeName = "plural";
181
184
  else if (nodeType === NodeTypes.CONDITION) calleeName = "cond";
182
185
  else if (nodeType === NodeTypes.GENDER) calleeName = "gender";
183
186
  else if (nodeType === NodeTypes.INSERTION) calleeName = "insert";
@@ -190,6 +193,7 @@ const buildNodeForValue = (val, existingNode, fallbackLocale, requiredImports) =
190
193
  if ([
191
194
  "t",
192
195
  "enu",
196
+ "plural",
193
197
  "cond",
194
198
  "gender"
195
199
  ].includes(calleeName)) {
@@ -1 +1 @@
1
- {"version":3,"file":"transformJSFile.mjs","names":[],"sources":["../../../src/writeContentDeclaration/transformJSFile.ts"],"sourcesContent":["import { getNodeType } from '@intlayer/core/dictionaryManipulator';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport * as recast from 'recast';\nimport * as babelTsParser from 'recast/parsers/babel-ts.js';\n\nconst b = recast.types.builders;\nconst n = recast.types.namedTypes;\n\n/**\n * Unwraps TypeScript/Babel expression wrappers (satisfies, as, !, <Type>).\n * Uses string fallbacks to bypass outdated ast-types definitions.\n */\nconst unwrap = (node: any) => {\n while (\n node &&\n (n.TSSatisfiesExpression?.check(node) ||\n n.TSAsExpression?.check(node) ||\n n.TSTypeAssertion?.check(node) ||\n n.TSNonNullExpression?.check(node) ||\n [\n 'TSSatisfiesExpression',\n 'TSAsExpression',\n 'TSTypeAssertion',\n 'TSNonNullExpression',\n ].includes(node.type))\n ) {\n node = node.expression;\n }\n return node;\n};\n\n/**\n * Robustly finds a property in a recast ObjectExpression.\n * Handles quoted (\"key\") or unquoted (key) properties.\n */\nconst getMatchingProperty = (node: any, key: string) => {\n return node.properties.find((prop: any) => {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n if (n.Identifier.check(prop.key) && prop.key.name === key) return true;\n\n if (n.StringLiteral.check(prop.key) && prop.key.value === key)\n return true;\n\n if (n.Literal.check(prop.key) && prop.key.value === key) return true;\n }\n\n return false;\n });\n};\n\n/**\n * Synchronizes numeric suffixes across locales.\n * E.g. \"Hello 1\" -> \"Hello 3\" updates \"Bonjour 1\" to \"Bonjour 3\".\n */\nconst syncNumericSuffixAcrossLocales = (\n existingNode: any,\n fallbackLocaleCode: string,\n newFallbackValue: string\n) => {\n const trailingNumberMatch = newFallbackValue.match(/\\d+(?!.*\\d)/);\n if (!trailingNumberMatch) return;\n const newTrailingNumber = trailingNumberMatch[0];\n\n if (n.ObjectExpression.check(existingNode)) {\n for (const prop of existingNode.properties) {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n let propName = '';\n\n if (n.Identifier.check(prop.key)) propName = prop.key.name;\n else if (\n n.Literal.check(prop.key) &&\n typeof prop.key.value === 'string'\n )\n propName = prop.key.value;\n else if (n.StringLiteral.check(prop.key)) propName = prop.key.value;\n\n if (propName && propName !== fallbackLocaleCode) {\n if (\n n.Literal.check(prop.value) &&\n typeof prop.value.value === 'string'\n ) {\n const currentValue = prop.value.value;\n const currentTrailingNumberMatch =\n currentValue.match(/\\d+(?!.*\\d)/);\n\n if (currentTrailingNumberMatch) {\n prop.value = b.literal(\n currentValue.replace(/(\\d+)(?!.*\\d)/, newTrailingNumber)\n );\n }\n } else if (n.StringLiteral.check(prop.value)) {\n const currentValue = prop.value.value;\n const currentTrailingNumberMatch =\n currentValue.match(/\\d+(?!.*\\d)/);\n\n if (currentTrailingNumberMatch) {\n prop.value = b.stringLiteral(\n currentValue.replace(/(\\d+)(?!.*\\d)/, newTrailingNumber)\n );\n }\n }\n }\n }\n }\n }\n};\n\n/**\n * Checks if a value represents a multilingual Intlayer node.\n * A node is multilingual if it is a Translation node, or if it is a specialized node\n * (Markdown, HTML, etc.) that contains a Translation node.\n */\nconst isMultilingualNode = (val: any): boolean => {\n if (typeof val !== 'object' || val === null || Array.isArray(val)) {\n return false;\n }\n\n const nodeType = getNodeType(val as ContentNode);\n\n if (nodeType === NodeTypes.TRANSLATION) {\n return true;\n }\n\n if (\n nodeType === NodeTypes.MARKDOWN ||\n nodeType === NodeTypes.HTML ||\n nodeType === NodeTypes.INSERTION\n ) {\n return isMultilingualNode((val as any)[nodeType]);\n }\n\n if (\n nodeType === NodeTypes.ENUMERATION ||\n nodeType === NodeTypes.CONDITION ||\n nodeType === NodeTypes.GENDER\n ) {\n const data = (val as any)[nodeType];\n\n if (data && typeof data === 'object') {\n return Object.values(data).some((v) => isMultilingualNode(v));\n }\n }\n\n return false;\n};\n\n/**\n * Recursively builds or updates an AST node for a given dictionary value.\n */\nconst buildNodeForValue = (\n val: any,\n existingNode: any,\n fallbackLocale: string | undefined, // In per-locale mode, this is the locale of the file\n requiredImports: Set<string>\n): any => {\n const unwrappedExisting = unwrap(existingNode);\n\n // --- CRITICAL GUARD: STRICT AST PRESERVATION ---\n // If the existing node is code (JSX, Variables, standard functions), leave it alone.\n // Only allow updates to literals, plain objects, arrays, and Intlayer helpers.\n if (unwrappedExisting) {\n const isUpdatableNode =\n n.Literal.check(unwrappedExisting) ||\n n.StringLiteral.check(unwrappedExisting) ||\n n.NumericLiteral.check(unwrappedExisting) ||\n n.BooleanLiteral.check(unwrappedExisting) ||\n n.TemplateLiteral.check(unwrappedExisting) ||\n n.ObjectExpression.check(unwrappedExisting) ||\n n.ArrayExpression.check(unwrappedExisting) ||\n (n.CallExpression.check(unwrappedExisting) &&\n n.Identifier.check(unwrappedExisting.callee) &&\n [\n 't',\n 'enu',\n 'cond',\n 'gender',\n 'insert',\n 'md',\n 'html',\n 'file',\n 'nest',\n ].includes(unwrappedExisting.callee.name));\n\n if (!isUpdatableNode) {\n return existingNode;\n }\n }\n\n // If we are in per-locale mode (fallbackLocale is set)\n // and the value is not already a complex translation node,\n // we want to store it as a simple literal, NOT wrapped in t().\n if (fallbackLocale && !existingNode && !isMultilingualNode(val)) {\n if (val === null) return b.literal(null);\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n if (typeof val === 'string' && val.includes('\\n')) {\n return b.templateLiteral(\n [b.templateElement({ raw: val, cooked: val }, true)],\n []\n );\n }\n return b.literal(val);\n }\n }\n\n if (fallbackLocale && existingNode && !isMultilingualNode(val)) {\n if (\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === 't'\n ) {\n const arg = unwrap(existingNode.arguments[0]);\n\n if (n.ObjectExpression.check(arg)) {\n if (typeof val === 'string') {\n syncNumericSuffixAcrossLocales(arg, fallbackLocale, val);\n }\n updateObjectLiteral(\n arg,\n { [fallbackLocale]: val },\n fallbackLocale,\n requiredImports\n );\n\n if (!fallbackLocale) {\n requiredImports.add('t');\n }\n\n return existingNode;\n }\n }\n\n if (\n (!val || typeof val !== 'object') &&\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === 'md'\n ) {\n const innerArg = existingNode.arguments[0];\n\n if (\n n.CallExpression.check(innerArg) &&\n n.Identifier.check(innerArg.callee) &&\n innerArg.callee.name === 't'\n ) {\n const tArg = unwrap(innerArg.arguments[0]);\n\n if (n.ObjectExpression.check(tArg)) {\n if (typeof val === 'string') {\n syncNumericSuffixAcrossLocales(tArg, fallbackLocale, val);\n }\n updateObjectLiteral(\n tArg,\n { [fallbackLocale]: val },\n fallbackLocale,\n requiredImports\n );\n requiredImports.add('md');\n requiredImports.add('t');\n\n return existingNode;\n }\n }\n }\n }\n\n // 1. Primitives\n if (val === null) return b.literal(null);\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n if (unwrappedExisting) {\n // Preserve existing template literals (backticks)\n if (\n n.TemplateLiteral.check(unwrappedExisting) &&\n unwrappedExisting.expressions.length === 0\n ) {\n unwrappedExisting.quasis[0].value.raw = String(val);\n unwrappedExisting.quasis[0].value.cooked = String(val);\n return existingNode;\n }\n // Preserve existing standard literals (keeps quote styling)\n if (\n n.Literal.check(unwrappedExisting) ||\n n.StringLiteral.check(unwrappedExisting)\n ) {\n unwrappedExisting.value = val;\n return existingNode;\n }\n }\n\n // Force multiline strings to use Template Literals\n if (typeof val === 'string' && val.includes('\\n')) {\n return b.templateLiteral(\n [b.templateElement({ raw: val, cooked: val }, true)],\n []\n );\n }\n return b.literal(val);\n }\n\n // 2. Arrays\n if (Array.isArray(val)) {\n if (unwrappedExisting && n.ArrayExpression.check(unwrappedExisting)) {\n const elements = [...unwrappedExisting.elements];\n val.forEach((item, i) => {\n elements[i] = buildNodeForValue(\n item,\n elements[i],\n fallbackLocale,\n requiredImports\n );\n });\n\n if (elements.length > val.length) elements.length = val.length;\n unwrappedExisting.elements = elements as any;\n\n return existingNode;\n } else {\n return b.arrayExpression(\n val.map((item) =>\n buildNodeForValue(item, null, fallbackLocale, requiredImports)\n )\n );\n }\n }\n\n // 3. Intlayer Specialized Nodes\n const nodeType =\n val && typeof val === 'object' && !Array.isArray(val)\n ? getNodeType(val as ContentNode)\n : null;\n\n if (\n nodeType &&\n [\n NodeTypes.TRANSLATION,\n NodeTypes.ENUMERATION,\n NodeTypes.CONDITION,\n NodeTypes.GENDER,\n NodeTypes.INSERTION,\n NodeTypes.MARKDOWN,\n NodeTypes.HTML,\n NodeTypes.FILE,\n NodeTypes.NESTED,\n NodeTypes.ARRAY,\n NodeTypes.OBJECT,\n NodeTypes.REACT_NODE,\n NodeTypes.NUMBER,\n NodeTypes.BOOLEAN,\n NodeTypes.NULL,\n NodeTypes.UNKNOWN,\n ].includes(nodeType as any) &&\n nodeType !== NodeTypes.TEXT\n ) {\n const nodeData = (val as any)[nodeType];\n let calleeName = '';\n\n if (nodeType === NodeTypes.TRANSLATION) calleeName = 't';\n else if (nodeType === NodeTypes.ENUMERATION) calleeName = 'enu';\n else if (nodeType === NodeTypes.CONDITION) calleeName = 'cond';\n else if (nodeType === NodeTypes.GENDER) calleeName = 'gender';\n else if (nodeType === NodeTypes.INSERTION) calleeName = 'insert';\n else if (nodeType === NodeTypes.MARKDOWN) calleeName = 'md';\n else if (nodeType === NodeTypes.HTML) calleeName = 'html';\n else if (nodeType === NodeTypes.FILE) calleeName = 'file';\n else if (nodeType === NodeTypes.NESTED) calleeName = 'nest';\n\n if (calleeName) requiredImports.add(calleeName);\n\n const isMatchingCall =\n existingNode &&\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === calleeName;\n\n if (['t', 'enu', 'cond', 'gender'].includes(calleeName)) {\n let objArg: any = null;\n\n if (\n isMatchingCall &&\n existingNode.arguments.length > 0 &&\n n.ObjectExpression.check(existingNode.arguments[0])\n ) {\n objArg = existingNode.arguments[0];\n } else {\n objArg = b.objectExpression([]);\n }\n updateObjectLiteral(objArg, nodeData, fallbackLocale, requiredImports);\n\n return isMatchingCall\n ? existingNode\n : b.callExpression(b.identifier(calleeName), [objArg]);\n }\n\n if (['md', 'html', 'insert', 'file'].includes(calleeName)) {\n const argNode = buildNodeForValue(\n nodeData,\n isMatchingCall && existingNode.arguments.length > 0\n ? existingNode.arguments[0]\n : null,\n fallbackLocale,\n requiredImports\n );\n\n if (isMatchingCall) {\n existingNode.arguments[0] = argNode;\n\n return existingNode;\n }\n\n return b.callExpression(b.identifier(calleeName), [argNode]);\n }\n\n if (calleeName === 'nest') {\n const args = [b.literal(nodeData.dictionaryKey)];\n\n if (nodeData.path) args.push(b.literal(nodeData.path));\n\n if (isMatchingCall) {\n existingNode.arguments = args;\n\n return existingNode;\n }\n\n return b.callExpression(b.identifier('nest'), args);\n }\n }\n\n // 4. Plain Object\n const objNode =\n unwrappedExisting && n.ObjectExpression.check(unwrappedExisting)\n ? unwrappedExisting\n : b.objectExpression([]);\n\n updateObjectLiteral(objNode, val, fallbackLocale, requiredImports);\n\n return existingNode && unwrappedExisting === existingNode\n ? objNode\n : existingNode || objNode;\n};\n\n/**\n * Recursively updates the AST object literal properties.\n */\nconst updateObjectLiteral = (\n node: recast.types.namedTypes.ObjectExpression,\n data: Record<string, any>,\n fallbackLocale: string | undefined,\n requiredImports: Set<string>\n) => {\n for (const [key, val] of Object.entries(data)) {\n if (val === undefined) continue;\n\n const existingProp = getMatchingProperty(node, key);\n\n if (existingProp) {\n existingProp.value = buildNodeForValue(\n val,\n existingProp.value,\n fallbackLocale,\n requiredImports\n );\n } else {\n const isValidId = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key);\n const keyNode = isValidId ? b.identifier(key) : b.literal(key);\n const valueNode = buildNodeForValue(\n val,\n null,\n fallbackLocale,\n requiredImports\n );\n node.properties.push(b.property('init', keyNode, valueNode));\n }\n }\n};\n\n/**\n * Modifies the AST's top-level imports to inject dynamically needed helper utilities seamlessly.\n */\nconst addImports = (ast: any, requiredImports: Set<string>, isESM: boolean) => {\n if (requiredImports.size === 0) return;\n\n const existingCoreImports = new Set<string>();\n let coreImportPath: any = null;\n\n recast.visit(ast, {\n visitImportDeclaration(path) {\n const source = path.node.source.value;\n\n if (source === 'intlayer') {\n coreImportPath = path;\n path.node.specifiers?.forEach((spec) => {\n if (\n n.ImportSpecifier.check(spec) &&\n typeof spec.imported.name === 'string'\n ) {\n existingCoreImports.add(spec.imported.name);\n }\n });\n }\n\n return false;\n },\n visitVariableDeclaration(path) {\n path.node.declarations.forEach((decl) => {\n if (\n n.VariableDeclarator.check(decl) &&\n n.CallExpression.check(decl.init) &&\n n.Identifier.check(decl.init.callee) &&\n decl.init.callee.name === 'require'\n ) {\n const arg = decl.init.arguments[0];\n\n if (n.Literal.check(arg)) {\n if (arg.value === 'intlayer') {\n if (n.ObjectPattern.check(decl.id)) {\n decl.id.properties.forEach((prop) => {\n if (\n n.Property.check(prop) &&\n (n.Identifier.check(prop.key) ||\n n.Identifier.check(prop.value))\n ) {\n const name = n.Identifier.check(prop.key)\n ? prop.key.name\n : (prop.value as any).name;\n existingCoreImports.add(name);\n }\n });\n } else if (n.Identifier.check(decl.id)) {\n // Handle const intlayer = require('intlayer')\n existingCoreImports.add(decl.id.name);\n }\n }\n }\n }\n });\n\n return false;\n },\n });\n\n const missingCore = Array.from(requiredImports).filter(\n (imp) => !existingCoreImports.has(imp)\n );\n\n if (missingCore.length === 0) return;\n\n if (isESM) {\n if (coreImportPath) {\n missingCore.forEach((imp) => {\n coreImportPath.node.specifiers.push(\n b.importSpecifier(b.identifier(imp))\n );\n });\n coreImportPath.node.specifiers.sort((a: any, b: any) =>\n a.imported.name.localeCompare(b.imported.name)\n );\n } else {\n const specifiers = missingCore\n .sort()\n .map((imp) => b.importSpecifier(b.identifier(imp)));\n const newImport = b.importDeclaration(specifiers, b.literal('intlayer'));\n ast.program.body.unshift(newImport);\n }\n } else {\n let insertIndex = 0;\n\n if (\n ast.program.body.length > 0 &&\n n.ExpressionStatement.check(ast.program.body[0]) &&\n n.Literal.check(ast.program.body[0].expression)\n ) {\n insertIndex = 1; // Insert after 'use strict'\n }\n const cjsLines: any[] = [];\n\n const properties = missingCore.sort().map((imp) => {\n const prop = b.property('init', b.identifier(imp), b.identifier(imp));\n prop.shorthand = true;\n\n return prop;\n });\n cjsLines.push(\n b.variableDeclaration('const', [\n b.variableDeclarator(\n b.objectPattern(properties),\n b.callExpression(b.identifier('require'), [b.literal('intlayer')])\n ),\n ])\n );\n\n ast.program.body.splice(insertIndex, 0, ...cjsLines);\n }\n};\n\n/**\n * Updates a JS/TS file seamlessly to map new localization keys, arrays, complex nodes and nested dictionaries gracefully using AST updates via Recast parser.\n */\nexport const transformJSFile = async (\n fileContent: string,\n dictionary: Dictionary,\n fallbackLocale?: Locale,\n noMetadata?: boolean\n): Promise<string> => {\n if (!dictionary || typeof dictionary !== 'object') return fileContent;\n\n let ast: any;\n try {\n ast = recast.parse(fileContent, {\n parser: babelTsParser,\n });\n } catch (error) {\n console.error({ error });\n return fileContent;\n }\n\n let rootObject: any = null;\n let isESM = false;\n\n recast.visit(ast, {\n visitExportDefaultDeclaration() {\n isESM = true;\n\n return false;\n },\n visitImportDeclaration() {\n isESM = true;\n\n return false;\n },\n });\n\n recast.visit(ast, {\n visitExportDefaultDeclaration(path) {\n const decl = path.node.declaration;\n const unwrappedDecl = unwrap(decl);\n\n if (n.ObjectExpression.check(unwrappedDecl)) {\n rootObject = unwrappedDecl;\n } else if (n.Identifier.check(unwrappedDecl)) {\n const varName = unwrappedDecl.name;\n recast.visit(ast, {\n visitVariableDeclarator(vp) {\n const unwrappedInit = unwrap(vp.node.init);\n\n if (\n n.Identifier.check(vp.node.id) &&\n vp.node.id.name === varName &&\n n.ObjectExpression.check(unwrappedInit)\n ) {\n rootObject = unwrappedInit;\n }\n\n return false;\n },\n });\n }\n\n return false;\n },\n visitAssignmentExpression(path) {\n const left = path.node.left;\n\n if (n.MemberExpression.check(left)) {\n if (\n n.Identifier.check(left.object) &&\n left.object.name === 'module' &&\n n.Identifier.check(left.property) &&\n left.property.name === 'exports'\n ) {\n const unwrappedRight = unwrap(path.node.right);\n\n if (n.ObjectExpression.check(unwrappedRight)) {\n rootObject = unwrappedRight;\n }\n }\n\n if (\n n.Identifier.check(left.object) &&\n left.object.name === 'exports' &&\n n.Identifier.check(left.property) &&\n left.property.name === 'default'\n ) {\n const unwrappedRight = unwrap(path.node.right);\n\n if (n.ObjectExpression.check(unwrappedRight)) {\n rootObject = unwrappedRight;\n }\n }\n }\n this.traverse(path);\n },\n });\n\n if (!rootObject) {\n recast.visit(ast, {\n visitVariableDeclarator(path) {\n const unwrappedInit = unwrap(path.node.init);\n\n if (!rootObject && n.ObjectExpression.check(unwrappedInit)) {\n rootObject = unwrappedInit;\n }\n\n return false;\n },\n });\n }\n\n if (!rootObject) return fileContent;\n\n const requiredImports = new Set<string>();\n const effectiveFallbackLocale = (fallbackLocale as string) ?? 'en';\n\n const metadataProperties = [\n 'id',\n 'locale',\n 'filled',\n 'fill',\n 'title',\n 'description',\n 'tags',\n 'version',\n 'priority',\n 'contentAutoTransformation',\n ];\n\n if (noMetadata) {\n // Remove key, content and metadata properties if they exist\n rootObject.properties = rootObject.properties.filter((prop: any) => {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n let propName = '';\n if (n.Identifier.check(prop.key)) propName = prop.key.name;\n else if (n.StringLiteral.check(prop.key)) propName = prop.key.value;\n else if (n.Literal.check(prop.key)) propName = String(prop.key.value);\n\n return !['key', 'content', ...metadataProperties].includes(propName);\n }\n return true;\n });\n\n // Update satisfies type if exists\n recast.visit(ast, {\n visitNode(path) {\n const node = path.node;\n if (\n (n.TSSatisfiesExpression?.check(node) ||\n node.type === 'TSSatisfiesExpression') &&\n (node as any).typeAnnotation &&\n n.TSTypeReference.check((node as any).typeAnnotation) &&\n n.Identifier.check((node as any).typeAnnotation.typeName) &&\n (node as any).typeAnnotation.typeName.name === 'Dictionary'\n ) {\n (node as any).typeAnnotation = b.tsIndexedAccessType(\n b.tsTypeReference(b.identifier('Dictionary')),\n b.tsLiteralType(b.stringLiteral('content'))\n );\n }\n this.traverse(path);\n },\n });\n } else {\n for (const prop of metadataProperties) {\n if ((dictionary as any)[prop] !== undefined) {\n updateObjectLiteral(\n rootObject,\n { [prop]: (dictionary as any)[prop] },\n undefined,\n requiredImports\n );\n }\n }\n }\n\n if (dictionary.content !== undefined) {\n updateObjectLiteral(\n rootObject,\n noMetadata\n ? (dictionary.content as Record<string, any>)\n : { content: dictionary.content },\n effectiveFallbackLocale,\n requiredImports\n );\n }\n\n addImports(ast, requiredImports, isESM);\n\n return recast.print(ast).code;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"transformJSFile.mjs","names":[],"sources":["../../../src/writeContentDeclaration/transformJSFile.ts"],"sourcesContent":["import { getNodeType } from '@intlayer/core/dictionaryManipulator';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport * as recast from 'recast';\nimport * as babelTsParser from 'recast/parsers/babel-ts.js';\n\nconst b = recast.types.builders;\nconst n = recast.types.namedTypes;\n\n/**\n * Unwraps TypeScript/Babel expression wrappers (satisfies, as, !, <Type>).\n * Uses string fallbacks to bypass outdated ast-types definitions.\n */\nconst unwrap = (node: any) => {\n while (\n node &&\n (n.TSSatisfiesExpression?.check(node) ||\n n.TSAsExpression?.check(node) ||\n n.TSTypeAssertion?.check(node) ||\n n.TSNonNullExpression?.check(node) ||\n [\n 'TSSatisfiesExpression',\n 'TSAsExpression',\n 'TSTypeAssertion',\n 'TSNonNullExpression',\n ].includes(node.type))\n ) {\n node = node.expression;\n }\n return node;\n};\n\n/**\n * Robustly finds a property in a recast ObjectExpression.\n * Handles quoted (\"key\") or unquoted (key) properties.\n */\nconst getMatchingProperty = (node: any, key: string) => {\n return node.properties.find((prop: any) => {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n if (n.Identifier.check(prop.key) && prop.key.name === key) return true;\n\n if (n.StringLiteral.check(prop.key) && prop.key.value === key)\n return true;\n\n if (n.Literal.check(prop.key) && prop.key.value === key) return true;\n }\n\n return false;\n });\n};\n\n/**\n * Synchronizes numeric suffixes across locales.\n * E.g. \"Hello 1\" -> \"Hello 3\" updates \"Bonjour 1\" to \"Bonjour 3\".\n */\nconst syncNumericSuffixAcrossLocales = (\n existingNode: any,\n fallbackLocaleCode: string,\n newFallbackValue: string\n) => {\n const trailingNumberMatch = newFallbackValue.match(/\\d+(?!.*\\d)/);\n if (!trailingNumberMatch) return;\n const newTrailingNumber = trailingNumberMatch[0];\n\n if (n.ObjectExpression.check(existingNode)) {\n for (const prop of existingNode.properties) {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n let propName = '';\n\n if (n.Identifier.check(prop.key)) propName = prop.key.name;\n else if (\n n.Literal.check(prop.key) &&\n typeof prop.key.value === 'string'\n )\n propName = prop.key.value;\n else if (n.StringLiteral.check(prop.key)) propName = prop.key.value;\n\n if (propName && propName !== fallbackLocaleCode) {\n if (\n n.Literal.check(prop.value) &&\n typeof prop.value.value === 'string'\n ) {\n const currentValue = prop.value.value;\n const currentTrailingNumberMatch =\n currentValue.match(/\\d+(?!.*\\d)/);\n\n if (currentTrailingNumberMatch) {\n prop.value = b.literal(\n currentValue.replace(/(\\d+)(?!.*\\d)/, newTrailingNumber)\n );\n }\n } else if (n.StringLiteral.check(prop.value)) {\n const currentValue = prop.value.value;\n const currentTrailingNumberMatch =\n currentValue.match(/\\d+(?!.*\\d)/);\n\n if (currentTrailingNumberMatch) {\n prop.value = b.stringLiteral(\n currentValue.replace(/(\\d+)(?!.*\\d)/, newTrailingNumber)\n );\n }\n }\n }\n }\n }\n }\n};\n\n/**\n * Checks if a value represents a multilingual Intlayer node.\n * A node is multilingual if it is a Translation node, or if it is a specialized node\n * (Markdown, HTML, etc.) that contains a Translation node.\n */\nconst isMultilingualNode = (val: any): boolean => {\n if (typeof val !== 'object' || val === null || Array.isArray(val)) {\n return false;\n }\n\n const nodeType = getNodeType(val as ContentNode);\n\n if (nodeType === NodeTypes.TRANSLATION) {\n return true;\n }\n\n if (\n nodeType === NodeTypes.MARKDOWN ||\n nodeType === NodeTypes.HTML ||\n nodeType === NodeTypes.INSERTION\n ) {\n return isMultilingualNode((val as any)[nodeType]);\n }\n\n if (\n nodeType === NodeTypes.ENUMERATION ||\n nodeType === NodeTypes.PLURAL ||\n nodeType === NodeTypes.CONDITION ||\n nodeType === NodeTypes.GENDER\n ) {\n const data = (val as any)[nodeType];\n\n if (data && typeof data === 'object') {\n return Object.values(data).some((v) => isMultilingualNode(v));\n }\n }\n\n return false;\n};\n\n/**\n * Recursively builds or updates an AST node for a given dictionary value.\n */\nconst buildNodeForValue = (\n val: any,\n existingNode: any,\n fallbackLocale: string | undefined, // In per-locale mode, this is the locale of the file\n requiredImports: Set<string>\n): any => {\n const unwrappedExisting = unwrap(existingNode);\n\n // --- CRITICAL GUARD: STRICT AST PRESERVATION ---\n // If the existing node is code (JSX, Variables, standard functions), leave it alone.\n // Only allow updates to literals, plain objects, arrays, and Intlayer helpers.\n if (unwrappedExisting) {\n const isUpdatableNode =\n n.Literal.check(unwrappedExisting) ||\n n.StringLiteral.check(unwrappedExisting) ||\n n.NumericLiteral.check(unwrappedExisting) ||\n n.BooleanLiteral.check(unwrappedExisting) ||\n n.TemplateLiteral.check(unwrappedExisting) ||\n n.ObjectExpression.check(unwrappedExisting) ||\n n.ArrayExpression.check(unwrappedExisting) ||\n (n.CallExpression.check(unwrappedExisting) &&\n n.Identifier.check(unwrappedExisting.callee) &&\n [\n 't',\n 'enu',\n 'plural',\n 'cond',\n 'gender',\n 'insert',\n 'md',\n 'html',\n 'file',\n 'nest',\n ].includes(unwrappedExisting.callee.name));\n\n if (!isUpdatableNode) {\n return existingNode;\n }\n }\n\n // If we are in per-locale mode (fallbackLocale is set)\n // and the value is not already a complex translation node,\n // we want to store it as a simple literal, NOT wrapped in t().\n if (fallbackLocale && !existingNode && !isMultilingualNode(val)) {\n if (val === null) return b.literal(null);\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n if (typeof val === 'string' && val.includes('\\n')) {\n return b.templateLiteral(\n [b.templateElement({ raw: val, cooked: val }, true)],\n []\n );\n }\n return b.literal(val);\n }\n }\n\n if (fallbackLocale && existingNode && !isMultilingualNode(val)) {\n if (\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === 't'\n ) {\n const arg = unwrap(existingNode.arguments[0]);\n\n if (n.ObjectExpression.check(arg)) {\n if (typeof val === 'string') {\n syncNumericSuffixAcrossLocales(arg, fallbackLocale, val);\n }\n updateObjectLiteral(\n arg,\n { [fallbackLocale]: val },\n fallbackLocale,\n requiredImports\n );\n\n if (!fallbackLocale) {\n requiredImports.add('t');\n }\n\n return existingNode;\n }\n }\n\n if (\n (!val || typeof val !== 'object') &&\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === 'md'\n ) {\n const innerArg = existingNode.arguments[0];\n\n if (\n n.CallExpression.check(innerArg) &&\n n.Identifier.check(innerArg.callee) &&\n innerArg.callee.name === 't'\n ) {\n const tArg = unwrap(innerArg.arguments[0]);\n\n if (n.ObjectExpression.check(tArg)) {\n if (typeof val === 'string') {\n syncNumericSuffixAcrossLocales(tArg, fallbackLocale, val);\n }\n updateObjectLiteral(\n tArg,\n { [fallbackLocale]: val },\n fallbackLocale,\n requiredImports\n );\n requiredImports.add('md');\n requiredImports.add('t');\n\n return existingNode;\n }\n }\n }\n }\n\n // 1. Primitives\n if (val === null) return b.literal(null);\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n if (unwrappedExisting) {\n // Preserve existing template literals (backticks)\n if (\n n.TemplateLiteral.check(unwrappedExisting) &&\n unwrappedExisting.expressions.length === 0\n ) {\n unwrappedExisting.quasis[0].value.raw = String(val);\n unwrappedExisting.quasis[0].value.cooked = String(val);\n return existingNode;\n }\n // Preserve existing standard literals (keeps quote styling)\n if (\n n.Literal.check(unwrappedExisting) ||\n n.StringLiteral.check(unwrappedExisting)\n ) {\n unwrappedExisting.value = val;\n return existingNode;\n }\n }\n\n // Force multiline strings to use Template Literals\n if (typeof val === 'string' && val.includes('\\n')) {\n return b.templateLiteral(\n [b.templateElement({ raw: val, cooked: val }, true)],\n []\n );\n }\n return b.literal(val);\n }\n\n // 2. Arrays\n if (Array.isArray(val)) {\n if (unwrappedExisting && n.ArrayExpression.check(unwrappedExisting)) {\n const elements = [...unwrappedExisting.elements];\n val.forEach((item, i) => {\n elements[i] = buildNodeForValue(\n item,\n elements[i],\n fallbackLocale,\n requiredImports\n );\n });\n\n if (elements.length > val.length) elements.length = val.length;\n unwrappedExisting.elements = elements as any;\n\n return existingNode;\n } else {\n return b.arrayExpression(\n val.map((item) =>\n buildNodeForValue(item, null, fallbackLocale, requiredImports)\n )\n );\n }\n }\n\n // 3. Intlayer Specialized Nodes\n const nodeType =\n val && typeof val === 'object' && !Array.isArray(val)\n ? getNodeType(val as ContentNode)\n : null;\n\n if (\n nodeType &&\n [\n NodeTypes.TRANSLATION,\n NodeTypes.ENUMERATION,\n NodeTypes.PLURAL,\n NodeTypes.CONDITION,\n NodeTypes.GENDER,\n NodeTypes.INSERTION,\n NodeTypes.MARKDOWN,\n NodeTypes.HTML,\n NodeTypes.FILE,\n NodeTypes.NESTED,\n NodeTypes.ARRAY,\n NodeTypes.OBJECT,\n NodeTypes.REACT_NODE,\n NodeTypes.NUMBER,\n NodeTypes.BOOLEAN,\n NodeTypes.NULL,\n NodeTypes.UNKNOWN,\n ].includes(nodeType as any) &&\n nodeType !== NodeTypes.TEXT\n ) {\n const nodeData = (val as any)[nodeType];\n let calleeName = '';\n\n if (nodeType === NodeTypes.TRANSLATION) calleeName = 't';\n else if (nodeType === NodeTypes.ENUMERATION) calleeName = 'enu';\n else if (nodeType === NodeTypes.PLURAL) calleeName = 'plural';\n else if (nodeType === NodeTypes.CONDITION) calleeName = 'cond';\n else if (nodeType === NodeTypes.GENDER) calleeName = 'gender';\n else if (nodeType === NodeTypes.INSERTION) calleeName = 'insert';\n else if (nodeType === NodeTypes.MARKDOWN) calleeName = 'md';\n else if (nodeType === NodeTypes.HTML) calleeName = 'html';\n else if (nodeType === NodeTypes.FILE) calleeName = 'file';\n else if (nodeType === NodeTypes.NESTED) calleeName = 'nest';\n\n if (calleeName) requiredImports.add(calleeName);\n\n const isMatchingCall =\n existingNode &&\n n.CallExpression.check(existingNode) &&\n n.Identifier.check(existingNode.callee) &&\n existingNode.callee.name === calleeName;\n\n if (['t', 'enu', 'plural', 'cond', 'gender'].includes(calleeName)) {\n let objArg: any = null;\n\n if (\n isMatchingCall &&\n existingNode.arguments.length > 0 &&\n n.ObjectExpression.check(existingNode.arguments[0])\n ) {\n objArg = existingNode.arguments[0];\n } else {\n objArg = b.objectExpression([]);\n }\n updateObjectLiteral(objArg, nodeData, fallbackLocale, requiredImports);\n\n return isMatchingCall\n ? existingNode\n : b.callExpression(b.identifier(calleeName), [objArg]);\n }\n\n if (['md', 'html', 'insert', 'file'].includes(calleeName)) {\n const argNode = buildNodeForValue(\n nodeData,\n isMatchingCall && existingNode.arguments.length > 0\n ? existingNode.arguments[0]\n : null,\n fallbackLocale,\n requiredImports\n );\n\n if (isMatchingCall) {\n existingNode.arguments[0] = argNode;\n\n return existingNode;\n }\n\n return b.callExpression(b.identifier(calleeName), [argNode]);\n }\n\n if (calleeName === 'nest') {\n const args = [b.literal(nodeData.dictionaryKey)];\n\n if (nodeData.path) args.push(b.literal(nodeData.path));\n\n if (isMatchingCall) {\n existingNode.arguments = args;\n\n return existingNode;\n }\n\n return b.callExpression(b.identifier('nest'), args);\n }\n }\n\n // 4. Plain Object\n const objNode =\n unwrappedExisting && n.ObjectExpression.check(unwrappedExisting)\n ? unwrappedExisting\n : b.objectExpression([]);\n\n updateObjectLiteral(objNode, val, fallbackLocale, requiredImports);\n\n return existingNode && unwrappedExisting === existingNode\n ? objNode\n : existingNode || objNode;\n};\n\n/**\n * Recursively updates the AST object literal properties.\n */\nconst updateObjectLiteral = (\n node: recast.types.namedTypes.ObjectExpression,\n data: Record<string, any>,\n fallbackLocale: string | undefined,\n requiredImports: Set<string>\n) => {\n for (const [key, val] of Object.entries(data)) {\n if (val === undefined) continue;\n\n const existingProp = getMatchingProperty(node, key);\n\n if (existingProp) {\n existingProp.value = buildNodeForValue(\n val,\n existingProp.value,\n fallbackLocale,\n requiredImports\n );\n } else {\n const isValidId = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key);\n const keyNode = isValidId ? b.identifier(key) : b.literal(key);\n const valueNode = buildNodeForValue(\n val,\n null,\n fallbackLocale,\n requiredImports\n );\n node.properties.push(b.property('init', keyNode, valueNode));\n }\n }\n};\n\n/**\n * Modifies the AST's top-level imports to inject dynamically needed helper utilities seamlessly.\n */\nconst addImports = (ast: any, requiredImports: Set<string>, isESM: boolean) => {\n if (requiredImports.size === 0) return;\n\n const existingCoreImports = new Set<string>();\n let coreImportPath: any = null;\n\n recast.visit(ast, {\n visitImportDeclaration(path) {\n const source = path.node.source.value;\n\n if (source === 'intlayer') {\n coreImportPath = path;\n path.node.specifiers?.forEach((spec) => {\n if (\n n.ImportSpecifier.check(spec) &&\n typeof spec.imported.name === 'string'\n ) {\n existingCoreImports.add(spec.imported.name);\n }\n });\n }\n\n return false;\n },\n visitVariableDeclaration(path) {\n path.node.declarations.forEach((decl) => {\n if (\n n.VariableDeclarator.check(decl) &&\n n.CallExpression.check(decl.init) &&\n n.Identifier.check(decl.init.callee) &&\n decl.init.callee.name === 'require'\n ) {\n const arg = decl.init.arguments[0];\n\n if (n.Literal.check(arg)) {\n if (arg.value === 'intlayer') {\n if (n.ObjectPattern.check(decl.id)) {\n decl.id.properties.forEach((prop) => {\n if (\n n.Property.check(prop) &&\n (n.Identifier.check(prop.key) ||\n n.Identifier.check(prop.value))\n ) {\n const name = n.Identifier.check(prop.key)\n ? prop.key.name\n : (prop.value as any).name;\n existingCoreImports.add(name);\n }\n });\n } else if (n.Identifier.check(decl.id)) {\n // Handle const intlayer = require('intlayer')\n existingCoreImports.add(decl.id.name);\n }\n }\n }\n }\n });\n\n return false;\n },\n });\n\n const missingCore = Array.from(requiredImports).filter(\n (imp) => !existingCoreImports.has(imp)\n );\n\n if (missingCore.length === 0) return;\n\n if (isESM) {\n if (coreImportPath) {\n missingCore.forEach((imp) => {\n coreImportPath.node.specifiers.push(\n b.importSpecifier(b.identifier(imp))\n );\n });\n coreImportPath.node.specifiers.sort((a: any, b: any) =>\n a.imported.name.localeCompare(b.imported.name)\n );\n } else {\n const specifiers = missingCore\n .sort()\n .map((imp) => b.importSpecifier(b.identifier(imp)));\n const newImport = b.importDeclaration(specifiers, b.literal('intlayer'));\n ast.program.body.unshift(newImport);\n }\n } else {\n let insertIndex = 0;\n\n if (\n ast.program.body.length > 0 &&\n n.ExpressionStatement.check(ast.program.body[0]) &&\n n.Literal.check(ast.program.body[0].expression)\n ) {\n insertIndex = 1; // Insert after 'use strict'\n }\n const cjsLines: any[] = [];\n\n const properties = missingCore.sort().map((imp) => {\n const prop = b.property('init', b.identifier(imp), b.identifier(imp));\n prop.shorthand = true;\n\n return prop;\n });\n cjsLines.push(\n b.variableDeclaration('const', [\n b.variableDeclarator(\n b.objectPattern(properties),\n b.callExpression(b.identifier('require'), [b.literal('intlayer')])\n ),\n ])\n );\n\n ast.program.body.splice(insertIndex, 0, ...cjsLines);\n }\n};\n\n/**\n * Updates a JS/TS file seamlessly to map new localization keys, arrays, complex nodes and nested dictionaries gracefully using AST updates via Recast parser.\n */\nexport const transformJSFile = async (\n fileContent: string,\n dictionary: Dictionary,\n fallbackLocale?: Locale,\n noMetadata?: boolean\n): Promise<string> => {\n if (!dictionary || typeof dictionary !== 'object') return fileContent;\n\n let ast: any;\n try {\n ast = recast.parse(fileContent, {\n parser: babelTsParser,\n });\n } catch (error) {\n console.error({ error });\n return fileContent;\n }\n\n let rootObject: any = null;\n let isESM = false;\n\n recast.visit(ast, {\n visitExportDefaultDeclaration() {\n isESM = true;\n\n return false;\n },\n visitImportDeclaration() {\n isESM = true;\n\n return false;\n },\n });\n\n recast.visit(ast, {\n visitExportDefaultDeclaration(path) {\n const decl = path.node.declaration;\n const unwrappedDecl = unwrap(decl);\n\n if (n.ObjectExpression.check(unwrappedDecl)) {\n rootObject = unwrappedDecl;\n } else if (n.Identifier.check(unwrappedDecl)) {\n const varName = unwrappedDecl.name;\n recast.visit(ast, {\n visitVariableDeclarator(vp) {\n const unwrappedInit = unwrap(vp.node.init);\n\n if (\n n.Identifier.check(vp.node.id) &&\n vp.node.id.name === varName &&\n n.ObjectExpression.check(unwrappedInit)\n ) {\n rootObject = unwrappedInit;\n }\n\n return false;\n },\n });\n }\n\n return false;\n },\n visitAssignmentExpression(path) {\n const left = path.node.left;\n\n if (n.MemberExpression.check(left)) {\n if (\n n.Identifier.check(left.object) &&\n left.object.name === 'module' &&\n n.Identifier.check(left.property) &&\n left.property.name === 'exports'\n ) {\n const unwrappedRight = unwrap(path.node.right);\n\n if (n.ObjectExpression.check(unwrappedRight)) {\n rootObject = unwrappedRight;\n }\n }\n\n if (\n n.Identifier.check(left.object) &&\n left.object.name === 'exports' &&\n n.Identifier.check(left.property) &&\n left.property.name === 'default'\n ) {\n const unwrappedRight = unwrap(path.node.right);\n\n if (n.ObjectExpression.check(unwrappedRight)) {\n rootObject = unwrappedRight;\n }\n }\n }\n this.traverse(path);\n },\n });\n\n if (!rootObject) {\n recast.visit(ast, {\n visitVariableDeclarator(path) {\n const unwrappedInit = unwrap(path.node.init);\n\n if (!rootObject && n.ObjectExpression.check(unwrappedInit)) {\n rootObject = unwrappedInit;\n }\n\n return false;\n },\n });\n }\n\n if (!rootObject) return fileContent;\n\n const requiredImports = new Set<string>();\n const effectiveFallbackLocale = (fallbackLocale as string) ?? 'en';\n\n const metadataProperties = [\n 'id',\n 'locale',\n 'filled',\n 'fill',\n 'title',\n 'description',\n 'tags',\n 'version',\n 'priority',\n 'contentAutoTransformation',\n ];\n\n if (noMetadata) {\n // Remove key, content and metadata properties if they exist\n rootObject.properties = rootObject.properties.filter((prop: any) => {\n if (n.Property.check(prop) || n.ObjectProperty.check(prop)) {\n let propName = '';\n if (n.Identifier.check(prop.key)) propName = prop.key.name;\n else if (n.StringLiteral.check(prop.key)) propName = prop.key.value;\n else if (n.Literal.check(prop.key)) propName = String(prop.key.value);\n\n return !['key', 'content', ...metadataProperties].includes(propName);\n }\n return true;\n });\n\n // Update satisfies type if exists\n recast.visit(ast, {\n visitNode(path) {\n const node = path.node;\n if (\n (n.TSSatisfiesExpression?.check(node) ||\n node.type === 'TSSatisfiesExpression') &&\n (node as any).typeAnnotation &&\n n.TSTypeReference.check((node as any).typeAnnotation) &&\n n.Identifier.check((node as any).typeAnnotation.typeName) &&\n (node as any).typeAnnotation.typeName.name === 'Dictionary'\n ) {\n (node as any).typeAnnotation = b.tsIndexedAccessType(\n b.tsTypeReference(b.identifier('Dictionary')),\n b.tsLiteralType(b.stringLiteral('content'))\n );\n }\n this.traverse(path);\n },\n });\n } else {\n for (const prop of metadataProperties) {\n if ((dictionary as any)[prop] !== undefined) {\n updateObjectLiteral(\n rootObject,\n { [prop]: (dictionary as any)[prop] },\n undefined,\n requiredImports\n );\n }\n }\n }\n\n if (dictionary.content !== undefined) {\n updateObjectLiteral(\n rootObject,\n noMetadata\n ? (dictionary.content as Record<string, any>)\n : { content: dictionary.content },\n effectiveFallbackLocale,\n requiredImports\n );\n }\n\n addImports(ast, requiredImports, isESM);\n\n return recast.print(ast).code;\n};\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import * as _$_intlayer_types_config0 from "@intlayer/types/config";
1
+ import * as _$_intlayer_types0 from "@intlayer/types";
2
2
 
3
3
  //#region src/createDictionaryEntryPoint/createDictionaryEntryPoint.d.ts
4
4
  type CreateDictionaryEntryPointOptions = {
@@ -8,7 +8,7 @@ type CreateDictionaryEntryPointOptions = {
8
8
  /**
9
9
  * This function generates a list of dictionaries in the main directory
10
10
  */
11
- declare const createDictionaryEntryPoint: (configuration?: _$_intlayer_types_config0.IntlayerConfig, options?: CreateDictionaryEntryPointOptions) => Promise<void>;
11
+ declare const createDictionaryEntryPoint: (configuration?: _$_intlayer_types0.IntlayerConfig, options?: CreateDictionaryEntryPointOptions) => Promise<void>;
12
12
  //#endregion
13
13
  export { CreateDictionaryEntryPointOptions, createDictionaryEntryPoint };
14
14
  //# sourceMappingURL=createDictionaryEntryPoint.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createDictionaryEntryPoint.d.ts","names":[],"sources":["../../../src/createDictionaryEntryPoint/createDictionaryEntryPoint.ts"],"mappings":";;;KAuCY,iCAAA;EACV,OAAA;EACA,WAAA;AAAA;;;;cAMW,0BAAA,GACX,aAAA,GAkFD,yBAAA,CAlFC,cAAA,EACA,OAAA,GAAS,iCAAA,KAAsC,OAAA"}
1
+ {"version":3,"file":"createDictionaryEntryPoint.d.ts","names":[],"sources":["../../../src/createDictionaryEntryPoint/createDictionaryEntryPoint.ts"],"mappings":";;;KAuCY,iCAAA;EACV,OAAA;EACA,WAAA;AAAA;;;;cAMW,0BAAA,GACX,aAAA,GAkFD,kBAAA,CAlFC,cAAA,EACA,OAAA,GAAS,iCAAA,KAAsC,OAAA"}
@@ -1,10 +1,10 @@
1
- import * as _$_intlayer_types_config0 from "@intlayer/types/config";
1
+ import * as _$_intlayer_types0 from "@intlayer/types";
2
2
 
3
3
  //#region src/createDictionaryEntryPoint/generateDictionaryListContent.d.ts
4
4
  /**
5
5
  * This function generates the content of the dictionary list file
6
6
  */
7
- declare const generateDictionaryListContent: (dictionaries: string[], functionName: string, importType: "json" | "javascript", format?: "cjs" | "esm", configuration?: _$_intlayer_types_config0.IntlayerConfig) => string;
7
+ declare const generateDictionaryListContent: (dictionaries: string[], functionName: string, importType: "json" | "javascript", format?: "cjs" | "esm", configuration?: _$_intlayer_types0.IntlayerConfig) => string;
8
8
  //#endregion
9
9
  export { generateDictionaryListContent };
10
10
  //# sourceMappingURL=generateDictionaryListContent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generateDictionaryListContent.d.ts","names":[],"sources":["../../../src/createDictionaryEntryPoint/generateDictionaryListContent.ts"],"mappings":";;;;;;cAQa,6BAAA,GACX,YAAA,YACA,YAAA,UACA,UAAA,yBACA,MAAA,kBACA,aAAA,GA0CD,yBAAA,CA1CC,cAAA"}
1
+ {"version":3,"file":"generateDictionaryListContent.d.ts","names":[],"sources":["../../../src/createDictionaryEntryPoint/generateDictionaryListContent.ts"],"mappings":";;;;;;cAQa,6BAAA,GACX,YAAA,YACA,YAAA,UACA,UAAA,yBACA,MAAA,kBACA,aAAA,GA0CD,kBAAA,CA1CC,cAAA"}
@@ -1,6 +1,5 @@
1
- import { LocalesValues } from "./intlayer/dist/types/index.js";
2
- import * as _$_intlayer_types_dictionary0 from "@intlayer/types/dictionary";
3
1
  import { Dictionary } from "@intlayer/types/dictionary";
2
+ import * as _$_intlayer_types0 from "@intlayer/types";
4
3
  import * as _$_intlayer_core_messageFormat0 from "@intlayer/core/messageFormat";
5
4
 
6
5
  //#region src/formatDictionary.d.ts
@@ -10,48 +9,48 @@ declare const formatDictionaryOutput: (dictionary: Dictionary, format: Dictionar
10
9
  format: string;
11
10
  content: _$_intlayer_core_messageFormat0.JsonValue;
12
11
  $schema?: "https://intlayer.org/schema.json";
13
- id?: _$_intlayer_types_dictionary0.DictionaryId;
12
+ id?: _$_intlayer_types0.DictionaryId;
14
13
  projectIds?: string[];
15
- localId?: _$_intlayer_types_dictionary0.LocalDictionaryId;
16
- localIds?: _$_intlayer_types_dictionary0.LocalDictionaryId[];
17
- key: _$_intlayer_types_dictionary0.DictionaryKey;
14
+ localId?: _$_intlayer_types0.LocalDictionaryId;
15
+ localIds?: _$_intlayer_types0.LocalDictionaryId[];
16
+ key: _$_intlayer_types0.DictionaryKey;
18
17
  title?: string;
19
18
  description?: string;
20
19
  versions?: string[];
21
20
  version?: string;
22
21
  filePath?: string;
23
22
  tags?: string[];
24
- locale?: LocalesValues;
25
- contentAutoTransformation?: _$_intlayer_types_dictionary0.ContentAutoTransformation;
26
- fill?: _$_intlayer_types_dictionary0.Fill;
23
+ locale?: _$_intlayer_types0.LocalesValues;
24
+ contentAutoTransformation?: _$_intlayer_types0.ContentAutoTransformation;
25
+ fill?: _$_intlayer_types0.Fill;
27
26
  filled?: true;
28
27
  priority?: number;
29
- importMode?: _$_intlayer_types_dictionary0.ImportMode;
30
- location?: _$_intlayer_types_dictionary0.DictionaryLocation;
28
+ importMode?: _$_intlayer_types0.ImportMode;
29
+ location?: _$_intlayer_types0.DictionaryLocation;
31
30
  schema: undefined;
32
31
  };
33
32
  declare const formatDictionariesOutput: (dictionaries: Dictionary[], format: Dictionary["format"]) => (Dictionary | {
34
33
  format: string;
35
34
  content: _$_intlayer_core_messageFormat0.JsonValue;
36
35
  $schema?: "https://intlayer.org/schema.json";
37
- id?: _$_intlayer_types_dictionary0.DictionaryId;
36
+ id?: _$_intlayer_types0.DictionaryId;
38
37
  projectIds?: string[];
39
- localId?: _$_intlayer_types_dictionary0.LocalDictionaryId;
40
- localIds?: _$_intlayer_types_dictionary0.LocalDictionaryId[];
41
- key: _$_intlayer_types_dictionary0.DictionaryKey;
38
+ localId?: _$_intlayer_types0.LocalDictionaryId;
39
+ localIds?: _$_intlayer_types0.LocalDictionaryId[];
40
+ key: _$_intlayer_types0.DictionaryKey;
42
41
  title?: string;
43
42
  description?: string;
44
43
  versions?: string[];
45
44
  version?: string;
46
45
  filePath?: string;
47
46
  tags?: string[];
48
- locale?: LocalesValues;
49
- contentAutoTransformation?: _$_intlayer_types_dictionary0.ContentAutoTransformation;
50
- fill?: _$_intlayer_types_dictionary0.Fill;
47
+ locale?: _$_intlayer_types0.LocalesValues;
48
+ contentAutoTransformation?: _$_intlayer_types0.ContentAutoTransformation;
49
+ fill?: _$_intlayer_types0.Fill;
51
50
  filled?: true;
52
51
  priority?: number;
53
- importMode?: _$_intlayer_types_dictionary0.ImportMode;
54
- location?: _$_intlayer_types_dictionary0.DictionaryLocation;
52
+ importMode?: _$_intlayer_types0.ImportMode;
53
+ location?: _$_intlayer_types0.DictionaryLocation;
55
54
  schema: undefined;
56
55
  })[];
57
56
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"formatDictionary.d.ts","names":[],"sources":["../../src/formatDictionary.ts"],"mappings":";;;;;;cAUa,gBAAA,GAAoB,UAAA,EAAY,UAAA,KAAa,UAAA;AAAA,cA4B7C,kBAAA,GACX,YAAA,EAAc,UAAA,OACb,OAAA,CAAQ,UAAA;AAAA,cAEE,sBAAA,GACX,UAAA,EAAY,UAAA,EACZ,MAAA,EAAQ,UAAA,eAAoB,UAAA;;WAAA,+BAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;cA6BjB,wBAAA,GACX,YAAA,EAAc,UAAA,IACd,MAAA,EAAQ,UAAA,gBAAoB,UAAA;;WAAA,+BAAA,CAAA,SAAA"}
1
+ {"version":3,"file":"formatDictionary.d.ts","names":[],"sources":["../../src/formatDictionary.ts"],"mappings":";;;;;cAUa,gBAAA,GAAoB,UAAA,EAAY,UAAA,KAAa,UAAA;AAAA,cA4B7C,kBAAA,GACX,YAAA,EAAc,UAAA,OACb,OAAA,CAAQ,UAAA;AAAA,cAEE,sBAAA,GACX,UAAA,EAAY,UAAA,EACZ,MAAA,EAAQ,UAAA,eAAoB,UAAA;;WAAA,+BAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;cA6BjB,wBAAA,GACX,YAAA,EAAc,UAAA,IACd,MAAA,EAAQ,UAAA,gBAAoB,UAAA;;WAAA,+BAAA,CAAA,SAAA"}
@@ -1,11 +1,11 @@
1
1
  import { DictionariesStatus } from "./loadDictionaries.js";
2
- import * as _$_intlayer_types_config0 from "@intlayer/types/config";
3
2
  import { Dictionary } from "@intlayer/types/dictionary";
3
+ import * as _$_intlayer_types0 from "@intlayer/types";
4
4
  import { DictionaryAPI } from "@intlayer/backend";
5
5
 
6
6
  //#region src/loadDictionaries/loadRemoteDictionaries.d.ts
7
7
  declare const formatDistantDictionaries: (dictionaries: (DictionaryAPI | Dictionary)[]) => Dictionary[];
8
- declare const loadRemoteDictionaries: (configuration?: _$_intlayer_types_config0.IntlayerConfig, onStatusUpdate?: (status: DictionariesStatus[]) => void, options?: {
8
+ declare const loadRemoteDictionaries: (configuration?: _$_intlayer_types0.IntlayerConfig, onStatusUpdate?: (status: DictionariesStatus[]) => void, options?: {
9
9
  onStartRemoteCheck?: () => void;
10
10
  onStopRemoteCheck?: () => void;
11
11
  onError?: (error: Error) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"loadRemoteDictionaries.d.ts","names":[],"sources":["../../../src/loadDictionaries/loadRemoteDictionaries.ts"],"mappings":";;;;;;cAUa,yBAAA,GACX,YAAA,GAAe,aAAA,GAAgB,UAAA,QAC9B,UAAA;AAAA,cAOU,sBAAA,GACX,aAAA,GAqID,yBAAA,CArIC,cAAA,EACA,cAAA,IAAkB,MAAA,EAAQ,kBAAA,aAC1B,OAAA;EACE,kBAAA;EACA,iBAAA;EACA,OAAA,IAAW,KAAA,EAAO,KAAA;AAAA,MAEnB,OAAA,CAAQ,UAAA"}
1
+ {"version":3,"file":"loadRemoteDictionaries.d.ts","names":[],"sources":["../../../src/loadDictionaries/loadRemoteDictionaries.ts"],"mappings":";;;;;;cAUa,yBAAA,GACX,YAAA,GAAe,aAAA,GAAgB,UAAA,QAC9B,UAAA;AAAA,cAOU,sBAAA,GACX,aAAA,GAqID,kBAAA,CArIC,cAAA,EACA,cAAA,IAAkB,MAAA,EAAQ,kBAAA,aAC1B,OAAA;EACE,kBAAA;EACA,iBAAA;EACA,OAAA,IAAW,KAAA,EAAO,KAAA;AAAA,MAEnB,OAAA,CAAQ,UAAA"}
@@ -1,4 +1,7 @@
1
1
  //#region src/utils/getPathHash.d.ts
2
+ /**
3
+ * Fast hashing using cyrb53 algorithm for small unique strings with low collisions risk
4
+ */
2
5
  declare const getPathHash: (filePath: string) => string;
3
6
  //#endregion
4
7
  export { getPathHash };
@@ -1 +1 @@
1
- {"version":3,"file":"getPathHash.d.ts","names":[],"sources":["../../../src/utils/getPathHash.ts"],"mappings":";cAAa,WAAA,GAAe,QAAA"}
1
+ {"version":3,"file":"getPathHash.d.ts","names":[],"sources":["../../../src/utils/getPathHash.ts"],"mappings":";;AAGA;;cAAa,WAAA,GAAe,QAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"watcher.d.ts","names":[],"sources":["../../src/watcher.ts"],"mappings":";;;;;;KAwDK,YAAA,GAAe,eAAA;EAClB,aAAA,GAAgB,cAAA;EAChB,aAAA,GAAgB,uBAAA;EAChB,WAAA;AAAA;AAAA,cAIW,KAAA,GAAS,OAAA,GAAU,YAAA,KAAY,UAAA,CAAA,SAAA;AAAA,cA6J/B,qBAAA,GAA+B,OAAA,GAAU,YAAA,KAAY,OAAA"}
1
+ {"version":3,"file":"watcher.d.ts","names":[],"sources":["../../src/watcher.ts"],"mappings":";;;;;;KAyDK,YAAA,GAAe,eAAA;EAClB,aAAA,GAAgB,cAAA;EAChB,aAAA,GAAgB,uBAAA;EAChB,WAAA;AAAA;AAAA,cAIW,KAAA,GAAS,OAAA,GAAU,YAAA,KAAY,UAAA,CAAA,SAAA;AAAA,cA8K/B,qBAAA,GAA+B,OAAA,GAAU,YAAA,KAAY,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"transformJSFile.d.ts","names":[],"sources":["../../../src/writeContentDeclaration/transformJSFile.ts"],"mappings":";;;;;;AA8lBA;cAAa,eAAA,GACX,WAAA,UACA,UAAA,EAAY,UAAA,EACZ,cAAA,GAAiB,MAAA,EACjB,UAAA,eACC,OAAA"}
1
+ {"version":3,"file":"transformJSFile.d.ts","names":[],"sources":["../../../src/writeContentDeclaration/transformJSFile.ts"],"mappings":";;;;;;AAkmBA;cAAa,eAAA,GACX,WAAA,UACA,UAAA,EAAY,UAAA,EACZ,cAAA,GAAiB,MAAA,EACjB,UAAA,eACC,OAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlayer/chokidar",
3
- "version": "8.7.14",
3
+ "version": "8.8.0",
4
4
  "private": false,
5
5
  "description": "Uses chokidar to scan and build Intlayer declaration files into dictionaries based on Intlayer configuration.",
6
6
  "keywords": [
@@ -109,13 +109,13 @@
109
109
  "typecheck": "tsc --noEmit --project tsconfig.types.json"
110
110
  },
111
111
  "dependencies": {
112
- "@intlayer/api": "8.7.14",
113
- "@intlayer/config": "8.7.14",
114
- "@intlayer/core": "8.7.14",
115
- "@intlayer/dictionaries-entry": "8.7.14",
116
- "@intlayer/remote-dictionaries-entry": "8.7.14",
117
- "@intlayer/types": "8.7.14",
118
- "@intlayer/unmerged-dictionaries-entry": "8.7.14",
112
+ "@intlayer/api": "8.8.0",
113
+ "@intlayer/config": "8.8.0",
114
+ "@intlayer/core": "8.8.0",
115
+ "@intlayer/dictionaries-entry": "8.8.0",
116
+ "@intlayer/remote-dictionaries-entry": "8.8.0",
117
+ "@intlayer/types": "8.8.0",
118
+ "@intlayer/unmerged-dictionaries-entry": "8.8.0",
119
119
  "chokidar": "3.6.0",
120
120
  "defu": "6.1.7",
121
121
  "fast-glob": "3.3.3",
@@ -1,3 +0,0 @@
1
- import { Dictionary } from "@intlayer/types/dictionary";
2
- import { LocalesValues as LocalesValues$1 } from "@intlayer/types/module_augmentation";
3
- export { type LocalesValues$1 as LocalesValues };