@intlayer/core 8.1.2 → 8.1.3
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.
- package/dist/cjs/_virtual/_rolldown/runtime.cjs +1 -29
- package/dist/cjs/deepTransformPlugins/getFilterMissingTranslationsContent.cjs +1 -212
- package/dist/cjs/deepTransformPlugins/getFilterMissingTranslationsContent.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/getFilterTranslationsOnlyContent.cjs +1 -94
- package/dist/cjs/deepTransformPlugins/getFilterTranslationsOnlyContent.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/getFilteredLocalesContent.cjs +1 -45
- package/dist/cjs/deepTransformPlugins/getFilteredLocalesContent.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/getLocalizedContent.cjs +1 -33
- package/dist/cjs/deepTransformPlugins/getLocalizedContent.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/getMaskContent.cjs +1 -27
- package/dist/cjs/deepTransformPlugins/getMaskContent.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/getMissingLocalesContent.cjs +1 -82
- package/dist/cjs/deepTransformPlugins/getMissingLocalesContent.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/getMultilingualDictionary.cjs +1 -87
- package/dist/cjs/deepTransformPlugins/getMultilingualDictionary.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/getReplacedValuesContent.cjs +1 -60
- package/dist/cjs/deepTransformPlugins/getReplacedValuesContent.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/getSplittedContent.cjs +1 -122
- package/dist/cjs/deepTransformPlugins/getSplittedContent.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/index.cjs +1 -32
- package/dist/cjs/deepTransformPlugins/insertContentInDictionary.cjs +1 -106
- package/dist/cjs/deepTransformPlugins/insertContentInDictionary.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/editDictionaryByKeyPath.cjs +1 -64
- package/dist/cjs/dictionaryManipulator/editDictionaryByKeyPath.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/getContentNodeByKeyPath.cjs +1 -18
- package/dist/cjs/dictionaryManipulator/getContentNodeByKeyPath.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/getDefaultNode.cjs +1 -55
- package/dist/cjs/dictionaryManipulator/getDefaultNode.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/getEmptyNode.cjs +1 -26
- package/dist/cjs/dictionaryManipulator/getEmptyNode.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/getNodeChildren.cjs +1 -23
- package/dist/cjs/dictionaryManipulator/getNodeChildren.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/getNodeType.cjs +1 -36
- package/dist/cjs/dictionaryManipulator/getNodeType.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/index.cjs +1 -27
- package/dist/cjs/dictionaryManipulator/mergeDictionaries.cjs +1 -69
- package/dist/cjs/dictionaryManipulator/mergeDictionaries.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/normalizeDictionary.cjs +1 -30
- package/dist/cjs/dictionaryManipulator/normalizeDictionary.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/orderDictionaries.cjs +1 -48
- package/dist/cjs/dictionaryManipulator/orderDictionaries.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/removeContentNodeByKeyPath.cjs +1 -31
- package/dist/cjs/dictionaryManipulator/removeContentNodeByKeyPath.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/renameContentNodeByKeyPath.cjs +1 -39
- package/dist/cjs/dictionaryManipulator/renameContentNodeByKeyPath.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/updateNodeChildren.cjs +1 -38
- package/dist/cjs/dictionaryManipulator/updateNodeChildren.cjs.map +1 -1
- package/dist/cjs/formatters/compact.cjs +1 -25
- package/dist/cjs/formatters/compact.cjs.map +1 -1
- package/dist/cjs/formatters/currency.cjs +1 -29
- package/dist/cjs/formatters/currency.cjs.map +1 -1
- package/dist/cjs/formatters/date.cjs +1 -60
- package/dist/cjs/formatters/date.cjs.map +1 -1
- package/dist/cjs/formatters/index.cjs +1 -18
- package/dist/cjs/formatters/list.cjs +1 -30
- package/dist/cjs/formatters/list.cjs.map +1 -1
- package/dist/cjs/formatters/number.cjs +1 -18
- package/dist/cjs/formatters/number.cjs.map +1 -1
- package/dist/cjs/formatters/percentage.cjs +1 -25
- package/dist/cjs/formatters/percentage.cjs.map +1 -1
- package/dist/cjs/formatters/relativeTime.cjs +1 -33
- package/dist/cjs/formatters/relativeTime.cjs.map +1 -1
- package/dist/cjs/formatters/units.cjs +1 -23
- package/dist/cjs/formatters/units.cjs.map +1 -1
- package/dist/cjs/getStorageAttributes.cjs +1 -134
- package/dist/cjs/getStorageAttributes.cjs.map +1 -1
- package/dist/cjs/index.cjs +1 -300
- package/dist/cjs/interpreter/getCondition.cjs +1 -27
- package/dist/cjs/interpreter/getCondition.cjs.map +1 -1
- package/dist/cjs/interpreter/getContent/deepTransform.cjs +1 -41
- package/dist/cjs/interpreter/getContent/deepTransform.cjs.map +1 -1
- package/dist/cjs/interpreter/getContent/getContent.cjs +1 -34
- package/dist/cjs/interpreter/getContent/getContent.cjs.map +1 -1
- package/dist/cjs/interpreter/getContent/index.cjs +1 -14
- package/dist/cjs/interpreter/getContent/plugins.cjs +1 -161
- package/dist/cjs/interpreter/getContent/plugins.cjs.map +1 -1
- package/dist/cjs/interpreter/getDictionary.cjs +1 -24
- package/dist/cjs/interpreter/getDictionary.cjs.map +1 -1
- package/dist/cjs/interpreter/getEnumeration.cjs +1 -72
- package/dist/cjs/interpreter/getEnumeration.cjs.map +1 -1
- package/dist/cjs/interpreter/getGender.cjs +1 -38
- package/dist/cjs/interpreter/getGender.cjs.map +1 -1
- package/dist/cjs/interpreter/getHTML.cjs +1 -121
- package/dist/cjs/interpreter/getHTML.cjs.map +1 -1
- package/dist/cjs/interpreter/getInsertion.cjs +1 -22
- package/dist/cjs/interpreter/getInsertion.cjs.map +1 -1
- package/dist/cjs/interpreter/getIntlayer.cjs +1 -40
- package/dist/cjs/interpreter/getIntlayer.cjs.map +1 -1
- package/dist/cjs/interpreter/getNesting.cjs +1 -36
- package/dist/cjs/interpreter/getNesting.cjs.map +1 -1
- package/dist/cjs/interpreter/getTranslation.cjs +1 -112
- package/dist/cjs/interpreter/getTranslation.cjs.map +1 -1
- package/dist/cjs/interpreter/index.cjs +1 -31
- package/dist/cjs/interpreter/splitAndJoinInsertion.cjs +1 -55
- package/dist/cjs/interpreter/splitAndJoinInsertion.cjs.map +1 -1
- package/dist/cjs/localization/getBrowserLocale.cjs +1 -143
- package/dist/cjs/localization/getBrowserLocale.cjs.map +1 -1
- package/dist/cjs/localization/getHTMLTextDir.cjs +1 -64
- package/dist/cjs/localization/getHTMLTextDir.cjs.map +1 -1
- package/dist/cjs/localization/getLocale.cjs +1 -27
- package/dist/cjs/localization/getLocale.cjs.map +1 -1
- package/dist/cjs/localization/getLocaleFromPath.cjs +1 -45
- package/dist/cjs/localization/getLocaleFromPath.cjs.map +1 -1
- package/dist/cjs/localization/getLocaleLang.cjs +1 -20
- package/dist/cjs/localization/getLocaleLang.cjs.map +1 -1
- package/dist/cjs/localization/getLocaleName.cjs +1 -10
- package/dist/cjs/localization/getLocaleName.cjs.map +1 -1
- package/dist/cjs/localization/getLocalizedUrl.cjs +1 -82
- package/dist/cjs/localization/getLocalizedUrl.cjs.map +1 -1
- package/dist/cjs/localization/getMultilingualUrls.cjs +1 -63
- package/dist/cjs/localization/getMultilingualUrls.cjs.map +1 -1
- package/dist/cjs/localization/getPathWithoutLocale.cjs +1 -55
- package/dist/cjs/localization/getPathWithoutLocale.cjs.map +1 -1
- package/dist/cjs/localization/getPrefix.cjs +1 -63
- package/dist/cjs/localization/getPrefix.cjs.map +1 -1
- package/dist/cjs/localization/index.cjs +1 -39
- package/dist/cjs/localization/localeDetector.cjs +1 -133
- package/dist/cjs/localization/localeDetector.cjs.map +1 -1
- package/dist/cjs/localization/localeMapper.cjs +1 -119
- package/dist/cjs/localization/localeMapper.cjs.map +1 -1
- package/dist/cjs/localization/localeResolver.cjs +1 -28
- package/dist/cjs/localization/localeResolver.cjs.map +1 -1
- package/dist/cjs/localization/rewriteUtils.cjs +1 -110
- package/dist/cjs/localization/rewriteUtils.cjs.map +1 -1
- package/dist/cjs/localization/validatePrefix.cjs +1 -54
- package/dist/cjs/localization/validatePrefix.cjs.map +1 -1
- package/dist/cjs/markdown/compiler.cjs +10 -810
- package/dist/cjs/markdown/compiler.cjs.map +1 -1
- package/dist/cjs/markdown/constants.cjs +1 -328
- package/dist/cjs/markdown/constants.cjs.map +1 -1
- package/dist/cjs/markdown/index.cjs +1 -120
- package/dist/cjs/markdown/parser.cjs +1 -66
- package/dist/cjs/markdown/parser.cjs.map +1 -1
- package/dist/cjs/markdown/renderer.cjs +1 -61
- package/dist/cjs/markdown/renderer.cjs.map +1 -1
- package/dist/cjs/markdown/utils.cjs +6 -391
- package/dist/cjs/markdown/utils.cjs.map +1 -1
- package/dist/cjs/messageFormat/ICU.cjs +1 -319
- package/dist/cjs/messageFormat/ICU.cjs.map +1 -1
- package/dist/cjs/messageFormat/i18next.cjs +1 -330
- package/dist/cjs/messageFormat/i18next.cjs.map +1 -1
- package/dist/cjs/messageFormat/index.cjs +1 -11
- package/dist/cjs/messageFormat/verify-icu-format.cjs +2 -64
- package/dist/cjs/messageFormat/verify-icu-format.cjs.map +1 -1
- package/dist/cjs/messageFormat/vue-i18n.cjs +1 -166
- package/dist/cjs/messageFormat/vue-i18n.cjs.map +1 -1
- package/dist/cjs/transpiler/condition/condition.cjs +1 -26
- package/dist/cjs/transpiler/condition/condition.cjs.map +1 -1
- package/dist/cjs/transpiler/condition/index.cjs +1 -4
- package/dist/cjs/transpiler/enumeration/enumeration.cjs +1 -28
- package/dist/cjs/transpiler/enumeration/enumeration.cjs.map +1 -1
- package/dist/cjs/transpiler/enumeration/index.cjs +1 -4
- package/dist/cjs/transpiler/file/file.cjs +1 -52
- package/dist/cjs/transpiler/file/file.cjs.map +1 -1
- package/dist/cjs/transpiler/file/fileBrowser.cjs +1 -25
- package/dist/cjs/transpiler/file/fileBrowser.cjs.map +1 -1
- package/dist/cjs/transpiler/file/index.cjs +1 -5
- package/dist/cjs/transpiler/gender/gender.cjs +1 -26
- package/dist/cjs/transpiler/gender/gender.cjs.map +1 -1
- package/dist/cjs/transpiler/gender/index.cjs +1 -4
- package/dist/cjs/transpiler/html/getHTMLCustomComponents.cjs +1 -44
- package/dist/cjs/transpiler/html/getHTMLCustomComponents.cjs.map +1 -1
- package/dist/cjs/transpiler/html/html.cjs +1 -37
- package/dist/cjs/transpiler/html/html.cjs.map +1 -1
- package/dist/cjs/transpiler/html/htmlTags.cjs +1 -116
- package/dist/cjs/transpiler/html/htmlTags.cjs.map +1 -1
- package/dist/cjs/transpiler/html/index.cjs +1 -6
- package/dist/cjs/transpiler/index.cjs +1 -24
- package/dist/cjs/transpiler/insertion/getInsertionValues.cjs +1 -11
- package/dist/cjs/transpiler/insertion/getInsertionValues.cjs.map +1 -1
- package/dist/cjs/transpiler/insertion/index.cjs +1 -6
- package/dist/cjs/transpiler/insertion/insertion.cjs +1 -36
- package/dist/cjs/transpiler/insertion/insertion.cjs.map +1 -1
- package/dist/cjs/transpiler/markdown/getMarkdownMetadata.cjs +2 -23
- package/dist/cjs/transpiler/markdown/getMarkdownMetadata.cjs.map +1 -1
- package/dist/cjs/transpiler/markdown/index.cjs +1 -6
- package/dist/cjs/transpiler/markdown/markdown.cjs +1 -54
- package/dist/cjs/transpiler/markdown/markdown.cjs.map +1 -1
- package/dist/cjs/transpiler/nesting/index.cjs +1 -4
- package/dist/cjs/transpiler/nesting/nesting.cjs +1 -27
- package/dist/cjs/transpiler/nesting/nesting.cjs.map +1 -1
- package/dist/cjs/transpiler/translation/index.cjs +1 -4
- package/dist/cjs/transpiler/translation/translation.cjs +1 -29
- package/dist/cjs/transpiler/translation/translation.cjs.map +1 -1
- package/dist/cjs/utils/checkIsURLAbsolute.cjs +1 -7
- package/dist/cjs/utils/checkIsURLAbsolute.cjs.map +1 -1
- package/dist/cjs/utils/getCookie.cjs +1 -32
- package/dist/cjs/utils/getCookie.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +1 -0
- package/dist/cjs/utils/intl.cjs +1 -91
- package/dist/cjs/utils/intl.cjs.map +1 -1
- package/dist/cjs/utils/isSameKeyPath.cjs +1 -7
- package/dist/cjs/utils/isSameKeyPath.cjs.map +1 -1
- package/dist/cjs/utils/isValidReactElement.cjs +1 -14
- package/dist/cjs/utils/isValidReactElement.cjs.map +1 -1
- package/dist/cjs/utils/localeStorage.cjs +1 -140
- package/dist/cjs/utils/localeStorage.cjs.map +1 -1
- package/dist/cjs/utils/parseYaml.cjs +16 -322
- package/dist/cjs/utils/parseYaml.cjs.map +1 -1
- package/dist/esm/deepTransformPlugins/getFilterMissingTranslationsContent.mjs +1 -207
- package/dist/esm/deepTransformPlugins/getFilterMissingTranslationsContent.mjs.map +1 -1
- package/dist/esm/deepTransformPlugins/getFilterTranslationsOnlyContent.mjs +1 -89
- package/dist/esm/deepTransformPlugins/getFilterTranslationsOnlyContent.mjs.map +1 -1
- package/dist/esm/deepTransformPlugins/getFilteredLocalesContent.mjs +1 -42
- package/dist/esm/deepTransformPlugins/getFilteredLocalesContent.mjs.map +1 -1
- package/dist/esm/deepTransformPlugins/getLocalizedContent.mjs +1 -31
- package/dist/esm/deepTransformPlugins/getLocalizedContent.mjs.map +1 -1
- package/dist/esm/deepTransformPlugins/getMaskContent.mjs +1 -25
- package/dist/esm/deepTransformPlugins/getMaskContent.mjs.map +1 -1
- package/dist/esm/deepTransformPlugins/getMissingLocalesContent.mjs +1 -77
- package/dist/esm/deepTransformPlugins/getMissingLocalesContent.mjs.map +1 -1
- package/dist/esm/deepTransformPlugins/getMultilingualDictionary.mjs +1 -86
- package/dist/esm/deepTransformPlugins/getMultilingualDictionary.mjs.map +1 -1
- package/dist/esm/deepTransformPlugins/getReplacedValuesContent.mjs +1 -59
- package/dist/esm/deepTransformPlugins/getReplacedValuesContent.mjs.map +1 -1
- package/dist/esm/deepTransformPlugins/getSplittedContent.mjs +1 -119
- package/dist/esm/deepTransformPlugins/getSplittedContent.mjs.map +1 -1
- package/dist/esm/deepTransformPlugins/index.mjs +1 -12
- package/dist/esm/deepTransformPlugins/insertContentInDictionary.mjs +1 -104
- package/dist/esm/deepTransformPlugins/insertContentInDictionary.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/editDictionaryByKeyPath.mjs +1 -62
- package/dist/esm/dictionaryManipulator/editDictionaryByKeyPath.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/getContentNodeByKeyPath.mjs +1 -16
- package/dist/esm/dictionaryManipulator/getContentNodeByKeyPath.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/getDefaultNode.mjs +1 -53
- package/dist/esm/dictionaryManipulator/getDefaultNode.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/getEmptyNode.mjs +1 -24
- package/dist/esm/dictionaryManipulator/getEmptyNode.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/getNodeChildren.mjs +1 -21
- package/dist/esm/dictionaryManipulator/getNodeChildren.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/getNodeType.mjs +1 -34
- package/dist/esm/dictionaryManipulator/getNodeType.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/index.mjs +1 -14
- package/dist/esm/dictionaryManipulator/mergeDictionaries.mjs +1 -66
- package/dist/esm/dictionaryManipulator/mergeDictionaries.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/normalizeDictionary.mjs +1 -28
- package/dist/esm/dictionaryManipulator/normalizeDictionary.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/orderDictionaries.mjs +1 -45
- package/dist/esm/dictionaryManipulator/orderDictionaries.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/removeContentNodeByKeyPath.mjs +1 -29
- package/dist/esm/dictionaryManipulator/removeContentNodeByKeyPath.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/renameContentNodeByKeyPath.mjs +1 -37
- package/dist/esm/dictionaryManipulator/renameContentNodeByKeyPath.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/updateNodeChildren.mjs +1 -36
- package/dist/esm/dictionaryManipulator/updateNodeChildren.mjs.map +1 -1
- package/dist/esm/formatters/compact.mjs +1 -22
- package/dist/esm/formatters/compact.mjs.map +1 -1
- package/dist/esm/formatters/currency.mjs +1 -26
- package/dist/esm/formatters/currency.mjs.map +1 -1
- package/dist/esm/formatters/date.mjs +1 -57
- package/dist/esm/formatters/date.mjs.map +1 -1
- package/dist/esm/formatters/index.mjs +1 -10
- package/dist/esm/formatters/list.mjs +1 -27
- package/dist/esm/formatters/list.mjs.map +1 -1
- package/dist/esm/formatters/number.mjs +1 -15
- package/dist/esm/formatters/number.mjs.map +1 -1
- package/dist/esm/formatters/percentage.mjs +1 -22
- package/dist/esm/formatters/percentage.mjs.map +1 -1
- package/dist/esm/formatters/relativeTime.mjs +1 -30
- package/dist/esm/formatters/relativeTime.mjs.map +1 -1
- package/dist/esm/formatters/units.mjs +1 -20
- package/dist/esm/formatters/units.mjs.map +1 -1
- package/dist/esm/getStorageAttributes.mjs +1 -132
- package/dist/esm/getStorageAttributes.mjs.map +1 -1
- package/dist/esm/index.mjs +1 -82
- package/dist/esm/interpreter/getCondition.mjs +1 -25
- package/dist/esm/interpreter/getCondition.mjs.map +1 -1
- package/dist/esm/interpreter/getContent/deepTransform.mjs +1 -39
- package/dist/esm/interpreter/getContent/deepTransform.mjs.map +1 -1
- package/dist/esm/interpreter/getContent/getContent.mjs +1 -31
- package/dist/esm/interpreter/getContent/getContent.mjs.map +1 -1
- package/dist/esm/interpreter/getContent/index.mjs +1 -5
- package/dist/esm/interpreter/getContent/plugins.mjs +1 -153
- package/dist/esm/interpreter/getContent/plugins.mjs.map +1 -1
- package/dist/esm/interpreter/getDictionary.mjs +1 -23
- package/dist/esm/interpreter/getDictionary.mjs.map +1 -1
- package/dist/esm/interpreter/getEnumeration.mjs +1 -69
- package/dist/esm/interpreter/getEnumeration.mjs.map +1 -1
- package/dist/esm/interpreter/getGender.mjs +1 -36
- package/dist/esm/interpreter/getGender.mjs.map +1 -1
- package/dist/esm/interpreter/getHTML.mjs +1 -119
- package/dist/esm/interpreter/getHTML.mjs.map +1 -1
- package/dist/esm/interpreter/getInsertion.mjs +1 -20
- package/dist/esm/interpreter/getInsertion.mjs.map +1 -1
- package/dist/esm/interpreter/getIntlayer.mjs +1 -36
- package/dist/esm/interpreter/getIntlayer.mjs.map +1 -1
- package/dist/esm/interpreter/getNesting.mjs +1 -35
- package/dist/esm/interpreter/getNesting.mjs.map +1 -1
- package/dist/esm/interpreter/getTranslation.mjs +1 -110
- package/dist/esm/interpreter/getTranslation.mjs.map +1 -1
- package/dist/esm/interpreter/index.mjs +1 -13
- package/dist/esm/interpreter/splitAndJoinInsertion.mjs +1 -53
- package/dist/esm/interpreter/splitAndJoinInsertion.mjs.map +1 -1
- package/dist/esm/localization/getBrowserLocale.mjs +1 -138
- package/dist/esm/localization/getBrowserLocale.mjs.map +1 -1
- package/dist/esm/localization/getHTMLTextDir.mjs +1 -62
- package/dist/esm/localization/getHTMLTextDir.mjs.map +1 -1
- package/dist/esm/localization/getLocale.mjs +1 -24
- package/dist/esm/localization/getLocale.mjs.map +1 -1
- package/dist/esm/localization/getLocaleFromPath.mjs +1 -42
- package/dist/esm/localization/getLocaleFromPath.mjs.map +1 -1
- package/dist/esm/localization/getLocaleLang.mjs +1 -18
- package/dist/esm/localization/getLocaleLang.mjs.map +1 -1
- package/dist/esm/localization/getLocaleName.mjs +1 -9
- package/dist/esm/localization/getLocaleName.mjs.map +1 -1
- package/dist/esm/localization/getLocalizedUrl.mjs +1 -79
- package/dist/esm/localization/getLocalizedUrl.mjs.map +1 -1
- package/dist/esm/localization/getMultilingualUrls.mjs +1 -60
- package/dist/esm/localization/getMultilingualUrls.mjs.map +1 -1
- package/dist/esm/localization/getPathWithoutLocale.mjs +1 -52
- package/dist/esm/localization/getPathWithoutLocale.mjs.map +1 -1
- package/dist/esm/localization/getPrefix.mjs +1 -60
- package/dist/esm/localization/getPrefix.mjs.map +1 -1
- package/dist/esm/localization/index.mjs +1 -17
- package/dist/esm/localization/localeDetector.mjs +1 -131
- package/dist/esm/localization/localeDetector.mjs.map +1 -1
- package/dist/esm/localization/localeMapper.mjs +1 -114
- package/dist/esm/localization/localeMapper.mjs.map +1 -1
- package/dist/esm/localization/localeResolver.mjs +1 -25
- package/dist/esm/localization/localeResolver.mjs.map +1 -1
- package/dist/esm/localization/rewriteUtils.mjs +1 -104
- package/dist/esm/localization/rewriteUtils.mjs.map +1 -1
- package/dist/esm/localization/validatePrefix.mjs +1 -51
- package/dist/esm/localization/validatePrefix.mjs.map +1 -1
- package/dist/esm/markdown/compiler.mjs +10 -786
- package/dist/esm/markdown/compiler.mjs.map +1 -1
- package/dist/esm/markdown/constants.mjs +1 -247
- package/dist/esm/markdown/constants.mjs.map +1 -1
- package/dist/esm/markdown/index.mjs +1 -7
- package/dist/esm/markdown/parser.mjs +1 -65
- package/dist/esm/markdown/parser.mjs.map +1 -1
- package/dist/esm/markdown/renderer.mjs +1 -59
- package/dist/esm/markdown/renderer.mjs.map +1 -1
- package/dist/esm/markdown/utils.mjs +6 -361
- package/dist/esm/markdown/utils.mjs.map +1 -1
- package/dist/esm/messageFormat/ICU.mjs +1 -316
- package/dist/esm/messageFormat/ICU.mjs.map +1 -1
- package/dist/esm/messageFormat/i18next.mjs +1 -327
- package/dist/esm/messageFormat/i18next.mjs.map +1 -1
- package/dist/esm/messageFormat/index.mjs +1 -5
- package/dist/esm/messageFormat/verify-icu-format.mjs +2 -64
- package/dist/esm/messageFormat/verify-icu-format.mjs.map +1 -1
- package/dist/esm/messageFormat/vue-i18n.mjs +1 -163
- package/dist/esm/messageFormat/vue-i18n.mjs.map +1 -1
- package/dist/esm/transpiler/condition/condition.mjs +1 -24
- package/dist/esm/transpiler/condition/condition.mjs.map +1 -1
- package/dist/esm/transpiler/condition/index.mjs +1 -3
- package/dist/esm/transpiler/enumeration/enumeration.mjs +1 -26
- package/dist/esm/transpiler/enumeration/enumeration.mjs.map +1 -1
- package/dist/esm/transpiler/enumeration/index.mjs +1 -3
- package/dist/esm/transpiler/file/file.mjs +1 -49
- package/dist/esm/transpiler/file/file.mjs.map +1 -1
- package/dist/esm/transpiler/file/fileBrowser.mjs +1 -24
- package/dist/esm/transpiler/file/fileBrowser.mjs.map +1 -1
- package/dist/esm/transpiler/file/index.mjs +1 -3
- package/dist/esm/transpiler/gender/gender.mjs +1 -24
- package/dist/esm/transpiler/gender/gender.mjs.map +1 -1
- package/dist/esm/transpiler/gender/index.mjs +1 -3
- package/dist/esm/transpiler/html/getHTMLCustomComponents.mjs +1 -43
- package/dist/esm/transpiler/html/getHTMLCustomComponents.mjs.map +1 -1
- package/dist/esm/transpiler/html/html.mjs +1 -35
- package/dist/esm/transpiler/html/html.mjs.map +1 -1
- package/dist/esm/transpiler/html/htmlTags.mjs +1 -114
- package/dist/esm/transpiler/html/htmlTags.mjs.map +1 -1
- package/dist/esm/transpiler/html/index.mjs +1 -4
- package/dist/esm/transpiler/index.mjs +1 -13
- package/dist/esm/transpiler/insertion/getInsertionValues.mjs +1 -9
- package/dist/esm/transpiler/insertion/getInsertionValues.mjs.map +1 -1
- package/dist/esm/transpiler/insertion/index.mjs +1 -4
- package/dist/esm/transpiler/insertion/insertion.mjs +1 -34
- package/dist/esm/transpiler/insertion/insertion.mjs.map +1 -1
- package/dist/esm/transpiler/markdown/getMarkdownMetadata.mjs +2 -22
- package/dist/esm/transpiler/markdown/getMarkdownMetadata.mjs.map +1 -1
- package/dist/esm/transpiler/markdown/index.mjs +1 -4
- package/dist/esm/transpiler/markdown/markdown.mjs +1 -52
- package/dist/esm/transpiler/markdown/markdown.mjs.map +1 -1
- package/dist/esm/transpiler/nesting/index.mjs +1 -3
- package/dist/esm/transpiler/nesting/nesting.mjs +1 -25
- package/dist/esm/transpiler/nesting/nesting.mjs.map +1 -1
- package/dist/esm/transpiler/translation/index.mjs +1 -3
- package/dist/esm/transpiler/translation/translation.mjs +1 -27
- package/dist/esm/transpiler/translation/translation.mjs.map +1 -1
- package/dist/esm/utils/checkIsURLAbsolute.mjs +1 -5
- package/dist/esm/utils/checkIsURLAbsolute.mjs.map +1 -1
- package/dist/esm/utils/getCookie.mjs +1 -30
- package/dist/esm/utils/getCookie.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +1 -0
- package/dist/esm/utils/intl.mjs +1 -86
- package/dist/esm/utils/intl.mjs.map +1 -1
- package/dist/esm/utils/isSameKeyPath.mjs +1 -5
- package/dist/esm/utils/isSameKeyPath.mjs.map +1 -1
- package/dist/esm/utils/isValidReactElement.mjs +1 -12
- package/dist/esm/utils/isValidReactElement.mjs.map +1 -1
- package/dist/esm/utils/localeStorage.mjs +1 -135
- package/dist/esm/utils/localeStorage.mjs.map +1 -1
- package/dist/esm/utils/parseYaml.mjs +16 -320
- package/dist/esm/utils/parseYaml.mjs.map +1 -1
- package/dist/types/formatters/index.d.ts +2 -1
- package/dist/types/index.d.ts +8 -2
- package/dist/types/interpreter/getContent/plugins.d.ts +4 -4
- package/dist/types/interpreter/getContent/plugins.d.ts.map +1 -1
- package/dist/types/localization/index.d.ts +2 -1
- package/dist/types/markdown/index.d.ts +4 -1
- package/dist/types/markdown/types.d.ts +1 -1
- package/dist/types/markdown/types.d.ts.map +1 -1
- package/dist/types/transpiler/translation/translation.d.ts +1 -1
- package/dist/types/utils/index.d.ts +8 -0
- package/package.json +65 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.mjs","names":[],"sources":["../../../src/markdown/utils.ts"],"sourcesContent":["import {\n ATTRIBUTES_TO_SANITIZE,\n CAPTURE_LETTER_AFTER_HYPHEN,\n CR_NEWLINE_R,\n DURATION_DELAY_TRIGGER,\n FORMFEED_R,\n HTML_CUSTOM_ATTR_R,\n INTERPOLATION_R,\n TAB_R,\n TABLE_CENTER_ALIGN,\n TABLE_LEFT_ALIGN,\n TABLE_RIGHT_ALIGN,\n TABLE_TRIM_PIPES,\n UNESCAPE_R,\n} from './constants';\nimport type { NestedParser, ParserResult, ParseState, Rule } from './types';\n\n// ============================================================================\n// STRING UTILITIES\n// ============================================================================\n\n/**\n * Trim trailing whitespace from a string.\n */\nexport const trimEnd = (str: string): string => {\n let end = str.length;\n\n while (end > 0 && str[end - 1] <= ' ') end--;\n\n return str.slice(0, end);\n};\n\n/**\n * Check if string starts with prefix.\n */\nexport const startsWith = (str: string, prefix: string): boolean => {\n return str.startsWith(prefix);\n};\n\n/**\n * Remove symmetrical leading and trailing quotes.\n */\nexport const unquote = (str: string): string => {\n const first = str[0];\n\n if (\n (first === '\"' || first === \"'\") &&\n str.length >= 2 &&\n str[str.length - 1] === first\n ) {\n return str.slice(1, -1);\n }\n\n return str;\n};\n\n/**\n * Unescape backslash-escaped characters.\n */\nexport const unescapeString = (rawString: string): string =>\n rawString ? rawString.replace(UNESCAPE_R, '$1') : rawString;\n\n/**\n * Join class names, filtering out falsy values.\n */\nexport const cx = (...args: any[]): string => args.filter(Boolean).join(' ');\n\n/**\n * Get a nested property from an object using dot notation.\n */\nexport const get = (src: any, path: string, fb?: any): any => {\n let ptr = src;\n const frags = path.split('.');\n\n while (frags.length) {\n ptr = ptr[frags[0]];\n\n if (ptr === undefined) break;\n else frags.shift();\n }\n\n return ptr ?? fb;\n};\n\n// ============================================================================\n// SLUGIFY\n// ============================================================================\n\n/**\n * Convert a string to a URL-safe slug.\n * Based on https://stackoverflow.com/a/18123682/1141611\n */\nexport const slugify = (str: string): string =>\n str\n .replace(/[ÀÁÂÃÄÅàáâãä忯]/g, 'a')\n .replace(/[çÇ]/g, 'c')\n .replace(/[ðÐ]/g, 'd')\n .replace(/[ÈÉÊËéèêë]/g, 'e')\n .replace(/[ÏïÎîÍíÌì]/g, 'i')\n .replace(/[Ññ]/g, 'n')\n .replace(/[øØœŒÕõÔôÓóÒò]/g, 'o')\n .replace(/[ÜüÛûÚúÙù]/g, 'u')\n .replace(/[ŸÿÝý]/g, 'y')\n .replace(/[^a-z0-9- ]/gi, '')\n .replace(/ /gi, '-')\n .toLowerCase();\n\n// ============================================================================\n// SANITIZER\n// ============================================================================\n\nconst SANITIZE_R = /(javascript|vbscript|data(?!:image)):/i;\n\n/**\n * Sanitize URLs to prevent XSS attacks.\n * Returns null if the URL is unsafe.\n */\nexport const sanitizer = (input: string): string | null => {\n try {\n const decoded = decodeURIComponent(input).replace(/[^A-Za-z0-9/:]/g, '');\n\n if (SANITIZE_R.test(decoded)) {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n 'Input contains an unsafe JavaScript/VBScript/data expression, it will not be rendered.',\n decoded\n );\n }\n\n return null;\n }\n } catch (_e) {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n 'Input could not be decoded due to malformed syntax or characters, it will not be rendered.',\n input\n );\n }\n\n // decodeURIComponent sometimes throws a URIError\n return null;\n }\n\n return input;\n};\n\n// ============================================================================\n// WHITESPACE NORMALIZATION\n// ============================================================================\n\n/**\n * Normalize whitespace in source string.\n */\nexport const normalizeWhitespace = (source: string): string => {\n const start = performance.now();\n const result = source\n .replace(CR_NEWLINE_R, '\\n')\n .replace(FORMFEED_R, '')\n .replace(TAB_R, ' ');\n\n const duration = performance.now() - start;\n\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `normalizeWhitespace: ${duration.toFixed(3)}ms, source length: ${source.length}`\n );\n }\n\n return result;\n};\n\n/**\n * Safely remove a uniform leading indentation from lines, but do NOT touch\n * the content inside fenced code blocks (``` or ~~~).\n */\nexport const trimLeadingWhitespaceOutsideFences = (\n text: string,\n whitespace: string\n): string => {\n const start = performance.now();\n if (!whitespace) return text;\n\n const lines = text.split('\\n');\n let inFence = false;\n let fenceToken: string | null = null;\n\n const isFenceLine = (line: string): RegExpMatchArray | null =>\n line.match(/^\\s*(`{3,}|~{3,})/);\n\n const maybeToggleFence = (line: string): void => {\n const m = isFenceLine(line);\n\n if (!m) return;\n\n const token = m[1];\n\n if (!inFence) {\n inFence = true;\n fenceToken = token;\n } else if (fenceToken && line.includes(fenceToken)) {\n inFence = false;\n fenceToken = null;\n }\n };\n\n const out = lines.map((line) => {\n const fenceMatch = isFenceLine(line);\n if (fenceMatch) {\n const trimmedFenceLine = line.startsWith(whitespace)\n ? line.slice(whitespace.length)\n : line;\n maybeToggleFence(line);\n return trimmedFenceLine;\n }\n\n if (inFence) {\n return line;\n }\n\n return line.startsWith(whitespace) ? line.slice(whitespace.length) : line;\n });\n\n const result = out.join('\\n');\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `trimLeadingWhitespaceOutsideFences: ${duration.toFixed(3)}ms, text length: ${text.length}, lines count: ${lines.length}`\n );\n }\n\n return result;\n};\n\n/**\n * Normalize HTML attribute key to JSX prop name.\n */\nexport const normalizeAttributeKey = (key: string): string => {\n const hyphenIndex = key.indexOf('-');\n\n if (hyphenIndex !== -1 && key.match(HTML_CUSTOM_ATTR_R) === null) {\n key = key.replace(CAPTURE_LETTER_AFTER_HYPHEN, (_, letter) => {\n return letter.toUpperCase();\n });\n }\n\n return key;\n};\n\ntype StyleTuple = [key: string, value: string];\n\n/**\n * Parse a CSS style string into an array of [key, value] tuples.\n */\nexport const parseStyleAttribute = (styleString: string): StyleTuple[] => {\n const start = performance.now();\n const styles: StyleTuple[] = [];\n let buffer = '';\n let inUrl = false;\n let inQuotes = false;\n let quoteChar: '\"' | \"'\" | '' = '';\n\n if (!styleString) return styles;\n\n for (let i = 0; i < styleString.length; i++) {\n const char = styleString[i];\n\n if ((char === '\"' || char === \"'\") && !inUrl) {\n if (!inQuotes) {\n inQuotes = true;\n quoteChar = char;\n } else if (char === quoteChar) {\n inQuotes = false;\n quoteChar = '';\n }\n }\n\n if (char === '(' && buffer.endsWith('url')) {\n inUrl = true;\n } else if (char === ')' && inUrl) {\n inUrl = false;\n }\n\n if (char === ';' && !inQuotes && !inUrl) {\n const declaration = buffer.trim();\n\n if (declaration) {\n const colonIndex = declaration.indexOf(':');\n\n if (colonIndex > 0) {\n const key = declaration.slice(0, colonIndex).trim();\n const value = declaration.slice(colonIndex + 1).trim();\n styles.push([key, value]);\n }\n }\n buffer = '';\n } else {\n buffer += char;\n }\n }\n\n const declaration = buffer.trim();\n\n if (declaration) {\n const colonIndex = declaration.indexOf(':');\n if (colonIndex > 0) {\n const key = declaration.slice(0, colonIndex).trim();\n const value = declaration.slice(colonIndex + 1).trim();\n styles.push([key, value]);\n }\n }\n\n const duration = performance.now() - start;\n\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseStyleAttribute: ${duration.toFixed(3)}ms, styleString length: ${styleString.length}, styles count: ${styles.length}`\n );\n }\n\n return styles;\n};\n\n/**\n * Convert an attribute value to a Node prop value.\n */\nexport const attributeValueToNodePropValue = (\n tag: string,\n key: string,\n value: string,\n sanitizeUrlFn: (\n value: string,\n tag: string,\n attribute: string\n ) => string | null\n): any => {\n if (key === 'style') {\n return parseStyleAttribute(value).reduce(\n (styles, [styleKey, styleValue]) => {\n const camelCasedKey = styleKey.replace(/(-[a-z])/g, (substr) =>\n substr[1].toUpperCase()\n );\n\n (styles as Record<string, any>)[camelCasedKey] = sanitizeUrlFn(\n styleValue,\n tag,\n styleKey\n );\n\n return styles;\n },\n {} as Record<string, any>\n );\n } else if (ATTRIBUTES_TO_SANITIZE.indexOf(key) !== -1) {\n return sanitizeUrlFn(unescapeString(value), tag, key);\n } else if (value.match(INTERPOLATION_R)) {\n value = unescapeString(value.slice(1, value.length - 1));\n }\n\n if (value === 'true') {\n return true;\n } else if (value === 'false') {\n return false;\n }\n\n return value;\n};\n\n// ============================================================================\n// TABLE PARSING\n// ============================================================================\n\n/**\n * Parse table alignment from a separator row.\n */\nexport const parseTableAlignCapture = (\n alignCapture: string\n): 'left' | 'right' | 'center' => {\n if (TABLE_RIGHT_ALIGN.test(alignCapture)) {\n return 'right';\n } else if (TABLE_CENTER_ALIGN.test(alignCapture)) {\n return 'center';\n } else if (TABLE_LEFT_ALIGN.test(alignCapture)) {\n return 'left';\n }\n\n return 'left';\n};\n\n/**\n * Parse table alignment row.\n */\nexport const parseTableAlign = (\n source: string\n): ('left' | 'right' | 'center')[] => {\n const alignText = source.replace(TABLE_TRIM_PIPES, '').split('|');\n return alignText.map(parseTableAlignCapture);\n};\n\n/**\n * Parse a single table row.\n */\nexport const parseTableRow = (\n source: string,\n parse: NestedParser,\n state: ParseState,\n tableOutput: boolean\n): ParserResult[][] => {\n const start = performance.now();\n const prevInTable = state.inTable;\n\n state.inTable = true;\n\n const cells: ParserResult[][] = [[]];\n let acc = '';\n\n const flush = (): void => {\n if (!acc) return;\n\n const cell = cells[cells.length - 1];\n cell.push.apply(cell, parse(acc, state));\n acc = '';\n };\n\n source\n .trim()\n .split(/(`[^`]*`|\\\\\\||\\|)/)\n .filter(Boolean)\n .forEach((fragment, i, arr) => {\n if (fragment.trim() === '|') {\n flush();\n\n if (tableOutput) {\n if (i !== 0 && i !== arr.length - 1) {\n cells.push([]);\n }\n\n return;\n }\n }\n\n acc += fragment;\n });\n\n flush();\n\n state.inTable = prevInTable;\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseTableRow: ${duration.toFixed(3)}ms, source length: ${source.length}, cells count: ${cells.length}`\n );\n }\n\n return cells;\n};\n\n/**\n * Parse table cells (multiple rows).\n */\nexport const parseTableCells = (\n source: string,\n parse: NestedParser,\n state: ParseState\n): ParserResult[][][] => {\n const start = performance.now();\n const rowsText = source.trim().split('\\n');\n\n const result = rowsText.map((rowText) =>\n parseTableRow(rowText, parse, state, true)\n );\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseTableCells: ${duration.toFixed(3)}ms, source length: ${source.length}, rows count: ${rowsText.length}`\n );\n }\n\n return result;\n};\n\n// ============================================================================\n// PARSING HELPERS\n// ============================================================================\n\n/**\n * Check if a rule qualifies for the current source and state.\n */\nexport const qualifies = (\n source: string,\n state: ParseState,\n qualify: NonNullable<Rule<any>['_qualify']>\n): boolean => {\n if (Array.isArray(qualify)) {\n for (let i = 0; i < qualify.length; i++) {\n if (startsWith(source, qualify[i])) return true;\n }\n\n return false;\n }\n\n return (qualify as (source: string, state: ParseState) => boolean)(\n source,\n state\n );\n};\n\n/**\n * Marks a matcher function as eligible for being run inside an inline context.\n */\nexport const allowInline = <T extends (...args: any[]) => any>(\n fn: T\n): T & { inline: 1 } => {\n (fn as any).inline = 1;\n return fn as T & { inline: 1 };\n};\n\n/**\n * Creates a match function for an inline scoped element from a regex.\n */\nexport const inlineRegex = (regex: RegExp) =>\n allowInline((source: string, state: ParseState): RegExpMatchArray | null => {\n if (state.inline) {\n return regex.exec(source);\n } else {\n return null;\n }\n });\n\n/**\n * Creates a match function for inline elements except links.\n */\nexport const simpleInlineRegex = (regex: RegExp) =>\n allowInline((source: string, state: ParseState): RegExpMatchArray | null => {\n if (state.inline || state.simple) {\n return regex.exec(source);\n } else {\n return null;\n }\n });\n\n/**\n * Creates a match function for a block scoped element from a regex.\n */\nexport const blockRegex =\n (regex: RegExp) =>\n (source: string, state: ParseState): RegExpMatchArray | null => {\n if (state.inline || state.simple) {\n return null;\n } else {\n return regex.exec(source);\n }\n };\n\n/**\n * Creates a match function from a regex, ignoring block/inline scope.\n */\nexport const anyScopeRegex = (\n fn: RegExp | ((source: string, state: ParseState) => RegExpMatchArray | null)\n) =>\n allowInline((source: string, state: ParseState): RegExpMatchArray | null => {\n if (typeof fn === 'function') {\n return fn(source, state);\n }\n return fn.exec(source);\n });\n\n/**\n * Parse inline content (including links).\n */\nexport const parseInline = (\n parse: NestedParser,\n children: string,\n state: ParseState\n): ParserResult[] => {\n const start = performance.now();\n const isCurrentlyInline = state.inline ?? false;\n const isCurrentlySimple = state.simple ?? false;\n state.inline = true;\n state.simple = true;\n const result = parse(children, state);\n state.inline = isCurrentlyInline;\n state.simple = isCurrentlySimple;\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseInline: ${duration.toFixed(3)}ms, children length: ${children.length}, result count: ${result.length}`\n );\n }\n\n return result;\n};\n\n/**\n * Parse simple inline content (no links).\n */\nexport const parseSimpleInline = (\n parse: NestedParser,\n children: string,\n state: ParseState\n): ParserResult[] => {\n const start = performance.now();\n const isCurrentlyInline = state.inline ?? false;\n const isCurrentlySimple = state.simple ?? false;\n\n state.inline = false;\n state.simple = true;\n const result = parse(children, state);\n state.inline = isCurrentlyInline;\n state.simple = isCurrentlySimple;\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseSimpleInline: ${duration.toFixed(3)}ms, children length: ${children.length}, result count: ${result.length}`\n );\n }\n\n return result;\n};\n\n/**\n * Parse block content.\n */\nexport const parseBlock = (\n parse: NestedParser,\n children: string,\n state: ParseState = {}\n): ParserResult[] => {\n const start = performance.now();\n const isCurrentlyInline = state.inline || false;\n state.inline = false;\n const normalizedChildren = trimEnd(children);\n const needsTerminator = /\\n\\n$/.test(normalizedChildren) === false;\n const blockInput = needsTerminator\n ? normalizedChildren.endsWith('\\n')\n ? `${normalizedChildren}\\n`\n : `${normalizedChildren}\\n\\n`\n : normalizedChildren;\n\n const result = parse(blockInput, state);\n state.inline = isCurrentlyInline;\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseBlock: ${duration.toFixed(3)}ms, children length: ${children.length}, result count: ${result.length}`\n );\n }\n\n return result;\n};\n\n/**\n * Helper to parse capture group 2 as inline content.\n */\nexport const parseCaptureInline = (\n capture: RegExpMatchArray,\n parse: NestedParser,\n state: ParseState\n): { children: ParserResult[] } => {\n return {\n children: parseInline(parse, capture[2], state),\n };\n};\n\n/**\n * Helper that captures nothing (empty object).\n */\nexport const captureNothing = (): Record<string, never> => ({});\n\n/**\n * Helper that renders nothing (null).\n */\nexport const renderNothing = (): null => null;\n\n/**\n * Check if any regex in a list matches the input.\n */\nexport const some = (regexes: RegExp[], input: string): boolean => {\n for (let i = 0; i < regexes.length; i++) {\n if (regexes[i].test(input)) {\n return true;\n }\n }\n return false;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.mjs","names":[],"sources":["../../../src/markdown/utils.ts"],"sourcesContent":["import {\n ATTRIBUTES_TO_SANITIZE,\n CAPTURE_LETTER_AFTER_HYPHEN,\n CR_NEWLINE_R,\n DURATION_DELAY_TRIGGER,\n FORMFEED_R,\n HTML_CUSTOM_ATTR_R,\n INTERPOLATION_R,\n TAB_R,\n TABLE_CENTER_ALIGN,\n TABLE_LEFT_ALIGN,\n TABLE_RIGHT_ALIGN,\n TABLE_TRIM_PIPES,\n UNESCAPE_R,\n} from './constants';\nimport type { NestedParser, ParserResult, ParseState, Rule } from './types';\n\n// ============================================================================\n// STRING UTILITIES\n// ============================================================================\n\n/**\n * Trim trailing whitespace from a string.\n */\nexport const trimEnd = (str: string): string => {\n let end = str.length;\n\n while (end > 0 && str[end - 1] <= ' ') end--;\n\n return str.slice(0, end);\n};\n\n/**\n * Check if string starts with prefix.\n */\nexport const startsWith = (str: string, prefix: string): boolean => {\n return str.startsWith(prefix);\n};\n\n/**\n * Remove symmetrical leading and trailing quotes.\n */\nexport const unquote = (str: string): string => {\n const first = str[0];\n\n if (\n (first === '\"' || first === \"'\") &&\n str.length >= 2 &&\n str[str.length - 1] === first\n ) {\n return str.slice(1, -1);\n }\n\n return str;\n};\n\n/**\n * Unescape backslash-escaped characters.\n */\nexport const unescapeString = (rawString: string): string =>\n rawString ? rawString.replace(UNESCAPE_R, '$1') : rawString;\n\n/**\n * Join class names, filtering out falsy values.\n */\nexport const cx = (...args: any[]): string => args.filter(Boolean).join(' ');\n\n/**\n * Get a nested property from an object using dot notation.\n */\nexport const get = (src: any, path: string, fb?: any): any => {\n let ptr = src;\n const frags = path.split('.');\n\n while (frags.length) {\n ptr = ptr[frags[0]];\n\n if (ptr === undefined) break;\n else frags.shift();\n }\n\n return ptr ?? fb;\n};\n\n// ============================================================================\n// SLUGIFY\n// ============================================================================\n\n/**\n * Convert a string to a URL-safe slug.\n * Based on https://stackoverflow.com/a/18123682/1141611\n */\nexport const slugify = (str: string): string =>\n str\n .replace(/[ÀÁÂÃÄÅàáâãä忯]/g, 'a')\n .replace(/[çÇ]/g, 'c')\n .replace(/[ðÐ]/g, 'd')\n .replace(/[ÈÉÊËéèêë]/g, 'e')\n .replace(/[ÏïÎîÍíÌì]/g, 'i')\n .replace(/[Ññ]/g, 'n')\n .replace(/[øØœŒÕõÔôÓóÒò]/g, 'o')\n .replace(/[ÜüÛûÚúÙù]/g, 'u')\n .replace(/[ŸÿÝý]/g, 'y')\n .replace(/[^a-z0-9- ]/gi, '')\n .replace(/ /gi, '-')\n .toLowerCase();\n\n// ============================================================================\n// SANITIZER\n// ============================================================================\n\nconst SANITIZE_R = /(javascript|vbscript|data(?!:image)):/i;\n\n/**\n * Sanitize URLs to prevent XSS attacks.\n * Returns null if the URL is unsafe.\n */\nexport const sanitizer = (input: string): string | null => {\n try {\n const decoded = decodeURIComponent(input).replace(/[^A-Za-z0-9/:]/g, '');\n\n if (SANITIZE_R.test(decoded)) {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n 'Input contains an unsafe JavaScript/VBScript/data expression, it will not be rendered.',\n decoded\n );\n }\n\n return null;\n }\n } catch (_e) {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n 'Input could not be decoded due to malformed syntax or characters, it will not be rendered.',\n input\n );\n }\n\n // decodeURIComponent sometimes throws a URIError\n return null;\n }\n\n return input;\n};\n\n// ============================================================================\n// WHITESPACE NORMALIZATION\n// ============================================================================\n\n/**\n * Normalize whitespace in source string.\n */\nexport const normalizeWhitespace = (source: string): string => {\n const start = performance.now();\n const result = source\n .replace(CR_NEWLINE_R, '\\n')\n .replace(FORMFEED_R, '')\n .replace(TAB_R, ' ');\n\n const duration = performance.now() - start;\n\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `normalizeWhitespace: ${duration.toFixed(3)}ms, source length: ${source.length}`\n );\n }\n\n return result;\n};\n\n/**\n * Safely remove a uniform leading indentation from lines, but do NOT touch\n * the content inside fenced code blocks (``` or ~~~).\n */\nexport const trimLeadingWhitespaceOutsideFences = (\n text: string,\n whitespace: string\n): string => {\n const start = performance.now();\n if (!whitespace) return text;\n\n const lines = text.split('\\n');\n let inFence = false;\n let fenceToken: string | null = null;\n\n const isFenceLine = (line: string): RegExpMatchArray | null =>\n line.match(/^\\s*(`{3,}|~{3,})/);\n\n const maybeToggleFence = (line: string): void => {\n const m = isFenceLine(line);\n\n if (!m) return;\n\n const token = m[1];\n\n if (!inFence) {\n inFence = true;\n fenceToken = token;\n } else if (fenceToken && line.includes(fenceToken)) {\n inFence = false;\n fenceToken = null;\n }\n };\n\n const out = lines.map((line) => {\n const fenceMatch = isFenceLine(line);\n if (fenceMatch) {\n const trimmedFenceLine = line.startsWith(whitespace)\n ? line.slice(whitespace.length)\n : line;\n maybeToggleFence(line);\n return trimmedFenceLine;\n }\n\n if (inFence) {\n return line;\n }\n\n return line.startsWith(whitespace) ? line.slice(whitespace.length) : line;\n });\n\n const result = out.join('\\n');\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `trimLeadingWhitespaceOutsideFences: ${duration.toFixed(3)}ms, text length: ${text.length}, lines count: ${lines.length}`\n );\n }\n\n return result;\n};\n\n/**\n * Normalize HTML attribute key to JSX prop name.\n */\nexport const normalizeAttributeKey = (key: string): string => {\n const hyphenIndex = key.indexOf('-');\n\n if (hyphenIndex !== -1 && key.match(HTML_CUSTOM_ATTR_R) === null) {\n key = key.replace(CAPTURE_LETTER_AFTER_HYPHEN, (_, letter) => {\n return letter.toUpperCase();\n });\n }\n\n return key;\n};\n\ntype StyleTuple = [key: string, value: string];\n\n/**\n * Parse a CSS style string into an array of [key, value] tuples.\n */\nexport const parseStyleAttribute = (styleString: string): StyleTuple[] => {\n const start = performance.now();\n const styles: StyleTuple[] = [];\n let buffer = '';\n let inUrl = false;\n let inQuotes = false;\n let quoteChar: '\"' | \"'\" | '' = '';\n\n if (!styleString) return styles;\n\n for (let i = 0; i < styleString.length; i++) {\n const char = styleString[i];\n\n if ((char === '\"' || char === \"'\") && !inUrl) {\n if (!inQuotes) {\n inQuotes = true;\n quoteChar = char;\n } else if (char === quoteChar) {\n inQuotes = false;\n quoteChar = '';\n }\n }\n\n if (char === '(' && buffer.endsWith('url')) {\n inUrl = true;\n } else if (char === ')' && inUrl) {\n inUrl = false;\n }\n\n if (char === ';' && !inQuotes && !inUrl) {\n const declaration = buffer.trim();\n\n if (declaration) {\n const colonIndex = declaration.indexOf(':');\n\n if (colonIndex > 0) {\n const key = declaration.slice(0, colonIndex).trim();\n const value = declaration.slice(colonIndex + 1).trim();\n styles.push([key, value]);\n }\n }\n buffer = '';\n } else {\n buffer += char;\n }\n }\n\n const declaration = buffer.trim();\n\n if (declaration) {\n const colonIndex = declaration.indexOf(':');\n if (colonIndex > 0) {\n const key = declaration.slice(0, colonIndex).trim();\n const value = declaration.slice(colonIndex + 1).trim();\n styles.push([key, value]);\n }\n }\n\n const duration = performance.now() - start;\n\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseStyleAttribute: ${duration.toFixed(3)}ms, styleString length: ${styleString.length}, styles count: ${styles.length}`\n );\n }\n\n return styles;\n};\n\n/**\n * Convert an attribute value to a Node prop value.\n */\nexport const attributeValueToNodePropValue = (\n tag: string,\n key: string,\n value: string,\n sanitizeUrlFn: (\n value: string,\n tag: string,\n attribute: string\n ) => string | null\n): any => {\n if (key === 'style') {\n return parseStyleAttribute(value).reduce(\n (styles, [styleKey, styleValue]) => {\n const camelCasedKey = styleKey.replace(/(-[a-z])/g, (substr) =>\n substr[1].toUpperCase()\n );\n\n (styles as Record<string, any>)[camelCasedKey] = sanitizeUrlFn(\n styleValue,\n tag,\n styleKey\n );\n\n return styles;\n },\n {} as Record<string, any>\n );\n } else if (ATTRIBUTES_TO_SANITIZE.indexOf(key) !== -1) {\n return sanitizeUrlFn(unescapeString(value), tag, key);\n } else if (value.match(INTERPOLATION_R)) {\n value = unescapeString(value.slice(1, value.length - 1));\n }\n\n if (value === 'true') {\n return true;\n } else if (value === 'false') {\n return false;\n }\n\n return value;\n};\n\n// ============================================================================\n// TABLE PARSING\n// ============================================================================\n\n/**\n * Parse table alignment from a separator row.\n */\nexport const parseTableAlignCapture = (\n alignCapture: string\n): 'left' | 'right' | 'center' => {\n if (TABLE_RIGHT_ALIGN.test(alignCapture)) {\n return 'right';\n } else if (TABLE_CENTER_ALIGN.test(alignCapture)) {\n return 'center';\n } else if (TABLE_LEFT_ALIGN.test(alignCapture)) {\n return 'left';\n }\n\n return 'left';\n};\n\n/**\n * Parse table alignment row.\n */\nexport const parseTableAlign = (\n source: string\n): ('left' | 'right' | 'center')[] => {\n const alignText = source.replace(TABLE_TRIM_PIPES, '').split('|');\n return alignText.map(parseTableAlignCapture);\n};\n\n/**\n * Parse a single table row.\n */\nexport const parseTableRow = (\n source: string,\n parse: NestedParser,\n state: ParseState,\n tableOutput: boolean\n): ParserResult[][] => {\n const start = performance.now();\n const prevInTable = state.inTable;\n\n state.inTable = true;\n\n const cells: ParserResult[][] = [[]];\n let acc = '';\n\n const flush = (): void => {\n if (!acc) return;\n\n const cell = cells[cells.length - 1];\n cell.push.apply(cell, parse(acc, state));\n acc = '';\n };\n\n source\n .trim()\n .split(/(`[^`]*`|\\\\\\||\\|)/)\n .filter(Boolean)\n .forEach((fragment, i, arr) => {\n if (fragment.trim() === '|') {\n flush();\n\n if (tableOutput) {\n if (i !== 0 && i !== arr.length - 1) {\n cells.push([]);\n }\n\n return;\n }\n }\n\n acc += fragment;\n });\n\n flush();\n\n state.inTable = prevInTable;\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseTableRow: ${duration.toFixed(3)}ms, source length: ${source.length}, cells count: ${cells.length}`\n );\n }\n\n return cells;\n};\n\n/**\n * Parse table cells (multiple rows).\n */\nexport const parseTableCells = (\n source: string,\n parse: NestedParser,\n state: ParseState\n): ParserResult[][][] => {\n const start = performance.now();\n const rowsText = source.trim().split('\\n');\n\n const result = rowsText.map((rowText) =>\n parseTableRow(rowText, parse, state, true)\n );\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseTableCells: ${duration.toFixed(3)}ms, source length: ${source.length}, rows count: ${rowsText.length}`\n );\n }\n\n return result;\n};\n\n// ============================================================================\n// PARSING HELPERS\n// ============================================================================\n\n/**\n * Check if a rule qualifies for the current source and state.\n */\nexport const qualifies = (\n source: string,\n state: ParseState,\n qualify: NonNullable<Rule<any>['_qualify']>\n): boolean => {\n if (Array.isArray(qualify)) {\n for (let i = 0; i < qualify.length; i++) {\n if (startsWith(source, qualify[i])) return true;\n }\n\n return false;\n }\n\n return (qualify as (source: string, state: ParseState) => boolean)(\n source,\n state\n );\n};\n\n/**\n * Marks a matcher function as eligible for being run inside an inline context.\n */\nexport const allowInline = <T extends (...args: any[]) => any>(\n fn: T\n): T & { inline: 1 } => {\n (fn as any).inline = 1;\n return fn as T & { inline: 1 };\n};\n\n/**\n * Creates a match function for an inline scoped element from a regex.\n */\nexport const inlineRegex = (regex: RegExp) =>\n allowInline((source: string, state: ParseState): RegExpMatchArray | null => {\n if (state.inline) {\n return regex.exec(source);\n } else {\n return null;\n }\n });\n\n/**\n * Creates a match function for inline elements except links.\n */\nexport const simpleInlineRegex = (regex: RegExp) =>\n allowInline((source: string, state: ParseState): RegExpMatchArray | null => {\n if (state.inline || state.simple) {\n return regex.exec(source);\n } else {\n return null;\n }\n });\n\n/**\n * Creates a match function for a block scoped element from a regex.\n */\nexport const blockRegex =\n (regex: RegExp) =>\n (source: string, state: ParseState): RegExpMatchArray | null => {\n if (state.inline || state.simple) {\n return null;\n } else {\n return regex.exec(source);\n }\n };\n\n/**\n * Creates a match function from a regex, ignoring block/inline scope.\n */\nexport const anyScopeRegex = (\n fn: RegExp | ((source: string, state: ParseState) => RegExpMatchArray | null)\n) =>\n allowInline((source: string, state: ParseState): RegExpMatchArray | null => {\n if (typeof fn === 'function') {\n return fn(source, state);\n }\n return fn.exec(source);\n });\n\n/**\n * Parse inline content (including links).\n */\nexport const parseInline = (\n parse: NestedParser,\n children: string,\n state: ParseState\n): ParserResult[] => {\n const start = performance.now();\n const isCurrentlyInline = state.inline ?? false;\n const isCurrentlySimple = state.simple ?? false;\n state.inline = true;\n state.simple = true;\n const result = parse(children, state);\n state.inline = isCurrentlyInline;\n state.simple = isCurrentlySimple;\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseInline: ${duration.toFixed(3)}ms, children length: ${children.length}, result count: ${result.length}`\n );\n }\n\n return result;\n};\n\n/**\n * Parse simple inline content (no links).\n */\nexport const parseSimpleInline = (\n parse: NestedParser,\n children: string,\n state: ParseState\n): ParserResult[] => {\n const start = performance.now();\n const isCurrentlyInline = state.inline ?? false;\n const isCurrentlySimple = state.simple ?? false;\n\n state.inline = false;\n state.simple = true;\n const result = parse(children, state);\n state.inline = isCurrentlyInline;\n state.simple = isCurrentlySimple;\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseSimpleInline: ${duration.toFixed(3)}ms, children length: ${children.length}, result count: ${result.length}`\n );\n }\n\n return result;\n};\n\n/**\n * Parse block content.\n */\nexport const parseBlock = (\n parse: NestedParser,\n children: string,\n state: ParseState = {}\n): ParserResult[] => {\n const start = performance.now();\n const isCurrentlyInline = state.inline || false;\n state.inline = false;\n const normalizedChildren = trimEnd(children);\n const needsTerminator = /\\n\\n$/.test(normalizedChildren) === false;\n const blockInput = needsTerminator\n ? normalizedChildren.endsWith('\\n')\n ? `${normalizedChildren}\\n`\n : `${normalizedChildren}\\n\\n`\n : normalizedChildren;\n\n const result = parse(blockInput, state);\n state.inline = isCurrentlyInline;\n\n const duration = performance.now() - start;\n if (duration > DURATION_DELAY_TRIGGER) {\n console.log(\n `parseBlock: ${duration.toFixed(3)}ms, children length: ${children.length}, result count: ${result.length}`\n );\n }\n\n return result;\n};\n\n/**\n * Helper to parse capture group 2 as inline content.\n */\nexport const parseCaptureInline = (\n capture: RegExpMatchArray,\n parse: NestedParser,\n state: ParseState\n): { children: ParserResult[] } => {\n return {\n children: parseInline(parse, capture[2], state),\n };\n};\n\n/**\n * Helper that captures nothing (empty object).\n */\nexport const captureNothing = (): Record<string, never> => ({});\n\n/**\n * Helper that renders nothing (null).\n */\nexport const renderNothing = (): null => null;\n\n/**\n * Check if any regex in a list matches the input.\n */\nexport const some = (regexes: RegExp[], input: string): boolean => {\n for (let i = 0; i < regexes.length; i++) {\n if (regexes[i].test(input)) {\n return true;\n }\n }\n return false;\n};\n"],"mappings":"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"}
|
|
@@ -1,317 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { enu as enumeration } from "../transpiler/enumeration/enumeration.mjs";
|
|
3
|
-
import { gender } from "../transpiler/gender/gender.mjs";
|
|
4
|
-
import { html } from "../transpiler/html/html.mjs";
|
|
5
|
-
import { insert as insertion } from "../transpiler/insertion/insertion.mjs";
|
|
6
|
-
import { NodeType } from "@intlayer/types";
|
|
7
|
-
|
|
8
|
-
//#region src/messageFormat/ICU.ts
|
|
9
|
-
const parseICU = (text) => {
|
|
10
|
-
let index = 0;
|
|
11
|
-
const parseNodes = () => {
|
|
12
|
-
const nodes = [];
|
|
13
|
-
let currentText = "";
|
|
14
|
-
while (index < text.length) {
|
|
15
|
-
const char = text[index];
|
|
16
|
-
if (char === "{") {
|
|
17
|
-
if (currentText) {
|
|
18
|
-
nodes.push(currentText);
|
|
19
|
-
currentText = "";
|
|
20
|
-
}
|
|
21
|
-
index++;
|
|
22
|
-
nodes.push(parseArgument());
|
|
23
|
-
} else if (char === "}") break;
|
|
24
|
-
else if (char === "'") if (index + 1 < text.length && text[index + 1] === "'") {
|
|
25
|
-
currentText += "'";
|
|
26
|
-
index += 2;
|
|
27
|
-
} else {
|
|
28
|
-
const nextQuote = text.indexOf("'", index + 1);
|
|
29
|
-
if (nextQuote !== -1) {
|
|
30
|
-
currentText += text.substring(index + 1, nextQuote);
|
|
31
|
-
index = nextQuote + 1;
|
|
32
|
-
} else {
|
|
33
|
-
currentText += "'";
|
|
34
|
-
index++;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
currentText += char;
|
|
39
|
-
index++;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
if (currentText) nodes.push(currentText);
|
|
43
|
-
return nodes;
|
|
44
|
-
};
|
|
45
|
-
const parseArgument = () => {
|
|
46
|
-
let name = "";
|
|
47
|
-
while (index < text.length && /[^,}]/.test(text[index])) {
|
|
48
|
-
name += text[index];
|
|
49
|
-
index++;
|
|
50
|
-
}
|
|
51
|
-
name = name.trim();
|
|
52
|
-
if (index >= text.length) throw new Error("Unclosed argument");
|
|
53
|
-
if (text[index] === "}") {
|
|
54
|
-
index++;
|
|
55
|
-
return {
|
|
56
|
-
type: "argument",
|
|
57
|
-
name
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
if (text[index] === ",") {
|
|
61
|
-
index++;
|
|
62
|
-
let type = "";
|
|
63
|
-
while (index < text.length && /[^,}]/.test(text[index])) {
|
|
64
|
-
type += text[index];
|
|
65
|
-
index++;
|
|
66
|
-
}
|
|
67
|
-
type = type.trim();
|
|
68
|
-
if (index >= text.length) throw new Error("Unclosed argument");
|
|
69
|
-
if (text[index] === "}") {
|
|
70
|
-
index++;
|
|
71
|
-
return {
|
|
72
|
-
type: "argument",
|
|
73
|
-
name,
|
|
74
|
-
format: { type }
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
if (text[index] === ",") {
|
|
78
|
-
index++;
|
|
79
|
-
if (type === "plural" || type === "select") {
|
|
80
|
-
const options = {};
|
|
81
|
-
while (index < text.length && text[index] !== "}") {
|
|
82
|
-
while (index < text.length && /\s/.test(text[index])) index++;
|
|
83
|
-
let key = "";
|
|
84
|
-
while (index < text.length && /[^{\s]/.test(text[index])) {
|
|
85
|
-
key += text[index];
|
|
86
|
-
index++;
|
|
87
|
-
}
|
|
88
|
-
while (index < text.length && /\s/.test(text[index])) index++;
|
|
89
|
-
if (text[index] !== "{") throw new Error("Expected { after option key");
|
|
90
|
-
index++;
|
|
91
|
-
const value = parseNodes();
|
|
92
|
-
if (text[index] !== "}") throw new Error("Expected } after option value");
|
|
93
|
-
index++;
|
|
94
|
-
options[key] = value;
|
|
95
|
-
while (index < text.length && /\s/.test(text[index])) index++;
|
|
96
|
-
}
|
|
97
|
-
index++;
|
|
98
|
-
if (type === "plural") return {
|
|
99
|
-
type: "plural",
|
|
100
|
-
name,
|
|
101
|
-
options
|
|
102
|
-
};
|
|
103
|
-
else if (type === "select") return {
|
|
104
|
-
type: "select",
|
|
105
|
-
name,
|
|
106
|
-
options
|
|
107
|
-
};
|
|
108
|
-
} else {
|
|
109
|
-
let style = "";
|
|
110
|
-
while (index < text.length && text[index] !== "}") {
|
|
111
|
-
style += text[index];
|
|
112
|
-
index++;
|
|
113
|
-
}
|
|
114
|
-
if (index >= text.length) throw new Error("Unclosed argument");
|
|
115
|
-
style = style.trim();
|
|
116
|
-
index++;
|
|
117
|
-
return {
|
|
118
|
-
type: "argument",
|
|
119
|
-
name,
|
|
120
|
-
format: {
|
|
121
|
-
type,
|
|
122
|
-
style
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
throw new Error("Malformed argument");
|
|
129
|
-
};
|
|
130
|
-
return parseNodes();
|
|
131
|
-
};
|
|
132
|
-
const icuNodesToIntlayer = (nodes) => {
|
|
133
|
-
if (nodes.length === 0) return "";
|
|
134
|
-
if (nodes.length === 1 && typeof nodes[0] === "string") {
|
|
135
|
-
const node = nodes[0];
|
|
136
|
-
if (/<[a-zA-Z0-9-]+[^>]*>/.test(node)) return html(node);
|
|
137
|
-
return node;
|
|
138
|
-
}
|
|
139
|
-
if (nodes.every((node) => typeof node === "string" || node.type === "argument")) {
|
|
140
|
-
let str = "";
|
|
141
|
-
for (const node of nodes) if (typeof node === "string") str += node;
|
|
142
|
-
else if (typeof node !== "string" && node.type === "argument") if (node.format) str += `{${node.name}, ${node.format.type}${node.format.style ? `, ${node.format.style}` : ""}}`;
|
|
143
|
-
else str += `{{${node.name}}}`;
|
|
144
|
-
if (/<[a-zA-Z0-9-]+[^>]*>/.test(str)) return html(str);
|
|
145
|
-
return insertion(str);
|
|
146
|
-
}
|
|
147
|
-
if (nodes.length === 1) {
|
|
148
|
-
const node = nodes[0];
|
|
149
|
-
if (typeof node === "string") {
|
|
150
|
-
if (/<[a-zA-Z0-9-]+[^>]*>/.test(node)) return html(node);
|
|
151
|
-
return node;
|
|
152
|
-
}
|
|
153
|
-
if (node.type === "argument") {
|
|
154
|
-
if (node.format) return insertion(`{${node.name}, ${node.format.type}${node.format.style ? `, ${node.format.style}` : ""}}`);
|
|
155
|
-
return insertion(`{{${node.name}}}`);
|
|
156
|
-
}
|
|
157
|
-
if (node.type === "plural") {
|
|
158
|
-
const options = {};
|
|
159
|
-
for (const [key, val] of Object.entries(node.options)) {
|
|
160
|
-
let newKey = key;
|
|
161
|
-
if (key.startsWith("=")) newKey = key.substring(1);
|
|
162
|
-
else if (key === "one") newKey = "1";
|
|
163
|
-
else if (key === "two") newKey = "2";
|
|
164
|
-
else if (key === "few") newKey = "<=3";
|
|
165
|
-
else if (key === "many") newKey = ">=4";
|
|
166
|
-
else if (key === "other") newKey = "fallback";
|
|
167
|
-
options[newKey] = icuNodesToIntlayer(val.map((v) => {
|
|
168
|
-
if (typeof v === "string") return v.replace(/#/g, `{{${node.name}}}`);
|
|
169
|
-
return v;
|
|
170
|
-
}));
|
|
171
|
-
}
|
|
172
|
-
options.__intlayer_icu_var = node.name;
|
|
173
|
-
return enumeration(options);
|
|
174
|
-
}
|
|
175
|
-
if (node.type === "select") {
|
|
176
|
-
const options = {};
|
|
177
|
-
for (const [key, val] of Object.entries(node.options)) options[key] = icuNodesToIntlayer(val);
|
|
178
|
-
const optionKeys = Object.keys(options);
|
|
179
|
-
if ((options.male || options.female) && optionKeys.every((k) => [
|
|
180
|
-
"male",
|
|
181
|
-
"female",
|
|
182
|
-
"other",
|
|
183
|
-
"fallback"
|
|
184
|
-
].includes(k))) return gender({
|
|
185
|
-
fallback: options.other,
|
|
186
|
-
male: options.male,
|
|
187
|
-
female: options.female
|
|
188
|
-
});
|
|
189
|
-
options.__intlayer_icu_var = node.name;
|
|
190
|
-
return enumeration(options);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return nodes.map((node) => icuNodesToIntlayer([node]));
|
|
194
|
-
};
|
|
195
|
-
const icuToIntlayerPlugin = {
|
|
196
|
-
canHandle: (node) => typeof node === "string" && (node.includes("{") || node.includes("}") || /<[a-zA-Z0-9-]+[^>]*>/.test(node)),
|
|
197
|
-
transform: (node) => {
|
|
198
|
-
try {
|
|
199
|
-
return icuNodesToIntlayer(parseICU(node));
|
|
200
|
-
} catch {
|
|
201
|
-
return node;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
const intlayerToIcuPlugin = {
|
|
206
|
-
canHandle: (node) => typeof node === "string" && (node.includes("{") || node.includes("}")) || node && typeof node === "object" && (node.nodeType === NodeType.Insertion || node.nodeType === NodeType.HTML || node.nodeType === NodeType.Enumeration || node.nodeType === NodeType.Gender || node.nodeType === "composite") || Array.isArray(node),
|
|
207
|
-
transform: (node, props, next) => {
|
|
208
|
-
if (typeof node === "string") return node.replace(/\{\{([^}]+)\}\}/g, "{$1}");
|
|
209
|
-
if (node.nodeType === NodeType.Insertion) return node.insertion.replace(/\{\{([^}]+)\}\}/g, "{$1}");
|
|
210
|
-
if (node.nodeType === NodeType.HTML) return node.html;
|
|
211
|
-
if (node.nodeType === NodeType.Enumeration) {
|
|
212
|
-
const options = node.enumeration;
|
|
213
|
-
const transformedOptions = {};
|
|
214
|
-
for (const [key, val] of Object.entries(options)) {
|
|
215
|
-
if (key === "__intlayer_icu_var") continue;
|
|
216
|
-
const childVal = next(val, props);
|
|
217
|
-
transformedOptions[key] = typeof childVal === "string" ? childVal : JSON.stringify(childVal);
|
|
218
|
-
}
|
|
219
|
-
let varName = options.__intlayer_icu_var || "n";
|
|
220
|
-
if (!options.__intlayer_icu_var) {
|
|
221
|
-
const match = (transformedOptions.fallback || transformedOptions.other || Object.values(transformedOptions)[0]).match(/\{([a-zA-Z0-9_]+)\}(?!,)/);
|
|
222
|
-
if (match) varName = match[1];
|
|
223
|
-
}
|
|
224
|
-
const keys = Object.keys(transformedOptions);
|
|
225
|
-
const pluralKeys = [
|
|
226
|
-
"1",
|
|
227
|
-
"2",
|
|
228
|
-
"<=3",
|
|
229
|
-
">=4",
|
|
230
|
-
"fallback",
|
|
231
|
-
"other",
|
|
232
|
-
"zero",
|
|
233
|
-
"one",
|
|
234
|
-
"two",
|
|
235
|
-
"few",
|
|
236
|
-
"many"
|
|
237
|
-
];
|
|
238
|
-
const isPlural = keys.every((k) => pluralKeys.includes(k) || /^[<>=]?\d+(\.\d+)?$/.test(k));
|
|
239
|
-
const parts = [];
|
|
240
|
-
if (isPlural) {
|
|
241
|
-
for (const [key, val] of Object.entries(transformedOptions)) {
|
|
242
|
-
let icuKey = key;
|
|
243
|
-
if (key === "fallback") icuKey = "other";
|
|
244
|
-
else if (key === "<=3") icuKey = "few";
|
|
245
|
-
else if (key === ">=4") icuKey = "many";
|
|
246
|
-
else if (/^\d+$/.test(key)) icuKey = `=${key}`;
|
|
247
|
-
else if ([
|
|
248
|
-
"zero",
|
|
249
|
-
"few",
|
|
250
|
-
"many"
|
|
251
|
-
].includes(key)) icuKey = key;
|
|
252
|
-
else icuKey = "other";
|
|
253
|
-
let strVal = val;
|
|
254
|
-
strVal = strVal.replace(new RegExp(`\\{${varName}\\}`, "g"), "#");
|
|
255
|
-
parts.push(`${icuKey} {${strVal}}`);
|
|
256
|
-
}
|
|
257
|
-
return `{${varName}, plural, ${parts.join(" ")}}`;
|
|
258
|
-
} else {
|
|
259
|
-
const entries = Object.entries(transformedOptions).sort(([keyA], [keyB]) => {
|
|
260
|
-
if (keyA === "fallback" || keyA === "other") return 1;
|
|
261
|
-
if (keyB === "fallback" || keyB === "other") return -1;
|
|
262
|
-
return 0;
|
|
263
|
-
});
|
|
264
|
-
for (const [key, val] of entries) {
|
|
265
|
-
let icuKey = key;
|
|
266
|
-
if (key === "fallback") icuKey = "other";
|
|
267
|
-
parts.push(`${icuKey} {${val}}`);
|
|
268
|
-
}
|
|
269
|
-
return `{${varName}, select, ${parts.join(" ")}}`;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
if (node.nodeType === NodeType.Gender) {
|
|
273
|
-
const options = node.gender;
|
|
274
|
-
const varName = "gender";
|
|
275
|
-
const parts = [];
|
|
276
|
-
const entries = Object.entries(options).sort(([keyA], [keyB]) => {
|
|
277
|
-
if (keyA === "fallback") return 1;
|
|
278
|
-
if (keyB === "fallback") return -1;
|
|
279
|
-
return 0;
|
|
280
|
-
});
|
|
281
|
-
for (const [key, val] of entries) {
|
|
282
|
-
let icuKey = key;
|
|
283
|
-
if (key === "fallback") icuKey = "other";
|
|
284
|
-
const childVal = next(val, props);
|
|
285
|
-
const strVal = typeof childVal === "string" ? childVal : JSON.stringify(childVal);
|
|
286
|
-
parts.push(`${icuKey} {${strVal}}`);
|
|
287
|
-
}
|
|
288
|
-
return `{${varName}, select, ${parts.join(" ")}}`;
|
|
289
|
-
}
|
|
290
|
-
if (Array.isArray(node) || node.nodeType === "composite" && Array.isArray(node.composite)) return (Array.isArray(node) ? node : node.composite).map((item) => next(item, props)).join("");
|
|
291
|
-
return next(node, props);
|
|
292
|
-
}
|
|
293
|
-
};
|
|
294
|
-
const intlayerToICUFormatter = (message) => {
|
|
295
|
-
return deepTransformNode(message, {
|
|
296
|
-
dictionaryKey: "icu",
|
|
297
|
-
keyPath: [],
|
|
298
|
-
plugins: [{
|
|
299
|
-
id: "icu",
|
|
300
|
-
...intlayerToIcuPlugin
|
|
301
|
-
}]
|
|
302
|
-
});
|
|
303
|
-
};
|
|
304
|
-
const icuToIntlayerFormatter = (message) => {
|
|
305
|
-
return deepTransformNode(message, {
|
|
306
|
-
dictionaryKey: "icu",
|
|
307
|
-
keyPath: [],
|
|
308
|
-
plugins: [{
|
|
309
|
-
id: "icu",
|
|
310
|
-
...icuToIntlayerPlugin
|
|
311
|
-
}]
|
|
312
|
-
});
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
//#endregion
|
|
316
|
-
export { icuToIntlayerFormatter, intlayerToICUFormatter };
|
|
1
|
+
import{deepTransformNode as e}from"../interpreter/getContent/deepTransform.mjs";import{enu as t}from"../transpiler/enumeration/enumeration.mjs";import{gender as n}from"../transpiler/gender/gender.mjs";import{html as r}from"../transpiler/html/html.mjs";import{insert as i}from"../transpiler/insertion/insertion.mjs";import{NodeType as a}from"@intlayer/types";const o=e=>{let t=0,n=()=>{let n=[],i=``;for(;t<e.length;){let a=e[t];if(a===`{`)i&&=(n.push(i),``),t++,n.push(r());else if(a===`}`)break;else if(a===`'`)if(t+1<e.length&&e[t+1]===`'`)i+=`'`,t+=2;else{let n=e.indexOf(`'`,t+1);n===-1?(i+=`'`,t++):(i+=e.substring(t+1,n),t=n+1)}else i+=a,t++}return i&&n.push(i),n},r=()=>{let r=``;for(;t<e.length&&/[^,}]/.test(e[t]);)r+=e[t],t++;if(r=r.trim(),t>=e.length)throw Error(`Unclosed argument`);if(e[t]===`}`)return t++,{type:`argument`,name:r};if(e[t]===`,`){t++;let i=``;for(;t<e.length&&/[^,}]/.test(e[t]);)i+=e[t],t++;if(i=i.trim(),t>=e.length)throw Error(`Unclosed argument`);if(e[t]===`}`)return t++,{type:`argument`,name:r,format:{type:i}};if(e[t]===`,`)if(t++,i===`plural`||i===`select`){let a={};for(;t<e.length&&e[t]!==`}`;){for(;t<e.length&&/\s/.test(e[t]);)t++;let r=``;for(;t<e.length&&/[^{\s]/.test(e[t]);)r+=e[t],t++;for(;t<e.length&&/\s/.test(e[t]);)t++;if(e[t]!==`{`)throw Error(`Expected { after option key`);t++;let i=n();if(e[t]!==`}`)throw Error(`Expected } after option value`);for(t++,a[r]=i;t<e.length&&/\s/.test(e[t]);)t++}if(t++,i===`plural`)return{type:`plural`,name:r,options:a};if(i===`select`)return{type:`select`,name:r,options:a}}else{let n=``;for(;t<e.length&&e[t]!==`}`;)n+=e[t],t++;if(t>=e.length)throw Error(`Unclosed argument`);return n=n.trim(),t++,{type:`argument`,name:r,format:{type:i,style:n}}}}throw Error(`Malformed argument`)};return n()},s=e=>{if(e.length===0)return``;if(e.length===1&&typeof e[0]==`string`){let t=e[0];return/<[a-zA-Z0-9-]+[^>]*>/.test(t)?r(t):t}if(e.every(e=>typeof e==`string`||e.type===`argument`)){let t=``;for(let n of e)typeof n==`string`?t+=n:typeof n!=`string`&&n.type===`argument`&&(n.format?t+=`{${n.name}, ${n.format.type}${n.format.style?`, ${n.format.style}`:``}}`:t+=`{{${n.name}}}`);return/<[a-zA-Z0-9-]+[^>]*>/.test(t)?r(t):i(t)}if(e.length===1){let a=e[0];if(typeof a==`string`)return/<[a-zA-Z0-9-]+[^>]*>/.test(a)?r(a):a;if(a.type===`argument`)return a.format?i(`{${a.name}, ${a.format.type}${a.format.style?`, ${a.format.style}`:``}}`):i(`{{${a.name}}}`);if(a.type===`plural`){let e={};for(let[t,n]of Object.entries(a.options)){let r=t;t.startsWith(`=`)?r=t.substring(1):t===`one`?r=`1`:t===`two`?r=`2`:t===`few`?r=`<=3`:t===`many`?r=`>=4`:t===`other`&&(r=`fallback`),e[r]=s(n.map(e=>typeof e==`string`?e.replace(/#/g,`{{${a.name}}}`):e))}return e.__intlayer_icu_var=a.name,t(e)}if(a.type===`select`){let e={};for(let[t,n]of Object.entries(a.options))e[t]=s(n);let r=Object.keys(e);return(e.male||e.female)&&r.every(e=>[`male`,`female`,`other`,`fallback`].includes(e))?n({fallback:e.other,male:e.male,female:e.female}):(e.__intlayer_icu_var=a.name,t(e))}}return e.map(e=>s([e]))},c={canHandle:e=>typeof e==`string`&&(e.includes(`{`)||e.includes(`}`)||/<[a-zA-Z0-9-]+[^>]*>/.test(e)),transform:e=>{try{return s(o(e))}catch{return e}}},l={canHandle:e=>typeof e==`string`&&(e.includes(`{`)||e.includes(`}`))||e&&typeof e==`object`&&(e.nodeType===a.Insertion||e.nodeType===a.HTML||e.nodeType===a.Enumeration||e.nodeType===a.Gender||e.nodeType===`composite`)||Array.isArray(e),transform:(e,t,n)=>{if(typeof e==`string`)return e.replace(/\{\{([^}]+)\}\}/g,`{$1}`);if(e.nodeType===a.Insertion)return e.insertion.replace(/\{\{([^}]+)\}\}/g,`{$1}`);if(e.nodeType===a.HTML)return e.html;if(e.nodeType===a.Enumeration){let r=e.enumeration,i={};for(let[e,a]of Object.entries(r)){if(e===`__intlayer_icu_var`)continue;let r=n(a,t);i[e]=typeof r==`string`?r:JSON.stringify(r)}let a=r.__intlayer_icu_var||`n`;if(!r.__intlayer_icu_var){let e=(i.fallback||i.other||Object.values(i)[0]).match(/\{([a-zA-Z0-9_]+)\}(?!,)/);e&&(a=e[1])}let o=Object.keys(i),s=[`1`,`2`,`<=3`,`>=4`,`fallback`,`other`,`zero`,`one`,`two`,`few`,`many`],c=o.every(e=>s.includes(e)||/^[<>=]?\d+(\.\d+)?$/.test(e)),l=[];if(c){for(let[e,t]of Object.entries(i)){let n=e;n=e===`fallback`?`other`:e===`<=3`?`few`:e===`>=4`?`many`:/^\d+$/.test(e)?`=${e}`:[`zero`,`few`,`many`].includes(e)?e:`other`;let r=t;r=r.replace(RegExp(`\\{${a}\\}`,`g`),`#`),l.push(`${n} {${r}}`)}return`{${a}, plural, ${l.join(` `)}}`}else{let e=Object.entries(i).sort(([e],[t])=>e===`fallback`||e===`other`?1:t===`fallback`||t===`other`?-1:0);for(let[t,n]of e){let e=t;t===`fallback`&&(e=`other`),l.push(`${e} {${n}}`)}return`{${a}, select, ${l.join(` `)}}`}}if(e.nodeType===a.Gender){let r=e.gender,i=[],a=Object.entries(r).sort(([e],[t])=>e===`fallback`?1:t===`fallback`?-1:0);for(let[e,r]of a){let a=e;e===`fallback`&&(a=`other`);let o=n(r,t),s=typeof o==`string`?o:JSON.stringify(o);i.push(`${a} {${s}}`)}return`{gender, select, ${i.join(` `)}}`}return Array.isArray(e)||e.nodeType===`composite`&&Array.isArray(e.composite)?(Array.isArray(e)?e:e.composite).map(e=>n(e,t)).join(``):n(e,t)}},u=t=>e(t,{dictionaryKey:`icu`,keyPath:[],plugins:[{id:`icu`,...l}]}),d=t=>e(t,{dictionaryKey:`icu`,keyPath:[],plugins:[{id:`icu`,...c}]});export{d as icuToIntlayerFormatter,u as intlayerToICUFormatter};
|
|
317
2
|
//# sourceMappingURL=ICU.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ICU.mjs","names":["insert","enu"],"sources":["../../../src/messageFormat/ICU.ts"],"sourcesContent":["import { type Dictionary, NodeType } from '@intlayer/types';\nimport { deepTransformNode } from '../interpreter';\nimport { enu, gender, html, insert } from '../transpiler';\n\n/**\n * ICU MessageFormat Converter\n *\n * This module converts between ICU MessageFormat and Intlayer's internal format.\n *\n * IMPORTANT: Two different formats are used:\n *\n * 1. ICU MessageFormat (external format):\n * - Simple variables: {name}\n * - Formatted variables: {amount, number, currency}\n * - Plural: {count, plural, =0 {none} other {# items}}\n * - Select: {gender, select, male {He} female {She} other {They}}\n *\n * 2. Intlayer Internal Format:\n * - Simple variables: {{name}} (double braces for clarity and to distinguish from literal text)\n * - Formatted variables: {amount, number, currency} (keeps ICU format)\n * - Plural: enu({ 0: 'none', fallback: '{{count}} items' })\n * - Select/Gender: gender({ male: 'He', female: 'She', fallback: 'They' })\n *\n * Conversion flow:\n * - ICU → Intlayer: {name} → {{name}}\n * - Intlayer → ICU: {{name}} → {name}\n *\n * The double braces in Intlayer format serve to:\n * - Distinguish variables from literal text containing braces\n * - Work with getInsertion() runtime function which expects {{var}} patterns\n * - Provide clear visual distinction in content dictionaries\n */\n\n// Types for our AST\ntype ICUNode =\n | string\n | {\n type: 'argument';\n name: string;\n format?: { type: string; style?: string };\n }\n | { type: 'plural'; name: string; options: Record<string, ICUNode[]> }\n | { type: 'select'; name: string; options: Record<string, ICUNode[]> };\n\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\n\nconst parseICU = (text: string): ICUNode[] => {\n let index = 0;\n\n const parseNodes = (): ICUNode[] => {\n const nodes: ICUNode[] = [];\n let currentText = '';\n\n while (index < text.length) {\n const char = text[index];\n\n if (char === '{') {\n if (currentText) {\n nodes.push(currentText);\n currentText = '';\n }\n index++; // skip {\n nodes.push(parseArgument());\n } else if (char === '}') {\n // End of current block\n break;\n } else if (char === \"'\") {\n // Escaping\n if (index + 1 < text.length && text[index + 1] === \"'\") {\n currentText += \"'\";\n index += 2;\n } else {\n // Find next quote\n const nextQuote = text.indexOf(\"'\", index + 1);\n if (nextQuote !== -1) {\n // Determine if this is escaping syntax characters\n // For simplicity, we'll treat content between single quotes as literal\n // provided it contains syntax chars.\n // Standard ICU: ' quoted string '\n // If it is just an apostrophe, it should be doubled.\n // But simplified: take content between quotes literally.\n currentText += text.substring(index + 1, nextQuote);\n index = nextQuote + 1;\n } else {\n currentText += \"'\";\n index++;\n }\n }\n } else {\n currentText += char;\n index++;\n }\n }\n\n if (currentText) {\n nodes.push(currentText);\n }\n return nodes;\n };\n\n const parseArgument = (): ICUNode => {\n // We are past '{'\n // Parse name\n let name = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n name += text[index];\n index++;\n }\n name = name.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name };\n }\n\n // Must be comma\n if (text[index] === ',') {\n index++;\n // Parse type\n let type = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n type += text[index];\n index++;\n }\n type = type.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name, format: { type } };\n }\n\n if (text[index] === ',') {\n index++;\n\n // If plural or select, parse options\n if (type === 'plural' || type === 'select') {\n // Parse options\n const options: Record<string, ICUNode[]> = {};\n\n while (index < text.length && text[index] !== '}') {\n // skip whitespace\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n // parse key\n let key = '';\n while (index < text.length && /[^{\\s]/.test(text[index])) {\n key += text[index];\n index++;\n }\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n if (text[index] !== '{')\n throw new Error('Expected { after option key');\n index++; // skip {\n\n const value = parseNodes();\n\n if (text[index] !== '}')\n throw new Error('Expected } after option value');\n index++; // skip }\n\n options[key] = value;\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n }\n\n index++; // skip closing argument }\n\n if (type === 'plural') {\n return { type: 'plural', name, options };\n } else if (type === 'select') {\n return { type: 'select', name, options };\n }\n } else {\n // Parse style for number/date/time\n let style = '';\n while (index < text.length && text[index] !== '}') {\n style += text[index];\n index++;\n }\n if (index >= text.length) throw new Error('Unclosed argument');\n\n style = style.trim();\n index++; // skip }\n\n return { type: 'argument', name, format: { type, style } };\n }\n }\n }\n\n throw new Error('Malformed argument');\n };\n\n return parseNodes();\n};\n\nconst icuNodesToIntlayer = (nodes: ICUNode[]): any => {\n if (nodes.length === 0) return '';\n if (nodes.length === 1 && typeof nodes[0] === 'string') {\n const node = nodes[0];\n if (/<[a-zA-Z0-9-]+[^>]*>/.test(node)) {\n return html(node);\n }\n return node;\n }\n\n // Check if we can flatten to a single string (insert)\n const canFlatten = nodes.every(\n (node) => typeof node === 'string' || node.type === 'argument'\n );\n if (canFlatten) {\n let str = '';\n for (const node of nodes) {\n if (typeof node === 'string') {\n str += node;\n } else if (typeof node !== 'string' && node.type === 'argument') {\n if (node.format) {\n // Formatted variables keep ICU format: {var, type, style}\n str += `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`;\n } else {\n // Simple variables use Intlayer format: {{var}}\n str += `{{${node.name}}}`;\n }\n }\n }\n if (/<[a-zA-Z0-9-]+[^>]*>/.test(str)) {\n return html(str);\n }\n return insert(str);\n }\n\n // Mix of string and complex types.\n // If we have just one complex type and it covers everything?\n if (nodes.length === 1) {\n const node = nodes[0];\n\n if (typeof node === 'string') {\n if (/<[a-zA-Z0-9-]+[^>]*>/.test(node)) {\n return html(node);\n }\n return node;\n }\n if (node.type === 'argument') {\n if (node.format) {\n return insert(\n `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`\n );\n }\n return insert(`{{${node.name}}}`);\n }\n if (node.type === 'plural') {\n const options: Record<string, any> = {};\n\n for (const [key, val] of Object.entries(node.options)) {\n // Map ICU keys to Intlayer keys\n let newKey = key;\n if (key.startsWith('=')) {\n newKey = key.substring(1); // =0 -> 0\n } else if (key === 'one') {\n newKey = '1';\n } else if (key === 'two') {\n newKey = '2';\n } else if (key === 'few') {\n newKey = '<=3';\n } else if (key === 'many') {\n newKey = '>=4';\n } else if (key === 'other') {\n newKey = 'fallback';\n }\n // Handle # in plural value\n // For plural, we need to pass the variable name down or replace #\n // Intlayer uses {{n}} (or whatever var name) for simple variables\n // We should replace # with {{n}} in the string parts of val\n const replacedVal = val.map((v) => {\n if (typeof v === 'string') {\n return v.replace(/#/g, `{{${node.name}}}`);\n }\n return v;\n });\n\n options[newKey] = icuNodesToIntlayer(replacedVal);\n }\n\n // Preserve variable name\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n }\n if (node.type === 'select') {\n const options: Record<string, any> = {};\n\n for (const [key, val] of Object.entries(node.options)) {\n options[key] = icuNodesToIntlayer(val);\n }\n\n // Check if it looks like gender\n const optionKeys = Object.keys(options);\n // It is gender if it has 'male' OR 'female' AND only contains gender keys (male, female, other)\n const isGender =\n (options.male || options.female) &&\n optionKeys.every((k) =>\n ['male', 'female', 'other', 'fallback'].includes(k)\n );\n\n if (isGender) {\n return gender({\n fallback: options.other,\n male: options.male,\n female: options.female,\n });\n }\n\n // Preserve variable name\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n }\n }\n\n // If multiple nodes, return array\n return nodes.map((node) => icuNodesToIntlayer([node]));\n};\n\nconst icuToIntlayerPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' &&\n (node.includes('{') ||\n node.includes('}') ||\n /<[a-zA-Z0-9-]+[^>]*>/.test(node)),\n transform: (node: any) => {\n try {\n const ast = parseICU(node);\n return icuNodesToIntlayer(ast);\n } catch {\n // If parsing fails, return original string\n return node;\n }\n },\n};\n\nconst intlayerToIcuPlugin = {\n canHandle: (node: any) =>\n (typeof node === 'string' && (node.includes('{') || node.includes('}'))) ||\n (node &&\n typeof node === 'object' &&\n (node.nodeType === NodeType.Insertion ||\n node.nodeType === NodeType.HTML ||\n node.nodeType === NodeType.Enumeration ||\n node.nodeType === NodeType.Gender ||\n node.nodeType === 'composite')) ||\n Array.isArray(node),\n transform: (node: any, props: any, next: any) => {\n // Convert Intlayer's double-brace format {{var}} to ICU's single-brace format {var}\n if (typeof node === 'string') {\n return node.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeType.Insertion) {\n // Convert Intlayer format to ICU format:\n // - {{name}} → {name} (simple variable)\n // - {amount, number, currency} → {amount, number, currency} (formatted variable, already in ICU format)\n return node.insertion.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeType.HTML) {\n return node.html;\n }\n\n if (node.nodeType === NodeType.Enumeration) {\n const options = node.enumeration;\n\n // Transform all values first\n const transformedOptions: Record<string, string> = {};\n for (const [key, val] of Object.entries(options)) {\n if (key === '__intlayer_icu_var') continue;\n const childVal = next(val, props);\n transformedOptions[key] =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n }\n\n // Infer variable name\n let varName = options.__intlayer_icu_var || 'n';\n\n if (!options.__intlayer_icu_var) {\n const fallbackVal =\n transformedOptions.fallback ||\n transformedOptions.other ||\n Object.values(transformedOptions)[0];\n // Match {variable} but avoid {variable, ...} (which are nested ICUs)\n // Actually nested ICU starts with {var, ...\n // Simple variable is {var}\n // We look for {var} that is NOT followed by ,\n const match = fallbackVal.match(/\\{([a-zA-Z0-9_]+)\\}(?!,)/);\n if (match) {\n varName = match[1];\n }\n }\n\n const keys = Object.keys(transformedOptions);\n const pluralKeys = [\n '1',\n '2',\n '<=3',\n '>=4',\n 'fallback',\n 'other',\n 'zero',\n 'one',\n 'two',\n 'few',\n 'many',\n ];\n // Also check for numbers\n const isPlural = keys.every(\n (k) => pluralKeys.includes(k) || /^[<>=]?\\d+(\\.\\d+)?$/.test(k)\n );\n\n const parts = [];\n\n if (isPlural) {\n for (const [key, val] of Object.entries(transformedOptions)) {\n let icuKey = key;\n\n if (key === 'fallback') icuKey = 'other';\n else if (key === '<=3') icuKey = 'few';\n else if (key === '>=4') icuKey = 'many';\n else if (/^\\d+$/.test(key)) icuKey = `=${key}`;\n else if (['zero', 'few', 'many'].includes(key)) icuKey = key;\n else icuKey = 'other';\n\n let strVal = val;\n\n // Replace {varName} with #\n // Note: next() has already converted {{var}} -> {var}\n strVal = strVal.replace(new RegExp(`\\\\{${varName}\\\\}`, 'g'), '#');\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n\n return `{${varName}, plural, ${parts.join(' ')}}`;\n } else {\n // Select\n const entries = Object.entries(transformedOptions).sort(\n ([keyA], [keyB]) => {\n if (keyA === 'fallback' || keyA === 'other') return 1;\n if (keyB === 'fallback' || keyB === 'other') return -1;\n return 0;\n }\n );\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n // Do NOT map other keys to 'other'. Keep 'active', 'inactive', etc.\n\n parts.push(`${icuKey} {${val}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n }\n\n if (node.nodeType === NodeType.Gender) {\n const options = node.gender;\n const varName = 'gender';\n const parts = [];\n\n const entries = Object.entries(options).sort(([keyA], [keyB]) => {\n if (keyA === 'fallback') return 1;\n if (keyB === 'fallback') return -1;\n return 0;\n });\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n\n const childVal = next(val, props);\n const strVal =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n\n if (\n Array.isArray(node) ||\n (node.nodeType === 'composite' && Array.isArray(node.composite))\n ) {\n // handle array/composite\n const arr = Array.isArray(node) ? node : node.composite;\n const items = arr.map((item: any) => next(item, props));\n return items.join('');\n }\n\n return next(node, props);\n },\n};\n\nexport const intlayerToICUFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'icu',\n keyPath: [],\n plugins: [{ id: 'icu', ...intlayerToIcuPlugin }],\n });\n};\n\nexport const icuToIntlayerFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'icu',\n keyPath: [],\n plugins: [{ id: 'icu', ...icuToIntlayerPlugin }],\n });\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ICU.mjs","names":["insert","enu"],"sources":["../../../src/messageFormat/ICU.ts"],"sourcesContent":["import { type Dictionary, NodeType } from '@intlayer/types';\nimport { deepTransformNode } from '../interpreter';\nimport { enu, gender, html, insert } from '../transpiler';\n\n/**\n * ICU MessageFormat Converter\n *\n * This module converts between ICU MessageFormat and Intlayer's internal format.\n *\n * IMPORTANT: Two different formats are used:\n *\n * 1. ICU MessageFormat (external format):\n * - Simple variables: {name}\n * - Formatted variables: {amount, number, currency}\n * - Plural: {count, plural, =0 {none} other {# items}}\n * - Select: {gender, select, male {He} female {She} other {They}}\n *\n * 2. Intlayer Internal Format:\n * - Simple variables: {{name}} (double braces for clarity and to distinguish from literal text)\n * - Formatted variables: {amount, number, currency} (keeps ICU format)\n * - Plural: enu({ 0: 'none', fallback: '{{count}} items' })\n * - Select/Gender: gender({ male: 'He', female: 'She', fallback: 'They' })\n *\n * Conversion flow:\n * - ICU → Intlayer: {name} → {{name}}\n * - Intlayer → ICU: {{name}} → {name}\n *\n * The double braces in Intlayer format serve to:\n * - Distinguish variables from literal text containing braces\n * - Work with getInsertion() runtime function which expects {{var}} patterns\n * - Provide clear visual distinction in content dictionaries\n */\n\n// Types for our AST\ntype ICUNode =\n | string\n | {\n type: 'argument';\n name: string;\n format?: { type: string; style?: string };\n }\n | { type: 'plural'; name: string; options: Record<string, ICUNode[]> }\n | { type: 'select'; name: string; options: Record<string, ICUNode[]> };\n\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\n\nconst parseICU = (text: string): ICUNode[] => {\n let index = 0;\n\n const parseNodes = (): ICUNode[] => {\n const nodes: ICUNode[] = [];\n let currentText = '';\n\n while (index < text.length) {\n const char = text[index];\n\n if (char === '{') {\n if (currentText) {\n nodes.push(currentText);\n currentText = '';\n }\n index++; // skip {\n nodes.push(parseArgument());\n } else if (char === '}') {\n // End of current block\n break;\n } else if (char === \"'\") {\n // Escaping\n if (index + 1 < text.length && text[index + 1] === \"'\") {\n currentText += \"'\";\n index += 2;\n } else {\n // Find next quote\n const nextQuote = text.indexOf(\"'\", index + 1);\n if (nextQuote !== -1) {\n // Determine if this is escaping syntax characters\n // For simplicity, we'll treat content between single quotes as literal\n // provided it contains syntax chars.\n // Standard ICU: ' quoted string '\n // If it is just an apostrophe, it should be doubled.\n // But simplified: take content between quotes literally.\n currentText += text.substring(index + 1, nextQuote);\n index = nextQuote + 1;\n } else {\n currentText += \"'\";\n index++;\n }\n }\n } else {\n currentText += char;\n index++;\n }\n }\n\n if (currentText) {\n nodes.push(currentText);\n }\n return nodes;\n };\n\n const parseArgument = (): ICUNode => {\n // We are past '{'\n // Parse name\n let name = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n name += text[index];\n index++;\n }\n name = name.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name };\n }\n\n // Must be comma\n if (text[index] === ',') {\n index++;\n // Parse type\n let type = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n type += text[index];\n index++;\n }\n type = type.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name, format: { type } };\n }\n\n if (text[index] === ',') {\n index++;\n\n // If plural or select, parse options\n if (type === 'plural' || type === 'select') {\n // Parse options\n const options: Record<string, ICUNode[]> = {};\n\n while (index < text.length && text[index] !== '}') {\n // skip whitespace\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n // parse key\n let key = '';\n while (index < text.length && /[^{\\s]/.test(text[index])) {\n key += text[index];\n index++;\n }\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n if (text[index] !== '{')\n throw new Error('Expected { after option key');\n index++; // skip {\n\n const value = parseNodes();\n\n if (text[index] !== '}')\n throw new Error('Expected } after option value');\n index++; // skip }\n\n options[key] = value;\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n }\n\n index++; // skip closing argument }\n\n if (type === 'plural') {\n return { type: 'plural', name, options };\n } else if (type === 'select') {\n return { type: 'select', name, options };\n }\n } else {\n // Parse style for number/date/time\n let style = '';\n while (index < text.length && text[index] !== '}') {\n style += text[index];\n index++;\n }\n if (index >= text.length) throw new Error('Unclosed argument');\n\n style = style.trim();\n index++; // skip }\n\n return { type: 'argument', name, format: { type, style } };\n }\n }\n }\n\n throw new Error('Malformed argument');\n };\n\n return parseNodes();\n};\n\nconst icuNodesToIntlayer = (nodes: ICUNode[]): any => {\n if (nodes.length === 0) return '';\n if (nodes.length === 1 && typeof nodes[0] === 'string') {\n const node = nodes[0];\n if (/<[a-zA-Z0-9-]+[^>]*>/.test(node)) {\n return html(node);\n }\n return node;\n }\n\n // Check if we can flatten to a single string (insert)\n const canFlatten = nodes.every(\n (node) => typeof node === 'string' || node.type === 'argument'\n );\n if (canFlatten) {\n let str = '';\n for (const node of nodes) {\n if (typeof node === 'string') {\n str += node;\n } else if (typeof node !== 'string' && node.type === 'argument') {\n if (node.format) {\n // Formatted variables keep ICU format: {var, type, style}\n str += `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`;\n } else {\n // Simple variables use Intlayer format: {{var}}\n str += `{{${node.name}}}`;\n }\n }\n }\n if (/<[a-zA-Z0-9-]+[^>]*>/.test(str)) {\n return html(str);\n }\n return insert(str);\n }\n\n // Mix of string and complex types.\n // If we have just one complex type and it covers everything?\n if (nodes.length === 1) {\n const node = nodes[0];\n\n if (typeof node === 'string') {\n if (/<[a-zA-Z0-9-]+[^>]*>/.test(node)) {\n return html(node);\n }\n return node;\n }\n if (node.type === 'argument') {\n if (node.format) {\n return insert(\n `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`\n );\n }\n return insert(`{{${node.name}}}`);\n }\n if (node.type === 'plural') {\n const options: Record<string, any> = {};\n\n for (const [key, val] of Object.entries(node.options)) {\n // Map ICU keys to Intlayer keys\n let newKey = key;\n if (key.startsWith('=')) {\n newKey = key.substring(1); // =0 -> 0\n } else if (key === 'one') {\n newKey = '1';\n } else if (key === 'two') {\n newKey = '2';\n } else if (key === 'few') {\n newKey = '<=3';\n } else if (key === 'many') {\n newKey = '>=4';\n } else if (key === 'other') {\n newKey = 'fallback';\n }\n // Handle # in plural value\n // For plural, we need to pass the variable name down or replace #\n // Intlayer uses {{n}} (or whatever var name) for simple variables\n // We should replace # with {{n}} in the string parts of val\n const replacedVal = val.map((v) => {\n if (typeof v === 'string') {\n return v.replace(/#/g, `{{${node.name}}}`);\n }\n return v;\n });\n\n options[newKey] = icuNodesToIntlayer(replacedVal);\n }\n\n // Preserve variable name\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n }\n if (node.type === 'select') {\n const options: Record<string, any> = {};\n\n for (const [key, val] of Object.entries(node.options)) {\n options[key] = icuNodesToIntlayer(val);\n }\n\n // Check if it looks like gender\n const optionKeys = Object.keys(options);\n // It is gender if it has 'male' OR 'female' AND only contains gender keys (male, female, other)\n const isGender =\n (options.male || options.female) &&\n optionKeys.every((k) =>\n ['male', 'female', 'other', 'fallback'].includes(k)\n );\n\n if (isGender) {\n return gender({\n fallback: options.other,\n male: options.male,\n female: options.female,\n });\n }\n\n // Preserve variable name\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n }\n }\n\n // If multiple nodes, return array\n return nodes.map((node) => icuNodesToIntlayer([node]));\n};\n\nconst icuToIntlayerPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' &&\n (node.includes('{') ||\n node.includes('}') ||\n /<[a-zA-Z0-9-]+[^>]*>/.test(node)),\n transform: (node: any) => {\n try {\n const ast = parseICU(node);\n return icuNodesToIntlayer(ast);\n } catch {\n // If parsing fails, return original string\n return node;\n }\n },\n};\n\nconst intlayerToIcuPlugin = {\n canHandle: (node: any) =>\n (typeof node === 'string' && (node.includes('{') || node.includes('}'))) ||\n (node &&\n typeof node === 'object' &&\n (node.nodeType === NodeType.Insertion ||\n node.nodeType === NodeType.HTML ||\n node.nodeType === NodeType.Enumeration ||\n node.nodeType === NodeType.Gender ||\n node.nodeType === 'composite')) ||\n Array.isArray(node),\n transform: (node: any, props: any, next: any) => {\n // Convert Intlayer's double-brace format {{var}} to ICU's single-brace format {var}\n if (typeof node === 'string') {\n return node.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeType.Insertion) {\n // Convert Intlayer format to ICU format:\n // - {{name}} → {name} (simple variable)\n // - {amount, number, currency} → {amount, number, currency} (formatted variable, already in ICU format)\n return node.insertion.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeType.HTML) {\n return node.html;\n }\n\n if (node.nodeType === NodeType.Enumeration) {\n const options = node.enumeration;\n\n // Transform all values first\n const transformedOptions: Record<string, string> = {};\n for (const [key, val] of Object.entries(options)) {\n if (key === '__intlayer_icu_var') continue;\n const childVal = next(val, props);\n transformedOptions[key] =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n }\n\n // Infer variable name\n let varName = options.__intlayer_icu_var || 'n';\n\n if (!options.__intlayer_icu_var) {\n const fallbackVal =\n transformedOptions.fallback ||\n transformedOptions.other ||\n Object.values(transformedOptions)[0];\n // Match {variable} but avoid {variable, ...} (which are nested ICUs)\n // Actually nested ICU starts with {var, ...\n // Simple variable is {var}\n // We look for {var} that is NOT followed by ,\n const match = fallbackVal.match(/\\{([a-zA-Z0-9_]+)\\}(?!,)/);\n if (match) {\n varName = match[1];\n }\n }\n\n const keys = Object.keys(transformedOptions);\n const pluralKeys = [\n '1',\n '2',\n '<=3',\n '>=4',\n 'fallback',\n 'other',\n 'zero',\n 'one',\n 'two',\n 'few',\n 'many',\n ];\n // Also check for numbers\n const isPlural = keys.every(\n (k) => pluralKeys.includes(k) || /^[<>=]?\\d+(\\.\\d+)?$/.test(k)\n );\n\n const parts = [];\n\n if (isPlural) {\n for (const [key, val] of Object.entries(transformedOptions)) {\n let icuKey = key;\n\n if (key === 'fallback') icuKey = 'other';\n else if (key === '<=3') icuKey = 'few';\n else if (key === '>=4') icuKey = 'many';\n else if (/^\\d+$/.test(key)) icuKey = `=${key}`;\n else if (['zero', 'few', 'many'].includes(key)) icuKey = key;\n else icuKey = 'other';\n\n let strVal = val;\n\n // Replace {varName} with #\n // Note: next() has already converted {{var}} -> {var}\n strVal = strVal.replace(new RegExp(`\\\\{${varName}\\\\}`, 'g'), '#');\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n\n return `{${varName}, plural, ${parts.join(' ')}}`;\n } else {\n // Select\n const entries = Object.entries(transformedOptions).sort(\n ([keyA], [keyB]) => {\n if (keyA === 'fallback' || keyA === 'other') return 1;\n if (keyB === 'fallback' || keyB === 'other') return -1;\n return 0;\n }\n );\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n // Do NOT map other keys to 'other'. Keep 'active', 'inactive', etc.\n\n parts.push(`${icuKey} {${val}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n }\n\n if (node.nodeType === NodeType.Gender) {\n const options = node.gender;\n const varName = 'gender';\n const parts = [];\n\n const entries = Object.entries(options).sort(([keyA], [keyB]) => {\n if (keyA === 'fallback') return 1;\n if (keyB === 'fallback') return -1;\n return 0;\n });\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n\n const childVal = next(val, props);\n const strVal =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n\n if (\n Array.isArray(node) ||\n (node.nodeType === 'composite' && Array.isArray(node.composite))\n ) {\n // handle array/composite\n const arr = Array.isArray(node) ? node : node.composite;\n const items = arr.map((item: any) => next(item, props));\n return items.join('');\n }\n\n return next(node, props);\n },\n};\n\nexport const intlayerToICUFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'icu',\n keyPath: [],\n plugins: [{ id: 'icu', ...intlayerToIcuPlugin }],\n });\n};\n\nexport const icuToIntlayerFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'icu',\n keyPath: [],\n plugins: [{ id: 'icu', ...icuToIntlayerPlugin }],\n });\n};\n"],"mappings":"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"}
|