@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
@@ -14,8 +14,9 @@ const fileContent = (path, callerDir, baseDir) => {
14
14
  } else if (isRelativePath) filePath = resolve(callerDir, path);
15
15
  else filePath = resolve(baseDir, path);
16
16
  if (existsSync(filePath) && statSync(filePath).isFile()) try {
17
+ const content = readFileSync(filePath, "utf8");
17
18
  return formatNodeType(FILE, path, {
18
- content: readFileSync(filePath, "utf8"),
19
+ content,
19
20
  fixedPath: relative(baseDir, filePath)
20
21
  });
21
22
  } catch {
@@ -1 +1 @@
1
- {"version":3,"file":"file.mjs","names":["baseDir"],"sources":["../../../../src/transpiler/file/file.ts"],"sourcesContent":["import { existsSync, readFileSync, statSync } from 'node:fs';\nimport { dirname, isAbsolute, relative, resolve } from 'node:path';\nimport { colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport type { TypedNodeModel } from '@intlayer/types/nodeType';\nimport { FILE, formatNodeType } from '@intlayer/types/nodeType';\n\nexport type FileContentConstructor<T extends Record<string, any> = {}> =\n TypedNodeModel<typeof FILE, string, T>;\n\nexport type FileContent = FileContentConstructor<{\n content: string;\n fixedPath?: string;\n}>;\n\nexport const fileContent = (\n path: string,\n callerDir: string,\n baseDir: string\n): FileContent => {\n const isRelativePath = path.startsWith('./') || path.startsWith('../');\n const appLogger = getAppLogger();\n\n let filePath: string;\n if (isAbsolute(path)) {\n appLogger(\n `Using absolute path for file is not recommended. Use relative paths instead. Path: ${path}, imported from: ${callerDir}`,\n { level: 'warn' }\n );\n filePath = path;\n } else if (isRelativePath) {\n filePath = resolve(callerDir, path);\n } else {\n filePath = resolve(baseDir, path);\n }\n\n if (existsSync(filePath) && statSync(filePath).isFile()) {\n try {\n const content = readFileSync(filePath, 'utf8');\n\n return formatNodeType(FILE, path, {\n content,\n fixedPath: relative(baseDir, filePath),\n });\n } catch {\n throw new Error(\n `Unable to read path: ${colorizePath(relative(baseDir, filePath))}`\n );\n }\n } else {\n throw new Error(\n `File not found: ${colorizePath(relative(baseDir, filePath))}`\n );\n }\n};\n\ntype GlobalIntlayerFilePath = {\n INTLAYER_FILE_PATH: string;\n INTLAYER_BASE_DIR: string;\n};\n\n/**\n * Function intended to be used to build intlayer dictionaries.\n *\n * Allow identify the usage of an external resource.\n *\n * Usage:\n *\n * ```ts\n * file('/path/to/file.md') // absolute path\n *\n * // or\n *\n * file('path/to/file.md') // relative path\n * ```\n */\nexport const file = (path: string): FileContent => {\n const { INTLAYER_FILE_PATH, INTLAYER_BASE_DIR } =\n globalThis as unknown as GlobalIntlayerFilePath;\n\n const callerDir = dirname(INTLAYER_FILE_PATH);\n const baseDir = INTLAYER_BASE_DIR;\n\n return fileContent(path, callerDir, baseDir);\n};\n"],"mappings":";;;;;;AAcA,MAAa,eACX,MACA,WACA,YACgB;CAChB,MAAM,iBAAiB,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW,KAAK;CACrE,MAAM,YAAY,aAAa;CAE/B,IAAI;CACJ,IAAI,WAAW,IAAI,GAAG;EACpB,UACE,sFAAsF,KAAK,mBAAmB,aAC9G,EAAE,OAAO,OAAO,CAClB;EACA,WAAW;CACb,OAAO,IAAI,gBACT,WAAW,QAAQ,WAAW,IAAI;MAElC,WAAW,QAAQ,SAAS,IAAI;CAGlC,IAAI,WAAW,QAAQ,KAAK,SAAS,QAAQ,CAAC,CAAC,OAAO,GACpD,IAAI;EAGF,OAAO,eAAe,MAAM,MAAM;GAChC,SAHc,aAAa,UAAU,MAG/B;GACN,WAAW,SAAS,SAAS,QAAQ;EACvC,CAAC;CACH,QAAQ;EACN,MAAM,IAAI,MACR,wBAAwB,aAAa,SAAS,SAAS,QAAQ,CAAC,GAClE;CACF;MAEA,MAAM,IAAI,MACR,mBAAmB,aAAa,SAAS,SAAS,QAAQ,CAAC,GAC7D;AAEJ;;;;;;;;;;;;;;;;AAsBA,MAAa,QAAQ,SAA8B;CACjD,MAAM,EAAE,oBAAoB,sBAC1B;CAEF,MAAM,YAAY,QAAQ,kBAAkB;CAG5C,OAAO,YAAY,MAAM,WAAWA,iBAAO;AAC7C"}
1
+ {"version":3,"file":"file.mjs","names":["baseDir"],"sources":["../../../../src/transpiler/file/file.ts"],"sourcesContent":["import { existsSync, readFileSync, statSync } from 'node:fs';\nimport { dirname, isAbsolute, relative, resolve } from 'node:path';\nimport { colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport type { TypedNodeModel } from '@intlayer/types/nodeType';\nimport { FILE, formatNodeType } from '@intlayer/types/nodeType';\n\nexport type FileContentConstructor<T extends Record<string, any> = {}> =\n TypedNodeModel<typeof FILE, string, T>;\n\nexport type FileContent = FileContentConstructor<{\n content: string;\n fixedPath?: string;\n}>;\n\nexport const fileContent = (\n path: string,\n callerDir: string,\n baseDir: string\n): FileContent => {\n const isRelativePath = path.startsWith('./') || path.startsWith('../');\n const appLogger = getAppLogger();\n\n let filePath: string;\n if (isAbsolute(path)) {\n appLogger(\n `Using absolute path for file is not recommended. Use relative paths instead. Path: ${path}, imported from: ${callerDir}`,\n { level: 'warn' }\n );\n filePath = path;\n } else if (isRelativePath) {\n filePath = resolve(callerDir, path);\n } else {\n filePath = resolve(baseDir, path);\n }\n\n if (existsSync(filePath) && statSync(filePath).isFile()) {\n try {\n const content = readFileSync(filePath, 'utf8');\n\n return formatNodeType(FILE, path, {\n content,\n fixedPath: relative(baseDir, filePath),\n });\n } catch {\n throw new Error(\n `Unable to read path: ${colorizePath(relative(baseDir, filePath))}`\n );\n }\n } else {\n throw new Error(\n `File not found: ${colorizePath(relative(baseDir, filePath))}`\n );\n }\n};\n\ntype GlobalIntlayerFilePath = {\n INTLAYER_FILE_PATH: string;\n INTLAYER_BASE_DIR: string;\n};\n\n/**\n * Function intended to be used to build intlayer dictionaries.\n *\n * Allow identify the usage of an external resource.\n *\n * Usage:\n *\n * ```ts\n * file('/path/to/file.md') // absolute path\n *\n * // or\n *\n * file('path/to/file.md') // relative path\n * ```\n */\nexport const file = (path: string): FileContent => {\n const { INTLAYER_FILE_PATH, INTLAYER_BASE_DIR } =\n globalThis as unknown as GlobalIntlayerFilePath;\n\n const callerDir = dirname(INTLAYER_FILE_PATH);\n const baseDir = INTLAYER_BASE_DIR;\n\n return fileContent(path, callerDir, baseDir);\n};\n"],"mappings":";;;;;;AAcA,MAAa,eACX,MACA,WACA,YACgB;CAChB,MAAM,iBAAiB,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW,KAAK;CACrE,MAAM,YAAY,aAAa;CAE/B,IAAI;CACJ,IAAI,WAAW,IAAI,GAAG;EACpB,UACE,sFAAsF,KAAK,mBAAmB,aAC9G,EAAE,OAAO,OAAO,CAClB;EACA,WAAW;CACb,OAAO,IAAI,gBACT,WAAW,QAAQ,WAAW,IAAI;MAElC,WAAW,QAAQ,SAAS,IAAI;CAGlC,IAAI,WAAW,QAAQ,KAAK,SAAS,QAAQ,CAAC,CAAC,OAAO,GACpD,IAAI;EACF,MAAM,UAAU,aAAa,UAAU,MAAM;EAE7C,OAAO,eAAe,MAAM,MAAM;GAChC;GACA,WAAW,SAAS,SAAS,QAAQ;EACvC,CAAC;CACH,QAAQ;EACN,MAAM,IAAI,MACR,wBAAwB,aAAa,SAAS,SAAS,QAAQ,CAAC,GAClE;CACF;MAEA,MAAM,IAAI,MACR,mBAAmB,aAAa,SAAS,SAAS,QAAQ,CAAC,GAC7D;AAEJ;;;;;;;;;;;;;;;;AAsBA,MAAa,QAAQ,SAA8B;CACjD,MAAM,EAAE,oBAAoB,sBAC1B;CAEF,MAAM,YAAY,QAAQ,kBAAkB;CAG5C,OAAO,YAAY,MAAM,WAAWA,iBAAO;AAC7C"}
@@ -31,19 +31,20 @@ const validateHTML = (content) => {
31
31
  const attrs = match[3];
32
32
  const isSelfClosing = !!match[4];
33
33
  if (attrs.trimStart().startsWith("://") || attrs.trimStart().startsWith(":")) continue;
34
- if (isClosing) if (stack.length === 0) issues.push({
35
- type: "error",
36
- message: `Closing tag </${tagName}> has no matching opening tag`
37
- });
38
- else {
39
- const last = stack[stack.length - 1];
40
- if (last.tag.toLowerCase() !== tagName.toLowerCase()) issues.push({
34
+ if (isClosing) {
35
+ if (stack.length === 0) issues.push({
41
36
  type: "error",
42
- message: `Mismatched closing tag: expected </${last.tag}> but found </${tagName}>`
37
+ message: `Closing tag </${tagName}> has no matching opening tag`
43
38
  });
44
- stack.pop();
45
- }
46
- else {
39
+ else {
40
+ const last = stack[stack.length - 1];
41
+ if (last.tag.toLowerCase() !== tagName.toLowerCase()) issues.push({
42
+ type: "error",
43
+ message: `Mismatched closing tag: expected </${last.tag}> but found </${tagName}>`
44
+ });
45
+ stack.pop();
46
+ }
47
+ } else {
47
48
  const isVoidElement = VOID_HTML_ELEMENTS.has(tagName.toLowerCase());
48
49
  if (!isSelfClosing && !isVoidElement) stack.push({ tag: tagName });
49
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"validateHTML.mjs","names":[],"sources":["../../../../src/transpiler/html/validateHTML.ts"],"sourcesContent":["export const VOID_HTML_ELEMENTS = new Set([\n 'area',\n 'base',\n 'br',\n 'col',\n 'embed',\n 'hr',\n 'img',\n 'input',\n 'link',\n 'meta',\n 'source',\n 'track',\n 'wbr',\n]);\n\nexport type HTMLValidationIssue = {\n type: 'error' | 'warning';\n message: string;\n};\n\nexport type HTMLValidationResult = {\n valid: boolean;\n issues: HTMLValidationIssue[];\n};\n\n// Matches HTML tags: <Tag ...>, </Tag>, or <Tag ... />\n// Attributes may span multiple lines but NOT blank lines (two consecutive newlines),\n// which prevents matching blockquote `>` markers as tag closers.\n// Groups: 1: closing slash, 2: tag name, 3: attributes, 4: self-closing slash\nconst TAG_REGEX =\n /<(\\/)?([a-zA-Z][a-zA-Z0-9.-]*)\\s*((?:[^\\n]|\\n(?!\\n))*?)(\\/?)>/g;\n\n/**\n * Validates that HTML tags in `content` are properly opened, nested, and closed.\n * Returns structured issues instead of logging to the console.\n *\n * False-positive exclusions:\n * - Tags whose attribute string starts with `://` are URL autolinks (e.g. `<https://…>`).\n */\nexport const validateHTML = (content: string): HTMLValidationResult => {\n const issues: HTMLValidationIssue[] = [];\n const stack: Array<{ tag: string }> = [];\n\n for (const match of content.matchAll(TAG_REGEX)) {\n const isClosing = !!match[1];\n const tagName = match[2];\n const attrs = match[3];\n const isSelfClosing = !!match[4];\n\n // Skip URL autolinks like <https://example.com> or <mailto:user@example.com>\n if (\n attrs.trimStart().startsWith('://') ||\n attrs.trimStart().startsWith(':')\n ) {\n continue;\n }\n\n if (isClosing) {\n if (stack.length === 0) {\n issues.push({\n type: 'error',\n message: `Closing tag </${tagName}> has no matching opening tag`,\n });\n } else {\n const last = stack[stack.length - 1];\n if (last.tag.toLowerCase() !== tagName.toLowerCase()) {\n issues.push({\n type: 'error',\n message: `Mismatched closing tag: expected </${last.tag}> but found </${tagName}>`,\n });\n }\n stack.pop();\n }\n } else {\n const isVoidElement = VOID_HTML_ELEMENTS.has(tagName.toLowerCase());\n if (!isSelfClosing && !isVoidElement) {\n stack.push({ tag: tagName });\n }\n }\n }\n\n for (const unclosed of stack) {\n issues.push({\n type: 'error',\n message: `Unclosed HTML tag: <${unclosed.tag}>`,\n });\n }\n\n return {\n valid: issues.filter((i) => i.type === 'error').length === 0,\n issues,\n };\n};\n"],"mappings":";AAAA,MAAa,qCAAqB,IAAI,IAAI;CACxC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAgBD,MAAM,YACJ;;;;;;;;AASF,MAAa,gBAAgB,YAA0C;CACrE,MAAM,SAAgC,CAAC;CACvC,MAAM,QAAgC,CAAC;CAEvC,KAAK,MAAM,SAAS,QAAQ,SAAS,SAAS,GAAG;EAC/C,MAAM,YAAY,CAAC,CAAC,MAAM;EAC1B,MAAM,UAAU,MAAM;EACtB,MAAM,QAAQ,MAAM;EACpB,MAAM,gBAAgB,CAAC,CAAC,MAAM;EAG9B,IACE,MAAM,UAAU,CAAC,CAAC,WAAW,KAAK,KAClC,MAAM,UAAU,CAAC,CAAC,WAAW,GAAG,GAEhC;EAGF,IAAI,WACF,IAAI,MAAM,WAAW,GACnB,OAAO,KAAK;GACV,MAAM;GACN,SAAS,iBAAiB,QAAQ;EACpC,CAAC;OACI;GACL,MAAM,OAAO,MAAM,MAAM,SAAS;GAClC,IAAI,KAAK,IAAI,YAAY,MAAM,QAAQ,YAAY,GACjD,OAAO,KAAK;IACV,MAAM;IACN,SAAS,sCAAsC,KAAK,IAAI,gBAAgB,QAAQ;GAClF,CAAC;GAEH,MAAM,IAAI;EACZ;OACK;GACL,MAAM,gBAAgB,mBAAmB,IAAI,QAAQ,YAAY,CAAC;GAClE,IAAI,CAAC,iBAAiB,CAAC,eACrB,MAAM,KAAK,EAAE,KAAK,QAAQ,CAAC;EAE/B;CACF;CAEA,KAAK,MAAM,YAAY,OACrB,OAAO,KAAK;EACV,MAAM;EACN,SAAS,uBAAuB,SAAS,IAAI;CAC/C,CAAC;CAGH,OAAO;EACL,OAAO,OAAO,QAAQ,MAAM,EAAE,SAAS,OAAO,CAAC,CAAC,WAAW;EAC3D;CACF;AACF"}
1
+ {"version":3,"file":"validateHTML.mjs","names":[],"sources":["../../../../src/transpiler/html/validateHTML.ts"],"sourcesContent":["export const VOID_HTML_ELEMENTS = new Set([\n 'area',\n 'base',\n 'br',\n 'col',\n 'embed',\n 'hr',\n 'img',\n 'input',\n 'link',\n 'meta',\n 'source',\n 'track',\n 'wbr',\n]);\n\nexport type HTMLValidationIssue = {\n type: 'error' | 'warning';\n message: string;\n};\n\nexport type HTMLValidationResult = {\n valid: boolean;\n issues: HTMLValidationIssue[];\n};\n\n// Matches HTML tags: <Tag ...>, </Tag>, or <Tag ... />\n// Attributes may span multiple lines but NOT blank lines (two consecutive newlines),\n// which prevents matching blockquote `>` markers as tag closers.\n// Groups: 1: closing slash, 2: tag name, 3: attributes, 4: self-closing slash\nconst TAG_REGEX =\n /<(\\/)?([a-zA-Z][a-zA-Z0-9.-]*)\\s*((?:[^\\n]|\\n(?!\\n))*?)(\\/?)>/g;\n\n/**\n * Validates that HTML tags in `content` are properly opened, nested, and closed.\n * Returns structured issues instead of logging to the console.\n *\n * False-positive exclusions:\n * - Tags whose attribute string starts with `://` are URL autolinks (e.g. `<https://…>`).\n */\nexport const validateHTML = (content: string): HTMLValidationResult => {\n const issues: HTMLValidationIssue[] = [];\n const stack: Array<{ tag: string }> = [];\n\n for (const match of content.matchAll(TAG_REGEX)) {\n const isClosing = !!match[1];\n const tagName = match[2];\n const attrs = match[3];\n const isSelfClosing = !!match[4];\n\n // Skip URL autolinks like <https://example.com> or <mailto:user@example.com>\n if (\n attrs.trimStart().startsWith('://') ||\n attrs.trimStart().startsWith(':')\n ) {\n continue;\n }\n\n if (isClosing) {\n if (stack.length === 0) {\n issues.push({\n type: 'error',\n message: `Closing tag </${tagName}> has no matching opening tag`,\n });\n } else {\n const last = stack[stack.length - 1];\n if (last.tag.toLowerCase() !== tagName.toLowerCase()) {\n issues.push({\n type: 'error',\n message: `Mismatched closing tag: expected </${last.tag}> but found </${tagName}>`,\n });\n }\n stack.pop();\n }\n } else {\n const isVoidElement = VOID_HTML_ELEMENTS.has(tagName.toLowerCase());\n if (!isSelfClosing && !isVoidElement) {\n stack.push({ tag: tagName });\n }\n }\n }\n\n for (const unclosed of stack) {\n issues.push({\n type: 'error',\n message: `Unclosed HTML tag: <${unclosed.tag}>`,\n });\n }\n\n return {\n valid: issues.filter((i) => i.type === 'error').length === 0,\n issues,\n };\n};\n"],"mappings":";AAAA,MAAa,qCAAqB,IAAI,IAAI;CACxC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAgBD,MAAM,YACJ;;;;;;;;AASF,MAAa,gBAAgB,YAA0C;CACrE,MAAM,SAAgC,CAAC;CACvC,MAAM,QAAgC,CAAC;CAEvC,KAAK,MAAM,SAAS,QAAQ,SAAS,SAAS,GAAG;EAC/C,MAAM,YAAY,CAAC,CAAC,MAAM;EAC1B,MAAM,UAAU,MAAM;EACtB,MAAM,QAAQ,MAAM;EACpB,MAAM,gBAAgB,CAAC,CAAC,MAAM;EAG9B,IACE,MAAM,UAAU,CAAC,CAAC,WAAW,KAAK,KAClC,MAAM,UAAU,CAAC,CAAC,WAAW,GAAG,GAEhC;EAGF,IAAI,WAAW;GACb,IAAI,MAAM,WAAW,GACnB,OAAO,KAAK;IACV,MAAM;IACN,SAAS,iBAAiB,QAAQ;GACpC,CAAC;QACI;IACL,MAAM,OAAO,MAAM,MAAM,SAAS;IAClC,IAAI,KAAK,IAAI,YAAY,MAAM,QAAQ,YAAY,GACjD,OAAO,KAAK;KACV,MAAM;KACN,SAAS,sCAAsC,KAAK,IAAI,gBAAgB,QAAQ;IAClF,CAAC;IAEH,MAAM,IAAI;GACZ;EACF,OAAO;GACL,MAAM,gBAAgB,mBAAmB,IAAI,QAAQ,YAAY,CAAC;GAClE,IAAI,CAAC,iBAAiB,CAAC,eACrB,MAAM,KAAK,EAAE,KAAK,QAAQ,CAAC;EAE/B;CACF;CAEA,KAAK,MAAM,YAAY,OACrB,OAAO,KAAK;EACV,MAAM;EACN,SAAS,uBAAuB,SAAS,IAAI;CAC/C,CAAC;CAGH,OAAO;EACL,OAAO,OAAO,QAAQ,MAAM,EAAE,SAAS,OAAO,CAAC,CAAC,WAAW;EAC3D;CACF;AACF"}
@@ -11,7 +11,8 @@ const getMarkdownMetadata = (markdown) => {
11
11
  break;
12
12
  }
13
13
  if (metadataEndIndex === -1) return {};
14
- return parseYaml(lines.slice(1, metadataEndIndex).join("\n")) ?? {};
14
+ const metadataContent = lines.slice(1, metadataEndIndex).join("\n");
15
+ return parseYaml(metadataContent) ?? {};
15
16
  } catch {
16
17
  return {};
17
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"getMarkdownMetadata.mjs","names":[],"sources":["../../../../src/transpiler/markdown/getMarkdownMetadata.ts"],"sourcesContent":["import { parseYaml } from '../../utils/parseYaml';\n\nexport const getMarkdownMetadata = <T extends Record<string, any>>(\n markdown: string\n): T => {\n try {\n const lines = markdown.split(/\\r?\\n/);\n\n // Check if the very first non-empty line is the metadata start delimiter.\n const firstNonEmptyLine = lines.find((line) => line.trim() !== '');\n\n if (firstNonEmptyLine?.trim() !== '---') {\n const result: T = {} as T;\n return result;\n }\n\n // Find the end of the metadata block\n let metadataEndIndex = -1;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i]?.trim() === '---') {\n metadataEndIndex = i;\n break;\n }\n }\n\n if (metadataEndIndex === -1) {\n // No closing delimiter found\n const result: T = {} as T;\n return result;\n }\n\n // Extract the metadata content between the delimiters\n const metadataLines = lines.slice(1, metadataEndIndex);\n const metadataContent = metadataLines.join('\\n');\n\n // Use the improved parseYaml function to parse the entire metadata block\n const metadata = parseYaml<T>(metadataContent);\n\n return metadata ?? ({} as T);\n } catch {\n const result: T = {} as T;\n return result;\n }\n};\n"],"mappings":";;;AAEA,MAAa,uBACX,aACM;CACN,IAAI;EACF,MAAM,QAAQ,SAAS,MAAM,OAAO;EAKpC,IAF0B,MAAM,MAAM,SAAS,KAAK,KAAK,MAAM,EAE3C,CAAC,EAAE,KAAK,MAAM,OAEhC,OAAO,CAAK;EAId,IAAI,mBAAmB;EACvB,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAChC,IAAI,MAAM,EAAE,EAAE,KAAK,MAAM,OAAO;GAC9B,mBAAmB;GACnB;EACF;EAGF,IAAI,qBAAqB,IAGvB,OAAO,CAAK;EAUd,OAFiB,UAJK,MAAM,MAAM,GAAG,gBACD,CAAC,CAAC,KAAK,IAGC,CAE9B,KAAM,CAAC;CACvB,QAAQ;EAEN,OAAO,CAAK;CACd;AACF"}
1
+ {"version":3,"file":"getMarkdownMetadata.mjs","names":[],"sources":["../../../../src/transpiler/markdown/getMarkdownMetadata.ts"],"sourcesContent":["import { parseYaml } from '../../utils/parseYaml';\n\nexport const getMarkdownMetadata = <T extends Record<string, any>>(\n markdown: string\n): T => {\n try {\n const lines = markdown.split(/\\r?\\n/);\n\n // Check if the very first non-empty line is the metadata start delimiter.\n const firstNonEmptyLine = lines.find((line) => line.trim() !== '');\n\n if (firstNonEmptyLine?.trim() !== '---') {\n const result: T = {} as T;\n return result;\n }\n\n // Find the end of the metadata block\n let metadataEndIndex = -1;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i]?.trim() === '---') {\n metadataEndIndex = i;\n break;\n }\n }\n\n if (metadataEndIndex === -1) {\n // No closing delimiter found\n const result: T = {} as T;\n return result;\n }\n\n // Extract the metadata content between the delimiters\n const metadataLines = lines.slice(1, metadataEndIndex);\n const metadataContent = metadataLines.join('\\n');\n\n // Use the improved parseYaml function to parse the entire metadata block\n const metadata = parseYaml<T>(metadataContent);\n\n return metadata ?? ({} as T);\n } catch {\n const result: T = {} as T;\n return result;\n }\n};\n"],"mappings":";;;AAEA,MAAa,uBACX,aACM;CACN,IAAI;EACF,MAAM,QAAQ,SAAS,MAAM,OAAO;EAKpC,IAF0B,MAAM,MAAM,SAAS,KAAK,KAAK,MAAM,EAE3C,CAAC,EAAE,KAAK,MAAM,OAEhC,OAAO,CAAK;EAId,IAAI,mBAAmB;EACvB,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAChC,IAAI,MAAM,EAAE,EAAE,KAAK,MAAM,OAAO;GAC9B,mBAAmB;GACnB;EACF;EAGF,IAAI,qBAAqB,IAGvB,OAAO,CAAK;EAKd,MAAM,kBADgB,MAAM,MAAM,GAAG,gBACD,CAAC,CAAC,KAAK,IAAI;EAK/C,OAFiB,UAAa,eAEhB,KAAM,CAAC;CACvB,QAAQ;EAEN,OAAO,CAAK;CACd;AACF"}
@@ -24,7 +24,8 @@ const awaitContent = async (content) => {
24
24
  */
25
25
  const markdown = (content, components) => {
26
26
  const metadata = async () => {
27
- const flatContent = getContent(await awaitContent(content), {
27
+ const awaitedContent = await awaitContent(content);
28
+ const flatContent = getContent(awaitedContent, {
28
29
  dictionaryKey: "",
29
30
  keyPath: []
30
31
  });
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.mjs","names":[],"sources":["../../../../src/transpiler/markdown/markdown.ts"],"sourcesContent":["import type { TypedNodeModel } from '@intlayer/types/nodeType';\nimport { formatNodeType, MARKDOWN } from '@intlayer/types/nodeType';\nimport { getContent } from '../../interpreter/getContent/getContent';\nimport { getHTMLCustomComponents } from '../html/getHTMLCustomComponents';\nimport { getMarkdownMetadata } from './getMarkdownMetadata';\nimport { validateMarkdown } from './validateMarkdown';\n\ntype PropsType = 'number' | 'string' | 'node';\n\ntype ComponentName = string;\n\nexport type MarkdownContentConstructor<\n T extends Record<string, any> = {},\n Content = unknown,\n> = TypedNodeModel<typeof MARKDOWN, Content, T>;\n\nexport type MarkdownContent<\n Content = unknown,\n Components extends Record<ComponentName, PropsType> = Record<\n ComponentName,\n PropsType\n >,\n> = MarkdownContentConstructor<\n {\n metadata?: Record<string, any>;\n tags?: string[] | Components;\n },\n Content\n>;\n\nconst awaitContent = async (content: any) => {\n if (typeof content === 'string' || typeof content === 'object') {\n return content as any;\n }\n\n if (typeof content === 'function') {\n return content();\n }\n if (typeof content.then === 'function') {\n return await content;\n }\n};\n\n/**\n * Function intended to be used to build intlayer dictionaries.\n *\n * Allow to pick a content based on a quantity.\n *\n * Usage:\n *\n * ```ts\n * markdown('## Hello world!');\n * ```\n *\n */\nconst markdown = <\n Components extends Record<string, any> = Record<string, any>,\n Content = unknown,\n>(\n content: Content,\n components?: Components\n): MarkdownContent<Content, Components> => {\n const metadata = async () => {\n const awaitedContent = await awaitContent(content);\n\n const flatContent = getContent(awaitedContent, {\n dictionaryKey: '',\n keyPath: [],\n });\n\n if (typeof flatContent === 'string') {\n if (process.env.NODE_ENV !== 'production') {\n const { issues } = validateMarkdown(flatContent);\n for (const issue of issues) {\n if (issue.type === 'error') {\n console.error(`[intlayer/markdown] ${issue.message}`);\n } else {\n console.warn(`[intlayer/markdown] ${issue.message}`);\n }\n }\n }\n\n return getMarkdownMetadata(flatContent);\n }\n };\n\n const getComponents = () => {\n if (components) {\n return components;\n }\n\n if (typeof content === 'string') {\n return getHTMLCustomComponents(content);\n }\n\n let stringContent: any;\n\n if (typeof content === 'function') {\n stringContent = content();\n } else if (typeof (content as Promise<string>).then === 'function') {\n stringContent = async () =>\n getHTMLCustomComponents((await (content as Promise<string>)) as string);\n }\n\n if (typeof stringContent === 'string') {\n return getHTMLCustomComponents(stringContent);\n }\n\n try {\n return getHTMLCustomComponents(JSON.stringify(content));\n } catch (_e) {\n return [];\n }\n };\n\n return formatNodeType(MARKDOWN, content, {\n metadata,\n tags: getComponents(),\n });\n};\n\nexport { markdown as md };\n"],"mappings":";;;;;;;AA8BA,MAAM,eAAe,OAAO,YAAiB;CAC3C,IAAI,OAAO,YAAY,YAAY,OAAO,YAAY,UACpD,OAAO;CAGT,IAAI,OAAO,YAAY,YACrB,OAAO,QAAQ;CAEjB,IAAI,OAAO,QAAQ,SAAS,YAC1B,OAAO,MAAM;AAEjB;;;;;;;;;;;;;AAcA,MAAM,YAIJ,SACA,eACyC;CACzC,MAAM,WAAW,YAAY;EAG3B,MAAM,cAAc,WAAW,MAFF,aAAa,OAAO,GAEF;GAC7C,eAAe;GACf,SAAS,CAAC;EACZ,CAAC;EAED,IAAI,OAAO,gBAAgB,UAAU;GACQ;IACzC,MAAM,EAAE,WAAW,iBAAiB,WAAW;IAC/C,KAAK,MAAM,SAAS,QAClB,IAAI,MAAM,SAAS,SACjB,QAAQ,MAAM,uBAAuB,MAAM,SAAS;SAEpD,QAAQ,KAAK,uBAAuB,MAAM,SAAS;GAGzD;GAEA,OAAO,oBAAoB,WAAW;EACxC;CACF;CAEA,MAAM,sBAAsB;EAC1B,IAAI,YACF,OAAO;EAGT,IAAI,OAAO,YAAY,UACrB,OAAO,wBAAwB,OAAO;EAGxC,IAAI;EAEJ,IAAI,OAAO,YAAY,YACrB,gBAAgB,QAAQ;OACnB,IAAI,OAAQ,QAA4B,SAAS,YACtD,gBAAgB,YACd,wBAAyB,MAAO,OAAsC;EAG1E,IAAI,OAAO,kBAAkB,UAC3B,OAAO,wBAAwB,aAAa;EAG9C,IAAI;GACF,OAAO,wBAAwB,KAAK,UAAU,OAAO,CAAC;EACxD,SAAS,IAAI;GACX,OAAO,CAAC;EACV;CACF;CAEA,OAAO,eAAe,UAAU,SAAS;EACvC;EACA,MAAM,cAAc;CACtB,CAAC;AACH"}
1
+ {"version":3,"file":"markdown.mjs","names":[],"sources":["../../../../src/transpiler/markdown/markdown.ts"],"sourcesContent":["import type { TypedNodeModel } from '@intlayer/types/nodeType';\nimport { formatNodeType, MARKDOWN } from '@intlayer/types/nodeType';\nimport { getContent } from '../../interpreter/getContent/getContent';\nimport { getHTMLCustomComponents } from '../html/getHTMLCustomComponents';\nimport { getMarkdownMetadata } from './getMarkdownMetadata';\nimport { validateMarkdown } from './validateMarkdown';\n\ntype PropsType = 'number' | 'string' | 'node';\n\ntype ComponentName = string;\n\nexport type MarkdownContentConstructor<\n T extends Record<string, any> = {},\n Content = unknown,\n> = TypedNodeModel<typeof MARKDOWN, Content, T>;\n\nexport type MarkdownContent<\n Content = unknown,\n Components extends Record<ComponentName, PropsType> = Record<\n ComponentName,\n PropsType\n >,\n> = MarkdownContentConstructor<\n {\n metadata?: Record<string, any>;\n tags?: string[] | Components;\n },\n Content\n>;\n\nconst awaitContent = async (content: any) => {\n if (typeof content === 'string' || typeof content === 'object') {\n return content as any;\n }\n\n if (typeof content === 'function') {\n return content();\n }\n if (typeof content.then === 'function') {\n return await content;\n }\n};\n\n/**\n * Function intended to be used to build intlayer dictionaries.\n *\n * Allow to pick a content based on a quantity.\n *\n * Usage:\n *\n * ```ts\n * markdown('## Hello world!');\n * ```\n *\n */\nconst markdown = <\n Components extends Record<string, any> = Record<string, any>,\n Content = unknown,\n>(\n content: Content,\n components?: Components\n): MarkdownContent<Content, Components> => {\n const metadata = async () => {\n const awaitedContent = await awaitContent(content);\n\n const flatContent = getContent(awaitedContent, {\n dictionaryKey: '',\n keyPath: [],\n });\n\n if (typeof flatContent === 'string') {\n if (process.env.NODE_ENV !== 'production') {\n const { issues } = validateMarkdown(flatContent);\n for (const issue of issues) {\n if (issue.type === 'error') {\n console.error(`[intlayer/markdown] ${issue.message}`);\n } else {\n console.warn(`[intlayer/markdown] ${issue.message}`);\n }\n }\n }\n\n return getMarkdownMetadata(flatContent);\n }\n };\n\n const getComponents = () => {\n if (components) {\n return components;\n }\n\n if (typeof content === 'string') {\n return getHTMLCustomComponents(content);\n }\n\n let stringContent: any;\n\n if (typeof content === 'function') {\n stringContent = content();\n } else if (typeof (content as Promise<string>).then === 'function') {\n stringContent = async () =>\n getHTMLCustomComponents((await (content as Promise<string>)) as string);\n }\n\n if (typeof stringContent === 'string') {\n return getHTMLCustomComponents(stringContent);\n }\n\n try {\n return getHTMLCustomComponents(JSON.stringify(content));\n } catch (_e) {\n return [];\n }\n };\n\n return formatNodeType(MARKDOWN, content, {\n metadata,\n tags: getComponents(),\n });\n};\n\nexport { markdown as md };\n"],"mappings":";;;;;;;AA8BA,MAAM,eAAe,OAAO,YAAiB;CAC3C,IAAI,OAAO,YAAY,YAAY,OAAO,YAAY,UACpD,OAAO;CAGT,IAAI,OAAO,YAAY,YACrB,OAAO,QAAQ;CAEjB,IAAI,OAAO,QAAQ,SAAS,YAC1B,OAAO,MAAM;AAEjB;;;;;;;;;;;;;AAcA,MAAM,YAIJ,SACA,eACyC;CACzC,MAAM,WAAW,YAAY;EAC3B,MAAM,iBAAiB,MAAM,aAAa,OAAO;EAEjD,MAAM,cAAc,WAAW,gBAAgB;GAC7C,eAAe;GACf,SAAS,CAAC;EACZ,CAAC;EAED,IAAI,OAAO,gBAAgB,UAAU;GACQ;IACzC,MAAM,EAAE,WAAW,iBAAiB,WAAW;IAC/C,KAAK,MAAM,SAAS,QAClB,IAAI,MAAM,SAAS,SACjB,QAAQ,MAAM,uBAAuB,MAAM,SAAS;SAEpD,QAAQ,KAAK,uBAAuB,MAAM,SAAS;GAGzD;GAEA,OAAO,oBAAoB,WAAW;EACxC;CACF;CAEA,MAAM,sBAAsB;EAC1B,IAAI,YACF,OAAO;EAGT,IAAI,OAAO,YAAY,UACrB,OAAO,wBAAwB,OAAO;EAGxC,IAAI;EAEJ,IAAI,OAAO,YAAY,YACrB,gBAAgB,QAAQ;OACnB,IAAI,OAAQ,QAA4B,SAAS,YACtD,gBAAgB,YACd,wBAAyB,MAAO,OAAsC;EAG1E,IAAI,OAAO,kBAAkB,UAC3B,OAAO,wBAAwB,aAAa;EAG9C,IAAI;GACF,OAAO,wBAAwB,KAAK,UAAU,OAAO,CAAC;EACxD,SAAS,IAAI;GACX,OAAO,CAAC;EACV;CACF;CAEA,OAAO,eAAe,UAAU,SAAS;EACvC;EACA,MAAM,cAAc;CACtB,CAAC;AACH"}
@@ -12,12 +12,13 @@ const stripCode = (content) => {
12
12
  let openFence = null;
13
13
  for (const line of lines) {
14
14
  const fence = line.match(/^[\s>]*(`{3,}|~{3,})/);
15
- if (!inCodeBlock) if (fence?.[1]) {
16
- inCodeBlock = true;
17
- openFence = fence[1];
18
- result.push("");
19
- } else result.push(line.replace(/(`+)(?:(?!\1).)+?\1/g, (m) => " ".repeat(m.length)));
20
- else {
15
+ if (!inCodeBlock) {
16
+ if (fence?.[1]) {
17
+ inCodeBlock = true;
18
+ openFence = fence[1];
19
+ result.push("");
20
+ } else result.push(line.replace(/(`+)(?:(?!\1).)+?\1/g, (m) => " ".repeat(m.length)));
21
+ } else {
21
22
  if (fence?.[1]?.[0] && fence[1][0] === openFence[0] && fence[1].length >= openFence.length) {
22
23
  inCodeBlock = false;
23
24
  openFence = null;
@@ -1 +1 @@
1
- {"version":3,"file":"validateMarkdown.mjs","names":[],"sources":["../../../../src/transpiler/markdown/validateMarkdown.ts"],"sourcesContent":["import { type HTMLValidationIssue, validateHTML } from '../html/validateHTML';\n\nexport type { HTMLValidationIssue as MarkdownValidationIssue } from '../html/validateHTML';\n\nexport type MarkdownValidationResult = {\n valid: boolean;\n issues: HTMLValidationIssue[];\n};\n\n/**\n * Strips fenced code blocks and inline code from markdown content so that\n * HTML-like syntax inside code is not mistakenly validated.\n */\nconst stripCode = (content: string): string => {\n const lines = content.split('\\n');\n const result: string[] = [];\n let inCodeBlock = false;\n let openFence: string | null = null;\n\n for (const line of lines) {\n // Allow leading whitespace and blockquote markers before the fence characters\n const fence = line.match(/^[\\s>]*(`{3,}|~{3,})/);\n if (!inCodeBlock) {\n if (fence?.[1]) {\n inCodeBlock = true;\n openFence = fence[1];\n result.push('');\n } else {\n // Also strip inline code spans on this line. Code spans may be\n // delimited by a run of one or more backticks and end with a matching\n // run of the same length (CommonMark), allowing shorter backtick runs\n // inside (e.g. `` t`Hello ${name}` ``).\n result.push(\n line.replace(/(`+)(?:(?!\\1).)+?\\1/g, (m) => ' '.repeat(m.length))\n );\n }\n } else {\n if (\n fence?.[1]?.[0] &&\n fence[1][0] === openFence![0] &&\n fence[1].length >= openFence!.length\n ) {\n inCodeBlock = false;\n openFence = null;\n }\n result.push('');\n }\n }\n\n return result.join('\\n');\n};\n\nconst validateCodeBlocks = (content: string): HTMLValidationIssue[] => {\n const issues: HTMLValidationIssue[] = [];\n const lines = content.split('\\n');\n let inCodeBlock = false;\n let openFence: string | null = null;\n let openLineNumber = -1;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n // Allow leading whitespace and blockquote markers before the fence characters\n const fence = line?.match(/^[\\s>]*(`{3,}|~{3,})/);\n\n if (!inCodeBlock) {\n if (fence?.[1]) {\n inCodeBlock = true;\n openFence = fence[1];\n openLineNumber = i + 1;\n }\n } else {\n if (\n fence?.[1] &&\n fence[1][0] === openFence![0] &&\n fence[1].length >= openFence!.length\n ) {\n inCodeBlock = false;\n openFence = null;\n }\n }\n }\n\n if (inCodeBlock) {\n issues.push({\n type: 'error',\n message: `Unclosed code block (opened at line ${openLineNumber})`,\n });\n }\n\n return issues;\n};\n\n/**\n * Validates markdown content for structural correctness:\n * - All fenced code blocks are properly closed\n * - HTML tags are properly nested and closed\n *\n * HTML inside code blocks is excluded from HTML validation.\n */\nexport const validateMarkdown = (content: string): MarkdownValidationResult => {\n const codeIssues = validateCodeBlocks(content);\n const htmlIssues = validateHTML(stripCode(content)).issues;\n const issues = [...codeIssues, ...htmlIssues];\n\n return {\n valid: issues.filter((i) => i.type === 'error').length === 0,\n issues,\n };\n};\n"],"mappings":";;;;;;;AAaA,MAAM,aAAa,YAA4B;CAC7C,MAAM,QAAQ,QAAQ,MAAM,IAAI;CAChC,MAAM,SAAmB,CAAC;CAC1B,IAAI,cAAc;CAClB,IAAI,YAA2B;CAE/B,KAAK,MAAM,QAAQ,OAAO;EAExB,MAAM,QAAQ,KAAK,MAAM,sBAAsB;EAC/C,IAAI,CAAC,aACH,IAAI,QAAQ,IAAI;GACd,cAAc;GACd,YAAY,MAAM;GAClB,OAAO,KAAK,EAAE;EAChB,OAKE,OAAO,KACL,KAAK,QAAQ,yBAAyB,MAAM,IAAI,OAAO,EAAE,MAAM,CAAC,CAClE;OAEG;GACL,IACE,QAAQ,EAAE,GAAG,MACb,MAAM,EAAE,CAAC,OAAO,UAAW,MAC3B,MAAM,EAAE,CAAC,UAAU,UAAW,QAC9B;IACA,cAAc;IACd,YAAY;GACd;GACA,OAAO,KAAK,EAAE;EAChB;CACF;CAEA,OAAO,OAAO,KAAK,IAAI;AACzB;AAEA,MAAM,sBAAsB,YAA2C;CACrE,MAAM,SAAgC,CAAC;CACvC,MAAM,QAAQ,QAAQ,MAAM,IAAI;CAChC,IAAI,cAAc;CAClB,IAAI,YAA2B;CAC/B,IAAI,iBAAiB;CAErB,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EAGrC,MAAM,QAFO,MAAM,EAED,EAAE,MAAM,sBAAsB;EAEhD,IAAI,CAAC,aACH;OAAI,QAAQ,IAAI;IACd,cAAc;IACd,YAAY,MAAM;IAClB,iBAAiB,IAAI;GACvB;SAEA,IACE,QAAQ,MACR,MAAM,EAAE,CAAC,OAAO,UAAW,MAC3B,MAAM,EAAE,CAAC,UAAU,UAAW,QAC9B;GACA,cAAc;GACd,YAAY;EACd;CAEJ;CAEA,IAAI,aACF,OAAO,KAAK;EACV,MAAM;EACN,SAAS,uCAAuC,eAAe;CACjE,CAAC;CAGH,OAAO;AACT;;;;;;;;AASA,MAAa,oBAAoB,YAA8C;CAC7E,MAAM,aAAa,mBAAmB,OAAO;CAC7C,MAAM,aAAa,aAAa,UAAU,OAAO,CAAC,CAAC,CAAC;CACpD,MAAM,SAAS,CAAC,GAAG,YAAY,GAAG,UAAU;CAE5C,OAAO;EACL,OAAO,OAAO,QAAQ,MAAM,EAAE,SAAS,OAAO,CAAC,CAAC,WAAW;EAC3D;CACF;AACF"}
1
+ {"version":3,"file":"validateMarkdown.mjs","names":[],"sources":["../../../../src/transpiler/markdown/validateMarkdown.ts"],"sourcesContent":["import { type HTMLValidationIssue, validateHTML } from '../html/validateHTML';\n\nexport type { HTMLValidationIssue as MarkdownValidationIssue } from '../html/validateHTML';\n\nexport type MarkdownValidationResult = {\n valid: boolean;\n issues: HTMLValidationIssue[];\n};\n\n/**\n * Strips fenced code blocks and inline code from markdown content so that\n * HTML-like syntax inside code is not mistakenly validated.\n */\nconst stripCode = (content: string): string => {\n const lines = content.split('\\n');\n const result: string[] = [];\n let inCodeBlock = false;\n let openFence: string | null = null;\n\n for (const line of lines) {\n // Allow leading whitespace and blockquote markers before the fence characters\n const fence = line.match(/^[\\s>]*(`{3,}|~{3,})/);\n if (!inCodeBlock) {\n if (fence?.[1]) {\n inCodeBlock = true;\n openFence = fence[1];\n result.push('');\n } else {\n // Also strip inline code spans on this line. Code spans may be\n // delimited by a run of one or more backticks and end with a matching\n // run of the same length (CommonMark), allowing shorter backtick runs\n // inside (e.g. `` t`Hello ${name}` ``).\n result.push(\n line.replace(/(`+)(?:(?!\\1).)+?\\1/g, (m) => ' '.repeat(m.length))\n );\n }\n } else {\n if (\n fence?.[1]?.[0] &&\n fence[1][0] === openFence![0] &&\n fence[1].length >= openFence!.length\n ) {\n inCodeBlock = false;\n openFence = null;\n }\n result.push('');\n }\n }\n\n return result.join('\\n');\n};\n\nconst validateCodeBlocks = (content: string): HTMLValidationIssue[] => {\n const issues: HTMLValidationIssue[] = [];\n const lines = content.split('\\n');\n let inCodeBlock = false;\n let openFence: string | null = null;\n let openLineNumber = -1;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n // Allow leading whitespace and blockquote markers before the fence characters\n const fence = line?.match(/^[\\s>]*(`{3,}|~{3,})/);\n\n if (!inCodeBlock) {\n if (fence?.[1]) {\n inCodeBlock = true;\n openFence = fence[1];\n openLineNumber = i + 1;\n }\n } else {\n if (\n fence?.[1] &&\n fence[1][0] === openFence![0] &&\n fence[1].length >= openFence!.length\n ) {\n inCodeBlock = false;\n openFence = null;\n }\n }\n }\n\n if (inCodeBlock) {\n issues.push({\n type: 'error',\n message: `Unclosed code block (opened at line ${openLineNumber})`,\n });\n }\n\n return issues;\n};\n\n/**\n * Validates markdown content for structural correctness:\n * - All fenced code blocks are properly closed\n * - HTML tags are properly nested and closed\n *\n * HTML inside code blocks is excluded from HTML validation.\n */\nexport const validateMarkdown = (content: string): MarkdownValidationResult => {\n const codeIssues = validateCodeBlocks(content);\n const htmlIssues = validateHTML(stripCode(content)).issues;\n const issues = [...codeIssues, ...htmlIssues];\n\n return {\n valid: issues.filter((i) => i.type === 'error').length === 0,\n issues,\n };\n};\n"],"mappings":";;;;;;;AAaA,MAAM,aAAa,YAA4B;CAC7C,MAAM,QAAQ,QAAQ,MAAM,IAAI;CAChC,MAAM,SAAmB,CAAC;CAC1B,IAAI,cAAc;CAClB,IAAI,YAA2B;CAE/B,KAAK,MAAM,QAAQ,OAAO;EAExB,MAAM,QAAQ,KAAK,MAAM,sBAAsB;EAC/C,IAAI,CAAC,aAAa;GAChB,IAAI,QAAQ,IAAI;IACd,cAAc;IACd,YAAY,MAAM;IAClB,OAAO,KAAK,EAAE;GAChB,OAKE,OAAO,KACL,KAAK,QAAQ,yBAAyB,MAAM,IAAI,OAAO,EAAE,MAAM,CAAC,CAClE;EAEJ,OAAO;GACL,IACE,QAAQ,EAAE,GAAG,MACb,MAAM,EAAE,CAAC,OAAO,UAAW,MAC3B,MAAM,EAAE,CAAC,UAAU,UAAW,QAC9B;IACA,cAAc;IACd,YAAY;GACd;GACA,OAAO,KAAK,EAAE;EAChB;CACF;CAEA,OAAO,OAAO,KAAK,IAAI;AACzB;AAEA,MAAM,sBAAsB,YAA2C;CACrE,MAAM,SAAgC,CAAC;CACvC,MAAM,QAAQ,QAAQ,MAAM,IAAI;CAChC,IAAI,cAAc;CAClB,IAAI,YAA2B;CAC/B,IAAI,iBAAiB;CAErB,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EAGrC,MAAM,QAFO,MAAM,EAED,EAAE,MAAM,sBAAsB;EAEhD,IAAI,CAAC,aACH;OAAI,QAAQ,IAAI;IACd,cAAc;IACd,YAAY,MAAM;IAClB,iBAAiB,IAAI;GACvB;SAEA,IACE,QAAQ,MACR,MAAM,EAAE,CAAC,OAAO,UAAW,MAC3B,MAAM,EAAE,CAAC,UAAU,UAAW,QAC9B;GACA,cAAc;GACd,YAAY;EACd;CAEJ;CAEA,IAAI,aACF,OAAO,KAAK;EACV,MAAM;EACN,SAAS,uCAAuC,eAAe;CACjE,CAAC;CAGH,OAAO;AACT;;;;;;;;AASA,MAAa,oBAAoB,YAA8C;CAC7E,MAAM,aAAa,mBAAmB,OAAO;CAC7C,MAAM,aAAa,aAAa,UAAU,OAAO,CAAC,CAAC,CAAC;CACpD,MAAM,SAAS,CAAC,GAAG,YAAY,GAAG,UAAU;CAE5C,OAAO;EACL,OAAO,OAAO,QAAQ,MAAM,EAAE,SAAS,OAAO,CAAC,CAAC,WAAW;EAC3D;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"parseYaml.mjs","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.mjs","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 +1 @@
1
- {"version":3,"file":"getEditedContent.d.ts","names":[],"sources":["../../../src/deepTransformPlugins/getEditedContent.ts"],"mappings":";;;;;;;;;;;;;;;;;;;cA2Ja,mBAAgB,iBACV,yBAAuB,YAC5B,aAAW,eACR,kBACd;;;;;;;;;cAYU,sBAAmB,oBACV,wBAAsB,eAC3B,YAAU,eACV,kBACd"}
1
+ {"version":3,"file":"getEditedContent.d.ts","names":[],"sources":["../../../src/deepTransformPlugins/getEditedContent.ts"],"mappings":";;;;;;;;;;;;;;;;;;;cA2Ka,mBAAgB,iBACV,yBAAuB,YAC5B,aAAW,eACR,kBACd;;;;;;;;;cAeU,sBAAmB,oBACV,wBAAsB,eAC3B,YAAU,eACV,kBACd"}
@@ -26,6 +26,7 @@ declare const getFilterMissingTranslationsDictionary: (dictionary: Dictionary, l
26
26
  projectIds?: string[];
27
27
  localId?: import("@intlayer/types").LocalDictionaryId;
28
28
  localIds?: import("@intlayer/types").LocalDictionaryId[];
29
+ nestedDictionaries?: Record<import("@intlayer/types").DictionaryKey, unknown>;
29
30
  format?: import("@intlayer/types").DictionaryFormat;
30
31
  key: import("@intlayer/types").DictionaryKey;
31
32
  title?: string;
@@ -18,6 +18,7 @@ declare const getFilterTranslationsOnlyDictionary: (dictionary: Dictionary, loca
18
18
  projectIds?: string[];
19
19
  localId?: import("@intlayer/types").LocalDictionaryId;
20
20
  localIds?: import("@intlayer/types").LocalDictionaryId[];
21
+ nestedDictionaries?: Record<import("@intlayer/types").DictionaryKey, unknown>;
21
22
  format?: import("@intlayer/types").DictionaryFormat;
22
23
  key: import("@intlayer/types").DictionaryKey;
23
24
  title?: string;
@@ -10,6 +10,7 @@ declare const getFilteredLocalesDictionary: (dictionary: Dictionary, locale: Loc
10
10
  projectIds?: string[];
11
11
  localId?: import("@intlayer/types").LocalDictionaryId;
12
12
  localIds?: import("@intlayer/types").LocalDictionaryId[];
13
+ nestedDictionaries?: Record<import("@intlayer/types").DictionaryKey, unknown>;
13
14
  format?: import("@intlayer/types").DictionaryFormat;
14
15
  key: import("@intlayer/types").DictionaryKey;
15
16
  title?: string;
@@ -0,0 +1,62 @@
1
+ //#region src/dictionaryManipulator/getNestedDictionaryReferences.d.ts
2
+ /**
3
+ * Top-level content fields of a nest target that are referenced through
4
+ * `nest()` nodes.
5
+ *
6
+ * `'all'` means at least one reference targets the whole dictionary
7
+ * (`nest('common')` without a path), so no field of that dictionary may be
8
+ * dropped.
9
+ */
10
+ type NestedFieldReferences = Set<string> | 'all';
11
+ /**
12
+ * Walks a dictionary tree and collects every dictionary referenced through a
13
+ * `nest()` node, together with the top-level fields those references read.
14
+ *
15
+ * The walk is iterative (no recursion depth limit) and guards against shared
16
+ * or circular references, so it is safe on both compiled JSON and in-memory
17
+ * dictionaries.
18
+ *
19
+ * @param dictionaries - Dictionary objects (or any content subtree) to scan.
20
+ * @returns Map of nest-target dictionary key → referenced top-level fields.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * // dashboard.content.ts → { period: nest('common', 'period') }
25
+ * getNestedDictionaryReferences([dashboardDictionary]);
26
+ * // Map { 'common' => Set { 'period' } }
27
+ * ```
28
+ */
29
+ declare const getNestedDictionaryReferences: (dictionaries: Iterable<unknown>) => Map<string, NestedFieldReferences>;
30
+ /**
31
+ * Keys of every dictionary referenced through a `nest()` node.
32
+ *
33
+ * @param dictionaries - Dictionary objects (or any content subtree) to scan.
34
+ * @returns Set of nest-target dictionary keys.
35
+ */
36
+ declare const getNestedDictionaryKeys: (dictionaries: Iterable<unknown>) => Set<string>;
37
+ /**
38
+ * Builds the `nest()` dependency graph of a set of dictionaries: for each
39
+ * dictionary key, the keys of every dictionary it needs in order to resolve its
40
+ * nested nodes, transitively.
41
+ *
42
+ * The build optimization uses this to attach the nest targets to the dictionary
43
+ * artifact itself, so `nest()` resolves from a local reference and the target
44
+ * lands in the same chunk (or the same lazy per-locale loader) as the
45
+ * dictionary referencing it.
46
+ *
47
+ * Dictionaries without nested nodes are absent from the result.
48
+ *
49
+ * @param dictionaries - Compiled dictionaries to scan; each must carry its `key`.
50
+ * @returns Map of dictionary key → keys it depends on through `nest()`.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * // dashboard nests common, common nests labels
55
+ * getNestedDictionaryGraph([dashboard, common]);
56
+ * // Map { 'dashboard' => Set { 'common', 'labels' }, 'common' => Set { 'labels' } }
57
+ * ```
58
+ */
59
+ declare const getNestedDictionaryGraph: (dictionaries: Iterable<unknown>) => Map<string, Set<string>>;
60
+ //#endregion
61
+ export { NestedFieldReferences, getNestedDictionaryGraph, getNestedDictionaryKeys, getNestedDictionaryReferences };
62
+ //# sourceMappingURL=getNestedDictionaryReferences.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getNestedDictionaryReferences.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/getNestedDictionaryReferences.ts"],"mappings":";;;;;;;;;KAUY,wBAAwB;;;;;;;;;;;;;;;;;;;cAkEvB,gCAA6B,cAC1B,sBACb,YAAY;;;;;;;cAkDF,0BAAuB,cACpB,sBACb;;;;;;;;;;;;;;;;;;;;;;;cAyDU,2BAAwB,cACrB,sBACb,YAAY"}
@@ -2,14 +2,17 @@ import { editDictionaryByKeyPath } from "./editDictionaryByKeyPath.js";
2
2
  import { getContentNodeByKeyPath } from "./getContentNodeByKeyPath.js";
3
3
  import { getDefaultNode } from "./getDefaultNode.js";
4
4
  import { getEmptyNode } from "./getEmptyNode.js";
5
+ import { NestedFieldReferences, getNestedDictionaryGraph, getNestedDictionaryKeys, getNestedDictionaryReferences } from "./getNestedDictionaryReferences.js";
5
6
  import { getNodeChildren } from "./getNodeChildren.js";
6
7
  import { getNodeType } from "./getNodeType.js";
7
8
  import { mergeDictionaries } from "./mergeDictionaries.js";
8
9
  import { mergeQualifiedDictionaries } from "./mergeQualifiedDictionaries.js";
9
10
  import { normalizeDictionaries, normalizeDictionary } from "./normalizeDictionary.js";
10
11
  import { orderDictionaries } from "./orderDictionaries.js";
11
- import { COMPOSITE_ID_SEPARATOR, DEFAULT_VARIANT_ID, DynamicDictionaryLoader, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getVariantIds, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, parseDictionarySelector, reconstructQualifiedEntry, resolveDictionaryArgument, resolveProviderVariant, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, serializeVariant, serializeVariantChain } from "./qualifiedDictionary.js";
12
+ import { COMPOSITE_ID_SEPARATOR, DEFAULT_VARIANT_ID, getDictionarySelectorCacheKey, isQualifiedDictionaryGroup, parseDictionarySelector, reconstructQualifiedEntry, resolveDictionaryArgument, resolveEffectiveVariantId, resolveProviderVariant, resolveQualifiedDictionary, serializeVariant, serializeVariantChain } from "./qualifiedDictionary.js";
13
+ import { QUALIFIER_ORDER, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getVariantIds } from "./qualifiedDictionaryDeclaration.js";
14
+ import { DynamicDictionaryLoader, QUALIFIER_DYNAMIC_TYPES_KEY, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, isQualifiedDynamicLoaderMap, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync } from "./qualifiedDynamicLoader.js";
12
15
  import { removeContentNodeByKeyPath } from "./removeContentNodeByKeyPath.js";
13
16
  import { renameContentNodeByKeyPath } from "./renameContentNodeByKeyPath.js";
14
17
  import { updateNodeChildren } from "./updateNodeChildren.js";
15
- export { COMPOSITE_ID_SEPARATOR, DEFAULT_VARIANT_ID, DynamicDictionaryLoader, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, editDictionaryByKeyPath, getContentNodeByKeyPath, getDefaultNode, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getEmptyNode, getNodeChildren, getNodeType, getVariantIds, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, mergeDictionaries, mergeQualifiedDictionaries, normalizeDictionaries, normalizeDictionary, orderDictionaries, parseDictionarySelector, reconstructQualifiedEntry, removeContentNodeByKeyPath, renameContentNodeByKeyPath, resolveDictionaryArgument, resolveProviderVariant, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, serializeVariant, serializeVariantChain, updateNodeChildren };
18
+ export { COMPOSITE_ID_SEPARATOR, DEFAULT_VARIANT_ID, DynamicDictionaryLoader, NestedFieldReferences, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, editDictionaryByKeyPath, getContentNodeByKeyPath, getDefaultNode, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getEmptyNode, getNestedDictionaryGraph, getNestedDictionaryKeys, getNestedDictionaryReferences, getNodeChildren, getNodeType, getVariantIds, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, mergeDictionaries, mergeQualifiedDictionaries, normalizeDictionaries, normalizeDictionary, orderDictionaries, parseDictionarySelector, reconstructQualifiedEntry, removeContentNodeByKeyPath, renameContentNodeByKeyPath, resolveDictionaryArgument, resolveEffectiveVariantId, resolveProviderVariant, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, serializeVariant, serializeVariantChain, updateNodeChildren };
@@ -1 +1 @@
1
- {"version":3,"file":"mergeQualifiedDictionaries.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/mergeQualifiedDictionaries.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;cAkCa,6BAA0B,cACvB,iBACb,aAAa"}
1
+ {"version":3,"file":"mergeQualifiedDictionaries.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/mergeQualifiedDictionaries.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;cAoCa,6BAA0B,cACvB,iBACb,aAAa"}
@@ -1,12 +1,6 @@
1
- import { Dictionary, DictionaryQualifierType, DictionarySelector, DictionaryVariantChain, DictionaryVariantValue, ProviderVariant, QualifiedDictionaryGroup } from "@intlayer/types/dictionary";
1
+ import { Dictionary, DictionarySelector, DictionaryVariantChain, DictionaryVariantValue, ProviderVariant, QualifiedDictionaryGroup } from "@intlayer/types/dictionary";
2
2
  import { LocalesValues } from "@intlayer/types/module_augmentation";
3
3
  //#region src/dictionaryManipulator/qualifiedDictionary.d.ts
4
- /**
5
- * Canonical order of qualifier dimensions. A key that declares both dimensions
6
- * always nests them in this order, with `item` innermost so it can act as the
7
- * collection (array) axis.
8
- */
9
- declare const QUALIFIER_ORDER: readonly ["variant", "item"];
10
4
  /**
11
5
  * Separator joining per-dimension ids into a composite entry id. Also used as
12
6
  * the chunk path separator in dynamic mode.
@@ -37,36 +31,6 @@ declare const DEFAULT_VARIANT_ID = "default";
37
31
  * an object variant in a selector must equal the one declared on the dictionary.
38
32
  */
39
33
  declare const serializeVariant: (variant: DictionaryVariantValue | undefined) => string;
40
- /**
41
- * Normalizes the `variant` field of a dictionary into the list of variant ids
42
- * the declaration registers under. A single value yields one id; an **array**
43
- * fans out into one id per element (duplicates collapsed). Returns `undefined`
44
- * when the dictionary does not declare the variant dimension (no `variant`
45
- * field, or an empty array).
46
- */
47
- declare const getVariantIds: (variant: Dictionary['variant']) => string[] | undefined;
48
- /**
49
- * Returns the qualifier dimensions declared on a dictionary, in canonical
50
- * order (`variant → item`). Empty when the dictionary is unqualified
51
- * (plain dictionary or shared base content of a qualified group).
52
- */
53
- declare const getDictionaryQualifierTypes: (dictionary: Dictionary) => DictionaryQualifierType[];
54
- /**
55
- * Returns the qualifier identifiers of a dictionary for the given qualifier
56
- * dimension — the candidate segments of the composite entry ids.
57
- *
58
- * - 'variant' → the serialized variant id(s); an array variant yields one id
59
- * per element (declaration-side fan-out)
60
- * - 'item' → the item index as a single-element list
61
- */
62
- declare const getDictionaryQualifierIds: (dictionary: Dictionary, qualifierType: DictionaryQualifierType) => string[] | undefined;
63
- /**
64
- * Builds every composite entry id of a dictionary — the cartesian product of
65
- * its per-dimension id lists, joined in canonical order. A dictionary with a
66
- * plain (non-array) variant yields exactly one id; an array variant fans out
67
- * into one id per element. `undefined` when a dimension of the set is missing.
68
- */
69
- declare const getDictionaryCompositeIds: (dictionary: Dictionary, qualifierTypes: DictionaryQualifierType[]) => string[] | undefined;
70
34
  /**
71
35
  * Serializes the variant coordinate of a selector into the ordered list of
72
36
  * candidate ids to try, so a single value and a preference chain share one code
@@ -80,6 +44,22 @@ declare const getDictionaryCompositeIds: (dictionary: Dictionary, qualifierTypes
80
44
  * as an unsatisfiable request.
81
45
  */
82
46
  declare const serializeVariantChain: (variant: DictionaryVariantChain | undefined) => string[];
47
+ /**
48
+ * Resolves the variant id a selector actually targets among the ids a key
49
+ * declares — the sparse-override fallback.
50
+ *
51
+ * Candidates are tried in order and the first one the key declares wins.
52
+ * Otherwise the key falls back to its `default` entry, so a variant only has to
53
+ * be declared where its wording differs. When the key declares no `default`
54
+ * either, the first candidate is returned unchanged and the caller resolves to
55
+ * `null` / `[]`.
56
+ *
57
+ * @param requestedVariantIds - The serialized ids the selector asks for, in
58
+ * preference order (a single value is a 1-element
59
+ * list).
60
+ * @param isVariantIdDeclared - Whether the key declares an entry for an id.
61
+ */
62
+ declare const resolveEffectiveVariantId: (requestedVariantIds: string[], isVariantIdDeclared: (variantId: string) => boolean) => string;
83
63
  /**
84
64
  * Type guard discriminating a `QualifiedDictionaryGroup` (merge output of a
85
65
  * qualified key) from a plain `Dictionary`. Both carry a `content` field; only
@@ -163,94 +143,6 @@ declare const resolveDictionaryArgument: (params: {
163
143
  * for cache keys and memoization dependencies.
164
144
  */
165
145
  declare const getDictionarySelectorCacheKey: (selector?: DictionarySelector) => string;
166
- /**
167
- * Marker property carrying the ordered qualifier dimensions on a dynamic loader
168
- * map. Its presence distinguishes a qualified group loader map (a nested tree
169
- * of chunks) from a plain dynamic loader map (one chunk per `locale`). Prefixed
170
- * and unlikely to collide with a real locale code.
171
- */
172
- declare const QUALIFIER_DYNAMIC_TYPES_KEY = "__intlayerQualifierTypes";
173
- /**
174
- * A lazily-imported per-locale dictionary chunk loader.
175
- */
176
- type DynamicDictionaryLoader = () => Promise<Dictionary>;
177
- /**
178
- * Nested tree of chunk loaders: one nesting level per declared dimension (in
179
- * canonical order), leaves are loaders.
180
- */
181
- type QualifiedDynamicLoaderTree = {
182
- [segment: string]: QualifiedDynamicLoaderTree | DynamicDictionaryLoader;
183
- };
184
- /**
185
- * Default export shape of a generated dynamic entry point for a qualified key.
186
- * One nesting level per dimension under each locale, plus the dimension marker.
187
- *
188
- * ```ts
189
- * {
190
- * __intlayerQualifierTypes: ['variant', 'item'],
191
- * en: { promo: { '1': () => import('./json/x/promo/1/en.json'), … }, … },
192
- * fr: { … },
193
- * }
194
- * ```
195
- */
196
- type QualifiedDynamicLoaderMap = {
197
- [QUALIFIER_DYNAMIC_TYPES_KEY]: DictionaryQualifierType[];
198
- [locale: string]: QualifiedDynamicLoaderTree | DictionaryQualifierType[];
199
- };
200
- /**
201
- * Type guard discriminating a qualified dynamic loader map (collections /
202
- * variants, possibly combined) from a plain dynamic loader map.
203
- */
204
- declare const isQualifiedDynamicLoaderMap: (value: unknown) => value is QualifiedDynamicLoaderMap;
205
- /**
206
- * Resolves the content of a qualified dynamic loader map against a selector,
207
- * loading only the chunk(s) the selector actually targets.
208
- *
209
- * Walks the nested loader tree one dimension at a time (canonical order
210
- * `variant → item`): `variant` descends by the serialized id, falling back to
211
- * `default` when the selected variant has no chunk of its own, and `item`
212
- * either narrows to the selected index or — when no item is given — expands
213
- * into every sibling chunk (the collection axis). Semantics mirror
214
- * {@link resolveQualifiedDictionary} so dynamic and static modes behave alike.
215
- *
216
- * The Suspense mechanism is injected through `loadChunk` so the same logic
217
- * serves both the client (suspender cache) and the server (`react.use`). Every
218
- * targeted loader is started before the first chunk is read, so sibling chunks
219
- * load in parallel rather than waterfalling.
220
- *
221
- * @param loaderMap - The qualified dynamic loader map (entry point default export).
222
- * @param key - The dictionary key (used to build stable chunk cache keys).
223
- * @param locale - The resolved locale to load chunks for.
224
- * @param selector - The selector splitting the qualifier dimensions.
225
- * @param loadChunk - Reads a started chunk promise, suspending until it resolves.
226
- * @param transform - Turns a resolved chunk dictionary into final content.
227
- */
228
- declare const resolveQualifiedDynamicContent: <Content>(params: {
229
- loaderMap: QualifiedDynamicLoaderMap;
230
- key: string;
231
- locale: string;
232
- selector: DictionarySelector | undefined;
233
- loadChunk: (cacheKey: string, promise: Promise<Dictionary>) => Dictionary;
234
- transform: (dictionary: Dictionary) => Content;
235
- }) => Content | Content[] | null;
236
- /**
237
- * Async counterpart of {@link resolveQualifiedDynamicContent} for frameworks
238
- * that load dictionaries with `await` instead of Suspense (Vue, Svelte, Lit,
239
- * vanilla). Awaits every targeted chunk in parallel, then resolves identically.
240
- *
241
- * @param loaderMap - The qualified dynamic loader map.
242
- * @param key - The dictionary key (used to build stable chunk cache keys).
243
- * @param locale - The resolved locale to load chunks for.
244
- * @param selector - The selector splitting the qualifier dimensions.
245
- * @param transform - Turns a resolved chunk dictionary into final content.
246
- */
247
- declare const resolveQualifiedDynamicContentAsync: <Content>(params: {
248
- loaderMap: QualifiedDynamicLoaderMap;
249
- key: string;
250
- locale: string;
251
- selector: DictionarySelector | undefined;
252
- transform: (dictionary: Dictionary) => Content;
253
- }) => Promise<Content | Content[] | null>;
254
146
  //#endregion
255
- export { COMPOSITE_ID_SEPARATOR, DEFAULT_VARIANT_ID, DynamicDictionaryLoader, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getVariantIds, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, parseDictionarySelector, reconstructQualifiedEntry, resolveDictionaryArgument, resolveProviderVariant, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, serializeVariant, serializeVariantChain };
147
+ export { COMPOSITE_ID_SEPARATOR, DEFAULT_VARIANT_ID, getDictionarySelectorCacheKey, isQualifiedDictionaryGroup, parseDictionarySelector, reconstructQualifiedEntry, resolveDictionaryArgument, resolveEffectiveVariantId, resolveProviderVariant, resolveQualifiedDictionary, serializeVariant, serializeVariantChain };
256
148
  //# sourceMappingURL=qualifiedDictionary.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"qualifiedDictionary.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/qualifiedDictionary.ts"],"mappings":";;;;;;;;cAiBa;;;;;cASA;;;;;;cAOA;;;;;;;;;;;;;;;;;;;cAqDA,mBAAgB,SAClB;;;;;;;;cAuBE,gBAAa,SACf;;;;;;cAeE,8BAA2B,YAC1B,eACX;;;;;;;;;cAmBU,4BAAyB,YACxB,YAAU,eACP;;;;;;;cAcJ,4BAAyB,YACxB,YAAU,gBACN;;;;;;;;;;;;;cA8BL,wBAAqB,SACvB;;;;;;cAwEE,6BAA0B,mBAEpC,SAAS;;;;;;;;;;;;cAkBC,4BAAyB,OAC7B,0BAAwB,wBAE9B;;;;;;;;;;;;;;;;cAkCU,6BAA0B,mBAClB,aAAa,0BAAwB,WAC7C,uBACV,aAAa;;;;;cAoDH,0BAA2B,UAAU,eAAa,mBAC1C,IAAI;EACpB,SAAS;EAAG,WAAW;;;;;;;;;;;;;;;;;cA0Bf,yBAAsB,iBAChB,6BAA2B,0BAE3C;;;;;;;;;;;;;;;cA0BU,4BAAyB;EACpC,mBAAmB,gBAAgB;EACnC,gBAAgB;EAChB,iBAAiB;EACjB;MACE,gBAAgB;;;;;cAqCP,gCAA6B,WAC7B;;;;;;;cA0BA;;;;KAKD,gCAAgC,QAAQ;;;;;KAMxC;GACT,kBAAkB,6BAA6B;;;;;;;;;;;;;;KAetC;GACT,8BAA8B;GAC9B,iBAAiB,6BAA6B;;;;;;cAOpC,8BAA2B,mBAErC,SAAS;;;;;;;;;;;;;;;;;;;;;;;;cAkHC,iCAAkC,SAAO;EACpD,WAAW;EACX;EACA;EACA,UAAU;EACV,YAAY,kBAAkB,SAAS,QAAQ,gBAAgB;EAC/D,YAAY,YAAY,eAAe;MACrC,UAAU;;;;;;;;;;;;cAkCD,sCAA6C,SAAO;EAC/D,WAAW;EACX;EACA;EACA,UAAU;EACV,YAAY,YAAY,eAAe;MACrC,QAAQ,UAAU"}
1
+ {"version":3,"file":"qualifiedDictionary.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/qualifiedDictionary.ts"],"mappings":";;;;;;;cAgBa;;;;;;cAOA;;;;;;;;;;;;;;;;;;;cAqDA,mBAAgB,SAClB;;;;;;;;;;;;;cA4BE,wBAAqB,SACvB;;;;;;;;;;;;;;;;cA0BE,4BAAyB,+BACP,sBACP;;;;;;cA4CX,6BAA0B,mBAEpC,SAAS;;;;;;;;;;;;cAkBC,4BAAyB,OAC7B,0BAAwB,wBAE9B;;;;;;;;;;;;;;;;cAkCU,6BAA0B,mBAClB,aAAa,0BAAwB,WAC7C,uBACV,aAAa;;;;;cAoDH,0BAA2B,UAAU,eAAa,mBAC1C,IAAI;EACpB,SAAS;EAAG,WAAW;;;;;;;;;;;;;;;;;cA0Bf,yBAAsB,iBAChB,6BAA2B,0BAE3C;;;;;;;;;;;;;;;cA0BU,4BAAyB;EACpC,mBAAmB,gBAAgB;EACnC,gBAAgB;EAChB,iBAAiB;EACjB;MACE,gBAAgB;;;;;cAqCP,gCAA6B,WAC7B"}