@intlayer/core 9.2.0 → 9.3.0
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/getEditedContent.cjs +10 -6
- package/dist/cjs/deepTransformPlugins/getEditedContent.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/getNestedDictionaryReferences.cjs +153 -0
- package/dist/cjs/dictionaryManipulator/getNestedDictionaryReferences.cjs.map +1 -0
- package/dist/cjs/dictionaryManipulator/index.cjs +16 -9
- package/dist/cjs/dictionaryManipulator/mergeQualifiedDictionaries.cjs +4 -3
- package/dist/cjs/dictionaryManipulator/mergeQualifiedDictionaries.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/qualifiedDictionary.cjs +1 -170
- package/dist/cjs/dictionaryManipulator/qualifiedDictionary.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/qualifiedDictionaryDeclaration.cjs +69 -0
- package/dist/cjs/dictionaryManipulator/qualifiedDictionaryDeclaration.cjs.map +1 -0
- package/dist/cjs/dictionaryManipulator/qualifiedDynamicLoader.cjs +115 -0
- package/dist/cjs/dictionaryManipulator/qualifiedDynamicLoader.cjs.map +1 -0
- package/dist/cjs/index.cjs +16 -9
- package/dist/cjs/interpreter/getContent/plugins.cjs +12 -1
- package/dist/cjs/interpreter/getContent/plugins.cjs.map +1 -1
- package/dist/cjs/interpreter/getDictionary.cjs +2 -1
- package/dist/cjs/interpreter/getDictionary.cjs.map +1 -1
- package/dist/cjs/interpreter/getNesting.optimized.cjs +59 -0
- package/dist/cjs/interpreter/getNesting.optimized.cjs.map +1 -0
- package/dist/esm/deepTransformPlugins/getEditedContent.mjs +10 -6
- package/dist/esm/deepTransformPlugins/getEditedContent.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/getNestedDictionaryReferences.mjs +150 -0
- package/dist/esm/dictionaryManipulator/getNestedDictionaryReferences.mjs.map +1 -0
- package/dist/esm/dictionaryManipulator/index.mjs +5 -2
- package/dist/esm/dictionaryManipulator/mergeQualifiedDictionaries.mjs +2 -1
- package/dist/esm/dictionaryManipulator/mergeQualifiedDictionaries.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/qualifiedDictionary.mjs +1 -162
- package/dist/esm/dictionaryManipulator/qualifiedDictionary.mjs.map +1 -1
- package/dist/esm/dictionaryManipulator/qualifiedDictionaryDeclaration.mjs +64 -0
- package/dist/esm/dictionaryManipulator/qualifiedDictionaryDeclaration.mjs.map +1 -0
- package/dist/esm/dictionaryManipulator/qualifiedDynamicLoader.mjs +111 -0
- package/dist/esm/dictionaryManipulator/qualifiedDynamicLoader.mjs.map +1 -0
- package/dist/esm/index.mjs +5 -2
- package/dist/esm/interpreter/getContent/plugins.mjs +12 -1
- package/dist/esm/interpreter/getContent/plugins.mjs.map +1 -1
- package/dist/esm/interpreter/getDictionary.mjs +2 -1
- package/dist/esm/interpreter/getDictionary.mjs.map +1 -1
- package/dist/esm/interpreter/getNesting.optimized.mjs +58 -0
- package/dist/esm/interpreter/getNesting.optimized.mjs.map +1 -0
- package/dist/types/deepTransformPlugins/getEditedContent.d.ts.map +1 -1
- package/dist/types/deepTransformPlugins/getFilterMissingTranslationsContent.d.ts +1 -0
- package/dist/types/deepTransformPlugins/getFilterTranslationsOnlyContent.d.ts +1 -0
- package/dist/types/deepTransformPlugins/getFilteredLocalesContent.d.ts +1 -0
- package/dist/types/dictionaryManipulator/getNestedDictionaryReferences.d.ts +62 -0
- package/dist/types/dictionaryManipulator/getNestedDictionaryReferences.d.ts.map +1 -0
- package/dist/types/dictionaryManipulator/index.d.ts +5 -2
- package/dist/types/dictionaryManipulator/mergeQualifiedDictionaries.d.ts.map +1 -1
- package/dist/types/dictionaryManipulator/qualifiedDictionary.d.ts +18 -126
- package/dist/types/dictionaryManipulator/qualifiedDictionary.d.ts.map +1 -1
- package/dist/types/dictionaryManipulator/qualifiedDictionaryDeclaration.d.ts +41 -0
- package/dist/types/dictionaryManipulator/qualifiedDictionaryDeclaration.d.ts.map +1 -0
- package/dist/types/dictionaryManipulator/qualifiedDynamicLoader.d.ts +93 -0
- package/dist/types/dictionaryManipulator/qualifiedDynamicLoader.d.ts.map +1 -0
- package/dist/types/index.d.ts +5 -2
- package/dist/types/interpreter/getContent/plugins.d.ts +10 -0
- package/dist/types/interpreter/getContent/plugins.d.ts.map +1 -1
- package/dist/types/interpreter/getNesting.optimized.d.ts +33 -0
- package/dist/types/interpreter/getNesting.optimized.d.ts.map +1 -0
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.mjs","names":[],"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 PluralContent,\n PluralContentState,\n SelectContent,\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 { getPlural } from '../getPlural';\nimport { getSelect } from '../getSelect';\nimport { getTranslation } from '../getTranslation';\nimport {\n isInterpolableWrapperNode,\n transformInterpolableNode,\n} from '../interpolableNode';\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 * 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 process.env.INTLAYER_NODE_TYPE_TRANSLATION === 'false'\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 =\n process.env.INTLAYER_NODE_TYPE_ENUMERATION === 'false'\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 * PLURAL PLUGIN\n * --------------------------------------------- */\n\nexport type PluralCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.PLURAL]: object;\n}\n ? (\n arg: number | { count: number; [key: string]: unknown }\n ) => DeepTransformContent<\n T[typeof NodeTypes.PLURAL][keyof T[typeof NodeTypes.PLURAL]],\n S\n >\n : never;\n\ntype SubResultFunction = (values: Record<string, string | number>) => string;\n\n/**\n * Plural plugin. Replaces node with a function that takes a count (or\n * `{ count, ...values }`) => string, picking the matching CLDR plural form\n * for the active locale and interpolating `{{count}}` (and other values).\n */\nexport const pluralPlugin = (locale?: LocalesValues): Plugins =>\n process.env.INTLAYER_NODE_TYPE_PLURAL === 'false'\n ? fallbackPlugin\n : {\n id: 'plural-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.PLURAL,\n transform: (node: PluralContent, props, deepTransformNode) => {\n const original = node[NodeTypes.PLURAL];\n const result: Record<string, any> = {};\n\n /** String plugin for plural. Replaces string node with a component that renders the insertion. */\n const pluralStringPlugin: Plugins = {\n id: 'plural-string-plugin',\n canHandle: (node) =>\n typeof node === 'string' || isInterpolableWrapperNode(node),\n transform: (node, subProps, deepTransformNode) => {\n // `html()`/`markdown()` nodes carry their `{{count}}` placeholders\n // inside a raw string. Interpolate into that string, then re-run\n // the transform so the html/markdown renderer applies afterwards.\n if (isInterpolableWrapperNode(node)) {\n return (values: { [k: string]: string | number }) =>\n transformInterpolableNode(\n node,\n values,\n subProps,\n props.plugins,\n deepTransformNode\n );\n }\n\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 (values: { [k: string]: string | number }) => {\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 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.PLURAL, key } as KeyPath,\n ],\n plugins: [pluralStringPlugin, ...(props.plugins ?? [])],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n const effectiveLocale = String(locale ?? props.locale ?? 'en');\n\n return (arg: number | { count: number; [key: string]: unknown }) => {\n const count = typeof arg === 'number' ? arg : arg.count;\n const values =\n typeof arg === 'number'\n ? { count: arg }\n : (arg as { count: number; [key: string]: unknown });\n\n const subResult: string | SubResultFunction = getPlural(\n result as PluralContent['plural'] as PluralContentState<string>,\n count,\n effectiveLocale\n );\n\n if (typeof subResult === 'function') {\n return (subResult as SubResultFunction)(values);\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 =\n process.env.INTLAYER_NODE_TYPE_CONDITION === 'false'\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 =\n process.env.INTLAYER_NODE_TYPE_INSERTION === 'false'\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) =>\n typeof node === 'string' || isInterpolableWrapperNode(node),\n transform: (node, subProps, deepTransformNode) => {\n // `html()`/`markdown()` nodes carry their `{{ … }}` placeholders\n // inside a raw string. Interpolate into that string, then re-run\n // the transform so the html/markdown renderer applies afterwards.\n if (isInterpolableWrapperNode(node)) {\n return (\n values: {\n [K in InsertionContent['fields'][number]]: string | number;\n }\n ) =>\n transformInterpolableNode(\n node,\n values,\n subProps,\n props.plugins,\n deepTransformNode\n );\n }\n\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 =\n process.env.INTLAYER_NODE_TYPE_GENDER === 'false'\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 * SELECT PLUGIN\n * --------------------------------------------- */\n\n/**\n * Accepted selector for a select node.\n *\n * When the node declares a `fallback` case, any string is accepted (the\n * fallback covers the unmatched values) while the declared cases still\n * autocomplete. Without a `fallback`, only the declared cases are accepted.\n */\nexport type SelectSelector<States> = 'fallback' extends keyof States\n ? Exclude<keyof States & string, 'fallback'> | (string & {})\n : keyof States & string;\n\nexport type SelectCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.SELECT]: object;\n}\n ? (\n value:\n | SelectSelector<T[typeof NodeTypes.SELECT]>\n | { value: SelectSelector<T[typeof NodeTypes.SELECT]> }\n ) => DeepTransformContent<\n T[typeof NodeTypes.SELECT][keyof T[typeof NodeTypes.SELECT]],\n S\n >\n : never;\n\n/** Select plugin. Replaces node with a function that takes a string => content. */\nexport const selectPlugin: Plugins =\n process.env.INTLAYER_NODE_TYPE_SELECT === 'false'\n ? fallbackPlugin\n : {\n id: 'select-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.SELECT,\n transform: (node: SelectContent, props, deepTransformNode) => {\n const original = node[NodeTypes.SELECT];\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.SELECT, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: string | { value: string }) => {\n const value = typeof arg === 'string' ? arg : arg?.value;\n const subResult = getSelect(result, value);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * 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 process.env.INTLAYER_NODE_TYPE_NESTED === 'false'\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, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.FILE]: string;\n content?: string;\n}\n ? DeepTransformContent<string, S>\n : never;\n\n/** File plugin. Replaces node with the result of `getNesting`. */\nexport const filePlugin: Plugins =\n process.env.INTLAYER_NODE_TYPE_FILE === 'false'\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 * Forces eager traversal of plain objects in `deepTransformNode`. By default\n * traversal is lazy (property getters), so callers that discard the returned\n * value never trigger plugins on nested nodes. Set this when running plugins\n * for their side effects only (e.g. missing-locale detection).\n */\n eager?: boolean;\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 plural: PluralCond<T, S, L>;\n condition: ConditionCond<T, S, L>;\n insertion: InsertionCond<T, S, L>;\n gender: GenderCond<T, S, L>;\n select: SelectCond<T, S, L>;\n nested: NestedCond<T, S, L>;\n file: FileCond<T, S, L>;\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 plural: true;\n condition: true;\n insertion: true;\n gender: true;\n select: 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.mjs","names":["getNestingOptimized"],"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 PluralContent,\n PluralContentState,\n SelectContent,\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 { getNesting as getNestingOptimized } from '../getNesting.optimized';\nimport { getPlural } from '../getPlural';\nimport { getSelect } from '../getSelect';\nimport { getTranslation } from '../getTranslation';\nimport {\n isInterpolableWrapperNode,\n transformInterpolableNode,\n} from '../interpolableNode';\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 * 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 process.env.INTLAYER_NODE_TYPE_TRANSLATION === 'false'\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 =\n process.env.INTLAYER_NODE_TYPE_ENUMERATION === 'false'\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 * PLURAL PLUGIN\n * --------------------------------------------- */\n\nexport type PluralCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.PLURAL]: object;\n}\n ? (\n arg: number | { count: number; [key: string]: unknown }\n ) => DeepTransformContent<\n T[typeof NodeTypes.PLURAL][keyof T[typeof NodeTypes.PLURAL]],\n S\n >\n : never;\n\ntype SubResultFunction = (values: Record<string, string | number>) => string;\n\n/**\n * Plural plugin. Replaces node with a function that takes a count (or\n * `{ count, ...values }`) => string, picking the matching CLDR plural form\n * for the active locale and interpolating `{{count}}` (and other values).\n */\nexport const pluralPlugin = (locale?: LocalesValues): Plugins =>\n process.env.INTLAYER_NODE_TYPE_PLURAL === 'false'\n ? fallbackPlugin\n : {\n id: 'plural-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.PLURAL,\n transform: (node: PluralContent, props, deepTransformNode) => {\n const original = node[NodeTypes.PLURAL];\n const result: Record<string, any> = {};\n\n /** String plugin for plural. Replaces string node with a component that renders the insertion. */\n const pluralStringPlugin: Plugins = {\n id: 'plural-string-plugin',\n canHandle: (node) =>\n typeof node === 'string' || isInterpolableWrapperNode(node),\n transform: (node, subProps, deepTransformNode) => {\n // `html()`/`markdown()` nodes carry their `{{count}}` placeholders\n // inside a raw string. Interpolate into that string, then re-run\n // the transform so the html/markdown renderer applies afterwards.\n if (isInterpolableWrapperNode(node)) {\n return (values: { [k: string]: string | number }) =>\n transformInterpolableNode(\n node,\n values,\n subProps,\n props.plugins,\n deepTransformNode\n );\n }\n\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 (values: { [k: string]: string | number }) => {\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 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.PLURAL, key } as KeyPath,\n ],\n plugins: [pluralStringPlugin, ...(props.plugins ?? [])],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n const effectiveLocale = String(locale ?? props.locale ?? 'en');\n\n return (arg: number | { count: number; [key: string]: unknown }) => {\n const count = typeof arg === 'number' ? arg : arg.count;\n const values =\n typeof arg === 'number'\n ? { count: arg }\n : (arg as { count: number; [key: string]: unknown });\n\n const subResult: string | SubResultFunction = getPlural(\n result as PluralContent['plural'] as PluralContentState<string>,\n count,\n effectiveLocale\n );\n\n if (typeof subResult === 'function') {\n return (subResult as SubResultFunction)(values);\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 =\n process.env.INTLAYER_NODE_TYPE_CONDITION === 'false'\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 =\n process.env.INTLAYER_NODE_TYPE_INSERTION === 'false'\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) =>\n typeof node === 'string' || isInterpolableWrapperNode(node),\n transform: (node, subProps, deepTransformNode) => {\n // `html()`/`markdown()` nodes carry their `{{ … }}` placeholders\n // inside a raw string. Interpolate into that string, then re-run\n // the transform so the html/markdown renderer applies afterwards.\n if (isInterpolableWrapperNode(node)) {\n return (\n values: {\n [K in InsertionContent['fields'][number]]: string | number;\n }\n ) =>\n transformInterpolableNode(\n node,\n values,\n subProps,\n props.plugins,\n deepTransformNode\n );\n }\n\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 =\n process.env.INTLAYER_NODE_TYPE_GENDER === 'false'\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 * SELECT PLUGIN\n * --------------------------------------------- */\n\n/**\n * Accepted selector for a select node.\n *\n * When the node declares a `fallback` case, any string is accepted (the\n * fallback covers the unmatched values) while the declared cases still\n * autocomplete. Without a `fallback`, only the declared cases are accepted.\n */\nexport type SelectSelector<States> = 'fallback' extends keyof States\n ? Exclude<keyof States & string, 'fallback'> | (string & {})\n : keyof States & string;\n\nexport type SelectCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.SELECT]: object;\n}\n ? (\n value:\n | SelectSelector<T[typeof NodeTypes.SELECT]>\n | { value: SelectSelector<T[typeof NodeTypes.SELECT]> }\n ) => DeepTransformContent<\n T[typeof NodeTypes.SELECT][keyof T[typeof NodeTypes.SELECT]],\n S\n >\n : never;\n\n/** Select plugin. Replaces node with a function that takes a string => content. */\nexport const selectPlugin: Plugins =\n process.env.INTLAYER_NODE_TYPE_SELECT === 'false'\n ? fallbackPlugin\n : {\n id: 'select-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.SELECT,\n transform: (node: SelectContent, props, deepTransformNode) => {\n const original = node[NodeTypes.SELECT];\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.SELECT, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: string | { value: string }) => {\n const value = typeof arg === 'string' ? arg : arg?.value;\n const subResult = getSelect(result, value);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * 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/**\n * Resolver used to turn a nested node into content.\n *\n * Optimized builds set `INTLAYER_OPTIMIZED_NESTING` so bundlers fold this to\n * the local resolver and dead-code-eliminate the registry-based one — together\n * with its `getIntlayer` import, and therefore the whole\n * `@intlayer/dictionaries-entry` module. That is what allows the dictionaries\n * entry to be emptied while `nest()` keeps working.\n */\nconst resolveNesting =\n process.env.INTLAYER_OPTIMIZED_NESTING === 'true'\n ? getNestingOptimized\n : getNesting;\n\n/** Nested plugin. Replaces node with the result of `getNesting`. */\nexport const nestedPlugin = (locale?: LocalesValues): Plugins =>\n process.env.INTLAYER_NODE_TYPE_NESTED === 'false'\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 resolveNesting(\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, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.FILE]: string;\n content?: string;\n}\n ? DeepTransformContent<string, S>\n : never;\n\n/** File plugin. Replaces node with the result of `getNesting`. */\nexport const filePlugin: Plugins =\n process.env.INTLAYER_NODE_TYPE_FILE === 'false'\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 * Dictionaries referenced through `nest()`, attached to the consuming\n * dictionary by the build optimization and threaded down by\n * `deepTransformNode`.\n *\n * Present only in optimized builds, where the global dictionary registry is\n * stripped and `getNesting` resolves from this map instead. See\n * `getNesting.optimized.ts`.\n */\n nestedDictionaries?: Record<string, unknown>;\n /**\n * Forces eager traversal of plain objects in `deepTransformNode`. By default\n * traversal is lazy (property getters), so callers that discard the returned\n * value never trigger plugins on nested nodes. Set this when running plugins\n * for their side effects only (e.g. missing-locale detection).\n */\n eager?: boolean;\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 plural: PluralCond<T, S, L>;\n condition: ConditionCond<T, S, L>;\n insertion: InsertionCond<T, S, L>;\n gender: GenderCond<T, S, L>;\n select: SelectCond<T, S, L>;\n nested: NestedCond<T, S, L>;\n file: FileCond<T, S, L>;\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 plural: true;\n condition: true;\n insertion: true;\n gender: true;\n select: 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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"}
|
|
@@ -25,7 +25,8 @@ const getDictionary = (dictionary, localeOrSelector, plugins) => {
|
|
|
25
25
|
dictionaryKey: resolvedDictionary.key,
|
|
26
26
|
dictionaryPath: resolvedDictionary.filePath,
|
|
27
27
|
keyPath: [],
|
|
28
|
-
plugins: appliedPlugins
|
|
28
|
+
plugins: appliedPlugins,
|
|
29
|
+
nestedDictionaries: resolvedDictionary.nestedDictionaries
|
|
29
30
|
};
|
|
30
31
|
return getContent(resolvedDictionary.content, props, appliedPlugins);
|
|
31
32
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getDictionary.mjs","names":[],"sources":["../../../src/interpreter/getDictionary.ts"],"sourcesContent":["import type {\n Dictionary,\n DictionarySelector,\n QualifiedDictionaryGroup,\n ResolveQualifiedDictionaryContent,\n} from '@intlayer/types/dictionary';\nimport type {\n DeclaredLocales,\n ExtractSelectorLocale,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport {\n parseDictionarySelector,\n resolveQualifiedDictionary,\n} from '../dictionaryManipulator/qualifiedDictionary';\nimport type {\n DeepTransformContent,\n IInterpreterPluginState,\n NodeProps,\n Plugins,\n} from './getContent';\nimport { getBasePlugins, getContent } from './getContent/getContent';\n\n/**\n * Transforms a dictionary in a single pass, applying each plugin as needed.\n *\n * Also accepts a `QualifiedDictionaryGroup` (collections, variants) together\n * with a selector as second argument — the group is resolved to a single entry\n * (or an ordered array of entries for collections without an `item` selector)\n * before transformation.\n *\n * @param dictionary The dictionary (or qualified dictionary group) to transform.\n * @param localeOrSelector The locale, or a selector object (`{ item }`,\n * `{ variant }`, optionally with `locale`).\n * @param plugins An array of NodeTransformer that define how to transform recognized nodes.\n * If omitted, we’ll use a default set of plugins.\n */\nexport const getDictionary = <\n const T extends Dictionary | QualifiedDictionaryGroup,\n const A extends LocalesValues | DictionarySelector = DeclaredLocales,\n>(\n dictionary: T,\n localeOrSelector?: A,\n plugins?: Plugins[]\n): DeepTransformContent<\n ResolveQualifiedDictionaryContent<T, A>,\n IInterpreterPluginState,\n ExtractSelectorLocale<A>\n> => {\n const { locale, selector } = parseDictionarySelector(localeOrSelector);\n const appliedPlugins = plugins ?? getBasePlugins(locale);\n\n const resolved = resolveQualifiedDictionary(dictionary, selector);\n\n const transformDictionary = (resolvedDictionary: Dictionary) => {\n const props: NodeProps = {\n dictionaryKey: resolvedDictionary.key,\n dictionaryPath: resolvedDictionary.filePath,\n keyPath: [],\n plugins: appliedPlugins,\n };\n\n return getContent(resolvedDictionary.content, props, appliedPlugins);\n };\n\n if (resolved === null) return null as any;\n\n if (Array.isArray(resolved)) {\n return resolved.map(transformDictionary) as any;\n }\n\n return transformDictionary(resolved) as any;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqCA,MAAa,iBAIX,YACA,kBACA,YAKG;CACH,MAAM,EAAE,QAAQ,aAAa,wBAAwB,gBAAgB;CACrE,MAAM,iBAAiB,WAAW,eAAe,MAAM;CAEvD,MAAM,WAAW,2BAA2B,YAAY,QAAQ;CAEhE,MAAM,uBAAuB,uBAAmC;EAC9D,MAAM,QAAmB;GACvB,eAAe,mBAAmB;GAClC,gBAAgB,mBAAmB;GACnC,SAAS,CAAC;GACV,SAAS;
|
|
1
|
+
{"version":3,"file":"getDictionary.mjs","names":[],"sources":["../../../src/interpreter/getDictionary.ts"],"sourcesContent":["import type {\n Dictionary,\n DictionarySelector,\n QualifiedDictionaryGroup,\n ResolveQualifiedDictionaryContent,\n} from '@intlayer/types/dictionary';\nimport type {\n DeclaredLocales,\n ExtractSelectorLocale,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport {\n parseDictionarySelector,\n resolveQualifiedDictionary,\n} from '../dictionaryManipulator/qualifiedDictionary';\nimport type {\n DeepTransformContent,\n IInterpreterPluginState,\n NodeProps,\n Plugins,\n} from './getContent';\nimport { getBasePlugins, getContent } from './getContent/getContent';\n\n/**\n * Transforms a dictionary in a single pass, applying each plugin as needed.\n *\n * Also accepts a `QualifiedDictionaryGroup` (collections, variants) together\n * with a selector as second argument — the group is resolved to a single entry\n * (or an ordered array of entries for collections without an `item` selector)\n * before transformation.\n *\n * @param dictionary The dictionary (or qualified dictionary group) to transform.\n * @param localeOrSelector The locale, or a selector object (`{ item }`,\n * `{ variant }`, optionally with `locale`).\n * @param plugins An array of NodeTransformer that define how to transform recognized nodes.\n * If omitted, we’ll use a default set of plugins.\n */\nexport const getDictionary = <\n const T extends Dictionary | QualifiedDictionaryGroup,\n const A extends LocalesValues | DictionarySelector = DeclaredLocales,\n>(\n dictionary: T,\n localeOrSelector?: A,\n plugins?: Plugins[]\n): DeepTransformContent<\n ResolveQualifiedDictionaryContent<T, A>,\n IInterpreterPluginState,\n ExtractSelectorLocale<A>\n> => {\n const { locale, selector } = parseDictionarySelector(localeOrSelector);\n const appliedPlugins = plugins ?? getBasePlugins(locale);\n\n const resolved = resolveQualifiedDictionary(dictionary, selector);\n\n const transformDictionary = (resolvedDictionary: Dictionary) => {\n const props: NodeProps = {\n dictionaryKey: resolvedDictionary.key,\n dictionaryPath: resolvedDictionary.filePath,\n keyPath: [],\n plugins: appliedPlugins,\n // Attached by the build optimization so `nest()` resolves without the\n // global registry. Undefined in unoptimized builds, where the\n // registry-based resolver is used instead.\n nestedDictionaries: resolvedDictionary.nestedDictionaries,\n };\n\n return getContent(resolvedDictionary.content, props, appliedPlugins);\n };\n\n if (resolved === null) return null as any;\n\n if (Array.isArray(resolved)) {\n return resolved.map(transformDictionary) as any;\n }\n\n return transformDictionary(resolved) as any;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqCA,MAAa,iBAIX,YACA,kBACA,YAKG;CACH,MAAM,EAAE,QAAQ,aAAa,wBAAwB,gBAAgB;CACrE,MAAM,iBAAiB,WAAW,eAAe,MAAM;CAEvD,MAAM,WAAW,2BAA2B,YAAY,QAAQ;CAEhE,MAAM,uBAAuB,uBAAmC;EAC9D,MAAM,QAAmB;GACvB,eAAe,mBAAmB;GAClC,gBAAgB,mBAAmB;GACnC,SAAS,CAAC;GACV,SAAS;GAIT,oBAAoB,mBAAmB;EACzC;EAEA,OAAO,WAAW,mBAAmB,SAAS,OAAO,cAAc;CACrE;CAEA,IAAI,aAAa,MAAM,OAAO;CAE9B,IAAI,MAAM,QAAQ,QAAQ,GACxB,OAAO,SAAS,IAAI,mBAAmB;CAGzC,OAAO,oBAAoB,QAAQ;AACrC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { getDictionary } from "./getDictionary.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/interpreter/getNesting.optimized.ts
|
|
4
|
+
/**
|
|
5
|
+
* Walks a dot-separated path on an already-interpreted dictionary content.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors the registry-based resolver: an unresolvable segment yields the whole
|
|
8
|
+
* content rather than `undefined`, so a stale path degrades to the parent
|
|
9
|
+
* object instead of crashing the render.
|
|
10
|
+
*/
|
|
11
|
+
const walkPath = (content, path) => {
|
|
12
|
+
let current = content;
|
|
13
|
+
for (const segment of path.split(".")) {
|
|
14
|
+
current = current?.[segment];
|
|
15
|
+
if (current === void 0) return content;
|
|
16
|
+
}
|
|
17
|
+
return current;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Optimized-build replacement for `getNesting`.
|
|
21
|
+
*
|
|
22
|
+
* Resolves a `nest()` reference from the dictionaries the compiler attached to
|
|
23
|
+
* the consuming dictionary (`props.nestedDictionaries`) instead of looking the
|
|
24
|
+
* key up in the global registry exposed by `@intlayer/dictionaries-entry`.
|
|
25
|
+
*
|
|
26
|
+
* That is what lets the build optimization erase the registry entirely: this
|
|
27
|
+
* module never imports `getIntlayer`, so no dictionary reaches the bundle
|
|
28
|
+
* except through the static import injected at the call site. The nest target
|
|
29
|
+
* then lands in the same chunk as the dictionary referencing it — and, in
|
|
30
|
+
* `dynamic` / `fetch` mode, is loaded by the same lazy per-locale loader.
|
|
31
|
+
*
|
|
32
|
+
* The compiler guarantees the attachment for every dictionary holding a nested
|
|
33
|
+
* node, so a missing entry means the dictionary was not produced by the
|
|
34
|
+
* optimized pipeline; the reference then resolves to `undefined`.
|
|
35
|
+
*
|
|
36
|
+
* @param dictionaryKey - The key of the dictionary to nest.
|
|
37
|
+
* @param path - Optional dot-separated path within the nested dictionary.
|
|
38
|
+
* @param props - Interpreter node props, carrying the attached dictionaries.
|
|
39
|
+
* @returns The nested content.
|
|
40
|
+
*/
|
|
41
|
+
const getNesting = (dictionaryKey, path, props) => {
|
|
42
|
+
const nestedDictionaries = props?.nestedDictionaries;
|
|
43
|
+
const nestedDictionary = nestedDictionaries?.[dictionaryKey];
|
|
44
|
+
if (!nestedDictionary) return void 0;
|
|
45
|
+
const content = getDictionary({
|
|
46
|
+
...nestedDictionary,
|
|
47
|
+
nestedDictionaries: {
|
|
48
|
+
...nestedDictionaries,
|
|
49
|
+
...nestedDictionary.nestedDictionaries
|
|
50
|
+
}
|
|
51
|
+
}, props?.locale, props?.plugins);
|
|
52
|
+
if (typeof path !== "string") return content;
|
|
53
|
+
return walkPath(content, path);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
export { getNesting };
|
|
58
|
+
//# sourceMappingURL=getNesting.optimized.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getNesting.optimized.mjs","names":[],"sources":["../../../src/interpreter/getNesting.optimized.ts"],"sourcesContent":["import type { Dictionary } from '@intlayer/types/dictionary';\nimport type {\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type { ValidDotPathsFor } from '../transpiler';\nimport type { NodeProps } from './getContent';\nimport { getDictionary } from './getDictionary';\nimport type { GetNestingResult } from './getNesting';\n\n/**\n * Walks a dot-separated path on an already-interpreted dictionary content.\n *\n * Mirrors the registry-based resolver: an unresolvable segment yields the whole\n * content rather than `undefined`, so a stale path degrades to the parent\n * object instead of crashing the render.\n */\nconst walkPath = (content: unknown, path: string): unknown => {\n let current: unknown = content;\n\n for (const segment of path.split('.')) {\n current = (current as Record<string, unknown> | undefined)?.[segment];\n\n if (current === undefined) return content;\n }\n\n return current;\n};\n\n/**\n * Optimized-build replacement for `getNesting`.\n *\n * Resolves a `nest()` reference from the dictionaries the compiler attached to\n * the consuming dictionary (`props.nestedDictionaries`) instead of looking the\n * key up in the global registry exposed by `@intlayer/dictionaries-entry`.\n *\n * That is what lets the build optimization erase the registry entirely: this\n * module never imports `getIntlayer`, so no dictionary reaches the bundle\n * except through the static import injected at the call site. The nest target\n * then lands in the same chunk as the dictionary referencing it — and, in\n * `dynamic` / `fetch` mode, is loaded by the same lazy per-locale loader.\n *\n * The compiler guarantees the attachment for every dictionary holding a nested\n * node, so a missing entry means the dictionary was not produced by the\n * optimized pipeline; the reference then resolves to `undefined`.\n *\n * @param dictionaryKey - The key of the dictionary to nest.\n * @param path - Optional dot-separated path within the nested dictionary.\n * @param props - Interpreter node props, carrying the attached dictionaries.\n * @returns The nested content.\n */\nexport const getNesting = <const K extends DictionaryKeys, const P>(\n dictionaryKey: K,\n path?: P extends ValidDotPathsFor<K> ? P : never,\n props?: NodeProps\n): GetNestingResult<K, P> => {\n const nestedDictionaries = props?.nestedDictionaries;\n const nestedDictionary = nestedDictionaries?.[dictionaryKey as string];\n\n if (!nestedDictionary) return undefined as GetNestingResult<K, P>;\n\n // The attached dictionaries are the raw compiled artifacts, which carry no\n // attachment of their own. Hand the consumer's map down so a nest target that\n // nests further dictionaries resolves too — the map is the transitive\n // closure, so one level of propagation covers any depth, and cycles simply\n // re-read the same finite map.\n const content = getDictionary(\n {\n ...(nestedDictionary as Dictionary),\n nestedDictionaries: {\n ...nestedDictionaries,\n ...(nestedDictionary as Dictionary).nestedDictionaries,\n },\n } as Dictionary,\n props?.locale as LocalesValues,\n props?.plugins\n );\n\n if (typeof path !== 'string') return content as GetNestingResult<K, P>;\n\n return walkPath(content, path) as GetNestingResult<K, P>;\n};\n"],"mappings":";;;;;;;;;;AAiBA,MAAM,YAAY,SAAkB,SAA0B;CAC5D,IAAI,UAAmB;CAEvB,KAAK,MAAM,WAAW,KAAK,MAAM,GAAG,GAAG;EACrC,UAAW,UAAkD;EAE7D,IAAI,YAAY,QAAW,OAAO;CACpC;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAa,cACX,eACA,MACA,UAC2B;CAC3B,MAAM,qBAAqB,OAAO;CAClC,MAAM,mBAAmB,qBAAqB;CAE9C,IAAI,CAAC,kBAAkB,OAAO;CAO9B,MAAM,UAAU,cACd;EACE,GAAI;EACJ,oBAAoB;GAClB,GAAG;GACH,GAAI,iBAAgC;EACtC;CACF,GACA,OAAO,QACP,OAAO,OACT;CAEA,IAAI,OAAO,SAAS,UAAU,OAAO;CAErC,OAAO,SAAS,SAAS,IAAI;AAC/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getEditedContent.d.ts","names":[],"sources":["../../../src/deepTransformPlugins/getEditedContent.ts"],"mappings":";;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"getEditedContent.d.ts","names":[],"sources":["../../../src/deepTransformPlugins/getEditedContent.ts"],"mappings":";;;;;;;;;;;;;;;;;;;cA2Ka,mBAAgB,iBACV,yBAAuB,YAC5B,aAAW,eACR,kBACd;;;;;;;;;cAeU,sBAAmB,oBACV,wBAAsB,eAC3B,YAAU,eACV,kBACd"}
|
|
@@ -26,6 +26,7 @@ declare const getFilterMissingTranslationsDictionary: (dictionary: Dictionary, l
|
|
|
26
26
|
projectIds?: string[];
|
|
27
27
|
localId?: import("@intlayer/types").LocalDictionaryId;
|
|
28
28
|
localIds?: import("@intlayer/types").LocalDictionaryId[];
|
|
29
|
+
nestedDictionaries?: Record<import("@intlayer/types").DictionaryKey, unknown>;
|
|
29
30
|
format?: import("@intlayer/types").DictionaryFormat;
|
|
30
31
|
key: import("@intlayer/types").DictionaryKey;
|
|
31
32
|
title?: string;
|
|
@@ -18,6 +18,7 @@ declare const getFilterTranslationsOnlyDictionary: (dictionary: Dictionary, loca
|
|
|
18
18
|
projectIds?: string[];
|
|
19
19
|
localId?: import("@intlayer/types").LocalDictionaryId;
|
|
20
20
|
localIds?: import("@intlayer/types").LocalDictionaryId[];
|
|
21
|
+
nestedDictionaries?: Record<import("@intlayer/types").DictionaryKey, unknown>;
|
|
21
22
|
format?: import("@intlayer/types").DictionaryFormat;
|
|
22
23
|
key: import("@intlayer/types").DictionaryKey;
|
|
23
24
|
title?: string;
|
|
@@ -10,6 +10,7 @@ declare const getFilteredLocalesDictionary: (dictionary: Dictionary, locale: Loc
|
|
|
10
10
|
projectIds?: string[];
|
|
11
11
|
localId?: import("@intlayer/types").LocalDictionaryId;
|
|
12
12
|
localIds?: import("@intlayer/types").LocalDictionaryId[];
|
|
13
|
+
nestedDictionaries?: Record<import("@intlayer/types").DictionaryKey, unknown>;
|
|
13
14
|
format?: import("@intlayer/types").DictionaryFormat;
|
|
14
15
|
key: import("@intlayer/types").DictionaryKey;
|
|
15
16
|
title?: string;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
//#region src/dictionaryManipulator/getNestedDictionaryReferences.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Top-level content fields of a nest target that are referenced through
|
|
4
|
+
* `nest()` nodes.
|
|
5
|
+
*
|
|
6
|
+
* `'all'` means at least one reference targets the whole dictionary
|
|
7
|
+
* (`nest('common')` without a path), so no field of that dictionary may be
|
|
8
|
+
* dropped.
|
|
9
|
+
*/
|
|
10
|
+
type NestedFieldReferences = Set<string> | 'all';
|
|
11
|
+
/**
|
|
12
|
+
* Walks a dictionary tree and collects every dictionary referenced through a
|
|
13
|
+
* `nest()` node, together with the top-level fields those references read.
|
|
14
|
+
*
|
|
15
|
+
* The walk is iterative (no recursion depth limit) and guards against shared
|
|
16
|
+
* or circular references, so it is safe on both compiled JSON and in-memory
|
|
17
|
+
* dictionaries.
|
|
18
|
+
*
|
|
19
|
+
* @param dictionaries - Dictionary objects (or any content subtree) to scan.
|
|
20
|
+
* @returns Map of nest-target dictionary key → referenced top-level fields.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* // dashboard.content.ts → { period: nest('common', 'period') }
|
|
25
|
+
* getNestedDictionaryReferences([dashboardDictionary]);
|
|
26
|
+
* // Map { 'common' => Set { 'period' } }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
declare const getNestedDictionaryReferences: (dictionaries: Iterable<unknown>) => Map<string, NestedFieldReferences>;
|
|
30
|
+
/**
|
|
31
|
+
* Keys of every dictionary referenced through a `nest()` node.
|
|
32
|
+
*
|
|
33
|
+
* @param dictionaries - Dictionary objects (or any content subtree) to scan.
|
|
34
|
+
* @returns Set of nest-target dictionary keys.
|
|
35
|
+
*/
|
|
36
|
+
declare const getNestedDictionaryKeys: (dictionaries: Iterable<unknown>) => Set<string>;
|
|
37
|
+
/**
|
|
38
|
+
* Builds the `nest()` dependency graph of a set of dictionaries: for each
|
|
39
|
+
* dictionary key, the keys of every dictionary it needs in order to resolve its
|
|
40
|
+
* nested nodes, transitively.
|
|
41
|
+
*
|
|
42
|
+
* The build optimization uses this to attach the nest targets to the dictionary
|
|
43
|
+
* artifact itself, so `nest()` resolves from a local reference and the target
|
|
44
|
+
* lands in the same chunk (or the same lazy per-locale loader) as the
|
|
45
|
+
* dictionary referencing it.
|
|
46
|
+
*
|
|
47
|
+
* Dictionaries without nested nodes are absent from the result.
|
|
48
|
+
*
|
|
49
|
+
* @param dictionaries - Compiled dictionaries to scan; each must carry its `key`.
|
|
50
|
+
* @returns Map of dictionary key → keys it depends on through `nest()`.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* // dashboard nests common, common nests labels
|
|
55
|
+
* getNestedDictionaryGraph([dashboard, common]);
|
|
56
|
+
* // Map { 'dashboard' => Set { 'common', 'labels' }, 'common' => Set { 'labels' } }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
declare const getNestedDictionaryGraph: (dictionaries: Iterable<unknown>) => Map<string, Set<string>>;
|
|
60
|
+
//#endregion
|
|
61
|
+
export { NestedFieldReferences, getNestedDictionaryGraph, getNestedDictionaryKeys, getNestedDictionaryReferences };
|
|
62
|
+
//# sourceMappingURL=getNestedDictionaryReferences.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getNestedDictionaryReferences.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/getNestedDictionaryReferences.ts"],"mappings":";;;;;;;;;KAUY,wBAAwB;;;;;;;;;;;;;;;;;;;cAkEvB,gCAA6B,cAC1B,sBACb,YAAY;;;;;;;cAkDF,0BAAuB,cACpB,sBACb;;;;;;;;;;;;;;;;;;;;;;;cAyDU,2BAAwB,cACrB,sBACb,YAAY"}
|
|
@@ -2,14 +2,17 @@ import { editDictionaryByKeyPath } from "./editDictionaryByKeyPath.js";
|
|
|
2
2
|
import { getContentNodeByKeyPath } from "./getContentNodeByKeyPath.js";
|
|
3
3
|
import { getDefaultNode } from "./getDefaultNode.js";
|
|
4
4
|
import { getEmptyNode } from "./getEmptyNode.js";
|
|
5
|
+
import { NestedFieldReferences, getNestedDictionaryGraph, getNestedDictionaryKeys, getNestedDictionaryReferences } from "./getNestedDictionaryReferences.js";
|
|
5
6
|
import { getNodeChildren } from "./getNodeChildren.js";
|
|
6
7
|
import { getNodeType } from "./getNodeType.js";
|
|
7
8
|
import { mergeDictionaries } from "./mergeDictionaries.js";
|
|
8
9
|
import { mergeQualifiedDictionaries } from "./mergeQualifiedDictionaries.js";
|
|
9
10
|
import { normalizeDictionaries, normalizeDictionary } from "./normalizeDictionary.js";
|
|
10
11
|
import { orderDictionaries } from "./orderDictionaries.js";
|
|
11
|
-
import { COMPOSITE_ID_SEPARATOR, DEFAULT_VARIANT_ID,
|
|
12
|
+
import { COMPOSITE_ID_SEPARATOR, DEFAULT_VARIANT_ID, getDictionarySelectorCacheKey, isQualifiedDictionaryGroup, parseDictionarySelector, reconstructQualifiedEntry, resolveDictionaryArgument, resolveEffectiveVariantId, resolveProviderVariant, resolveQualifiedDictionary, serializeVariant, serializeVariantChain } from "./qualifiedDictionary.js";
|
|
13
|
+
import { QUALIFIER_ORDER, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getVariantIds } from "./qualifiedDictionaryDeclaration.js";
|
|
14
|
+
import { DynamicDictionaryLoader, QUALIFIER_DYNAMIC_TYPES_KEY, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, isQualifiedDynamicLoaderMap, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync } from "./qualifiedDynamicLoader.js";
|
|
12
15
|
import { removeContentNodeByKeyPath } from "./removeContentNodeByKeyPath.js";
|
|
13
16
|
import { renameContentNodeByKeyPath } from "./renameContentNodeByKeyPath.js";
|
|
14
17
|
import { updateNodeChildren } from "./updateNodeChildren.js";
|
|
15
|
-
export { COMPOSITE_ID_SEPARATOR, DEFAULT_VARIANT_ID, DynamicDictionaryLoader, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, editDictionaryByKeyPath, getContentNodeByKeyPath, getDefaultNode, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getEmptyNode, getNodeChildren, getNodeType, getVariantIds, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, mergeDictionaries, mergeQualifiedDictionaries, normalizeDictionaries, normalizeDictionary, orderDictionaries, parseDictionarySelector, reconstructQualifiedEntry, removeContentNodeByKeyPath, renameContentNodeByKeyPath, resolveDictionaryArgument, resolveProviderVariant, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, serializeVariant, serializeVariantChain, updateNodeChildren };
|
|
18
|
+
export { COMPOSITE_ID_SEPARATOR, DEFAULT_VARIANT_ID, DynamicDictionaryLoader, NestedFieldReferences, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, editDictionaryByKeyPath, getContentNodeByKeyPath, getDefaultNode, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getEmptyNode, getNestedDictionaryGraph, getNestedDictionaryKeys, getNestedDictionaryReferences, getNodeChildren, getNodeType, getVariantIds, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, mergeDictionaries, mergeQualifiedDictionaries, normalizeDictionaries, normalizeDictionary, orderDictionaries, parseDictionarySelector, reconstructQualifiedEntry, removeContentNodeByKeyPath, renameContentNodeByKeyPath, resolveDictionaryArgument, resolveEffectiveVariantId, resolveProviderVariant, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, serializeVariant, serializeVariantChain, updateNodeChildren };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mergeQualifiedDictionaries.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/mergeQualifiedDictionaries.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"mergeQualifiedDictionaries.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/mergeQualifiedDictionaries.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;cAoCa,6BAA0B,cACvB,iBACb,aAAa"}
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
import { Dictionary,
|
|
1
|
+
import { Dictionary, DictionarySelector, DictionaryVariantChain, DictionaryVariantValue, ProviderVariant, QualifiedDictionaryGroup } from "@intlayer/types/dictionary";
|
|
2
2
|
import { LocalesValues } from "@intlayer/types/module_augmentation";
|
|
3
3
|
//#region src/dictionaryManipulator/qualifiedDictionary.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* Canonical order of qualifier dimensions. A key that declares both dimensions
|
|
6
|
-
* always nests them in this order, with `item` innermost so it can act as the
|
|
7
|
-
* collection (array) axis.
|
|
8
|
-
*/
|
|
9
|
-
declare const QUALIFIER_ORDER: readonly ["variant", "item"];
|
|
10
4
|
/**
|
|
11
5
|
* Separator joining per-dimension ids into a composite entry id. Also used as
|
|
12
6
|
* the chunk path separator in dynamic mode.
|
|
@@ -37,36 +31,6 @@ declare const DEFAULT_VARIANT_ID = "default";
|
|
|
37
31
|
* an object variant in a selector must equal the one declared on the dictionary.
|
|
38
32
|
*/
|
|
39
33
|
declare const serializeVariant: (variant: DictionaryVariantValue | undefined) => string;
|
|
40
|
-
/**
|
|
41
|
-
* Normalizes the `variant` field of a dictionary into the list of variant ids
|
|
42
|
-
* the declaration registers under. A single value yields one id; an **array**
|
|
43
|
-
* fans out into one id per element (duplicates collapsed). Returns `undefined`
|
|
44
|
-
* when the dictionary does not declare the variant dimension (no `variant`
|
|
45
|
-
* field, or an empty array).
|
|
46
|
-
*/
|
|
47
|
-
declare const getVariantIds: (variant: Dictionary['variant']) => string[] | undefined;
|
|
48
|
-
/**
|
|
49
|
-
* Returns the qualifier dimensions declared on a dictionary, in canonical
|
|
50
|
-
* order (`variant → item`). Empty when the dictionary is unqualified
|
|
51
|
-
* (plain dictionary or shared base content of a qualified group).
|
|
52
|
-
*/
|
|
53
|
-
declare const getDictionaryQualifierTypes: (dictionary: Dictionary) => DictionaryQualifierType[];
|
|
54
|
-
/**
|
|
55
|
-
* Returns the qualifier identifiers of a dictionary for the given qualifier
|
|
56
|
-
* dimension — the candidate segments of the composite entry ids.
|
|
57
|
-
*
|
|
58
|
-
* - 'variant' → the serialized variant id(s); an array variant yields one id
|
|
59
|
-
* per element (declaration-side fan-out)
|
|
60
|
-
* - 'item' → the item index as a single-element list
|
|
61
|
-
*/
|
|
62
|
-
declare const getDictionaryQualifierIds: (dictionary: Dictionary, qualifierType: DictionaryQualifierType) => string[] | undefined;
|
|
63
|
-
/**
|
|
64
|
-
* Builds every composite entry id of a dictionary — the cartesian product of
|
|
65
|
-
* its per-dimension id lists, joined in canonical order. A dictionary with a
|
|
66
|
-
* plain (non-array) variant yields exactly one id; an array variant fans out
|
|
67
|
-
* into one id per element. `undefined` when a dimension of the set is missing.
|
|
68
|
-
*/
|
|
69
|
-
declare const getDictionaryCompositeIds: (dictionary: Dictionary, qualifierTypes: DictionaryQualifierType[]) => string[] | undefined;
|
|
70
34
|
/**
|
|
71
35
|
* Serializes the variant coordinate of a selector into the ordered list of
|
|
72
36
|
* candidate ids to try, so a single value and a preference chain share one code
|
|
@@ -80,6 +44,22 @@ declare const getDictionaryCompositeIds: (dictionary: Dictionary, qualifierTypes
|
|
|
80
44
|
* as an unsatisfiable request.
|
|
81
45
|
*/
|
|
82
46
|
declare const serializeVariantChain: (variant: DictionaryVariantChain | undefined) => string[];
|
|
47
|
+
/**
|
|
48
|
+
* Resolves the variant id a selector actually targets among the ids a key
|
|
49
|
+
* declares — the sparse-override fallback.
|
|
50
|
+
*
|
|
51
|
+
* Candidates are tried in order and the first one the key declares wins.
|
|
52
|
+
* Otherwise the key falls back to its `default` entry, so a variant only has to
|
|
53
|
+
* be declared where its wording differs. When the key declares no `default`
|
|
54
|
+
* either, the first candidate is returned unchanged and the caller resolves to
|
|
55
|
+
* `null` / `[]`.
|
|
56
|
+
*
|
|
57
|
+
* @param requestedVariantIds - The serialized ids the selector asks for, in
|
|
58
|
+
* preference order (a single value is a 1-element
|
|
59
|
+
* list).
|
|
60
|
+
* @param isVariantIdDeclared - Whether the key declares an entry for an id.
|
|
61
|
+
*/
|
|
62
|
+
declare const resolveEffectiveVariantId: (requestedVariantIds: string[], isVariantIdDeclared: (variantId: string) => boolean) => string;
|
|
83
63
|
/**
|
|
84
64
|
* Type guard discriminating a `QualifiedDictionaryGroup` (merge output of a
|
|
85
65
|
* qualified key) from a plain `Dictionary`. Both carry a `content` field; only
|
|
@@ -163,94 +143,6 @@ declare const resolveDictionaryArgument: (params: {
|
|
|
163
143
|
* for cache keys and memoization dependencies.
|
|
164
144
|
*/
|
|
165
145
|
declare const getDictionarySelectorCacheKey: (selector?: DictionarySelector) => string;
|
|
166
|
-
/**
|
|
167
|
-
* Marker property carrying the ordered qualifier dimensions on a dynamic loader
|
|
168
|
-
* map. Its presence distinguishes a qualified group loader map (a nested tree
|
|
169
|
-
* of chunks) from a plain dynamic loader map (one chunk per `locale`). Prefixed
|
|
170
|
-
* and unlikely to collide with a real locale code.
|
|
171
|
-
*/
|
|
172
|
-
declare const QUALIFIER_DYNAMIC_TYPES_KEY = "__intlayerQualifierTypes";
|
|
173
|
-
/**
|
|
174
|
-
* A lazily-imported per-locale dictionary chunk loader.
|
|
175
|
-
*/
|
|
176
|
-
type DynamicDictionaryLoader = () => Promise<Dictionary>;
|
|
177
|
-
/**
|
|
178
|
-
* Nested tree of chunk loaders: one nesting level per declared dimension (in
|
|
179
|
-
* canonical order), leaves are loaders.
|
|
180
|
-
*/
|
|
181
|
-
type QualifiedDynamicLoaderTree = {
|
|
182
|
-
[segment: string]: QualifiedDynamicLoaderTree | DynamicDictionaryLoader;
|
|
183
|
-
};
|
|
184
|
-
/**
|
|
185
|
-
* Default export shape of a generated dynamic entry point for a qualified key.
|
|
186
|
-
* One nesting level per dimension under each locale, plus the dimension marker.
|
|
187
|
-
*
|
|
188
|
-
* ```ts
|
|
189
|
-
* {
|
|
190
|
-
* __intlayerQualifierTypes: ['variant', 'item'],
|
|
191
|
-
* en: { promo: { '1': () => import('./json/x/promo/1/en.json'), … }, … },
|
|
192
|
-
* fr: { … },
|
|
193
|
-
* }
|
|
194
|
-
* ```
|
|
195
|
-
*/
|
|
196
|
-
type QualifiedDynamicLoaderMap = {
|
|
197
|
-
[QUALIFIER_DYNAMIC_TYPES_KEY]: DictionaryQualifierType[];
|
|
198
|
-
[locale: string]: QualifiedDynamicLoaderTree | DictionaryQualifierType[];
|
|
199
|
-
};
|
|
200
|
-
/**
|
|
201
|
-
* Type guard discriminating a qualified dynamic loader map (collections /
|
|
202
|
-
* variants, possibly combined) from a plain dynamic loader map.
|
|
203
|
-
*/
|
|
204
|
-
declare const isQualifiedDynamicLoaderMap: (value: unknown) => value is QualifiedDynamicLoaderMap;
|
|
205
|
-
/**
|
|
206
|
-
* Resolves the content of a qualified dynamic loader map against a selector,
|
|
207
|
-
* loading only the chunk(s) the selector actually targets.
|
|
208
|
-
*
|
|
209
|
-
* Walks the nested loader tree one dimension at a time (canonical order
|
|
210
|
-
* `variant → item`): `variant` descends by the serialized id, falling back to
|
|
211
|
-
* `default` when the selected variant has no chunk of its own, and `item`
|
|
212
|
-
* either narrows to the selected index or — when no item is given — expands
|
|
213
|
-
* into every sibling chunk (the collection axis). Semantics mirror
|
|
214
|
-
* {@link resolveQualifiedDictionary} so dynamic and static modes behave alike.
|
|
215
|
-
*
|
|
216
|
-
* The Suspense mechanism is injected through `loadChunk` so the same logic
|
|
217
|
-
* serves both the client (suspender cache) and the server (`react.use`). Every
|
|
218
|
-
* targeted loader is started before the first chunk is read, so sibling chunks
|
|
219
|
-
* load in parallel rather than waterfalling.
|
|
220
|
-
*
|
|
221
|
-
* @param loaderMap - The qualified dynamic loader map (entry point default export).
|
|
222
|
-
* @param key - The dictionary key (used to build stable chunk cache keys).
|
|
223
|
-
* @param locale - The resolved locale to load chunks for.
|
|
224
|
-
* @param selector - The selector splitting the qualifier dimensions.
|
|
225
|
-
* @param loadChunk - Reads a started chunk promise, suspending until it resolves.
|
|
226
|
-
* @param transform - Turns a resolved chunk dictionary into final content.
|
|
227
|
-
*/
|
|
228
|
-
declare const resolveQualifiedDynamicContent: <Content>(params: {
|
|
229
|
-
loaderMap: QualifiedDynamicLoaderMap;
|
|
230
|
-
key: string;
|
|
231
|
-
locale: string;
|
|
232
|
-
selector: DictionarySelector | undefined;
|
|
233
|
-
loadChunk: (cacheKey: string, promise: Promise<Dictionary>) => Dictionary;
|
|
234
|
-
transform: (dictionary: Dictionary) => Content;
|
|
235
|
-
}) => Content | Content[] | null;
|
|
236
|
-
/**
|
|
237
|
-
* Async counterpart of {@link resolveQualifiedDynamicContent} for frameworks
|
|
238
|
-
* that load dictionaries with `await` instead of Suspense (Vue, Svelte, Lit,
|
|
239
|
-
* vanilla). Awaits every targeted chunk in parallel, then resolves identically.
|
|
240
|
-
*
|
|
241
|
-
* @param loaderMap - The qualified dynamic loader map.
|
|
242
|
-
* @param key - The dictionary key (used to build stable chunk cache keys).
|
|
243
|
-
* @param locale - The resolved locale to load chunks for.
|
|
244
|
-
* @param selector - The selector splitting the qualifier dimensions.
|
|
245
|
-
* @param transform - Turns a resolved chunk dictionary into final content.
|
|
246
|
-
*/
|
|
247
|
-
declare const resolveQualifiedDynamicContentAsync: <Content>(params: {
|
|
248
|
-
loaderMap: QualifiedDynamicLoaderMap;
|
|
249
|
-
key: string;
|
|
250
|
-
locale: string;
|
|
251
|
-
selector: DictionarySelector | undefined;
|
|
252
|
-
transform: (dictionary: Dictionary) => Content;
|
|
253
|
-
}) => Promise<Content | Content[] | null>;
|
|
254
146
|
//#endregion
|
|
255
|
-
export { COMPOSITE_ID_SEPARATOR, DEFAULT_VARIANT_ID,
|
|
147
|
+
export { COMPOSITE_ID_SEPARATOR, DEFAULT_VARIANT_ID, getDictionarySelectorCacheKey, isQualifiedDictionaryGroup, parseDictionarySelector, reconstructQualifiedEntry, resolveDictionaryArgument, resolveEffectiveVariantId, resolveProviderVariant, resolveQualifiedDictionary, serializeVariant, serializeVariantChain };
|
|
256
148
|
//# sourceMappingURL=qualifiedDictionary.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qualifiedDictionary.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/qualifiedDictionary.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"qualifiedDictionary.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/qualifiedDictionary.ts"],"mappings":";;;;;;;cAgBa;;;;;;cAOA;;;;;;;;;;;;;;;;;;;cAqDA,mBAAgB,SAClB;;;;;;;;;;;;;cA4BE,wBAAqB,SACvB;;;;;;;;;;;;;;;;cA0BE,4BAAyB,+BACP,sBACP;;;;;;cA4CX,6BAA0B,mBAEpC,SAAS;;;;;;;;;;;;cAkBC,4BAAyB,OAC7B,0BAAwB,wBAE9B;;;;;;;;;;;;;;;;cAkCU,6BAA0B,mBAClB,aAAa,0BAAwB,WAC7C,uBACV,aAAa;;;;;cAoDH,0BAA2B,UAAU,eAAa,mBAC1C,IAAI;EACpB,SAAS;EAAG,WAAW;;;;;;;;;;;;;;;;;cA0Bf,yBAAsB,iBAChB,6BAA2B,0BAE3C;;;;;;;;;;;;;;;cA0BU,4BAAyB;EACpC,mBAAmB,gBAAgB;EACnC,gBAAgB;EAChB,iBAAiB;EACjB;MACE,gBAAgB;;;;;cAqCP,gCAA6B,WAC7B"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Dictionary, DictionaryQualifierType } from "@intlayer/types/dictionary";
|
|
2
|
+
//#region src/dictionaryManipulator/qualifiedDictionaryDeclaration.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Canonical order of qualifier dimensions. A key that declares both dimensions
|
|
5
|
+
* always nests them in this order, with `item` innermost so it can act as the
|
|
6
|
+
* collection (array) axis.
|
|
7
|
+
*/
|
|
8
|
+
declare const QUALIFIER_ORDER: readonly ["variant", "item"];
|
|
9
|
+
/**
|
|
10
|
+
* Normalizes the `variant` field of a dictionary into the list of variant ids
|
|
11
|
+
* the declaration registers under. A single value yields one id; an **array**
|
|
12
|
+
* fans out into one id per element (duplicates collapsed). Returns `undefined`
|
|
13
|
+
* when the dictionary does not declare the variant dimension (no `variant`
|
|
14
|
+
* field, or an empty array).
|
|
15
|
+
*/
|
|
16
|
+
declare const getVariantIds: (variant: Dictionary['variant']) => string[] | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Returns the qualifier dimensions declared on a dictionary, in canonical
|
|
19
|
+
* order (`variant → item`). Empty when the dictionary is unqualified
|
|
20
|
+
* (plain dictionary or shared base content of a qualified group).
|
|
21
|
+
*/
|
|
22
|
+
declare const getDictionaryQualifierTypes: (dictionary: Dictionary) => DictionaryQualifierType[];
|
|
23
|
+
/**
|
|
24
|
+
* Returns the qualifier identifiers of a dictionary for the given qualifier
|
|
25
|
+
* dimension — the candidate segments of the composite entry ids.
|
|
26
|
+
*
|
|
27
|
+
* - 'variant' → the serialized variant id(s); an array variant yields one id
|
|
28
|
+
* per element (declaration-side fan-out)
|
|
29
|
+
* - 'item' → the item index as a single-element list
|
|
30
|
+
*/
|
|
31
|
+
declare const getDictionaryQualifierIds: (dictionary: Dictionary, qualifierType: DictionaryQualifierType) => string[] | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Builds every composite entry id of a dictionary — the cartesian product of
|
|
34
|
+
* its per-dimension id lists, joined in canonical order. A dictionary with a
|
|
35
|
+
* plain (non-array) variant yields exactly one id; an array variant fans out
|
|
36
|
+
* into one id per element. `undefined` when a dimension of the set is missing.
|
|
37
|
+
*/
|
|
38
|
+
declare const getDictionaryCompositeIds: (dictionary: Dictionary, qualifierTypes: DictionaryQualifierType[]) => string[] | undefined;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { QUALIFIER_ORDER, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getVariantIds };
|
|
41
|
+
//# sourceMappingURL=qualifiedDictionaryDeclaration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qualifiedDictionaryDeclaration.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/qualifiedDictionaryDeclaration.ts"],"mappings":";;;;;;;cAca;;;;;;;;cAYA,gBAAa,SACf;;;;;;cAeE,8BAA2B,YAC1B,eACX;;;;;;;;;cAmBU,4BAAyB,YACxB,YAAU,eACP;;;;;;;cAcJ,4BAAyB,YACxB,YAAU,gBACN"}
|