@intlayer/core 8.0.0-canary.3 → 8.0.0-canary.5

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 (76) hide show
  1. package/README.md +0 -2
  2. package/dist/cjs/index.cjs +77 -3
  3. package/dist/cjs/interpreter/getContent/plugins.cjs.map +1 -1
  4. package/dist/cjs/localization/getLocalizedUrl.cjs +3 -2
  5. package/dist/cjs/localization/getLocalizedUrl.cjs.map +1 -1
  6. package/dist/cjs/localization/index.cjs +3 -0
  7. package/dist/cjs/localization/rewriteUtils.cjs +62 -23
  8. package/dist/cjs/localization/rewriteUtils.cjs.map +1 -1
  9. package/dist/cjs/markdown/compiler.cjs +17 -21
  10. package/dist/cjs/markdown/compiler.cjs.map +1 -1
  11. package/dist/cjs/markdown/index.cjs +70 -0
  12. package/dist/cjs/transpiler/html/getHTMLCustomComponents.cjs +2 -2
  13. package/dist/cjs/transpiler/html/getHTMLCustomComponents.cjs.map +1 -1
  14. package/dist/cjs/transpiler/html/html.cjs +37 -0
  15. package/dist/cjs/transpiler/html/html.cjs.map +1 -0
  16. package/dist/cjs/transpiler/html/htmlTags.cjs +116 -0
  17. package/dist/cjs/transpiler/html/htmlTags.cjs.map +1 -0
  18. package/dist/cjs/transpiler/html/index.cjs +4 -147
  19. package/dist/cjs/transpiler/index.cjs +4 -3
  20. package/dist/cjs/transpiler/markdown/markdown.cjs +19 -2
  21. package/dist/cjs/transpiler/markdown/markdown.cjs.map +1 -1
  22. package/dist/esm/index.mjs +6 -5
  23. package/dist/esm/interpreter/getContent/plugins.mjs.map +1 -1
  24. package/dist/esm/localization/getLocalizedUrl.mjs +4 -3
  25. package/dist/esm/localization/getLocalizedUrl.mjs.map +1 -1
  26. package/dist/esm/localization/index.mjs +2 -2
  27. package/dist/esm/localization/rewriteUtils.mjs +60 -23
  28. package/dist/esm/localization/rewriteUtils.mjs.map +1 -1
  29. package/dist/esm/markdown/compiler.mjs +17 -21
  30. package/dist/esm/markdown/compiler.mjs.map +1 -1
  31. package/dist/esm/markdown/index.mjs +3 -3
  32. package/dist/esm/transpiler/html/getHTMLCustomComponents.mjs +1 -1
  33. package/dist/esm/transpiler/html/html.mjs +36 -0
  34. package/dist/esm/transpiler/html/html.mjs.map +1 -0
  35. package/dist/esm/transpiler/html/htmlTags.mjs +115 -0
  36. package/dist/esm/transpiler/html/htmlTags.mjs.map +1 -0
  37. package/dist/esm/transpiler/html/index.mjs +3 -145
  38. package/dist/esm/transpiler/index.mjs +2 -1
  39. package/dist/esm/transpiler/markdown/markdown.mjs +19 -2
  40. package/dist/esm/transpiler/markdown/markdown.mjs.map +1 -1
  41. package/dist/types/deepTransformPlugins/getFilterMissingTranslationsContent.d.ts +10 -10
  42. package/dist/types/deepTransformPlugins/getFilterMissingTranslationsContent.d.ts.map +1 -1
  43. package/dist/types/deepTransformPlugins/getFilterTranslationsOnlyContent.d.ts +10 -10
  44. package/dist/types/deepTransformPlugins/getFilterTranslationsOnlyContent.d.ts.map +1 -1
  45. package/dist/types/dictionaryManipulator/orderDictionaries.d.ts +2 -2
  46. package/dist/types/dictionaryManipulator/orderDictionaries.d.ts.map +1 -1
  47. package/dist/types/index.d.ts +8 -8
  48. package/dist/types/interpreter/getContent/index.d.ts +2 -2
  49. package/dist/types/interpreter/getContent/plugins.d.ts +3 -52
  50. package/dist/types/interpreter/getContent/plugins.d.ts.map +1 -1
  51. package/dist/types/interpreter/index.d.ts +2 -2
  52. package/dist/types/localization/getLocalizedUrl.d.ts.map +1 -1
  53. package/dist/types/localization/index.d.ts +2 -2
  54. package/dist/types/localization/rewriteUtils.d.ts +21 -4
  55. package/dist/types/localization/rewriteUtils.d.ts.map +1 -1
  56. package/dist/types/markdown/compiler.d.ts +3 -3
  57. package/dist/types/markdown/compiler.d.ts.map +1 -1
  58. package/dist/types/markdown/index.d.ts +4 -4
  59. package/dist/types/markdown/types.d.ts +18 -38
  60. package/dist/types/markdown/types.d.ts.map +1 -1
  61. package/dist/types/transpiler/html/html.d.ts +25 -0
  62. package/dist/types/transpiler/html/html.d.ts.map +1 -0
  63. package/dist/types/transpiler/html/htmlTags.d.ts +115 -0
  64. package/dist/types/transpiler/html/htmlTags.d.ts.map +1 -0
  65. package/dist/types/transpiler/html/index.d.ts +3 -138
  66. package/dist/types/transpiler/index.d.ts +4 -3
  67. package/dist/types/transpiler/markdown/markdown.d.ts +6 -3
  68. package/dist/types/transpiler/markdown/markdown.d.ts.map +1 -1
  69. package/package.json +6 -6
  70. package/dist/cjs/transpiler/html/index.cjs.map +0 -1
  71. package/dist/cjs/transpiler/html/types.cjs +0 -0
  72. package/dist/esm/transpiler/html/index.mjs.map +0 -1
  73. package/dist/esm/transpiler/html/types.mjs +0 -0
  74. package/dist/types/transpiler/html/index.d.ts.map +0 -1
  75. package/dist/types/transpiler/html/types.d.ts +0 -37
  76. package/dist/types/transpiler/html/types.d.ts.map +0 -1
package/README.md CHANGED
@@ -27,8 +27,6 @@
27
27
  <a href="https://github.com/aymericzip/intlayer/blob/main/LICENSE" target="_blank" rel="noopener noreferrer nofollow"><img src="https://img.shields.io/github/license/aymericzip/intlayer?style=for-the-badge&labelColor=000000&color=FFFFFF&logoColor=000000&cacheSeconds=86400" alt="license"/></a>
28
28
  <a href="https://github.com/aymericzip/intlayer/commits/main" target="_blank" rel="noopener noreferrer nofollow"><img src="https://img.shields.io/github/last-commit/aymericzip/intlayer?style=for-the-badge&labelColor=000000&color=FFFFFF&logoColor=000000&cacheSeconds=86400" alt="last commit"/>
29
29
  </a>
30
- <a href="https://www.bountyhub.dev/en/bounty/view/a2f24259-80ae-4a19-82e7-288718fba449/adapt-markdown-parser-in-a-custom-packages" target="_blank" rel="noopener noreferrer nofollow"><img src="https://img.shields.io/badge/Bounties-on%20BountyHub-yellow?style=for-the-badge&labelColor=000000&color=FFFFFF&logoColor=000000&cacheSeconds=86400" alt="Bounties on BountyHub"/>
31
- </a>
32
30
  </p>
33
31
 
34
32
  ![Watch the video](https://github.com/aymericzip/intlayer/blob/main/docs/assets/demo_video.gif)
@@ -14,7 +14,8 @@ const require_deepTransformPlugins_getFilteredLocalesContent = require('./deepTr
14
14
  const require_transpiler_condition_condition = require('./transpiler/condition/condition.cjs');
15
15
  const require_transpiler_enumeration_enumeration = require('./transpiler/enumeration/enumeration.cjs');
16
16
  const require_transpiler_gender_gender = require('./transpiler/gender/gender.cjs');
17
- const require_transpiler_html_index = require('./transpiler/html/index.cjs');
17
+ const require_transpiler_html_html = require('./transpiler/html/html.cjs');
18
+ const require_transpiler_html_htmlTags = require('./transpiler/html/htmlTags.cjs');
18
19
  const require_transpiler_insertion_getInsertionValues = require('./transpiler/insertion/getInsertionValues.cjs');
19
20
  const require_transpiler_insertion_insertion = require('./transpiler/insertion/insertion.cjs');
20
21
  const require_utils_parseYaml = require('./utils/parseYaml.cjs');
@@ -80,17 +81,81 @@ const require_utils_isSameKeyPath = require('./utils/isSameKeyPath.cjs');
80
81
 
81
82
  exports.ATTRIBUTES_TO_SANITIZE = require_markdown_constants.ATTRIBUTES_TO_SANITIZE;
82
83
  exports.ATTRIBUTE_TO_NODE_PROP_MAP = require_markdown_constants.ATTRIBUTE_TO_NODE_PROP_MAP;
84
+ exports.ATTR_EXTRACTOR_R = require_markdown_constants.ATTR_EXTRACTOR_R;
85
+ exports.BLOCKQUOTE_ALERT_R = require_markdown_constants.BLOCKQUOTE_ALERT_R;
86
+ exports.BLOCKQUOTE_R = require_markdown_constants.BLOCKQUOTE_R;
87
+ exports.BLOCKQUOTE_TRIM_LEFT_MULTILINE_R = require_markdown_constants.BLOCKQUOTE_TRIM_LEFT_MULTILINE_R;
88
+ exports.BLOCK_END_R = require_markdown_constants.BLOCK_END_R;
89
+ exports.BREAK_LINE_R = require_markdown_constants.BREAK_LINE_R;
90
+ exports.BREAK_THEMATIC_R = require_markdown_constants.BREAK_THEMATIC_R;
91
+ exports.CAPTURE_LETTER_AFTER_HYPHEN = require_markdown_constants.CAPTURE_LETTER_AFTER_HYPHEN;
92
+ exports.CODE_BLOCK_FENCED_R = require_markdown_constants.CODE_BLOCK_FENCED_R;
93
+ exports.CODE_BLOCK_R = require_markdown_constants.CODE_BLOCK_R;
94
+ exports.CODE_INLINE_R = require_markdown_constants.CODE_INLINE_R;
95
+ exports.CONSECUTIVE_NEWLINE_R = require_markdown_constants.CONSECUTIVE_NEWLINE_R;
96
+ exports.CR_NEWLINE_R = require_markdown_constants.CR_NEWLINE_R;
97
+ exports.CUSTOM_COMPONENT_R = require_markdown_constants.CUSTOM_COMPONENT_R;
83
98
  exports.CachedIntl = require_utils_intl.CachedIntl;
84
99
  exports.Intl = require_utils_intl.CachedIntl;
85
100
  exports.DO_NOT_PROCESS_HTML_ELEMENTS = require_markdown_constants.DO_NOT_PROCESS_HTML_ELEMENTS;
86
101
  exports.DURATION_DELAY_TRIGGER = require_markdown_constants.DURATION_DELAY_TRIGGER;
87
- exports.HTML_TAGS = require_transpiler_html_index.HTML_TAGS;
102
+ exports.FOOTNOTE_R = require_markdown_constants.FOOTNOTE_R;
103
+ exports.FOOTNOTE_REFERENCE_R = require_markdown_constants.FOOTNOTE_REFERENCE_R;
104
+ exports.FORMFEED_R = require_markdown_constants.FORMFEED_R;
105
+ exports.FRONT_MATTER_R = require_markdown_constants.FRONT_MATTER_R;
106
+ exports.GFM_TASK_R = require_markdown_constants.GFM_TASK_R;
107
+ exports.HEADING_ATX_COMPLIANT_R = require_markdown_constants.HEADING_ATX_COMPLIANT_R;
108
+ exports.HEADING_R = require_markdown_constants.HEADING_R;
109
+ exports.HEADING_SETEXT_R = require_markdown_constants.HEADING_SETEXT_R;
110
+ exports.HTML_BLOCK_ELEMENT_R = require_markdown_constants.HTML_BLOCK_ELEMENT_R;
111
+ exports.HTML_CHAR_CODE_R = require_markdown_constants.HTML_CHAR_CODE_R;
112
+ exports.HTML_COMMENT_R = require_markdown_constants.HTML_COMMENT_R;
113
+ exports.HTML_CUSTOM_ATTR_R = require_markdown_constants.HTML_CUSTOM_ATTR_R;
114
+ exports.HTML_LEFT_TRIM_AMOUNT_R = require_markdown_constants.HTML_LEFT_TRIM_AMOUNT_R;
115
+ exports.HTML_SELF_CLOSING_ELEMENT_R = require_markdown_constants.HTML_SELF_CLOSING_ELEMENT_R;
116
+ exports.HTML_TAGS = require_transpiler_html_htmlTags.HTML_TAGS;
117
+ exports.INLINE_SKIP_R = require_markdown_constants.INLINE_SKIP_R;
118
+ exports.INTERPOLATION_R = require_markdown_constants.INTERPOLATION_R;
119
+ exports.LINK_AUTOLINK_BARE_URL_R = require_markdown_constants.LINK_AUTOLINK_BARE_URL_R;
120
+ exports.LINK_AUTOLINK_R = require_markdown_constants.LINK_AUTOLINK_R;
121
+ exports.LIST_LOOKBEHIND_R = require_markdown_constants.LIST_LOOKBEHIND_R;
122
+ exports.LOOKAHEAD = require_markdown_constants.LOOKAHEAD;
88
123
  exports.LocaleStorage = require_utils_localeStorage.LocaleStorage;
89
124
  exports.NAMED_CODES_TO_UNICODE = require_markdown_constants.NAMED_CODES_TO_UNICODE;
125
+ exports.NP_TABLE_R = require_markdown_constants.NP_TABLE_R;
90
126
  exports.ORDERED = require_markdown_constants.ORDERED;
127
+ exports.ORDERED_LIST_BULLET = require_markdown_constants.ORDERED_LIST_BULLET;
128
+ exports.ORDERED_LIST_ITEM_PREFIX = require_markdown_constants.ORDERED_LIST_ITEM_PREFIX;
129
+ exports.ORDERED_LIST_ITEM_PREFIX_R = require_markdown_constants.ORDERED_LIST_ITEM_PREFIX_R;
130
+ exports.ORDERED_LIST_ITEM_R = require_markdown_constants.ORDERED_LIST_ITEM_R;
131
+ exports.ORDERED_LIST_R = require_markdown_constants.ORDERED_LIST_R;
132
+ exports.PARAGRAPH_R = require_markdown_constants.PARAGRAPH_R;
91
133
  exports.Priority = require_markdown_constants.Priority;
134
+ exports.REFERENCE_IMAGE_OR_LINK = require_markdown_constants.REFERENCE_IMAGE_OR_LINK;
135
+ exports.REFERENCE_IMAGE_R = require_markdown_constants.REFERENCE_IMAGE_R;
136
+ exports.REFERENCE_LINK_R = require_markdown_constants.REFERENCE_LINK_R;
92
137
  exports.RuleType = require_markdown_constants.RuleType;
138
+ exports.SHORTCODE_R = require_markdown_constants.SHORTCODE_R;
139
+ exports.SHOULD_RENDER_AS_BLOCK_R = require_markdown_constants.SHOULD_RENDER_AS_BLOCK_R;
140
+ exports.TABLE_CENTER_ALIGN = require_markdown_constants.TABLE_CENTER_ALIGN;
141
+ exports.TABLE_LEFT_ALIGN = require_markdown_constants.TABLE_LEFT_ALIGN;
142
+ exports.TABLE_RIGHT_ALIGN = require_markdown_constants.TABLE_RIGHT_ALIGN;
143
+ exports.TABLE_TRIM_PIPES = require_markdown_constants.TABLE_TRIM_PIPES;
144
+ exports.TAB_R = require_markdown_constants.TAB_R;
145
+ exports.TEXT_BOLD_R = require_markdown_constants.TEXT_BOLD_R;
146
+ exports.TEXT_EMPHASIZED_R = require_markdown_constants.TEXT_EMPHASIZED_R;
147
+ exports.TEXT_ESCAPED_R = require_markdown_constants.TEXT_ESCAPED_R;
148
+ exports.TEXT_MARKED_R = require_markdown_constants.TEXT_MARKED_R;
149
+ exports.TEXT_PLAIN_R = require_markdown_constants.TEXT_PLAIN_R;
150
+ exports.TEXT_STRIKETHROUGHED_R = require_markdown_constants.TEXT_STRIKETHROUGHED_R;
151
+ exports.TRIM_STARTING_NEWLINES = require_markdown_constants.TRIM_STARTING_NEWLINES;
152
+ exports.UNESCAPE_R = require_markdown_constants.UNESCAPE_R;
93
153
  exports.UNORDERED = require_markdown_constants.UNORDERED;
154
+ exports.UNORDERED_LIST_BULLET = require_markdown_constants.UNORDERED_LIST_BULLET;
155
+ exports.UNORDERED_LIST_ITEM_PREFIX = require_markdown_constants.UNORDERED_LIST_ITEM_PREFIX;
156
+ exports.UNORDERED_LIST_ITEM_PREFIX_R = require_markdown_constants.UNORDERED_LIST_ITEM_PREFIX_R;
157
+ exports.UNORDERED_LIST_ITEM_R = require_markdown_constants.UNORDERED_LIST_ITEM_R;
158
+ exports.UNORDERED_LIST_R = require_markdown_constants.UNORDERED_LIST_R;
94
159
  exports.allowInline = require_markdown_utils.allowInline;
95
160
  exports.anyScopeRegex = require_markdown_utils.anyScopeRegex;
96
161
  exports.attributeValueToNodePropValue = require_markdown_utils.attributeValueToNodePropValue;
@@ -121,6 +186,10 @@ exports.filterTranslationsOnlyPlugin = require_deepTransformPlugins_getFilterTra
121
186
  exports.findMatchingCondition = require_interpreter_getEnumeration.findMatchingCondition;
122
187
  exports.gender = require_transpiler_gender_gender.gender;
123
188
  exports.genderPlugin = require_interpreter_getContent_plugins.genderPlugin;
189
+ exports.generateListItemPrefix = require_markdown_constants.generateListItemPrefix;
190
+ exports.generateListItemPrefixRegex = require_markdown_constants.generateListItemPrefixRegex;
191
+ exports.generateListItemRegex = require_markdown_constants.generateListItemRegex;
192
+ exports.generateListRegex = require_markdown_constants.generateListRegex;
124
193
  exports.get = require_markdown_utils.get;
125
194
  exports.getBrowserLocale = require_localization_getBrowserLocale.getBrowserLocale;
126
195
  exports.getCanonicalPath = require_localization_rewriteUtils.getCanonicalPath;
@@ -141,6 +210,7 @@ exports.getFilteredLocalesDictionary = require_deepTransformPlugins_getFilteredL
141
210
  exports.getHTML = require_interpreter_getHTML.getHTML;
142
211
  exports.getHTMLTextDir = require_localization_getHTMLTextDir.getHTMLTextDir;
143
212
  exports.getInsertionValues = require_transpiler_insertion_getInsertionValues.getInsertionValues;
213
+ exports.getInternalPath = require_localization_rewriteUtils.getInternalPath;
144
214
  exports.getIntlayer = require_interpreter_getIntlayer.getIntlayer;
145
215
  exports.getLocale = require_localization_getLocale.getLocale;
146
216
  exports.getLocaleFromPath = require_localization_getLocaleFromPath.getLocaleFromPath;
@@ -163,11 +233,13 @@ exports.getPathWithoutLocale = require_localization_getPathWithoutLocale.getPath
163
233
  exports.getPerLocaleDictionary = require_deepTransformPlugins_getLocalizedContent.getPerLocaleDictionary;
164
234
  exports.getPrefix = require_localization_getPrefix.getPrefix;
165
235
  exports.getReplacedValuesContent = require_deepTransformPlugins_getReplacedValuesContent.getReplacedValuesContent;
236
+ exports.getRewritePath = require_localization_rewriteUtils.getRewritePath;
237
+ exports.getRewriteRules = require_localization_rewriteUtils.getRewriteRules;
166
238
  exports.getSplittedContent = require_deepTransformPlugins_getSplittedContent.getSplittedContent;
167
239
  exports.getSplittedDictionaryContent = require_deepTransformPlugins_getSplittedContent.getSplittedDictionaryContent;
168
240
  exports.getStorageAttributes = require_getStorageAttributes.getStorageAttributes;
169
241
  exports.getTranslation = require_interpreter_getTranslation.getTranslation;
170
- exports.html = require_transpiler_html_index.html;
242
+ exports.html = require_transpiler_html_html.html;
171
243
  exports.inlineRegex = require_markdown_utils.inlineRegex;
172
244
  exports.insert = require_transpiler_insertion_insertion.insert;
173
245
  exports.insertContentInDictionary = require_deepTransformPlugins_insertContentInDictionary.insertContentInDictionary;
@@ -197,6 +269,7 @@ exports.parseInline = require_markdown_utils.parseInline;
197
269
  exports.parseSimpleInline = require_markdown_utils.parseSimpleInline;
198
270
  exports.parseStyleAttribute = require_markdown_utils.parseStyleAttribute;
199
271
  exports.parseTableAlign = require_markdown_utils.parseTableAlign;
272
+ exports.parseTableAlignCapture = require_markdown_utils.parseTableAlignCapture;
200
273
  exports.parseTableCells = require_markdown_utils.parseTableCells;
201
274
  exports.parseTableRow = require_markdown_utils.parseTableRow;
202
275
  exports.parseYaml = require_utils_parseYaml.parseYaml;
@@ -214,6 +287,7 @@ exports.simpleInlineRegex = require_markdown_utils.simpleInlineRegex;
214
287
  exports.slugify = require_markdown_utils.slugify;
215
288
  exports.some = require_markdown_utils.some;
216
289
  exports.splitInsertionTemplate = require_interpreter_splitAndJoinInsertion.splitInsertionTemplate;
290
+ exports.startsWith = require_markdown_utils.startsWith;
217
291
  exports.t = require_transpiler_translation_translation.t;
218
292
  exports.translationPlugin = require_interpreter_getContent_plugins.translationPlugin;
219
293
  exports.trimEnd = require_markdown_utils.trimEnd;
@@ -1 +1 @@
1
- {"version":3,"file":"plugins.cjs","names":["NodeType","getTranslation","getEnumeration","getCondition","getInsertion","getGender","getNesting"],"sources":["../../../../src/interpreter/getContent/plugins.ts"],"sourcesContent":["import {\n type DeclaredLocales,\n type DictionaryKeys,\n type KeyPath,\n type Locale,\n type LocalesValues,\n NodeType,\n} from '@intlayer/types';\nimport type {\n ConditionContent,\n EnumerationContent,\n FileContent,\n Gender,\n GenderContent,\n InsertionContent,\n NestedContent,\n TranslationContent,\n} from '../../transpiler';\nimport { getCondition } from '../getCondition';\nimport { getEnumeration } from '../getEnumeration';\nimport { getGender } from '../getGender';\nimport { getInsertion } from '../getInsertion';\nimport { type GetNestingResult, getNesting } from '../getNesting';\nimport { getTranslation } from '../getTranslation';\n\n/** ---------------------------------------------\n * PLUGIN DEFINITION\n * --------------------------------------------- */\n\n/**\n * A plugin/transformer that can optionally transform a node during a single DFS pass.\n * - `canHandle` decides if the node is transformable by this plugin.\n * - `transform` returns the transformed node (and does not recurse further).\n *\n * > `transformFn` is a function that can be used to deeply transform inside the plugin.\n */\nexport type Plugins = {\n id: string;\n canHandle: (node: any) => boolean;\n transform: (\n node: any,\n props: NodeProps,\n transformFn: (node: any, props: NodeProps) => any\n ) => any;\n};\n\n/** ---------------------------------------------\n * TRANSLATION PLUGIN\n * --------------------------------------------- */\n\nexport type TranslationCond<T, S, L extends LocalesValues> = T extends {\n nodeType: NodeType | string;\n [NodeType.Translation]: infer U;\n}\n ? U extends Record<PropertyKey, unknown>\n ? L extends keyof U\n ? DeepTransformContent<U[L], S>\n : DeepTransformContent<U[keyof U], S>\n : never\n : never;\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const translationPlugin = (\n locale: LocalesValues,\n fallback?: LocalesValues\n): Plugins => ({\n id: 'translation-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeType.Translation,\n transform: (node: TranslationContent, props, deepTransformNode) => {\n const result = structuredClone(node[NodeType.Translation]);\n\n for (const key in result) {\n const childProps = {\n ...props,\n children: result[key as keyof typeof result],\n keyPath: [\n ...props.keyPath,\n { type: NodeType.Translation, key } as KeyPath,\n ],\n };\n result[key as keyof typeof result] = deepTransformNode(\n result[key as keyof typeof result],\n childProps\n );\n }\n\n return getTranslation(result, locale, fallback);\n },\n});\n\n/** ---------------------------------------------\n * ENUMERATION PLUGIN\n * --------------------------------------------- */\n\nexport type EnumerationCond<T, S, L> = T extends {\n nodeType: NodeType | string;\n [NodeType.Enumeration]: object;\n}\n ? (\n quantity: number\n ) => DeepTransformContent<\n T[NodeType.Enumeration][keyof T[NodeType.Enumeration]],\n S\n >\n : never;\n\n/** Enumeration plugin. Replaces node with a function that takes quantity => string. */\nexport const enumerationPlugin: Plugins = {\n id: 'enumeration-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeType.Enumeration,\n transform: (node: EnumerationContent, props, deepTransformNode) => {\n const result = structuredClone(node[NodeType.Enumeration]);\n\n for (const key in result) {\n const child = result[key as unknown as keyof typeof result];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeType.Enumeration, key } as KeyPath,\n ],\n };\n result[key as unknown as keyof typeof result] = deepTransformNode(\n child,\n childProps\n );\n }\n\n return (arg: number | { count: number }) => {\n const quantity = typeof arg === 'number' ? arg : arg.count;\n const subResult = getEnumeration(result, quantity);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n};\n\n/** ---------------------------------------------\n * CONDITION PLUGIN\n * --------------------------------------------- */\n\nexport type ConditionCond<T, S, L> = T extends {\n nodeType: NodeType | string;\n [NodeType.Condition]: object;\n}\n ? (\n value: boolean | { value: boolean }\n ) => DeepTransformContent<\n T[NodeType.Condition][keyof T[NodeType.Condition]],\n S\n >\n : never;\n\n/** Condition plugin. Replaces node with a function that takes boolean => string. */\nexport const conditionPlugin: Plugins = {\n id: 'condition-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeType.Condition,\n transform: (node: ConditionContent, props, deepTransformNode) => {\n const result = structuredClone(node[NodeType.Condition]);\n\n for (const key in result) {\n const child = result[key as keyof typeof result];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeType.Condition, key } as KeyPath,\n ],\n };\n result[key as unknown as keyof typeof result] = deepTransformNode(\n child,\n childProps\n );\n }\n\n return (arg: boolean | { value: boolean }) => {\n const value = typeof arg === 'boolean' ? arg : arg.value;\n const subResult = getCondition(result, value);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n};\n\n/** ---------------------------------------------\n * INSERTION PLUGIN\n * --------------------------------------------- */\n\nexport type InsertionCond<T, S, L> = T extends {\n nodeType: NodeType | string;\n [NodeType.Insertion]: string;\n fields: readonly string[];\n}\n ? (\n values: {\n [K in T['fields'][number]]: string | number;\n }\n ) => DeepTransformContent<string, S>\n : never;\n\n/** Insertion plugin. Replaces node with a function that takes quantity => string. */\nexport const insertionPlugin: Plugins = {\n id: 'insertion-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeType.Insertion,\n transform: (node: InsertionContent, props, deepTransformNode) => {\n const newKeyPath: KeyPath[] = [\n ...props.keyPath,\n {\n type: NodeType.Insertion,\n },\n ];\n\n const children = node[NodeType.Insertion];\n\n /** Insertion string plugin. Replaces string node with a component that render the insertion. */\n const insertionStringPlugin: Plugins = {\n id: 'insertion-string-plugin',\n canHandle: (node) => typeof node === 'string',\n transform: (node: string, subProps, deepTransformNode) => {\n const transformedResult = deepTransformNode(node, {\n ...subProps,\n children: node,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) => plugin.id !== 'intlayer-node-plugin'\n ),\n ],\n });\n\n return (\n values: {\n [K in InsertionContent['fields'][number]]: string | number;\n }\n ) => {\n const children = getInsertion(transformedResult, values);\n\n return deepTransformNode(children, {\n ...subProps,\n plugins: props.plugins,\n children,\n });\n };\n },\n };\n\n return deepTransformNode(children, {\n ...props,\n children,\n keyPath: newKeyPath,\n plugins: [insertionStringPlugin, ...(props.plugins ?? [])],\n });\n },\n};\n\n/** ---------------------------------------------\n * GENDER PLUGIN\n * --------------------------------------------- */\n\nexport type GenderCond<T, S, L> = T extends {\n nodeType: NodeType | string;\n [NodeType.Gender]: object;\n}\n ? (\n value: Gender\n ) => DeepTransformContent<T[NodeType.Gender][keyof T[NodeType.Gender]], S>\n : never;\n\n/** Gender plugin. Replaces node with a function that takes gender => string. */\nexport const genderPlugin: Plugins = {\n id: 'gender-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeType.Gender,\n transform: (node: GenderContent, props, deepTransformNode) => {\n const result = structuredClone(node[NodeType.Gender]);\n\n for (const key in result) {\n const child = result[key as keyof typeof result];\n const childProps = {\n ...props,\n children: child,\n keyPath: [...props.keyPath, { type: NodeType.Gender, key } as KeyPath],\n };\n result[key as keyof typeof result] = deepTransformNode(child, childProps);\n }\n\n return (value: Gender) => getGender(result, value);\n },\n};\n\n/** ---------------------------------------------\n * NESTED PLUGIN\n * --------------------------------------------- */\n\nexport type NestedCond<T, S, L> = T extends {\n nodeType: NodeType | string;\n [NodeType.Nested]: infer U;\n}\n ? U extends {\n dictionaryKey: infer K extends DictionaryKeys;\n path?: infer P;\n }\n ? GetNestingResult<K, P, S>\n : never\n : never;\n\n/** Nested plugin. Replaces node with the result of `getNesting`. */\nexport const nestedPlugin = (locale?: LocalesValues): Plugins => ({\n id: 'nested-plugin',\n canHandle: (node) =>\n typeof node === 'object' &&\n (node?.nodeType === NodeType.Nested || node?.nodeType === 'nested'),\n transform: (node: NestedContent, props) =>\n getNesting(node.nested.dictionaryKey, node.nested.path, {\n ...props,\n locale: (locale ?? props.locale) as Locale,\n }),\n});\n\n/** ---------------------------------------------\n * HTML PLUGIN\n * --------------------------------------------- */\n\n/**\n * Props for HTML tag components.\n * Includes children and an index signature for attributes.\n * Framework-specific implementations should extend this with proper types (ReactNode, VNode, etc.)\n */\nexport type HTMLTagComponentProps = {\n children?: any;\n [key: string]: any;\n};\n\n/**\n * A component that can be used to replace an HTML tag.\n * Can be a string (tag name) or a functional component.\n * Framework-specific implementations should use properly typed versions.\n */\nexport type HTMLTagComponent<Children = any, Return = any> =\n | string\n | ((props: { children?: Children; [key: string]: any }) => Return);\n\n/**\n * Helper to map string types from dictionary to TypeScript types\n */\nexport type PropTypeMap<T> = T extends 'string'\n ? string\n : T extends 'number'\n ? number\n : T extends 'boolean'\n ? boolean\n : any;\n\n/**\n * Helper to extract props from the dictionary definition of a custom component\n */\nexport type ExtractCustomProps<Definition, Children = any> = {\n [K in keyof Definition]?: Definition[K] extends string\n ? PropTypeMap<Definition[K]>\n : any;\n} & {\n children?: Children;\n [key: string]: any;\n};\n\n/**\n * HTML conditional type that enforces:\n * - All components (Standard or Custom) are OPTIONAL in the `use()` method.\n * - Custom components props are strictly inferred from the dictionary definition.\n *\n * This ensures type safety:\n * - `html('<div>Hello <CustomComponent /></div>').use({ CustomComponent: ... })` - optional but typed\n */\nexport type HTMLCond<T, S, L, Children = any, Return = any> = T extends {\n nodeType: NodeType | string;\n [NodeType.HTML]: string;\n tags?: infer U;\n}\n ? {\n use: U extends Record<string, any>\n ? (\n components?: {\n // Map all keys from U, making them optional\n [K in keyof U]?: U[K] extends true\n ? HTMLTagComponent<Children, Return>\n :\n | string\n | ((props: ExtractCustomProps<U[K], Children>) => Return);\n } & Partial<Record<string, HTMLTagComponent<Children, Return>>>\n ) => Return\n : // Fallback for array or undefined tags (legacy)\n (\n components?: Record<string, HTMLTagComponent<Children, Return>>\n ) => Return;\n } & any\n : never;\n\n/** ---------------------------------------------\n * FILE PLUGIN\n * --------------------------------------------- */\n\nexport type FileCond<T> = T extends {\n nodeType: NodeType | string;\n [NodeType.File]: string;\n content?: string;\n}\n ? string\n : never;\n\n/** File plugin. Replaces node with the result of `getNesting`. */\nexport const filePlugin: Plugins = {\n id: 'file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeType.File,\n transform: (node: FileContent, props, deepTransform) =>\n deepTransform(node.content, {\n ...props,\n children: node.content,\n }),\n};\n\n/**\n * PLUGIN RESULT\n */\n\n/**\n * Interface that defines the properties of a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface NodeProps {\n dictionaryKey: string;\n keyPath: KeyPath[];\n plugins?: Plugins[];\n locale?: Locale;\n dictionaryPath?: string;\n children?: any;\n}\n\n/**\n * Interface that defines the plugins that can be used to transform a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface IInterpreterPlugin<T, S, L extends LocalesValues> {\n translation: TranslationCond<T, S, L>;\n insertion: InsertionCond<T, S, L>;\n enumeration: EnumerationCond<T, S, L>;\n condition: ConditionCond<T, S, L>;\n nested: NestedCond<T, S, L>;\n html: HTMLCond<T, S, L>;\n // file: FileCond<T>;\n}\n\n/**\n * Allow to avoid overwriting import from `intlayer` package when `IInterpreterPlugin<T>` interface is augmented in another package, such as `react-intlayer`.\n */\nexport type IInterpreterPluginState = {\n translation: true;\n enumeration: true;\n condition: true;\n insertion: true;\n nested: true;\n html: true;\n // file: true;\n};\n\n/**\n * Utility type to check if a plugin can be applied to a node.\n */\ntype CheckApplyPlugin<\n T,\n K extends keyof IInterpreterPlugin<T, S, L>,\n S,\n L extends LocalesValues = DeclaredLocales,\n> = K extends keyof S // Test if the key is a key of S.\n ? // Test if the key of S is true. Then the plugin can be applied.\n S[K] extends true\n ? // Test if the key of S exist\n IInterpreterPlugin<T, S, L>[K] extends never\n ? never\n : // Test if the plugin condition is true (if it's not, the plugin is skipped for this node)\n IInterpreterPlugin<T, S, L>[K]\n : never\n : never;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\ntype Traverse<\n T,\n S,\n L extends LocalesValues = DeclaredLocales,\n> = T extends ReadonlyArray<infer U> // Turn any read-only array into a plain mutable array\n ? Array<DeepTransformContent<U, S, L>>\n : T extends object\n ? { [K in keyof T]: DeepTransformContent<T[K], S, L> }\n : T;\n\nexport type IsAny<T> = 0 extends 1 & T ? true : false;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\nexport type DeepTransformContent<\n T,\n S = IInterpreterPluginState,\n L extends LocalesValues = DeclaredLocales,\n> = IsAny<T> extends true\n ? T\n : CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S> extends never // Check if there is a plugin for T:\n ? // No plugin was found, so try to transform T recursively:\n Traverse<T, S, L>\n : // A plugin was found – use the plugin’s transformation.\n IInterpreterPlugin<T, S, L>[keyof IInterpreterPlugin<T, S, L>];\n"],"mappings":";;;;;;;;;;;AA8DA,MAAa,qBACX,QACA,cACa;CACb,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAS;CAC1D,YAAY,MAA0B,OAAO,sBAAsB;EACjE,MAAM,SAAS,gBAAgB,KAAKA,yBAAS,aAAa;AAE1D,OAAK,MAAM,OAAO,QAAQ;GACxB,MAAM,aAAa;IACjB,GAAG;IACH,UAAU,OAAO;IACjB,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAMA,yBAAS;KAAa;KAAK,CACpC;IACF;AACD,UAAO,OAA8B,kBACnC,OAAO,MACP,WACD;;AAGH,SAAOC,kDAAe,QAAQ,QAAQ,SAAS;;CAElD;;AAmBD,MAAa,oBAA6B;CACxC,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaD,yBAAS;CAC1D,YAAY,MAA0B,OAAO,sBAAsB;EACjE,MAAM,SAAS,gBAAgB,KAAKA,yBAAS,aAAa;AAE1D,OAAK,MAAM,OAAO,QAAQ;GACxB,MAAM,QAAQ,OAAO;AASrB,UAAO,OAAyC,kBAC9C,OATiB;IACjB,GAAG;IACH,UAAU;IACV,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAMA,yBAAS;KAAa;KAAK,CACpC;IACF,CAIA;;AAGH,UAAQ,QAAoC;GAE1C,MAAM,YAAYE,kDAAe,QADhB,OAAO,QAAQ,WAAW,MAAM,IAAI,MACH;AAElD,OAAI,OAAO,cAAc,cAAc,OAAO,QAAQ,SACpD,QAAO,UAAU,IAAI;AAGvB,UAAO;;;CAGZ;;AAmBD,MAAa,kBAA2B;CACtC,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaF,yBAAS;CAC1D,YAAY,MAAwB,OAAO,sBAAsB;EAC/D,MAAM,SAAS,gBAAgB,KAAKA,yBAAS,WAAW;AAExD,OAAK,MAAM,OAAO,QAAQ;GACxB,MAAM,QAAQ,OAAO;AASrB,UAAO,OAAyC,kBAC9C,OATiB;IACjB,GAAG;IACH,UAAU;IACV,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAMA,yBAAS;KAAW;KAAK,CAClC;IACF,CAIA;;AAGH,UAAQ,QAAsC;GAE5C,MAAM,YAAYG,8CAAa,QADjB,OAAO,QAAQ,YAAY,MAAM,IAAI,MACN;AAE7C,OAAI,OAAO,cAAc,cAAc,OAAO,QAAQ,SACpD,QAAO,UAAU,IAAI;AAGvB,UAAO;;;CAGZ;;AAmBD,MAAa,kBAA2B;CACtC,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaH,yBAAS;CAC1D,YAAY,MAAwB,OAAO,sBAAsB;EAC/D,MAAM,aAAwB,CAC5B,GAAG,MAAM,SACT,EACE,MAAMA,yBAAS,WAChB,CACF;EAED,MAAM,WAAW,KAAKA,yBAAS;;EAG/B,MAAM,wBAAiC;GACrC,IAAI;GACJ,YAAY,SAAS,OAAO,SAAS;GACrC,YAAY,MAAc,UAAU,sBAAsB;IACxD,MAAM,oBAAoB,kBAAkB,MAAM;KAChD,GAAG;KACH,UAAU;KACV,SAAS,CACP,IAAI,MAAM,WAAY,EAAE,EAAgB,QACrC,WAAW,OAAO,OAAO,uBAC3B,CACF;KACF,CAAC;AAEF,YACE,WAGG;KACH,MAAM,WAAWI,8CAAa,mBAAmB,OAAO;AAExD,YAAO,kBAAkB,UAAU;MACjC,GAAG;MACH,SAAS,MAAM;MACf;MACD,CAAC;;;GAGP;AAED,SAAO,kBAAkB,UAAU;GACjC,GAAG;GACH;GACA,SAAS;GACT,SAAS,CAAC,uBAAuB,GAAI,MAAM,WAAW,EAAE,CAAE;GAC3D,CAAC;;CAEL;;AAgBD,MAAa,eAAwB;CACnC,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaJ,yBAAS;CAC1D,YAAY,MAAqB,OAAO,sBAAsB;EAC5D,MAAM,SAAS,gBAAgB,KAAKA,yBAAS,QAAQ;AAErD,OAAK,MAAM,OAAO,QAAQ;GACxB,MAAM,QAAQ,OAAO;AAMrB,UAAO,OAA8B,kBAAkB,OALpC;IACjB,GAAG;IACH,UAAU;IACV,SAAS,CAAC,GAAG,MAAM,SAAS;KAAE,MAAMA,yBAAS;KAAQ;KAAK,CAAY;IACvE,CACwE;;AAG3E,UAAQ,UAAkBK,wCAAU,QAAQ,MAAM;;CAErD;;AAmBD,MAAa,gBAAgB,YAAqC;CAChE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,aACf,MAAM,aAAaL,yBAAS,UAAU,MAAM,aAAa;CAC5D,YAAY,MAAqB,UAC/BM,0CAAW,KAAK,OAAO,eAAe,KAAK,OAAO,MAAM;EACtD,GAAG;EACH,QAAS,UAAU,MAAM;EAC1B,CAAC;CACL;;AA6FD,MAAa,aAAsB;CACjC,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaN,yBAAS;CAC1D,YAAY,MAAmB,OAAO,kBACpC,cAAc,KAAK,SAAS;EAC1B,GAAG;EACH,UAAU,KAAK;EAChB,CAAC;CACL"}
1
+ {"version":3,"file":"plugins.cjs","names":["NodeType","getTranslation","getEnumeration","getCondition","getInsertion","getGender","getNesting"],"sources":["../../../../src/interpreter/getContent/plugins.ts"],"sourcesContent":["import {\n type DeclaredLocales,\n type DictionaryKeys,\n type KeyPath,\n type Locale,\n type LocalesValues,\n NodeType,\n} from '@intlayer/types';\nimport type {\n ConditionContent,\n EnumerationContent,\n FileContent,\n Gender,\n GenderContent,\n InsertionContent,\n NestedContent,\n TranslationContent,\n} from '../../transpiler';\nimport { getCondition } from '../getCondition';\nimport { getEnumeration } from '../getEnumeration';\nimport { getGender } from '../getGender';\nimport { getInsertion } from '../getInsertion';\nimport { type GetNestingResult, getNesting } from '../getNesting';\nimport { getTranslation } from '../getTranslation';\n\n/** ---------------------------------------------\n * PLUGIN DEFINITION\n * --------------------------------------------- */\n\n/**\n * A plugin/transformer that can optionally transform a node during a single DFS pass.\n * - `canHandle` decides if the node is transformable by this plugin.\n * - `transform` returns the transformed node (and does not recurse further).\n *\n * > `transformFn` is a function that can be used to deeply transform inside the plugin.\n */\nexport type Plugins = {\n id: string;\n canHandle: (node: any) => boolean;\n transform: (\n node: any,\n props: NodeProps,\n transformFn: (node: any, props: NodeProps) => any\n ) => any;\n};\n\n/** ---------------------------------------------\n * TRANSLATION PLUGIN\n * --------------------------------------------- */\n\nexport type TranslationCond<T, S, L extends LocalesValues> = T extends {\n nodeType: NodeType | string;\n [NodeType.Translation]: infer U;\n}\n ? U extends Record<PropertyKey, unknown>\n ? L extends keyof U\n ? DeepTransformContent<U[L], S>\n : DeepTransformContent<U[keyof U], S>\n : never\n : never;\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const translationPlugin = (\n locale: LocalesValues,\n fallback?: LocalesValues\n): Plugins => ({\n id: 'translation-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeType.Translation,\n transform: (node: TranslationContent, props, deepTransformNode) => {\n const result = structuredClone(node[NodeType.Translation]);\n\n for (const key in result) {\n const childProps = {\n ...props,\n children: result[key as keyof typeof result],\n keyPath: [\n ...props.keyPath,\n { type: NodeType.Translation, key } as KeyPath,\n ],\n };\n result[key as keyof typeof result] = deepTransformNode(\n result[key as keyof typeof result],\n childProps\n );\n }\n\n return getTranslation(result, locale, fallback);\n },\n});\n\n/** ---------------------------------------------\n * ENUMERATION PLUGIN\n * --------------------------------------------- */\n\nexport type EnumerationCond<T, S, L> = T extends {\n nodeType: NodeType | string;\n [NodeType.Enumeration]: object;\n}\n ? (\n quantity: number\n ) => DeepTransformContent<\n T[NodeType.Enumeration][keyof T[NodeType.Enumeration]],\n S\n >\n : never;\n\n/** Enumeration plugin. Replaces node with a function that takes quantity => string. */\nexport const enumerationPlugin: Plugins = {\n id: 'enumeration-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeType.Enumeration,\n transform: (node: EnumerationContent, props, deepTransformNode) => {\n const result = structuredClone(node[NodeType.Enumeration]);\n\n for (const key in result) {\n const child = result[key as unknown as keyof typeof result];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeType.Enumeration, key } as KeyPath,\n ],\n };\n result[key as unknown as keyof typeof result] = deepTransformNode(\n child,\n childProps\n );\n }\n\n return (arg: number | { count: number }) => {\n const quantity = typeof arg === 'number' ? arg : arg.count;\n const subResult = getEnumeration(result, quantity);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n};\n\n/** ---------------------------------------------\n * CONDITION PLUGIN\n * --------------------------------------------- */\n\nexport type ConditionCond<T, S, L> = T extends {\n nodeType: NodeType | string;\n [NodeType.Condition]: object;\n}\n ? (\n value: boolean | { value: boolean }\n ) => DeepTransformContent<\n T[NodeType.Condition][keyof T[NodeType.Condition]],\n S\n >\n : never;\n\n/** Condition plugin. Replaces node with a function that takes boolean => string. */\nexport const conditionPlugin: Plugins = {\n id: 'condition-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeType.Condition,\n transform: (node: ConditionContent, props, deepTransformNode) => {\n const result = structuredClone(node[NodeType.Condition]);\n\n for (const key in result) {\n const child = result[key as keyof typeof result];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeType.Condition, key } as KeyPath,\n ],\n };\n result[key as unknown as keyof typeof result] = deepTransformNode(\n child,\n childProps\n );\n }\n\n return (arg: boolean | { value: boolean }) => {\n const value = typeof arg === 'boolean' ? arg : arg.value;\n const subResult = getCondition(result, value);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n};\n\n/** ---------------------------------------------\n * INSERTION PLUGIN\n * --------------------------------------------- */\n\nexport type InsertionCond<T, S, L> = T extends {\n nodeType: NodeType | string;\n [NodeType.Insertion]: string;\n fields: readonly string[];\n}\n ? (\n values: {\n [K in T['fields'][number]]: string | number;\n }\n ) => DeepTransformContent<string, S>\n : never;\n\n/** Insertion plugin. Replaces node with a function that takes quantity => string. */\nexport const insertionPlugin: Plugins = {\n id: 'insertion-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeType.Insertion,\n transform: (node: InsertionContent, props, deepTransformNode) => {\n const newKeyPath: KeyPath[] = [\n ...props.keyPath,\n {\n type: NodeType.Insertion,\n },\n ];\n\n const children = node[NodeType.Insertion];\n\n /** Insertion string plugin. Replaces string node with a component that render the insertion. */\n const insertionStringPlugin: Plugins = {\n id: 'insertion-string-plugin',\n canHandle: (node) => typeof node === 'string',\n transform: (node: string, subProps, deepTransformNode) => {\n const transformedResult = deepTransformNode(node, {\n ...subProps,\n children: node,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) => plugin.id !== 'intlayer-node-plugin'\n ),\n ],\n });\n\n return (\n values: {\n [K in InsertionContent['fields'][number]]: string | number;\n }\n ) => {\n const children = getInsertion(transformedResult, values);\n\n return deepTransformNode(children, {\n ...subProps,\n plugins: props.plugins,\n children,\n });\n };\n },\n };\n\n return deepTransformNode(children, {\n ...props,\n children,\n keyPath: newKeyPath,\n plugins: [insertionStringPlugin, ...(props.plugins ?? [])],\n });\n },\n};\n\n/** ---------------------------------------------\n * GENDER PLUGIN\n * --------------------------------------------- */\n\nexport type GenderCond<T, S, L> = T extends {\n nodeType: NodeType | string;\n [NodeType.Gender]: object;\n}\n ? (\n value: Gender\n ) => DeepTransformContent<T[NodeType.Gender][keyof T[NodeType.Gender]], S>\n : never;\n\n/** Gender plugin. Replaces node with a function that takes gender => string. */\nexport const genderPlugin: Plugins = {\n id: 'gender-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeType.Gender,\n transform: (node: GenderContent, props, deepTransformNode) => {\n const result = structuredClone(node[NodeType.Gender]);\n\n for (const key in result) {\n const child = result[key as keyof typeof result];\n const childProps = {\n ...props,\n children: child,\n keyPath: [...props.keyPath, { type: NodeType.Gender, key } as KeyPath],\n };\n result[key as keyof typeof result] = deepTransformNode(child, childProps);\n }\n\n return (value: Gender) => getGender(result, value);\n },\n};\n\n/** ---------------------------------------------\n * NESTED PLUGIN\n * --------------------------------------------- */\n\nexport type NestedCond<T, S, L> = T extends {\n nodeType: NodeType | string;\n [NodeType.Nested]: infer U;\n}\n ? U extends {\n dictionaryKey: infer K extends DictionaryKeys;\n path?: infer P;\n }\n ? GetNestingResult<K, P, S>\n : never\n : never;\n\n/** Nested plugin. Replaces node with the result of `getNesting`. */\nexport const nestedPlugin = (locale?: LocalesValues): Plugins => ({\n id: 'nested-plugin',\n canHandle: (node) =>\n typeof node === 'object' &&\n (node?.nodeType === NodeType.Nested || node?.nodeType === 'nested'),\n transform: (node: NestedContent, props) =>\n getNesting(node.nested.dictionaryKey, node.nested.path, {\n ...props,\n locale: (locale ?? props.locale) as Locale,\n }),\n});\n\n/** ---------------------------------------------\n * FILE PLUGIN\n * --------------------------------------------- */\n\nexport type FileCond<T> = T extends {\n nodeType: NodeType | string;\n [NodeType.File]: string;\n content?: string;\n}\n ? string\n : never;\n\n/** File plugin. Replaces node with the result of `getNesting`. */\nexport const filePlugin: Plugins = {\n id: 'file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeType.File,\n transform: (node: FileContent, props, deepTransform) =>\n deepTransform(node.content, {\n ...props,\n children: node.content,\n }),\n};\n\n/**\n * PLUGIN RESULT\n */\n\n/**\n * Interface that defines the properties of a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface NodeProps {\n dictionaryKey: string;\n keyPath: KeyPath[];\n plugins?: Plugins[];\n locale?: Locale;\n dictionaryPath?: string;\n children?: any;\n}\n\n/**\n * Interface that defines the plugins that can be used to transform a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface IInterpreterPlugin<T, S, L extends LocalesValues> {\n translation: TranslationCond<T, S, L>;\n enumeration: EnumerationCond<T, S, L>;\n condition: ConditionCond<T, S, L>;\n nested: NestedCond<T, S, L>;\n file: FileCond<T>;\n}\n\n/**\n * Allow to avoid overwriting import from `intlayer` package when `IInterpreterPlugin<T>` interface is augmented in another package, such as `react-intlayer`.\n */\nexport type IInterpreterPluginState = {\n translation: true;\n enumeration: true;\n condition: true;\n nested: true;\n file: true;\n};\n\n/**\n * Utility type to check if a plugin can be applied to a node.\n */\ntype CheckApplyPlugin<\n T,\n K extends keyof IInterpreterPlugin<T, S, L>,\n S,\n L extends LocalesValues = DeclaredLocales,\n> = K extends keyof S // Test if the key is a key of S.\n ? // Test if the key of S is true. Then the plugin can be applied.\n S[K] extends true\n ? // Test if the key of S exist\n IInterpreterPlugin<T, S, L>[K] extends never\n ? never\n : // Test if the plugin condition is true (if it's not, the plugin is skipped for this node)\n IInterpreterPlugin<T, S, L>[K]\n : never\n : never;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\ntype Traverse<\n T,\n S,\n L extends LocalesValues = DeclaredLocales,\n> = T extends ReadonlyArray<infer U> // Turn any read-only array into a plain mutable array\n ? Array<DeepTransformContent<U, S, L>>\n : T extends object\n ? { [K in keyof T]: DeepTransformContent<T[K], S, L> }\n : T;\n\nexport type IsAny<T> = 0 extends 1 & T ? true : false;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\nexport type DeepTransformContent<\n T,\n S = IInterpreterPluginState,\n L extends LocalesValues = DeclaredLocales,\n> = IsAny<T> extends true\n ? T\n : CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S> extends never // Check if there is a plugin for T:\n ? // No plugin was found, so try to transform T recursively:\n Traverse<T, S, L>\n : // A plugin was found – use the plugin’s transformation.\n IInterpreterPlugin<T, S, L>[keyof IInterpreterPlugin<T, S, L>];\n"],"mappings":"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"}
@@ -53,11 +53,12 @@ const getLocalizedUrl = (url, currentLocale, options = {}) => {
53
53
  ...options
54
54
  };
55
55
  const urlWithoutLocale = require_localization_getPathWithoutLocale.getPathWithoutLocale(url, locales);
56
- if (mode === "no-prefix") return require_localization_rewriteUtils.getLocalizedPath(require_localization_rewriteUtils.getCanonicalPath(urlWithoutLocale, void 0, rewrite), currentLocale, rewrite);
56
+ const urlRewriteRules = require_localization_rewriteUtils.getRewriteRules(rewrite, "url");
57
+ if (mode === "no-prefix") return require_localization_rewriteUtils.getLocalizedPath(require_localization_rewriteUtils.getCanonicalPath(urlWithoutLocale, void 0, urlRewriteRules), currentLocale, urlRewriteRules).path;
57
58
  const isAbsoluteUrl = require_utils_checkIsURLAbsolute.checkIsURLAbsolute(urlWithoutLocale);
58
59
  const parsedUrl = isAbsoluteUrl ? new URL(urlWithoutLocale) : new URL(urlWithoutLocale, "http://example.com");
59
60
  const baseUrl = isAbsoluteUrl ? `${parsedUrl.protocol}//${parsedUrl.host}` : "";
60
- const translatedPathname = require_localization_rewriteUtils.getLocalizedPath(require_localization_rewriteUtils.getCanonicalPath(parsedUrl.pathname, void 0, rewrite), currentLocale, rewrite);
61
+ const translatedPathname = require_localization_rewriteUtils.getLocalizedPath(require_localization_rewriteUtils.getCanonicalPath(parsedUrl.pathname, void 0, urlRewriteRules), currentLocale, urlRewriteRules).path;
61
62
  if (mode === "search-params") {
62
63
  const searchParams = new URLSearchParams(parsedUrl.search);
63
64
  searchParams.set("locale", currentLocale.toString());
@@ -1 +1 @@
1
- {"version":3,"file":"getLocalizedUrl.cjs","names":["configuration","DefaultValues","getPathWithoutLocale","getLocalizedPath","getCanonicalPath","checkIsURLAbsolute","getPrefix"],"sources":["../../../src/localization/getLocalizedUrl.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport { DefaultValues } from '@intlayer/config/client';\nimport type { LocalesValues, RoutingConfig } from '@intlayer/types';\nimport { checkIsURLAbsolute } from '../utils/checkIsURLAbsolute';\nimport { getPathWithoutLocale } from './getPathWithoutLocale';\nimport { getPrefix } from './getPrefix';\nimport { getCanonicalPath, getLocalizedPath } from './rewriteUtils';\n\n/**\n * Generate URL by prefixing the given URL with the referenced locale or adding search parameters\n * based on the routing mode. Handles both absolute and relative URLs appropriately.\n *\n * This function gets the locales, default locale, and routing mode from the configuration if not provided.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-no-default' });\n * // Returns '/fr/about' for the French locale\n * // Returns '/about' for the English locale (default)\n *\n * // prefix-all mode\n * getLocalizedUrl('/about', 'en', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-all' });\n * // Returns '/en/about' for the English locale\n * // Returns '/fr/about' for the French locale\n *\n * // search-params mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'search-params' });\n * // Returns '/about?locale=fr' for the French locale\n *\n * // no-prefix mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'no-prefix' });\n * // Returns '/about' for any locale\n * ```\n *\n * @param url - The original URL string to be processed.\n * @param currentLocale - The current locale.\n * @param options - Configuration options\n * @param options.locales - Optional array of supported locales. Defaults to configured locales.\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @returns The localized URL for the current locale.\n */\nexport const getLocalizedUrl = (\n url: string,\n currentLocale: LocalesValues,\n options: {\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n rewrite?: RoutingConfig['rewrite'];\n } = {}\n): string => {\n const { defaultLocale, mode, locales, rewrite } = {\n defaultLocale:\n configuration?.internationalization?.defaultLocale ??\n DefaultValues.Internationalization.DEFAULT_LOCALE,\n mode: configuration?.routing?.mode ?? DefaultValues.Routing.ROUTING_MODE,\n locales:\n configuration?.internationalization?.locales ??\n DefaultValues.Internationalization.LOCALES,\n rewrite: configuration?.routing?.rewrite,\n ...options,\n };\n\n const urlWithoutLocale = getPathWithoutLocale(url, locales);\n\n if (mode === 'no-prefix') {\n // 1. Resolve to canonical path first from the potentially localized input URL\n const canonicalPathname = getCanonicalPath(\n urlWithoutLocale,\n undefined,\n rewrite\n );\n\n // 2. Localize the canonical path for the target locale\n return getLocalizedPath(canonicalPathname, currentLocale as any, rewrite);\n }\n\n const isAbsoluteUrl = checkIsURLAbsolute(urlWithoutLocale);\n\n const parsedUrl = isAbsoluteUrl\n ? new URL(urlWithoutLocale)\n : new URL(urlWithoutLocale, 'http://example.com');\n\n const baseUrl = isAbsoluteUrl\n ? `${parsedUrl.protocol}//${parsedUrl.host}`\n : '';\n\n // 1. Resolve to canonical path first\n const canonicalPathname = getCanonicalPath(\n parsedUrl.pathname,\n undefined,\n rewrite\n );\n\n // 2. Localize the canonical path for the target locale\n const translatedPathname = getLocalizedPath(\n canonicalPathname,\n currentLocale as any,\n rewrite\n );\n\n if (mode === 'search-params') {\n const searchParams = new URLSearchParams(parsedUrl.search);\n searchParams.set('locale', currentLocale.toString());\n\n const queryString = searchParams.toString();\n const pathWithQuery = queryString\n ? `${translatedPathname}?${queryString}`\n : translatedPathname;\n\n return isAbsoluteUrl\n ? `${baseUrl}${pathWithQuery}${parsedUrl.hash}`\n : `${pathWithQuery}${parsedUrl.hash}`;\n }\n\n const { prefix } = getPrefix(currentLocale, {\n defaultLocale,\n mode,\n locales,\n });\n\n let localizedPath = `/${prefix}${translatedPathname}`;\n\n localizedPath = localizedPath.replaceAll(/\\/+/g, '/');\n\n if (localizedPath.length > 1 && localizedPath.endsWith('/')) {\n localizedPath = localizedPath.slice(0, -1);\n }\n\n const finalUrl = isAbsoluteUrl\n ? `${baseUrl}${localizedPath}${parsedUrl.search}${parsedUrl.hash}`\n : `${localizedPath}${parsedUrl.search}${parsedUrl.hash}`;\n\n return finalUrl;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,MAAa,mBACX,KACA,eACA,UAKI,EAAE,KACK;CACX,MAAM,EAAE,eAAe,MAAM,SAAS,YAAY;EAChD,eACEA,gCAAe,sBAAsB,iBACrCC,sCAAc,qBAAqB;EACrC,MAAMD,gCAAe,SAAS,QAAQC,sCAAc,QAAQ;EAC5D,SACED,gCAAe,sBAAsB,WACrCC,sCAAc,qBAAqB;EACrC,SAASD,gCAAe,SAAS;EACjC,GAAG;EACJ;CAED,MAAM,mBAAmBE,+DAAqB,KAAK,QAAQ;AAE3D,KAAI,SAAS,YASX,QAAOC,mDAPmBC,mDACxB,kBACA,QACA,QACD,EAG0C,eAAsB,QAAQ;CAG3E,MAAM,gBAAgBC,oDAAmB,iBAAiB;CAE1D,MAAM,YAAY,gBACd,IAAI,IAAI,iBAAiB,GACzB,IAAI,IAAI,kBAAkB,qBAAqB;CAEnD,MAAM,UAAU,gBACZ,GAAG,UAAU,SAAS,IAAI,UAAU,SACpC;CAUJ,MAAM,qBAAqBF,mDAPDC,mDACxB,UAAU,UACV,QACA,QACD,EAKC,eACA,QACD;AAED,KAAI,SAAS,iBAAiB;EAC5B,MAAM,eAAe,IAAI,gBAAgB,UAAU,OAAO;AAC1D,eAAa,IAAI,UAAU,cAAc,UAAU,CAAC;EAEpD,MAAM,cAAc,aAAa,UAAU;EAC3C,MAAM,gBAAgB,cAClB,GAAG,mBAAmB,GAAG,gBACzB;AAEJ,SAAO,gBACH,GAAG,UAAU,gBAAgB,UAAU,SACvC,GAAG,gBAAgB,UAAU;;CAGnC,MAAM,EAAE,WAAWE,yCAAU,eAAe;EAC1C;EACA;EACA;EACD,CAAC;CAEF,IAAI,gBAAgB,IAAI,SAAS;AAEjC,iBAAgB,cAAc,WAAW,QAAQ,IAAI;AAErD,KAAI,cAAc,SAAS,KAAK,cAAc,SAAS,IAAI,CACzD,iBAAgB,cAAc,MAAM,GAAG,GAAG;AAO5C,QAJiB,gBACb,GAAG,UAAU,gBAAgB,UAAU,SAAS,UAAU,SAC1D,GAAG,gBAAgB,UAAU,SAAS,UAAU"}
1
+ {"version":3,"file":"getLocalizedUrl.cjs","names":["configuration","DefaultValues","getPathWithoutLocale","getRewriteRules","getLocalizedPath","getCanonicalPath","checkIsURLAbsolute","getPrefix"],"sources":["../../../src/localization/getLocalizedUrl.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport { DefaultValues } from '@intlayer/config/client';\nimport type { Locale, LocalesValues, RoutingConfig } from '@intlayer/types';\nimport { checkIsURLAbsolute } from '../utils/checkIsURLAbsolute';\nimport { getPathWithoutLocale } from './getPathWithoutLocale';\nimport { getPrefix } from './getPrefix';\nimport {\n getCanonicalPath,\n getLocalizedPath,\n getRewriteRules,\n} from './rewriteUtils';\n\n/**\n * Generate URL by prefixing the given URL with the referenced locale or adding search parameters\n * based on the routing mode. Handles both absolute and relative URLs appropriately.\n *\n * This function gets the locales, default locale, and routing mode from the configuration if not provided.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-no-default' });\n * // Returns '/fr/about' for the French locale\n * // Returns '/about' for the English locale (default)\n *\n * // prefix-all mode\n * getLocalizedUrl('/about', 'en', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-all' });\n * // Returns '/en/about' for the English locale\n * // Returns '/fr/about' for the French locale\n *\n * // search-params mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'search-params' });\n * // Returns '/about?locale=fr' for the French locale\n *\n * // no-prefix mode\n * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'no-prefix' });\n * // Returns '/about' for any locale\n * ```\n *\n * @param url - The original URL string to be processed.\n * @param currentLocale - The current locale.\n * @param options - Configuration options\n * @param options.locales - Optional array of supported locales. Defaults to configured locales.\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @returns The localized URL for the current locale.\n */\nexport const getLocalizedUrl = (\n url: string,\n currentLocale: LocalesValues,\n options: {\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n rewrite?: RoutingConfig['rewrite'];\n } = {}\n): string => {\n const { defaultLocale, mode, locales, rewrite } = {\n defaultLocale:\n configuration?.internationalization?.defaultLocale ??\n DefaultValues.Internationalization.DEFAULT_LOCALE,\n mode: configuration?.routing?.mode ?? DefaultValues.Routing.ROUTING_MODE,\n locales:\n configuration?.internationalization?.locales ??\n DefaultValues.Internationalization.LOCALES,\n rewrite: configuration?.routing?.rewrite,\n ...options,\n };\n\n const urlWithoutLocale = getPathWithoutLocale(url, locales);\n\n const urlRewriteRules = getRewriteRules(rewrite, 'url');\n\n if (mode === 'no-prefix') {\n // Resolve to canonical path first from the potentially localized input URL\n const canonicalPathname = getCanonicalPath(\n urlWithoutLocale,\n undefined,\n urlRewriteRules\n );\n\n // Localize the canonical path for the target locale\n return getLocalizedPath(\n canonicalPathname,\n currentLocale as Locale,\n urlRewriteRules\n ).path;\n }\n\n const isAbsoluteUrl = checkIsURLAbsolute(urlWithoutLocale);\n\n const parsedUrl = isAbsoluteUrl\n ? new URL(urlWithoutLocale)\n : new URL(urlWithoutLocale, 'http://example.com');\n\n const baseUrl = isAbsoluteUrl\n ? `${parsedUrl.protocol}//${parsedUrl.host}`\n : '';\n\n // Resolve to canonical path first\n const canonicalPathname = getCanonicalPath(\n parsedUrl.pathname,\n undefined,\n urlRewriteRules\n );\n\n // Localize the canonical path for the target locale\n const translatedPathname = getLocalizedPath(\n canonicalPathname,\n currentLocale as Locale,\n urlRewriteRules\n ).path;\n\n if (mode === 'search-params') {\n const searchParams = new URLSearchParams(parsedUrl.search);\n searchParams.set('locale', currentLocale.toString());\n\n const queryString = searchParams.toString();\n const pathWithQuery = queryString\n ? `${translatedPathname}?${queryString}`\n : translatedPathname;\n\n return isAbsoluteUrl\n ? `${baseUrl}${pathWithQuery}${parsedUrl.hash}`\n : `${pathWithQuery}${parsedUrl.hash}`;\n }\n\n const { prefix } = getPrefix(currentLocale, {\n defaultLocale,\n mode,\n locales,\n });\n\n let localizedPath = `/${prefix}${translatedPathname}`;\n\n localizedPath = localizedPath.replaceAll(/\\/+/g, '/');\n\n if (localizedPath.length > 1 && localizedPath.endsWith('/')) {\n localizedPath = localizedPath.slice(0, -1);\n }\n\n const finalUrl = isAbsoluteUrl\n ? `${baseUrl}${localizedPath}${parsedUrl.search}${parsedUrl.hash}`\n : `${localizedPath}${parsedUrl.search}${parsedUrl.hash}`;\n\n return finalUrl;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,MAAa,mBACX,KACA,eACA,UAKI,EAAE,KACK;CACX,MAAM,EAAE,eAAe,MAAM,SAAS,YAAY;EAChD,eACEA,gCAAe,sBAAsB,iBACrCC,sCAAc,qBAAqB;EACrC,MAAMD,gCAAe,SAAS,QAAQC,sCAAc,QAAQ;EAC5D,SACED,gCAAe,sBAAsB,WACrCC,sCAAc,qBAAqB;EACrC,SAASD,gCAAe,SAAS;EACjC,GAAG;EACJ;CAED,MAAM,mBAAmBE,+DAAqB,KAAK,QAAQ;CAE3D,MAAM,kBAAkBC,kDAAgB,SAAS,MAAM;AAEvD,KAAI,SAAS,YASX,QAAOC,mDAPmBC,mDACxB,kBACA,QACA,gBACD,EAKC,eACA,gBACD,CAAC;CAGJ,MAAM,gBAAgBC,oDAAmB,iBAAiB;CAE1D,MAAM,YAAY,gBACd,IAAI,IAAI,iBAAiB,GACzB,IAAI,IAAI,kBAAkB,qBAAqB;CAEnD,MAAM,UAAU,gBACZ,GAAG,UAAU,SAAS,IAAI,UAAU,SACpC;CAUJ,MAAM,qBAAqBF,mDAPDC,mDACxB,UAAU,UACV,QACA,gBACD,EAKC,eACA,gBACD,CAAC;AAEF,KAAI,SAAS,iBAAiB;EAC5B,MAAM,eAAe,IAAI,gBAAgB,UAAU,OAAO;AAC1D,eAAa,IAAI,UAAU,cAAc,UAAU,CAAC;EAEpD,MAAM,cAAc,aAAa,UAAU;EAC3C,MAAM,gBAAgB,cAClB,GAAG,mBAAmB,GAAG,gBACzB;AAEJ,SAAO,gBACH,GAAG,UAAU,gBAAgB,UAAU,SACvC,GAAG,gBAAgB,UAAU;;CAGnC,MAAM,EAAE,WAAWE,yCAAU,eAAe;EAC1C;EACA;EACA;EACD,CAAC;CAEF,IAAI,gBAAgB,IAAI,SAAS;AAEjC,iBAAgB,cAAc,WAAW,QAAQ,IAAI;AAErD,KAAI,cAAc,SAAS,KAAK,cAAc,SAAS,IAAI,CACzD,iBAAgB,cAAc,MAAM,GAAG,GAAG;AAO5C,QAJiB,gBACb,GAAG,UAAU,gBAAgB,UAAU,SAAS,UAAU,SAC1D,GAAG,gBAAgB,UAAU,SAAS,UAAU"}
@@ -17,6 +17,7 @@ const require_localization_validatePrefix = require('./validatePrefix.cjs');
17
17
  exports.getBrowserLocale = require_localization_getBrowserLocale.getBrowserLocale;
18
18
  exports.getCanonicalPath = require_localization_rewriteUtils.getCanonicalPath;
19
19
  exports.getHTMLTextDir = require_localization_getHTMLTextDir.getHTMLTextDir;
20
+ exports.getInternalPath = require_localization_rewriteUtils.getInternalPath;
20
21
  exports.getLocale = require_localization_getLocale.getLocale;
21
22
  exports.getLocaleFromPath = require_localization_getLocaleFromPath.getLocaleFromPath;
22
23
  exports.getLocaleLang = require_localization_getLocaleLang.getLocaleLang;
@@ -26,6 +27,8 @@ exports.getLocalizedUrl = require_localization_getLocalizedUrl.getLocalizedUrl;
26
27
  exports.getMultilingualUrls = require_localization_getMultilingualUrls.getMultilingualUrls;
27
28
  exports.getPathWithoutLocale = require_localization_getPathWithoutLocale.getPathWithoutLocale;
28
29
  exports.getPrefix = require_localization_getPrefix.getPrefix;
30
+ exports.getRewritePath = require_localization_rewriteUtils.getRewritePath;
31
+ exports.getRewriteRules = require_localization_rewriteUtils.getRewriteRules;
29
32
  exports.localeDetector = require_localization_localeDetector.localeDetector;
30
33
  exports.localeFlatMap = require_localization_localeMapper.localeFlatMap;
31
34
  exports.localeMap = require_localization_localeMapper.localeMap;
@@ -1,26 +1,35 @@
1
- const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
- let _intlayer_config_built = require("@intlayer/config/built");
3
- _intlayer_config_built = require_rolldown_runtime.__toESM(_intlayer_config_built);
4
1
 
5
2
  //#region src/localization/rewriteUtils.ts
6
3
  /**
7
- * Helper to convert Next.js dynamic path "[param]" to Regex "([^/]+)"
4
+ * Normalizes legacy Record format or extracts specialized rules from RewriteObject.
8
5
  */
9
- const pathFormatToRegex = (path) => new RegExp(`^${path.replace(/\[([^\]]+)\]/g, "([^/]+)")}$`);
6
+ const getRewriteRules = (rewrite, context = "url") => {
7
+ if (!rewrite) return void 0;
8
+ if ("url" in rewrite) return rewrite[context];
9
+ return { rules: Object.entries(rewrite).map(([canonical, localized]) => ({
10
+ canonical: canonical.startsWith("/") ? canonical.replace(/\[([^\]]+)\]/g, ":$1") : `/${canonical.replace(/\[([^\]]+)\]/g, ":$1")}`,
11
+ localized: Object.fromEntries(Object.entries(localized).map(([locale, pattern]) => {
12
+ return [locale, pattern?.startsWith("/") ? pattern.replace(/\[([^\]]+)\]/g, ":$1") : `/${(pattern || "").replace(/\[([^\]]+)\]/g, ":$1")}`];
13
+ }))
14
+ })) };
15
+ };
16
+ /**
17
+ * Converts normalized pattern to Regex.
18
+ * Internal syntax is strictly :param.
19
+ */
20
+ const patternToRegex = (pattern) => new RegExp(`^${pattern.replace(/:([^/]+)/g, "([^/]+)")}$`);
10
21
  /**
11
22
  * Replaces route parameters in a path with provided values.
12
- * Ex: fillPath('/products/[id]', ['123']) -> '/products/123'
13
23
  */
14
- const fillPath = (path, params) => {
24
+ const fillPath = (pattern, params) => {
15
25
  let index = 0;
16
- return path.replace(/\[([^\]]+)\]/g, () => params[index++] || "");
26
+ return pattern.replace(/:([^/]+)/g, () => params[index++] || "");
17
27
  };
18
28
  /**
19
29
  * Extract values from a URL based on a pattern.
20
- * Ex: extractParams('/products/123', '/products/[id]') -> ['123']
21
30
  */
22
31
  const extractParams = (url, pattern) => {
23
- const regex = pathFormatToRegex(pattern);
32
+ const regex = patternToRegex(pattern);
24
33
  const match = url.match(regex);
25
34
  return match ? match.slice(1) : null;
26
35
  };
@@ -29,15 +38,15 @@ const extractParams = (url, pattern) => {
29
38
  * If locale is provided, only check for that locale. Otherwise, check for all locales.
30
39
  */
31
40
  const getCanonicalPath = (localizedPath, locale, rewriteRules) => {
32
- const rewrite = rewriteRules ?? _intlayer_config_built.default?.routing?.rewrite;
33
- if (!rewrite) return localizedPath;
34
- for (const [canonicalPattern, rules] of Object.entries(rewrite)) {
35
- const localesToCheck = locale ? [locale] : Object.keys(rules);
41
+ if (!rewriteRules) return localizedPath;
42
+ for (const rule of rewriteRules.rules) {
43
+ const { canonical, localized } = rule;
44
+ const localesToCheck = locale ? [locale] : Object.keys(localized);
36
45
  for (const loc of localesToCheck) {
37
- const localizedPattern = rules[loc];
46
+ const localizedPattern = localized[loc];
38
47
  if (!localizedPattern) continue;
39
48
  const params = extractParams(localizedPath, localizedPattern);
40
- if (params) return fillPath(canonicalPattern, params);
49
+ if (params) return fillPath(canonical, params);
41
50
  }
42
51
  }
43
52
  return localizedPath;
@@ -46,19 +55,49 @@ const getCanonicalPath = (localizedPath, locale, rewriteRules) => {
46
55
  * Given a canonical path (e.g., "/products/123"), finds the localized URL pattern (e.g., "/produits/123").
47
56
  */
48
57
  const getLocalizedPath = (canonicalPath, locale, rewriteRules) => {
49
- const rewrite = rewriteRules ?? _intlayer_config_built.default?.routing?.rewrite;
50
- if (!rewrite) return canonicalPath;
51
- for (const [canonicalPattern, rules] of Object.entries(rewrite)) {
52
- const params = extractParams(canonicalPath, canonicalPattern);
58
+ if (!rewriteRules) return {
59
+ path: canonicalPath,
60
+ isRewritten: false
61
+ };
62
+ for (const rule of rewriteRules.rules) {
63
+ const { canonical, localized } = rule;
64
+ const params = extractParams(canonicalPath, canonical);
53
65
  if (params) {
54
- const targetPattern = rules[locale];
55
- if (targetPattern) return fillPath(targetPattern, params);
66
+ const targetPattern = localized[locale];
67
+ if (targetPattern) return {
68
+ path: fillPath(targetPattern, params),
69
+ isRewritten: true
70
+ };
56
71
  }
57
72
  }
58
- return canonicalPath;
73
+ return {
74
+ path: canonicalPath,
75
+ isRewritten: false
76
+ };
77
+ };
78
+ /**
79
+ * Returns the internal path for a given canonical path and locale.
80
+ * Ensures the locale prefix is present exactly once.
81
+ */
82
+ const getInternalPath = (canonicalPath, locale) => {
83
+ const pathWithLeadingSlash = canonicalPath.startsWith("/") ? canonicalPath : `/${canonicalPath}`;
84
+ if (pathWithLeadingSlash.startsWith(`/${locale}/`) || pathWithLeadingSlash === `/${locale}`) return pathWithLeadingSlash;
85
+ return `/${locale}${pathWithLeadingSlash === "/" ? "" : pathWithLeadingSlash}`;
86
+ };
87
+ /**
88
+ * Given a current pathname and locale, returns the pretty localized path if a rewrite rule exists and the path is not already localized.
89
+ */
90
+ const getRewritePath = (pathname, locale, rewrite) => {
91
+ const rules = getRewriteRules(rewrite, "url");
92
+ if (!rules) return void 0;
93
+ const { path: localizedPath, isRewritten } = getLocalizedPath(getCanonicalPath(pathname, void 0, rules), locale, rules);
94
+ if (isRewritten && localizedPath !== pathname) return localizedPath;
59
95
  };
60
96
 
61
97
  //#endregion
62
98
  exports.getCanonicalPath = getCanonicalPath;
99
+ exports.getInternalPath = getInternalPath;
63
100
  exports.getLocalizedPath = getLocalizedPath;
101
+ exports.getRewritePath = getRewritePath;
102
+ exports.getRewriteRules = getRewriteRules;
64
103
  //# sourceMappingURL=rewriteUtils.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"rewriteUtils.cjs","names":["configuration"],"sources":["../../../src/localization/rewriteUtils.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport type { Locale, RoutingConfig } from '@intlayer/types';\n\n/**\n * Helper to convert Next.js dynamic path \"[param]\" to Regex \"([^/]+)\"\n */\nconst pathFormatToRegex = (path: string) =>\n new RegExp(`^${path.replace(/\\[([^\\]]+)\\]/g, '([^/]+)')}$`);\n\n/**\n * Replaces route parameters in a path with provided values.\n * Ex: fillPath('/products/[id]', ['123']) -> '/products/123'\n */\nconst fillPath = (path: string, params: string[]) => {\n let index = 0;\n return path.replace(/\\[([^\\]]+)\\]/g, () => params[index++] || '');\n};\n\n/**\n * Extract values from a URL based on a pattern.\n * Ex: extractParams('/products/123', '/products/[id]') -> ['123']\n */\nconst extractParams = (url: string, pattern: string): string[] | null => {\n const regex = pathFormatToRegex(pattern);\n const match = url.match(regex);\n return match ? match.slice(1) : null;\n};\n\n/**\n * Given a localized URL (e.g., \"/produits/123\"), finds the canonical internal path (e.g., \"/products/123\").\n * If locale is provided, only check for that locale. Otherwise, check for all locales.\n */\nexport const getCanonicalPath = (\n localizedPath: string,\n locale?: Locale,\n rewriteRules?: RoutingConfig['rewrite']\n): string => {\n const rewrite = rewriteRules ?? configuration?.routing?.rewrite;\n\n if (!rewrite) return localizedPath;\n\n for (const [canonicalPattern, rules] of Object.entries(rewrite)) {\n const localesToCheck = locale ? [locale] : Object.keys(rules);\n\n for (const loc of localesToCheck) {\n const localizedPattern = rules[loc as keyof typeof rules];\n\n if (!localizedPattern) continue;\n\n // Check if the current URL matches this localized pattern\n const params = extractParams(localizedPath, localizedPattern);\n\n if (params) {\n // Reconstruct the canonical URL using the extracted params\n return fillPath(canonicalPattern, params);\n }\n }\n }\n\n return localizedPath;\n};\n\n/**\n * Given a canonical path (e.g., \"/products/123\"), finds the localized URL pattern (e.g., \"/produits/123\").\n */\nexport const getLocalizedPath = (\n canonicalPath: string,\n locale: Locale,\n rewriteRules?: RoutingConfig['rewrite']\n): string => {\n const rewrite = rewriteRules ?? configuration?.routing?.rewrite;\n\n if (!rewrite) return canonicalPath;\n\n for (const [canonicalPattern, rules] of Object.entries(rewrite)) {\n // Check if the input path matches a configured canonical pattern\n const params = extractParams(canonicalPath, canonicalPattern);\n\n if (params) {\n const targetPattern = rules[locale as keyof typeof rules];\n if (targetPattern) {\n return fillPath(targetPattern, params);\n }\n }\n }\n\n return canonicalPath;\n};\n"],"mappings":";;;;;;;;AAMA,MAAM,qBAAqB,SACzB,IAAI,OAAO,IAAI,KAAK,QAAQ,iBAAiB,UAAU,CAAC,GAAG;;;;;AAM7D,MAAM,YAAY,MAAc,WAAqB;CACnD,IAAI,QAAQ;AACZ,QAAO,KAAK,QAAQ,uBAAuB,OAAO,YAAY,GAAG;;;;;;AAOnE,MAAM,iBAAiB,KAAa,YAAqC;CACvE,MAAM,QAAQ,kBAAkB,QAAQ;CACxC,MAAM,QAAQ,IAAI,MAAM,MAAM;AAC9B,QAAO,QAAQ,MAAM,MAAM,EAAE,GAAG;;;;;;AAOlC,MAAa,oBACX,eACA,QACA,iBACW;CACX,MAAM,UAAU,gBAAgBA,gCAAe,SAAS;AAExD,KAAI,CAAC,QAAS,QAAO;AAErB,MAAK,MAAM,CAAC,kBAAkB,UAAU,OAAO,QAAQ,QAAQ,EAAE;EAC/D,MAAM,iBAAiB,SAAS,CAAC,OAAO,GAAG,OAAO,KAAK,MAAM;AAE7D,OAAK,MAAM,OAAO,gBAAgB;GAChC,MAAM,mBAAmB,MAAM;AAE/B,OAAI,CAAC,iBAAkB;GAGvB,MAAM,SAAS,cAAc,eAAe,iBAAiB;AAE7D,OAAI,OAEF,QAAO,SAAS,kBAAkB,OAAO;;;AAK/C,QAAO;;;;;AAMT,MAAa,oBACX,eACA,QACA,iBACW;CACX,MAAM,UAAU,gBAAgBA,gCAAe,SAAS;AAExD,KAAI,CAAC,QAAS,QAAO;AAErB,MAAK,MAAM,CAAC,kBAAkB,UAAU,OAAO,QAAQ,QAAQ,EAAE;EAE/D,MAAM,SAAS,cAAc,eAAe,iBAAiB;AAE7D,MAAI,QAAQ;GACV,MAAM,gBAAgB,MAAM;AAC5B,OAAI,cACF,QAAO,SAAS,eAAe,OAAO;;;AAK5C,QAAO"}
1
+ {"version":3,"file":"rewriteUtils.cjs","names":[],"sources":["../../../src/localization/rewriteUtils.ts"],"sourcesContent":["import type {\n Locale,\n RewriteObject,\n RewriteRules,\n RoutingConfig,\n} from '@intlayer/types';\n\nexport type LocalizedPathResult = {\n path: string;\n isRewritten: boolean;\n};\n\n/**\n * Normalizes legacy Record format or extracts specialized rules from RewriteObject.\n */\nexport const getRewriteRules = (\n rewrite: RoutingConfig['rewrite'],\n context: keyof RewriteObject = 'url'\n): RewriteRules | undefined => {\n if (!rewrite) return undefined;\n\n if ('url' in rewrite) {\n return (rewrite as RewriteObject)[context];\n }\n\n // Normalize legacy format\n return {\n rules: Object.entries(rewrite).map(([canonical, localized]) => ({\n // Normalize canonical path\n canonical: canonical.startsWith('/')\n ? canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')\n : `/${canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')}`,\n\n // Normalize localized path\n localized: Object.fromEntries(\n Object.entries(localized).map(([locale, pattern]) => {\n const normalizedPattern = pattern?.startsWith('/')\n ? pattern.replace(/\\[([^\\]]+)\\]/g, ':$1')\n : `/${(pattern || '').replace(/\\[([^\\]]+)\\]/g, ':$1')}`;\n return [locale, normalizedPattern];\n })\n ),\n })),\n };\n};\n\n/**\n * Converts normalized pattern to Regex.\n * Internal syntax is strictly :param.\n */\nconst patternToRegex = (pattern: string) =>\n new RegExp(`^${pattern.replace(/:([^/]+)/g, '([^/]+)')}$`);\n\n/**\n * Replaces route parameters in a path with provided values.\n */\nconst fillPath = (pattern: string, params: string[]) => {\n let index = 0;\n return pattern.replace(/:([^/]+)/g, () => params[index++] || '');\n};\n\n/**\n * Extract values from a URL based on a pattern.\n */\nconst extractParams = (url: string, pattern: string): string[] | null => {\n const regex = patternToRegex(pattern);\n const match = url.match(regex);\n return match ? match.slice(1) : null;\n};\n\n/**\n * Given a localized URL (e.g., \"/produits/123\"), finds the canonical internal path (e.g., \"/products/123\").\n * If locale is provided, only check for that locale. Otherwise, check for all locales.\n */\nexport const getCanonicalPath = (\n localizedPath: string,\n locale?: Locale,\n rewriteRules?: RewriteRules\n): string => {\n if (!rewriteRules) return localizedPath;\n\n for (const rule of rewriteRules.rules) {\n const { canonical, localized } = rule;\n const localesToCheck = locale ? [locale] : Object.keys(localized);\n\n for (const loc of localesToCheck) {\n const localizedPattern = localized[loc as keyof typeof localized];\n\n if (!localizedPattern) continue;\n\n const params = extractParams(localizedPath, localizedPattern);\n\n if (params) {\n return fillPath(canonical, params);\n }\n }\n }\n\n return localizedPath;\n};\n\n/**\n * Given a canonical path (e.g., \"/products/123\"), finds the localized URL pattern (e.g., \"/produits/123\").\n */\nexport const getLocalizedPath = (\n canonicalPath: string,\n locale: Locale,\n rewriteRules?: RewriteRules\n): LocalizedPathResult => {\n if (!rewriteRules) return { path: canonicalPath, isRewritten: false };\n\n for (const rule of rewriteRules.rules) {\n const { canonical, localized } = rule;\n\n // Check if the input path matches a configured canonical pattern\n const params = extractParams(canonicalPath, canonical);\n\n if (params) {\n const targetPattern = localized[locale as keyof typeof localized];\n\n if (targetPattern) {\n return {\n path: fillPath(targetPattern, params),\n isRewritten: true,\n };\n }\n }\n }\n\n return { path: canonicalPath, isRewritten: false };\n};\n\n/**\n * Returns the internal path for a given canonical path and locale.\n * Ensures the locale prefix is present exactly once.\n */\nexport const getInternalPath = (\n canonicalPath: string,\n locale: Locale\n): string => {\n const pathWithLeadingSlash = canonicalPath.startsWith('/')\n ? canonicalPath\n : `/${canonicalPath}`;\n\n if (\n pathWithLeadingSlash.startsWith(`/${locale}/`) ||\n pathWithLeadingSlash === `/${locale}`\n ) {\n return pathWithLeadingSlash;\n }\n\n return `/${locale}${pathWithLeadingSlash === '/' ? '' : pathWithLeadingSlash}`;\n};\n\n/**\n * Given a current pathname and locale, returns the pretty localized path if a rewrite rule exists and the path is not already localized.\n */\nexport const getRewritePath = (\n pathname: string,\n locale: Locale,\n rewrite?: RoutingConfig['rewrite']\n): string | undefined => {\n const rules = getRewriteRules(rewrite, 'url');\n if (!rules) return undefined;\n\n // Identify canonical path (relative to root, no locale prefix expected in 'url' context)\n const canonicalPath = getCanonicalPath(pathname, undefined, rules);\n\n // Get the localized path for the current locale\n const { path: localizedPath, isRewritten } = getLocalizedPath(\n canonicalPath,\n locale,\n rules\n );\n\n if (isRewritten && localizedPath !== pathname) {\n return localizedPath;\n }\n\n return undefined;\n};\n"],"mappings":";;;;;AAeA,MAAa,mBACX,SACA,UAA+B,UACF;AAC7B,KAAI,CAAC,QAAS,QAAO;AAErB,KAAI,SAAS,QACX,QAAQ,QAA0B;AAIpC,QAAO,EACL,OAAO,OAAO,QAAQ,QAAQ,CAAC,KAAK,CAAC,WAAW,gBAAgB;EAE9D,WAAW,UAAU,WAAW,IAAI,GAChC,UAAU,QAAQ,iBAAiB,MAAM,GACzC,IAAI,UAAU,QAAQ,iBAAiB,MAAM;EAGjD,WAAW,OAAO,YAChB,OAAO,QAAQ,UAAU,CAAC,KAAK,CAAC,QAAQ,aAAa;AAInD,UAAO,CAAC,QAHkB,SAAS,WAAW,IAAI,GAC9C,QAAQ,QAAQ,iBAAiB,MAAM,GACvC,KAAK,WAAW,IAAI,QAAQ,iBAAiB,MAAM,GACrB;IAClC,CACH;EACF,EAAE,EACJ;;;;;;AAOH,MAAM,kBAAkB,YACtB,IAAI,OAAO,IAAI,QAAQ,QAAQ,aAAa,UAAU,CAAC,GAAG;;;;AAK5D,MAAM,YAAY,SAAiB,WAAqB;CACtD,IAAI,QAAQ;AACZ,QAAO,QAAQ,QAAQ,mBAAmB,OAAO,YAAY,GAAG;;;;;AAMlE,MAAM,iBAAiB,KAAa,YAAqC;CACvE,MAAM,QAAQ,eAAe,QAAQ;CACrC,MAAM,QAAQ,IAAI,MAAM,MAAM;AAC9B,QAAO,QAAQ,MAAM,MAAM,EAAE,GAAG;;;;;;AAOlC,MAAa,oBACX,eACA,QACA,iBACW;AACX,KAAI,CAAC,aAAc,QAAO;AAE1B,MAAK,MAAM,QAAQ,aAAa,OAAO;EACrC,MAAM,EAAE,WAAW,cAAc;EACjC,MAAM,iBAAiB,SAAS,CAAC,OAAO,GAAG,OAAO,KAAK,UAAU;AAEjE,OAAK,MAAM,OAAO,gBAAgB;GAChC,MAAM,mBAAmB,UAAU;AAEnC,OAAI,CAAC,iBAAkB;GAEvB,MAAM,SAAS,cAAc,eAAe,iBAAiB;AAE7D,OAAI,OACF,QAAO,SAAS,WAAW,OAAO;;;AAKxC,QAAO;;;;;AAMT,MAAa,oBACX,eACA,QACA,iBACwB;AACxB,KAAI,CAAC,aAAc,QAAO;EAAE,MAAM;EAAe,aAAa;EAAO;AAErE,MAAK,MAAM,QAAQ,aAAa,OAAO;EACrC,MAAM,EAAE,WAAW,cAAc;EAGjC,MAAM,SAAS,cAAc,eAAe,UAAU;AAEtD,MAAI,QAAQ;GACV,MAAM,gBAAgB,UAAU;AAEhC,OAAI,cACF,QAAO;IACL,MAAM,SAAS,eAAe,OAAO;IACrC,aAAa;IACd;;;AAKP,QAAO;EAAE,MAAM;EAAe,aAAa;EAAO;;;;;;AAOpD,MAAa,mBACX,eACA,WACW;CACX,MAAM,uBAAuB,cAAc,WAAW,IAAI,GACtD,gBACA,IAAI;AAER,KACE,qBAAqB,WAAW,IAAI,OAAO,GAAG,IAC9C,yBAAyB,IAAI,SAE7B,QAAO;AAGT,QAAO,IAAI,SAAS,yBAAyB,MAAM,KAAK;;;;;AAM1D,MAAa,kBACX,UACA,QACA,YACuB;CACvB,MAAM,QAAQ,gBAAgB,SAAS,MAAM;AAC7C,KAAI,CAAC,MAAO,QAAO;CAMnB,MAAM,EAAE,MAAM,eAAe,gBAAgB,iBAHvB,iBAAiB,UAAU,QAAW,MAAM,EAKhE,QACA,MACD;AAED,KAAI,eAAe,kBAAkB,SACnC,QAAO"}
@@ -15,12 +15,14 @@ const IMAGE_R = /^!\[(.*?)\]\( *((?:\([^)]*\)|[^() ])*) *"?([^)"]*)?"?\)/;
15
15
  const LINK_R = new RegExp(`^\\[((?:\\[[^\\[\\]]*(?:\\[[^\\[\\]]*\\][^\\[\\]]*)*\\]|[^\\[\\]])*)\\]\\(\\s*<?((?:\\([^)]*\\)|[^\\s\\\\]|\\\\.)*?)>?(?:\\s+['"]([\\s\\S]*?)['"])?\\s*\\)`);
16
16
  const getTag = (tag, components) => {
17
17
  if (typeof tag !== "string") return tag;
18
- const override = require_markdown_utils.get(components, tag);
18
+ let override = require_markdown_utils.get(components, tag);
19
+ if (!override && typeof tag === "string") {
20
+ const lowercaseTag = tag.toLowerCase();
21
+ const key = Object.keys(components).find((k) => k.toLowerCase() === lowercaseTag);
22
+ if (key) override = require_markdown_utils.get(components, key);
23
+ }
19
24
  if (!override) return tag;
20
- if (typeof override === "function") return override;
21
- if (typeof override === "object" && !("component" in override) && !("props" in override)) return override;
22
- if (typeof override === "object" && "component" in override) return override.component ?? tag;
23
- return tag;
25
+ return override;
24
26
  };
25
27
  const createElementFactory = (ctx, options) => {
26
28
  const { runtime, components = {} } = ctx;
@@ -38,17 +40,11 @@ const createElementFactory = (ctx, options) => {
38
40
  return (tag, props, ...children) => {
39
41
  if (typeof tag === "string" && filteredTags.includes(tag.toLowerCase())) return null;
40
42
  const isStringTag = typeof tag === "string";
41
- let overrideProps = {};
42
- if (isStringTag) overrideProps = require_markdown_utils.get(components, `${tag}.props`, {}) ?? {};
43
- const className = require_markdown_utils.cx(props?.className, props?.class, overrideProps?.className, overrideProps?.class);
44
- const initialMergedProps = {
45
- ...props,
46
- ...overrideProps
47
- };
43
+ const className = require_markdown_utils.cx(props?.className, props?.class);
48
44
  const mergedProps = {};
49
45
  let classNameHandled = false;
50
- for (const key in initialMergedProps) {
51
- const value = initialMergedProps[key];
46
+ if (props) for (const key in props) {
47
+ const value = props[key];
52
48
  if (value === void 0 || value === null) continue;
53
49
  if (key === "className" || key === "class") {
54
50
  if (!classNameHandled) {
@@ -99,7 +95,6 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
99
95
  }),
100
96
  _order: require_markdown_constants.Priority.HIGH,
101
97
  _parse(capture, parse, state) {
102
- performance.now();
103
98
  const bullet = capture[2];
104
99
  const startValue = ordered ? +bullet.slice(0, -1) : void 0;
105
100
  const items = capture[0].replace(require_markdown_constants.BLOCK_END_R, "\n").match(LIST_ITEM_R);
@@ -359,15 +354,15 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
359
354
  const whitespace = capture[3].match(require_markdown_constants.HTML_LEFT_TRIM_AMOUNT_R)?.[1] ?? "";
360
355
  const trimmed = require_markdown_utils.trimLeadingWhitespaceOutsideFences(capture[3], whitespace);
361
356
  const parseFunc = containsBlockSyntax(trimmed) ? require_markdown_utils.parseBlock : require_markdown_utils.parseInline;
362
- const tagName = capture[1].toLowerCase();
363
- const noInnerParse = require_markdown_constants.DO_NOT_PROCESS_HTML_ELEMENTS.indexOf(tagName) !== -1;
364
- const tag = (noInnerParse ? tagName : capture[1]).trim();
357
+ const tagName = capture[1].trim();
358
+ const noInnerParse = require_markdown_constants.DO_NOT_PROCESS_HTML_ELEMENTS.indexOf(tagName.toLowerCase()) !== -1;
359
+ const tag = noInnerParse ? tagName.toLowerCase() : tagName;
365
360
  const ast = {
366
361
  attrs: attrStringToMap(tag, capture[2] ?? ""),
367
362
  noInnerParse,
368
363
  tag
369
364
  };
370
- state.inAnchor = state.inAnchor || tagName === "a";
365
+ state.inAnchor = state.inAnchor || tagName.toLowerCase() === "a";
371
366
  if (noInnerParse) ast.text = capture[3];
372
367
  else {
373
368
  const prevInHTML = state.inHTML;
@@ -415,7 +410,7 @@ const createRules = (createElement, ctx, options, footnotes, refs, attrStringToM
415
410
  },
416
411
  [require_markdown_constants.RuleType.customComponent]: {
417
412
  _qualify: (source) => /^ *<([A-Z][a-zA-Z0-9]*)/.test(source),
418
- _match: require_markdown_utils.blockRegex(require_markdown_constants.CUSTOM_COMPONENT_R),
413
+ _match: require_markdown_utils.anyScopeRegex(require_markdown_constants.CUSTOM_COMPONENT_R),
419
414
  _order: require_markdown_constants.Priority.MAX,
420
415
  _parse(capture, parse, state) {
421
416
  const whitespace = capture[3].match(require_markdown_constants.HTML_LEFT_TRIM_AMOUNT_R)?.[1] ?? "";
@@ -745,7 +740,8 @@ const compile = (markdown = "", ctx, options = {}) => {
745
740
  require_markdown_constants.HEADING_SETEXT_R,
746
741
  require_markdown_constants.NP_TABLE_R,
747
742
  require_markdown_constants.ORDERED_LIST_R,
748
- require_markdown_constants.UNORDERED_LIST_R
743
+ require_markdown_constants.UNORDERED_LIST_R,
744
+ require_markdown_constants.CUSTOM_COMPONENT_R
749
745
  ];
750
746
  const containsBlockSyntax = (input) => {
751
747
  const cleaned = input.replace(require_markdown_constants.TRIM_STARTING_NEWLINES, "");