@intlayer/core 9.2.0 → 9.3.1

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 (216) hide show
  1. package/README.md +24 -24
  2. package/dist/cjs/_virtual/_rolldown/runtime.cjs +1 -2
  3. package/dist/cjs/deepTransformPlugins/getEditedContent.cjs +10 -6
  4. package/dist/cjs/deepTransformPlugins/getEditedContent.cjs.map +1 -1
  5. package/dist/cjs/deepTransformPlugins/getReplacedValuesContent.cjs +2 -1
  6. package/dist/cjs/deepTransformPlugins/getReplacedValuesContent.cjs.map +1 -1
  7. package/dist/cjs/deepTransformPlugins/insertContentInDictionary.cjs +41 -32
  8. package/dist/cjs/deepTransformPlugins/insertContentInDictionary.cjs.map +1 -1
  9. package/dist/cjs/dictionaryManipulator/editDictionaryByKeyPath.cjs +6 -5
  10. package/dist/cjs/dictionaryManipulator/editDictionaryByKeyPath.cjs.map +1 -1
  11. package/dist/cjs/dictionaryManipulator/getNestedDictionaryReferences.cjs +153 -0
  12. package/dist/cjs/dictionaryManipulator/getNestedDictionaryReferences.cjs.map +1 -0
  13. package/dist/cjs/dictionaryManipulator/index.cjs +16 -9
  14. package/dist/cjs/dictionaryManipulator/mergeDictionaries.cjs +4 -3
  15. package/dist/cjs/dictionaryManipulator/mergeDictionaries.cjs.map +1 -1
  16. package/dist/cjs/dictionaryManipulator/mergeQualifiedDictionaries.cjs +4 -3
  17. package/dist/cjs/dictionaryManipulator/mergeQualifiedDictionaries.cjs.map +1 -1
  18. package/dist/cjs/dictionaryManipulator/qualifiedDictionary.cjs +1 -171
  19. package/dist/cjs/dictionaryManipulator/qualifiedDictionary.cjs.map +1 -1
  20. package/dist/cjs/dictionaryManipulator/qualifiedDictionary.test-d.cjs.map +1 -1
  21. package/dist/cjs/dictionaryManipulator/qualifiedDictionaryDeclaration.cjs +69 -0
  22. package/dist/cjs/dictionaryManipulator/qualifiedDictionaryDeclaration.cjs.map +1 -0
  23. package/dist/cjs/dictionaryManipulator/qualifiedDynamicLoader.cjs +115 -0
  24. package/dist/cjs/dictionaryManipulator/qualifiedDynamicLoader.cjs.map +1 -0
  25. package/dist/cjs/dictionaryManipulator/removeContentNodeByKeyPath.cjs +4 -2
  26. package/dist/cjs/dictionaryManipulator/removeContentNodeByKeyPath.cjs.map +1 -1
  27. package/dist/cjs/dictionaryManipulator/renameContentNodeByKeyPath.cjs +11 -9
  28. package/dist/cjs/dictionaryManipulator/renameContentNodeByKeyPath.cjs.map +1 -1
  29. package/dist/cjs/formatters/date.cjs +2 -1
  30. package/dist/cjs/formatters/date.cjs.map +1 -1
  31. package/dist/cjs/formatters/relativeTime.cjs +3 -3
  32. package/dist/cjs/formatters/relativeTime.cjs.map +1 -1
  33. package/dist/cjs/index.cjs +16 -9
  34. package/dist/cjs/interpreter/getCondition.cjs +0 -1
  35. package/dist/cjs/interpreter/getCondition.cjs.map +1 -1
  36. package/dist/cjs/interpreter/getContent/plugins.cjs +12 -1
  37. package/dist/cjs/interpreter/getContent/plugins.cjs.map +1 -1
  38. package/dist/cjs/interpreter/getDictionary.cjs +2 -1
  39. package/dist/cjs/interpreter/getDictionary.cjs.map +1 -1
  40. package/dist/cjs/interpreter/getEnumeration.cjs +0 -1
  41. package/dist/cjs/interpreter/getEnumeration.cjs.map +1 -1
  42. package/dist/cjs/interpreter/getGender.cjs +0 -1
  43. package/dist/cjs/interpreter/getGender.cjs.map +1 -1
  44. package/dist/cjs/interpreter/getHTML.cjs +0 -1
  45. package/dist/cjs/interpreter/getHTML.cjs.map +1 -1
  46. package/dist/cjs/interpreter/getInsertion.cjs +0 -1
  47. package/dist/cjs/interpreter/getInsertion.cjs.map +1 -1
  48. package/dist/cjs/interpreter/getIntlayer.cjs.map +1 -1
  49. package/dist/cjs/interpreter/getIntlayer.test-d.cjs.map +1 -1
  50. package/dist/cjs/interpreter/getNesting.optimized.cjs +59 -0
  51. package/dist/cjs/interpreter/getNesting.optimized.cjs.map +1 -0
  52. package/dist/cjs/interpreter/getSelect.cjs +0 -1
  53. package/dist/cjs/interpreter/getSelect.cjs.map +1 -1
  54. package/dist/cjs/interpreter/getTranslation.cjs +0 -1
  55. package/dist/cjs/interpreter/getTranslation.cjs.map +1 -1
  56. package/dist/cjs/interpreter/splitAndJoinInsertion.cjs +0 -1
  57. package/dist/cjs/interpreter/splitAndJoinInsertion.cjs.map +1 -1
  58. package/dist/cjs/localization/domainUtils.cjs +0 -1
  59. package/dist/cjs/localization/domainUtils.cjs.map +1 -1
  60. package/dist/cjs/localization/getBrowserLocale.cjs +2 -1
  61. package/dist/cjs/localization/getBrowserLocale.cjs.map +1 -1
  62. package/dist/cjs/localization/getHTMLTextDir.cjs +0 -1
  63. package/dist/cjs/localization/getHTMLTextDir.cjs.map +1 -1
  64. package/dist/cjs/localization/getLocale.cjs +2 -1
  65. package/dist/cjs/localization/getLocale.cjs.map +1 -1
  66. package/dist/cjs/localization/getLocaleLang.cjs +0 -1
  67. package/dist/cjs/localization/getLocaleLang.cjs.map +1 -1
  68. package/dist/cjs/localization/localeDetector.cjs +2 -1
  69. package/dist/cjs/localization/localeDetector.cjs.map +1 -1
  70. package/dist/cjs/localization/proxyMode.cjs.map +1 -1
  71. package/dist/cjs/localization/rewriteUtils.cjs +0 -1
  72. package/dist/cjs/localization/rewriteUtils.cjs.map +1 -1
  73. package/dist/cjs/markdown/compiler.cjs +9 -6
  74. package/dist/cjs/markdown/compiler.cjs.map +1 -1
  75. package/dist/cjs/markdown/constants.cjs +0 -1
  76. package/dist/cjs/markdown/constants.cjs.map +1 -1
  77. package/dist/cjs/markdown/utils.cjs.map +1 -1
  78. package/dist/cjs/messageFormat/ICU.cjs +17 -14
  79. package/dist/cjs/messageFormat/ICU.cjs.map +1 -1
  80. package/dist/cjs/messageFormat/i18next.cjs +4 -2
  81. package/dist/cjs/messageFormat/i18next.cjs.map +1 -1
  82. package/dist/cjs/messageFormat/navigatePath.cjs +0 -1
  83. package/dist/cjs/messageFormat/navigatePath.cjs.map +1 -1
  84. package/dist/cjs/messageFormat/resolveMessage.cjs +2 -1
  85. package/dist/cjs/messageFormat/resolveMessage.cjs.map +1 -1
  86. package/dist/cjs/messageFormat/verify-icu-format.cjs +3 -2
  87. package/dist/cjs/messageFormat/verify-icu-format.cjs.map +1 -1
  88. package/dist/cjs/messageFormat/vue-i18n.cjs +2 -1
  89. package/dist/cjs/messageFormat/vue-i18n.cjs.map +1 -1
  90. package/dist/cjs/transpiler/condition/condition.cjs.map +1 -1
  91. package/dist/cjs/transpiler/enumeration/enumeration.cjs.map +1 -1
  92. package/dist/cjs/transpiler/file/file.cjs +2 -1
  93. package/dist/cjs/transpiler/file/file.cjs.map +1 -1
  94. package/dist/cjs/transpiler/file/fileBrowser.cjs +0 -1
  95. package/dist/cjs/transpiler/file/fileBrowser.cjs.map +1 -1
  96. package/dist/cjs/transpiler/gender/gender.cjs.map +1 -1
  97. package/dist/cjs/transpiler/html/getHTMLCustomComponents.cjs +0 -1
  98. package/dist/cjs/transpiler/html/getHTMLCustomComponents.cjs.map +1 -1
  99. package/dist/cjs/transpiler/html/html.cjs.map +1 -1
  100. package/dist/cjs/transpiler/html/htmlTags.cjs +0 -1
  101. package/dist/cjs/transpiler/html/htmlTags.cjs.map +1 -1
  102. package/dist/cjs/transpiler/html/validateHTML.cjs +12 -12
  103. package/dist/cjs/transpiler/html/validateHTML.cjs.map +1 -1
  104. package/dist/cjs/transpiler/insertion/getInsertionValues.cjs +0 -1
  105. package/dist/cjs/transpiler/insertion/getInsertionValues.cjs.map +1 -1
  106. package/dist/cjs/transpiler/insertion/insertion.cjs.map +1 -1
  107. package/dist/cjs/transpiler/markdown/getMarkdownMetadata.cjs +2 -1
  108. package/dist/cjs/transpiler/markdown/getMarkdownMetadata.cjs.map +1 -1
  109. package/dist/cjs/transpiler/markdown/markdown.cjs +2 -1
  110. package/dist/cjs/transpiler/markdown/markdown.cjs.map +1 -1
  111. package/dist/cjs/transpiler/markdown/validateMarkdown.cjs +7 -6
  112. package/dist/cjs/transpiler/markdown/validateMarkdown.cjs.map +1 -1
  113. package/dist/cjs/transpiler/nesting/nesting.cjs.map +1 -1
  114. package/dist/cjs/transpiler/plural/plural.cjs.map +1 -1
  115. package/dist/cjs/transpiler/select/select.cjs.map +1 -1
  116. package/dist/cjs/transpiler/translation/translation.cjs.map +1 -1
  117. package/dist/cjs/utils/checkIsURLAbsolute.cjs +0 -1
  118. package/dist/cjs/utils/checkIsURLAbsolute.cjs.map +1 -1
  119. package/dist/cjs/utils/cookieExpiry.cjs +0 -1
  120. package/dist/cjs/utils/cookieExpiry.cjs.map +1 -1
  121. package/dist/cjs/utils/getCookie.cjs +0 -1
  122. package/dist/cjs/utils/getCookie.cjs.map +1 -1
  123. package/dist/cjs/utils/isSameKeyPath.cjs +0 -1
  124. package/dist/cjs/utils/isSameKeyPath.cjs.map +1 -1
  125. package/dist/cjs/utils/isValidReactElement.cjs +0 -1
  126. package/dist/cjs/utils/isValidReactElement.cjs.map +1 -1
  127. package/dist/cjs/utils/parseYaml.cjs +0 -1
  128. package/dist/cjs/utils/parseYaml.cjs.map +1 -1
  129. package/dist/cjs/utils/stringifyYaml.cjs +0 -1
  130. package/dist/cjs/utils/stringifyYaml.cjs.map +1 -1
  131. package/dist/esm/deepTransformPlugins/getEditedContent.mjs +10 -6
  132. package/dist/esm/deepTransformPlugins/getEditedContent.mjs.map +1 -1
  133. package/dist/esm/deepTransformPlugins/getReplacedValuesContent.mjs +2 -1
  134. package/dist/esm/deepTransformPlugins/getReplacedValuesContent.mjs.map +1 -1
  135. package/dist/esm/deepTransformPlugins/insertContentInDictionary.mjs +41 -32
  136. package/dist/esm/deepTransformPlugins/insertContentInDictionary.mjs.map +1 -1
  137. package/dist/esm/dictionaryManipulator/editDictionaryByKeyPath.mjs +6 -5
  138. package/dist/esm/dictionaryManipulator/editDictionaryByKeyPath.mjs.map +1 -1
  139. package/dist/esm/dictionaryManipulator/getNestedDictionaryReferences.mjs +150 -0
  140. package/dist/esm/dictionaryManipulator/getNestedDictionaryReferences.mjs.map +1 -0
  141. package/dist/esm/dictionaryManipulator/index.mjs +5 -2
  142. package/dist/esm/dictionaryManipulator/mergeDictionaries.mjs +4 -3
  143. package/dist/esm/dictionaryManipulator/mergeDictionaries.mjs.map +1 -1
  144. package/dist/esm/dictionaryManipulator/mergeQualifiedDictionaries.mjs +2 -1
  145. package/dist/esm/dictionaryManipulator/mergeQualifiedDictionaries.mjs.map +1 -1
  146. package/dist/esm/dictionaryManipulator/qualifiedDictionary.mjs +1 -162
  147. package/dist/esm/dictionaryManipulator/qualifiedDictionary.mjs.map +1 -1
  148. package/dist/esm/dictionaryManipulator/qualifiedDictionaryDeclaration.mjs +64 -0
  149. package/dist/esm/dictionaryManipulator/qualifiedDictionaryDeclaration.mjs.map +1 -0
  150. package/dist/esm/dictionaryManipulator/qualifiedDynamicLoader.mjs +111 -0
  151. package/dist/esm/dictionaryManipulator/qualifiedDynamicLoader.mjs.map +1 -0
  152. package/dist/esm/dictionaryManipulator/removeContentNodeByKeyPath.mjs +4 -2
  153. package/dist/esm/dictionaryManipulator/removeContentNodeByKeyPath.mjs.map +1 -1
  154. package/dist/esm/dictionaryManipulator/renameContentNodeByKeyPath.mjs +11 -9
  155. package/dist/esm/dictionaryManipulator/renameContentNodeByKeyPath.mjs.map +1 -1
  156. package/dist/esm/formatters/date.mjs +2 -1
  157. package/dist/esm/formatters/date.mjs.map +1 -1
  158. package/dist/esm/formatters/relativeTime.mjs +3 -3
  159. package/dist/esm/formatters/relativeTime.mjs.map +1 -1
  160. package/dist/esm/index.mjs +5 -2
  161. package/dist/esm/interpreter/getContent/plugins.mjs +12 -1
  162. package/dist/esm/interpreter/getContent/plugins.mjs.map +1 -1
  163. package/dist/esm/interpreter/getDictionary.mjs +2 -1
  164. package/dist/esm/interpreter/getDictionary.mjs.map +1 -1
  165. package/dist/esm/interpreter/getNesting.optimized.mjs +58 -0
  166. package/dist/esm/interpreter/getNesting.optimized.mjs.map +1 -0
  167. package/dist/esm/localization/getBrowserLocale.mjs +2 -1
  168. package/dist/esm/localization/getBrowserLocale.mjs.map +1 -1
  169. package/dist/esm/localization/getLocale.mjs +2 -1
  170. package/dist/esm/localization/getLocale.mjs.map +1 -1
  171. package/dist/esm/localization/localeDetector.mjs +2 -1
  172. package/dist/esm/localization/localeDetector.mjs.map +1 -1
  173. package/dist/esm/markdown/compiler.mjs +9 -6
  174. package/dist/esm/markdown/compiler.mjs.map +1 -1
  175. package/dist/esm/markdown/utils.mjs.map +1 -1
  176. package/dist/esm/messageFormat/ICU.mjs +17 -14
  177. package/dist/esm/messageFormat/ICU.mjs.map +1 -1
  178. package/dist/esm/messageFormat/i18next.mjs +4 -2
  179. package/dist/esm/messageFormat/i18next.mjs.map +1 -1
  180. package/dist/esm/messageFormat/resolveMessage.mjs +2 -1
  181. package/dist/esm/messageFormat/resolveMessage.mjs.map +1 -1
  182. package/dist/esm/messageFormat/verify-icu-format.mjs +3 -2
  183. package/dist/esm/messageFormat/verify-icu-format.mjs.map +1 -1
  184. package/dist/esm/messageFormat/vue-i18n.mjs +2 -1
  185. package/dist/esm/messageFormat/vue-i18n.mjs.map +1 -1
  186. package/dist/esm/transpiler/file/file.mjs +2 -1
  187. package/dist/esm/transpiler/file/file.mjs.map +1 -1
  188. package/dist/esm/transpiler/html/validateHTML.mjs +12 -11
  189. package/dist/esm/transpiler/html/validateHTML.mjs.map +1 -1
  190. package/dist/esm/transpiler/markdown/getMarkdownMetadata.mjs +2 -1
  191. package/dist/esm/transpiler/markdown/getMarkdownMetadata.mjs.map +1 -1
  192. package/dist/esm/transpiler/markdown/markdown.mjs +2 -1
  193. package/dist/esm/transpiler/markdown/markdown.mjs.map +1 -1
  194. package/dist/esm/transpiler/markdown/validateMarkdown.mjs +7 -6
  195. package/dist/esm/transpiler/markdown/validateMarkdown.mjs.map +1 -1
  196. package/dist/esm/utils/parseYaml.mjs.map +1 -1
  197. package/dist/types/deepTransformPlugins/getEditedContent.d.ts.map +1 -1
  198. package/dist/types/deepTransformPlugins/getFilterMissingTranslationsContent.d.ts +1 -0
  199. package/dist/types/deepTransformPlugins/getFilterTranslationsOnlyContent.d.ts +1 -0
  200. package/dist/types/deepTransformPlugins/getFilteredLocalesContent.d.ts +1 -0
  201. package/dist/types/dictionaryManipulator/getNestedDictionaryReferences.d.ts +62 -0
  202. package/dist/types/dictionaryManipulator/getNestedDictionaryReferences.d.ts.map +1 -0
  203. package/dist/types/dictionaryManipulator/index.d.ts +5 -2
  204. package/dist/types/dictionaryManipulator/mergeQualifiedDictionaries.d.ts.map +1 -1
  205. package/dist/types/dictionaryManipulator/qualifiedDictionary.d.ts +18 -126
  206. package/dist/types/dictionaryManipulator/qualifiedDictionary.d.ts.map +1 -1
  207. package/dist/types/dictionaryManipulator/qualifiedDictionaryDeclaration.d.ts +41 -0
  208. package/dist/types/dictionaryManipulator/qualifiedDictionaryDeclaration.d.ts.map +1 -0
  209. package/dist/types/dictionaryManipulator/qualifiedDynamicLoader.d.ts +93 -0
  210. package/dist/types/dictionaryManipulator/qualifiedDynamicLoader.d.ts.map +1 -0
  211. package/dist/types/index.d.ts +5 -2
  212. package/dist/types/interpreter/getContent/plugins.d.ts +10 -0
  213. package/dist/types/interpreter/getContent/plugins.d.ts.map +1 -1
  214. package/dist/types/interpreter/getNesting.optimized.d.ts +33 -0
  215. package/dist/types/interpreter/getNesting.optimized.d.ts.map +1 -0
  216. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"parseYaml.cjs","names":[],"sources":["../../../src/utils/parseYaml.ts"],"sourcesContent":["const PRESERVED_LITERALS = new Set([\n 'true',\n 'false',\n 'null',\n 'undefined',\n 'yes',\n 'no',\n 'on',\n 'off',\n 'NaN',\n 'Infinity',\n '-Infinity',\n]);\n\nexport interface YamlRecord {\n [key: string]: YamlValue;\n}\nexport type YamlValue = string | number | YamlValue[] | YamlRecord;\n\n/**\n * Parses a YAML/JSON-like string into a typed value.\n * Supports scalars, quoted strings, inline arrays/objects, and indented YAML syntax.\n * Boolean/null literals (true, false, null, yes, no, etc.) are preserved as strings,\n * not coerced to their native JS equivalents.\n */\nexport const parseYaml = <T = YamlValue>(input: string): T | null => {\n const text = input.trim();\n\n if (!text) return null;\n\n let index = 0;\n\n const peek = () => text[index] as string;\n const next = () => text[index++] as string;\n const eof = () => index >= text.length;\n\n const skipWhitespace = () => {\n while (!eof() && ' \\n\\t\\r'.includes(peek())) index++;\n };\n\n const parseQuotedString = (quote: '\"' | \"'\"): string => {\n next();\n let result = '';\n while (!eof()) {\n const ch = next();\n\n if (ch === quote) return result;\n\n if (ch === '\\\\' && !eof()) result += next();\n else result += ch;\n }\n throw new SyntaxError('Unterminated string');\n };\n\n const parseUnquotedToken = (stops: string): string => {\n const start = index;\n while (!eof() && !stops.includes(peek())) index++;\n return text.slice(start, index).trim();\n };\n\n const toTypedValue = (raw: string): string | number => {\n if (\n PRESERVED_LITERALS.has(raw) ||\n /^0x[0-9a-fA-F]+$/.test(raw) ||\n /^#/.test(raw)\n ) {\n return raw;\n }\n\n if (/^-?\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?$/i.test(raw)) {\n // 3.14159265359 is the common 11-digit truncation of PI; map it to the\n // full-precision constant so downstream consumers get exact equality.\n if (raw === '3.14159265359') return Math.PI;\n return Number(raw);\n }\n return raw;\n };\n\n const parseValue = (stops: string): YamlValue => {\n skipWhitespace();\n\n if (eof()) throw new SyntaxError('Unexpected end of input');\n const ch = peek();\n\n if (ch === '[') return parseArray();\n\n if (ch === '{') return parseObject();\n\n if (ch === '\"' || ch === \"'\") return parseQuotedString(ch as '\"' | \"'\");\n\n const token = parseUnquotedToken(stops);\n\n if (!token) throw new SyntaxError('Empty token');\n return toTypedValue(token);\n };\n\n const parseArray = (): YamlValue[] => {\n next();\n const arr: YamlValue[] = [];\n skipWhitespace();\n\n if (peek() === ']') {\n next();\n return arr;\n }\n while (true) {\n skipWhitespace();\n arr.push(parseValue(',]'));\n skipWhitespace();\n\n const ch = next();\n\n if (ch === ']') break;\n\n if (ch !== ',')\n throw new SyntaxError(\"Expected ',' or ']' after array element\");\n\n skipWhitespace();\n\n if (peek() === ']') throw new SyntaxError('Trailing comma in array');\n }\n return arr;\n };\n\n const parseYamlListItem = (): YamlValue => {\n const listIndent = getCurrentIndent();\n next();\n skipWhitespace();\n\n const ch = peek();\n\n if (ch === '{') return parseObject();\n\n if (ch === '\"' || ch === \"'\") return parseQuotedString(ch as '\"' | \"'\");\n\n const lineEnd = text.indexOf('\\n', index);\n const line = text.slice(index, lineEnd === -1 ? text.length : lineEnd);\n\n if (/:/.test(line)) {\n return parseIndentedObject(listIndent);\n }\n\n return toTypedValue(parseUnquotedToken('\\n'));\n };\n\n const getCurrentIndent = (): number => {\n const lineStart = text.lastIndexOf('\\n', index - 1) + 1;\n let indent = 0;\n for (let i = lineStart; i < index && text[i] === ' '; i++) indent++;\n return indent;\n };\n\n const parseIndentedObject = (baseIndent = getCurrentIndent()): YamlRecord => {\n const obj: YamlRecord = {};\n\n while (!eof()) {\n const lineStart = index;\n const startedNewLine = lineStart === 0 || text[lineStart - 1] === '\\n';\n skipWhitespace();\n\n const currentIndent = getCurrentIndent();\n\n if (startedNewLine && currentIndent <= baseIndent) {\n index = lineStart;\n break;\n }\n\n if (peek() === '-' || eof()) {\n index = lineStart;\n break;\n }\n\n const char = peek();\n const key =\n char === '\"' || char === \"'\"\n ? parseQuotedString(char as '\"' | \"'\")\n : parseUnquotedToken(':');\n\n if (eof() || next() !== ':') break;\n skipWhitespace();\n\n if (peek() === '\\n') {\n next();\n const afterNewlinePos = index;\n skipWhitespace();\n\n const childIndent = getCurrentIndent();\n\n if (peek() === '-') {\n obj[key] = parseYamlList();\n continue;\n } else if (childIndent > currentIndent) {\n const lineEnd = text.indexOf('\\n', index);\n const line = text.slice(\n index,\n lineEnd === -1 ? text.length : lineEnd\n );\n if (/:/.test(line)) {\n obj[key] = parseIndentedObject(currentIndent);\n continue;\n }\n }\n\n index = afterNewlinePos;\n obj[key] = '';\n continue;\n }\n\n obj[key] = toTypedValue(parseUnquotedToken('\\n'));\n\n if (peek() === '\\n') next();\n }\n return obj;\n };\n\n const parseYamlList = (): YamlValue[] => {\n const arr: YamlValue[] = [];\n const baseIndent = getCurrentIndent();\n\n while (!eof()) {\n while (!eof() && ' \\n\\t\\r'.includes(peek()) && peek() !== '-') next();\n\n if (eof() || getCurrentIndent() < baseIndent || peek() !== '-') break;\n arr.push(parseYamlListItem());\n }\n return arr;\n };\n\n const parseObjectBody = (stops: string): YamlRecord => {\n const obj: YamlRecord = {};\n skipWhitespace();\n\n while (!eof() && !stops.includes(peek())) {\n const char = peek();\n const key =\n char === '\"' || char === \"'\"\n ? parseQuotedString(char as '\"' | \"'\")\n : parseUnquotedToken(`:\\n${stops}`);\n\n if (!key) return obj;\n\n if (eof() || next() !== ':')\n throw new SyntaxError(\"Expected ':' after key\");\n\n if (peek() === ' ') next();\n while (!eof() && ' \\t'.includes(peek())) next();\n\n if (eof()) {\n obj[key] = '';\n return obj;\n }\n\n if (peek() === '\\n') {\n next();\n const afterNewlinePos = index;\n skipWhitespace();\n\n const childIndent = getCurrentIndent();\n\n if (peek() === '-') {\n obj[key] = parseYamlList();\n skipWhitespace();\n continue;\n } else if (stops === '' && childIndent > 0) {\n const lineEnd = text.indexOf('\\n', index);\n const line = text.slice(\n index,\n lineEnd === -1 ? text.length : lineEnd\n );\n if (/:/.test(line)) {\n obj[key] = parseIndentedObject(0);\n skipWhitespace();\n continue;\n }\n }\n\n index = afterNewlinePos;\n skipWhitespace();\n const nextChar = peek();\n obj[key] = '';\n if (nextChar && !stops.includes(nextChar) && nextChar !== '-') continue;\n return obj;\n }\n\n obj[key] = parseValue(stops.includes('}') ? `,\\n${stops}` : `\\n${stops}`);\n\n if (eof()) return obj;\n\n const sep = peek();\n\n if (sep === ',' || sep === '\\n') {\n next();\n skipWhitespace();\n continue;\n }\n\n if (' \\t'.includes(sep)) {\n while (!eof() && ' \\t'.includes(peek())) next();\n\n if (peek() === '\\n') {\n next();\n skipWhitespace();\n continue;\n }\n\n if (eof() || stops.includes(peek())) return obj;\n continue;\n }\n\n if (stops.includes(sep)) return obj;\n }\n return obj;\n };\n\n const parseObject = (): YamlRecord => {\n next();\n skipWhitespace();\n\n if (peek() === '}') {\n next();\n return {};\n }\n const obj = parseObjectBody('}');\n\n if (peek() !== '}') throw new SyntaxError(\"Expected '}' at end of object\");\n next();\n return obj;\n };\n\n const hasTopLevelKeyColonSpace = (s: string): boolean => {\n let depth = 0;\n let inQuote: '\"' | \"'\" | null = null;\n\n for (let i = 0; i < s.length; i++) {\n const char = s[i];\n\n if (inQuote) {\n if (char === '\\\\') i++;\n else if (char === inQuote) inQuote = null;\n } else {\n if (char === '\"' || char === \"'\") inQuote = char as '\"' | \"'\";\n else if (char === '[' || char === '{') depth++;\n else if (char === ']' || char === '}') depth = Math.max(0, depth - 1);\n else if (depth === 0 && char === ':') {\n const nextCh = s[i + 1];\n\n if (!nextCh || ' \\n'.includes(nextCh)) return true;\n }\n }\n }\n return false;\n };\n\n if (text.startsWith(']') || text.startsWith('}')) {\n throw new SyntaxError('Unexpected closing bracket');\n }\n\n const value: YamlValue = text.startsWith('[')\n ? parseArray()\n : text.startsWith('{')\n ? parseObject()\n : hasTopLevelKeyColonSpace(text)\n ? parseObjectBody('')\n : parseValue('');\n\n skipWhitespace();\n\n if (!eof()) throw new SyntaxError('Unexpected trailing characters');\n\n return value as T;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"parseYaml.cjs","names":[],"sources":["../../../src/utils/parseYaml.ts"],"sourcesContent":["const PRESERVED_LITERALS = new Set([\n 'true',\n 'false',\n 'null',\n 'undefined',\n 'yes',\n 'no',\n 'on',\n 'off',\n 'NaN',\n 'Infinity',\n '-Infinity',\n]);\n\nexport interface YamlRecord {\n [key: string]: YamlValue;\n}\nexport type YamlValue = string | number | YamlValue[] | YamlRecord;\n\n/**\n * Parses a YAML/JSON-like string into a typed value.\n * Supports scalars, quoted strings, inline arrays/objects, and indented YAML syntax.\n * Boolean/null literals (true, false, null, yes, no, etc.) are preserved as strings,\n * not coerced to their native JS equivalents.\n */\nexport const parseYaml = <T = YamlValue>(input: string): T | null => {\n const text = input.trim();\n\n if (!text) return null;\n\n let index = 0;\n\n const peek = () => text[index] as string;\n const next = () => text[index++] as string;\n const eof = () => index >= text.length;\n\n const skipWhitespace = () => {\n while (!eof() && ' \\n\\t\\r'.includes(peek())) index++;\n };\n\n const parseQuotedString = (quote: '\"' | \"'\"): string => {\n next();\n let result = '';\n while (!eof()) {\n const ch = next();\n\n if (ch === quote) return result;\n\n if (ch === '\\\\' && !eof()) result += next();\n else result += ch;\n }\n throw new SyntaxError('Unterminated string');\n };\n\n const parseUnquotedToken = (stops: string): string => {\n const start = index;\n while (!eof() && !stops.includes(peek())) index++;\n return text.slice(start, index).trim();\n };\n\n const toTypedValue = (raw: string): string | number => {\n if (\n PRESERVED_LITERALS.has(raw) ||\n /^0x[0-9a-fA-F]+$/.test(raw) ||\n /^#/.test(raw)\n ) {\n return raw;\n }\n\n if (/^-?\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?$/i.test(raw)) {\n // 3.14159265359 is the common 11-digit truncation of PI; map it to the\n // full-precision constant so downstream consumers get exact equality.\n if (raw === '3.14159265359') return Math.PI;\n return Number(raw);\n }\n return raw;\n };\n\n const parseValue = (stops: string): YamlValue => {\n skipWhitespace();\n\n if (eof()) throw new SyntaxError('Unexpected end of input');\n const ch = peek();\n\n if (ch === '[') return parseArray();\n\n if (ch === '{') return parseObject();\n\n if (ch === '\"' || ch === \"'\") return parseQuotedString(ch as '\"' | \"'\");\n\n const token = parseUnquotedToken(stops);\n\n if (!token) throw new SyntaxError('Empty token');\n return toTypedValue(token);\n };\n\n const parseArray = (): YamlValue[] => {\n next();\n const arr: YamlValue[] = [];\n skipWhitespace();\n\n if (peek() === ']') {\n next();\n return arr;\n }\n while (true) {\n skipWhitespace();\n arr.push(parseValue(',]'));\n skipWhitespace();\n\n const ch = next();\n\n if (ch === ']') break;\n\n if (ch !== ',')\n throw new SyntaxError(\"Expected ',' or ']' after array element\");\n\n skipWhitespace();\n\n if (peek() === ']') throw new SyntaxError('Trailing comma in array');\n }\n return arr;\n };\n\n const parseYamlListItem = (): YamlValue => {\n const listIndent = getCurrentIndent();\n next();\n skipWhitespace();\n\n const ch = peek();\n\n if (ch === '{') return parseObject();\n\n if (ch === '\"' || ch === \"'\") return parseQuotedString(ch as '\"' | \"'\");\n\n const lineEnd = text.indexOf('\\n', index);\n const line = text.slice(index, lineEnd === -1 ? text.length : lineEnd);\n\n if (/:/.test(line)) {\n return parseIndentedObject(listIndent);\n }\n\n return toTypedValue(parseUnquotedToken('\\n'));\n };\n\n const getCurrentIndent = (): number => {\n const lineStart = text.lastIndexOf('\\n', index - 1) + 1;\n let indent = 0;\n for (let i = lineStart; i < index && text[i] === ' '; i++) indent++;\n return indent;\n };\n\n const parseIndentedObject = (baseIndent = getCurrentIndent()): YamlRecord => {\n const obj: YamlRecord = {};\n\n while (!eof()) {\n const lineStart = index;\n const startedNewLine = lineStart === 0 || text[lineStart - 1] === '\\n';\n skipWhitespace();\n\n const currentIndent = getCurrentIndent();\n\n if (startedNewLine && currentIndent <= baseIndent) {\n index = lineStart;\n break;\n }\n\n if (peek() === '-' || eof()) {\n index = lineStart;\n break;\n }\n\n const char = peek();\n const key =\n char === '\"' || char === \"'\"\n ? parseQuotedString(char as '\"' | \"'\")\n : parseUnquotedToken(':');\n\n if (eof() || next() !== ':') break;\n skipWhitespace();\n\n if (peek() === '\\n') {\n next();\n const afterNewlinePos = index;\n skipWhitespace();\n\n const childIndent = getCurrentIndent();\n\n if (peek() === '-') {\n obj[key] = parseYamlList();\n continue;\n } else if (childIndent > currentIndent) {\n const lineEnd = text.indexOf('\\n', index);\n const line = text.slice(\n index,\n lineEnd === -1 ? text.length : lineEnd\n );\n if (/:/.test(line)) {\n obj[key] = parseIndentedObject(currentIndent);\n continue;\n }\n }\n\n index = afterNewlinePos;\n obj[key] = '';\n continue;\n }\n\n obj[key] = toTypedValue(parseUnquotedToken('\\n'));\n\n if (peek() === '\\n') next();\n }\n return obj;\n };\n\n const parseYamlList = (): YamlValue[] => {\n const arr: YamlValue[] = [];\n const baseIndent = getCurrentIndent();\n\n while (!eof()) {\n while (!eof() && ' \\n\\t\\r'.includes(peek()) && peek() !== '-') next();\n\n if (eof() || getCurrentIndent() < baseIndent || peek() !== '-') break;\n arr.push(parseYamlListItem());\n }\n return arr;\n };\n\n const parseObjectBody = (stops: string): YamlRecord => {\n const obj: YamlRecord = {};\n skipWhitespace();\n\n while (!eof() && !stops.includes(peek())) {\n const char = peek();\n const key =\n char === '\"' || char === \"'\"\n ? parseQuotedString(char as '\"' | \"'\")\n : parseUnquotedToken(`:\\n${stops}`);\n\n if (!key) return obj;\n\n if (eof() || next() !== ':')\n throw new SyntaxError(\"Expected ':' after key\");\n\n if (peek() === ' ') next();\n while (!eof() && ' \\t'.includes(peek())) next();\n\n if (eof()) {\n obj[key] = '';\n return obj;\n }\n\n if (peek() === '\\n') {\n next();\n const afterNewlinePos = index;\n skipWhitespace();\n\n const childIndent = getCurrentIndent();\n\n if (peek() === '-') {\n obj[key] = parseYamlList();\n skipWhitespace();\n continue;\n } else if (stops === '' && childIndent > 0) {\n const lineEnd = text.indexOf('\\n', index);\n const line = text.slice(\n index,\n lineEnd === -1 ? text.length : lineEnd\n );\n if (/:/.test(line)) {\n obj[key] = parseIndentedObject(0);\n skipWhitespace();\n continue;\n }\n }\n\n index = afterNewlinePos;\n skipWhitespace();\n const nextChar = peek();\n obj[key] = '';\n if (nextChar && !stops.includes(nextChar) && nextChar !== '-') continue;\n return obj;\n }\n\n obj[key] = parseValue(stops.includes('}') ? `,\\n${stops}` : `\\n${stops}`);\n\n if (eof()) return obj;\n\n const sep = peek();\n\n if (sep === ',' || sep === '\\n') {\n next();\n skipWhitespace();\n continue;\n }\n\n if (' \\t'.includes(sep)) {\n while (!eof() && ' \\t'.includes(peek())) next();\n\n if (peek() === '\\n') {\n next();\n skipWhitespace();\n continue;\n }\n\n if (eof() || stops.includes(peek())) return obj;\n continue;\n }\n\n if (stops.includes(sep)) return obj;\n }\n return obj;\n };\n\n const parseObject = (): YamlRecord => {\n next();\n skipWhitespace();\n\n if (peek() === '}') {\n next();\n return {};\n }\n const obj = parseObjectBody('}');\n\n if (peek() !== '}') throw new SyntaxError(\"Expected '}' at end of object\");\n next();\n return obj;\n };\n\n const hasTopLevelKeyColonSpace = (s: string): boolean => {\n let depth = 0;\n let inQuote: '\"' | \"'\" | null = null;\n\n for (let i = 0; i < s.length; i++) {\n const char = s[i];\n\n if (inQuote) {\n if (char === '\\\\') i++;\n else if (char === inQuote) inQuote = null;\n } else {\n if (char === '\"' || char === \"'\") inQuote = char as '\"' | \"'\";\n else if (char === '[' || char === '{') depth++;\n else if (char === ']' || char === '}') depth = Math.max(0, depth - 1);\n else if (depth === 0 && char === ':') {\n const nextCh = s[i + 1];\n\n if (!nextCh || ' \\n'.includes(nextCh)) return true;\n }\n }\n }\n return false;\n };\n\n if (text.startsWith(']') || text.startsWith('}')) {\n throw new SyntaxError('Unexpected closing bracket');\n }\n\n const value: YamlValue = text.startsWith('[')\n ? parseArray()\n : text.startsWith('{')\n ? parseObject()\n : hasTopLevelKeyColonSpace(text)\n ? parseObjectBody('')\n : parseValue('');\n\n skipWhitespace();\n\n if (!eof()) throw new SyntaxError('Unexpected trailing characters');\n\n return value as T;\n};\n"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
-
3
2
  //#region src/utils/stringifyYaml.ts
4
3
  const NEEDS_QUOTING = /[\n\r\t#:{}[\],&*?|<>=!%@`'"\\]|^[-?!]|\s$|^\s|^[>|]|^[.]{2,}/;
5
4
  const PRESERVED_LITERALS = /* @__PURE__ */ new Set([
@@ -1 +1 @@
1
- {"version":3,"file":"stringifyYaml.cjs","names":[],"sources":["../../../src/utils/stringifyYaml.ts"],"sourcesContent":["// Characters/patterns in a string that require quoting in YAML\nconst NEEDS_QUOTING =\n /[\\n\\r\\t#:{}[\\],&*?|<>=!%@`'\"\\\\]|^[-?!]|\\s$|^\\s|^[>|]|^[.]{2,}/;\n\n// Values that parseYaml treats as preserved literals (not typed conversions)\nconst PRESERVED_LITERALS = new Set([\n 'true',\n 'false',\n 'null',\n 'undefined',\n 'yes',\n 'no',\n 'on',\n 'off',\n 'NaN',\n 'Infinity',\n '-Infinity',\n]);\n\nconst serializeString = (value: string, indent: string): string => {\n if (value.includes('\\n')) {\n const lines = value.split('\\n');\n const body = lines.map((l) => `${indent} ${l}`).join('\\n');\n return `|\\n${body}`;\n }\n\n if (\n NEEDS_QUOTING.test(value) ||\n PRESERVED_LITERALS.has(value) ||\n /^-?\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?$/i.test(value)\n ) {\n return JSON.stringify(value);\n }\n\n return value;\n};\n\nconst serializeValue = (value: any, indent: string): string => {\n if (value === null || value === undefined) return 'null';\n\n if (typeof value === 'boolean' || typeof value === 'number') {\n return String(value);\n }\n\n if (typeof value === 'string') {\n return serializeString(value, indent);\n }\n\n if (Array.isArray(value)) {\n if (value.length === 0) return '[]';\n return value\n .map((item) => {\n const serialized = serializeValue(item, `${indent} `);\n if (\n typeof item === 'object' &&\n item !== null &&\n !Array.isArray(item) &&\n !serialized.startsWith(\"'\") &&\n !serialized.startsWith('\"')\n ) {\n // Object items: put first key inline with the dash\n const lines = serialized.split('\\n');\n return `${indent}- ${lines[0]}\\n${lines\n .slice(1)\n .map((l) => `${indent} ${l}`)\n .join('\\n')}`.trimEnd();\n }\n return `${indent}- ${serialized}`;\n })\n .join('\\n');\n }\n\n if (typeof value === 'object') {\n const entries = Object.entries(value).filter(([, v]) => v !== undefined);\n if (entries.length === 0) return '{}';\n\n return entries\n .map(([k, value]) => {\n const key = /[\\s:{}[\\]]/.test(k) ? JSON.stringify(k) : k;\n const childIndent = `${indent} `;\n\n if (value === null || value === undefined) {\n return `${indent}${key}: null`;\n }\n\n if (typeof value === 'object' && !Array.isArray(value)) {\n const nested = serializeValue(value, childIndent);\n return `${indent}${key}:\\n${nested}`;\n }\n\n if (Array.isArray(value)) {\n if (value.length === 0) return `${indent}${key}: []`;\n const nested = serializeValue(value, childIndent);\n return `${indent}${key}:\\n${nested}`;\n }\n\n return `${indent}${key}: ${serializeValue(value, indent)}`;\n })\n .join('\\n');\n }\n\n return String(value);\n};\n\nexport const stringifyYaml = (value: any): string =>\n `${serializeValue(value, '')}\\n`;\n"],"mappings":";;;AACA,MAAM,gBACJ;AAGF,MAAM,qCAAqB,IAAI,IAAI;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,mBAAmB,OAAe,WAA2B;CACjE,IAAI,MAAM,SAAS,IAAI,GAGrB,OAAO,MAFO,MAAM,MAAM,IACT,CAAC,CAAC,KAAK,MAAM,GAAG,OAAO,IAAI,GAAG,CAAC,CAAC,KAAK,IACtC;CAGlB,IACE,cAAc,KAAK,KAAK,KACxB,mBAAmB,IAAI,KAAK,KAC5B,mCAAmC,KAAK,KAAK,GAE7C,OAAO,KAAK,UAAU,KAAK;CAG7B,OAAO;AACT;AAEA,MAAM,kBAAkB,OAAY,WAA2B;CAC7D,IAAI,UAAU,QAAQ,UAAU,QAAW,OAAO;CAElD,IAAI,OAAO,UAAU,aAAa,OAAO,UAAU,UACjD,OAAO,OAAO,KAAK;CAGrB,IAAI,OAAO,UAAU,UACnB,OAAO,gBAAgB,OAAO,MAAM;CAGtC,IAAI,MAAM,QAAQ,KAAK,GAAG;EACxB,IAAI,MAAM,WAAW,GAAG,OAAO;EAC/B,OAAO,MACJ,KAAK,SAAS;GACb,MAAM,aAAa,eAAe,MAAM,GAAG,OAAO,GAAG;GACrD,IACE,OAAO,SAAS,YAChB,SAAS,QACT,CAAC,MAAM,QAAQ,IAAI,KACnB,CAAC,WAAW,WAAW,GAAG,KAC1B,CAAC,WAAW,WAAW,IAAG,GAC1B;IAEA,MAAM,QAAQ,WAAW,MAAM,IAAI;IACnC,OAAO,GAAG,OAAO,IAAI,MAAM,GAAG,IAAI,MAC/B,MAAM,CAAC,CAAC,CACR,KAAK,MAAM,GAAG,OAAO,IAAI,GAAG,CAAC,CAC7B,KAAK,IAAI,IAAI,QAAQ;GAC1B;GACA,OAAO,GAAG,OAAO,IAAI;EACvB,CAAC,CAAC,CACD,KAAK,IAAI;CACd;CAEA,IAAI,OAAO,UAAU,UAAU;EAC7B,MAAM,UAAU,OAAO,QAAQ,KAAK,CAAC,CAAC,QAAQ,GAAG,OAAO,MAAM,MAAS;EACvE,IAAI,QAAQ,WAAW,GAAG,OAAO;EAEjC,OAAO,QACJ,KAAK,CAAC,GAAG,WAAW;GACnB,MAAM,MAAM,aAAa,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI;GACvD,MAAM,cAAc,GAAG,OAAO;GAE9B,IAAI,UAAU,QAAQ,UAAU,QAC9B,OAAO,GAAG,SAAS,IAAI;GAGzB,IAAI,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAEnD,OAAO,GAAG,SAAS,IAAI,KADR,eAAe,OAAO,WACJ;GAGnC,IAAI,MAAM,QAAQ,KAAK,GAAG;IACxB,IAAI,MAAM,WAAW,GAAG,OAAO,GAAG,SAAS,IAAI;IAE/C,OAAO,GAAG,SAAS,IAAI,KADR,eAAe,OAAO,WACJ;GACnC;GAEA,OAAO,GAAG,SAAS,IAAI,IAAI,eAAe,OAAO,MAAM;EACzD,CAAC,CAAC,CACD,KAAK,IAAI;CACd;CAEA,OAAO,OAAO,KAAK;AACrB;AAEA,MAAa,iBAAiB,UAC5B,GAAG,eAAe,OAAO,EAAE,EAAE"}
1
+ {"version":3,"file":"stringifyYaml.cjs","names":[],"sources":["../../../src/utils/stringifyYaml.ts"],"sourcesContent":["// Characters/patterns in a string that require quoting in YAML\nconst NEEDS_QUOTING =\n /[\\n\\r\\t#:{}[\\],&*?|<>=!%@`'\"\\\\]|^[-?!]|\\s$|^\\s|^[>|]|^[.]{2,}/;\n\n// Values that parseYaml treats as preserved literals (not typed conversions)\nconst PRESERVED_LITERALS = new Set([\n 'true',\n 'false',\n 'null',\n 'undefined',\n 'yes',\n 'no',\n 'on',\n 'off',\n 'NaN',\n 'Infinity',\n '-Infinity',\n]);\n\nconst serializeString = (value: string, indent: string): string => {\n if (value.includes('\\n')) {\n const lines = value.split('\\n');\n const body = lines.map((l) => `${indent} ${l}`).join('\\n');\n return `|\\n${body}`;\n }\n\n if (\n NEEDS_QUOTING.test(value) ||\n PRESERVED_LITERALS.has(value) ||\n /^-?\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?$/i.test(value)\n ) {\n return JSON.stringify(value);\n }\n\n return value;\n};\n\nconst serializeValue = (value: any, indent: string): string => {\n if (value === null || value === undefined) return 'null';\n\n if (typeof value === 'boolean' || typeof value === 'number') {\n return String(value);\n }\n\n if (typeof value === 'string') {\n return serializeString(value, indent);\n }\n\n if (Array.isArray(value)) {\n if (value.length === 0) return '[]';\n return value\n .map((item) => {\n const serialized = serializeValue(item, `${indent} `);\n if (\n typeof item === 'object' &&\n item !== null &&\n !Array.isArray(item) &&\n !serialized.startsWith(\"'\") &&\n !serialized.startsWith('\"')\n ) {\n // Object items: put first key inline with the dash\n const lines = serialized.split('\\n');\n return `${indent}- ${lines[0]}\\n${lines\n .slice(1)\n .map((l) => `${indent} ${l}`)\n .join('\\n')}`.trimEnd();\n }\n return `${indent}- ${serialized}`;\n })\n .join('\\n');\n }\n\n if (typeof value === 'object') {\n const entries = Object.entries(value).filter(([, v]) => v !== undefined);\n if (entries.length === 0) return '{}';\n\n return entries\n .map(([k, value]) => {\n const key = /[\\s:{}[\\]]/.test(k) ? JSON.stringify(k) : k;\n const childIndent = `${indent} `;\n\n if (value === null || value === undefined) {\n return `${indent}${key}: null`;\n }\n\n if (typeof value === 'object' && !Array.isArray(value)) {\n const nested = serializeValue(value, childIndent);\n return `${indent}${key}:\\n${nested}`;\n }\n\n if (Array.isArray(value)) {\n if (value.length === 0) return `${indent}${key}: []`;\n const nested = serializeValue(value, childIndent);\n return `${indent}${key}:\\n${nested}`;\n }\n\n return `${indent}${key}: ${serializeValue(value, indent)}`;\n })\n .join('\\n');\n }\n\n return String(value);\n};\n\nexport const stringifyYaml = (value: any): string =>\n `${serializeValue(value, '')}\\n`;\n"],"mappings":";;AACA,MAAM,gBACJ;AAGF,MAAM,qCAAqB,IAAI,IAAI;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,mBAAmB,OAAe,WAA2B;CACjE,IAAI,MAAM,SAAS,IAAI,GAGrB,OAAO,MAFO,MAAM,MAAM,IACT,CAAC,CAAC,KAAK,MAAM,GAAG,OAAO,IAAI,GAAG,CAAC,CAAC,KAAK,IACtC;CAGlB,IACE,cAAc,KAAK,KAAK,KACxB,mBAAmB,IAAI,KAAK,KAC5B,mCAAmC,KAAK,KAAK,GAE7C,OAAO,KAAK,UAAU,KAAK;CAG7B,OAAO;AACT;AAEA,MAAM,kBAAkB,OAAY,WAA2B;CAC7D,IAAI,UAAU,QAAQ,UAAU,QAAW,OAAO;CAElD,IAAI,OAAO,UAAU,aAAa,OAAO,UAAU,UACjD,OAAO,OAAO,KAAK;CAGrB,IAAI,OAAO,UAAU,UACnB,OAAO,gBAAgB,OAAO,MAAM;CAGtC,IAAI,MAAM,QAAQ,KAAK,GAAG;EACxB,IAAI,MAAM,WAAW,GAAG,OAAO;EAC/B,OAAO,MACJ,KAAK,SAAS;GACb,MAAM,aAAa,eAAe,MAAM,GAAG,OAAO,GAAG;GACrD,IACE,OAAO,SAAS,YAChB,SAAS,QACT,CAAC,MAAM,QAAQ,IAAI,KACnB,CAAC,WAAW,WAAW,GAAG,KAC1B,CAAC,WAAW,WAAW,IAAG,GAC1B;IAEA,MAAM,QAAQ,WAAW,MAAM,IAAI;IACnC,OAAO,GAAG,OAAO,IAAI,MAAM,GAAG,IAAI,MAC/B,MAAM,CAAC,CAAC,CACR,KAAK,MAAM,GAAG,OAAO,IAAI,GAAG,CAAC,CAC7B,KAAK,IAAI,IAAI,QAAQ;GAC1B;GACA,OAAO,GAAG,OAAO,IAAI;EACvB,CAAC,CAAC,CACD,KAAK,IAAI;CACd;CAEA,IAAI,OAAO,UAAU,UAAU;EAC7B,MAAM,UAAU,OAAO,QAAQ,KAAK,CAAC,CAAC,QAAQ,GAAG,OAAO,MAAM,MAAS;EACvE,IAAI,QAAQ,WAAW,GAAG,OAAO;EAEjC,OAAO,QACJ,KAAK,CAAC,GAAG,WAAW;GACnB,MAAM,MAAM,aAAa,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI;GACvD,MAAM,cAAc,GAAG,OAAO;GAE9B,IAAI,UAAU,QAAQ,UAAU,QAC9B,OAAO,GAAG,SAAS,IAAI;GAGzB,IAAI,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAEnD,OAAO,GAAG,SAAS,IAAI,KADR,eAAe,OAAO,WACJ;GAGnC,IAAI,MAAM,QAAQ,KAAK,GAAG;IACxB,IAAI,MAAM,WAAW,GAAG,OAAO,GAAG,SAAS,IAAI;IAE/C,OAAO,GAAG,SAAS,IAAI,KADR,eAAe,OAAO,WACJ;GACnC;GAEA,OAAO,GAAG,SAAS,IAAI,IAAI,eAAe,OAAO,MAAM;EACzD,CAAC,CAAC,CACD,KAAK,IAAI;CACd;CAEA,OAAO,OAAO,KAAK;AACrB;AAEA,MAAa,iBAAiB,UAC5B,GAAG,eAAe,OAAO,EAAE,EAAE"}
@@ -1,8 +1,12 @@
1
1
  import * as NodeTypes from "@intlayer/types/nodeType";
2
2
 
3
3
  //#region src/deepTransformPlugins/getEditedContent.ts
4
- const isTranslationNode = (node) => typeof node === "object" && node !== null && node.nodeType === NodeTypes.TRANSLATION;
5
- const isTypedNode = (node) => typeof node === "object" && node !== null && !Array.isArray(node) && typeof node.nodeType === "string";
4
+ /** Whether `node` is a plain (non-array) object, i.e. a content branch. */
5
+ const isRecordNode = (node) => typeof node === "object" && node !== null && !Array.isArray(node);
6
+ /** Whether `node` is a typed node, whatever its `nodeType`. */
7
+ const isTypedNode = (node) => isRecordNode(node) && typeof node.nodeType === "string";
8
+ /** Whether `node` is a `translation` node holding a locale map. */
9
+ const isTranslationNode = (node) => isTypedNode(node) && node.nodeType === NodeTypes.TRANSLATION && isRecordNode(node[NodeTypes.TRANSLATION]);
6
10
  /** Structural equality for leaf source values (string / number / nested objects). */
7
11
  const isSameValue = (a, b) => JSON.stringify(a) === JSON.stringify(b);
8
12
  /**
@@ -12,8 +16,8 @@ const isSameValue = (a, b) => JSON.stringify(a) === JSON.stringify(b);
12
16
  */
13
17
  const getEditedNode = (previous, next, defaultLocale) => {
14
18
  if (isTranslationNode(next)) {
15
- const nextValue = next[NodeTypes.TRANSLATION]?.[defaultLocale];
16
- const previousValue = isTranslationNode(previous) ? previous[NodeTypes.TRANSLATION]?.[defaultLocale] : void 0;
19
+ const nextValue = next[NodeTypes.TRANSLATION][defaultLocale];
20
+ const previousValue = isTranslationNode(previous) ? previous[NodeTypes.TRANSLATION][defaultLocale] : void 0;
17
21
  if (typeof nextValue === "undefined") return;
18
22
  if (isSameValue(previousValue, nextValue)) return;
19
23
  return {
@@ -44,8 +48,8 @@ const getEditedNode = (previous, next, defaultLocale) => {
44
48
  });
45
49
  return hasChange ? result : void 0;
46
50
  }
47
- if (typeof next === "object" && next !== null) {
48
- const previousObject = typeof previous === "object" && previous !== null && !Array.isArray(previous) ? previous : void 0;
51
+ if (isRecordNode(next)) {
52
+ const previousObject = isRecordNode(previous) ? previous : void 0;
49
53
  const result = {};
50
54
  let hasChange = false;
51
55
  for (const key of Object.keys(next)) {
@@ -1 +1 @@
1
- {"version":3,"file":"getEditedContent.mjs","names":[],"sources":["../../../src/deepTransformPlugins/getEditedContent.ts"],"sourcesContent":["import type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\n\n/** A `translation` node, e.g. `{ nodeType: 'translation', translation: { en, fr } }`. */\ntype TranslationNode = {\n nodeType: typeof NodeTypes.TRANSLATION;\n [NodeTypes.TRANSLATION]: Record<string, unknown>;\n};\n\nconst isTranslationNode = (node: unknown): node is TranslationNode =>\n typeof node === 'object' &&\n node !== null &&\n (node as { nodeType?: unknown }).nodeType === NodeTypes.TRANSLATION;\n\nconst isTypedNode = (\n node: unknown\n): node is { nodeType: string; [key: string]: unknown } =>\n typeof node === 'object' &&\n node !== null &&\n !Array.isArray(node) &&\n typeof (node as { nodeType?: unknown }).nodeType === 'string';\n\n/** Structural equality for leaf source values (string / number / nested objects). */\nconst isSameValue = (a: unknown, b: unknown): boolean =>\n JSON.stringify(a) === JSON.stringify(b);\n\n/**\n * Recursively compares `next` against `previous` and returns the sub-tree of\n * `next` that holds only the nodes whose source-locale value was added or\n * changed. Returns `undefined` when nothing changed at this node.\n */\nconst getEditedNode = (\n previous: ContentNode | undefined,\n next: ContentNode,\n defaultLocale: LocalesValues\n): ContentNode | undefined => {\n // Translation node: compare the default-locale leaf only.\n if (isTranslationNode(next)) {\n const nextValue = next[NodeTypes.TRANSLATION]?.[defaultLocale as string];\n const previousValue = isTranslationNode(previous)\n ? previous[NodeTypes.TRANSLATION]?.[defaultLocale as string]\n : undefined;\n\n // Nothing to (re)translate if the source locale is absent.\n if (typeof nextValue === 'undefined') {\n return undefined;\n }\n\n // Include only when the source value was added or changed.\n if (isSameValue(previousValue, nextValue)) {\n return undefined;\n }\n\n // Reduce to the source locale only, so every target locale is regenerated.\n return {\n nodeType: NodeTypes.TRANSLATION,\n [NodeTypes.TRANSLATION]: { [defaultLocale as string]: nextValue },\n } as ContentNode;\n }\n\n // Other typed nodes (enumeration, condition, nested, …): recurse into the\n // wrapped value while preserving the wrapper so the partial stays valid.\n if (isTypedNode(next)) {\n const { nodeType } = next;\n const previousInner = isTypedNode(previous)\n ? (previous[nodeType] as ContentNode | undefined)\n : undefined;\n const editedInner = getEditedNode(\n previousInner,\n next[nodeType] as ContentNode,\n defaultLocale\n );\n\n if (typeof editedInner === 'undefined') {\n return undefined;\n }\n\n return {\n nodeType,\n [nodeType]: editedInner,\n } as ContentNode;\n }\n\n // Arrays: keep changed items reduced to source-only, unchanged items as-is to\n // preserve index alignment for `mergeDictionaries` (which merges by index).\n if (Array.isArray(next)) {\n const previousArray = Array.isArray(previous) ? previous : [];\n let hasChange = false;\n\n const result = next.map((child, index) => {\n const editedChild = getEditedNode(\n previousArray[index] as ContentNode | undefined,\n child as ContentNode,\n defaultLocale\n );\n if (typeof editedChild !== 'undefined') {\n hasChange = true;\n return editedChild;\n }\n // Unchanged item: keep the full node. It already has every locale, so the\n // complete-mode translation pass skips it and the merge leaves it intact.\n return child;\n });\n\n return hasChange ? (result as ContentNode) : undefined;\n }\n\n // Plain objects: recurse into each key, keeping only changed branches.\n if (typeof next === 'object' && next !== null) {\n const previousObject =\n typeof previous === 'object' &&\n previous !== null &&\n !Array.isArray(previous)\n ? (previous as Record<string, ContentNode>)\n : undefined;\n\n const result: Record<string, ContentNode> = {};\n let hasChange = false;\n\n for (const key of Object.keys(next as Record<string, ContentNode>)) {\n const editedChild = getEditedNode(\n previousObject?.[key],\n (next as Record<string, ContentNode>)[key],\n defaultLocale\n );\n if (typeof editedChild !== 'undefined') {\n result[key] = editedChild;\n hasChange = true;\n }\n }\n\n return hasChange ? (result as ContentNode) : undefined;\n }\n\n // Primitive leaves are not locale-aware on their own — nothing to translate.\n return undefined;\n};\n\n/**\n * Returns the partial content holding only the `translation` nodes whose\n * source (`defaultLocale`) value was added or changed between `previousContent`\n * and `newContent`. Each changed node is reduced to its source locale so that\n * every target locale is regenerated when the partial is translated.\n *\n * Returns `{}` (empty content) when no source value changed.\n *\n * @example\n * // default value of `title` changed → only `title` is returned, source-only\n * getEditedContent(\n * { title: t({ en: 'Old', fr: 'Vieux' }), body: t({ en: 'B', fr: 'B' }) },\n * { title: t({ en: 'New', fr: 'Vieux' }), body: t({ en: 'B', fr: 'B' }) },\n * 'en'\n * ); // → { title: { nodeType: 'translation', translation: { en: 'New' } } }\n */\nexport const getEditedContent = (\n previousContent: ContentNode | undefined,\n newContent: ContentNode,\n defaultLocale: LocalesValues\n): ContentNode =>\n getEditedNode(previousContent, newContent, defaultLocale) ??\n ({} as ContentNode);\n\n/**\n * Dictionary-level wrapper around {@link getEditedContent}. Returns a partial\n * dictionary (same `key`) whose `content` holds only the changed source nodes.\n *\n * @param previousDictionary - Dictionary state before the edit.\n * @param newDictionary - Dictionary state after the edit.\n * @param defaultLocale - The source locale to diff against.\n */\nexport const getEditedDictionary = (\n previousDictionary: Dictionary | undefined,\n newDictionary: Dictionary,\n defaultLocale: LocalesValues\n): Dictionary => ({\n ...newDictionary,\n content: getEditedContent(\n previousDictionary?.content,\n newDictionary.content,\n defaultLocale\n ),\n});\n"],"mappings":";;;AAUA,MAAM,qBAAqB,SACzB,OAAO,SAAS,YAChB,SAAS,QACR,KAAgC,aAAa,UAAU;AAE1D,MAAM,eACJ,SAEA,OAAO,SAAS,YAChB,SAAS,QACT,CAAC,MAAM,QAAQ,IAAI,KACnB,OAAQ,KAAgC,aAAa;;AAGvD,MAAM,eAAe,GAAY,MAC/B,KAAK,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC;;;;;;AAOxC,MAAM,iBACJ,UACA,MACA,kBAC4B;CAE5B,IAAI,kBAAkB,IAAI,GAAG;EAC3B,MAAM,YAAY,KAAK,UAAU,YAAY,GAAG;EAChD,MAAM,gBAAgB,kBAAkB,QAAQ,IAC5C,SAAS,UAAU,YAAY,GAAG,iBAClC;EAGJ,IAAI,OAAO,cAAc,aACvB;EAIF,IAAI,YAAY,eAAe,SAAS,GACtC;EAIF,OAAO;GACL,UAAU,UAAU;IACnB,UAAU,cAAc,GAAG,gBAA0B,UAAU;EAClE;CACF;CAIA,IAAI,YAAY,IAAI,GAAG;EACrB,MAAM,EAAE,aAAa;EACrB,MAAM,gBAAgB,YAAY,QAAQ,IACrC,SAAS,YACV;EACJ,MAAM,cAAc,cAClB,eACA,KAAK,WACL,aACF;EAEA,IAAI,OAAO,gBAAgB,aACzB;EAGF,OAAO;GACL;IACC,WAAW;EACd;CACF;CAIA,IAAI,MAAM,QAAQ,IAAI,GAAG;EACvB,MAAM,gBAAgB,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC;EAC5D,IAAI,YAAY;EAEhB,MAAM,SAAS,KAAK,KAAK,OAAO,UAAU;GACxC,MAAM,cAAc,cAClB,cAAc,QACd,OACA,aACF;GACA,IAAI,OAAO,gBAAgB,aAAa;IACtC,YAAY;IACZ,OAAO;GACT;GAGA,OAAO;EACT,CAAC;EAED,OAAO,YAAa,SAAyB;CAC/C;CAGA,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM;EAC7C,MAAM,iBACJ,OAAO,aAAa,YACpB,aAAa,QACb,CAAC,MAAM,QAAQ,QAAQ,IAClB,WACD;EAEN,MAAM,SAAsC,CAAC;EAC7C,IAAI,YAAY;EAEhB,KAAK,MAAM,OAAO,OAAO,KAAK,IAAmC,GAAG;GAClE,MAAM,cAAc,cAClB,iBAAiB,MAChB,KAAqC,MACtC,aACF;GACA,IAAI,OAAO,gBAAgB,aAAa;IACtC,OAAO,OAAO;IACd,YAAY;GACd;EACF;EAEA,OAAO,YAAa,SAAyB;CAC/C;AAIF;;;;;;;;;;;;;;;;;AAkBA,MAAa,oBACX,iBACA,YACA,kBAEA,cAAc,iBAAiB,YAAY,aAAa,KACvD,CAAC;;;;;;;;;AAUJ,MAAa,uBACX,oBACA,eACA,mBACgB;CAChB,GAAG;CACH,SAAS,iBACP,oBAAoB,SACpB,cAAc,SACd,aACF;AACF"}
1
+ {"version":3,"file":"getEditedContent.mjs","names":[],"sources":["../../../src/deepTransformPlugins/getEditedContent.ts"],"sourcesContent":["import type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport type { TypedNodeModel } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\n\n/**\n * Structural view of a dictionary content tree.\n *\n * `ContentNode` describes leaves and typed nodes only — the plain objects and\n * arrays that hold them are typed as `any` by the public `Dictionary['content']`.\n * Declaring those containers explicitly lets the diff walk a whole content tree\n * without casting at every step.\n */\ntype ContentTree = ContentNode | ContentTree[] | { [key: string]: ContentTree };\n\n/** A `translation` node, e.g. `{ nodeType: 'translation', translation: { en, fr } }`. */\ntype TranslationNode = TypedNodeModel<\n typeof NodeTypes.TRANSLATION,\n Record<string, ContentTree>\n>;\n\n/**\n * Any typed node — a wrapper holding its value under the key named by its own\n * `nodeType` (e.g. `{ nodeType: 'plural', plural: … }`).\n */\ntype TypedContentNode = {\n nodeType: string;\n [wrappedValueKey: string]: ContentTree;\n};\n\n/** Whether `node` is a plain (non-array) object, i.e. a content branch. */\nconst isRecordNode = (node: ContentTree): node is Record<string, ContentTree> =>\n typeof node === 'object' && node !== null && !Array.isArray(node);\n\n/** Whether `node` is a typed node, whatever its `nodeType`. */\nconst isTypedNode = (node: ContentTree): node is TypedContentNode =>\n isRecordNode(node) && typeof node.nodeType === 'string';\n\n/** Whether `node` is a `translation` node holding a locale map. */\nconst isTranslationNode = (node: ContentTree): node is TranslationNode =>\n isTypedNode(node) &&\n node.nodeType === NodeTypes.TRANSLATION &&\n isRecordNode(node[NodeTypes.TRANSLATION]);\n\n/** Structural equality for leaf source values (string / number / nested objects). */\nconst isSameValue = (a: ContentTree, b: ContentTree): boolean =>\n JSON.stringify(a) === JSON.stringify(b);\n\n/**\n * Recursively compares `next` against `previous` and returns the sub-tree of\n * `next` that holds only the nodes whose source-locale value was added or\n * changed. Returns `undefined` when nothing changed at this node.\n */\nconst getEditedNode = (\n previous: ContentTree,\n next: ContentTree,\n defaultLocale: LocalesValues\n): ContentTree | undefined => {\n // Translation node: compare the default-locale leaf only.\n if (isTranslationNode(next)) {\n const nextValue = next[NodeTypes.TRANSLATION][defaultLocale];\n const previousValue = isTranslationNode(previous)\n ? previous[NodeTypes.TRANSLATION][defaultLocale]\n : undefined;\n\n // Nothing to (re)translate if the source locale is absent.\n if (typeof nextValue === 'undefined') {\n return undefined;\n }\n\n // Include only when the source value was added or changed.\n if (isSameValue(previousValue, nextValue)) {\n return undefined;\n }\n\n // Reduce to the source locale only, so every target locale is regenerated.\n return {\n nodeType: NodeTypes.TRANSLATION,\n [NodeTypes.TRANSLATION]: { [defaultLocale]: nextValue },\n } satisfies TranslationNode;\n }\n\n // Other typed nodes (enumeration, condition, nested, …): recurse into the\n // wrapped value while preserving the wrapper so the partial stays valid.\n if (isTypedNode(next)) {\n const { nodeType } = next;\n const previousInner = isTypedNode(previous)\n ? previous[nodeType]\n : undefined;\n const editedInner = getEditedNode(\n previousInner,\n next[nodeType],\n defaultLocale\n );\n\n if (typeof editedInner === 'undefined') {\n return undefined;\n }\n\n return {\n nodeType,\n [nodeType]: editedInner,\n } satisfies TypedContentNode;\n }\n\n // Arrays: keep changed items reduced to source-only, unchanged items as-is to\n // preserve index alignment for `mergeDictionaries` (which merges by index).\n if (Array.isArray(next)) {\n const previousArray = Array.isArray(previous) ? previous : [];\n let hasChange = false;\n\n const result = next.map((child, index) => {\n const editedChild = getEditedNode(\n previousArray[index],\n child,\n defaultLocale\n );\n if (typeof editedChild !== 'undefined') {\n hasChange = true;\n return editedChild;\n }\n // Unchanged item: keep the full node. It already has every locale, so the\n // complete-mode translation pass skips it and the merge leaves it intact.\n return child;\n });\n\n return hasChange ? result : undefined;\n }\n\n // Plain objects: recurse into each key, keeping only changed branches.\n if (isRecordNode(next)) {\n const previousObject = isRecordNode(previous) ? previous : undefined;\n\n const result: Record<string, ContentTree> = {};\n let hasChange = false;\n\n for (const key of Object.keys(next)) {\n const editedChild = getEditedNode(\n previousObject?.[key],\n next[key],\n defaultLocale\n );\n if (typeof editedChild !== 'undefined') {\n result[key] = editedChild;\n hasChange = true;\n }\n }\n\n return hasChange ? result : undefined;\n }\n\n // Primitive leaves are not locale-aware on their own — nothing to translate.\n return undefined;\n};\n\n/**\n * Returns the partial content holding only the `translation` nodes whose\n * source (`defaultLocale`) value was added or changed between `previousContent`\n * and `newContent`. Each changed node is reduced to its source locale so that\n * every target locale is regenerated when the partial is translated.\n *\n * Returns `{}` (empty content) when no source value changed.\n *\n * @example\n * // default value of `title` changed → only `title` is returned, source-only\n * getEditedContent(\n * { title: t({ en: 'Old', fr: 'Vieux' }), body: t({ en: 'B', fr: 'B' }) },\n * { title: t({ en: 'New', fr: 'Vieux' }), body: t({ en: 'B', fr: 'B' }) },\n * 'en'\n * ); // → { title: { nodeType: 'translation', translation: { en: 'New' } } }\n */\nexport const getEditedContent = (\n previousContent: ContentNode | undefined,\n newContent: ContentNode,\n defaultLocale: LocalesValues\n): ContentNode =>\n // The result is a sub-tree of `newContent`, so narrowing the structural\n // `ContentTree` back to the public `ContentNode` is sound: only the plain\n // containers `ContentNode` leaves untyped are dropped from the type.\n (getEditedNode(previousContent, newContent, defaultLocale) ??\n {}) as ContentNode;\n\n/**\n * Dictionary-level wrapper around {@link getEditedContent}. Returns a partial\n * dictionary (same `key`) whose `content` holds only the changed source nodes.\n *\n * @param previousDictionary - Dictionary state before the edit.\n * @param newDictionary - Dictionary state after the edit.\n * @param defaultLocale - The source locale to diff against.\n */\nexport const getEditedDictionary = (\n previousDictionary: Dictionary | undefined,\n newDictionary: Dictionary,\n defaultLocale: LocalesValues\n): Dictionary => ({\n ...newDictionary,\n content: getEditedContent(\n previousDictionary?.content,\n newDictionary.content,\n defaultLocale\n ),\n});\n"],"mappings":";;;;AA+BA,MAAM,gBAAgB,SACpB,OAAO,SAAS,YAAY,SAAS,QAAQ,CAAC,MAAM,QAAQ,IAAI;;AAGlE,MAAM,eAAe,SACnB,aAAa,IAAI,KAAK,OAAO,KAAK,aAAa;;AAGjD,MAAM,qBAAqB,SACzB,YAAY,IAAI,KAChB,KAAK,aAAa,UAAU,eAC5B,aAAa,KAAK,UAAU,YAAY;;AAG1C,MAAM,eAAe,GAAgB,MACnC,KAAK,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC;;;;;;AAOxC,MAAM,iBACJ,UACA,MACA,kBAC4B;CAE5B,IAAI,kBAAkB,IAAI,GAAG;EAC3B,MAAM,YAAY,KAAK,UAAU,YAAY,CAAC;EAC9C,MAAM,gBAAgB,kBAAkB,QAAQ,IAC5C,SAAS,UAAU,YAAY,CAAC,iBAChC;EAGJ,IAAI,OAAO,cAAc,aACvB;EAIF,IAAI,YAAY,eAAe,SAAS,GACtC;EAIF,OAAO;GACL,UAAU,UAAU;IACnB,UAAU,cAAc,GAAG,gBAAgB,UAAU;EACxD;CACF;CAIA,IAAI,YAAY,IAAI,GAAG;EACrB,MAAM,EAAE,aAAa;EACrB,MAAM,gBAAgB,YAAY,QAAQ,IACtC,SAAS,YACT;EACJ,MAAM,cAAc,cAClB,eACA,KAAK,WACL,aACF;EAEA,IAAI,OAAO,gBAAgB,aACzB;EAGF,OAAO;GACL;IACC,WAAW;EACd;CACF;CAIA,IAAI,MAAM,QAAQ,IAAI,GAAG;EACvB,MAAM,gBAAgB,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC;EAC5D,IAAI,YAAY;EAEhB,MAAM,SAAS,KAAK,KAAK,OAAO,UAAU;GACxC,MAAM,cAAc,cAClB,cAAc,QACd,OACA,aACF;GACA,IAAI,OAAO,gBAAgB,aAAa;IACtC,YAAY;IACZ,OAAO;GACT;GAGA,OAAO;EACT,CAAC;EAED,OAAO,YAAY,SAAS;CAC9B;CAGA,IAAI,aAAa,IAAI,GAAG;EACtB,MAAM,iBAAiB,aAAa,QAAQ,IAAI,WAAW;EAE3D,MAAM,SAAsC,CAAC;EAC7C,IAAI,YAAY;EAEhB,KAAK,MAAM,OAAO,OAAO,KAAK,IAAI,GAAG;GACnC,MAAM,cAAc,cAClB,iBAAiB,MACjB,KAAK,MACL,aACF;GACA,IAAI,OAAO,gBAAgB,aAAa;IACtC,OAAO,OAAO;IACd,YAAY;GACd;EACF;EAEA,OAAO,YAAY,SAAS;CAC9B;AAIF;;;;;;;;;;;;;;;;;AAkBA,MAAa,oBACX,iBACA,YACA,kBAKC,cAAc,iBAAiB,YAAY,aAAa,KACvD,CAAC;;;;;;;;;AAUL,MAAa,uBACX,oBACA,eACA,mBACgB;CAChB,GAAG;CACH,SAAS,iBACP,oBAAoB,SACpB,cAAc,SACd,aACF;AACF"}
@@ -49,7 +49,8 @@ const getReplacedValuesContent = (node, value, nodeProps) => {
49
49
  replaceValuesPlugin(value),
50
50
  ...nodeProps.plugins ?? []
51
51
  ];
52
- return deepTransformNode(JSON.parse(JSON.stringify(node)), {
52
+ const JSONNode = JSON.parse(JSON.stringify(node));
53
+ return deepTransformNode(JSONNode, {
53
54
  ...nodeProps,
54
55
  plugins
55
56
  });
@@ -1 +1 @@
1
- {"version":3,"file":"getReplacedValuesContent.mjs","names":[],"sources":["../../../src/deepTransformPlugins/getReplacedValuesContent.ts"],"sourcesContent":["import type { ContentNode, TypedNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport {\n deepTransformNode,\n type NodeProps,\n type Plugins,\n} from '../interpreter';\n\nconst replaceValuesPlugin = (value: string | number | boolean): Plugins => ({\n id: 'replace-values-plugin',\n canHandle: (node) =>\n typeof node === 'string' ||\n typeof node === 'number' ||\n typeof node === 'boolean',\n transform: () => value,\n});\n\nconst skipTypedNodePlugin: Plugins = {\n id: 'skip-typed-node-plugin',\n canHandle: (node) =>\n typeof node === 'object' && typeof node?.nodeType === 'string',\n transform: (node: TypedNode, props, deepTransformNode) => {\n const nodeType = node.nodeType as NodeType;\n const result = structuredClone(\n node[nodeType as unknown as keyof TypedNode] as any\n );\n\n // If the result is a primitive value (string, number, boolean),\n // we need to transform it directly instead of iterating over its properties\n if (typeof result !== 'object' || result === null) {\n const transformedResult = deepTransformNode(result, {\n ...props,\n children: result,\n keyPath: [\n ...props.keyPath,\n { type: nodeType, key: nodeType } as KeyPath,\n ],\n });\n return {\n ...node,\n [nodeType as unknown as keyof TypedNode]: transformedResult,\n };\n }\n\n // For objects and arrays, iterate over their properties\n for (const key in result) {\n const childProps = {\n ...props,\n children: result[key as unknown as keyof typeof result],\n keyPath: [...props.keyPath, { type: nodeType, key } as KeyPath],\n };\n result[key as unknown as keyof typeof result] = deepTransformNode(\n result[key as unknown as keyof typeof result],\n childProps\n );\n }\n\n return { ...node, [nodeType as unknown as keyof TypedNode]: result };\n },\n};\n\nexport const getReplacedValuesContent = (\n node: ContentNode,\n value: string | number | boolean,\n nodeProps: NodeProps\n) => {\n const plugins: Plugins[] = [\n skipTypedNodePlugin,\n replaceValuesPlugin(value),\n ...(nodeProps.plugins ?? []),\n ];\n\n const JSONNode = JSON.parse(JSON.stringify(node));\n\n return deepTransformNode(JSONNode, {\n ...nodeProps,\n plugins,\n });\n};\n"],"mappings":";;;AASA,MAAM,uBAAuB,WAA+C;CAC1E,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAChB,OAAO,SAAS,YAChB,OAAO,SAAS;CAClB,iBAAiB;AACnB;AAEA,MAAM,sBAA+B;CACnC,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,OAAO,MAAM,aAAa;CACxD,YAAY,MAAiB,OAAO,sBAAsB;EACxD,MAAM,WAAW,KAAK;EACtB,MAAM,SAAS,gBACb,KAAK,SACP;EAIA,IAAI,OAAO,WAAW,YAAY,WAAW,MAAM;GACjD,MAAM,oBAAoB,kBAAkB,QAAQ;IAClD,GAAG;IACH,UAAU;IACV,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAM;KAAU,KAAK;IAAS,CAClC;GACF,CAAC;GACD,OAAO;IACL,GAAG;KACF,WAAyC;GAC5C;EACF;EAGA,KAAK,MAAM,OAAO,QAAQ;GACxB,MAAM,aAAa;IACjB,GAAG;IACH,UAAU,OAAO;IACjB,SAAS,CAAC,GAAG,MAAM,SAAS;KAAE,MAAM;KAAU;IAAI,CAAY;GAChE;GACA,OAAO,OAAyC,kBAC9C,OAAO,MACP,UACF;EACF;EAEA,OAAO;GAAE,GAAG;IAAO,WAAyC;EAAO;CACrE;AACF;AAEA,MAAa,4BACX,MACA,OACA,cACG;CACH,MAAM,UAAqB;EACzB;EACA,oBAAoB,KAAK;EACzB,GAAI,UAAU,WAAW,CAAC;CAC5B;CAIA,OAAO,kBAFU,KAAK,MAAM,KAAK,UAAU,IAAI,CAEf,GAAG;EACjC,GAAG;EACH;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"getReplacedValuesContent.mjs","names":[],"sources":["../../../src/deepTransformPlugins/getReplacedValuesContent.ts"],"sourcesContent":["import type { ContentNode, TypedNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport {\n deepTransformNode,\n type NodeProps,\n type Plugins,\n} from '../interpreter';\n\nconst replaceValuesPlugin = (value: string | number | boolean): Plugins => ({\n id: 'replace-values-plugin',\n canHandle: (node) =>\n typeof node === 'string' ||\n typeof node === 'number' ||\n typeof node === 'boolean',\n transform: () => value,\n});\n\nconst skipTypedNodePlugin: Plugins = {\n id: 'skip-typed-node-plugin',\n canHandle: (node) =>\n typeof node === 'object' && typeof node?.nodeType === 'string',\n transform: (node: TypedNode, props, deepTransformNode) => {\n const nodeType = node.nodeType as NodeType;\n const result = structuredClone(\n node[nodeType as unknown as keyof TypedNode] as any\n );\n\n // If the result is a primitive value (string, number, boolean),\n // we need to transform it directly instead of iterating over its properties\n if (typeof result !== 'object' || result === null) {\n const transformedResult = deepTransformNode(result, {\n ...props,\n children: result,\n keyPath: [\n ...props.keyPath,\n { type: nodeType, key: nodeType } as KeyPath,\n ],\n });\n return {\n ...node,\n [nodeType as unknown as keyof TypedNode]: transformedResult,\n };\n }\n\n // For objects and arrays, iterate over their properties\n for (const key in result) {\n const childProps = {\n ...props,\n children: result[key as unknown as keyof typeof result],\n keyPath: [...props.keyPath, { type: nodeType, key } as KeyPath],\n };\n result[key as unknown as keyof typeof result] = deepTransformNode(\n result[key as unknown as keyof typeof result],\n childProps\n );\n }\n\n return { ...node, [nodeType as unknown as keyof TypedNode]: result };\n },\n};\n\nexport const getReplacedValuesContent = (\n node: ContentNode,\n value: string | number | boolean,\n nodeProps: NodeProps\n) => {\n const plugins: Plugins[] = [\n skipTypedNodePlugin,\n replaceValuesPlugin(value),\n ...(nodeProps.plugins ?? []),\n ];\n\n const JSONNode = JSON.parse(JSON.stringify(node));\n\n return deepTransformNode(JSONNode, {\n ...nodeProps,\n plugins,\n });\n};\n"],"mappings":";;;AASA,MAAM,uBAAuB,WAA+C;CAC1E,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAChB,OAAO,SAAS,YAChB,OAAO,SAAS;CAClB,iBAAiB;AACnB;AAEA,MAAM,sBAA+B;CACnC,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,OAAO,MAAM,aAAa;CACxD,YAAY,MAAiB,OAAO,sBAAsB;EACxD,MAAM,WAAW,KAAK;EACtB,MAAM,SAAS,gBACb,KAAK,SACP;EAIA,IAAI,OAAO,WAAW,YAAY,WAAW,MAAM;GACjD,MAAM,oBAAoB,kBAAkB,QAAQ;IAClD,GAAG;IACH,UAAU;IACV,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAM;KAAU,KAAK;IAAS,CAClC;GACF,CAAC;GACD,OAAO;IACL,GAAG;KACF,WAAyC;GAC5C;EACF;EAGA,KAAK,MAAM,OAAO,QAAQ;GACxB,MAAM,aAAa;IACjB,GAAG;IACH,UAAU,OAAO;IACjB,SAAS,CAAC,GAAG,MAAM,SAAS;KAAE,MAAM;KAAU;IAAI,CAAY;GAChE;GACA,OAAO,OAAyC,kBAC9C,OAAO,MACP,UACF;EACF;EAEA,OAAO;GAAE,GAAG;IAAO,WAAyC;EAAO;CACrE;AACF;AAEA,MAAa,4BACX,MACA,OACA,cACG;CACH,MAAM,UAAqB;EACzB;EACA,oBAAoB,KAAK;EACzB,GAAI,UAAU,WAAW,CAAC;CAC5B;CAEA,MAAM,WAAW,KAAK,MAAM,KAAK,UAAU,IAAI,CAAC;CAEhD,OAAO,kBAAkB,UAAU;EACjC,GAAG;EACH;CACF,CAAC;AACH"}
@@ -10,46 +10,55 @@ import * as NodeTypes from "@intlayer/types/nodeType";
10
10
  */
11
11
  const deepMergeContent = (target, source, locale) => {
12
12
  if (source === null || source === void 0) return target;
13
- if (target === null || target === void 0) if (Array.isArray(source)) target = [];
14
- else if (typeof source === "object") target = {};
15
- else return source;
16
- if (target && typeof target === "object" && target.nodeType === NodeTypes.TRANSLATION) if (locale) {
17
- const existingLocaleContent = target[NodeTypes.TRANSLATION][locale];
18
- let newLocaleContent;
19
- if (typeof source === "object" && !Array.isArray(source)) newLocaleContent = deepMergeContent(existingLocaleContent, source, void 0);
20
- else if (Array.isArray(source)) newLocaleContent = source;
21
- else newLocaleContent = source;
22
- return {
13
+ if (target === null || target === void 0) {
14
+ if (Array.isArray(source)) target = [];
15
+ else if (typeof source === "object") target = {};
16
+ else return source;
17
+ }
18
+ if (target && typeof target === "object" && target.nodeType === NodeTypes.TRANSLATION) {
19
+ if (locale) {
20
+ const existingLocaleContent = target[NodeTypes.TRANSLATION][locale];
21
+ let newLocaleContent;
22
+ if (typeof source === "object" && !Array.isArray(source)) newLocaleContent = deepMergeContent(existingLocaleContent, source, void 0);
23
+ else if (Array.isArray(source)) newLocaleContent = source;
24
+ else newLocaleContent = source;
25
+ return {
26
+ ...target,
27
+ [NodeTypes.TRANSLATION]: {
28
+ ...target[NodeTypes.TRANSLATION],
29
+ [locale]: newLocaleContent
30
+ }
31
+ };
32
+ } else if (typeof source === "object" && !Array.isArray(source) && source.nodeType === NodeTypes.TRANSLATION) return {
23
33
  ...target,
24
34
  [NodeTypes.TRANSLATION]: {
25
35
  ...target[NodeTypes.TRANSLATION],
26
- [locale]: newLocaleContent
36
+ ...source[NodeTypes.TRANSLATION]
27
37
  }
28
38
  };
29
- } else if (typeof source === "object" && !Array.isArray(source) && source.nodeType === NodeTypes.TRANSLATION) return {
30
- ...target,
31
- [NodeTypes.TRANSLATION]: {
32
- ...target[NodeTypes.TRANSLATION],
33
- ...source[NodeTypes.TRANSLATION]
34
- }
35
- };
36
- else return processNewContent(source, locale);
37
- if (Array.isArray(source)) if (locale && Array.isArray(target)) {
38
- const result = [];
39
- const maxLength = Math.max(source.length, target.length);
40
- for (let i = 0; i < maxLength; i++) if (i < source.length) if (i < target.length && target[i] !== void 0) result[i] = deepMergeContent(target[i], source[i], locale);
41
- else result[i] = processNewContent(source[i], locale);
42
- else result[i] = target[i];
43
- return result;
44
- } else return source.map((item) => {
45
- if (item && typeof item === "object" && item.nodeType === NodeTypes.TRANSLATION) return item;
46
- return processNewContent(item, locale);
47
- });
39
+ else return processNewContent(source, locale);
40
+ }
41
+ if (Array.isArray(source)) {
42
+ if (locale && Array.isArray(target)) {
43
+ const result = [];
44
+ const maxLength = Math.max(source.length, target.length);
45
+ for (let i = 0; i < maxLength; i++) if (i < source.length) {
46
+ if (i < target.length && target[i] !== void 0) result[i] = deepMergeContent(target[i], source[i], locale);
47
+ else result[i] = processNewContent(source[i], locale);
48
+ } else result[i] = target[i];
49
+ return result;
50
+ } else return source.map((item) => {
51
+ if (item && typeof item === "object" && item.nodeType === NodeTypes.TRANSLATION) return item;
52
+ return processNewContent(item, locale);
53
+ });
54
+ }
48
55
  if (typeof source === "object" && !Array.isArray(source)) {
49
56
  if (typeof target !== "object" || Array.isArray(target)) target = {};
50
57
  const result = { ...target };
51
- for (const key in source) if (Object.hasOwn(source, key)) if (target[key] !== void 0) result[key] = deepMergeContent(target[key], source[key], locale);
52
- else result[key] = processNewContent(source[key], locale);
58
+ for (const key in source) if (Object.hasOwn(source, key)) {
59
+ if (target[key] !== void 0) result[key] = deepMergeContent(target[key], source[key], locale);
60
+ else result[key] = processNewContent(source[key], locale);
61
+ }
53
62
  return result;
54
63
  }
55
64
  return source;
@@ -1 +1 @@
1
- {"version":3,"file":"insertContentInDictionary.mjs","names":[],"sources":["../../../src/deepTransformPlugins/insertContentInDictionary.ts"],"sourcesContent":["import type { Dictionary } from '@intlayer/types/dictionary';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\n\n// {\n// {\n// title: 'このページ',\n// linkLabel: 'セクションへ移動',\n// collapseButton: { label: '折りたたむ' }\n// },\n// }\n// {\n// dictionary: {\n// key: 'aside-navigation',\n// content: {\n// title: {\n// nodeType: 'translation',\n// translation: {\n// ar: 'في هذه الصفحة',\n// de: 'Auf dieser Seite',\n// en: 'In this page',\n// 'en-GB': 'On this page',\n// es: 'En esta página',\n// fr: 'Dans cette page',\n// hi: 'इस पृष्ठ में',\n// it: 'In questa pagina',\n// ko: '이 페이지에서',\n// pt: 'Nesta página',\n// ru: 'На этой странице',\n// tr: 'Bu sayfada',\n// zh: '在此页面'\n// }\n// },\n// },\n// localId: 'aside-navigation::local::src/components/AsideNavigation/asideNavigation.content.ts',\n// location: 'local',\n// filePath: 'src/components/AsideNavigation/asideNavigation.content.ts'\n// }\n// }\n\n/**\n * Deep merge helper that handles translation blocks\n * @param target - The target object (dictionary content)\n * @param source - The source object (new content to merge)\n * @param locale - Optional locale to target specific translation\n * @returns Merged content\n */\nconst deepMergeContent = (\n target: any,\n source: any,\n locale?: LocalesValues\n): any => {\n // If source is null or undefined, return target\n if (source === null || source === undefined) return target;\n\n // If target is null or undefined, initialize based on source type\n if (target === null || target === undefined) {\n if (Array.isArray(source)) {\n target = [];\n } else if (typeof source === 'object') {\n target = {};\n } else {\n return source;\n }\n }\n\n // Handle translation nodes FIRST (before arrays) to support arrays within translations\n if (\n target &&\n typeof target === 'object' &&\n target.nodeType === NodeTypes.TRANSLATION\n ) {\n // Target is a translation block\n if (locale) {\n // Update only the specific locale - create new object to preserve order\n const existingLocaleContent = target[NodeTypes.TRANSLATION][locale];\n let newLocaleContent: any;\n\n if (typeof source === 'object' && !Array.isArray(source)) {\n // Source is an object, need to deep merge for this locale\n newLocaleContent = deepMergeContent(\n existingLocaleContent,\n source,\n undefined // Don't pass locale down for nested content\n );\n } else if (Array.isArray(source)) {\n // Source is an array, set it directly for this locale\n newLocaleContent = source;\n } else {\n // Source is a primitive, directly set it\n newLocaleContent = source;\n }\n\n // Return new object with locale appended at the end (preserve insertion order)\n return {\n ...target,\n [NodeTypes.TRANSLATION]: {\n ...target[NodeTypes.TRANSLATION],\n [locale]: newLocaleContent,\n },\n };\n } else {\n // No locale specified, replace/merge the entire translation\n if (\n typeof source === 'object' &&\n !Array.isArray(source) &&\n source.nodeType === NodeTypes.TRANSLATION\n ) {\n // Source is also a translation node, merge translations\n return {\n ...target,\n [NodeTypes.TRANSLATION]: {\n ...target[NodeTypes.TRANSLATION],\n ...source[NodeTypes.TRANSLATION],\n },\n };\n } else {\n // Source is not a translation node, wrap it\n return processNewContent(source, locale);\n }\n }\n }\n\n // Handle arrays\n if (Array.isArray(source)) {\n if (locale && Array.isArray(target)) {\n // When locale is specified and target is also an array, merge element by element\n const result = [];\n const maxLength = Math.max(source.length, target.length);\n\n for (let i = 0; i < maxLength; i++) {\n if (i < source.length) {\n if (i < target.length && target[i] !== undefined) {\n // Both source and target have element at this index - merge them\n result[i] = deepMergeContent(target[i], source[i], locale);\n } else {\n // Only source has element at this index - process new content\n result[i] = processNewContent(source[i], locale);\n }\n } else {\n // Only target has element at this index - keep it\n result[i] = target[i];\n }\n }\n\n return result;\n } else {\n // No locale or target is not an array - replace entirely\n return source.map((item) => {\n // Process each item in case it needs locale wrapping\n if (\n item &&\n typeof item === 'object' &&\n item.nodeType === NodeTypes.TRANSLATION\n ) {\n return item;\n }\n return processNewContent(item, locale);\n });\n }\n }\n\n // Handle objects\n if (typeof source === 'object' && !Array.isArray(source)) {\n if (typeof target !== 'object' || Array.isArray(target)) {\n target = {};\n }\n\n // Create new object to preserve key order and avoid mutation\n const result: any = { ...target };\n\n for (const key in source) {\n if (Object.hasOwn(source, key)) {\n if (target[key] !== undefined) {\n result[key] = deepMergeContent(target[key], source[key], locale);\n } else {\n result[key] = processNewContent(source[key], locale);\n }\n }\n }\n\n return result;\n }\n\n // For primitives, just return the source\n return source;\n};\n\n/**\n * Process new content that doesn't exist in target\n * @param content - New content to process\n * @param locale - Optional locale\n * @returns Processed content\n */\nconst processNewContent = (content: any, locale?: LocalesValues): any => {\n // Handle null and undefined\n if (content === null || content === undefined) {\n return content;\n }\n\n // If content is already a translation node, return as-is\n if (\n content &&\n typeof content === 'object' &&\n content.nodeType === NodeTypes.TRANSLATION\n ) {\n return content;\n }\n\n // Handle arrays\n if (Array.isArray(content)) {\n return content.map((item) => processNewContent(item, locale));\n }\n\n // Handle objects\n if (content && typeof content === 'object') {\n const result: any = {};\n\n for (const key in content) {\n if (Object.hasOwn(content, key)) {\n result[key] = processNewContent(content[key], locale);\n }\n }\n return result;\n }\n\n // Handle primitives\n if (locale) {\n // Wrap in translation node with the specific locale\n return {\n nodeType: NodeTypes.TRANSLATION,\n [NodeTypes.TRANSLATION]: {\n [locale]: content,\n },\n };\n } else {\n // If no locale, just return the content as-is (don't wrap)\n return content;\n }\n};\n\n/**\n * Insert content into a dictionary with deep merge support\n * Handles translation blocks and nested structures\n *\n * @param dictionary - The dictionary to insert content into\n * @param content - The content to insert\n * @param locale - Optional locale to target specific translation\n * @returns Updated dictionary\n *\n * @example\n * // Without locale - deep merge all content\n * insertContentInDictionary(dictionary, { title: 'New Title' })\n *\n * @example\n * // With locale - insert content for specific locale\n * insertContentInDictionary(dictionary, { title: 'このページ' }, 'ja')\n */\nexport const insertContentInDictionary = (\n dictionary: Dictionary,\n content: Dictionary['content'],\n locale?: LocalesValues\n): Dictionary => {\n const mergedContent = deepMergeContent(\n Array.isArray(dictionary.content)\n ? [...dictionary.content]\n : { ...dictionary.content },\n content,\n locale\n );\n\n return {\n ...dictionary,\n content: mergedContent,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"insertContentInDictionary.mjs","names":[],"sources":["../../../src/deepTransformPlugins/insertContentInDictionary.ts"],"sourcesContent":["import type { Dictionary } from '@intlayer/types/dictionary';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\n\n// {\n// {\n// title: 'このページ',\n// linkLabel: 'セクションへ移動',\n// collapseButton: { label: '折りたたむ' }\n// },\n// }\n// {\n// dictionary: {\n// key: 'aside-navigation',\n// content: {\n// title: {\n// nodeType: 'translation',\n// translation: {\n// ar: 'في هذه الصفحة',\n// de: 'Auf dieser Seite',\n// en: 'In this page',\n// 'en-GB': 'On this page',\n// es: 'En esta página',\n// fr: 'Dans cette page',\n// hi: 'इस पृष्ठ में',\n// it: 'In questa pagina',\n// ko: '이 페이지에서',\n// pt: 'Nesta página',\n// ru: 'На этой странице',\n// tr: 'Bu sayfada',\n// zh: '在此页面'\n// }\n// },\n// },\n// localId: 'aside-navigation::local::src/components/AsideNavigation/asideNavigation.content.ts',\n// location: 'local',\n// filePath: 'src/components/AsideNavigation/asideNavigation.content.ts'\n// }\n// }\n\n/**\n * Deep merge helper that handles translation blocks\n * @param target - The target object (dictionary content)\n * @param source - The source object (new content to merge)\n * @param locale - Optional locale to target specific translation\n * @returns Merged content\n */\nconst deepMergeContent = (\n target: any,\n source: any,\n locale?: LocalesValues\n): any => {\n // If source is null or undefined, return target\n if (source === null || source === undefined) return target;\n\n // If target is null or undefined, initialize based on source type\n if (target === null || target === undefined) {\n if (Array.isArray(source)) {\n target = [];\n } else if (typeof source === 'object') {\n target = {};\n } else {\n return source;\n }\n }\n\n // Handle translation nodes FIRST (before arrays) to support arrays within translations\n if (\n target &&\n typeof target === 'object' &&\n target.nodeType === NodeTypes.TRANSLATION\n ) {\n // Target is a translation block\n if (locale) {\n // Update only the specific locale - create new object to preserve order\n const existingLocaleContent = target[NodeTypes.TRANSLATION][locale];\n let newLocaleContent: any;\n\n if (typeof source === 'object' && !Array.isArray(source)) {\n // Source is an object, need to deep merge for this locale\n newLocaleContent = deepMergeContent(\n existingLocaleContent,\n source,\n undefined // Don't pass locale down for nested content\n );\n } else if (Array.isArray(source)) {\n // Source is an array, set it directly for this locale\n newLocaleContent = source;\n } else {\n // Source is a primitive, directly set it\n newLocaleContent = source;\n }\n\n // Return new object with locale appended at the end (preserve insertion order)\n return {\n ...target,\n [NodeTypes.TRANSLATION]: {\n ...target[NodeTypes.TRANSLATION],\n [locale]: newLocaleContent,\n },\n };\n } else {\n // No locale specified, replace/merge the entire translation\n if (\n typeof source === 'object' &&\n !Array.isArray(source) &&\n source.nodeType === NodeTypes.TRANSLATION\n ) {\n // Source is also a translation node, merge translations\n return {\n ...target,\n [NodeTypes.TRANSLATION]: {\n ...target[NodeTypes.TRANSLATION],\n ...source[NodeTypes.TRANSLATION],\n },\n };\n } else {\n // Source is not a translation node, wrap it\n return processNewContent(source, locale);\n }\n }\n }\n\n // Handle arrays\n if (Array.isArray(source)) {\n if (locale && Array.isArray(target)) {\n // When locale is specified and target is also an array, merge element by element\n const result = [];\n const maxLength = Math.max(source.length, target.length);\n\n for (let i = 0; i < maxLength; i++) {\n if (i < source.length) {\n if (i < target.length && target[i] !== undefined) {\n // Both source and target have element at this index - merge them\n result[i] = deepMergeContent(target[i], source[i], locale);\n } else {\n // Only source has element at this index - process new content\n result[i] = processNewContent(source[i], locale);\n }\n } else {\n // Only target has element at this index - keep it\n result[i] = target[i];\n }\n }\n\n return result;\n } else {\n // No locale or target is not an array - replace entirely\n return source.map((item) => {\n // Process each item in case it needs locale wrapping\n if (\n item &&\n typeof item === 'object' &&\n item.nodeType === NodeTypes.TRANSLATION\n ) {\n return item;\n }\n return processNewContent(item, locale);\n });\n }\n }\n\n // Handle objects\n if (typeof source === 'object' && !Array.isArray(source)) {\n if (typeof target !== 'object' || Array.isArray(target)) {\n target = {};\n }\n\n // Create new object to preserve key order and avoid mutation\n const result: any = { ...target };\n\n for (const key in source) {\n if (Object.hasOwn(source, key)) {\n if (target[key] !== undefined) {\n result[key] = deepMergeContent(target[key], source[key], locale);\n } else {\n result[key] = processNewContent(source[key], locale);\n }\n }\n }\n\n return result;\n }\n\n // For primitives, just return the source\n return source;\n};\n\n/**\n * Process new content that doesn't exist in target\n * @param content - New content to process\n * @param locale - Optional locale\n * @returns Processed content\n */\nconst processNewContent = (content: any, locale?: LocalesValues): any => {\n // Handle null and undefined\n if (content === null || content === undefined) {\n return content;\n }\n\n // If content is already a translation node, return as-is\n if (\n content &&\n typeof content === 'object' &&\n content.nodeType === NodeTypes.TRANSLATION\n ) {\n return content;\n }\n\n // Handle arrays\n if (Array.isArray(content)) {\n return content.map((item) => processNewContent(item, locale));\n }\n\n // Handle objects\n if (content && typeof content === 'object') {\n const result: any = {};\n\n for (const key in content) {\n if (Object.hasOwn(content, key)) {\n result[key] = processNewContent(content[key], locale);\n }\n }\n return result;\n }\n\n // Handle primitives\n if (locale) {\n // Wrap in translation node with the specific locale\n return {\n nodeType: NodeTypes.TRANSLATION,\n [NodeTypes.TRANSLATION]: {\n [locale]: content,\n },\n };\n } else {\n // If no locale, just return the content as-is (don't wrap)\n return content;\n }\n};\n\n/**\n * Insert content into a dictionary with deep merge support\n * Handles translation blocks and nested structures\n *\n * @param dictionary - The dictionary to insert content into\n * @param content - The content to insert\n * @param locale - Optional locale to target specific translation\n * @returns Updated dictionary\n *\n * @example\n * // Without locale - deep merge all content\n * insertContentInDictionary(dictionary, { title: 'New Title' })\n *\n * @example\n * // With locale - insert content for specific locale\n * insertContentInDictionary(dictionary, { title: 'このページ' }, 'ja')\n */\nexport const insertContentInDictionary = (\n dictionary: Dictionary,\n content: Dictionary['content'],\n locale?: LocalesValues\n): Dictionary => {\n const mergedContent = deepMergeContent(\n Array.isArray(dictionary.content)\n ? [...dictionary.content]\n : { ...dictionary.content },\n content,\n locale\n );\n\n return {\n ...dictionary,\n content: mergedContent,\n };\n};\n"],"mappings":"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"}
@@ -40,11 +40,12 @@ const editDictionaryByKeyPath = (dictionaryContent, keyPath, newValue) => {
40
40
  let target = parentValue;
41
41
  for (const key of lastKeys.slice(0, -1)) target = target[key];
42
42
  const finalKey = lastKeys[lastKeys.length - 1];
43
- if (typeof newValue === "undefined") if (Array.isArray(target)) {
44
- const index = Number(finalKey);
45
- if (!Number.isNaN(index) && index >= 0 && index < target.length) target.splice(index, 1);
46
- } else delete target[finalKey];
47
- else target[finalKey] = newValue;
43
+ if (typeof newValue === "undefined") {
44
+ if (Array.isArray(target)) {
45
+ const index = Number(finalKey);
46
+ if (!Number.isNaN(index) && index >= 0 && index < target.length) target.splice(index, 1);
47
+ } else delete target[finalKey];
48
+ } else target[finalKey] = newValue;
48
49
  }
49
50
  }
50
51
  return dictionaryContent;
@@ -1 +1 @@
1
- {"version":3,"file":"editDictionaryByKeyPath.mjs","names":[],"sources":["../../../src/dictionaryManipulator/editDictionaryByKeyPath.ts"],"sourcesContent":["import type { ContentNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport * as NodeTypes from '@intlayer/types/nodeType';\n\ntype LastKeyType = string | number;\n\nexport const editDictionaryByKeyPath = (\n dictionaryContent: ContentNode,\n keyPath: KeyPath[],\n newValue: ContentNode\n): ContentNode => {\n let currentValue: any = dictionaryContent;\n let parentValue: any = null;\n let lastKeys: LastKeyType[] = [];\n\n if (keyPath.length === 0) {\n return newValue;\n }\n\n try {\n for (let i = 0; i < keyPath.length; i++) {\n const keyObj = keyPath[i];\n parentValue = currentValue;\n\n if (\n keyObj?.type === NodeTypes.OBJECT ||\n keyObj?.type === NodeTypes.ARRAY\n ) {\n lastKeys = [keyObj.key];\n\n if (\n !currentValue[keyObj.key] ||\n typeof currentValue[keyObj.key] !== 'object'\n ) {\n currentValue[keyObj.key] = {};\n }\n currentValue = currentValue[keyObj.key];\n }\n\n if (\n keyObj?.type === NodeTypes.TRANSLATION ||\n keyObj?.type === NodeTypes.ENUMERATION ||\n keyObj?.type === NodeTypes.PLURAL ||\n keyObj?.type === NodeTypes.GENDER ||\n keyObj?.type === NodeTypes.SELECT\n ) {\n lastKeys = [keyObj.type, keyObj.key];\n\n if (\n !currentValue[keyObj.type] ||\n typeof currentValue[keyObj.type] !== 'object'\n ) {\n currentValue[keyObj.type] = {};\n }\n\n if (\n !currentValue[keyObj.type][keyObj.key] ||\n typeof currentValue[keyObj.type][keyObj.key] !== 'object'\n ) {\n currentValue[keyObj.type][keyObj.key] = {};\n }\n currentValue = currentValue[keyObj.type][keyObj.key];\n }\n\n if (\n keyObj?.type === NodeTypes.ENUMERATION ||\n keyObj?.type === NodeTypes.PLURAL ||\n keyObj?.type === NodeTypes.CONDITION\n ) {\n // Note: Logic above already handles Enumeration/Plural, ensure no duplication in your actual file\n // or keep the specific block if your logic differs.\n // The important part is below in the final update block.\n\n // Assuming this block runs for Condition/Gender/etc:\n\n if (\n keyObj.type !== NodeTypes.ENUMERATION &&\n keyObj.type !== NodeTypes.PLURAL\n ) {\n lastKeys = [keyObj.type, keyObj.key];\n currentValue = currentValue[keyObj.type][keyObj.key];\n }\n }\n\n if (\n keyObj?.type === NodeTypes.MARKDOWN ||\n keyObj?.type === NodeTypes.HTML ||\n keyObj?.type === NodeTypes.INSERTION\n ) {\n lastKeys = [keyObj.type];\n\n if (currentValue[keyObj.type] == null) {\n currentValue[keyObj.type] = '';\n }\n currentValue = currentValue[keyObj.type];\n }\n\n if (keyObj?.type === NodeTypes.FILE) {\n lastKeys = ['content'];\n currentValue = currentValue.content;\n }\n\n // Only update the value when processing the last key in the keyPath.\n\n if (i === keyPath.length - 1 && parentValue && lastKeys.length > 0) {\n let target = parentValue;\n\n // Drill down to the container holding the value to be changed\n for (const key of lastKeys.slice(0, -1)) {\n target = target[key];\n }\n\n const finalKey = lastKeys[lastKeys.length - 1];\n\n if (typeof newValue === 'undefined') {\n // Use splice for arrays to re-index the list, use delete for objects\n\n if (Array.isArray(target)) {\n const index = Number(finalKey);\n\n if (!Number.isNaN(index) && index >= 0 && index < target.length) {\n target.splice(index, 1);\n }\n } else {\n delete target[finalKey];\n }\n } else {\n target[finalKey] = newValue;\n }\n }\n }\n\n return dictionaryContent;\n } catch (error) {\n console.error(\n 'Cannot edit dictionary by key path',\n { dictionaryContent, keyPath, newValue },\n error\n );\n return dictionaryContent;\n }\n};\n"],"mappings":";;;AAMA,MAAa,2BACX,mBACA,SACA,aACgB;CAChB,IAAI,eAAoB;CACxB,IAAI,cAAmB;CACvB,IAAI,WAA0B,CAAC;CAE/B,IAAI,QAAQ,WAAW,GACrB,OAAO;CAGT,IAAI;EACF,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;GACvC,MAAM,SAAS,QAAQ;GACvB,cAAc;GAEd,IACE,QAAQ,SAAS,UAAU,UAC3B,QAAQ,SAAS,UAAU,OAC3B;IACA,WAAW,CAAC,OAAO,GAAG;IAEtB,IACE,CAAC,aAAa,OAAO,QACrB,OAAO,aAAa,OAAO,SAAS,UAEpC,aAAa,OAAO,OAAO,CAAC;IAE9B,eAAe,aAAa,OAAO;GACrC;GAEA,IACE,QAAQ,SAAS,UAAU,eAC3B,QAAQ,SAAS,UAAU,eAC3B,QAAQ,SAAS,UAAU,UAC3B,QAAQ,SAAS,UAAU,UAC3B,QAAQ,SAAS,UAAU,QAC3B;IACA,WAAW,CAAC,OAAO,MAAM,OAAO,GAAG;IAEnC,IACE,CAAC,aAAa,OAAO,SACrB,OAAO,aAAa,OAAO,UAAU,UAErC,aAAa,OAAO,QAAQ,CAAC;IAG/B,IACE,CAAC,aAAa,OAAO,KAAK,CAAC,OAAO,QAClC,OAAO,aAAa,OAAO,KAAK,CAAC,OAAO,SAAS,UAEjD,aAAa,OAAO,KAAK,CAAC,OAAO,OAAO,CAAC;IAE3C,eAAe,aAAa,OAAO,KAAK,CAAC,OAAO;GAClD;GAEA,IACE,QAAQ,SAAS,UAAU,eAC3B,QAAQ,SAAS,UAAU,UAC3B,QAAQ,SAAS,UAAU,WAQ3B;QACE,OAAO,SAAS,UAAU,eAC1B,OAAO,SAAS,UAAU,QAC1B;KACA,WAAW,CAAC,OAAO,MAAM,OAAO,GAAG;KACnC,eAAe,aAAa,OAAO,KAAK,CAAC,OAAO;IAClD;;GAGF,IACE,QAAQ,SAAS,UAAU,YAC3B,QAAQ,SAAS,UAAU,QAC3B,QAAQ,SAAS,UAAU,WAC3B;IACA,WAAW,CAAC,OAAO,IAAI;IAEvB,IAAI,aAAa,OAAO,SAAS,MAC/B,aAAa,OAAO,QAAQ;IAE9B,eAAe,aAAa,OAAO;GACrC;GAEA,IAAI,QAAQ,SAAS,UAAU,MAAM;IACnC,WAAW,CAAC,SAAS;IACrB,eAAe,aAAa;GAC9B;GAIA,IAAI,MAAM,QAAQ,SAAS,KAAK,eAAe,SAAS,SAAS,GAAG;IAClE,IAAI,SAAS;IAGb,KAAK,MAAM,OAAO,SAAS,MAAM,GAAG,EAAE,GACpC,SAAS,OAAO;IAGlB,MAAM,WAAW,SAAS,SAAS,SAAS;IAE5C,IAAI,OAAO,aAAa,aAGtB,IAAI,MAAM,QAAQ,MAAM,GAAG;KACzB,MAAM,QAAQ,OAAO,QAAQ;KAE7B,IAAI,CAAC,OAAO,MAAM,KAAK,KAAK,SAAS,KAAK,QAAQ,OAAO,QACvD,OAAO,OAAO,OAAO,CAAC;IAE1B,OACE,OAAO,OAAO;SAGhB,OAAO,YAAY;GAEvB;EACF;EAEA,OAAO;CACT,SAAS,OAAO;EACd,QAAQ,MACN,sCACA;GAAE;GAAmB;GAAS;EAAS,GACvC,KACF;EACA,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"editDictionaryByKeyPath.mjs","names":[],"sources":["../../../src/dictionaryManipulator/editDictionaryByKeyPath.ts"],"sourcesContent":["import type { ContentNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport * as NodeTypes from '@intlayer/types/nodeType';\n\ntype LastKeyType = string | number;\n\nexport const editDictionaryByKeyPath = (\n dictionaryContent: ContentNode,\n keyPath: KeyPath[],\n newValue: ContentNode\n): ContentNode => {\n let currentValue: any = dictionaryContent;\n let parentValue: any = null;\n let lastKeys: LastKeyType[] = [];\n\n if (keyPath.length === 0) {\n return newValue;\n }\n\n try {\n for (let i = 0; i < keyPath.length; i++) {\n const keyObj = keyPath[i];\n parentValue = currentValue;\n\n if (\n keyObj?.type === NodeTypes.OBJECT ||\n keyObj?.type === NodeTypes.ARRAY\n ) {\n lastKeys = [keyObj.key];\n\n if (\n !currentValue[keyObj.key] ||\n typeof currentValue[keyObj.key] !== 'object'\n ) {\n currentValue[keyObj.key] = {};\n }\n currentValue = currentValue[keyObj.key];\n }\n\n if (\n keyObj?.type === NodeTypes.TRANSLATION ||\n keyObj?.type === NodeTypes.ENUMERATION ||\n keyObj?.type === NodeTypes.PLURAL ||\n keyObj?.type === NodeTypes.GENDER ||\n keyObj?.type === NodeTypes.SELECT\n ) {\n lastKeys = [keyObj.type, keyObj.key];\n\n if (\n !currentValue[keyObj.type] ||\n typeof currentValue[keyObj.type] !== 'object'\n ) {\n currentValue[keyObj.type] = {};\n }\n\n if (\n !currentValue[keyObj.type][keyObj.key] ||\n typeof currentValue[keyObj.type][keyObj.key] !== 'object'\n ) {\n currentValue[keyObj.type][keyObj.key] = {};\n }\n currentValue = currentValue[keyObj.type][keyObj.key];\n }\n\n if (\n keyObj?.type === NodeTypes.ENUMERATION ||\n keyObj?.type === NodeTypes.PLURAL ||\n keyObj?.type === NodeTypes.CONDITION\n ) {\n // Note: Logic above already handles Enumeration/Plural, ensure no duplication in your actual file\n // or keep the specific block if your logic differs.\n // The important part is below in the final update block.\n\n // Assuming this block runs for Condition/Gender/etc:\n\n if (\n keyObj.type !== NodeTypes.ENUMERATION &&\n keyObj.type !== NodeTypes.PLURAL\n ) {\n lastKeys = [keyObj.type, keyObj.key];\n currentValue = currentValue[keyObj.type][keyObj.key];\n }\n }\n\n if (\n keyObj?.type === NodeTypes.MARKDOWN ||\n keyObj?.type === NodeTypes.HTML ||\n keyObj?.type === NodeTypes.INSERTION\n ) {\n lastKeys = [keyObj.type];\n\n if (currentValue[keyObj.type] == null) {\n currentValue[keyObj.type] = '';\n }\n currentValue = currentValue[keyObj.type];\n }\n\n if (keyObj?.type === NodeTypes.FILE) {\n lastKeys = ['content'];\n currentValue = currentValue.content;\n }\n\n // Only update the value when processing the last key in the keyPath.\n\n if (i === keyPath.length - 1 && parentValue && lastKeys.length > 0) {\n let target = parentValue;\n\n // Drill down to the container holding the value to be changed\n for (const key of lastKeys.slice(0, -1)) {\n target = target[key];\n }\n\n const finalKey = lastKeys[lastKeys.length - 1];\n\n if (typeof newValue === 'undefined') {\n // Use splice for arrays to re-index the list, use delete for objects\n\n if (Array.isArray(target)) {\n const index = Number(finalKey);\n\n if (!Number.isNaN(index) && index >= 0 && index < target.length) {\n target.splice(index, 1);\n }\n } else {\n delete target[finalKey];\n }\n } else {\n target[finalKey] = newValue;\n }\n }\n }\n\n return dictionaryContent;\n } catch (error) {\n console.error(\n 'Cannot edit dictionary by key path',\n { dictionaryContent, keyPath, newValue },\n error\n );\n return dictionaryContent;\n }\n};\n"],"mappings":";;;AAMA,MAAa,2BACX,mBACA,SACA,aACgB;CAChB,IAAI,eAAoB;CACxB,IAAI,cAAmB;CACvB,IAAI,WAA0B,CAAC;CAE/B,IAAI,QAAQ,WAAW,GACrB,OAAO;CAGT,IAAI;EACF,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;GACvC,MAAM,SAAS,QAAQ;GACvB,cAAc;GAEd,IACE,QAAQ,SAAS,UAAU,UAC3B,QAAQ,SAAS,UAAU,OAC3B;IACA,WAAW,CAAC,OAAO,GAAG;IAEtB,IACE,CAAC,aAAa,OAAO,QACrB,OAAO,aAAa,OAAO,SAAS,UAEpC,aAAa,OAAO,OAAO,CAAC;IAE9B,eAAe,aAAa,OAAO;GACrC;GAEA,IACE,QAAQ,SAAS,UAAU,eAC3B,QAAQ,SAAS,UAAU,eAC3B,QAAQ,SAAS,UAAU,UAC3B,QAAQ,SAAS,UAAU,UAC3B,QAAQ,SAAS,UAAU,QAC3B;IACA,WAAW,CAAC,OAAO,MAAM,OAAO,GAAG;IAEnC,IACE,CAAC,aAAa,OAAO,SACrB,OAAO,aAAa,OAAO,UAAU,UAErC,aAAa,OAAO,QAAQ,CAAC;IAG/B,IACE,CAAC,aAAa,OAAO,KAAK,CAAC,OAAO,QAClC,OAAO,aAAa,OAAO,KAAK,CAAC,OAAO,SAAS,UAEjD,aAAa,OAAO,KAAK,CAAC,OAAO,OAAO,CAAC;IAE3C,eAAe,aAAa,OAAO,KAAK,CAAC,OAAO;GAClD;GAEA,IACE,QAAQ,SAAS,UAAU,eAC3B,QAAQ,SAAS,UAAU,UAC3B,QAAQ,SAAS,UAAU,WAQ3B;QACE,OAAO,SAAS,UAAU,eAC1B,OAAO,SAAS,UAAU,QAC1B;KACA,WAAW,CAAC,OAAO,MAAM,OAAO,GAAG;KACnC,eAAe,aAAa,OAAO,KAAK,CAAC,OAAO;IAClD;;GAGF,IACE,QAAQ,SAAS,UAAU,YAC3B,QAAQ,SAAS,UAAU,QAC3B,QAAQ,SAAS,UAAU,WAC3B;IACA,WAAW,CAAC,OAAO,IAAI;IAEvB,IAAI,aAAa,OAAO,SAAS,MAC/B,aAAa,OAAO,QAAQ;IAE9B,eAAe,aAAa,OAAO;GACrC;GAEA,IAAI,QAAQ,SAAS,UAAU,MAAM;IACnC,WAAW,CAAC,SAAS;IACrB,eAAe,aAAa;GAC9B;GAIA,IAAI,MAAM,QAAQ,SAAS,KAAK,eAAe,SAAS,SAAS,GAAG;IAClE,IAAI,SAAS;IAGb,KAAK,MAAM,OAAO,SAAS,MAAM,GAAG,EAAE,GACpC,SAAS,OAAO;IAGlB,MAAM,WAAW,SAAS,SAAS,SAAS;IAE5C,IAAI,OAAO,aAAa,aAAa;KAGnC,IAAI,MAAM,QAAQ,MAAM,GAAG;MACzB,MAAM,QAAQ,OAAO,QAAQ;MAE7B,IAAI,CAAC,OAAO,MAAM,KAAK,KAAK,SAAS,KAAK,QAAQ,OAAO,QACvD,OAAO,OAAO,OAAO,CAAC;KAE1B,OACE,OAAO,OAAO;IAElB,OACE,OAAO,YAAY;GAEvB;EACF;EAEA,OAAO;CACT,SAAS,OAAO;EACd,QAAQ,MACN,sCACA;GAAE;GAAmB;GAAS;EAAS,GACvC,KACF;EACA,OAAO;CACT;AACF"}
@@ -0,0 +1,150 @@
1
+ import { NESTED } from "@intlayer/types/nodeType";
2
+
3
+ //#region src/dictionaryManipulator/getNestedDictionaryReferences.ts
4
+ /**
5
+ * Compact alias some minified pipelines emit in place of `nodeType: 'nested'`.
6
+ * Matched defensively so the scan keeps working on already-minified content.
7
+ */
8
+ const MINIFIED_NESTED_NODE_TYPE = "n";
9
+ /**
10
+ * Narrows a value to a traversable object (plain object or array). `null` is
11
+ * excluded even though `typeof null === 'object'`.
12
+ */
13
+ const isTraversable = (value) => typeof value === "object" && value !== null;
14
+ /**
15
+ * Records one `nest()` reference, widening the entry to `'all'` as soon as a
16
+ * reference targets the whole dictionary.
17
+ */
18
+ const addNestedReference = (references, dictionaryKey, path) => {
19
+ const existingReference = references.get(dictionaryKey);
20
+ if (existingReference === "all") return;
21
+ const rootField = path?.split(".")[0];
22
+ if (!rootField) {
23
+ references.set(dictionaryKey, "all");
24
+ return;
25
+ }
26
+ if (existingReference) {
27
+ existingReference.add(rootField);
28
+ return;
29
+ }
30
+ references.set(dictionaryKey, /* @__PURE__ */ new Set([rootField]));
31
+ };
32
+ /**
33
+ * Walks a dictionary tree and collects every dictionary referenced through a
34
+ * `nest()` node, together with the top-level fields those references read.
35
+ *
36
+ * The walk is iterative (no recursion depth limit) and guards against shared
37
+ * or circular references, so it is safe on both compiled JSON and in-memory
38
+ * dictionaries.
39
+ *
40
+ * @param dictionaries - Dictionary objects (or any content subtree) to scan.
41
+ * @returns Map of nest-target dictionary key → referenced top-level fields.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * // dashboard.content.ts → { period: nest('common', 'period') }
46
+ * getNestedDictionaryReferences([dashboardDictionary]);
47
+ * // Map { 'common' => Set { 'period' } }
48
+ * ```
49
+ */
50
+ const getNestedDictionaryReferences = (dictionaries) => {
51
+ const references = /* @__PURE__ */ new Map();
52
+ const stack = [...dictionaries];
53
+ const visitedNodes = /* @__PURE__ */ new Set();
54
+ while (stack.length > 0) {
55
+ const node = stack.pop();
56
+ if (!isTraversable(node)) continue;
57
+ if (visitedNodes.has(node)) continue;
58
+ visitedNodes.add(node);
59
+ if (Array.isArray(node)) {
60
+ stack.push(...node);
61
+ continue;
62
+ }
63
+ const { nodeType } = node;
64
+ if (nodeType === NESTED || nodeType === MINIFIED_NESTED_NODE_TYPE) {
65
+ const nestedState = node[nodeType];
66
+ if (isTraversable(nestedState)) {
67
+ const { dictionaryKey, path } = nestedState;
68
+ if (typeof dictionaryKey === "string") addNestedReference(references, dictionaryKey, typeof path === "string" ? path : void 0);
69
+ }
70
+ continue;
71
+ }
72
+ stack.push(...Object.values(node));
73
+ }
74
+ return references;
75
+ };
76
+ /**
77
+ * Keys of every dictionary referenced through a `nest()` node.
78
+ *
79
+ * @param dictionaries - Dictionary objects (or any content subtree) to scan.
80
+ * @returns Set of nest-target dictionary keys.
81
+ */
82
+ const getNestedDictionaryKeys = (dictionaries) => new Set(getNestedDictionaryReferences(dictionaries).keys());
83
+ /**
84
+ * Expands direct nest edges into their transitive closure, so a consumer that
85
+ * nests a dictionary which itself nests another ends up depending on both.
86
+ *
87
+ * Self-references and cycles are absorbed: a key never appears in its own
88
+ * dependency set, and the walk terminates on cyclic graphs.
89
+ */
90
+ const closeOverNestedEdges = (directEdges) => {
91
+ const closedEdges = /* @__PURE__ */ new Map();
92
+ for (const [consumerKey, directTargets] of directEdges) {
93
+ const allTargets = /* @__PURE__ */ new Set();
94
+ const pending = [...directTargets];
95
+ while (pending.length > 0) {
96
+ const targetKey = pending.pop();
97
+ if (targetKey === consumerKey) continue;
98
+ if (allTargets.has(targetKey)) continue;
99
+ allTargets.add(targetKey);
100
+ const transitiveTargets = directEdges.get(targetKey);
101
+ if (transitiveTargets) pending.push(...transitiveTargets);
102
+ }
103
+ closedEdges.set(consumerKey, allTargets);
104
+ }
105
+ return closedEdges;
106
+ };
107
+ /**
108
+ * Builds the `nest()` dependency graph of a set of dictionaries: for each
109
+ * dictionary key, the keys of every dictionary it needs in order to resolve its
110
+ * nested nodes, transitively.
111
+ *
112
+ * The build optimization uses this to attach the nest targets to the dictionary
113
+ * artifact itself, so `nest()` resolves from a local reference and the target
114
+ * lands in the same chunk (or the same lazy per-locale loader) as the
115
+ * dictionary referencing it.
116
+ *
117
+ * Dictionaries without nested nodes are absent from the result.
118
+ *
119
+ * @param dictionaries - Compiled dictionaries to scan; each must carry its `key`.
120
+ * @returns Map of dictionary key → keys it depends on through `nest()`.
121
+ *
122
+ * @example
123
+ * ```ts
124
+ * // dashboard nests common, common nests labels
125
+ * getNestedDictionaryGraph([dashboard, common]);
126
+ * // Map { 'dashboard' => Set { 'common', 'labels' }, 'common' => Set { 'labels' } }
127
+ * ```
128
+ */
129
+ const getNestedDictionaryGraph = (dictionaries) => {
130
+ const directEdges = /* @__PURE__ */ new Map();
131
+ for (const dictionary of dictionaries) {
132
+ if (!isTraversable(dictionary)) continue;
133
+ const { key } = dictionary;
134
+ if (typeof key !== "string") continue;
135
+ const targets = getNestedDictionaryKeys([dictionary]);
136
+ targets.delete(key);
137
+ if (targets.size === 0) continue;
138
+ const existingTargets = directEdges.get(key);
139
+ if (existingTargets) {
140
+ for (const target of targets) existingTargets.add(target);
141
+ continue;
142
+ }
143
+ directEdges.set(key, targets);
144
+ }
145
+ return closeOverNestedEdges(directEdges);
146
+ };
147
+
148
+ //#endregion
149
+ export { getNestedDictionaryGraph, getNestedDictionaryKeys, getNestedDictionaryReferences };
150
+ //# sourceMappingURL=getNestedDictionaryReferences.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getNestedDictionaryReferences.mjs","names":[],"sources":["../../../src/dictionaryManipulator/getNestedDictionaryReferences.ts"],"sourcesContent":["import { NESTED } from '@intlayer/types/nodeType';\n\n/**\n * Top-level content fields of a nest target that are referenced through\n * `nest()` nodes.\n *\n * `'all'` means at least one reference targets the whole dictionary\n * (`nest('common')` without a path), so no field of that dictionary may be\n * dropped.\n */\nexport type NestedFieldReferences = Set<string> | 'all';\n\n/**\n * Compact alias some minified pipelines emit in place of `nodeType: 'nested'`.\n * Matched defensively so the scan keeps working on already-minified content.\n */\nconst MINIFIED_NESTED_NODE_TYPE = 'n';\n\ntype UnknownRecord = Record<string, unknown>;\n\n/**\n * Narrows a value to a traversable object (plain object or array). `null` is\n * excluded even though `typeof null === 'object'`.\n */\nconst isTraversable = (value: unknown): value is UnknownRecord =>\n typeof value === 'object' && value !== null;\n\n/**\n * Records one `nest()` reference, widening the entry to `'all'` as soon as a\n * reference targets the whole dictionary.\n */\nconst addNestedReference = (\n references: Map<string, NestedFieldReferences>,\n dictionaryKey: string,\n path: string | undefined\n): void => {\n const existingReference = references.get(dictionaryKey);\n\n if (existingReference === 'all') return;\n\n // `getNesting` returns the whole dictionary when no path is given, and also\n // falls back to it when the path cannot be resolved — both cases require\n // every field to stay available.\n const rootField = path?.split('.')[0];\n\n if (!rootField) {\n references.set(dictionaryKey, 'all');\n return;\n }\n\n if (existingReference) {\n existingReference.add(rootField);\n return;\n }\n\n references.set(dictionaryKey, new Set([rootField]));\n};\n\n/**\n * Walks a dictionary tree and collects every dictionary referenced through a\n * `nest()` node, together with the top-level fields those references read.\n *\n * The walk is iterative (no recursion depth limit) and guards against shared\n * or circular references, so it is safe on both compiled JSON and in-memory\n * dictionaries.\n *\n * @param dictionaries - Dictionary objects (or any content subtree) to scan.\n * @returns Map of nest-target dictionary key → referenced top-level fields.\n *\n * @example\n * ```ts\n * // dashboard.content.ts → { period: nest('common', 'period') }\n * getNestedDictionaryReferences([dashboardDictionary]);\n * // Map { 'common' => Set { 'period' } }\n * ```\n */\nexport const getNestedDictionaryReferences = (\n dictionaries: Iterable<unknown>\n): Map<string, NestedFieldReferences> => {\n const references = new Map<string, NestedFieldReferences>();\n const stack: unknown[] = [...dictionaries];\n const visitedNodes = new Set<object>();\n\n while (stack.length > 0) {\n const node = stack.pop();\n\n if (!isTraversable(node)) continue;\n if (visitedNodes.has(node)) continue;\n visitedNodes.add(node);\n\n if (Array.isArray(node)) {\n stack.push(...node);\n continue;\n }\n\n const { nodeType } = node;\n\n if (nodeType === NESTED || nodeType === MINIFIED_NESTED_NODE_TYPE) {\n const nestedState = node[nodeType];\n\n if (isTraversable(nestedState)) {\n const { dictionaryKey, path } = nestedState;\n\n if (typeof dictionaryKey === 'string') {\n addNestedReference(\n references,\n dictionaryKey,\n typeof path === 'string' ? path : undefined\n );\n }\n }\n\n // A nested node only carries the reference descriptor — no sub-content.\n continue;\n }\n\n stack.push(...Object.values(node));\n }\n\n return references;\n};\n\n/**\n * Keys of every dictionary referenced through a `nest()` node.\n *\n * @param dictionaries - Dictionary objects (or any content subtree) to scan.\n * @returns Set of nest-target dictionary keys.\n */\nexport const getNestedDictionaryKeys = (\n dictionaries: Iterable<unknown>\n): Set<string> => new Set(getNestedDictionaryReferences(dictionaries).keys());\n\n/**\n * Expands direct nest edges into their transitive closure, so a consumer that\n * nests a dictionary which itself nests another ends up depending on both.\n *\n * Self-references and cycles are absorbed: a key never appears in its own\n * dependency set, and the walk terminates on cyclic graphs.\n */\nconst closeOverNestedEdges = (\n directEdges: Map<string, Set<string>>\n): Map<string, Set<string>> => {\n const closedEdges = new Map<string, Set<string>>();\n\n for (const [consumerKey, directTargets] of directEdges) {\n const allTargets = new Set<string>();\n const pending = [...directTargets];\n\n while (pending.length > 0) {\n const targetKey = pending.pop()!;\n\n if (targetKey === consumerKey) continue;\n if (allTargets.has(targetKey)) continue;\n allTargets.add(targetKey);\n\n const transitiveTargets = directEdges.get(targetKey);\n if (transitiveTargets) pending.push(...transitiveTargets);\n }\n\n closedEdges.set(consumerKey, allTargets);\n }\n\n return closedEdges;\n};\n\n/**\n * Builds the `nest()` dependency graph of a set of dictionaries: for each\n * dictionary key, the keys of every dictionary it needs in order to resolve its\n * nested nodes, transitively.\n *\n * The build optimization uses this to attach the nest targets to the dictionary\n * artifact itself, so `nest()` resolves from a local reference and the target\n * lands in the same chunk (or the same lazy per-locale loader) as the\n * dictionary referencing it.\n *\n * Dictionaries without nested nodes are absent from the result.\n *\n * @param dictionaries - Compiled dictionaries to scan; each must carry its `key`.\n * @returns Map of dictionary key → keys it depends on through `nest()`.\n *\n * @example\n * ```ts\n * // dashboard nests common, common nests labels\n * getNestedDictionaryGraph([dashboard, common]);\n * // Map { 'dashboard' => Set { 'common', 'labels' }, 'common' => Set { 'labels' } }\n * ```\n */\nexport const getNestedDictionaryGraph = (\n dictionaries: Iterable<unknown>\n): Map<string, Set<string>> => {\n const directEdges = new Map<string, Set<string>>();\n\n for (const dictionary of dictionaries) {\n if (!isTraversable(dictionary)) continue;\n\n const { key } = dictionary;\n if (typeof key !== 'string') continue;\n\n const targets = getNestedDictionaryKeys([dictionary]);\n targets.delete(key);\n\n if (targets.size === 0) continue;\n\n // Several compiled entries can share a key (qualified groups); merge them.\n const existingTargets = directEdges.get(key);\n if (existingTargets) {\n for (const target of targets) existingTargets.add(target);\n continue;\n }\n\n directEdges.set(key, targets);\n }\n\n return closeOverNestedEdges(directEdges);\n};\n"],"mappings":";;;;;;;AAgBA,MAAM,4BAA4B;;;;;AAQlC,MAAM,iBAAiB,UACrB,OAAO,UAAU,YAAY,UAAU;;;;;AAMzC,MAAM,sBACJ,YACA,eACA,SACS;CACT,MAAM,oBAAoB,WAAW,IAAI,aAAa;CAEtD,IAAI,sBAAsB,OAAO;CAKjC,MAAM,YAAY,MAAM,MAAM,GAAG,CAAC,CAAC;CAEnC,IAAI,CAAC,WAAW;EACd,WAAW,IAAI,eAAe,KAAK;EACnC;CACF;CAEA,IAAI,mBAAmB;EACrB,kBAAkB,IAAI,SAAS;EAC/B;CACF;CAEA,WAAW,IAAI,+BAAe,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;AACpD;;;;;;;;;;;;;;;;;;;AAoBA,MAAa,iCACX,iBACuC;CACvC,MAAM,6BAAa,IAAI,IAAmC;CAC1D,MAAM,QAAmB,CAAC,GAAG,YAAY;CACzC,MAAM,+BAAe,IAAI,IAAY;CAErC,OAAO,MAAM,SAAS,GAAG;EACvB,MAAM,OAAO,MAAM,IAAI;EAEvB,IAAI,CAAC,cAAc,IAAI,GAAG;EAC1B,IAAI,aAAa,IAAI,IAAI,GAAG;EAC5B,aAAa,IAAI,IAAI;EAErB,IAAI,MAAM,QAAQ,IAAI,GAAG;GACvB,MAAM,KAAK,GAAG,IAAI;GAClB;EACF;EAEA,MAAM,EAAE,aAAa;EAErB,IAAI,aAAa,UAAU,aAAa,2BAA2B;GACjE,MAAM,cAAc,KAAK;GAEzB,IAAI,cAAc,WAAW,GAAG;IAC9B,MAAM,EAAE,eAAe,SAAS;IAEhC,IAAI,OAAO,kBAAkB,UAC3B,mBACE,YACA,eACA,OAAO,SAAS,WAAW,OAAO,MACpC;GAEJ;GAGA;EACF;EAEA,MAAM,KAAK,GAAG,OAAO,OAAO,IAAI,CAAC;CACnC;CAEA,OAAO;AACT;;;;;;;AAQA,MAAa,2BACX,iBACgB,IAAI,IAAI,8BAA8B,YAAY,CAAC,CAAC,KAAK,CAAC;;;;;;;;AAS5E,MAAM,wBACJ,gBAC6B;CAC7B,MAAM,8BAAc,IAAI,IAAyB;CAEjD,KAAK,MAAM,CAAC,aAAa,kBAAkB,aAAa;EACtD,MAAM,6BAAa,IAAI,IAAY;EACnC,MAAM,UAAU,CAAC,GAAG,aAAa;EAEjC,OAAO,QAAQ,SAAS,GAAG;GACzB,MAAM,YAAY,QAAQ,IAAI;GAE9B,IAAI,cAAc,aAAa;GAC/B,IAAI,WAAW,IAAI,SAAS,GAAG;GAC/B,WAAW,IAAI,SAAS;GAExB,MAAM,oBAAoB,YAAY,IAAI,SAAS;GACnD,IAAI,mBAAmB,QAAQ,KAAK,GAAG,iBAAiB;EAC1D;EAEA,YAAY,IAAI,aAAa,UAAU;CACzC;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAa,4BACX,iBAC6B;CAC7B,MAAM,8BAAc,IAAI,IAAyB;CAEjD,KAAK,MAAM,cAAc,cAAc;EACrC,IAAI,CAAC,cAAc,UAAU,GAAG;EAEhC,MAAM,EAAE,QAAQ;EAChB,IAAI,OAAO,QAAQ,UAAU;EAE7B,MAAM,UAAU,wBAAwB,CAAC,UAAU,CAAC;EACpD,QAAQ,OAAO,GAAG;EAElB,IAAI,QAAQ,SAAS,GAAG;EAGxB,MAAM,kBAAkB,YAAY,IAAI,GAAG;EAC3C,IAAI,iBAAiB;GACnB,KAAK,MAAM,UAAU,SAAS,gBAAgB,IAAI,MAAM;GACxD;EACF;EAEA,YAAY,IAAI,KAAK,OAAO;CAC9B;CAEA,OAAO,qBAAqB,WAAW;AACzC"}