@intlayer/core 8.7.6 → 8.7.7
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/deepTransformPlugins/getFilterMissingTranslationsContent.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/getFilterTranslationsOnlyContent.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/getMultilingualDictionary.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/getReplacedValuesContent.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/getEmptyNode.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/mergeDictionaries.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/normalizeDictionary.cjs.map +1 -1
- package/dist/cjs/formatters/date.cjs.map +1 -1
- package/dist/cjs/formatters/percentage.cjs.map +1 -1
- package/dist/cjs/interpreter/getContent/deepTransform.cjs.map +1 -1
- package/dist/cjs/interpreter/getContent/plugins.cjs.map +1 -1
- package/dist/cjs/interpreter/getGender.cjs.map +1 -1
- package/dist/cjs/interpreter/getHTML.cjs.map +1 -1
- package/dist/cjs/interpreter/getInsertion.cjs.map +1 -1
- package/dist/cjs/interpreter/getIntlayer.cjs.map +1 -1
- package/dist/cjs/localization/generateSitemap.cjs.map +1 -1
- package/dist/cjs/localization/getBrowserLocale.cjs.map +1 -1
- package/dist/cjs/localization/getHTMLTextDir.cjs.map +1 -1
- package/dist/cjs/localization/getLocale.cjs.map +1 -1
- package/dist/cjs/localization/getLocaleName.cjs.map +1 -1
- package/dist/cjs/localization/localeDetector.cjs.map +1 -1
- package/dist/cjs/localization/rewriteUtils.cjs.map +1 -1
- package/dist/cjs/localization/validatePrefix.cjs +4 -0
- package/dist/cjs/localization/validatePrefix.cjs.map +1 -1
- package/dist/cjs/markdown/compiler.cjs.map +1 -1
- package/dist/cjs/markdown/constants.cjs +10 -0
- package/dist/cjs/markdown/constants.cjs.map +1 -1
- package/dist/cjs/markdown/utils.cjs.map +1 -1
- package/dist/cjs/messageFormat/ICU.cjs.map +1 -1
- package/dist/cjs/messageFormat/i18next.cjs.map +1 -1
- package/dist/cjs/messageFormat/verify-icu-format.cjs.map +1 -1
- package/dist/cjs/messageFormat/vue-i18n.cjs.map +1 -1
- package/dist/cjs/transpiler/file/file.cjs.map +1 -1
- package/dist/cjs/transpiler/html/getHTMLCustomComponents.cjs.map +1 -1
- package/dist/cjs/transpiler/insertion/getInsertionValues.cjs.map +1 -1
- package/dist/cjs/transpiler/markdown/getMarkdownMetadata.cjs.map +1 -1
- package/dist/cjs/transpiler/markdown/markdown.cjs.map +1 -1
- package/dist/cjs/utils/localeStorage.cjs.map +1 -1
- package/dist/esm/deepTransformPlugins/getFilterMissingTranslationsContent.mjs.map +1 -1
- package/dist/esm/deepTransformPlugins/getFilterTranslationsOnlyContent.mjs.map +1 -1
- package/dist/esm/deepTransformPlugins/getMultilingualDictionary.mjs.map +1 -1
- package/dist/esm/deepTransformPlugins/getReplacedValuesContent.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/getEmptyNode.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/mergeDictionaries.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/normalizeDictionary.mjs.map +1 -1
- package/dist/esm/formatters/date.mjs.map +1 -1
- package/dist/esm/formatters/percentage.mjs.map +1 -1
- package/dist/esm/interpreter/getContent/deepTransform.mjs.map +1 -1
- package/dist/esm/interpreter/getContent/plugins.mjs.map +1 -1
- package/dist/esm/interpreter/getGender.mjs.map +1 -1
- package/dist/esm/interpreter/getHTML.mjs.map +1 -1
- package/dist/esm/interpreter/getInsertion.mjs.map +1 -1
- package/dist/esm/interpreter/getIntlayer.mjs.map +1 -1
- package/dist/esm/localization/generateSitemap.mjs.map +1 -1
- package/dist/esm/localization/getBrowserLocale.mjs.map +1 -1
- package/dist/esm/localization/getHTMLTextDir.mjs.map +1 -1
- package/dist/esm/localization/getLocale.mjs.map +1 -1
- package/dist/esm/localization/getLocaleName.mjs.map +1 -1
- package/dist/esm/localization/localeDetector.mjs.map +1 -1
- package/dist/esm/localization/rewriteUtils.mjs.map +1 -1
- package/dist/esm/localization/validatePrefix.mjs +4 -0
- package/dist/esm/localization/validatePrefix.mjs.map +1 -1
- package/dist/esm/markdown/compiler.mjs.map +1 -1
- package/dist/esm/markdown/constants.mjs +10 -0
- package/dist/esm/markdown/constants.mjs.map +1 -1
- package/dist/esm/markdown/utils.mjs.map +1 -1
- package/dist/esm/messageFormat/ICU.mjs.map +1 -1
- package/dist/esm/messageFormat/i18next.mjs.map +1 -1
- package/dist/esm/messageFormat/verify-icu-format.mjs.map +1 -1
- package/dist/esm/messageFormat/vue-i18n.mjs.map +1 -1
- package/dist/esm/transpiler/file/file.mjs.map +1 -1
- package/dist/esm/transpiler/html/getHTMLCustomComponents.mjs.map +1 -1
- package/dist/esm/transpiler/insertion/getInsertionValues.mjs.map +1 -1
- package/dist/esm/transpiler/markdown/getMarkdownMetadata.mjs.map +1 -1
- package/dist/esm/transpiler/markdown/markdown.mjs.map +1 -1
- package/dist/esm/utils/localeStorage.mjs.map +1 -1
- package/package.json +9 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getFilterMissingTranslationsContent.cjs","names":["NodeTypes","internationalization","getTranslation","tCore","deepTransformNode"],"sources":["../../../src/deepTransformPlugins/getFilterMissingTranslationsContent.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type {\n DeclaredLocales,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport {\n type DeepTransformContent,\n getTranslation,\n type NodeProps,\n type Plugins,\n} from '../interpreter';\nimport { deepTransformNode } from '../interpreter/getContent/deepTransform';\nimport { type TranslationContent, t as tCore } from '../transpiler';\n\n/**\n * Helper function to check if a node or its children contain translation nodes\n */\nconst hasTranslationNodes = (node: any): boolean => {\n if (typeof node !== 'object' || node === null) {\n return false;\n }\n\n if (node?.nodeType === NodeTypes.TRANSLATION) {\n return true;\n }\n\n if (Array.isArray(node)) {\n return node.some(hasTranslationNodes);\n }\n\n return Object.values(node).some(hasTranslationNodes);\n};\n\n/**\n * Get all keys from an object, recursively\n */\nconst getObjectKeys = (obj: any): Set<string> => {\n const keys = new Set<string>();\n\n if (typeof obj !== 'object' || obj === null) {\n return keys;\n }\n\n for (const key in obj) {\n keys.add(key);\n }\n\n return keys;\n};\n\n/**\n * Check if two objects have the same structure (same keys)\n */\nconst hasSameStructure = (obj1: any, obj2: any): boolean => {\n if (typeof obj1 !== 'object' || typeof obj2 !== 'object') {\n return typeof obj1 === typeof obj2;\n }\n\n if (obj1 === null || obj2 === null) {\n return obj1 === obj2;\n }\n\n if (Array.isArray(obj1) !== Array.isArray(obj2)) {\n return false;\n }\n\n const keys1 = getObjectKeys(obj1);\n const keys2 = getObjectKeys(obj2);\n\n if (keys1.size !== keys2.size) {\n return false;\n }\n\n for (const key of keys1) {\n if (!keys2.has(key)) {\n return false;\n }\n }\n\n return true;\n};\n\n/**\n * Check if all locales in a translation node have the same structure (recursively)\n * Returns an object with locales that have missing keys\n */\nconst checkTranslationStructureConsistency = (\n translationNode: Record<string, any>\n): { hasInconsistency: boolean; localesWithMissingKeys: Set<string> } => {\n const locales = Object.keys(translationNode);\n const localesWithMissingKeys = new Set<string>();\n\n if (locales.length <= 1) {\n return { hasInconsistency: false, localesWithMissingKeys };\n }\n\n // Helper function to check structure recursively\n const checkStructureRecursive = (\n path: string,\n localeValues: Map<string, any>\n ): Set<string> => {\n const localesWithIssues = new Set<string>();\n\n // Get all unique keys across all locale values at this path\n const allKeys = new Set<string>();\n const objectLocales = new Map<string, any>();\n\n for (const [locale, value] of localeValues.entries()) {\n if (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value)\n ) {\n objectLocales.set(locale, value);\n const keys = getObjectKeys(value);\n for (const key of keys) {\n allKeys.add(key);\n }\n }\n }\n\n // If no objects at this level, no inconsistency\n if (objectLocales.size === 0) {\n return localesWithIssues;\n }\n\n // Check if each locale has all the keys at this level\n for (const [locale, value] of objectLocales.entries()) {\n const keys = getObjectKeys(value);\n if (keys.size !== allKeys.size) {\n localesWithIssues.add(locale);\n }\n }\n\n // Recursively check nested objects\n for (const key of allKeys) {\n const nestedValues = new Map<string, any>();\n for (const [locale, value] of objectLocales.entries()) {\n if (value[key] !== undefined) {\n nestedValues.set(locale, value[key]);\n }\n }\n\n if (nestedValues.size > 1) {\n const nestedIssues = checkStructureRecursive(\n path ? `${path}.${key}` : key,\n nestedValues\n );\n for (const locale of nestedIssues) {\n localesWithIssues.add(locale);\n }\n }\n }\n\n return localesWithIssues;\n };\n\n // Start recursive check from root\n const rootValues = new Map<string, any>();\n for (const locale of locales) {\n rootValues.set(locale, translationNode[locale]);\n }\n\n const issuesFound = checkStructureRecursive('', rootValues);\n const hasInconsistency = issuesFound.size > 0;\n\n for (const locale of issuesFound) {\n localesWithMissingKeys.add(locale);\n }\n\n return { hasInconsistency, localesWithMissingKeys };\n};\n\n/**\n * Check if array elements have consistent structures\n */\nconst checkArrayStructureConsistency = (arr: any[]): boolean => {\n if (arr.length <= 1) {\n return true;\n }\n\n const firstElement = arr[0];\n\n for (let i = 1; i < arr.length; i++) {\n if (!hasSameStructure(firstElement, arr[i])) {\n return false;\n }\n }\n\n return true;\n};\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const filterMissingTranslationsOnlyPlugin = (\n localeToCheck: LocalesValues\n): Plugins => ({\n id: 'filter-missing-translations-only-plugin',\n canHandle: (node: ContentNode) => {\n // Only handle objects and arrays, not primitives\n return typeof node === 'object' && node !== null;\n },\n transform: (node: ContentNode, props, deepTransformNode) => {\n if (typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION) {\n const result = structuredClone(\n (node as TranslationContent)[NodeTypes.TRANSLATION]\n );\n\n const hasLocaleTranslation = Object.keys(result).includes(localeToCheck);\n\n // Check for structural inconsistencies across locales\n const { hasInconsistency, localesWithMissingKeys } =\n checkTranslationStructureConsistency(result);\n\n // If there's a structural inconsistency and the locale being checked\n // has missing keys, treat it as a missing translation\n const hasStructuralIssue =\n hasInconsistency && localesWithMissingKeys.has(localeToCheck);\n\n if (hasLocaleTranslation && !hasStructuralIssue) {\n return undefined; // Return undefined to remove the node\n }\n\n // Transform nested content\n for (const key in result) {\n const childProps = {\n ...props,\n children: result[key as unknown as keyof typeof result],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.TRANSLATION, key } as KeyPath,\n ],\n };\n result[key as unknown as keyof typeof result] = deepTransformNode(\n result[key as unknown as keyof typeof result],\n {\n ...childProps,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) =>\n plugin.id !== 'filter-missing-translations-only-plugin'\n ),\n ],\n }\n );\n }\n\n // Return the base locale content as a translation node\n // If base locale is missing, use any available locale as fallback\n const baseLocale = internationalization?.defaultLocale;\n\n const availableLocales = Object.keys(result);\n\n if (availableLocales.length === 0) {\n return undefined; // No translations available\n }\n\n // Try to get the base locale first, then any available locale as fallback\n const fallbackLocale = availableLocales.includes(baseLocale)\n ? baseLocale\n : availableLocales[0];\n\n const fallbackValue = getTranslation(result, baseLocale, fallbackLocale);\n\n // Return the translation node structure with only the fallback locale\n return tCore({ [fallbackLocale]: fallbackValue });\n } else if (\n typeof node === 'object' &&\n node !== null &&\n !Array.isArray(node) &&\n !node?.nodeType\n ) {\n // For regular objects, include only children that are related to translations\n // - Keep children that contain translation nodes (directly or nested)\n // - Keep arrays (they may mix translated and non-translated values)\n // - Exclude primitive values (string/number/boolean/null/undefined) at object level\n const result: Record<string, any> = {};\n let hasMissingTranslations = false;\n const arrayKeysIncluded: string[] = [];\n const primitiveSiblingsToAppend: any[] = [];\n\n for (const key in node as any) {\n const originalChild = (node as any)[key];\n const childProps = {\n ...props,\n children: originalChild,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.OBJECT, key } as KeyPath,\n ],\n };\n const transformedChild = deepTransformNode(originalChild, childProps);\n\n const isPrimitiveSibling =\n originalChild === null ||\n (typeof originalChild !== 'object' &&\n typeof originalChild !== 'function');\n\n if (isPrimitiveSibling) {\n // Defer primitives; they may be appended to an array sibling later\n if (originalChild !== undefined) {\n primitiveSiblingsToAppend.push(originalChild);\n }\n continue;\n }\n\n const includeChild =\n transformedChild !== undefined &&\n (hasTranslationNodes(originalChild) || Array.isArray(originalChild));\n\n if (includeChild) {\n result[key] = transformedChild;\n hasMissingTranslations = true;\n if (Array.isArray(transformedChild)) {\n arrayKeysIncluded.push(key);\n }\n }\n }\n\n // If any array child is present, append primitive siblings into the first array\n if (\n arrayKeysIncluded.length > 0 &&\n primitiveSiblingsToAppend.length > 0\n ) {\n const targetArrayKey = arrayKeysIncluded[0];\n // Ensure array exists in result (it should, but be defensive)\n if (Array.isArray(result[targetArrayKey])) {\n result[targetArrayKey] = [\n ...result[targetArrayKey],\n ...primitiveSiblingsToAppend,\n ];\n hasMissingTranslations = true;\n }\n }\n\n // Only return the object if it has missing translations-related content\n return hasMissingTranslations ? result : undefined;\n } else if (Array.isArray(node)) {\n // Check if array elements have consistent structures\n const hasConsistentStructure = checkArrayStructureConsistency(node);\n\n // For arrays, only include items that have missing translations\n const result = node\n .map((child, index) => {\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ARRAY, key: index } as KeyPath,\n ],\n };\n return deepTransformNode(child, childProps);\n })\n .filter((item) => item !== null && item !== undefined);\n\n // If there's structural inconsistency in the array, include it\n // even if it has no missing translations, to flag the issue\n if (!hasConsistentStructure && result.length === 0) {\n // Return a marker to indicate structural inconsistency\n return node; // Return original array to show the issue\n }\n\n // Only return the array if it has items with missing translations\n return result.length > 0 ? result : undefined;\n }\n\n return node; // Return non-translation content as is\n },\n});\n\n/**\n * For each translation node, it compare is both localeToCheck and baseLocale are present.\n *\n * If yes, it should remove the node from the content.\n * If no, it should keep the node\n *\n * In complete mode, for large dictionaries, we want to filter all content that is already translated\n *\n * locale: fr\n *\n * { test1: t({ ar: 'Hello', en: 'Hello', fr: 'Bonjour' } }) -> {}\n * { test2: t({ ar: 'Hello', en: 'Hello' }) } -> { test2: t({ ar: 'Hello', en: 'Hello' }) }\n *\n */\nexport const getFilterMissingTranslationsContent = <\n T extends ContentNode,\n L extends LocalesValues = DeclaredLocales,\n>(\n node: T,\n localeToCheck: L,\n nodeProps: NodeProps\n) => {\n const plugins: Plugins[] = [\n filterMissingTranslationsOnlyPlugin(localeToCheck),\n ...(nodeProps.plugins ?? []),\n ];\n\n const result = deepTransformNode(node, {\n ...nodeProps,\n plugins,\n }) as DeepTransformContent<T>;\n\n // Stringify the result to remove the undefined values\n if (result === undefined) {\n // No missing translations found\n return {} as DeepTransformContent<T>;\n }\n return JSON.parse(JSON.stringify(result));\n};\n\nexport const getFilterMissingTranslationsDictionary = (\n dictionary: Dictionary,\n localeToCheck: LocalesValues\n) => ({\n ...dictionary,\n content: getFilterMissingTranslationsContent(\n dictionary.content,\n localeToCheck,\n {\n dictionaryKey: dictionary.key,\n keyPath: [],\n plugins: [],\n }\n ),\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"getFilterMissingTranslationsContent.cjs","names":["NodeTypes","internationalization","getTranslation","tCore","deepTransformNode"],"sources":["../../../src/deepTransformPlugins/getFilterMissingTranslationsContent.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type {\n DeclaredLocales,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport {\n type DeepTransformContent,\n getTranslation,\n type NodeProps,\n type Plugins,\n} from '../interpreter';\nimport { deepTransformNode } from '../interpreter/getContent/deepTransform';\nimport { type TranslationContent, t as tCore } from '../transpiler';\n\n/**\n * Helper function to check if a node or its children contain translation nodes\n */\nconst hasTranslationNodes = (node: any): boolean => {\n if (typeof node !== 'object' || node === null) {\n return false;\n }\n\n if (node?.nodeType === NodeTypes.TRANSLATION) {\n return true;\n }\n\n if (Array.isArray(node)) {\n return node.some(hasTranslationNodes);\n }\n\n return Object.values(node).some(hasTranslationNodes);\n};\n\n/**\n * Get all keys from an object, recursively\n */\nconst getObjectKeys = (obj: any): Set<string> => {\n const keys = new Set<string>();\n\n if (typeof obj !== 'object' || obj === null) {\n return keys;\n }\n\n for (const key in obj) {\n keys.add(key);\n }\n\n return keys;\n};\n\n/**\n * Check if two objects have the same structure (same keys)\n */\nconst hasSameStructure = (obj1: any, obj2: any): boolean => {\n if (typeof obj1 !== 'object' || typeof obj2 !== 'object') {\n return typeof obj1 === typeof obj2;\n }\n\n if (obj1 === null || obj2 === null) {\n return obj1 === obj2;\n }\n\n if (Array.isArray(obj1) !== Array.isArray(obj2)) {\n return false;\n }\n\n const keys1 = getObjectKeys(obj1);\n const keys2 = getObjectKeys(obj2);\n\n if (keys1.size !== keys2.size) {\n return false;\n }\n\n for (const key of keys1) {\n if (!keys2.has(key)) {\n return false;\n }\n }\n\n return true;\n};\n\n/**\n * Check if all locales in a translation node have the same structure (recursively)\n * Returns an object with locales that have missing keys\n */\nconst checkTranslationStructureConsistency = (\n translationNode: Record<string, any>\n): { hasInconsistency: boolean; localesWithMissingKeys: Set<string> } => {\n const locales = Object.keys(translationNode);\n const localesWithMissingKeys = new Set<string>();\n\n if (locales.length <= 1) {\n return { hasInconsistency: false, localesWithMissingKeys };\n }\n\n // Helper function to check structure recursively\n const checkStructureRecursive = (\n path: string,\n localeValues: Map<string, any>\n ): Set<string> => {\n const localesWithIssues = new Set<string>();\n\n // Get all unique keys across all locale values at this path\n const allKeys = new Set<string>();\n const objectLocales = new Map<string, any>();\n\n for (const [locale, value] of localeValues.entries()) {\n if (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value)\n ) {\n objectLocales.set(locale, value);\n const keys = getObjectKeys(value);\n for (const key of keys) {\n allKeys.add(key);\n }\n }\n }\n\n // If no objects at this level, no inconsistency\n if (objectLocales.size === 0) {\n return localesWithIssues;\n }\n\n // Check if each locale has all the keys at this level\n for (const [locale, value] of objectLocales.entries()) {\n const keys = getObjectKeys(value);\n if (keys.size !== allKeys.size) {\n localesWithIssues.add(locale);\n }\n }\n\n // Recursively check nested objects\n for (const key of allKeys) {\n const nestedValues = new Map<string, any>();\n for (const [locale, value] of objectLocales.entries()) {\n if (value[key] !== undefined) {\n nestedValues.set(locale, value[key]);\n }\n }\n\n if (nestedValues.size > 1) {\n const nestedIssues = checkStructureRecursive(\n path ? `${path}.${key}` : key,\n nestedValues\n );\n for (const locale of nestedIssues) {\n localesWithIssues.add(locale);\n }\n }\n }\n\n return localesWithIssues;\n };\n\n // Start recursive check from root\n const rootValues = new Map<string, any>();\n for (const locale of locales) {\n rootValues.set(locale, translationNode[locale]);\n }\n\n const issuesFound = checkStructureRecursive('', rootValues);\n const hasInconsistency = issuesFound.size > 0;\n\n for (const locale of issuesFound) {\n localesWithMissingKeys.add(locale);\n }\n\n return { hasInconsistency, localesWithMissingKeys };\n};\n\n/**\n * Check if array elements have consistent structures\n */\nconst checkArrayStructureConsistency = (arr: any[]): boolean => {\n if (arr.length <= 1) {\n return true;\n }\n\n const firstElement = arr[0];\n\n for (let i = 1; i < arr.length; i++) {\n if (!hasSameStructure(firstElement, arr[i])) {\n return false;\n }\n }\n\n return true;\n};\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const filterMissingTranslationsOnlyPlugin = (\n localeToCheck: LocalesValues\n): Plugins => ({\n id: 'filter-missing-translations-only-plugin',\n canHandle: (node: ContentNode) => {\n // Only handle objects and arrays, not primitives\n return typeof node === 'object' && node !== null;\n },\n transform: (node: ContentNode, props, deepTransformNode) => {\n if (typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION) {\n const result = structuredClone(\n (node as TranslationContent)[NodeTypes.TRANSLATION]\n );\n\n const hasLocaleTranslation = Object.keys(result).includes(localeToCheck);\n\n // Check for structural inconsistencies across locales\n const { hasInconsistency, localesWithMissingKeys } =\n checkTranslationStructureConsistency(result);\n\n // If there's a structural inconsistency and the locale being checked\n // has missing keys, treat it as a missing translation\n const hasStructuralIssue =\n hasInconsistency && localesWithMissingKeys.has(localeToCheck);\n\n if (hasLocaleTranslation && !hasStructuralIssue) {\n return undefined; // Return undefined to remove the node\n }\n\n // Transform nested content\n for (const key in result) {\n const childProps = {\n ...props,\n children: result[key as unknown as keyof typeof result],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.TRANSLATION, key } as KeyPath,\n ],\n };\n result[key as unknown as keyof typeof result] = deepTransformNode(\n result[key as unknown as keyof typeof result],\n {\n ...childProps,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) =>\n plugin.id !== 'filter-missing-translations-only-plugin'\n ),\n ],\n }\n );\n }\n\n // Return the base locale content as a translation node\n // If base locale is missing, use any available locale as fallback\n const baseLocale = internationalization?.defaultLocale;\n\n const availableLocales = Object.keys(result);\n\n if (availableLocales.length === 0) {\n return undefined; // No translations available\n }\n\n // Try to get the base locale first, then any available locale as fallback\n const fallbackLocale = availableLocales.includes(baseLocale)\n ? baseLocale\n : availableLocales[0];\n\n const fallbackValue = getTranslation(result, baseLocale, fallbackLocale);\n\n // Return the translation node structure with only the fallback locale\n return tCore({ [fallbackLocale]: fallbackValue });\n } else if (\n typeof node === 'object' &&\n node !== null &&\n !Array.isArray(node) &&\n !node?.nodeType\n ) {\n // For regular objects, include only children that are related to translations\n // - Keep children that contain translation nodes (directly or nested)\n // - Keep arrays (they may mix translated and non-translated values)\n // - Exclude primitive values (string/number/boolean/null/undefined) at object level\n const result: Record<string, any> = {};\n let hasMissingTranslations = false;\n const arrayKeysIncluded: string[] = [];\n const primitiveSiblingsToAppend: any[] = [];\n\n for (const key in node as any) {\n const originalChild = (node as any)[key];\n const childProps = {\n ...props,\n children: originalChild,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.OBJECT, key } as KeyPath,\n ],\n };\n const transformedChild = deepTransformNode(originalChild, childProps);\n\n const isPrimitiveSibling =\n originalChild === null ||\n (typeof originalChild !== 'object' &&\n typeof originalChild !== 'function');\n\n if (isPrimitiveSibling) {\n // Defer primitives; they may be appended to an array sibling later\n if (originalChild !== undefined) {\n primitiveSiblingsToAppend.push(originalChild);\n }\n continue;\n }\n\n const includeChild =\n transformedChild !== undefined &&\n (hasTranslationNodes(originalChild) || Array.isArray(originalChild));\n\n if (includeChild) {\n result[key] = transformedChild;\n hasMissingTranslations = true;\n if (Array.isArray(transformedChild)) {\n arrayKeysIncluded.push(key);\n }\n }\n }\n\n // If any array child is present, append primitive siblings into the first array\n if (\n arrayKeysIncluded.length > 0 &&\n primitiveSiblingsToAppend.length > 0\n ) {\n const targetArrayKey = arrayKeysIncluded[0];\n // Ensure array exists in result (it should, but be defensive)\n if (Array.isArray(result[targetArrayKey])) {\n result[targetArrayKey] = [\n ...result[targetArrayKey],\n ...primitiveSiblingsToAppend,\n ];\n hasMissingTranslations = true;\n }\n }\n\n // Only return the object if it has missing translations-related content\n return hasMissingTranslations ? result : undefined;\n } else if (Array.isArray(node)) {\n // Check if array elements have consistent structures\n const hasConsistentStructure = checkArrayStructureConsistency(node);\n\n // For arrays, only include items that have missing translations\n const result = node\n .map((child, index) => {\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ARRAY, key: index } as KeyPath,\n ],\n };\n return deepTransformNode(child, childProps);\n })\n .filter((item) => item !== null && item !== undefined);\n\n // If there's structural inconsistency in the array, include it\n // even if it has no missing translations, to flag the issue\n if (!hasConsistentStructure && result.length === 0) {\n // Return a marker to indicate structural inconsistency\n return node; // Return original array to show the issue\n }\n\n // Only return the array if it has items with missing translations\n return result.length > 0 ? result : undefined;\n }\n\n return node; // Return non-translation content as is\n },\n});\n\n/**\n * For each translation node, it compare is both localeToCheck and baseLocale are present.\n *\n * If yes, it should remove the node from the content.\n * If no, it should keep the node\n *\n * In complete mode, for large dictionaries, we want to filter all content that is already translated\n *\n * locale: fr\n *\n * { test1: t({ ar: 'Hello', en: 'Hello', fr: 'Bonjour' } }) -> {}\n * { test2: t({ ar: 'Hello', en: 'Hello' }) } -> { test2: t({ ar: 'Hello', en: 'Hello' }) }\n *\n */\nexport const getFilterMissingTranslationsContent = <\n T extends ContentNode,\n L extends LocalesValues = DeclaredLocales,\n>(\n node: T,\n localeToCheck: L,\n nodeProps: NodeProps\n) => {\n const plugins: Plugins[] = [\n filterMissingTranslationsOnlyPlugin(localeToCheck),\n ...(nodeProps.plugins ?? []),\n ];\n\n const result = deepTransformNode(node, {\n ...nodeProps,\n plugins,\n }) as DeepTransformContent<T>;\n\n // Stringify the result to remove the undefined values\n if (result === undefined) {\n // No missing translations found\n return {} as DeepTransformContent<T>;\n }\n return JSON.parse(JSON.stringify(result));\n};\n\nexport const getFilterMissingTranslationsDictionary = (\n dictionary: Dictionary,\n localeToCheck: LocalesValues\n) => ({\n ...dictionary,\n content: getFilterMissingTranslationsContent(\n dictionary.content,\n localeToCheck,\n {\n dictionaryKey: dictionary.key,\n keyPath: [],\n plugins: [],\n }\n ),\n});\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getFilterTranslationsOnlyContent.cjs","names":["NodeTypes","getTranslation","internationalization","deepTransformNode"],"sources":["../../../src/deepTransformPlugins/getFilterTranslationsOnlyContent.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type {\n DeclaredLocales,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport {\n type DeepTransformContent,\n getTranslation,\n type NodeProps,\n type Plugins,\n} from '../interpreter';\nimport { deepTransformNode } from '../interpreter/getContent/deepTransform';\nimport type { TranslationContent } from '../transpiler';\n\n/**\n * Helper function to check if a node or its children contain translation nodes\n */\nconst hasTranslationNodes = (node: any): boolean => {\n if (typeof node !== 'object' || node === null) {\n return false;\n }\n\n if (node?.nodeType === NodeTypes.TRANSLATION) {\n return true;\n }\n\n if (Array.isArray(node)) {\n return node.some(hasTranslationNodes);\n }\n\n return Object.values(node).some(hasTranslationNodes);\n};\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const filterTranslationsOnlyPlugin = (\n locale: LocalesValues,\n fallback?: LocalesValues\n): Plugins => ({\n id: 'filter-translations-only-plugin',\n canHandle: (node: ContentNode) => {\n // Only handle objects and arrays, not primitives\n return typeof node === 'object' && node !== null;\n },\n transform: (node: ContentNode, props, deepTransformNode) => {\n if (typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION) {\n const result = structuredClone(\n (node as TranslationContent)[NodeTypes.TRANSLATION]\n );\n\n for (const key in result) {\n const childProps = {\n ...props,\n children: result[key as unknown as keyof typeof result],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.TRANSLATION, key } as KeyPath,\n ],\n };\n result[key as unknown as keyof typeof result] = deepTransformNode(\n result[key as unknown as keyof typeof result],\n {\n ...childProps,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) => plugin.id !== 'filter-translations-only-plugin'\n ),\n ],\n }\n );\n }\n return getTranslation(result, locale, fallback);\n } else if (\n typeof node === 'object' &&\n node !== null &&\n !Array.isArray(node) &&\n !node?.nodeType\n ) {\n // For regular objects, filter out properties that don't contain translations\n const result: Record<string, any> = {};\n for (const key in node as any) {\n if (hasTranslationNodes(node[key as unknown as keyof typeof node])) {\n const childProps = {\n ...props,\n children: node[key as unknown as keyof typeof node],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.OBJECT, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(\n node[key as unknown as keyof typeof node],\n childProps\n );\n }\n }\n return result;\n } else if (Array.isArray(node)) {\n // For arrays, keep all items but transform them\n return node.map((child, index) => {\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ARRAY, key: index } as KeyPath,\n ],\n };\n return deepTransformNode(child, childProps);\n });\n }\n\n return 'to remove from the object';\n },\n});\n\n/**\n * Return the content of a node with only the translation plugin.\n *\n * @param node The node to transform.\n * @param locale The locale to use if your transformers need it (e.g. for translations).\n */\nexport const getFilterTranslationsOnlyContent = <\n T extends ContentNode,\n L extends LocalesValues = DeclaredLocales,\n>(\n node: T,\n locale: L = internationalization?.defaultLocale as L,\n\n nodeProps: NodeProps,\n fallback?: LocalesValues\n) => {\n const plugins: Plugins[] = [\n filterTranslationsOnlyPlugin(locale, fallback),\n ...(nodeProps.plugins ?? []),\n ];\n\n return deepTransformNode(node, {\n ...nodeProps,\n plugins,\n }) as DeepTransformContent<T>;\n};\n\nexport const getFilterTranslationsOnlyDictionary = (\n dictionary: Dictionary,\n locale: LocalesValues = internationalization?.defaultLocale as LocalesValues,\n\n fallback?: LocalesValues\n) => ({\n ...dictionary,\n content: getFilterTranslationsOnlyContent(\n dictionary.content,\n locale,\n { dictionaryKey: dictionary.key, keyPath: [] },\n fallback\n ),\n});\n"],"mappings":";;;;;;;;;;;;AAoBA,MAAM,uBAAuB,SAAuB;AAClD,KAAI,OAAO,SAAS,YAAY,SAAS,KACvC,QAAO;AAGT,KAAI,MAAM,aAAaA,yBAAU,YAC/B,QAAO;AAGT,KAAI,MAAM,QAAQ,KAAK,CACrB,QAAO,KAAK,KAAK,oBAAoB;AAGvC,QAAO,OAAO,OAAO,KAAK,CAAC,KAAK,oBAAoB;;;AAItD,MAAa,gCACX,QACA,cACa;CACb,IAAI;CACJ,YAAY,SAAsB;AAEhC,SAAO,OAAO,SAAS,YAAY,SAAS;;CAE9C,YAAY,MAAmB,OAAO,sBAAsB;AAC1D,MAAI,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU,aAAa;GACxE,MAAM,SAAS,gBACZ,KAA4BA,yBAAU,aACxC;AAED,QAAK,MAAM,OAAO,QAAQ;IACxB,MAAM,aAAa;KACjB,GAAG;KACH,UAAU,OAAO;KACjB,SAAS,CACP,GAAG,MAAM,SACT;MAAE,MAAMA,yBAAU;MAAa;MAAK,CACrC;KACF;AACD,WAAO,OAAyC,kBAC9C,OAAO,MACP;KACE,GAAG;KACH,SAAS,CACP,IAAI,MAAM,WAAY,EAAE,EAAgB,QACrC,WAAW,OAAO,OAAO,kCAC3B,CACF;KACF,CACF;;AAEH,UAAOC,kDAAe,QAAQ,QAAQ,SAAS;aAE/C,OAAO,SAAS,YAChB,SAAS,QACT,CAAC,MAAM,QAAQ,KAAK,IACpB,CAAC,MAAM,UACP;GAEA,MAAM,SAA8B,EAAE;AACtC,QAAK,MAAM,OAAO,KAChB,KAAI,oBAAoB,KAAK,KAAqC,EAAE;IAClE,MAAM,aAAa;KACjB,GAAG;KACH,UAAU,KAAK;KACf,SAAS,CACP,GAAG,MAAM,SACT;MAAE,MAAMD,yBAAU;MAAQ;MAAK,CAChC;KACF;AACD,WAAO,OAAO,kBACZ,KAAK,MACL,WACD;;AAGL,UAAO;aACE,MAAM,QAAQ,KAAK,CAE5B,QAAO,KAAK,KAAK,OAAO,UAAU;AAShC,UAAO,kBAAkB,
|
|
1
|
+
{"version":3,"file":"getFilterTranslationsOnlyContent.cjs","names":["NodeTypes","getTranslation","internationalization","deepTransformNode"],"sources":["../../../src/deepTransformPlugins/getFilterTranslationsOnlyContent.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type {\n DeclaredLocales,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport {\n type DeepTransformContent,\n getTranslation,\n type NodeProps,\n type Plugins,\n} from '../interpreter';\nimport { deepTransformNode } from '../interpreter/getContent/deepTransform';\nimport type { TranslationContent } from '../transpiler';\n\n/**\n * Helper function to check if a node or its children contain translation nodes\n */\nconst hasTranslationNodes = (node: any): boolean => {\n if (typeof node !== 'object' || node === null) {\n return false;\n }\n\n if (node?.nodeType === NodeTypes.TRANSLATION) {\n return true;\n }\n\n if (Array.isArray(node)) {\n return node.some(hasTranslationNodes);\n }\n\n return Object.values(node).some(hasTranslationNodes);\n};\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const filterTranslationsOnlyPlugin = (\n locale: LocalesValues,\n fallback?: LocalesValues\n): Plugins => ({\n id: 'filter-translations-only-plugin',\n canHandle: (node: ContentNode) => {\n // Only handle objects and arrays, not primitives\n return typeof node === 'object' && node !== null;\n },\n transform: (node: ContentNode, props, deepTransformNode) => {\n if (typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION) {\n const result = structuredClone(\n (node as TranslationContent)[NodeTypes.TRANSLATION]\n );\n\n for (const key in result) {\n const childProps = {\n ...props,\n children: result[key as unknown as keyof typeof result],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.TRANSLATION, key } as KeyPath,\n ],\n };\n result[key as unknown as keyof typeof result] = deepTransformNode(\n result[key as unknown as keyof typeof result],\n {\n ...childProps,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) => plugin.id !== 'filter-translations-only-plugin'\n ),\n ],\n }\n );\n }\n return getTranslation(result, locale, fallback);\n } else if (\n typeof node === 'object' &&\n node !== null &&\n !Array.isArray(node) &&\n !node?.nodeType\n ) {\n // For regular objects, filter out properties that don't contain translations\n const result: Record<string, any> = {};\n for (const key in node as any) {\n if (hasTranslationNodes(node[key as unknown as keyof typeof node])) {\n const childProps = {\n ...props,\n children: node[key as unknown as keyof typeof node],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.OBJECT, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(\n node[key as unknown as keyof typeof node],\n childProps\n );\n }\n }\n return result;\n } else if (Array.isArray(node)) {\n // For arrays, keep all items but transform them\n return node.map((child, index) => {\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ARRAY, key: index } as KeyPath,\n ],\n };\n return deepTransformNode(child, childProps);\n });\n }\n\n return 'to remove from the object';\n },\n});\n\n/**\n * Return the content of a node with only the translation plugin.\n *\n * @param node The node to transform.\n * @param locale The locale to use if your transformers need it (e.g. for translations).\n */\nexport const getFilterTranslationsOnlyContent = <\n T extends ContentNode,\n L extends LocalesValues = DeclaredLocales,\n>(\n node: T,\n locale: L = internationalization?.defaultLocale as L,\n\n nodeProps: NodeProps,\n fallback?: LocalesValues\n) => {\n const plugins: Plugins[] = [\n filterTranslationsOnlyPlugin(locale, fallback),\n ...(nodeProps.plugins ?? []),\n ];\n\n return deepTransformNode(node, {\n ...nodeProps,\n plugins,\n }) as DeepTransformContent<T>;\n};\n\nexport const getFilterTranslationsOnlyDictionary = (\n dictionary: Dictionary,\n locale: LocalesValues = internationalization?.defaultLocale as LocalesValues,\n\n fallback?: LocalesValues\n) => ({\n ...dictionary,\n content: getFilterTranslationsOnlyContent(\n dictionary.content,\n locale,\n { dictionaryKey: dictionary.key, keyPath: [] },\n fallback\n ),\n});\n"],"mappings":";;;;;;;;;;;;AAoBA,MAAM,uBAAuB,SAAuB;AAClD,KAAI,OAAO,SAAS,YAAY,SAAS,KACvC,QAAO;AAGT,KAAI,MAAM,aAAaA,yBAAU,YAC/B,QAAO;AAGT,KAAI,MAAM,QAAQ,KAAK,CACrB,QAAO,KAAK,KAAK,oBAAoB;AAGvC,QAAO,OAAO,OAAO,KAAK,CAAC,KAAK,oBAAoB;;;AAItD,MAAa,gCACX,QACA,cACa;CACb,IAAI;CACJ,YAAY,SAAsB;AAEhC,SAAO,OAAO,SAAS,YAAY,SAAS;;CAE9C,YAAY,MAAmB,OAAO,sBAAsB;AAC1D,MAAI,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU,aAAa;GACxE,MAAM,SAAS,gBACZ,KAA4BA,yBAAU,aACxC;AAED,QAAK,MAAM,OAAO,QAAQ;IACxB,MAAM,aAAa;KACjB,GAAG;KACH,UAAU,OAAO;KACjB,SAAS,CACP,GAAG,MAAM,SACT;MAAE,MAAMA,yBAAU;MAAa;MAAK,CACrC;KACF;AACD,WAAO,OAAyC,kBAC9C,OAAO,MACP;KACE,GAAG;KACH,SAAS,CACP,IAAI,MAAM,WAAY,EAAE,EAAgB,QACrC,WAAW,OAAO,OAAO,kCAC3B,CACF;KACF,CACF;;AAEH,UAAOC,kDAAe,QAAQ,QAAQ,SAAS;aAE/C,OAAO,SAAS,YAChB,SAAS,QACT,CAAC,MAAM,QAAQ,KAAK,IACpB,CAAC,MAAM,UACP;GAEA,MAAM,SAA8B,EAAE;AACtC,QAAK,MAAM,OAAO,KAChB,KAAI,oBAAoB,KAAK,KAAqC,EAAE;IAClE,MAAM,aAAa;KACjB,GAAG;KACH,UAAU,KAAK;KACf,SAAS,CACP,GAAG,MAAM,SACT;MAAE,MAAMD,yBAAU;MAAQ;MAAK,CAChC;KACF;AACD,WAAO,OAAO,kBACZ,KAAK,MACL,WACD;;AAGL,UAAO;aACE,MAAM,QAAQ,KAAK,CAE5B,QAAO,KAAK,KAAK,OAAO,UAAU;AAShC,UAAO,kBAAkB,OAAO;IAP9B,GAAG;IACH,UAAU;IACV,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAMA,yBAAU;KAAO,KAAK;KAAO,CACtC;IAEuC,CAAC;IAC3C;AAGJ,SAAO;;CAEV;;;;;;;AAQD,MAAa,oCAIX,MACA,SAAYE,6CAAsB,eAElC,WACA,aACG;CACH,MAAM,UAAqB,CACzB,6BAA6B,QAAQ,SAAS,EAC9C,GAAI,UAAU,WAAW,EAAE,CAC5B;AAED,QAAOC,+DAAkB,MAAM;EAC7B,GAAG;EACH;EACD,CAAC;;AAGJ,MAAa,uCACX,YACA,SAAwBD,6CAAsB,eAE9C,cACI;CACJ,GAAG;CACH,SAAS,iCACP,WAAW,SACX,QACA;EAAE,eAAe,WAAW;EAAK,SAAS,EAAE;EAAE,EAC9C,SACD;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getMultilingualDictionary.cjs","names":["deepTransformNode","t"],"sources":["../../../src/deepTransformPlugins/getMultilingualDictionary.ts"],"sourcesContent":["import type { Dictionary, TypedNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport {\n deepTransformNode,\n type NodeProps,\n type Plugins,\n} from '../interpreter';\nimport { t } from '../transpiler';\n\n/**\n * Transform a per-locale dictionary into a multilingual dictionary.\n *\n * Example:\n * ```json\n * {\n * \"key\": \"about-page\",\n * \"locale\": \"en\",\n * \"content\": {\n * \"myContent\": \"English content\"\n * }\n * }\n * ```\n *\n * ```json\n * {\n * \"key\": \"about-page\",\n * \"content\": {\n * \"myContent\": t({\n * \"en\": \"English content\",\n * })\n * }\n * }\n * ```\n */\nexport const getMultilingualDictionary = (\n dictionary: Dictionary\n): Dictionary => {\n if (!dictionary.locale) {\n return dictionary;\n }\n\n const locale = dictionary.locale;\n\n const wrapPrimitiveInTranslationPlugin: Plugins = {\n id: 'wrap-primitive-in-translation',\n canHandle: (node) =>\n typeof node === 'string' ||\n typeof node === 'number' ||\n typeof node === 'boolean',\n transform: (node) => t({ [locale]: node } as Record<string, unknown>),\n };\n\n const traverseTypedNodePlugin: Plugins = {\n id: 'traverse-typed-node-plugin',\n canHandle: (node) =>\n typeof node === 'object' && typeof (node as any)?.nodeType === 'string',\n transform: (node: TypedNode, props, transformFn) => {\n const nodeType = (node as any).nodeType as NodeType;\n const inner = structuredClone(\n (node as any)[nodeType as unknown as keyof TypedNode] as any\n );\n\n if (typeof inner !== 'object' || inner === null) {\n const transformed = transformFn(inner, {\n ...props,\n children: inner,\n keyPath: [\n ...props.keyPath,\n { type: nodeType, key: nodeType } as KeyPath,\n ],\n });\n return {\n ...node,\n [nodeType as unknown as keyof TypedNode]: transformed,\n };\n }\n\n for (const key in inner) {\n const childProps: NodeProps = {\n ...props,\n children: inner[key as unknown as keyof typeof inner],\n keyPath: [...props.keyPath, { type: nodeType, key } as KeyPath],\n };\n inner[key as unknown as keyof typeof inner] = transformFn(\n inner[key as unknown as keyof typeof inner],\n childProps\n );\n }\n\n return { ...node, [nodeType as unknown as keyof TypedNode]: inner };\n },\n };\n\n const transformedContent = deepTransformNode(\n JSON.parse(JSON.stringify(dictionary.content)),\n {\n dictionaryKey: dictionary.key,\n keyPath: [],\n plugins: [traverseTypedNodePlugin, wrapPrimitiveInTranslationPlugin],\n }\n );\n\n const { locale: _omitLocale, ...rest } = dictionary as any;\n return {\n ...rest,\n content: transformedContent,\n } as Dictionary;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,MAAa,6BACX,eACe;AACf,KAAI,CAAC,WAAW,OACd,QAAO;CAGT,MAAM,SAAS,WAAW;CAoD1B,MAAM,qBAAqBA,+DACzB,KAAK,MAAM,KAAK,UAAU,WAAW,QAAQ,CAAC,EAC9C;EACE,eAAe,WAAW;EAC1B,SAAS,EAAE;EACX,SAAS,
|
|
1
|
+
{"version":3,"file":"getMultilingualDictionary.cjs","names":["deepTransformNode","t"],"sources":["../../../src/deepTransformPlugins/getMultilingualDictionary.ts"],"sourcesContent":["import type { Dictionary, TypedNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport {\n deepTransformNode,\n type NodeProps,\n type Plugins,\n} from '../interpreter';\nimport { t } from '../transpiler';\n\n/**\n * Transform a per-locale dictionary into a multilingual dictionary.\n *\n * Example:\n * ```json\n * {\n * \"key\": \"about-page\",\n * \"locale\": \"en\",\n * \"content\": {\n * \"myContent\": \"English content\"\n * }\n * }\n * ```\n *\n * ```json\n * {\n * \"key\": \"about-page\",\n * \"content\": {\n * \"myContent\": t({\n * \"en\": \"English content\",\n * })\n * }\n * }\n * ```\n */\nexport const getMultilingualDictionary = (\n dictionary: Dictionary\n): Dictionary => {\n if (!dictionary.locale) {\n return dictionary;\n }\n\n const locale = dictionary.locale;\n\n const wrapPrimitiveInTranslationPlugin: Plugins = {\n id: 'wrap-primitive-in-translation',\n canHandle: (node) =>\n typeof node === 'string' ||\n typeof node === 'number' ||\n typeof node === 'boolean',\n transform: (node) => t({ [locale]: node } as Record<string, unknown>),\n };\n\n const traverseTypedNodePlugin: Plugins = {\n id: 'traverse-typed-node-plugin',\n canHandle: (node) =>\n typeof node === 'object' && typeof (node as any)?.nodeType === 'string',\n transform: (node: TypedNode, props, transformFn) => {\n const nodeType = (node as any).nodeType as NodeType;\n const inner = structuredClone(\n (node as any)[nodeType as unknown as keyof TypedNode] as any\n );\n\n if (typeof inner !== 'object' || inner === null) {\n const transformed = transformFn(inner, {\n ...props,\n children: inner,\n keyPath: [\n ...props.keyPath,\n { type: nodeType, key: nodeType } as KeyPath,\n ],\n });\n return {\n ...node,\n [nodeType as unknown as keyof TypedNode]: transformed,\n };\n }\n\n for (const key in inner) {\n const childProps: NodeProps = {\n ...props,\n children: inner[key as unknown as keyof typeof inner],\n keyPath: [...props.keyPath, { type: nodeType, key } as KeyPath],\n };\n inner[key as unknown as keyof typeof inner] = transformFn(\n inner[key as unknown as keyof typeof inner],\n childProps\n );\n }\n\n return { ...node, [nodeType as unknown as keyof TypedNode]: inner };\n },\n };\n\n const transformedContent = deepTransformNode(\n JSON.parse(JSON.stringify(dictionary.content)),\n {\n dictionaryKey: dictionary.key,\n keyPath: [],\n plugins: [traverseTypedNodePlugin, wrapPrimitiveInTranslationPlugin],\n }\n );\n\n const { locale: _omitLocale, ...rest } = dictionary as any;\n return {\n ...rest,\n content: transformedContent,\n } as Dictionary;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,MAAa,6BACX,eACe;AACf,KAAI,CAAC,WAAW,OACd,QAAO;CAGT,MAAM,SAAS,WAAW;CAoD1B,MAAM,qBAAqBA,+DACzB,KAAK,MAAM,KAAK,UAAU,WAAW,QAAQ,CAAC,EAC9C;EACE,eAAe,WAAW;EAC1B,SAAS,EAAE;EACX,SAAS,CAAC;GA7CZ,IAAI;GACJ,YAAY,SACV,OAAO,SAAS,YAAY,OAAQ,MAAc,aAAa;GACjE,YAAY,MAAiB,OAAO,gBAAgB;IAClD,MAAM,WAAY,KAAa;IAC/B,MAAM,QAAQ,gBACX,KAAa,UACf;AAED,QAAI,OAAO,UAAU,YAAY,UAAU,MAAM;KAC/C,MAAM,cAAc,YAAY,OAAO;MACrC,GAAG;MACH,UAAU;MACV,SAAS,CACP,GAAG,MAAM,SACT;OAAE,MAAM;OAAU,KAAK;OAAU,CAClC;MACF,CAAC;AACF,YAAO;MACL,GAAG;OACF,WAAyC;MAC3C;;AAGH,SAAK,MAAM,OAAO,OAAO;KACvB,MAAM,aAAwB;MAC5B,GAAG;MACH,UAAU,MAAM;MAChB,SAAS,CAAC,GAAG,MAAM,SAAS;OAAE,MAAM;OAAU;OAAK,CAAY;MAChE;AACD,WAAM,OAAwC,YAC5C,MAAM,MACN,WACD;;AAGH,WAAO;KAAE,GAAG;MAAO,WAAyC;KAAO;;GASlC,EAAE;GAtDrC,IAAI;GACJ,YAAY,SACV,OAAO,SAAS,YAChB,OAAO,SAAS,YAChB,OAAO,SAAS;GAClB,YAAY,SAASC,6CAAE,GAAG,SAAS,MAAM,CAA4B;GAiDA,CAAC;EACrE,CACF;CAED,MAAM,EAAE,QAAQ,aAAa,GAAG,SAAS;AACzC,QAAO;EACL,GAAG;EACH,SAAS;EACV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getReplacedValuesContent.cjs","names":["deepTransformNode"],"sources":["../../../src/deepTransformPlugins/getReplacedValuesContent.ts"],"sourcesContent":["import type { ContentNode, TypedNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport {\n deepTransformNode,\n type NodeProps,\n type Plugins,\n} from '../interpreter';\n\nconst replaceValuesPlugin = (value: string | number | boolean): Plugins => ({\n id: 'replace-values-plugin',\n canHandle: (node) =>\n typeof node === 'string' ||\n typeof node === 'number' ||\n typeof node === 'boolean',\n transform: () => value,\n});\n\nconst skipTypedNodePlugin: Plugins = {\n id: 'skip-typed-node-plugin',\n canHandle: (node) =>\n typeof node === 'object' && typeof node?.nodeType === 'string',\n transform: (node: TypedNode, props, deepTransformNode) => {\n const nodeType = node.nodeType as NodeType;\n const result = structuredClone(\n node[nodeType as unknown as keyof TypedNode] as any\n );\n\n // If the result is a primitive value (string, number, boolean),\n // we need to transform it directly instead of iterating over its properties\n if (typeof result !== 'object' || result === null) {\n const transformedResult = deepTransformNode(result, {\n ...props,\n children: result,\n keyPath: [\n ...props.keyPath,\n { type: nodeType, key: nodeType } as KeyPath,\n ],\n });\n return {\n ...node,\n [nodeType as unknown as keyof TypedNode]: transformedResult,\n };\n }\n\n // For objects and arrays, iterate over their properties\n for (const key in result) {\n const childProps = {\n ...props,\n children: result[key as unknown as keyof typeof result],\n keyPath: [...props.keyPath, { type: nodeType, key } as KeyPath],\n };\n result[key as unknown as keyof typeof result] = deepTransformNode(\n result[key as unknown as keyof typeof result],\n childProps\n );\n }\n\n return { ...node, [nodeType as unknown as keyof TypedNode]: result };\n },\n};\n\nexport const getReplacedValuesContent = (\n node: ContentNode,\n value: string | number | boolean,\n nodeProps: NodeProps\n) => {\n const plugins: Plugins[] = [\n skipTypedNodePlugin,\n replaceValuesPlugin(value),\n ...(nodeProps.plugins ?? []),\n ];\n\n const JSONNode = JSON.parse(JSON.stringify(node));\n\n return deepTransformNode(JSONNode, {\n ...nodeProps,\n plugins,\n });\n};\n"],"mappings":";;;;AASA,MAAM,uBAAuB,WAA+C;CAC1E,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAChB,OAAO,SAAS,YAChB,OAAO,SAAS;CAClB,iBAAiB;CAClB;AAED,MAAM,sBAA+B;CACnC,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,OAAO,MAAM,aAAa;CACxD,YAAY,MAAiB,OAAO,sBAAsB;EACxD,MAAM,WAAW,KAAK;EACtB,MAAM,SAAS,gBACb,KAAK,UACN;AAID,MAAI,OAAO,WAAW,YAAY,WAAW,MAAM;GACjD,MAAM,oBAAoB,kBAAkB,QAAQ;IAClD,GAAG;IACH,UAAU;IACV,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAM;KAAU,KAAK;KAAU,CAClC;IACF,CAAC;AACF,UAAO;IACL,GAAG;KACF,WAAyC;IAC3C;;AAIH,OAAK,MAAM,OAAO,QAAQ;GACxB,MAAM,aAAa;IACjB,GAAG;IACH,UAAU,OAAO;IACjB,SAAS,CAAC,GAAG,MAAM,SAAS;KAAE,MAAM;KAAU;KAAK,CAAY;IAChE;AACD,UAAO,OAAyC,kBAC9C,OAAO,MACP,WACD;;AAGH,SAAO;GAAE,GAAG;IAAO,WAAyC;GAAQ;;CAEvE;AAED,MAAa,4BACX,MACA,OACA,cACG;CACH,MAAM,UAAqB;EACzB;EACA,oBAAoB,MAAM;EAC1B,GAAI,UAAU,WAAW,EAAE;EAC5B;AAID,QAAOA,+DAFU,KAAK,MAAM,KAAK,UAAU,KAAK,
|
|
1
|
+
{"version":3,"file":"getReplacedValuesContent.cjs","names":["deepTransformNode"],"sources":["../../../src/deepTransformPlugins/getReplacedValuesContent.ts"],"sourcesContent":["import type { ContentNode, TypedNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport {\n deepTransformNode,\n type NodeProps,\n type Plugins,\n} from '../interpreter';\n\nconst replaceValuesPlugin = (value: string | number | boolean): Plugins => ({\n id: 'replace-values-plugin',\n canHandle: (node) =>\n typeof node === 'string' ||\n typeof node === 'number' ||\n typeof node === 'boolean',\n transform: () => value,\n});\n\nconst skipTypedNodePlugin: Plugins = {\n id: 'skip-typed-node-plugin',\n canHandle: (node) =>\n typeof node === 'object' && typeof node?.nodeType === 'string',\n transform: (node: TypedNode, props, deepTransformNode) => {\n const nodeType = node.nodeType as NodeType;\n const result = structuredClone(\n node[nodeType as unknown as keyof TypedNode] as any\n );\n\n // If the result is a primitive value (string, number, boolean),\n // we need to transform it directly instead of iterating over its properties\n if (typeof result !== 'object' || result === null) {\n const transformedResult = deepTransformNode(result, {\n ...props,\n children: result,\n keyPath: [\n ...props.keyPath,\n { type: nodeType, key: nodeType } as KeyPath,\n ],\n });\n return {\n ...node,\n [nodeType as unknown as keyof TypedNode]: transformedResult,\n };\n }\n\n // For objects and arrays, iterate over their properties\n for (const key in result) {\n const childProps = {\n ...props,\n children: result[key as unknown as keyof typeof result],\n keyPath: [...props.keyPath, { type: nodeType, key } as KeyPath],\n };\n result[key as unknown as keyof typeof result] = deepTransformNode(\n result[key as unknown as keyof typeof result],\n childProps\n );\n }\n\n return { ...node, [nodeType as unknown as keyof TypedNode]: result };\n },\n};\n\nexport const getReplacedValuesContent = (\n node: ContentNode,\n value: string | number | boolean,\n nodeProps: NodeProps\n) => {\n const plugins: Plugins[] = [\n skipTypedNodePlugin,\n replaceValuesPlugin(value),\n ...(nodeProps.plugins ?? []),\n ];\n\n const JSONNode = JSON.parse(JSON.stringify(node));\n\n return deepTransformNode(JSONNode, {\n ...nodeProps,\n plugins,\n });\n};\n"],"mappings":";;;;AASA,MAAM,uBAAuB,WAA+C;CAC1E,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAChB,OAAO,SAAS,YAChB,OAAO,SAAS;CAClB,iBAAiB;CAClB;AAED,MAAM,sBAA+B;CACnC,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,OAAO,MAAM,aAAa;CACxD,YAAY,MAAiB,OAAO,sBAAsB;EACxD,MAAM,WAAW,KAAK;EACtB,MAAM,SAAS,gBACb,KAAK,UACN;AAID,MAAI,OAAO,WAAW,YAAY,WAAW,MAAM;GACjD,MAAM,oBAAoB,kBAAkB,QAAQ;IAClD,GAAG;IACH,UAAU;IACV,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAM;KAAU,KAAK;KAAU,CAClC;IACF,CAAC;AACF,UAAO;IACL,GAAG;KACF,WAAyC;IAC3C;;AAIH,OAAK,MAAM,OAAO,QAAQ;GACxB,MAAM,aAAa;IACjB,GAAG;IACH,UAAU,OAAO;IACjB,SAAS,CAAC,GAAG,MAAM,SAAS;KAAE,MAAM;KAAU;KAAK,CAAY;IAChE;AACD,UAAO,OAAyC,kBAC9C,OAAO,MACP,WACD;;AAGH,SAAO;GAAE,GAAG;IAAO,WAAyC;GAAQ;;CAEvE;AAED,MAAa,4BACX,MACA,OACA,cACG;CACH,MAAM,UAAqB;EACzB;EACA,oBAAoB,MAAM;EAC1B,GAAI,UAAU,WAAW,EAAE;EAC5B;AAID,QAAOA,+DAFU,KAAK,MAAM,KAAK,UAAU,KAAK,CAEf,EAAE;EACjC,GAAG;EACH;EACD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getEmptyNode.cjs","names":["NodeTypes"],"sources":["../../../src/dictionaryManipulator/getEmptyNode.ts"],"sourcesContent":["import type { ContentNode, TypedNode } from '@intlayer/types/dictionary';\n\nimport * as NodeTypes from '@intlayer/types/nodeType';\n\nexport const getEmptyNode = (section: ContentNode): ContentNode => {\n if (typeof section === 'string') {\n return '';\n }\n if (typeof section === 'number') {\n return 0;\n }\n if (typeof section === 'boolean') {\n return true;\n }\n if (typeof (section as TypedNode)?.nodeType === 'string') {\n const typedNode = section as TypedNode;\n const content =\n typedNode[typedNode.nodeType as unknown as keyof typeof typedNode];\n\n if (\n typedNode.nodeType === NodeTypes.TRANSLATION ||\n typedNode.nodeType === NodeTypes.ENUMERATION ||\n typedNode.nodeType === NodeTypes.CONDITION ||\n typedNode.nodeType === NodeTypes.INSERTION ||\n typedNode.nodeType === NodeTypes.HTML\n ) {\n return getEmptyNode(content as ContentNode);\n }\n\n if (typedNode.nodeType === NodeTypes.NESTED) {\n return 'dictionary-key';\n }\n\n if (typedNode.nodeType === NodeTypes.FILE) {\n return 'file/path';\n }\n\n if (typedNode.nodeType === NodeTypes.MARKDOWN) {\n return getEmptyNode(typedNode);\n }\n\n return content;\n }\n\n if (!section || typeof section !== 'object') {\n return section;\n }\n\n if (Array.isArray(section)) {\n return (section as ContentNode[]).map(\n getEmptyNode\n ) as unknown as ContentNode;\n }\n\n const mappedSectionObject = Object.entries(section).map(([key, value]) => [\n key,\n getEmptyNode(value as ContentNode),\n ]);\n\n const mappedSectionArray = Object.fromEntries(mappedSectionObject);\n\n return mappedSectionArray;\n};\n"],"mappings":";;;;;;AAIA,MAAa,gBAAgB,YAAsC;AACjE,KAAI,OAAO,YAAY,SACrB,QAAO;AAET,KAAI,OAAO,YAAY,SACrB,QAAO;AAET,KAAI,OAAO,YAAY,UACrB,QAAO;AAET,KAAI,OAAQ,SAAuB,aAAa,UAAU;EACxD,MAAM,YAAY;EAClB,MAAM,UACJ,UAAU,UAAU;AAEtB,MACE,UAAU,aAAaA,yBAAU,eACjC,UAAU,aAAaA,yBAAU,eACjC,UAAU,aAAaA,yBAAU,aACjC,UAAU,aAAaA,yBAAU,aACjC,UAAU,aAAaA,yBAAU,KAEjC,QAAO,aAAa,QAAuB;AAG7C,MAAI,UAAU,aAAaA,yBAAU,OACnC,QAAO;AAGT,MAAI,UAAU,aAAaA,yBAAU,KACnC,QAAO;AAGT,MAAI,UAAU,aAAaA,yBAAU,SACnC,QAAO,aAAa,UAAU;AAGhC,SAAO;;AAGT,KAAI,CAAC,WAAW,OAAO,YAAY,SACjC,QAAO;AAGT,KAAI,MAAM,QAAQ,QAAQ,CACxB,QAAQ,QAA0B,IAChC,aACD;CAGH,MAAM,sBAAsB,OAAO,QAAQ,QAAQ,CAAC,KAAK,CAAC,KAAK,WAAW,CACxE,KACA,aAAa,MAAqB,CACnC,CAAC;AAIF,QAF2B,OAAO,YAAY,
|
|
1
|
+
{"version":3,"file":"getEmptyNode.cjs","names":["NodeTypes"],"sources":["../../../src/dictionaryManipulator/getEmptyNode.ts"],"sourcesContent":["import type { ContentNode, TypedNode } from '@intlayer/types/dictionary';\n\nimport * as NodeTypes from '@intlayer/types/nodeType';\n\nexport const getEmptyNode = (section: ContentNode): ContentNode => {\n if (typeof section === 'string') {\n return '';\n }\n if (typeof section === 'number') {\n return 0;\n }\n if (typeof section === 'boolean') {\n return true;\n }\n if (typeof (section as TypedNode)?.nodeType === 'string') {\n const typedNode = section as TypedNode;\n const content =\n typedNode[typedNode.nodeType as unknown as keyof typeof typedNode];\n\n if (\n typedNode.nodeType === NodeTypes.TRANSLATION ||\n typedNode.nodeType === NodeTypes.ENUMERATION ||\n typedNode.nodeType === NodeTypes.CONDITION ||\n typedNode.nodeType === NodeTypes.INSERTION ||\n typedNode.nodeType === NodeTypes.HTML\n ) {\n return getEmptyNode(content as ContentNode);\n }\n\n if (typedNode.nodeType === NodeTypes.NESTED) {\n return 'dictionary-key';\n }\n\n if (typedNode.nodeType === NodeTypes.FILE) {\n return 'file/path';\n }\n\n if (typedNode.nodeType === NodeTypes.MARKDOWN) {\n return getEmptyNode(typedNode);\n }\n\n return content;\n }\n\n if (!section || typeof section !== 'object') {\n return section;\n }\n\n if (Array.isArray(section)) {\n return (section as ContentNode[]).map(\n getEmptyNode\n ) as unknown as ContentNode;\n }\n\n const mappedSectionObject = Object.entries(section).map(([key, value]) => [\n key,\n getEmptyNode(value as ContentNode),\n ]);\n\n const mappedSectionArray = Object.fromEntries(mappedSectionObject);\n\n return mappedSectionArray;\n};\n"],"mappings":";;;;;;AAIA,MAAa,gBAAgB,YAAsC;AACjE,KAAI,OAAO,YAAY,SACrB,QAAO;AAET,KAAI,OAAO,YAAY,SACrB,QAAO;AAET,KAAI,OAAO,YAAY,UACrB,QAAO;AAET,KAAI,OAAQ,SAAuB,aAAa,UAAU;EACxD,MAAM,YAAY;EAClB,MAAM,UACJ,UAAU,UAAU;AAEtB,MACE,UAAU,aAAaA,yBAAU,eACjC,UAAU,aAAaA,yBAAU,eACjC,UAAU,aAAaA,yBAAU,aACjC,UAAU,aAAaA,yBAAU,aACjC,UAAU,aAAaA,yBAAU,KAEjC,QAAO,aAAa,QAAuB;AAG7C,MAAI,UAAU,aAAaA,yBAAU,OACnC,QAAO;AAGT,MAAI,UAAU,aAAaA,yBAAU,KACnC,QAAO;AAGT,MAAI,UAAU,aAAaA,yBAAU,SACnC,QAAO,aAAa,UAAU;AAGhC,SAAO;;AAGT,KAAI,CAAC,WAAW,OAAO,YAAY,SACjC,QAAO;AAGT,KAAI,MAAM,QAAQ,QAAQ,CACxB,QAAQ,QAA0B,IAChC,aACD;CAGH,MAAM,sBAAsB,OAAO,QAAQ,QAAQ,CAAC,KAAK,CAAC,KAAK,WAAW,CACxE,KACA,aAAa,MAAqB,CACnC,CAAC;AAIF,QAF2B,OAAO,YAAY,oBAErB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mergeDictionaries.cjs","names":["getNodeType","getMultilingualDictionary"],"sources":["../../../src/dictionaryManipulator/mergeDictionaries.ts"],"sourcesContent":["import { log } from '@intlayer/config/built';\nimport { colorizeKey, getAppLogger } from '@intlayer/config/logger';\nimport type {\n ContentNode,\n Dictionary,\n LocalDictionaryId,\n} from '@intlayer/types/dictionary';\nimport { getMultilingualDictionary } from '../deepTransformPlugins';\nimport { getNodeType } from './getNodeType';\n\n// Extended type that includes arrays for internal merge operations\ntype MergeableContent = ContentNode | ContentNode[];\n\nconst checkTypesMatch = (\n object1: ContentNode,\n object2: ContentNode,\n object2LocalId: LocalDictionaryId | undefined,\n dictionaryKey: string,\n path: string[] = []\n): void => {\n const appLogger = getAppLogger({ log });\n\n // If either side is missing/undefined, allow merge without error\n if (\n object1 === undefined ||\n object1 === null ||\n object2 === undefined ||\n object2 === null\n )\n return;\n\n const type1 = getNodeType(object1);\n const type2 = getNodeType(object2);\n\n // Unknown types are treated as flexible; skip strict mismatch reporting\n if (type1 === 'unknown' || type2 === 'unknown') return;\n\n if (type1 !== type2) {\n appLogger(\n [\n `Error: Dictionary ${colorizeKey(dictionaryKey)} has a multiple content files with type mismatch at path \"${path.join('.')}\": Cannot merge ${type1} with ${type2} while merging ${object2LocalId}`,\n ],\n {\n level: 'error',\n }\n );\n\n return;\n }\n};\n\n// Custom merge function that prefers destination (first dictionary) values\nconst customMerge = (\n destination: ContentNode,\n source: ContentNode\n): MergeableContent => {\n // If destination is undefined/null, use source\n if (destination === undefined || destination === null) {\n return source;\n }\n\n // If source is undefined/null, use destination\n if (source === undefined || source === null) {\n return destination;\n }\n\n // For primitive values, prefer destination (first dictionary)\n if (typeof destination !== 'object' || typeof source !== 'object') {\n return destination;\n }\n\n // For arrays, use our custom array merge\n if (Array.isArray(destination) && Array.isArray(source)) {\n return arrayMerge(\n destination as ContentNode[],\n source as ContentNode[]\n ) as MergeableContent;\n }\n\n // For objects, recursively merge with our custom logic\n if (typeof destination === 'object' && typeof source === 'object') {\n const result: Record<string, MergeableContent> = {};\n const allKeys = new Set([\n ...Object.keys(destination as unknown as Record<string, ContentNode>),\n ...Object.keys(source as unknown as Record<string, ContentNode>),\n ]);\n\n for (const key of allKeys) {\n result[key] = customMerge(\n (destination as unknown as Record<string, ContentNode>)[key],\n (source as unknown as Record<string, ContentNode>)[key]\n );\n }\n\n return result as unknown as MergeableContent;\n }\n\n // Fallback to destination\n return destination;\n};\n\n// Custom array merge strategy that merges arrays by key when present, otherwise by index\nconst arrayMerge = (\n destinationArray: ContentNode[],\n sourceArray: ContentNode[]\n): MergeableContent[] => {\n // Check if both arrays contain only primitives\n const destHasOnlyPrimitives = destinationArray.every(\n (item) => typeof item !== 'object' || item === null\n );\n const sourceHasOnlyPrimitives = sourceArray.every(\n (item) => typeof item !== 'object' || item === null\n );\n\n // If both arrays contain only primitives, use the source array (second dictionary)\n if (destHasOnlyPrimitives && sourceHasOnlyPrimitives) {\n return sourceArray;\n }\n\n // Otherwise, merge by index with object merging logic\n const result: MergeableContent[] = [];\n const maxLength = Math.max(destinationArray.length, sourceArray.length);\n\n for (let i = 0; i < maxLength; i++) {\n const destItem = destinationArray[i];\n const sourceItem = sourceArray[i];\n\n if (destItem === undefined && sourceItem === undefined) {\n } else if (destItem === undefined) {\n // Only source exists, add it\n result.push(sourceItem);\n } else if (sourceItem === undefined) {\n // Only destination exists, add it\n result.push(destItem);\n } else {\n // Both exist, merge them\n if (\n typeof destItem === 'object' &&\n typeof sourceItem === 'object' &&\n destItem !== null &&\n sourceItem !== null\n ) {\n // Check if both objects have a 'key' property for keyed merging\n if (\n 'key' in destItem &&\n 'key' in sourceItem &&\n (destItem as Record<string, string>).key ===\n (sourceItem as Record<string, string>).key\n ) {\n // Merge objects with same key, preferring destination (first dictionary) values\n result.push(customMerge(destItem, sourceItem));\n } else {\n // Merge objects by index, preferring destination (first dictionary) values\n result.push(customMerge(destItem, sourceItem));\n }\n } else {\n // For primitives or non-objects, use destination value (first dictionary)\n result.push(destItem);\n }\n }\n }\n\n return result;\n};\n\nexport const mergeDictionaries = (dictionaries: Dictionary[]): Dictionary => {\n const localIds = Array.from(\n new Set<LocalDictionaryId>(\n dictionaries.filter((dict) => dict.localId).map((dict) => dict.localId!)\n )\n );\n\n const dictionariesKeys = dictionaries.map((dict) => dict.key);\n\n // Check if all dictionaries have the same key\n if (new Set(dictionariesKeys).size !== 1) {\n throw new Error('All dictionaries must have the same key');\n }\n\n let mergedContent: Dictionary['content'] = dictionaries[0].content;\n\n for (let i = 1; i < dictionaries.length; i++) {\n // If the dictionary is a per-locale dictionary, transform it to a partial multilingual dictionary\n const currentDictionary = getMultilingualDictionary(dictionaries[i]);\n\n // Check types before merging\n checkTypesMatch(\n mergedContent,\n currentDictionary.content,\n currentDictionary.localId,\n currentDictionary.key,\n []\n );\n\n mergedContent = customMerge(\n mergedContent,\n currentDictionary.content\n ) as ContentNode;\n }\n\n const mergedDictionary: Dictionary = {\n key: dictionaries[0].key,\n content: mergedContent,\n localIds,\n };\n\n return mergedDictionary;\n};\n"],"mappings":";;;;;;;;AAaA,MAAM,mBACJ,SACA,SACA,gBACA,eACA,OAAiB,EAAE,KACV;CACT,MAAM,sDAAyB,EAAE,iCAAK,CAAC;AAGvC,KACE,YAAY,UACZ,YAAY,QACZ,YAAY,UACZ,YAAY,KAEZ;CAEF,MAAM,QAAQA,sDAAY,QAAQ;CAClC,MAAM,QAAQA,sDAAY,QAAQ;AAGlC,KAAI,UAAU,aAAa,UAAU,UAAW;AAEhD,KAAI,UAAU,OAAO;AACnB,YACE,CACE,8DAAiC,cAAc,CAAC,4DAA4D,KAAK,KAAK,IAAI,CAAC,kBAAkB,MAAM,QAAQ,MAAM,iBAAiB,iBACnL,EACD,EACE,OAAO,SACR,CACF;AAED;;;AAKJ,MAAM,eACJ,aACA,WACqB;AAErB,KAAI,gBAAgB,UAAa,gBAAgB,KAC/C,QAAO;AAIT,KAAI,WAAW,UAAa,WAAW,KACrC,QAAO;AAIT,KAAI,OAAO,gBAAgB,YAAY,OAAO,WAAW,SACvD,QAAO;AAIT,KAAI,MAAM,QAAQ,YAAY,IAAI,MAAM,QAAQ,OAAO,CACrD,QAAO,WACL,aACA,OACD;AAIH,KAAI,OAAO,gBAAgB,YAAY,OAAO,WAAW,UAAU;EACjE,MAAM,SAA2C,EAAE;EACnD,MAAM,UAAU,IAAI,IAAI,CACtB,GAAG,OAAO,KAAK,YAAsD,EACrE,GAAG,OAAO,KAAK,OAAiD,CACjE,CAAC;AAEF,OAAK,MAAM,OAAO,QAChB,QAAO,OAAO,YACX,YAAuD,MACvD,OAAkD,KACpD;AAGH,SAAO;;AAIT,QAAO;;AAIT,MAAM,cACJ,kBACA,gBACuB;CAEvB,MAAM,wBAAwB,iBAAiB,OAC5C,SAAS,OAAO,SAAS,YAAY,SAAS,KAChD;CACD,MAAM,0BAA0B,YAAY,OACzC,SAAS,OAAO,SAAS,YAAY,SAAS,KAChD;AAGD,KAAI,yBAAyB,wBAC3B,QAAO;CAIT,MAAM,SAA6B,EAAE;CACrC,MAAM,YAAY,KAAK,IAAI,iBAAiB,QAAQ,YAAY,OAAO;AAEvE,MAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAAK;EAClC,MAAM,WAAW,iBAAiB;EAClC,MAAM,aAAa,YAAY;AAE/B,MAAI,aAAa,UAAa,eAAe,QAAW,YAC7C,aAAa,OAEtB,QAAO,KAAK,WAAW;WACd,eAAe,OAExB,QAAO,KAAK,SAAS;WAInB,OAAO,aAAa,YACpB,OAAO,eAAe,YACtB,aAAa,QACb,eAAe,KAGf,KACE,SAAS,YACT,SAAS,cACR,SAAoC,QAClC,WAAsC,IAGzC,QAAO,KAAK,YAAY,UAAU,WAAW,CAAC;MAG9C,QAAO,KAAK,YAAY,UAAU,WAAW,CAAC;MAIhD,QAAO,KAAK,SAAS;;AAK3B,QAAO;;AAGT,MAAa,qBAAqB,iBAA2C;CAC3E,MAAM,WAAW,MAAM,KACrB,IAAI,IACF,aAAa,QAAQ,SAAS,KAAK,QAAQ,CAAC,KAAK,SAAS,KAAK,QAAS,CACzE,CACF;CAED,MAAM,mBAAmB,aAAa,KAAK,SAAS,KAAK,IAAI;AAG7D,KAAI,IAAI,IAAI,iBAAiB,CAAC,SAAS,EACrC,OAAM,IAAI,MAAM,0CAA0C;CAG5D,IAAI,gBAAuC,aAAa,GAAG;AAE3D,MAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;EAE5C,MAAM,oBAAoBC,iFAA0B,aAAa,GAAG;AAGpE,kBACE,eACA,kBAAkB,SAClB,kBAAkB,SAClB,kBAAkB,KAClB,EAAE,CACH;AAED,kBAAgB,YACd,eACA,kBAAkB,QACnB;;AASH,
|
|
1
|
+
{"version":3,"file":"mergeDictionaries.cjs","names":["getNodeType","getMultilingualDictionary"],"sources":["../../../src/dictionaryManipulator/mergeDictionaries.ts"],"sourcesContent":["import { log } from '@intlayer/config/built';\nimport { colorizeKey, getAppLogger } from '@intlayer/config/logger';\nimport type {\n ContentNode,\n Dictionary,\n LocalDictionaryId,\n} from '@intlayer/types/dictionary';\nimport { getMultilingualDictionary } from '../deepTransformPlugins';\nimport { getNodeType } from './getNodeType';\n\n// Extended type that includes arrays for internal merge operations\ntype MergeableContent = ContentNode | ContentNode[];\n\nconst checkTypesMatch = (\n object1: ContentNode,\n object2: ContentNode,\n object2LocalId: LocalDictionaryId | undefined,\n dictionaryKey: string,\n path: string[] = []\n): void => {\n const appLogger = getAppLogger({ log });\n\n // If either side is missing/undefined, allow merge without error\n if (\n object1 === undefined ||\n object1 === null ||\n object2 === undefined ||\n object2 === null\n )\n return;\n\n const type1 = getNodeType(object1);\n const type2 = getNodeType(object2);\n\n // Unknown types are treated as flexible; skip strict mismatch reporting\n if (type1 === 'unknown' || type2 === 'unknown') return;\n\n if (type1 !== type2) {\n appLogger(\n [\n `Error: Dictionary ${colorizeKey(dictionaryKey)} has a multiple content files with type mismatch at path \"${path.join('.')}\": Cannot merge ${type1} with ${type2} while merging ${object2LocalId}`,\n ],\n {\n level: 'error',\n }\n );\n\n return;\n }\n};\n\n// Custom merge function that prefers destination (first dictionary) values\nconst customMerge = (\n destination: ContentNode,\n source: ContentNode\n): MergeableContent => {\n // If destination is undefined/null, use source\n if (destination === undefined || destination === null) {\n return source;\n }\n\n // If source is undefined/null, use destination\n if (source === undefined || source === null) {\n return destination;\n }\n\n // For primitive values, prefer destination (first dictionary)\n if (typeof destination !== 'object' || typeof source !== 'object') {\n return destination;\n }\n\n // For arrays, use our custom array merge\n if (Array.isArray(destination) && Array.isArray(source)) {\n return arrayMerge(\n destination as ContentNode[],\n source as ContentNode[]\n ) as MergeableContent;\n }\n\n // For objects, recursively merge with our custom logic\n if (typeof destination === 'object' && typeof source === 'object') {\n const result: Record<string, MergeableContent> = {};\n const allKeys = new Set([\n ...Object.keys(destination as unknown as Record<string, ContentNode>),\n ...Object.keys(source as unknown as Record<string, ContentNode>),\n ]);\n\n for (const key of allKeys) {\n result[key] = customMerge(\n (destination as unknown as Record<string, ContentNode>)[key],\n (source as unknown as Record<string, ContentNode>)[key]\n );\n }\n\n return result as unknown as MergeableContent;\n }\n\n // Fallback to destination\n return destination;\n};\n\n// Custom array merge strategy that merges arrays by key when present, otherwise by index\nconst arrayMerge = (\n destinationArray: ContentNode[],\n sourceArray: ContentNode[]\n): MergeableContent[] => {\n // Check if both arrays contain only primitives\n const destHasOnlyPrimitives = destinationArray.every(\n (item) => typeof item !== 'object' || item === null\n );\n const sourceHasOnlyPrimitives = sourceArray.every(\n (item) => typeof item !== 'object' || item === null\n );\n\n // If both arrays contain only primitives, use the source array (second dictionary)\n if (destHasOnlyPrimitives && sourceHasOnlyPrimitives) {\n return sourceArray;\n }\n\n // Otherwise, merge by index with object merging logic\n const result: MergeableContent[] = [];\n const maxLength = Math.max(destinationArray.length, sourceArray.length);\n\n for (let i = 0; i < maxLength; i++) {\n const destItem = destinationArray[i];\n const sourceItem = sourceArray[i];\n\n if (destItem === undefined && sourceItem === undefined) {\n } else if (destItem === undefined) {\n // Only source exists, add it\n result.push(sourceItem);\n } else if (sourceItem === undefined) {\n // Only destination exists, add it\n result.push(destItem);\n } else {\n // Both exist, merge them\n if (\n typeof destItem === 'object' &&\n typeof sourceItem === 'object' &&\n destItem !== null &&\n sourceItem !== null\n ) {\n // Check if both objects have a 'key' property for keyed merging\n if (\n 'key' in destItem &&\n 'key' in sourceItem &&\n (destItem as Record<string, string>).key ===\n (sourceItem as Record<string, string>).key\n ) {\n // Merge objects with same key, preferring destination (first dictionary) values\n result.push(customMerge(destItem, sourceItem));\n } else {\n // Merge objects by index, preferring destination (first dictionary) values\n result.push(customMerge(destItem, sourceItem));\n }\n } else {\n // For primitives or non-objects, use destination value (first dictionary)\n result.push(destItem);\n }\n }\n }\n\n return result;\n};\n\nexport const mergeDictionaries = (dictionaries: Dictionary[]): Dictionary => {\n const localIds = Array.from(\n new Set<LocalDictionaryId>(\n dictionaries.filter((dict) => dict.localId).map((dict) => dict.localId!)\n )\n );\n\n const dictionariesKeys = dictionaries.map((dict) => dict.key);\n\n // Check if all dictionaries have the same key\n if (new Set(dictionariesKeys).size !== 1) {\n throw new Error('All dictionaries must have the same key');\n }\n\n let mergedContent: Dictionary['content'] = dictionaries[0].content;\n\n for (let i = 1; i < dictionaries.length; i++) {\n // If the dictionary is a per-locale dictionary, transform it to a partial multilingual dictionary\n const currentDictionary = getMultilingualDictionary(dictionaries[i]);\n\n // Check types before merging\n checkTypesMatch(\n mergedContent,\n currentDictionary.content,\n currentDictionary.localId,\n currentDictionary.key,\n []\n );\n\n mergedContent = customMerge(\n mergedContent,\n currentDictionary.content\n ) as ContentNode;\n }\n\n const mergedDictionary: Dictionary = {\n key: dictionaries[0].key,\n content: mergedContent,\n localIds,\n };\n\n return mergedDictionary;\n};\n"],"mappings":";;;;;;;;AAaA,MAAM,mBACJ,SACA,SACA,gBACA,eACA,OAAiB,EAAE,KACV;CACT,MAAM,sDAAyB,EAAE,iCAAK,CAAC;AAGvC,KACE,YAAY,UACZ,YAAY,QACZ,YAAY,UACZ,YAAY,KAEZ;CAEF,MAAM,QAAQA,sDAAY,QAAQ;CAClC,MAAM,QAAQA,sDAAY,QAAQ;AAGlC,KAAI,UAAU,aAAa,UAAU,UAAW;AAEhD,KAAI,UAAU,OAAO;AACnB,YACE,CACE,8DAAiC,cAAc,CAAC,4DAA4D,KAAK,KAAK,IAAI,CAAC,kBAAkB,MAAM,QAAQ,MAAM,iBAAiB,iBACnL,EACD,EACE,OAAO,SACR,CACF;AAED;;;AAKJ,MAAM,eACJ,aACA,WACqB;AAErB,KAAI,gBAAgB,UAAa,gBAAgB,KAC/C,QAAO;AAIT,KAAI,WAAW,UAAa,WAAW,KACrC,QAAO;AAIT,KAAI,OAAO,gBAAgB,YAAY,OAAO,WAAW,SACvD,QAAO;AAIT,KAAI,MAAM,QAAQ,YAAY,IAAI,MAAM,QAAQ,OAAO,CACrD,QAAO,WACL,aACA,OACD;AAIH,KAAI,OAAO,gBAAgB,YAAY,OAAO,WAAW,UAAU;EACjE,MAAM,SAA2C,EAAE;EACnD,MAAM,UAAU,IAAI,IAAI,CACtB,GAAG,OAAO,KAAK,YAAsD,EACrE,GAAG,OAAO,KAAK,OAAiD,CACjE,CAAC;AAEF,OAAK,MAAM,OAAO,QAChB,QAAO,OAAO,YACX,YAAuD,MACvD,OAAkD,KACpD;AAGH,SAAO;;AAIT,QAAO;;AAIT,MAAM,cACJ,kBACA,gBACuB;CAEvB,MAAM,wBAAwB,iBAAiB,OAC5C,SAAS,OAAO,SAAS,YAAY,SAAS,KAChD;CACD,MAAM,0BAA0B,YAAY,OACzC,SAAS,OAAO,SAAS,YAAY,SAAS,KAChD;AAGD,KAAI,yBAAyB,wBAC3B,QAAO;CAIT,MAAM,SAA6B,EAAE;CACrC,MAAM,YAAY,KAAK,IAAI,iBAAiB,QAAQ,YAAY,OAAO;AAEvE,MAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAAK;EAClC,MAAM,WAAW,iBAAiB;EAClC,MAAM,aAAa,YAAY;AAE/B,MAAI,aAAa,UAAa,eAAe,QAAW,YAC7C,aAAa,OAEtB,QAAO,KAAK,WAAW;WACd,eAAe,OAExB,QAAO,KAAK,SAAS;WAInB,OAAO,aAAa,YACpB,OAAO,eAAe,YACtB,aAAa,QACb,eAAe,KAGf,KACE,SAAS,YACT,SAAS,cACR,SAAoC,QAClC,WAAsC,IAGzC,QAAO,KAAK,YAAY,UAAU,WAAW,CAAC;MAG9C,QAAO,KAAK,YAAY,UAAU,WAAW,CAAC;MAIhD,QAAO,KAAK,SAAS;;AAK3B,QAAO;;AAGT,MAAa,qBAAqB,iBAA2C;CAC3E,MAAM,WAAW,MAAM,KACrB,IAAI,IACF,aAAa,QAAQ,SAAS,KAAK,QAAQ,CAAC,KAAK,SAAS,KAAK,QAAS,CACzE,CACF;CAED,MAAM,mBAAmB,aAAa,KAAK,SAAS,KAAK,IAAI;AAG7D,KAAI,IAAI,IAAI,iBAAiB,CAAC,SAAS,EACrC,OAAM,IAAI,MAAM,0CAA0C;CAG5D,IAAI,gBAAuC,aAAa,GAAG;AAE3D,MAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;EAE5C,MAAM,oBAAoBC,iFAA0B,aAAa,GAAG;AAGpE,kBACE,eACA,kBAAkB,SAClB,kBAAkB,SAClB,kBAAkB,KAClB,EAAE,CACH;AAED,kBAAgB,YACd,eACA,kBAAkB,QACnB;;AASH,QAAO;EALL,KAAK,aAAa,GAAG;EACrB,SAAS;EACT;EAGqB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalizeDictionary.cjs","names":["t","getPerLocaleDictionary","orderDictionaries"],"sources":["../../../src/dictionaryManipulator/normalizeDictionary.ts"],"sourcesContent":["import type { Dictionary } from '@intlayer/types/dictionary';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { getPerLocaleDictionary } from '../deepTransformPlugins';\nimport { t } from '../transpiler/translation';\nimport { orderDictionaries } from './orderDictionaries';\n\nexport const normalizeDictionary = (\n dictionary: Dictionary,\n configuration: IntlayerConfig\n): Dictionary => {\n const { locales } = configuration.internationalization;\n\n const parsedDictionary = JSON.parse(JSON.stringify(dictionary));\n\n // If the dictionary is a per-locale dictionary, transform it to a partial multilingual dictionary\n if (dictionary.locale) {\n return {\n ...dictionary,\n locale: undefined,\n content: t({\n [dictionary.locale]: dictionary.content,\n }),\n };\n }\n\n const perLocaleContent = locales.reduce(\n (acc, locale) => {\n const perLocaleDictionary = getPerLocaleDictionary(\n parsedDictionary,\n locale\n );\n\n acc[locale] = perLocaleDictionary.content;\n return acc;\n },\n {} as Record<Locale, Dictionary['content']>\n );\n\n return {\n ...dictionary,\n content: t(perLocaleContent),\n };\n};\n\nexport const normalizeDictionaries = (\n dictionaries: Dictionary[],\n configuration: IntlayerConfig\n): Dictionary[] => {\n const orderedDictionaries = orderDictionaries(dictionaries, configuration);\n\n const structuredDictionaries = orderedDictionaries.map((dictionary) =>\n normalizeDictionary(dictionary, configuration)\n );\n\n return structuredDictionaries;\n};\n"],"mappings":";;;;;;AAOA,MAAa,uBACX,YACA,kBACe;CACf,MAAM,EAAE,YAAY,cAAc;CAElC,MAAM,mBAAmB,KAAK,MAAM,KAAK,UAAU,WAAW,CAAC;AAG/D,KAAI,WAAW,OACb,QAAO;EACL,GAAG;EACH,QAAQ;EACR,SAASA,6CAAE,GACR,WAAW,SAAS,WAAW,SACjC,CAAC;EACH;CAGH,MAAM,mBAAmB,QAAQ,QAC9B,KAAK,WAAW;AAMf,MAAI,UALwBC,wEAC1B,kBACA,
|
|
1
|
+
{"version":3,"file":"normalizeDictionary.cjs","names":["t","getPerLocaleDictionary","orderDictionaries"],"sources":["../../../src/dictionaryManipulator/normalizeDictionary.ts"],"sourcesContent":["import type { Dictionary } from '@intlayer/types/dictionary';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { getPerLocaleDictionary } from '../deepTransformPlugins';\nimport { t } from '../transpiler/translation';\nimport { orderDictionaries } from './orderDictionaries';\n\nexport const normalizeDictionary = (\n dictionary: Dictionary,\n configuration: IntlayerConfig\n): Dictionary => {\n const { locales } = configuration.internationalization;\n\n const parsedDictionary = JSON.parse(JSON.stringify(dictionary));\n\n // If the dictionary is a per-locale dictionary, transform it to a partial multilingual dictionary\n if (dictionary.locale) {\n return {\n ...dictionary,\n locale: undefined,\n content: t({\n [dictionary.locale]: dictionary.content,\n }),\n };\n }\n\n const perLocaleContent = locales.reduce(\n (acc, locale) => {\n const perLocaleDictionary = getPerLocaleDictionary(\n parsedDictionary,\n locale\n );\n\n acc[locale] = perLocaleDictionary.content;\n return acc;\n },\n {} as Record<Locale, Dictionary['content']>\n );\n\n return {\n ...dictionary,\n content: t(perLocaleContent),\n };\n};\n\nexport const normalizeDictionaries = (\n dictionaries: Dictionary[],\n configuration: IntlayerConfig\n): Dictionary[] => {\n const orderedDictionaries = orderDictionaries(dictionaries, configuration);\n\n const structuredDictionaries = orderedDictionaries.map((dictionary) =>\n normalizeDictionary(dictionary, configuration)\n );\n\n return structuredDictionaries;\n};\n"],"mappings":";;;;;;AAOA,MAAa,uBACX,YACA,kBACe;CACf,MAAM,EAAE,YAAY,cAAc;CAElC,MAAM,mBAAmB,KAAK,MAAM,KAAK,UAAU,WAAW,CAAC;AAG/D,KAAI,WAAW,OACb,QAAO;EACL,GAAG;EACH,QAAQ;EACR,SAASA,6CAAE,GACR,WAAW,SAAS,WAAW,SACjC,CAAC;EACH;CAGH,MAAM,mBAAmB,QAAQ,QAC9B,KAAK,WAAW;AAMf,MAAI,UALwBC,wEAC1B,kBACA,OAG+B,CAAC;AAClC,SAAO;IAET,EAAE,CACH;AAED,QAAO;EACL,GAAG;EACH,SAASD,6CAAE,iBAAiB;EAC7B;;AAGH,MAAa,yBACX,cACA,kBACiB;AAOjB,QAN4BE,kEAAkB,cAAc,cAEV,CAAC,KAAK,eACtD,oBAAoB,YAAY,cAAc,CAGnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"date.cjs","names":["internationalization","getCachedIntl"],"sources":["../../../src/formatters/date.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getCachedIntl } from '../utils/intl';\n\nexport type DateTimePreset =\n | 'short'\n | 'long'\n | 'dateOnly'\n | 'timeOnly'\n | 'full';\n\nexport const presets: Record<DateTimePreset, Intl.DateTimeFormatOptions> = {\n short: {\n year: '2-digit',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n },\n long: {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n },\n full: {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n hour12: false,\n },\n dateOnly: {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n },\n timeOnly: {\n hour: 'numeric',\n minute: 'numeric',\n second: 'numeric',\n },\n};\n\n/**\n * Formats a date/time value into a localized string using Intl.DateTimeFormat.\n *\n * @example\n * date(new Date('2025-08-02T14:30:00Z'), { year: '2-digit', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' });\n * // \"08/02/25, 14:30\"\n *\n * @example\n * date(\"2025-08-02T14:30:00Z\", { locale: Locales.FRENCH, month: \"long\", day: \"numeric\" });\n * // \"2 août\"\n */\nexport const date = (\n date: Date | string | number,\n options?:\n | (Intl.DateTimeFormatOptions & { locale?: LocalesValues })\n | DateTimePreset\n): string => {\n const dateTime = new Date(date);\n\n const resolvedOptions =\n typeof options === 'string' ? (presets[options] ?? {}) : options;\n\n const locale =\n (typeof options === 'object' ? options?.locale : undefined) ??\n internationalization?.defaultLocale;\n\n const formatter = getCachedIntl(Intl.DateTimeFormat, locale, resolvedOptions);\n\n return formatter.format(dateTime);\n};\n"],"mappings":";;;;;;AAWA,MAAa,UAA8D;CACzE,OAAO;EACL,MAAM;EACN,OAAO;EACP,KAAK;EACL,MAAM;EACN,QAAQ;EACT;CACD,MAAM;EACJ,MAAM;EACN,OAAO;EACP,KAAK;EACL,MAAM;EACN,QAAQ;EACT;CACD,MAAM;EACJ,MAAM;EACN,OAAO;EACP,KAAK;EACL,MAAM;EACN,QAAQ;EACR,QAAQ;EACT;CACD,UAAU;EACR,MAAM;EACN,OAAO;EACP,KAAK;EACN;CACD,UAAU;EACR,MAAM;EACN,QAAQ;EACR,QAAQ;EACT;CACF;;;;;;;;;;;;AAaD,MAAa,QACX,MACA,YAGW;CACX,MAAM,WAAW,IAAI,KAAK,KAAK;CAE/B,MAAM,kBACJ,OAAO,YAAY,WAAY,QAAQ,YAAY,EAAE,GAAI;CAE3D,MAAM,UACH,OAAO,YAAY,WAAW,SAAS,SAAS,WACjDA,6CAAsB;AAIxB,QAFkBC,iCAAc,KAAK,gBAAgB,QAAQ,
|
|
1
|
+
{"version":3,"file":"date.cjs","names":["internationalization","getCachedIntl"],"sources":["../../../src/formatters/date.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getCachedIntl } from '../utils/intl';\n\nexport type DateTimePreset =\n | 'short'\n | 'long'\n | 'dateOnly'\n | 'timeOnly'\n | 'full';\n\nexport const presets: Record<DateTimePreset, Intl.DateTimeFormatOptions> = {\n short: {\n year: '2-digit',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n },\n long: {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n },\n full: {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n hour12: false,\n },\n dateOnly: {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n },\n timeOnly: {\n hour: 'numeric',\n minute: 'numeric',\n second: 'numeric',\n },\n};\n\n/**\n * Formats a date/time value into a localized string using Intl.DateTimeFormat.\n *\n * @example\n * date(new Date('2025-08-02T14:30:00Z'), { year: '2-digit', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' });\n * // \"08/02/25, 14:30\"\n *\n * @example\n * date(\"2025-08-02T14:30:00Z\", { locale: Locales.FRENCH, month: \"long\", day: \"numeric\" });\n * // \"2 août\"\n */\nexport const date = (\n date: Date | string | number,\n options?:\n | (Intl.DateTimeFormatOptions & { locale?: LocalesValues })\n | DateTimePreset\n): string => {\n const dateTime = new Date(date);\n\n const resolvedOptions =\n typeof options === 'string' ? (presets[options] ?? {}) : options;\n\n const locale =\n (typeof options === 'object' ? options?.locale : undefined) ??\n internationalization?.defaultLocale;\n\n const formatter = getCachedIntl(Intl.DateTimeFormat, locale, resolvedOptions);\n\n return formatter.format(dateTime);\n};\n"],"mappings":";;;;;;AAWA,MAAa,UAA8D;CACzE,OAAO;EACL,MAAM;EACN,OAAO;EACP,KAAK;EACL,MAAM;EACN,QAAQ;EACT;CACD,MAAM;EACJ,MAAM;EACN,OAAO;EACP,KAAK;EACL,MAAM;EACN,QAAQ;EACT;CACD,MAAM;EACJ,MAAM;EACN,OAAO;EACP,KAAK;EACL,MAAM;EACN,QAAQ;EACR,QAAQ;EACT;CACD,UAAU;EACR,MAAM;EACN,OAAO;EACP,KAAK;EACN;CACD,UAAU;EACR,MAAM;EACN,QAAQ;EACR,QAAQ;EACT;CACF;;;;;;;;;;;;AAaD,MAAa,QACX,MACA,YAGW;CACX,MAAM,WAAW,IAAI,KAAK,KAAK;CAE/B,MAAM,kBACJ,OAAO,YAAY,WAAY,QAAQ,YAAY,EAAE,GAAI;CAE3D,MAAM,UACH,OAAO,YAAY,WAAW,SAAS,SAAS,WACjDA,6CAAsB;AAIxB,QAFkBC,iCAAc,KAAK,gBAAgB,QAAQ,gBAE7C,CAAC,OAAO,SAAS"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"percentage.cjs","names":["getCachedIntl","internationalization"],"sources":["../../../src/formatters/percentage.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getCachedIntl } from '../utils/intl';\n\n/**\n * Formats a number as a percentage string (e.g., 0.25 → \"25%\").\n *\n * @example\n * percentage(0.25); // \"25%\"\n *\n * @example\n * percentage(0.25, { minimumFractionDigits: 2 }); // \"25.00%\"\n */\nexport const percentage = (\n value: string | number,\n {\n locale,\n ...options\n }: Intl.NumberFormatOptions & { locale?: LocalesValues } = {}\n): string => {\n let numericValue = Number(value);\n\n // Normalize: if user passes 10, treat it as 10% instead of 1000%\n if (numericValue > 1) {\n numericValue /= 100;\n }\n\n const formatter = getCachedIntl(\n Intl.NumberFormat,\n locale ?? internationalization?.defaultLocale,\n\n {\n style: 'percent',\n ...options,\n }\n );\n\n return formatter.format(Number(numericValue));\n};\n"],"mappings":";;;;;;;;;;;;;;;AAaA,MAAa,cACX,OACA,EACE,QACA,GAAG,YACsD,EAAE,KAClD;CACX,IAAI,eAAe,OAAO,MAAM;AAGhC,KAAI,eAAe,EACjB,iBAAgB;AAalB,QAVkBA,iCAChB,KAAK,cACL,UAAUC,6CAAsB,eAEhC;EACE,OAAO;EACP,GAAG;EACJ,
|
|
1
|
+
{"version":3,"file":"percentage.cjs","names":["getCachedIntl","internationalization"],"sources":["../../../src/formatters/percentage.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getCachedIntl } from '../utils/intl';\n\n/**\n * Formats a number as a percentage string (e.g., 0.25 → \"25%\").\n *\n * @example\n * percentage(0.25); // \"25%\"\n *\n * @example\n * percentage(0.25, { minimumFractionDigits: 2 }); // \"25.00%\"\n */\nexport const percentage = (\n value: string | number,\n {\n locale,\n ...options\n }: Intl.NumberFormatOptions & { locale?: LocalesValues } = {}\n): string => {\n let numericValue = Number(value);\n\n // Normalize: if user passes 10, treat it as 10% instead of 1000%\n if (numericValue > 1) {\n numericValue /= 100;\n }\n\n const formatter = getCachedIntl(\n Intl.NumberFormat,\n locale ?? internationalization?.defaultLocale,\n\n {\n style: 'percent',\n ...options,\n }\n );\n\n return formatter.format(Number(numericValue));\n};\n"],"mappings":";;;;;;;;;;;;;;;AAaA,MAAa,cACX,OACA,EACE,QACA,GAAG,YACsD,EAAE,KAClD;CACX,IAAI,eAAe,OAAO,MAAM;AAGhC,KAAI,eAAe,EACjB,iBAAgB;AAalB,QAVkBA,iCAChB,KAAK,cACL,UAAUC,6CAAsB,eAEhC;EACE,OAAO;EACP,GAAG;EACJ,CAGa,CAAC,OAAO,OAAO,aAAa,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deepTransform.cjs","names":["NodeTypes"],"sources":["../../../../src/interpreter/getContent/deepTransform.ts"],"sourcesContent":["import type { KeyPath } from '@intlayer/types/keyPath';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type { NodeProps } from './plugins';\n\n/**\n * Recursively traverses a node (object/array/primitive).\n * Applies the *first* plugin that can transform a node, then stops descending further.\n * If no plugin transforms it, it recurses into its children.\n */\nexport const deepTransformNode = (node: any, props: NodeProps): any => {\n // Otherwise, if it's an object, check if any plugin can handle it:\n for (const plugin of props.plugins ?? []) {\n if (plugin.canHandle(node)) {\n // Return the transformed node => do NOT recurse further\n return plugin.transform(node, props, (node: any, props: any) =>\n deepTransformNode(node, props)\n );\n }\n }\n\n // If it's null/undefined or not an object, just return it directly:\n if (node === null || typeof node !== 'object') {\n return node;\n }\n\n // If it's a framework-specific virtual node or already a transformed Proxy,\n // return it directly to avoid re-transforming its internal properties.\n if (\n (node as any).$$typeof !== undefined ||\n (node as any).__v_isVNode !== undefined ||\n (node as any)._isVNode !== undefined ||\n (node as any).isJSX !== undefined ||\n typeof node === 'function' // Proxies for html/markdown are functions\n ) {\n return node;\n }\n\n // If it's an array, transform each element:\n if (Array.isArray(node)) {\n return node.map((child, index) => {\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ARRAY, key: index } as KeyPath,\n ],\n };\n return deepTransformNode(child, childProps);\n });\n }\n\n // If no plugin transforms it, we keep traversing its properties.\n const result: Record<string, any> = {};\n for (const key in node) {\n Object.defineProperty(result, key, {\n enumerable: true,\n configurable: true,\n get: function () {\n const childProps = {\n ...props,\n children: node[key],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.OBJECT, key } as KeyPath,\n ],\n };\n const transformed = deepTransformNode(node[key], childProps);\n\n // Memoize the result onto the property to avoid re-calculating on next read\n Object.defineProperty(this, key, {\n value: transformed,\n enumerable: true,\n configurable: true,\n });\n return transformed;\n },\n });\n }\n\n return result;\n};\n"],"mappings":";;;;;;;;;;;AASA,MAAa,qBAAqB,MAAW,UAA0B;AAErE,MAAK,MAAM,UAAU,MAAM,WAAW,EAAE,CACtC,KAAI,OAAO,UAAU,KAAK,CAExB,QAAO,OAAO,UAAU,MAAM,QAAQ,MAAW,UAC/C,kBAAkB,MAAM,MAAM,CAC/B;AAKL,KAAI,SAAS,QAAQ,OAAO,SAAS,SACnC,QAAO;AAKT,KACG,KAAa,aAAa,UAC1B,KAAa,gBAAgB,UAC7B,KAAa,aAAa,UAC1B,KAAa,UAAU,UACxB,OAAO,SAAS,WAEhB,QAAO;AAIT,KAAI,MAAM,QAAQ,KAAK,CACrB,QAAO,KAAK,KAAK,OAAO,UAAU;AAShC,SAAO,kBAAkB,
|
|
1
|
+
{"version":3,"file":"deepTransform.cjs","names":["NodeTypes"],"sources":["../../../../src/interpreter/getContent/deepTransform.ts"],"sourcesContent":["import type { KeyPath } from '@intlayer/types/keyPath';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type { NodeProps } from './plugins';\n\n/**\n * Recursively traverses a node (object/array/primitive).\n * Applies the *first* plugin that can transform a node, then stops descending further.\n * If no plugin transforms it, it recurses into its children.\n */\nexport const deepTransformNode = (node: any, props: NodeProps): any => {\n // Otherwise, if it's an object, check if any plugin can handle it:\n for (const plugin of props.plugins ?? []) {\n if (plugin.canHandle(node)) {\n // Return the transformed node => do NOT recurse further\n return plugin.transform(node, props, (node: any, props: any) =>\n deepTransformNode(node, props)\n );\n }\n }\n\n // If it's null/undefined or not an object, just return it directly:\n if (node === null || typeof node !== 'object') {\n return node;\n }\n\n // If it's a framework-specific virtual node or already a transformed Proxy,\n // return it directly to avoid re-transforming its internal properties.\n if (\n (node as any).$$typeof !== undefined ||\n (node as any).__v_isVNode !== undefined ||\n (node as any)._isVNode !== undefined ||\n (node as any).isJSX !== undefined ||\n typeof node === 'function' // Proxies for html/markdown are functions\n ) {\n return node;\n }\n\n // If it's an array, transform each element:\n if (Array.isArray(node)) {\n return node.map((child, index) => {\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ARRAY, key: index } as KeyPath,\n ],\n };\n return deepTransformNode(child, childProps);\n });\n }\n\n // If no plugin transforms it, we keep traversing its properties.\n const result: Record<string, any> = {};\n for (const key in node) {\n Object.defineProperty(result, key, {\n enumerable: true,\n configurable: true,\n get: function () {\n const childProps = {\n ...props,\n children: node[key],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.OBJECT, key } as KeyPath,\n ],\n };\n const transformed = deepTransformNode(node[key], childProps);\n\n // Memoize the result onto the property to avoid re-calculating on next read\n Object.defineProperty(this, key, {\n value: transformed,\n enumerable: true,\n configurable: true,\n });\n return transformed;\n },\n });\n }\n\n return result;\n};\n"],"mappings":";;;;;;;;;;;AASA,MAAa,qBAAqB,MAAW,UAA0B;AAErE,MAAK,MAAM,UAAU,MAAM,WAAW,EAAE,CACtC,KAAI,OAAO,UAAU,KAAK,CAExB,QAAO,OAAO,UAAU,MAAM,QAAQ,MAAW,UAC/C,kBAAkB,MAAM,MAAM,CAC/B;AAKL,KAAI,SAAS,QAAQ,OAAO,SAAS,SACnC,QAAO;AAKT,KACG,KAAa,aAAa,UAC1B,KAAa,gBAAgB,UAC7B,KAAa,aAAa,UAC1B,KAAa,UAAU,UACxB,OAAO,SAAS,WAEhB,QAAO;AAIT,KAAI,MAAM,QAAQ,KAAK,CACrB,QAAO,KAAK,KAAK,OAAO,UAAU;AAShC,SAAO,kBAAkB,OAAO;GAP9B,GAAG;GACH,UAAU;GACV,SAAS,CACP,GAAG,MAAM,SACT;IAAE,MAAMA,yBAAU;IAAO,KAAK;IAAO,CACtC;GAEuC,CAAC;GAC3C;CAIJ,MAAM,SAA8B,EAAE;AACtC,MAAK,MAAM,OAAO,KAChB,QAAO,eAAe,QAAQ,KAAK;EACjC,YAAY;EACZ,cAAc;EACd,KAAK,WAAY;GACf,MAAM,aAAa;IACjB,GAAG;IACH,UAAU,KAAK;IACf,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAMA,yBAAU;KAAQ;KAAK,CAChC;IACF;GACD,MAAM,cAAc,kBAAkB,KAAK,MAAM,WAAW;AAG5D,UAAO,eAAe,MAAM,KAAK;IAC/B,OAAO;IACP,YAAY;IACZ,cAAc;IACf,CAAC;AACF,UAAO;;EAEV,CAAC;AAGJ,QAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.cjs","names":["NodeTypes","getTranslation","getEnumeration","getCondition","getInsertion","getGender","getNesting"],"sources":["../../../../src/interpreter/getContent/plugins.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type {\n ConditionContent,\n EnumerationContent,\n FileContent,\n Gender,\n GenderContent,\n InsertionContent,\n NestedContent,\n TranslationContent,\n} from '../../transpiler';\nimport { getCondition } from '../getCondition';\nimport { getEnumeration } from '../getEnumeration';\nimport { getGender } from '../getGender';\nimport { getInsertion } from '../getInsertion';\nimport { type GetNestingResult, getNesting } from '../getNesting';\nimport { getTranslation } from '../getTranslation';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/**\n * True when the translation node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_TRANSLATION =\n process.env['INTLAYER_NODE_TYPE_TRANSLATION'] === 'false';\n\n/**\n * True when the enumeration node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_ENUMERATION =\n process.env['INTLAYER_NODE_TYPE_ENUMERATION'] === 'false';\n\n/**\n * True when the condition node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_CONDITION =\n process.env['INTLAYER_NODE_TYPE_CONDITION'] === 'false';\n\n/**\n * True when the insertion node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_INSERTION =\n process.env['INTLAYER_NODE_TYPE_INSERTION'] === 'false';\n\n/**\n * True when the gender node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_GENDER = process.env['INTLAYER_NODE_TYPE_GENDER'] === 'false';\n\n/**\n * True when the nested node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_NESTED = process.env['INTLAYER_NODE_TYPE_NESTED'] === 'false';\n\n/**\n * True when the file node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_FILE = process.env['INTLAYER_NODE_TYPE_FILE'] === 'false';\n\n/** ---------------------------------------------\n * PLUGIN DEFINITION\n * --------------------------------------------- */\n\n/**\n * A plugin/transformer that can optionally transform a node during a single DFS pass.\n * - `canHandle` decides if the node is transformable by this plugin.\n * - `transform` returns the transformed node (and does not recurse further).\n *\n * > `transformFn` is a function that can be used to deeply transform inside the plugin.\n */\nexport type Plugins = {\n id: string;\n canHandle: (node: any) => boolean;\n transform: (\n node: any,\n props: NodeProps,\n transformFn: (node: any, props: NodeProps) => any\n ) => any;\n};\n\n/** ---------------------------------------------\n * FALLBACK PLUGIN\n *\n * Used to fallback a tree-shaken plugin\n * --------------------------------------------- */\n\nexport const fallbackPlugin: Plugins = {\n id: 'fallback-plugin',\n canHandle: () => false,\n transform: (node) => node,\n};\n\n/** ---------------------------------------------\n * TRANSLATION PLUGIN\n * --------------------------------------------- */\n\nexport type UnionKeys<T> = T extends unknown ? keyof T : never;\nexport type ValueAtKey<T, K> = T extends unknown\n ? K extends keyof T\n ? T[K]\n : never\n : never;\n\nexport type TranslationCond<T, S, L extends LocalesValues> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.TRANSLATION]: infer U;\n}\n ? U extends Record<PropertyKey, unknown>\n ? U[keyof U] extends Record<PropertyKey, unknown>\n ? {\n [K in UnionKeys<U[keyof U]>]: L extends keyof U\n ? K extends keyof U[L]\n ? U[L][K]\n : ValueAtKey<U[keyof U], K>\n : ValueAtKey<U[keyof U], K>;\n } extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : (L extends keyof U ? U[L] : U[keyof U]) extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : never\n : never;\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const translationPlugin = (\n locale: LocalesValues,\n fallback?: LocalesValues\n): Plugins =>\n TREE_SHAKE_TRANSLATION\n ? fallbackPlugin\n : {\n id: 'translation-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION,\n transform: (node: TranslationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.TRANSLATION] ?? {};\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const childProps = {\n ...props,\n children: original[key as keyof typeof original],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.TRANSLATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(\n original[key as keyof typeof original],\n childProps\n );\n }\n\n return getTranslation(result, locale, fallback);\n },\n };\n\n/** ---------------------------------------------\n * ENUMERATION PLUGIN\n * --------------------------------------------- */\n\nexport type EnumerationCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.ENUMERATION]: object;\n}\n ? (\n quantity: number\n ) => DeepTransformContent<\n T[typeof NodeTypes.ENUMERATION][keyof T[typeof NodeTypes.ENUMERATION]],\n S\n >\n : never;\n\n/** Enumeration plugin. Replaces node with a function that takes quantity => string. */\nexport const enumerationPlugin: Plugins = TREE_SHAKE_ENUMERATION\n ? fallbackPlugin\n : {\n id: 'enumeration-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.ENUMERATION,\n transform: (node: EnumerationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.ENUMERATION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as unknown as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ENUMERATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: number | { count: number }) => {\n const quantity = typeof arg === 'number' ? arg : arg.count;\n const subResult = getEnumeration(result, quantity);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * CONDITION PLUGIN\n * --------------------------------------------- */\n\nexport type ConditionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.CONDITION]: object;\n}\n ? (\n value: boolean | { value: boolean }\n ) => DeepTransformContent<\n T[typeof NodeTypes.CONDITION][keyof T[typeof NodeTypes.CONDITION]],\n S\n >\n : never;\n\n/** Condition plugin. Replaces node with a function that takes boolean => string. */\nexport const conditionPlugin: Plugins = TREE_SHAKE_CONDITION\n ? fallbackPlugin\n : {\n id: 'condition-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.CONDITION,\n transform: (node: ConditionContent, props, deepTransformNode) => {\n const original = node[NodeTypes.CONDITION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.CONDITION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: boolean | { value: boolean }) => {\n const value = typeof arg === 'boolean' ? arg : arg.value;\n const subResult = getCondition(result as any, value);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * INSERTION PLUGIN\n * --------------------------------------------- */\n\nexport type InsertionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.INSERTION]: infer I;\n fields: readonly string[];\n}\n ? (\n values: {\n [K in T['fields'][number]]: string | number;\n }\n ) => I extends string\n ? DeepTransformContent<string, S>\n : DeepTransformContent<I, S>\n : never;\n\n/** Insertion plugin. Replaces node with a function that takes quantity => string. */\nexport const insertionPlugin: Plugins = TREE_SHAKE_INSERTION\n ? fallbackPlugin\n : {\n id: 'insertion-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.INSERTION,\n transform: (node: InsertionContent, props, deepTransformNode) => {\n const newKeyPath: KeyPath[] = [\n ...props.keyPath,\n {\n type: NodeTypes.INSERTION,\n },\n ];\n\n const children = node[NodeTypes.INSERTION];\n\n /** Insertion string plugin. Replaces string node with a component that render the insertion. */\n const insertionStringPlugin: Plugins = {\n id: 'insertion-string-plugin',\n canHandle: (node) => typeof node === 'string',\n transform: (node: string, subProps, deepTransformNode) => {\n const transformedResult = deepTransformNode(node, {\n ...subProps,\n children: node,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) => plugin.id !== 'intlayer-node-plugin'\n ),\n ],\n });\n\n return (\n values: {\n [K in InsertionContent['fields'][number]]: string | number;\n }\n ) => {\n const children = getInsertion(transformedResult, values);\n\n return deepTransformNode(children, {\n ...subProps,\n plugins: props.plugins,\n children,\n });\n };\n },\n };\n\n return deepTransformNode(children, {\n ...props,\n children,\n keyPath: newKeyPath,\n plugins: [insertionStringPlugin, ...(props.plugins ?? [])],\n });\n },\n };\n\n/** ---------------------------------------------\n * GENDER PLUGIN\n * --------------------------------------------- */\n\nexport type GenderCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.GENDER]: object;\n}\n ? (\n value: Gender\n ) => DeepTransformContent<\n T[typeof NodeTypes.GENDER][keyof T[typeof NodeTypes.GENDER]],\n S\n >\n : never;\n\n/** Gender plugin. Replaces node with a function that takes gender => string. */\nexport const genderPlugin: Plugins = TREE_SHAKE_GENDER\n ? fallbackPlugin\n : {\n id: 'gender-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.GENDER,\n transform: (node: GenderContent, props, deepTransformNode) => {\n const original = node[NodeTypes.GENDER];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.GENDER, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (value: Gender) => getGender(result as any, value);\n },\n };\n\n/** ---------------------------------------------\n * NESTED PLUGIN\n * --------------------------------------------- */\n\nexport type NestedCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.NESTED]: infer U;\n}\n ? U extends {\n dictionaryKey: infer K extends DictionaryKeys;\n path?: infer P;\n }\n ? GetNestingResult<K, P, S>\n : never\n : never;\n\n/** Nested plugin. Replaces node with the result of `getNesting`. */\nexport const nestedPlugin = (locale?: LocalesValues): Plugins =>\n TREE_SHAKE_NESTED\n ? fallbackPlugin\n : {\n id: 'nested-plugin',\n canHandle: (node) =>\n typeof node === 'object' &&\n (node?.nodeType === NodeTypes.NESTED || node?.nodeType === 'n'),\n transform: (node: NestedContent, props) =>\n getNesting(\n node[NodeTypes.NESTED].dictionaryKey,\n node[NodeTypes.NESTED].path,\n {\n ...props,\n locale: (locale ?? props.locale) as Locale,\n }\n ),\n };\n\n/** ---------------------------------------------\n * FILE PLUGIN\n * --------------------------------------------- */\n\nexport type FileCond<T> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.FILE]: string;\n content?: string;\n}\n ? string\n : never;\n\n/** File plugin. Replaces node with the result of `getNesting`. */\nexport const filePlugin: Plugins = TREE_SHAKE_FILE\n ? fallbackPlugin\n : {\n id: 'file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.FILE,\n transform: (node: FileContent, props, deepTransform) =>\n deepTransform(node.content, {\n ...props,\n children: node.content,\n }),\n };\n\n/**\n * PLUGIN RESULT\n */\n\n/**\n * Interface that defines the properties of a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface NodeProps {\n dictionaryKey: string;\n keyPath: KeyPath[];\n plugins?: Plugins[];\n locale?: Locale;\n dictionaryPath?: string;\n children?: any;\n}\n\n/**\n * Interface that defines the plugins that can be used to transform a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface IInterpreterPlugin<T, S, L extends LocalesValues> {\n translation: TranslationCond<T, S, L>;\n enumeration: EnumerationCond<T, S, L>;\n condition: ConditionCond<T, S, L>;\n insertion: InsertionCond<T, S, L>;\n gender: GenderCond<T, S, L>;\n nested: NestedCond<T, S, L>;\n file: FileCond<T>;\n}\n\n/**\n * Allow to avoid overwriting import from `intlayer` package when `IInterpreterPlugin<T>` interface is augmented in another package, such as `react-intlayer`.\n */\nexport type IInterpreterPluginState = {\n translation: true;\n enumeration: true;\n condition: true;\n insertion: true;\n gender: true;\n nested: true;\n file: true;\n};\n\n/**\n * Utility type to check if a plugin can be applied to a node.\n */\ntype CheckApplyPlugin<\n T,\n K extends keyof IInterpreterPlugin<T, S, L>,\n S,\n L extends LocalesValues = DeclaredLocales,\n> = K extends keyof S // Test if the key is a key of S.\n ? // Test if the key of S is true. Then the plugin can be applied.\n S[K] extends true\n ? // Test if the key of S exist\n IInterpreterPlugin<T, S, L>[K] extends never\n ? never\n : // Test if the plugin condition is true (if it's not, the plugin is skipped for this node)\n IInterpreterPlugin<T, S, L>[K]\n : never\n : never;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\ntype Traverse<T, S, L extends LocalesValues = DeclaredLocales> =\n T extends ReadonlyArray<infer U> // Turn any read-only array into a plain mutable array\n ? Array<DeepTransformContent<U, S, L>>\n : T extends object\n ? { [K in keyof T]: DeepTransformContent<T[K], S, L> }\n : T;\n\nexport type IsAny<T> = 0 extends 1 & T ? true : false;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\nexport type DeepTransformContent<\n T,\n S = IInterpreterPluginState,\n L extends LocalesValues = DeclaredLocales,\n> =\n IsAny<T> extends true\n ? T\n : CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L> extends never // Check if there is a plugin for T:\n ? // No plugin was found, so try to transform T recursively:\n Traverse<T, S, L>\n : // A plugin was found – use the plugin's transformation.\n CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L>;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugins.cjs","names":["NodeTypes","getTranslation","getEnumeration","getCondition","getInsertion","getGender","getNesting"],"sources":["../../../../src/interpreter/getContent/plugins.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type {\n ConditionContent,\n EnumerationContent,\n FileContent,\n Gender,\n GenderContent,\n InsertionContent,\n NestedContent,\n TranslationContent,\n} from '../../transpiler';\nimport { getCondition } from '../getCondition';\nimport { getEnumeration } from '../getEnumeration';\nimport { getGender } from '../getGender';\nimport { getInsertion } from '../getInsertion';\nimport { type GetNestingResult, getNesting } from '../getNesting';\nimport { getTranslation } from '../getTranslation';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/**\n * True when the translation node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_TRANSLATION =\n process.env['INTLAYER_NODE_TYPE_TRANSLATION'] === 'false';\n\n/**\n * True when the enumeration node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_ENUMERATION =\n process.env['INTLAYER_NODE_TYPE_ENUMERATION'] === 'false';\n\n/**\n * True when the condition node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_CONDITION =\n process.env['INTLAYER_NODE_TYPE_CONDITION'] === 'false';\n\n/**\n * True when the insertion node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_INSERTION =\n process.env['INTLAYER_NODE_TYPE_INSERTION'] === 'false';\n\n/**\n * True when the gender node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_GENDER = process.env['INTLAYER_NODE_TYPE_GENDER'] === 'false';\n\n/**\n * True when the nested node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_NESTED = process.env['INTLAYER_NODE_TYPE_NESTED'] === 'false';\n\n/**\n * True when the file node type is explicitly disabled at build time.\n */\nconst TREE_SHAKE_FILE = process.env['INTLAYER_NODE_TYPE_FILE'] === 'false';\n\n/** ---------------------------------------------\n * PLUGIN DEFINITION\n * --------------------------------------------- */\n\n/**\n * A plugin/transformer that can optionally transform a node during a single DFS pass.\n * - `canHandle` decides if the node is transformable by this plugin.\n * - `transform` returns the transformed node (and does not recurse further).\n *\n * > `transformFn` is a function that can be used to deeply transform inside the plugin.\n */\nexport type Plugins = {\n id: string;\n canHandle: (node: any) => boolean;\n transform: (\n node: any,\n props: NodeProps,\n transformFn: (node: any, props: NodeProps) => any\n ) => any;\n};\n\n/** ---------------------------------------------\n * FALLBACK PLUGIN\n *\n * Used to fallback a tree-shaken plugin\n * --------------------------------------------- */\n\nexport const fallbackPlugin: Plugins = {\n id: 'fallback-plugin',\n canHandle: () => false,\n transform: (node) => node,\n};\n\n/** ---------------------------------------------\n * TRANSLATION PLUGIN\n * --------------------------------------------- */\n\nexport type UnionKeys<T> = T extends unknown ? keyof T : never;\nexport type ValueAtKey<T, K> = T extends unknown\n ? K extends keyof T\n ? T[K]\n : never\n : never;\n\nexport type TranslationCond<T, S, L extends LocalesValues> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.TRANSLATION]: infer U;\n}\n ? U extends Record<PropertyKey, unknown>\n ? U[keyof U] extends Record<PropertyKey, unknown>\n ? {\n [K in UnionKeys<U[keyof U]>]: L extends keyof U\n ? K extends keyof U[L]\n ? U[L][K]\n : ValueAtKey<U[keyof U], K>\n : ValueAtKey<U[keyof U], K>;\n } extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : (L extends keyof U ? U[L] : U[keyof U]) extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : never\n : never;\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const translationPlugin = (\n locale: LocalesValues,\n fallback?: LocalesValues\n): Plugins =>\n TREE_SHAKE_TRANSLATION\n ? fallbackPlugin\n : {\n id: 'translation-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION,\n transform: (node: TranslationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.TRANSLATION] ?? {};\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const childProps = {\n ...props,\n children: original[key as keyof typeof original],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.TRANSLATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(\n original[key as keyof typeof original],\n childProps\n );\n }\n\n return getTranslation(result, locale, fallback);\n },\n };\n\n/** ---------------------------------------------\n * ENUMERATION PLUGIN\n * --------------------------------------------- */\n\nexport type EnumerationCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.ENUMERATION]: object;\n}\n ? (\n quantity: number\n ) => DeepTransformContent<\n T[typeof NodeTypes.ENUMERATION][keyof T[typeof NodeTypes.ENUMERATION]],\n S\n >\n : never;\n\n/** Enumeration plugin. Replaces node with a function that takes quantity => string. */\nexport const enumerationPlugin: Plugins = TREE_SHAKE_ENUMERATION\n ? fallbackPlugin\n : {\n id: 'enumeration-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.ENUMERATION,\n transform: (node: EnumerationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.ENUMERATION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as unknown as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ENUMERATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: number | { count: number }) => {\n const quantity = typeof arg === 'number' ? arg : arg.count;\n const subResult = getEnumeration(result, quantity);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * CONDITION PLUGIN\n * --------------------------------------------- */\n\nexport type ConditionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.CONDITION]: object;\n}\n ? (\n value: boolean | { value: boolean }\n ) => DeepTransformContent<\n T[typeof NodeTypes.CONDITION][keyof T[typeof NodeTypes.CONDITION]],\n S\n >\n : never;\n\n/** Condition plugin. Replaces node with a function that takes boolean => string. */\nexport const conditionPlugin: Plugins = TREE_SHAKE_CONDITION\n ? fallbackPlugin\n : {\n id: 'condition-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.CONDITION,\n transform: (node: ConditionContent, props, deepTransformNode) => {\n const original = node[NodeTypes.CONDITION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.CONDITION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: boolean | { value: boolean }) => {\n const value = typeof arg === 'boolean' ? arg : arg.value;\n const subResult = getCondition(result as any, value);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * INSERTION PLUGIN\n * --------------------------------------------- */\n\nexport type InsertionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.INSERTION]: infer I;\n fields: readonly string[];\n}\n ? (\n values: {\n [K in T['fields'][number]]: string | number;\n }\n ) => I extends string\n ? DeepTransformContent<string, S>\n : DeepTransformContent<I, S>\n : never;\n\n/** Insertion plugin. Replaces node with a function that takes quantity => string. */\nexport const insertionPlugin: Plugins = TREE_SHAKE_INSERTION\n ? fallbackPlugin\n : {\n id: 'insertion-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.INSERTION,\n transform: (node: InsertionContent, props, deepTransformNode) => {\n const newKeyPath: KeyPath[] = [\n ...props.keyPath,\n {\n type: NodeTypes.INSERTION,\n },\n ];\n\n const children = node[NodeTypes.INSERTION];\n\n /** Insertion string plugin. Replaces string node with a component that render the insertion. */\n const insertionStringPlugin: Plugins = {\n id: 'insertion-string-plugin',\n canHandle: (node) => typeof node === 'string',\n transform: (node: string, subProps, deepTransformNode) => {\n const transformedResult = deepTransformNode(node, {\n ...subProps,\n children: node,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) => plugin.id !== 'intlayer-node-plugin'\n ),\n ],\n });\n\n return (\n values: {\n [K in InsertionContent['fields'][number]]: string | number;\n }\n ) => {\n const children = getInsertion(transformedResult, values);\n\n return deepTransformNode(children, {\n ...subProps,\n plugins: props.plugins,\n children,\n });\n };\n },\n };\n\n return deepTransformNode(children, {\n ...props,\n children,\n keyPath: newKeyPath,\n plugins: [insertionStringPlugin, ...(props.plugins ?? [])],\n });\n },\n };\n\n/** ---------------------------------------------\n * GENDER PLUGIN\n * --------------------------------------------- */\n\nexport type GenderCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.GENDER]: object;\n}\n ? (\n value: Gender\n ) => DeepTransformContent<\n T[typeof NodeTypes.GENDER][keyof T[typeof NodeTypes.GENDER]],\n S\n >\n : never;\n\n/** Gender plugin. Replaces node with a function that takes gender => string. */\nexport const genderPlugin: Plugins = TREE_SHAKE_GENDER\n ? fallbackPlugin\n : {\n id: 'gender-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.GENDER,\n transform: (node: GenderContent, props, deepTransformNode) => {\n const original = node[NodeTypes.GENDER];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.GENDER, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (value: Gender) => getGender(result as any, value);\n },\n };\n\n/** ---------------------------------------------\n * NESTED PLUGIN\n * --------------------------------------------- */\n\nexport type NestedCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.NESTED]: infer U;\n}\n ? U extends {\n dictionaryKey: infer K extends DictionaryKeys;\n path?: infer P;\n }\n ? GetNestingResult<K, P, S>\n : never\n : never;\n\n/** Nested plugin. Replaces node with the result of `getNesting`. */\nexport const nestedPlugin = (locale?: LocalesValues): Plugins =>\n TREE_SHAKE_NESTED\n ? fallbackPlugin\n : {\n id: 'nested-plugin',\n canHandle: (node) =>\n typeof node === 'object' &&\n (node?.nodeType === NodeTypes.NESTED || node?.nodeType === 'n'),\n transform: (node: NestedContent, props) =>\n getNesting(\n node[NodeTypes.NESTED].dictionaryKey,\n node[NodeTypes.NESTED].path,\n {\n ...props,\n locale: (locale ?? props.locale) as Locale,\n }\n ),\n };\n\n/** ---------------------------------------------\n * FILE PLUGIN\n * --------------------------------------------- */\n\nexport type FileCond<T> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.FILE]: string;\n content?: string;\n}\n ? string\n : never;\n\n/** File plugin. Replaces node with the result of `getNesting`. */\nexport const filePlugin: Plugins = TREE_SHAKE_FILE\n ? fallbackPlugin\n : {\n id: 'file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.FILE,\n transform: (node: FileContent, props, deepTransform) =>\n deepTransform(node.content, {\n ...props,\n children: node.content,\n }),\n };\n\n/**\n * PLUGIN RESULT\n */\n\n/**\n * Interface that defines the properties of a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface NodeProps {\n dictionaryKey: string;\n keyPath: KeyPath[];\n plugins?: Plugins[];\n locale?: Locale;\n dictionaryPath?: string;\n children?: any;\n}\n\n/**\n * Interface that defines the plugins that can be used to transform a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface IInterpreterPlugin<T, S, L extends LocalesValues> {\n translation: TranslationCond<T, S, L>;\n enumeration: EnumerationCond<T, S, L>;\n condition: ConditionCond<T, S, L>;\n insertion: InsertionCond<T, S, L>;\n gender: GenderCond<T, S, L>;\n nested: NestedCond<T, S, L>;\n file: FileCond<T>;\n}\n\n/**\n * Allow to avoid overwriting import from `intlayer` package when `IInterpreterPlugin<T>` interface is augmented in another package, such as `react-intlayer`.\n */\nexport type IInterpreterPluginState = {\n translation: true;\n enumeration: true;\n condition: true;\n insertion: true;\n gender: true;\n nested: true;\n file: true;\n};\n\n/**\n * Utility type to check if a plugin can be applied to a node.\n */\ntype CheckApplyPlugin<\n T,\n K extends keyof IInterpreterPlugin<T, S, L>,\n S,\n L extends LocalesValues = DeclaredLocales,\n> = K extends keyof S // Test if the key is a key of S.\n ? // Test if the key of S is true. Then the plugin can be applied.\n S[K] extends true\n ? // Test if the key of S exist\n IInterpreterPlugin<T, S, L>[K] extends never\n ? never\n : // Test if the plugin condition is true (if it's not, the plugin is skipped for this node)\n IInterpreterPlugin<T, S, L>[K]\n : never\n : never;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\ntype Traverse<T, S, L extends LocalesValues = DeclaredLocales> =\n T extends ReadonlyArray<infer U> // Turn any read-only array into a plain mutable array\n ? Array<DeepTransformContent<U, S, L>>\n : T extends object\n ? { [K in keyof T]: DeepTransformContent<T[K], S, L> }\n : T;\n\nexport type IsAny<T> = 0 extends 1 & T ? true : false;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\nexport type DeepTransformContent<\n T,\n S = IInterpreterPluginState,\n L extends LocalesValues = DeclaredLocales,\n> =\n IsAny<T> extends true\n ? T\n : CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L> extends never // Check if there is a plugin for T:\n ? // No plugin was found, so try to transform T recursively:\n Traverse<T, S, L>\n : // A plugin was found – use the plugin's transformation.\n CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L>;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getGender.cjs","names":[],"sources":["../../../src/interpreter/getGender.ts"],"sourcesContent":["import type { Gender, GenderContentStates } from '../transpiler';\n\ntype GenderEntry = Gender | 'm' | 'f';\n\nconst getGenderEntry = (gender: GenderEntry): Gender => {\n if (gender === 'm' || gender === 'male') return 'male';\n if (gender === 'f' || gender === 'female') return 'female';\n return 'fallback';\n};\n\n/**\n * Allow to pick a content based on a gender.\n *\n * Usage:\n *\n * ```ts\n * const content = getGender({\n * 'true': 'The gender is validated',\n * 'false': 'The gender is not validated',\n * }, true);\n * // 'The gender is validated'\n * ```\n *\n * The last key provided will be used as the fallback value.\n *\n * ```ts\n * const content = getGender({\n * 'false': 'The gender is not validated',\n * 'true': 'The gender is validated',\n * }, undefined);\n * // 'The gender is validated'\n */\nexport const getGender = <Content>(\n genderContent: GenderContentStates<Content>,\n gender: GenderEntry\n): Content => {\n const stateList = Object.keys(genderContent);\n\n const fallbackState = stateList[\n stateList.length - 1\n ] as keyof typeof genderContent;\n\n const genderEntry = getGenderEntry(gender);\n\n // Default or error handling if no keys match\n return (\n genderContent[genderEntry as keyof typeof genderContent] ??\n genderContent.fallback ??\n (genderContent[fallbackState] as Content)\n );\n};\n"],"mappings":";;;AAIA,MAAM,kBAAkB,WAAgC;AACtD,KAAI,WAAW,OAAO,WAAW,OAAQ,QAAO;AAChD,KAAI,WAAW,OAAO,WAAW,SAAU,QAAO;AAClD,QAAO;;;;;;;;;;;;;;;;;;;;;;;;AAyBT,MAAa,aACX,eACA,WACY;CACZ,MAAM,YAAY,OAAO,KAAK,cAAc;CAE5C,MAAM,gBAAgB,UACpB,UAAU,SAAS;AAMrB,QACE,cAJkB,eAAe,
|
|
1
|
+
{"version":3,"file":"getGender.cjs","names":[],"sources":["../../../src/interpreter/getGender.ts"],"sourcesContent":["import type { Gender, GenderContentStates } from '../transpiler';\n\ntype GenderEntry = Gender | 'm' | 'f';\n\nconst getGenderEntry = (gender: GenderEntry): Gender => {\n if (gender === 'm' || gender === 'male') return 'male';\n if (gender === 'f' || gender === 'female') return 'female';\n return 'fallback';\n};\n\n/**\n * Allow to pick a content based on a gender.\n *\n * Usage:\n *\n * ```ts\n * const content = getGender({\n * 'true': 'The gender is validated',\n * 'false': 'The gender is not validated',\n * }, true);\n * // 'The gender is validated'\n * ```\n *\n * The last key provided will be used as the fallback value.\n *\n * ```ts\n * const content = getGender({\n * 'false': 'The gender is not validated',\n * 'true': 'The gender is validated',\n * }, undefined);\n * // 'The gender is validated'\n */\nexport const getGender = <Content>(\n genderContent: GenderContentStates<Content>,\n gender: GenderEntry\n): Content => {\n const stateList = Object.keys(genderContent);\n\n const fallbackState = stateList[\n stateList.length - 1\n ] as keyof typeof genderContent;\n\n const genderEntry = getGenderEntry(gender);\n\n // Default or error handling if no keys match\n return (\n genderContent[genderEntry as keyof typeof genderContent] ??\n genderContent.fallback ??\n (genderContent[fallbackState] as Content)\n );\n};\n"],"mappings":";;;AAIA,MAAM,kBAAkB,WAAgC;AACtD,KAAI,WAAW,OAAO,WAAW,OAAQ,QAAO;AAChD,KAAI,WAAW,OAAO,WAAW,SAAU,QAAO;AAClD,QAAO;;;;;;;;;;;;;;;;;;;;;;;;AAyBT,MAAa,aACX,eACA,WACY;CACZ,MAAM,YAAY,OAAO,KAAK,cAAc;CAE5C,MAAM,gBAAgB,UACpB,UAAU,SAAS;AAMrB,QACE,cAJkB,eAAe,OAIR,KACzB,cAAc,YACb,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getHTML.cjs","names":[],"sources":["../../../src/interpreter/getHTML.ts"],"sourcesContent":["/**\n * Component function that receives properly typed props\n * Props include:\n * - children?: any[] - Array of child elements (ReactNode[], VNode[], etc.)\n * - [key: string]: any - Any HTML attributes (className, style, href, etc.)\n */\ntype Component = (props: { children?: any[]; [key: string]: any }) => any;\n\n/**\n * Component object that delegates to another component\n */\ntype ComponentObject = {\n tag: string;\n props?: Record<string, any>;\n};\n\n/**\n * Components map:\n * - Function components receive typed props\n * - String components delegate to another tag\n * - Object components delegate with additional props\n */\ntype Components = Record<string, Component | string | ComponentObject>;\n\n/**\n * Helper to parse attributes from a tag string.\n */\nconst parseAttributes = (attributes: string): Record<string, string> => {\n const props: Record<string, string> = {};\n const attrRegex = /([a-zA-Z0-9-]+)=\"([^\"]*)\"/g;\n\n let match = attrRegex.exec(attributes);\n while (match !== null) {\n props[match[1]] = match[2];\n match = attrRegex.exec(attributes);\n }\n return props;\n};\n\ntype ASTNode =\n | string\n | {\n tagName: string;\n props: Record<string, string>;\n children: ASTNode[];\n };\n\nconst astCache = new Map<string, ASTNode[]>();\n\nconst parseHTML = (content: string): ASTNode[] => {\n if (astCache.has(content)) {\n return astCache.get(content)!;\n }\n\n if (typeof content !== 'string') {\n return [];\n }\n\n const tagRegex = /<(\\/)?([a-zA-Z0-9.-]+)([\\s\\S]*?)(\\/?)>/g;\n const elements: ASTNode[] = [];\n const stack: {\n tagName: string;\n children: ASTNode[];\n props: Record<string, string>;\n }[] = [];\n\n let lastIndex = 0;\n let match = tagRegex.exec(content);\n\n const appendChild = (child: ASTNode) => {\n const target =\n stack.length > 0 ? stack[stack.length - 1].children : elements;\n target.push(child);\n };\n\n while (match !== null) {\n const [fullMatch, isClosingRaw, tagName, attributesRaw, isSelfClosingRaw] =\n match;\n const matchIndex = match.index;\n\n if (matchIndex > lastIndex) {\n appendChild(content.slice(lastIndex, matchIndex));\n }\n\n const isClosing = isClosingRaw === '/';\n const isSelfClosing =\n isSelfClosingRaw === '/' ||\n attributesRaw.trim().endsWith('/') ||\n fullMatch.endsWith('/>');\n\n const cleanedAttributes = attributesRaw.trim().replace(/\\/$/, '').trim();\n\n if (isClosing) {\n const last = stack[stack.length - 1];\n\n // Only pop if the tag names match\n if (last && last.tagName === tagName) {\n const popped = stack.pop();\n if (popped) {\n appendChild({\n tagName: popped.tagName,\n props: popped.props,\n children: popped.children,\n });\n }\n }\n // If tags don't match or no open tag, silently ignore the closing tag\n } else if (isSelfClosing) {\n const tagProps = parseAttributes(cleanedAttributes);\n appendChild({\n tagName,\n props: tagProps,\n children: [],\n });\n } else {\n const tagProps = parseAttributes(cleanedAttributes);\n stack.push({ tagName, children: [], props: tagProps });\n }\n\n lastIndex = matchIndex + fullMatch.length;\n match = tagRegex.exec(content);\n }\n\n if (lastIndex < content.length) {\n appendChild(content.slice(lastIndex));\n }\n\n // Handle unclosed tags by appending them to the root or parent\n while (stack.length > 0) {\n const last = stack.pop();\n if (last) {\n appendChild({\n tagName: last.tagName,\n props: last.props,\n children: last.children,\n });\n }\n }\n\n astCache.set(content, elements);\n return elements;\n};\n\n/**\n * Interprets a string containing HTML-like tags and replaces them with provided components or strings.\n */\nexport const getHTML = (content: string, values: Components): any => {\n // Parse into AST (cached)\n const ast = parseHTML(content);\n\n // Render AST\n let keyCounter = 0;\n\n const renderASTNode = (node: ASTNode): any => {\n if (typeof node === 'string') {\n return node;\n }\n\n const { tagName, props, children } = node;\n const renderedChildren = children.flatMap(renderASTNode);\n const index = keyCounter++;\n\n let override = values[tagName];\n\n if (!override) {\n const lowerTagName = tagName.toLowerCase();\n const foundKey = Object.keys(values).find(\n (key) => key.toLowerCase() === lowerTagName\n );\n\n if (foundKey) override = values[foundKey];\n }\n\n const key = `html-tag-${tagName}-${index}`;\n\n if (typeof override === 'function') {\n return override({ ...props, children: renderedChildren, key });\n }\n\n if (typeof override === 'string') {\n const component = values[override];\n\n if (typeof component === 'function') {\n return component({ ...props, children: renderedChildren, key });\n }\n return renderedChildren;\n }\n\n if (\n typeof override === 'object' &&\n override !== null &&\n 'tag' in override\n ) {\n const { tag: targetTag, props: extraProps } = override as ComponentObject;\n const component = values[targetTag];\n\n if (typeof component === 'function') {\n return component({\n ...props,\n ...extraProps,\n children: renderedChildren,\n key,\n });\n }\n return renderedChildren;\n }\n\n // Default: Skip tag, render children\n return renderedChildren;\n };\n\n const result = ast.flatMap(renderASTNode);\n return result.length === 1 ? result[0] : result;\n};\n"],"mappings":";;;;;;AA2BA,MAAM,mBAAmB,eAA+C;CACtE,MAAM,QAAgC,EAAE;CACxC,MAAM,YAAY;CAElB,IAAI,QAAQ,UAAU,KAAK,WAAW;AACtC,QAAO,UAAU,MAAM;AACrB,QAAM,MAAM,MAAM,MAAM;AACxB,UAAQ,UAAU,KAAK,WAAW;;AAEpC,QAAO;;AAWT,MAAM,2BAAW,IAAI,KAAwB;AAE7C,MAAM,aAAa,YAA+B;AAChD,KAAI,SAAS,IAAI,QAAQ,CACvB,QAAO,SAAS,IAAI,QAAQ;AAG9B,KAAI,OAAO,YAAY,SACrB,QAAO,EAAE;CAGX,MAAM,WAAW;CACjB,MAAM,WAAsB,EAAE;CAC9B,MAAM,QAIA,EAAE;CAER,IAAI,YAAY;CAChB,IAAI,QAAQ,SAAS,KAAK,QAAQ;CAElC,MAAM,eAAe,UAAmB;AAGtC,GADE,MAAM,SAAS,IAAI,MAAM,MAAM,SAAS,GAAG,WAAW,UACjD,KAAK,MAAM;;AAGpB,QAAO,UAAU,MAAM;EACrB,MAAM,CAAC,WAAW,cAAc,SAAS,eAAe,oBACtD;EACF,MAAM,aAAa,MAAM;AAEzB,MAAI,aAAa,UACf,aAAY,QAAQ,MAAM,WAAW,WAAW,CAAC;EAGnD,MAAM,YAAY,iBAAiB;EACnC,MAAM,gBACJ,qBAAqB,OACrB,cAAc,MAAM,CAAC,SAAS,IAAI,IAClC,UAAU,SAAS,KAAK;EAE1B,MAAM,oBAAoB,cAAc,MAAM,CAAC,QAAQ,OAAO,GAAG,CAAC,MAAM;AAExE,MAAI,WAAW;GACb,MAAM,OAAO,MAAM,MAAM,SAAS;AAGlC,OAAI,QAAQ,KAAK,YAAY,SAAS;IACpC,MAAM,SAAS,MAAM,KAAK;AAC1B,QAAI,OACF,aAAY;KACV,SAAS,OAAO;KAChB,OAAO,OAAO;KACd,UAAU,OAAO;KAClB,CAAC;;aAIG,cAET,aAAY;GACV;GACA,OAHe,gBAAgB,
|
|
1
|
+
{"version":3,"file":"getHTML.cjs","names":[],"sources":["../../../src/interpreter/getHTML.ts"],"sourcesContent":["/**\n * Component function that receives properly typed props\n * Props include:\n * - children?: any[] - Array of child elements (ReactNode[], VNode[], etc.)\n * - [key: string]: any - Any HTML attributes (className, style, href, etc.)\n */\ntype Component = (props: { children?: any[]; [key: string]: any }) => any;\n\n/**\n * Component object that delegates to another component\n */\ntype ComponentObject = {\n tag: string;\n props?: Record<string, any>;\n};\n\n/**\n * Components map:\n * - Function components receive typed props\n * - String components delegate to another tag\n * - Object components delegate with additional props\n */\ntype Components = Record<string, Component | string | ComponentObject>;\n\n/**\n * Helper to parse attributes from a tag string.\n */\nconst parseAttributes = (attributes: string): Record<string, string> => {\n const props: Record<string, string> = {};\n const attrRegex = /([a-zA-Z0-9-]+)=\"([^\"]*)\"/g;\n\n let match = attrRegex.exec(attributes);\n while (match !== null) {\n props[match[1]] = match[2];\n match = attrRegex.exec(attributes);\n }\n return props;\n};\n\ntype ASTNode =\n | string\n | {\n tagName: string;\n props: Record<string, string>;\n children: ASTNode[];\n };\n\nconst astCache = new Map<string, ASTNode[]>();\n\nconst parseHTML = (content: string): ASTNode[] => {\n if (astCache.has(content)) {\n return astCache.get(content)!;\n }\n\n if (typeof content !== 'string') {\n return [];\n }\n\n const tagRegex = /<(\\/)?([a-zA-Z0-9.-]+)([\\s\\S]*?)(\\/?)>/g;\n const elements: ASTNode[] = [];\n const stack: {\n tagName: string;\n children: ASTNode[];\n props: Record<string, string>;\n }[] = [];\n\n let lastIndex = 0;\n let match = tagRegex.exec(content);\n\n const appendChild = (child: ASTNode) => {\n const target =\n stack.length > 0 ? stack[stack.length - 1].children : elements;\n target.push(child);\n };\n\n while (match !== null) {\n const [fullMatch, isClosingRaw, tagName, attributesRaw, isSelfClosingRaw] =\n match;\n const matchIndex = match.index;\n\n if (matchIndex > lastIndex) {\n appendChild(content.slice(lastIndex, matchIndex));\n }\n\n const isClosing = isClosingRaw === '/';\n const isSelfClosing =\n isSelfClosingRaw === '/' ||\n attributesRaw.trim().endsWith('/') ||\n fullMatch.endsWith('/>');\n\n const cleanedAttributes = attributesRaw.trim().replace(/\\/$/, '').trim();\n\n if (isClosing) {\n const last = stack[stack.length - 1];\n\n // Only pop if the tag names match\n if (last && last.tagName === tagName) {\n const popped = stack.pop();\n if (popped) {\n appendChild({\n tagName: popped.tagName,\n props: popped.props,\n children: popped.children,\n });\n }\n }\n // If tags don't match or no open tag, silently ignore the closing tag\n } else if (isSelfClosing) {\n const tagProps = parseAttributes(cleanedAttributes);\n appendChild({\n tagName,\n props: tagProps,\n children: [],\n });\n } else {\n const tagProps = parseAttributes(cleanedAttributes);\n stack.push({ tagName, children: [], props: tagProps });\n }\n\n lastIndex = matchIndex + fullMatch.length;\n match = tagRegex.exec(content);\n }\n\n if (lastIndex < content.length) {\n appendChild(content.slice(lastIndex));\n }\n\n // Handle unclosed tags by appending them to the root or parent\n while (stack.length > 0) {\n const last = stack.pop();\n if (last) {\n appendChild({\n tagName: last.tagName,\n props: last.props,\n children: last.children,\n });\n }\n }\n\n astCache.set(content, elements);\n return elements;\n};\n\n/**\n * Interprets a string containing HTML-like tags and replaces them with provided components or strings.\n */\nexport const getHTML = (content: string, values: Components): any => {\n // Parse into AST (cached)\n const ast = parseHTML(content);\n\n // Render AST\n let keyCounter = 0;\n\n const renderASTNode = (node: ASTNode): any => {\n if (typeof node === 'string') {\n return node;\n }\n\n const { tagName, props, children } = node;\n const renderedChildren = children.flatMap(renderASTNode);\n const index = keyCounter++;\n\n let override = values[tagName];\n\n if (!override) {\n const lowerTagName = tagName.toLowerCase();\n const foundKey = Object.keys(values).find(\n (key) => key.toLowerCase() === lowerTagName\n );\n\n if (foundKey) override = values[foundKey];\n }\n\n const key = `html-tag-${tagName}-${index}`;\n\n if (typeof override === 'function') {\n return override({ ...props, children: renderedChildren, key });\n }\n\n if (typeof override === 'string') {\n const component = values[override];\n\n if (typeof component === 'function') {\n return component({ ...props, children: renderedChildren, key });\n }\n return renderedChildren;\n }\n\n if (\n typeof override === 'object' &&\n override !== null &&\n 'tag' in override\n ) {\n const { tag: targetTag, props: extraProps } = override as ComponentObject;\n const component = values[targetTag];\n\n if (typeof component === 'function') {\n return component({\n ...props,\n ...extraProps,\n children: renderedChildren,\n key,\n });\n }\n return renderedChildren;\n }\n\n // Default: Skip tag, render children\n return renderedChildren;\n };\n\n const result = ast.flatMap(renderASTNode);\n return result.length === 1 ? result[0] : result;\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getInsertion.cjs","names":[],"sources":["../../../src/interpreter/getInsertion.ts"],"sourcesContent":["import type { InsertionContent } from '../transpiler';\n\n/**\n * Allow to insert values in a string.\n *\n * Usage:\n *\n * ```ts\n * const content = getInsertion('Hello {{name}}!', {\n * name: 'John',\n * });\n * // 'Hello John!'\n * ```\n *\n */\nexport const getInsertion = (\n content: string,\n values: { [K in InsertionContent['fields'][number]]: string | number }\n) =>\n content.replace(/\\{\\{\\s*(.*?)\\s*\\}\\}/g, (_, key) => {\n const trimmedKey = key.trim();\n return (values[trimmedKey] ?? '').toString();\n });\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,MAAa,gBACX,SACA,WAEA,QAAQ,QAAQ,yBAAyB,GAAG,QAAQ;AAElD,SAAQ,OADW,IAAI,
|
|
1
|
+
{"version":3,"file":"getInsertion.cjs","names":[],"sources":["../../../src/interpreter/getInsertion.ts"],"sourcesContent":["import type { InsertionContent } from '../transpiler';\n\n/**\n * Allow to insert values in a string.\n *\n * Usage:\n *\n * ```ts\n * const content = getInsertion('Hello {{name}}!', {\n * name: 'John',\n * });\n * // 'Hello John!'\n * ```\n *\n */\nexport const getInsertion = (\n content: string,\n values: { [K in InsertionContent['fields'][number]]: string | number }\n) =>\n content.replace(/\\{\\{\\s*(.*?)\\s*\\}\\}/g, (_, key) => {\n const trimmedKey = key.trim();\n return (values[trimmedKey] ?? '').toString();\n });\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,MAAa,gBACX,SACA,WAEA,QAAQ,QAAQ,yBAAyB,GAAG,QAAQ;AAElD,SAAQ,OADW,IAAI,MACE,KAAK,IAAI,UAAU;EAC5C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getIntlayer.cjs","names":["getDictionary"],"sources":["../../../src/interpreter/getIntlayer.ts"],"sourcesContent":["import { log } from '@intlayer/config/built';\nimport { colorizeKey, getAppLogger } from '@intlayer/config/logger';\nimport { getDictionaries } from '@intlayer/dictionaries-entry';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n DictionaryRegistryContent,\n DictionaryRegistryElement,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type {\n DeepTransformContent,\n IInterpreterPluginState,\n Plugins,\n} from './getContent';\nimport { getDictionary } from './getDictionary';\n\n/**\n * Creates a Recursive Proxy that returns the path of the accessed key\n * stringified. This prevents the app from crashing on undefined access.\n */\nconst createSafeFallback = (path = ''): any => {\n return new Proxy(\n // Target is a function so it can be called if the dictionary expects a function\n () => path,\n {\n get: (_target, prop) => {\n // Handle common object methods to prevent infinite recursion or weird behavior\n if (\n prop === 'toJSON' ||\n prop === Symbol.toPrimitive ||\n prop === 'toString'\n ) {\n return () => path;\n }\n if (prop === 'then') {\n return undefined; // Prevent it from being treated as a Promise\n }\n\n // Recursively build the path (e.g., \"myDictionary.home.title\")\n const nextPath = path ? `${path}.${String(prop)}` : String(prop);\n return createSafeFallback(nextPath);\n },\n // If the code tries to execute the missing key as a function: t.title()\n apply: () => {\n return path;\n },\n }\n );\n};\n\nconst dictionaryCache = new Map<string, any>();\n\nexport const getIntlayer = <\n T extends DictionaryKeys,\n L extends LocalesValues = DeclaredLocales,\n>(\n key: T,\n locale?: L,\n plugins?: Plugins[]\n): DeepTransformContent<\n DictionaryRegistryContent<T>,\n IInterpreterPluginState,\n L\n> => {\n const dictionaries = getDictionaries();\n const dictionary = dictionaries[key as T] as DictionaryRegistryElement<T>;\n\n if (!dictionary) {\n // Log a warning instead of throwing (so developers know it's missing)\n const logger = getAppLogger({ log });\n logger(\n `Dictionary ${colorizeKey(key as string)} was not found. Using fallback proxy.`,\n {\n level: 'warn',\n isVerbose: true,\n }\n );\n\n if (process.env.NODE_ENV === 'development') {\n // Return the Safe Proxy\n // We initialize it with the dictionary key name so the UI shows \"my-dictionary.someKey\"\n return createSafeFallback(key as string);\n }\n\n return createSafeFallback(key as string);\n }\n\n const cacheKey = `${key}_${locale ?? 'default'}_${plugins ? 'custom_plugins' : 'default_plugins'}`;\n\n if (dictionaryCache.has(cacheKey)) {\n return dictionaryCache.get(cacheKey);\n }\n\n const result = getDictionary<DictionaryRegistryElement<T>, L>(\n dictionary,\n locale,\n plugins\n );\n\n dictionaryCache.set(cacheKey, result);\n\n return result;\n};\n"],"mappings":";;;;;;;;;;;;AAqBA,MAAM,sBAAsB,OAAO,OAAY;AAC7C,QAAO,IAAI,YAEH,MACN;EACE,MAAM,SAAS,SAAS;AAEtB,OACE,SAAS,YACT,SAAS,OAAO,eAChB,SAAS,WAET,cAAa;AAEf,OAAI,SAAS,OACX;AAKF,UAAO,mBADU,OAAO,GAAG,KAAK,GAAG,OAAO,KAAK,KAAK,OAAO,KAAK,CAC7B;;EAGrC,aAAa;AACX,UAAO;;EAEV,CACF;;AAGH,MAAM,kCAAkB,IAAI,KAAkB;AAE9C,MAAa,eAIX,KACA,QACA,YAKG;CAEH,MAAM,
|
|
1
|
+
{"version":3,"file":"getIntlayer.cjs","names":["getDictionary"],"sources":["../../../src/interpreter/getIntlayer.ts"],"sourcesContent":["import { log } from '@intlayer/config/built';\nimport { colorizeKey, getAppLogger } from '@intlayer/config/logger';\nimport { getDictionaries } from '@intlayer/dictionaries-entry';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n DictionaryRegistryContent,\n DictionaryRegistryElement,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type {\n DeepTransformContent,\n IInterpreterPluginState,\n Plugins,\n} from './getContent';\nimport { getDictionary } from './getDictionary';\n\n/**\n * Creates a Recursive Proxy that returns the path of the accessed key\n * stringified. This prevents the app from crashing on undefined access.\n */\nconst createSafeFallback = (path = ''): any => {\n return new Proxy(\n // Target is a function so it can be called if the dictionary expects a function\n () => path,\n {\n get: (_target, prop) => {\n // Handle common object methods to prevent infinite recursion or weird behavior\n if (\n prop === 'toJSON' ||\n prop === Symbol.toPrimitive ||\n prop === 'toString'\n ) {\n return () => path;\n }\n if (prop === 'then') {\n return undefined; // Prevent it from being treated as a Promise\n }\n\n // Recursively build the path (e.g., \"myDictionary.home.title\")\n const nextPath = path ? `${path}.${String(prop)}` : String(prop);\n return createSafeFallback(nextPath);\n },\n // If the code tries to execute the missing key as a function: t.title()\n apply: () => {\n return path;\n },\n }\n );\n};\n\nconst dictionaryCache = new Map<string, any>();\n\nexport const getIntlayer = <\n T extends DictionaryKeys,\n L extends LocalesValues = DeclaredLocales,\n>(\n key: T,\n locale?: L,\n plugins?: Plugins[]\n): DeepTransformContent<\n DictionaryRegistryContent<T>,\n IInterpreterPluginState,\n L\n> => {\n const dictionaries = getDictionaries();\n const dictionary = dictionaries[key as T] as DictionaryRegistryElement<T>;\n\n if (!dictionary) {\n // Log a warning instead of throwing (so developers know it's missing)\n const logger = getAppLogger({ log });\n logger(\n `Dictionary ${colorizeKey(key as string)} was not found. Using fallback proxy.`,\n {\n level: 'warn',\n isVerbose: true,\n }\n );\n\n if (process.env.NODE_ENV === 'development') {\n // Return the Safe Proxy\n // We initialize it with the dictionary key name so the UI shows \"my-dictionary.someKey\"\n return createSafeFallback(key as string);\n }\n\n return createSafeFallback(key as string);\n }\n\n const cacheKey = `${key}_${locale ?? 'default'}_${plugins ? 'custom_plugins' : 'default_plugins'}`;\n\n if (dictionaryCache.has(cacheKey)) {\n return dictionaryCache.get(cacheKey);\n }\n\n const result = getDictionary<DictionaryRegistryElement<T>, L>(\n dictionary,\n locale,\n plugins\n );\n\n dictionaryCache.set(cacheKey, result);\n\n return result;\n};\n"],"mappings":";;;;;;;;;;;;AAqBA,MAAM,sBAAsB,OAAO,OAAY;AAC7C,QAAO,IAAI,YAEH,MACN;EACE,MAAM,SAAS,SAAS;AAEtB,OACE,SAAS,YACT,SAAS,OAAO,eAChB,SAAS,WAET,cAAa;AAEf,OAAI,SAAS,OACX;AAKF,UAAO,mBADU,OAAO,GAAG,KAAK,GAAG,OAAO,KAAK,KAAK,OAAO,KAAK,CAC7B;;EAGrC,aAAa;AACX,UAAO;;EAEV,CACF;;AAGH,MAAM,kCAAkB,IAAI,KAAkB;AAE9C,MAAa,eAIX,KACA,QACA,YAKG;CAEH,MAAM,gEAAyB,CAAC;AAEhC,KAAI,CAAC,YAAY;AAGf,4CAD4B,EAAE,iCAAK,CAC7B,CACJ,uDAA0B,IAAc,CAAC,wCACzC;GACE,OAAO;GACP,WAAW;GACZ,CACF;AAED,MAAI,QAAQ,IAAI,aAAa,cAG3B,QAAO,mBAAmB,IAAc;AAG1C,SAAO,mBAAmB,IAAc;;CAG1C,MAAM,WAAW,GAAG,IAAI,GAAG,UAAU,UAAU,GAAG,UAAU,mBAAmB;AAE/E,KAAI,gBAAgB,IAAI,SAAS,CAC/B,QAAO,gBAAgB,IAAI,SAAS;CAGtC,MAAM,SAASA,gDACb,YACA,QACA,QACD;AAED,iBAAgB,IAAI,UAAU,OAAO;AAErC,QAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateSitemap.cjs","names":["resolveRoutingConfig","getMultilingualUrls"],"sources":["../../../src/localization/generateSitemap.ts"],"sourcesContent":["import type { RoutingConfig } from '@intlayer/types/config';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getMultilingualUrls } from './getMultilingualUrls';\nimport { type RoutingOptions, resolveRoutingConfig } from './getPrefix';\n\nexport type SitemapUrlEntry = {\n /** The canonical path, e.g. '/dashboard' */\n path: string;\n changefreq?: string;\n priority?: number;\n /** ISO date string, e.g. '2024-01-15' */\n lastmod?: string;\n};\n\nexport type GenerateSitemapOptions = {\n /** Base site URL without trailing slash, e.g. 'https://example.com' */\n siteUrl: string;\n /**\n * Whether to include xhtml:link alternate tags for multilingual support.\n *\n * When enabled, alternate links are only generated for modes where URLs\n * differ per locale:\n * - 'prefix-no-default': included\n * - 'prefix-all': included\n * - 'search-params': included\n * - 'no-prefix': excluded (all locales share the same URL)\n *\n * @default true\n */\n xhtmlLinks?: boolean;\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n rewrite?: RoutingConfig['rewrite'];\n};\n\n/**\n * Returns whether xhtml:link alternate tags should be generated for the given routing mode.\n *\n * Alternates are meaningful only when locale URLs are distinct:\n * - 'no-prefix' produces identical URLs for all locales → no alternates\n * - all other modes produce distinct URLs → alternates are generated\n */\nconst shouldIncludeAlternates = (\n mode: RoutingConfig['mode'],\n xhtmlLinks: boolean\n): boolean => xhtmlLinks && mode !== 'no-prefix';\n\n/**\n * Generates a single `<url>` sitemap entry for the given path.\n *\n * Example:\n *\n * ```ts\n * generateSitemapUrl('/dashboard', {\n * siteUrl: 'https://example.com',\n * changefreq: 'weekly',\n * priority: 0.8,\n * xhtmlLinks: true,\n * locales: ['en', 'fr'],\n * defaultLocale: 'en',\n * mode: 'prefix-no-default',\n * });\n * // Returns:\n * // <url>\n * // <loc>https://example.com/dashboard</loc>\n * // <changefreq>weekly</changefreq>\n * // <priority>0.8</priority>\n * // <xhtml:link rel=\"alternate\" hrefLang=\"en\" href=\"https://example.com/dashboard\"/>\n * // <xhtml:link rel=\"alternate\" hrefLang=\"fr\" href=\"https://example.com/fr/dashboard\"/>\n * // <xhtml:link rel=\"alternate\" hrefLang=\"x-default\" href=\"https://example.com/dashboard\"/>\n * // </url>\n * ```\n *\n * @param path - The canonical path to generate the entry for.\n * @param options - Configuration options.\n * @returns A `<url>` XML string.\n */\nexport const generateSitemapUrl = (\n path: string,\n options: SitemapUrlEntry & GenerateSitemapOptions\n): string => {\n const {\n siteUrl,\n changefreq,\n priority,\n lastmod,\n xhtmlLinks = true,\n ...routingOptions\n } = options;\n\n const resolved = resolveRoutingConfig(routingOptions as RoutingOptions);\n const fullUrl = `${siteUrl}${path}`;\n\n const lines: (string | null)[] = [\n ' <url>',\n ` <loc>${fullUrl}</loc>`,\n lastmod ? ` <lastmod>${lastmod}</lastmod>` : null,\n changefreq ? ` <changefreq>${changefreq}</changefreq>` : null,\n priority !== undefined ? ` <priority>${priority}</priority>` : null,\n ];\n\n if (shouldIncludeAlternates(resolved.mode, xhtmlLinks)) {\n const alternates = getMultilingualUrls(\n path,\n routingOptions as RoutingOptions\n );\n\n for (const [lang, localePath] of Object.entries(alternates)) {\n lines.push(\n ` <xhtml:link rel=\"alternate\" hrefLang=\"${lang}\" href=\"${siteUrl}${localePath}\"/>`\n );\n }\n\n lines.push(\n ` <xhtml:link rel=\"alternate\" hrefLang=\"x-default\" href=\"${fullUrl}\"/>`\n );\n }\n\n lines.push(' </url>');\n\n return lines.filter(Boolean).join('\\n');\n};\n\n/**\n * Generates a full XML sitemap string from an array of URL entries.\n *\n * Automatically adds `xmlns:xhtml` to the `<urlset>` declaration when\n * xhtml:link alternate tags are included.\n *\n * Example:\n *\n * ```ts\n * generateSitemap(\n * [\n * { path: '/', changefreq: 'daily', priority: 1.0 },\n * { path: '/about', changefreq: 'monthly', priority: 0.5 },\n * ],\n * {\n * siteUrl: 'https://example.com',\n * xhtmlLinks: true,\n * locales: ['en', 'fr'],\n * defaultLocale: 'en',\n * mode: 'prefix-no-default',\n * }\n * );\n * ```\n *\n * @param entries - Array of URL entries to include in the sitemap.\n * @param options - Sitemap generation options.\n * @returns A full XML sitemap string.\n */\nexport const generateSitemap = (\n entries: SitemapUrlEntry[],\n options: GenerateSitemapOptions\n): string => {\n const { siteUrl, xhtmlLinks = true, ...routingOptions } = options;\n\n const resolved = resolveRoutingConfig(routingOptions as RoutingOptions);\n const includeAlternates = shouldIncludeAlternates(resolved.mode, xhtmlLinks);\n\n const xmlEntries = entries.map((entry) =>\n generateSitemapUrl(entry.path, {\n ...entry,\n siteUrl,\n xhtmlLinks,\n ...routingOptions,\n })\n );\n\n const xmlns = includeAlternates\n ? '\\n xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"'\n : '';\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset\n xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"${xmlns}\n>\n${xmlEntries.join('\\n')}\n</urlset>`;\n};\n"],"mappings":";;;;;;;;;;;;AA2CA,MAAM,2BACJ,MACA,eACY,cAAc,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCrC,MAAa,sBACX,MACA,YACW;CACX,MAAM,EACJ,SACA,YACA,UACA,SACA,aAAa,MACb,GAAG,mBACD;CAEJ,MAAM,WAAWA,oDAAqB,eAAiC;CACvE,MAAM,UAAU,GAAG,UAAU;CAE7B,MAAM,QAA2B;EAC/B;EACA,YAAY,QAAQ;EACpB,UAAU,gBAAgB,QAAQ,cAAc;EAChD,aAAa,mBAAmB,WAAW,iBAAiB;EAC5D,aAAa,SAAY,iBAAiB,SAAS,eAAe;EACnE;AAED,KAAI,wBAAwB,SAAS,MAAM,WAAW,EAAE;EACtD,MAAM,aAAaC,6DACjB,MACA,eACD;AAED,OAAK,MAAM,CAAC,MAAM,eAAe,OAAO,QAAQ,WAAW,CACzD,OAAM,KACJ,6CAA6C,KAAK,UAAU,UAAU,WAAW,KAClF;AAGH,QAAM,KACJ,8DAA8D,QAAQ,KACvE;;AAGH,OAAM,KAAK,WAAW;AAEtB,QAAO,MAAM,OAAO,QAAQ,CAAC,KAAK,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BzC,MAAa,mBACX,SACA,YACW;CACX,MAAM,EAAE,SAAS,aAAa,MAAM,GAAG,mBAAmB;CAG1D,MAAM,oBAAoB,wBADTD,oDAAqB,
|
|
1
|
+
{"version":3,"file":"generateSitemap.cjs","names":["resolveRoutingConfig","getMultilingualUrls"],"sources":["../../../src/localization/generateSitemap.ts"],"sourcesContent":["import type { RoutingConfig } from '@intlayer/types/config';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { getMultilingualUrls } from './getMultilingualUrls';\nimport { type RoutingOptions, resolveRoutingConfig } from './getPrefix';\n\nexport type SitemapUrlEntry = {\n /** The canonical path, e.g. '/dashboard' */\n path: string;\n changefreq?: string;\n priority?: number;\n /** ISO date string, e.g. '2024-01-15' */\n lastmod?: string;\n};\n\nexport type GenerateSitemapOptions = {\n /** Base site URL without trailing slash, e.g. 'https://example.com' */\n siteUrl: string;\n /**\n * Whether to include xhtml:link alternate tags for multilingual support.\n *\n * When enabled, alternate links are only generated for modes where URLs\n * differ per locale:\n * - 'prefix-no-default': included\n * - 'prefix-all': included\n * - 'search-params': included\n * - 'no-prefix': excluded (all locales share the same URL)\n *\n * @default true\n */\n xhtmlLinks?: boolean;\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n rewrite?: RoutingConfig['rewrite'];\n};\n\n/**\n * Returns whether xhtml:link alternate tags should be generated for the given routing mode.\n *\n * Alternates are meaningful only when locale URLs are distinct:\n * - 'no-prefix' produces identical URLs for all locales → no alternates\n * - all other modes produce distinct URLs → alternates are generated\n */\nconst shouldIncludeAlternates = (\n mode: RoutingConfig['mode'],\n xhtmlLinks: boolean\n): boolean => xhtmlLinks && mode !== 'no-prefix';\n\n/**\n * Generates a single `<url>` sitemap entry for the given path.\n *\n * Example:\n *\n * ```ts\n * generateSitemapUrl('/dashboard', {\n * siteUrl: 'https://example.com',\n * changefreq: 'weekly',\n * priority: 0.8,\n * xhtmlLinks: true,\n * locales: ['en', 'fr'],\n * defaultLocale: 'en',\n * mode: 'prefix-no-default',\n * });\n * // Returns:\n * // <url>\n * // <loc>https://example.com/dashboard</loc>\n * // <changefreq>weekly</changefreq>\n * // <priority>0.8</priority>\n * // <xhtml:link rel=\"alternate\" hrefLang=\"en\" href=\"https://example.com/dashboard\"/>\n * // <xhtml:link rel=\"alternate\" hrefLang=\"fr\" href=\"https://example.com/fr/dashboard\"/>\n * // <xhtml:link rel=\"alternate\" hrefLang=\"x-default\" href=\"https://example.com/dashboard\"/>\n * // </url>\n * ```\n *\n * @param path - The canonical path to generate the entry for.\n * @param options - Configuration options.\n * @returns A `<url>` XML string.\n */\nexport const generateSitemapUrl = (\n path: string,\n options: SitemapUrlEntry & GenerateSitemapOptions\n): string => {\n const {\n siteUrl,\n changefreq,\n priority,\n lastmod,\n xhtmlLinks = true,\n ...routingOptions\n } = options;\n\n const resolved = resolveRoutingConfig(routingOptions as RoutingOptions);\n const fullUrl = `${siteUrl}${path}`;\n\n const lines: (string | null)[] = [\n ' <url>',\n ` <loc>${fullUrl}</loc>`,\n lastmod ? ` <lastmod>${lastmod}</lastmod>` : null,\n changefreq ? ` <changefreq>${changefreq}</changefreq>` : null,\n priority !== undefined ? ` <priority>${priority}</priority>` : null,\n ];\n\n if (shouldIncludeAlternates(resolved.mode, xhtmlLinks)) {\n const alternates = getMultilingualUrls(\n path,\n routingOptions as RoutingOptions\n );\n\n for (const [lang, localePath] of Object.entries(alternates)) {\n lines.push(\n ` <xhtml:link rel=\"alternate\" hrefLang=\"${lang}\" href=\"${siteUrl}${localePath}\"/>`\n );\n }\n\n lines.push(\n ` <xhtml:link rel=\"alternate\" hrefLang=\"x-default\" href=\"${fullUrl}\"/>`\n );\n }\n\n lines.push(' </url>');\n\n return lines.filter(Boolean).join('\\n');\n};\n\n/**\n * Generates a full XML sitemap string from an array of URL entries.\n *\n * Automatically adds `xmlns:xhtml` to the `<urlset>` declaration when\n * xhtml:link alternate tags are included.\n *\n * Example:\n *\n * ```ts\n * generateSitemap(\n * [\n * { path: '/', changefreq: 'daily', priority: 1.0 },\n * { path: '/about', changefreq: 'monthly', priority: 0.5 },\n * ],\n * {\n * siteUrl: 'https://example.com',\n * xhtmlLinks: true,\n * locales: ['en', 'fr'],\n * defaultLocale: 'en',\n * mode: 'prefix-no-default',\n * }\n * );\n * ```\n *\n * @param entries - Array of URL entries to include in the sitemap.\n * @param options - Sitemap generation options.\n * @returns A full XML sitemap string.\n */\nexport const generateSitemap = (\n entries: SitemapUrlEntry[],\n options: GenerateSitemapOptions\n): string => {\n const { siteUrl, xhtmlLinks = true, ...routingOptions } = options;\n\n const resolved = resolveRoutingConfig(routingOptions as RoutingOptions);\n const includeAlternates = shouldIncludeAlternates(resolved.mode, xhtmlLinks);\n\n const xmlEntries = entries.map((entry) =>\n generateSitemapUrl(entry.path, {\n ...entry,\n siteUrl,\n xhtmlLinks,\n ...routingOptions,\n })\n );\n\n const xmlns = includeAlternates\n ? '\\n xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"'\n : '';\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset\n xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"${xmlns}\n>\n${xmlEntries.join('\\n')}\n</urlset>`;\n};\n"],"mappings":";;;;;;;;;;;;AA2CA,MAAM,2BACJ,MACA,eACY,cAAc,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCrC,MAAa,sBACX,MACA,YACW;CACX,MAAM,EACJ,SACA,YACA,UACA,SACA,aAAa,MACb,GAAG,mBACD;CAEJ,MAAM,WAAWA,oDAAqB,eAAiC;CACvE,MAAM,UAAU,GAAG,UAAU;CAE7B,MAAM,QAA2B;EAC/B;EACA,YAAY,QAAQ;EACpB,UAAU,gBAAgB,QAAQ,cAAc;EAChD,aAAa,mBAAmB,WAAW,iBAAiB;EAC5D,aAAa,SAAY,iBAAiB,SAAS,eAAe;EACnE;AAED,KAAI,wBAAwB,SAAS,MAAM,WAAW,EAAE;EACtD,MAAM,aAAaC,6DACjB,MACA,eACD;AAED,OAAK,MAAM,CAAC,MAAM,eAAe,OAAO,QAAQ,WAAW,CACzD,OAAM,KACJ,6CAA6C,KAAK,UAAU,UAAU,WAAW,KAClF;AAGH,QAAM,KACJ,8DAA8D,QAAQ,KACvE;;AAGH,OAAM,KAAK,WAAW;AAEtB,QAAO,MAAM,OAAO,QAAQ,CAAC,KAAK,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BzC,MAAa,mBACX,SACA,YACW;CACX,MAAM,EAAE,SAAS,aAAa,MAAM,GAAG,mBAAmB;CAG1D,MAAM,oBAAoB,wBADTD,oDAAqB,eACoB,CAAC,MAAM,WAAW;CAE5E,MAAM,aAAa,QAAQ,KAAK,UAC9B,mBAAmB,MAAM,MAAM;EAC7B,GAAG;EACH;EACA;EACA,GAAG;EACJ,CAAC,CACH;AAMD,QAAO;;uDAJO,oBACV,qDACA,GAIuD;;EAE3D,WAAW,KAAK,KAAK,CAAC"}
|