@intlayer/core 9.5.9 → 9.5.10
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/dictionaryManipulator/qualifiedDictionary.cjs.map +1 -1
- package/dist/cjs/index.cjs +4 -0
- package/dist/cjs/interpreter/getContent/deepTransform.cjs +17 -22
- package/dist/cjs/interpreter/getContent/deepTransform.cjs.map +1 -1
- package/dist/cjs/interpreter/getContent/getContent.cjs +1 -1
- package/dist/cjs/interpreter/getContent/getContent.cjs.map +1 -1
- package/dist/cjs/interpreter/getContent/plugins.cjs +29 -30
- package/dist/cjs/interpreter/getContent/plugins.cjs.map +1 -1
- package/dist/cjs/interpreter/getDictionary.cjs +20 -5
- package/dist/cjs/interpreter/getDictionary.cjs.map +1 -1
- package/dist/cjs/interpreter/getTranslation.cjs +31 -27
- package/dist/cjs/interpreter/getTranslation.cjs.map +1 -1
- package/dist/cjs/localization/getPathWithoutLocale.cjs.map +1 -1
- package/dist/cjs/localization/localeResolver.cjs +1 -0
- package/dist/cjs/localization/localeResolver.cjs.map +1 -1
- package/dist/cjs/markdown/compiler.cjs +12 -3
- package/dist/cjs/markdown/compiler.cjs.map +1 -1
- package/dist/cjs/markdown/constants.cjs +3 -0
- package/dist/cjs/markdown/constants.cjs.map +1 -1
- package/dist/cjs/markdown/index.cjs +1 -0
- package/dist/cjs/markdown/utils.cjs +1 -1
- package/dist/cjs/markdown/utils.cjs.map +1 -1
- package/dist/cjs/messageFormat/ICU.cjs +10 -10
- package/dist/cjs/messageFormat/ICU.cjs.map +1 -1
- package/dist/cjs/messageFormat/i18next.cjs +7 -7
- package/dist/cjs/messageFormat/i18next.cjs.map +1 -1
- package/dist/cjs/messageFormat/po.cjs +1 -1
- package/dist/cjs/messageFormat/po.cjs.map +1 -1
- package/dist/cjs/messageFormat/resolveMessage.cjs +2 -2
- package/dist/cjs/messageFormat/resolveMessage.cjs.map +1 -1
- package/dist/cjs/messageFormat/verify-icu-format.cjs +4 -4
- package/dist/cjs/messageFormat/verify-icu-format.cjs.map +1 -1
- package/dist/cjs/messageFormat/vue-i18n.cjs +4 -4
- package/dist/cjs/messageFormat/vue-i18n.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +3 -0
- package/dist/cjs/utils/intlayerNodePrototype.cjs +66 -0
- package/dist/cjs/utils/intlayerNodePrototype.cjs.map +1 -0
- package/dist/cjs/utils/localeStorage.cjs +20 -0
- package/dist/cjs/utils/localeStorage.cjs.map +1 -1
- package/dist/esm/dictionaryManipulator/qualifiedDictionary.mjs.map +1 -1
- package/dist/esm/index.mjs +4 -3
- package/dist/esm/interpreter/getContent/deepTransform.mjs +17 -22
- package/dist/esm/interpreter/getContent/deepTransform.mjs.map +1 -1
- package/dist/esm/interpreter/getContent/getContent.mjs +2 -2
- package/dist/esm/interpreter/getContent/getContent.mjs.map +1 -1
- package/dist/esm/interpreter/getContent/plugins.mjs +29 -30
- package/dist/esm/interpreter/getContent/plugins.mjs.map +1 -1
- package/dist/esm/interpreter/getDictionary.mjs +20 -5
- package/dist/esm/interpreter/getDictionary.mjs.map +1 -1
- package/dist/esm/interpreter/getTranslation.mjs +31 -27
- package/dist/esm/interpreter/getTranslation.mjs.map +1 -1
- package/dist/esm/localization/getPathWithoutLocale.mjs.map +1 -1
- package/dist/esm/localization/localeResolver.mjs +1 -0
- package/dist/esm/localization/localeResolver.mjs.map +1 -1
- package/dist/esm/markdown/compiler.mjs +13 -4
- package/dist/esm/markdown/compiler.mjs.map +1 -1
- package/dist/esm/markdown/constants.mjs +3 -1
- package/dist/esm/markdown/constants.mjs.map +1 -1
- package/dist/esm/markdown/index.mjs +2 -2
- package/dist/esm/markdown/utils.mjs +1 -1
- package/dist/esm/markdown/utils.mjs.map +1 -1
- package/dist/esm/messageFormat/ICU.mjs +10 -10
- package/dist/esm/messageFormat/ICU.mjs.map +1 -1
- package/dist/esm/messageFormat/i18next.mjs +7 -7
- package/dist/esm/messageFormat/i18next.mjs.map +1 -1
- package/dist/esm/messageFormat/po.mjs +1 -1
- package/dist/esm/messageFormat/po.mjs.map +1 -1
- package/dist/esm/messageFormat/resolveMessage.mjs +2 -2
- package/dist/esm/messageFormat/resolveMessage.mjs.map +1 -1
- package/dist/esm/messageFormat/verify-icu-format.mjs +4 -4
- package/dist/esm/messageFormat/verify-icu-format.mjs.map +1 -1
- package/dist/esm/messageFormat/vue-i18n.mjs +4 -4
- package/dist/esm/messageFormat/vue-i18n.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +3 -2
- package/dist/esm/utils/intlayerNodePrototype.mjs +65 -0
- package/dist/esm/utils/intlayerNodePrototype.mjs.map +1 -0
- package/dist/esm/utils/localeStorage.mjs +20 -1
- package/dist/esm/utils/localeStorage.mjs.map +1 -1
- package/dist/types/deepTransformPlugins/getFilterMissingTranslationsContent.d.ts +1 -1
- package/dist/types/deepTransformPlugins/getFilterTranslationsOnlyContent.d.ts +1 -1
- package/dist/types/deepTransformPlugins/getFilteredLocalesContent.d.ts +1 -1
- package/dist/types/index.d.ts +4 -3
- package/dist/types/interpreter/getContent/deepTransform.d.ts.map +1 -1
- package/dist/types/interpreter/getContent/getContent.d.ts.map +1 -1
- package/dist/types/interpreter/getContent/plugins.d.ts +3 -1
- package/dist/types/interpreter/getContent/plugins.d.ts.map +1 -1
- package/dist/types/interpreter/getDictionary.d.ts.map +1 -1
- package/dist/types/interpreter/getTranslation.d.ts.map +1 -1
- package/dist/types/markdown/compiler.d.ts +1 -0
- package/dist/types/markdown/compiler.d.ts.map +1 -1
- package/dist/types/markdown/constants.d.ts +2 -0
- package/dist/types/markdown/constants.d.ts.map +1 -1
- package/dist/types/markdown/index.d.ts +2 -2
- package/dist/types/messageFormat/ICU.d.ts.map +1 -1
- package/dist/types/messageFormat/i18next.d.ts.map +1 -1
- package/dist/types/messageFormat/vue-i18n.d.ts.map +1 -1
- package/dist/types/utils/index.d.ts +3 -2
- package/dist/types/utils/intlayerNodePrototype.d.ts +15 -0
- package/dist/types/utils/intlayerNodePrototype.d.ts.map +1 -0
- package/dist/types/utils/localeStorage.d.ts +9 -0
- package/dist/types/utils/localeStorage.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qualifiedDictionary.cjs","names":[],"sources":["../../../src/dictionaryManipulator/qualifiedDictionary.ts"],"sourcesContent":["import type {\n Dictionary,\n DictionaryQualifierType,\n DictionarySelector,\n DictionaryVariantChain,\n DictionaryVariantValue,\n ProviderVariantBase,\n ProviderVariantMap,\n QualifiedDictionaryGroup,\n} from '@intlayer/types/dictionary';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\n\n/**\n * Separator joining per-dimension ids into a composite entry id. Also used as\n * the chunk path separator in dynamic mode.\n */\nexport const COMPOSITE_ID_SEPARATOR = '/';\n\n/**\n * Identity of the implicit fallback variant. A selector that pins no variant\n * resolves to it, and a variant that declares no entry of its own falls back to\n * it — so a key only has to ship the entries that actually differ.\n */\nexport const DEFAULT_VARIANT_ID = 'default';\n\n/**\n * Characters kept verbatim in an encoded qualifier segment. Everything else is\n * percent-encoded so a segment can never contain the composite-id separator\n * (`/`), path-hostile characters (`\\` `:` `*` `?` `\"` `<` `>` `|`, control\n * chars), or characters that would break the generated loader modules (`'`).\n */\nconst SEGMENT_UNSAFE_CHARS = /[^A-Za-z0-9._&=-]/g;\n\n/**\n * Stricter set for the components of an object variant: also encodes `&` and\n * `=` so the `field=value&field=value` serialization stays unambiguous.\n */\nconst COMPONENT_UNSAFE_CHARS = /[^A-Za-z0-9._-]/g;\n\n/** Percent-encodes one UTF-16 code unit as a fixed-width `%XXXX` run. */\nconst percentEncodeChar = (char: string): string =>\n `%${char.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')}`;\n\nconst encodeSegmentText = (raw: string, unsafeChars: RegExp): string => {\n // Bare '%' cannot be produced by encoding (every encoded run is %XXXX),\n // so it is a safe stand-in for the empty string.\n if (raw === '') return '%';\n\n const encoded = raw.replace(unsafeChars, percentEncodeChar);\n\n // '.' and '..' are path navigation on every filesystem — encode the dots.\n if (encoded === '.' || encoded === '..') {\n return encoded.replace(/\\./g, '%002E');\n }\n\n return encoded;\n};\n\n/**\n * Canonical serialization of a single variant value into its identity string —\n * the variant segment of a composite id, the chunk directory name in dynamic\n * mode, and the runtime matching key.\n *\n * - `undefined` → `'default'` (the implicit fallback variant)\n * - a string → the string itself (a named variant)\n * - an object → its sorted `key=value` pairs joined by `&`\n * (e.g. `{ userId: '123', id: 'abc' }` → `'id=abc&userId=123'`)\n *\n * Characters that are unsafe in file paths or generated code are\n * percent-encoded (fixed-width `%XXXX` runs, injective). Common names —\n * letters, digits, `-` `_` `.` — are left untouched. Both the declaration and\n * the selector go through this function, so encoding never affects matching.\n *\n * Two variants resolve to the same entry iff their serializations are equal, so\n * an object variant in a selector must equal the one declared on the dictionary.\n */\nexport const serializeVariant = (\n variant: DictionaryVariantValue | undefined\n): string => {\n if (variant === undefined) return DEFAULT_VARIANT_ID;\n if (typeof variant === 'string') {\n return encodeSegmentText(variant, SEGMENT_UNSAFE_CHARS);\n }\n\n return Object.keys(variant)\n .sort()\n .map(\n (field) =>\n `${encodeSegmentText(field, COMPONENT_UNSAFE_CHARS)}=${encodeSegmentText(String(variant[field]), COMPONENT_UNSAFE_CHARS)}`\n )\n .join('&');\n};\n\n/**\n * Serializes the variant coordinate of a selector into the ordered list of\n * candidate ids to try, so a single value and a preference chain share one code\n * path downstream.\n *\n * - `undefined` → `['default']`\n * - a single value → its one serialization\n * - a chain → one serialization per entry, order preserved\n *\n * An empty chain is treated as \"no variant pinned\" (`['default']`) rather than\n * as an unsatisfiable request.\n */\nexport const serializeVariantChain = (\n variant: DictionaryVariantChain | undefined\n): string[] => {\n if (!Array.isArray(variant)) {\n return [serializeVariant(variant as DictionaryVariantValue | undefined)];\n }\n\n if (variant.length === 0) return [DEFAULT_VARIANT_ID];\n\n return variant.map(serializeVariant);\n};\n\n/**\n * Resolves the variant id a selector actually targets among the ids a key\n * declares — the sparse-override fallback.\n *\n * Candidates are tried in order and the first one the key declares wins.\n * Otherwise the key falls back to its `default` entry, so a variant only has to\n * be declared where its wording differs. When the key declares no `default`\n * either, the first candidate is returned unchanged and the caller resolves to\n * `null` / `[]`.\n *\n * @param requestedVariantIds - The serialized ids the selector asks for, in\n * preference order (a single value is a 1-element\n * list).\n * @param isVariantIdDeclared - Whether the key declares an entry for an id.\n */\nexport const resolveEffectiveVariantId = (\n requestedVariantIds: string[],\n isVariantIdDeclared: (variantId: string) => boolean\n): string => {\n for (const requestedVariantId of requestedVariantIds) {\n if (isVariantIdDeclared(requestedVariantId)) return requestedVariantId;\n }\n\n return isVariantIdDeclared(DEFAULT_VARIANT_ID)\n ? DEFAULT_VARIANT_ID\n : (requestedVariantIds[0] ?? DEFAULT_VARIANT_ID);\n};\n\n/**\n * Tests whether a composite entry id matches a selector across every declared\n * dimension. Segments are compared in their encoded form (both the stored id\n * and the selector go through {@link serializeVariant}). The `item` dimension\n * matches any value when the selector does not provide one (open collection\n * axis); the `variant` dimension is compared against the already-resolved\n * effective id, so the fallback is applied consistently across dimensions.\n */\nconst compositeIdMatchesSelector = (\n compositeId: string,\n qualifierTypes: DictionaryQualifierType[],\n selector: DictionarySelector | undefined,\n effectiveVariantId: string\n): boolean => {\n const segments = compositeId.split(COMPOSITE_ID_SEPARATOR);\n\n return qualifierTypes.every((qualifierType, index) => {\n if (qualifierType === 'variant') {\n return segments[index] === effectiveVariantId;\n }\n\n // qualifierType === 'item'\n return (\n selector?.item === undefined || segments[index] === String(selector.item)\n );\n });\n};\n\n/**\n * Type guard discriminating a `QualifiedDictionaryGroup` (merge output of a\n * qualified key) from a plain `Dictionary`. Both carry a `content` field; only\n * the group declares `qualifierTypes`, which is therefore the discriminator.\n */\nexport const isQualifiedDictionaryGroup = (\n value: unknown\n): value is QualifiedDictionaryGroup =>\n typeof value === 'object' &&\n value !== null &&\n 'qualifierTypes' in value &&\n Array.isArray((value as { qualifierTypes: unknown }).qualifierTypes) &&\n 'content' in value;\n\n/**\n * Reconstructs a resolvable {@link Dictionary} from a single entry of a\n * qualified group: the content node stored under its composite id, plus the\n * qualifier coordinates decoded from that id (`variant`, `item`).\n *\n * This keeps the resolver's transform code unchanged: it still sees a\n * `{ key, content, variant?, item? }` shape, even though the stored format no\n * longer duplicates those fields per entry. The `variant` coordinate stays in\n * its serialized (encoded) form, e.g. `'id=abc&userId=123'` — matching happens\n * on the composite id segments, never on this reconstructed field.\n */\nexport const reconstructQualifiedEntry = (\n group: QualifiedDictionaryGroup,\n compositeId: string\n): Dictionary => {\n const segments = compositeId.split(COMPOSITE_ID_SEPARATOR);\n\n const entry = {\n key: group.key,\n content: group.content[compositeId],\n } as Dictionary;\n\n group.qualifierTypes.forEach((qualifierType, index) => {\n if (qualifierType === 'variant') {\n entry.variant = segments[index];\n } else if (qualifierType === 'item') {\n entry.item = Number(segments[index]);\n }\n });\n\n return entry;\n};\n\n/**\n * Resolves a dictionary (or qualified dictionary group) against a selector,\n * across every declared dimension.\n *\n * - Plain dictionary → returned as-is (selector ignored)\n * - `item` declared but not selected → every matching entry ordered by index\n * - `item` selected → the matching entry or null\n * - `variant` defaults to the `default` entry when not selected, and falls back\n * to it when the selected variant declares no entry of its own; an object\n * variant resolves only when the selector provides an equal object (or, again,\n * through the `default` fallback)\n *\n * Dimensions compose: e.g. a variant × item key with `{ variant: 'promo' }`\n * returns every promo item as an array; adding `{ item: 2 }` narrows to one.\n */\nexport const resolveQualifiedDictionary = (\n dictionaryOrGroup: Dictionary | QualifiedDictionaryGroup,\n selector?: DictionarySelector\n): Dictionary | Dictionary[] | null => {\n if (!isQualifiedDictionaryGroup(dictionaryOrGroup)) {\n return dictionaryOrGroup;\n }\n\n const { qualifierTypes, content } = dictionaryOrGroup;\n\n const itemAxisOpen =\n qualifierTypes.includes('item') && selector?.item === undefined;\n\n const compositeIds = Object.keys(content);\n const variantIndex = qualifierTypes.indexOf('variant');\n\n const effectiveVariantId =\n variantIndex === -1\n ? DEFAULT_VARIANT_ID\n : resolveEffectiveVariantId(\n serializeVariantChain(selector?.variant),\n (variantId) =>\n compositeIds.some(\n (compositeId) =>\n compositeId.split(COMPOSITE_ID_SEPARATOR)[variantIndex] ===\n variantId\n )\n );\n\n const matchedEntries = compositeIds\n .filter((compositeId) =>\n compositeIdMatchesSelector(\n compositeId,\n qualifierTypes,\n selector,\n effectiveVariantId\n )\n )\n .map((compositeId) =>\n reconstructQualifiedEntry(dictionaryOrGroup, compositeId)\n );\n\n if (itemAxisOpen) {\n return matchedEntries.sort(\n (left, right) => (left.item ?? 0) - (right.item ?? 0)\n );\n }\n\n return matchedEntries[0] ?? null;\n};\n\n/**\n * Splits the second argument of `getIntlayer` / `getDictionary` into the\n * effective locale and the selector object (if any).\n */\nexport const parseDictionarySelector = <L extends LocalesValues>(\n localeOrSelector?: L | DictionarySelector\n): { locale?: L; selector?: DictionarySelector } => {\n if (typeof localeOrSelector === 'object' && localeOrSelector !== null) {\n return {\n locale: localeOrSelector.locale as L | undefined,\n selector: localeOrSelector,\n };\n }\n\n return { locale: localeOrSelector };\n};\n\n/**\n * Resolves the variant a provider pins for one dictionary key.\n *\n * A string or a chain applies to every key as-is. A plain object is the per-key\n * map: the entry for `dictionaryKey` wins, falling back to the reserved\n * `default` entry, and `undefined` when neither is present (the key then\n * resolves to its own `default` variant, i.e. the behaviour without a provider\n * variant at all).\n *\n * A plain object is **always** the map here — never a structured variant value,\n * which is why a structured variant has to be nested (`{ default: { id } }`).\n *\n * @param providerVariant - The `variant` prop of the surrounding provider.\n * @param dictionaryKey - The key being read.\n */\nexport const resolveProviderVariant = (\n providerVariant: ProviderVariantBase | undefined,\n dictionaryKey: string\n): DictionaryVariantChain | undefined => {\n if (providerVariant === undefined) return undefined;\n\n if (typeof providerVariant === 'string' || Array.isArray(providerVariant)) {\n return providerVariant as DictionaryVariantChain;\n }\n\n const variantMap = providerVariant as ProviderVariantMap;\n\n return variantMap[dictionaryKey] ?? variantMap[DEFAULT_VARIANT_ID];\n};\n\n/**\n * Builds the effective second argument of a dictionary read by layering the\n * provider defaults under the call-site one — the single place the `locale` and\n * `variant` context defaults are applied, shared by every framework binding.\n *\n * Precedence, per dimension independently:\n * - a call-site selector always wins; `{ variant: 'x' }` **replaces** the\n * provider chain rather than extending it\n * - otherwise the provider value applies\n *\n * Returns a bare locale (not a selector object) whenever no variant is in play,\n * so the existing fast path — and the cache keys built from it — are unchanged\n * for projects that never use variants.\n */\nexport const resolveDictionaryArgument = (params: {\n localeOrSelector?: LocalesValues | DictionarySelector;\n contextLocale?: LocalesValues;\n contextVariant?: ProviderVariantBase;\n dictionaryKey: string;\n}): LocalesValues | DictionarySelector | undefined => {\n const { localeOrSelector, contextLocale, contextVariant, dictionaryKey } =\n params;\n\n const callSelector =\n typeof localeOrSelector === 'object' && localeOrSelector !== null\n ? localeOrSelector\n : undefined;\n\n const callLocale = callSelector\n ? callSelector.locale\n : (localeOrSelector as LocalesValues | undefined);\n\n // The context locale is typed as widely as the runtime allows, while a\n // selector narrows `locale` to the declared ones — the value is the same.\n const locale = (callLocale ?? contextLocale) as DictionarySelector['locale'];\n\n // A call-site variant is authoritative; the provider only fills the gap.\n const variant =\n callSelector?.variant ??\n resolveProviderVariant(contextVariant, dictionaryKey);\n\n if (variant === undefined) {\n // Nothing to add: keep the argument in its original shape so the identity\n // built from it stays byte-identical to the pre-variant behaviour.\n return callSelector\n ? { ...callSelector, locale }\n : (locale as LocalesValues | undefined);\n }\n\n return { ...callSelector, locale, variant };\n};\n\n/**\n * Builds a stable string identity of a selector (excluding `locale`), suitable\n * for cache keys and memoization dependencies.\n */\nexport const getDictionarySelectorCacheKey = (\n selector?: DictionarySelector\n): string => {\n if (!selector) return '';\n\n return Object.keys(selector)\n .filter((selectorKey) => selectorKey !== 'locale')\n .sort()\n .map((selectorKey) => {\n const value = selector[selectorKey as keyof DictionarySelector];\n const serialized =\n selectorKey === 'variant'\n ? serializeVariantChain(\n value as DictionaryVariantChain | undefined\n ).join(',')\n : String(value);\n return `${selectorKey}:${serialized}`;\n })\n .join('|');\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"qualifiedDictionary.cjs","names":[],"sources":["../../../src/dictionaryManipulator/qualifiedDictionary.ts"],"sourcesContent":["import type {\n Dictionary,\n DictionaryQualifierType,\n DictionarySelector,\n DictionaryVariantChain,\n DictionaryVariantValue,\n ProviderVariantBase,\n ProviderVariantMap,\n QualifiedDictionaryGroup,\n} from '@intlayer/types/dictionary';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\n\n/**\n * Separator joining per-dimension ids into a composite entry id. Also used as\n * the chunk path separator in dynamic mode.\n */\nexport const COMPOSITE_ID_SEPARATOR = '/';\n\n/**\n * Identity of the implicit fallback variant. A selector that pins no variant\n * resolves to it, and a variant that declares no entry of its own falls back to\n * it — so a key only has to ship the entries that actually differ.\n */\nexport const DEFAULT_VARIANT_ID = 'default';\n\n/**\n * Characters kept verbatim in an encoded qualifier segment. Everything else is\n * percent-encoded so a segment can never contain the composite-id separator\n * (`/`), path-hostile characters (`\\` `:` `*` `?` `\"` `<` `>` `|`, control\n * chars), or characters that would break the generated loader modules (`'`).\n */\nconst SEGMENT_UNSAFE_CHARS = /[^A-Za-z0-9._&=-]/g;\n\n/**\n * Stricter set for the components of an object variant: also encodes `&` and\n * `=` so the `field=value&field=value` serialization stays unambiguous.\n */\nconst COMPONENT_UNSAFE_CHARS = /[^A-Za-z0-9._-]/g;\n\n/** Percent-encodes one UTF-16 code unit as a fixed-width `%XXXX` run. */\nconst percentEncodeChar = (char: string): string =>\n `%${char.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')}`;\n\nconst encodeSegmentText = (raw: string, unsafeChars: RegExp): string => {\n // Bare '%' cannot be produced by encoding (every encoded run is %XXXX),\n // so it is a safe stand-in for the empty string.\n if (raw === '') return '%';\n\n const encoded = raw.replace(unsafeChars, percentEncodeChar);\n\n // '.' and '..' are path navigation on every filesystem — encode the dots.\n if (encoded === '.' || encoded === '..') {\n return encoded.replace(/\\./g, '%002E');\n }\n\n return encoded;\n};\n\n/**\n * Canonical serialization of a single variant value into its identity string —\n * the variant segment of a composite id, the chunk directory name in dynamic\n * mode, and the runtime matching key.\n *\n * - `undefined` → `'default'` (the implicit fallback variant)\n * - a string → the string itself (a named variant)\n * - an object → its sorted `key=value` pairs joined by `&`\n * (e.g. `{ userId: '123', id: 'abc' }` → `'id=abc&userId=123'`)\n *\n * Characters that are unsafe in file paths or generated code are\n * percent-encoded (fixed-width `%XXXX` runs, injective). Common names —\n * letters, digits, `-` `_` `.` — are left untouched. Both the declaration and\n * the selector go through this function, so encoding never affects matching.\n *\n * Two variants resolve to the same entry iff their serializations are equal, so\n * an object variant in a selector must equal the one declared on the dictionary.\n */\nexport const serializeVariant = (\n variant: DictionaryVariantValue | undefined\n): string => {\n if (variant === undefined) return DEFAULT_VARIANT_ID;\n if (typeof variant === 'string') {\n return encodeSegmentText(variant, SEGMENT_UNSAFE_CHARS);\n }\n\n return Object.keys(variant)\n .sort()\n .map(\n (field) =>\n `${encodeSegmentText(field, COMPONENT_UNSAFE_CHARS)}=${encodeSegmentText(String(variant[field]), COMPONENT_UNSAFE_CHARS)}`\n )\n .join('&');\n};\n\n/**\n * Serializes the variant coordinate of a selector into the ordered list of\n * candidate ids to try, so a single value and a preference chain share one code\n * path downstream.\n *\n * - `undefined` → `['default']`\n * - a single value → its one serialization\n * - a chain → one serialization per entry, order preserved\n *\n * An empty chain is treated as \"no variant pinned\" (`['default']`) rather than\n * as an unsatisfiable request.\n */\nexport const serializeVariantChain = (\n variant: DictionaryVariantChain | undefined\n): string[] => {\n if (!Array.isArray(variant)) {\n return [serializeVariant(variant as DictionaryVariantValue | undefined)];\n }\n\n if (variant.length === 0) return [DEFAULT_VARIANT_ID];\n\n return variant.map(serializeVariant);\n};\n\n/**\n * Resolves the variant id a selector actually targets among the ids a key\n * declares — the sparse-override fallback.\n *\n * Candidates are tried in order and the first one the key declares wins.\n * Otherwise the key falls back to its `default` entry, so a variant only has to\n * be declared where its wording differs. When the key declares no `default`\n * either, the first candidate is returned unchanged and the caller resolves to\n * `null` / `[]`.\n *\n * @param requestedVariantIds - The serialized ids the selector asks for, in\n * preference order (a single value is a 1-element\n * list).\n * @param isVariantIdDeclared - Whether the key declares an entry for an id.\n */\nexport const resolveEffectiveVariantId = (\n requestedVariantIds: string[],\n isVariantIdDeclared: (variantId: string) => boolean\n): string => {\n for (const requestedVariantId of requestedVariantIds) {\n if (isVariantIdDeclared(requestedVariantId)) return requestedVariantId;\n }\n\n return isVariantIdDeclared(DEFAULT_VARIANT_ID)\n ? DEFAULT_VARIANT_ID\n : (requestedVariantIds[0] ?? DEFAULT_VARIANT_ID);\n};\n\n/**\n * Tests whether a composite entry id matches a selector across every declared\n * dimension. Segments are compared in their encoded form (both the stored id\n * and the selector go through {@link serializeVariant}). The `item` dimension\n * matches any value when the selector does not provide one (open collection\n * axis); the `variant` dimension is compared against the already-resolved\n * effective id, so the fallback is applied consistently across dimensions.\n */\nconst compositeIdMatchesSelector = (\n compositeId: string,\n qualifierTypes: DictionaryQualifierType[],\n selector: DictionarySelector | undefined,\n effectiveVariantId: string\n): boolean => {\n const segments = compositeId.split(COMPOSITE_ID_SEPARATOR);\n\n return qualifierTypes.every((qualifierType, index) => {\n if (qualifierType === 'variant') {\n return segments[index] === effectiveVariantId;\n }\n\n // qualifierType === 'item'\n return (\n selector?.item === undefined || segments[index] === String(selector.item)\n );\n });\n};\n\n/**\n * Type guard discriminating a `QualifiedDictionaryGroup` (merge output of a\n * qualified key) from a plain `Dictionary`. Both carry a `content` field; only\n * the group declares `qualifierTypes`, which is therefore the discriminator.\n */\nexport const isQualifiedDictionaryGroup = (\n value: unknown\n): value is QualifiedDictionaryGroup =>\n typeof value === 'object' &&\n value !== null &&\n 'qualifierTypes' in value &&\n Array.isArray((value as { qualifierTypes: unknown }).qualifierTypes) &&\n 'content' in value;\n\n/**\n * Reconstructs a resolvable {@link Dictionary} from a single entry of a\n * qualified group: the content node stored under its composite id, plus the\n * qualifier coordinates decoded from that id (`variant`, `item`).\n *\n * This keeps the resolver's transform code unchanged: it still sees a\n * `{ key, content, variant?, item? }` shape, even though the stored format no\n * longer duplicates those fields per entry. The `variant` coordinate stays in\n * its serialized (encoded) form, e.g. `'id=abc&userId=123'` — matching happens\n * on the composite id segments, never on this reconstructed field.\n */\nexport const reconstructQualifiedEntry = (\n group: QualifiedDictionaryGroup,\n compositeId: string\n): Dictionary => {\n const segments = compositeId.split(COMPOSITE_ID_SEPARATOR);\n\n const entry = {\n key: group.key,\n content: group.content[compositeId],\n } as Dictionary;\n\n group.qualifierTypes.forEach((qualifierType, index) => {\n if (qualifierType === 'variant') {\n entry.variant = segments[index];\n } else if (qualifierType === 'item') {\n entry.item = Number(segments[index]);\n }\n });\n\n return entry;\n};\n\n/**\n * Resolves a dictionary (or qualified dictionary group) against a selector,\n * across every declared dimension.\n *\n * - Plain dictionary → returned as-is (selector ignored)\n * - `item` declared but not selected → every matching entry ordered by index\n * - `item` selected → the matching entry or null\n * - `variant` defaults to the `default` entry when not selected, and falls back\n * to it when the selected variant declares no entry of its own; an object\n * variant resolves only when the selector provides an equal object (or, again,\n * through the `default` fallback)\n *\n * Dimensions compose: e.g. a variant × item key with `{ variant: 'promo' }`\n * returns every promo item as an array; adding `{ item: 2 }` narrows to one.\n */\nexport const resolveQualifiedDictionary = (\n dictionaryOrGroup: Dictionary | QualifiedDictionaryGroup,\n selector?: DictionarySelector\n): Dictionary | Dictionary[] | null => {\n if (!isQualifiedDictionaryGroup(dictionaryOrGroup)) {\n return dictionaryOrGroup;\n }\n\n const { qualifierTypes, content } = dictionaryOrGroup;\n\n const itemAxisOpen =\n qualifierTypes.includes('item') && selector?.item === undefined;\n\n const compositeIds = Object.keys(content);\n const variantIndex = qualifierTypes.indexOf('variant');\n\n const effectiveVariantId =\n variantIndex === -1\n ? DEFAULT_VARIANT_ID\n : resolveEffectiveVariantId(\n serializeVariantChain(selector?.variant),\n (variantId) =>\n compositeIds.some(\n (compositeId) =>\n compositeId.split(COMPOSITE_ID_SEPARATOR)[variantIndex] ===\n variantId\n )\n );\n\n const matchedEntries = compositeIds\n .filter((compositeId) =>\n compositeIdMatchesSelector(\n compositeId,\n qualifierTypes,\n selector,\n effectiveVariantId\n )\n )\n .map((compositeId) =>\n reconstructQualifiedEntry(dictionaryOrGroup, compositeId)\n );\n\n if (itemAxisOpen) {\n return matchedEntries.sort(\n (left, right) => (left.item ?? 0) - (right.item ?? 0)\n );\n }\n\n return matchedEntries[0] ?? null;\n};\n\n/**\n * Splits the second argument of `getIntlayer` / `getDictionary` into the\n * effective locale and the selector object (if any).\n */\nexport const parseDictionarySelector = <L extends LocalesValues>(\n localeOrSelector?: L | DictionarySelector\n): { locale?: L; selector?: DictionarySelector } => {\n if (typeof localeOrSelector === 'object' && localeOrSelector !== null) {\n return {\n locale: localeOrSelector.locale as L | undefined,\n selector: localeOrSelector,\n };\n }\n\n return { locale: localeOrSelector as L | undefined };\n};\n\n/**\n * Resolves the variant a provider pins for one dictionary key.\n *\n * A string or a chain applies to every key as-is. A plain object is the per-key\n * map: the entry for `dictionaryKey` wins, falling back to the reserved\n * `default` entry, and `undefined` when neither is present (the key then\n * resolves to its own `default` variant, i.e. the behaviour without a provider\n * variant at all).\n *\n * A plain object is **always** the map here — never a structured variant value,\n * which is why a structured variant has to be nested (`{ default: { id } }`).\n *\n * @param providerVariant - The `variant` prop of the surrounding provider.\n * @param dictionaryKey - The key being read.\n */\nexport const resolveProviderVariant = (\n providerVariant: ProviderVariantBase | undefined,\n dictionaryKey: string\n): DictionaryVariantChain | undefined => {\n if (providerVariant === undefined) return undefined;\n\n if (typeof providerVariant === 'string' || Array.isArray(providerVariant)) {\n return providerVariant as DictionaryVariantChain;\n }\n\n const variantMap = providerVariant as ProviderVariantMap;\n\n return variantMap[dictionaryKey] ?? variantMap[DEFAULT_VARIANT_ID];\n};\n\n/**\n * Builds the effective second argument of a dictionary read by layering the\n * provider defaults under the call-site one — the single place the `locale` and\n * `variant` context defaults are applied, shared by every framework binding.\n *\n * Precedence, per dimension independently:\n * - a call-site selector always wins; `{ variant: 'x' }` **replaces** the\n * provider chain rather than extending it\n * - otherwise the provider value applies\n *\n * Returns a bare locale (not a selector object) whenever no variant is in play,\n * so the existing fast path — and the cache keys built from it — are unchanged\n * for projects that never use variants.\n */\nexport const resolveDictionaryArgument = (params: {\n localeOrSelector?: LocalesValues | DictionarySelector;\n contextLocale?: LocalesValues;\n contextVariant?: ProviderVariantBase;\n dictionaryKey: string;\n}): LocalesValues | DictionarySelector | undefined => {\n const { localeOrSelector, contextLocale, contextVariant, dictionaryKey } =\n params;\n\n const callSelector =\n typeof localeOrSelector === 'object' && localeOrSelector !== null\n ? localeOrSelector\n : undefined;\n\n const callLocale = callSelector\n ? callSelector.locale\n : (localeOrSelector as LocalesValues | undefined);\n\n // The context locale is typed as widely as the runtime allows, while a\n // selector narrows `locale` to the declared ones — the value is the same.\n const locale = (callLocale ?? contextLocale) as DictionarySelector['locale'];\n\n // A call-site variant is authoritative; the provider only fills the gap.\n const variant =\n callSelector?.variant ??\n resolveProviderVariant(contextVariant, dictionaryKey);\n\n if (variant === undefined) {\n // Nothing to add: keep the argument in its original shape so the identity\n // built from it stays byte-identical to the pre-variant behaviour.\n return callSelector\n ? { ...callSelector, locale }\n : (locale as LocalesValues | undefined);\n }\n\n return { ...callSelector, locale, variant };\n};\n\n/**\n * Builds a stable string identity of a selector (excluding `locale`), suitable\n * for cache keys and memoization dependencies.\n */\nexport const getDictionarySelectorCacheKey = (\n selector?: DictionarySelector\n): string => {\n if (!selector) return '';\n\n return Object.keys(selector)\n .filter((selectorKey) => selectorKey !== 'locale')\n .sort()\n .map((selectorKey) => {\n const value = selector[selectorKey as keyof DictionarySelector];\n const serialized =\n selectorKey === 'variant'\n ? serializeVariantChain(\n value as DictionaryVariantChain | undefined\n ).join(',')\n : String(value);\n return `${selectorKey}:${serialized}`;\n })\n .join('|');\n};\n"],"mappings":"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"}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -112,11 +112,13 @@ const require_messageFormat_navigatePath = require('./messageFormat/navigatePath
|
|
|
112
112
|
const require_messageFormat_po = require('./messageFormat/po.cjs');
|
|
113
113
|
const require_messageFormat_vue_i18n = require('./messageFormat/vue-i18n.cjs');
|
|
114
114
|
const require_messageFormat_resolveMessage = require('./messageFormat/resolveMessage.cjs');
|
|
115
|
+
const require_utils_intlayerNodePrototype = require('./utils/intlayerNodePrototype.cjs');
|
|
115
116
|
const require_utils_isSameKeyPath = require('./utils/isSameKeyPath.cjs');
|
|
116
117
|
const require_utils_stringifyYaml = require('./utils/stringifyYaml.cjs');
|
|
117
118
|
let _intlayer_config_defaultValues = require("@intlayer/config/defaultValues");
|
|
118
119
|
|
|
119
120
|
exports.ATTRIBUTES_TO_SANITIZE = require_markdown_constants.ATTRIBUTES_TO_SANITIZE;
|
|
121
|
+
exports.ATTRIBUTE_NAME_START_R = require_markdown_constants.ATTRIBUTE_NAME_START_R;
|
|
120
122
|
exports.ATTRIBUTE_TO_NODE_PROP_MAP = require_markdown_constants.ATTRIBUTE_TO_NODE_PROP_MAP;
|
|
121
123
|
exports.ATTR_EXTRACTOR_R = require_markdown_constants.ATTR_EXTRACTOR_R;
|
|
122
124
|
exports.BLOCKQUOTE_ALERT_R = require_markdown_constants.BLOCKQUOTE_ALERT_R;
|
|
@@ -245,6 +247,7 @@ exports.get = require_markdown_utils.get;
|
|
|
245
247
|
exports.getBasePlugins = require_interpreter_getContent_getContent.getBasePlugins;
|
|
246
248
|
exports.getBrowserLocale = require_localization_getBrowserLocale.getBrowserLocale;
|
|
247
249
|
exports.getCachedIntl = require_utils_intl.getCachedIntl;
|
|
250
|
+
exports.getCachedLocaleFromStorageClient = require_utils_localeStorage.getCachedLocaleFromStorageClient;
|
|
248
251
|
exports.getCanonicalPath = require_localization_getCanonicalPath.getCanonicalPath;
|
|
249
252
|
exports.getCondition = require_interpreter_getCondition.getCondition;
|
|
250
253
|
exports.getContent = require_interpreter_getContent_getContent.getContent;
|
|
@@ -279,6 +282,7 @@ exports.getInternalPath = require_localization_rewriteUtils.getInternalPath;
|
|
|
279
282
|
exports.getInterpolableContent = require_interpreter_interpolableNode.getInterpolableContent;
|
|
280
283
|
exports.getIntlayer = require_interpreter_getIntlayer.getIntlayer;
|
|
281
284
|
exports.getIntlayerAsync = require_interpreter_getIntlayerAsync.getIntlayerAsync;
|
|
285
|
+
exports.getIntlayerNodePrototype = require_utils_intlayerNodePrototype.getIntlayerNodePrototype;
|
|
282
286
|
exports.getLocale = require_localization_getLocale.getLocale;
|
|
283
287
|
exports.getLocaleFromDomain = require_localization_domainUtils.getLocaleFromDomain;
|
|
284
288
|
exports.getLocaleFromPath = require_localization_getLocaleFromPath.getLocaleFromPath;
|
|
@@ -4,45 +4,40 @@ let _intlayer_types_nodeType = require("@intlayer/types/nodeType");
|
|
|
4
4
|
_intlayer_types_nodeType = require_runtime.__toESM(_intlayer_types_nodeType);
|
|
5
5
|
|
|
6
6
|
//#region src/interpreter/getContent/deepTransform.ts
|
|
7
|
+
/** Props of a child node: same context, one more key path segment. */
|
|
8
|
+
const getChildProps = (props, children, keyPathSegment) => ({
|
|
9
|
+
...props,
|
|
10
|
+
children,
|
|
11
|
+
keyPath: [...props.keyPath, keyPathSegment]
|
|
12
|
+
});
|
|
7
13
|
/**
|
|
8
14
|
* Recursively traverses a node (object/array/primitive).
|
|
9
15
|
* Applies the *first* plugin that can transform a node, then stops descending further.
|
|
10
16
|
* If no plugin transforms it, it recurses into its children.
|
|
11
17
|
*/
|
|
12
18
|
const deepTransformNode = (node, props) => {
|
|
13
|
-
for (const plugin of props.plugins ?? []) if (plugin.canHandle(node)) return plugin.transform(node, props,
|
|
19
|
+
for (const plugin of props.plugins ?? []) if (plugin.canHandle(node)) return plugin.transform(node, props, deepTransformNode);
|
|
14
20
|
if (node === null || typeof node !== "object") return node;
|
|
15
|
-
if (node.$$typeof !== void 0 || node.__v_isVNode !== void 0 || node._isVNode !== void 0 || node.isJSX !== void 0
|
|
16
|
-
if (Array.isArray(node)) return node.map((child, index) => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
keyPath: [...props.keyPath, {
|
|
21
|
-
type: _intlayer_types_nodeType.ARRAY,
|
|
22
|
-
key: index
|
|
23
|
-
}]
|
|
24
|
-
};
|
|
25
|
-
return deepTransformNode(child, childProps);
|
|
26
|
-
});
|
|
21
|
+
if (node.$$typeof !== void 0 || node.__v_isVNode !== void 0 || node._isVNode !== void 0 || node.isJSX !== void 0) return node;
|
|
22
|
+
if (Array.isArray(node)) return node.map((child, index) => deepTransformNode(child, getChildProps(props, child, {
|
|
23
|
+
type: _intlayer_types_nodeType.ARRAY,
|
|
24
|
+
key: index
|
|
25
|
+
})));
|
|
27
26
|
const result = {};
|
|
28
27
|
for (const key in node) {
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
keyPath: [...props.keyPath, {
|
|
33
|
-
type: _intlayer_types_nodeType.OBJECT,
|
|
34
|
-
key
|
|
35
|
-
}]
|
|
28
|
+
const keyPathSegment = {
|
|
29
|
+
type: _intlayer_types_nodeType.OBJECT,
|
|
30
|
+
key
|
|
36
31
|
};
|
|
37
32
|
if (props.eager) {
|
|
38
|
-
result[key] = deepTransformNode(node[key],
|
|
33
|
+
result[key] = deepTransformNode(node[key], getChildProps(props, node[key], keyPathSegment));
|
|
39
34
|
continue;
|
|
40
35
|
}
|
|
41
36
|
Object.defineProperty(result, key, {
|
|
42
37
|
enumerable: true,
|
|
43
38
|
configurable: true,
|
|
44
39
|
get: function() {
|
|
45
|
-
const transformed = deepTransformNode(node[key],
|
|
40
|
+
const transformed = deepTransformNode(node[key], getChildProps(props, node[key], keyPathSegment));
|
|
46
41
|
Object.defineProperty(this, key, {
|
|
47
42
|
value: transformed,
|
|
48
43
|
enumerable: true,
|
|
@@ -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
|
|
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/** Props of a child node: same context, one more key path segment. */\nconst getChildProps = (\n props: NodeProps,\n children: unknown,\n keyPathSegment: KeyPath\n): NodeProps => ({\n ...props,\n children,\n keyPath: [...props.keyPath, keyPathSegment],\n});\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 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, deepTransformNode);\n }\n }\n\n // Primitives, and functions such as html/markdown node renderers\n if (node === null || typeof node !== 'object') {\n return node;\n }\n\n // Framework virtual nodes and already-transformed nodes are final\n if (\n node.$$typeof !== undefined ||\n node.__v_isVNode !== undefined ||\n node._isVNode !== undefined ||\n node.isJSX !== undefined\n ) {\n return node;\n }\n\n if (Array.isArray(node)) {\n return node.map((child, index) =>\n deepTransformNode(\n child,\n getChildProps(props, child, {\n type: NodeTypes.ARRAY,\n key: index,\n } as KeyPath)\n )\n );\n }\n\n const result: Record<string, any> = {};\n\n for (const key in node) {\n const keyPathSegment = { type: NodeTypes.OBJECT, key } as KeyPath;\n\n if (props.eager) {\n result[key] = deepTransformNode(\n node[key],\n getChildProps(props, node[key], keyPathSegment)\n );\n continue;\n }\n\n // Lazy mode: transform on first read, then memoize onto the property\n Object.defineProperty(result, key, {\n enumerable: true,\n configurable: true,\n get: function () {\n const transformed = deepTransformNode(\n node[key],\n getChildProps(props, node[key], keyPathSegment)\n );\n\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":";;;;;;;AAKA,MAAM,iBACJ,OACA,UACA,oBACe;CACf,GAAG;CACH;CACA,SAAS,CAAC,GAAG,MAAM,SAAS,cAAc;AAC5C;;;;;;AAOA,MAAa,qBAAqB,MAAW,UAA0B;CACrE,KAAK,MAAM,UAAU,MAAM,WAAW,CAAC,GACrC,IAAI,OAAO,UAAU,IAAI,GAEvB,OAAO,OAAO,UAAU,MAAM,OAAO,iBAAiB;CAK1D,IAAI,SAAS,QAAQ,OAAO,SAAS,UACnC,OAAO;CAIT,IACE,KAAK,aAAa,UAClB,KAAK,gBAAgB,UACrB,KAAK,aAAa,UAClB,KAAK,UAAU,QAEf,OAAO;CAGT,IAAI,MAAM,QAAQ,IAAI,GACpB,OAAO,KAAK,KAAK,OAAO,UACtB,kBACE,OACA,cAAc,OAAO,OAAO;EAC1B,MAAMA,yBAAU;EAChB,KAAK;CACP,CAAY,CACd,CACF;CAGF,MAAM,SAA8B,CAAC;CAErC,KAAK,MAAM,OAAO,MAAM;EACtB,MAAM,iBAAiB;GAAE,MAAMA,yBAAU;GAAQ;EAAI;EAErD,IAAI,MAAM,OAAO;GACf,OAAO,OAAO,kBACZ,KAAK,MACL,cAAc,OAAO,KAAK,MAAM,cAAc,CAChD;GACA;EACF;EAGA,OAAO,eAAe,QAAQ,KAAK;GACjC,YAAY;GACZ,cAAc;GACd,KAAK,WAAY;IACf,MAAM,cAAc,kBAClB,KAAK,MACL,cAAc,OAAO,KAAK,MAAM,cAAc,CAChD;IAEA,OAAO,eAAe,MAAM,KAAK;KAC/B,OAAO;KACP,YAAY;KACZ,cAAc;IAChB,CAAC;IACD,OAAO;GACT;EACF,CAAC;CACH;CAEA,OAAO;AACT"}
|
|
@@ -14,7 +14,7 @@ const getBasePlugins = (locale, fallback = true) => [
|
|
|
14
14
|
require_interpreter_getContent_plugins.filePlugin,
|
|
15
15
|
require_interpreter_getContent_plugins.genderPlugin,
|
|
16
16
|
require_interpreter_getContent_plugins.selectPlugin
|
|
17
|
-
];
|
|
17
|
+
].filter((plugin) => plugin !== require_interpreter_getContent_plugins.fallbackPlugin);
|
|
18
18
|
/**
|
|
19
19
|
* Transforms a node in a single pass, applying each plugin as needed.
|
|
20
20
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getContent.cjs","names":["translationPlugin","internationalization","enumerationPlugin","pluralPlugin","conditionPlugin","insertionPlugin","nestedPlugin","filePlugin","genderPlugin","selectPlugin","deepTransformNode"],"sources":["../../../../src/interpreter/getContent/getContent.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type { ContentNode } from '@intlayer/types/dictionary';\nimport type {\n DeclaredLocales,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport { deepTransformNode } from './deepTransform';\nimport {\n conditionPlugin,\n type DeepTransformContent,\n enumerationPlugin,\n filePlugin,\n genderPlugin,\n type IInterpreterPluginState,\n insertionPlugin,\n type NodeProps,\n nestedPlugin,\n type Plugins,\n pluralPlugin,\n selectPlugin,\n translationPlugin,\n} from './plugins';\n\nexport const getBasePlugins = (\n locale?: LocalesValues,\n fallback: boolean = true\n): Plugins[] =>\n [\n translationPlugin(\n locale ?? internationalization.defaultLocale,\n fallback ? internationalization.defaultLocale : undefined\n ),\n enumerationPlugin,\n pluralPlugin(locale ?? internationalization.defaultLocale),\n conditionPlugin,\n insertionPlugin,\n nestedPlugin(locale ?? internationalization.defaultLocale),\n filePlugin,\n genderPlugin,\n selectPlugin,\n ] as Plugins[];\n\n/**\n * Transforms a node in a single pass, applying each plugin as needed.\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 getContent = <\n const T extends ContentNode,\n const L extends LocalesValues = DeclaredLocales,\n>(\n node: T,\n nodeProps: NodeProps,\n plugins: Plugins[] = []\n) =>\n deepTransformNode(node, {\n ...nodeProps,\n plugins,\n }) as DeepTransformContent<T, IInterpreterPluginState, L>;\n"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"getContent.cjs","names":["translationPlugin","internationalization","enumerationPlugin","pluralPlugin","conditionPlugin","insertionPlugin","nestedPlugin","filePlugin","genderPlugin","selectPlugin","fallbackPlugin","deepTransformNode"],"sources":["../../../../src/interpreter/getContent/getContent.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport type { ContentNode } from '@intlayer/types/dictionary';\nimport type {\n DeclaredLocales,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport { deepTransformNode } from './deepTransform';\nimport {\n conditionPlugin,\n type DeepTransformContent,\n enumerationPlugin,\n fallbackPlugin,\n filePlugin,\n genderPlugin,\n type IInterpreterPluginState,\n insertionPlugin,\n type NodeProps,\n nestedPlugin,\n type Plugins,\n pluralPlugin,\n selectPlugin,\n translationPlugin,\n} from './plugins';\n\nexport const getBasePlugins = (\n locale?: LocalesValues,\n fallback: boolean = true\n): Plugins[] =>\n [\n translationPlugin(\n locale ?? internationalization.defaultLocale,\n fallback ? internationalization.defaultLocale : undefined\n ),\n enumerationPlugin,\n pluralPlugin(locale ?? internationalization.defaultLocale),\n conditionPlugin,\n insertionPlugin,\n nestedPlugin(locale ?? internationalization.defaultLocale),\n filePlugin,\n genderPlugin,\n selectPlugin,\n ].filter(\n // Plugins disabled at build time never match: skip them on every node\n (plugin) => plugin !== fallbackPlugin\n ) as Plugins[];\n\n/**\n * Transforms a node in a single pass, applying each plugin as needed.\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 getContent = <\n const T extends ContentNode,\n const L extends LocalesValues = DeclaredLocales,\n>(\n node: T,\n nodeProps: NodeProps,\n plugins: Plugins[] = []\n) =>\n deepTransformNode(node, {\n ...nodeProps,\n plugins,\n }) as DeepTransformContent<T, IInterpreterPluginState, L>;\n"],"mappings":";;;;;;AAwBA,MAAa,kBACX,QACA,WAAoB,SAEpB;CACEA,yDACE,UAAUC,4CAAqB,eAC/B,WAAWA,4CAAqB,gBAAgB,MAClD;CACAC;CACAC,oDAAa,UAAUF,4CAAqB,aAAa;CACzDG;CACAC;CACAC,oDAAa,UAAUL,4CAAqB,aAAa;CACzDM;CACAC;CACAC;AACF,CAAC,CAAC,QAEC,WAAW,WAAWC,qDACzB;;;;;;;AAQF,MAAa,cAIX,MACA,WACA,UAAqB,CAAC,MAEtBC,+DAAkB,MAAM;CACtB,GAAG;CACH;AACF,CAAC"}
|
|
@@ -24,25 +24,33 @@ const fallbackPlugin = {
|
|
|
24
24
|
canHandle: () => false,
|
|
25
25
|
transform: (node) => node
|
|
26
26
|
};
|
|
27
|
+
/**
|
|
28
|
+
* Whether a resolved branch still expects insertion values.
|
|
29
|
+
*
|
|
30
|
+
* Some renderers return callable nodes (Svelte components, Angular proxies)
|
|
31
|
+
* exposing their content on `.value`: those are final and must not be called
|
|
32
|
+
* with the values. A pending insertion either has no `.value` or a function
|
|
33
|
+
* one.
|
|
34
|
+
*/
|
|
35
|
+
const isAwaitingValues = (branch) => {
|
|
36
|
+
if (typeof branch !== "function") return false;
|
|
37
|
+
const { value } = branch;
|
|
38
|
+
return value === void 0 || typeof value === "function";
|
|
39
|
+
};
|
|
27
40
|
/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */
|
|
28
41
|
const translationPlugin = (locale, fallback) => process.env.INTLAYER_NODE_TYPE_TRANSLATION === "false" ? fallbackPlugin : {
|
|
29
42
|
id: "translation-plugin",
|
|
30
43
|
canHandle: (node) => typeof node === "object" && node?.nodeType === _intlayer_types_nodeType.TRANSLATION,
|
|
31
44
|
transform: (node, props, deepTransformNode) => {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}]
|
|
42
|
-
};
|
|
43
|
-
result[key] = deepTransformNode(original[key], childProps);
|
|
44
|
-
}
|
|
45
|
-
return require_interpreter_getTranslation.getTranslation(result, locale, fallback);
|
|
45
|
+
const content = require_interpreter_getTranslation.getTranslation(node[_intlayer_types_nodeType.TRANSLATION] ?? {}, locale, fallback);
|
|
46
|
+
return deepTransformNode(content, {
|
|
47
|
+
...props,
|
|
48
|
+
children: content,
|
|
49
|
+
keyPath: [...props.keyPath, {
|
|
50
|
+
type: _intlayer_types_nodeType.TRANSLATION,
|
|
51
|
+
key: locale
|
|
52
|
+
}]
|
|
53
|
+
});
|
|
46
54
|
}
|
|
47
55
|
};
|
|
48
56
|
/** Enumeration plugin. Replaces node with a function that takes quantity => string. */
|
|
@@ -66,7 +74,7 @@ const enumerationPlugin = process.env.INTLAYER_NODE_TYPE_ENUMERATION === "false"
|
|
|
66
74
|
return (arg) => {
|
|
67
75
|
const quantity = typeof arg === "number" ? arg : arg.count;
|
|
68
76
|
const subResult = require_interpreter_getEnumeration.getEnumeration(result, quantity);
|
|
69
|
-
if (
|
|
77
|
+
if (isAwaitingValues(subResult) && typeof arg === "object") return subResult(arg);
|
|
70
78
|
return subResult;
|
|
71
79
|
};
|
|
72
80
|
}
|
|
@@ -125,7 +133,7 @@ const pluralPlugin = (locale) => process.env.INTLAYER_NODE_TYPE_PLURAL === "fals
|
|
|
125
133
|
const count = typeof arg === "number" ? arg : arg.count;
|
|
126
134
|
const values = typeof arg === "number" ? { count: arg } : arg;
|
|
127
135
|
const subResult = require_interpreter_getPlural.getPlural(result, count, effectiveLocale);
|
|
128
|
-
if (
|
|
136
|
+
if (isAwaitingValues(subResult)) return subResult(values);
|
|
129
137
|
return subResult;
|
|
130
138
|
};
|
|
131
139
|
}
|
|
@@ -151,7 +159,7 @@ const conditionPlugin = process.env.INTLAYER_NODE_TYPE_CONDITION === "false" ? f
|
|
|
151
159
|
return (arg) => {
|
|
152
160
|
const value = typeof arg === "boolean" ? arg : arg.value;
|
|
153
161
|
const subResult = require_interpreter_getCondition.getCondition(result, value);
|
|
154
|
-
if (
|
|
162
|
+
if (isAwaitingValues(subResult) && typeof arg === "object") return subResult(arg);
|
|
155
163
|
return subResult;
|
|
156
164
|
};
|
|
157
165
|
}
|
|
@@ -212,27 +220,18 @@ const selectorNodeTypes = [
|
|
|
212
220
|
const bindInsertedValues = (children, result, values, areBranchesInterpolated = false) => {
|
|
213
221
|
const nodeType = children?.nodeType;
|
|
214
222
|
if (typeof result !== "function" || !nodeType || !selectorNodeTypes.includes(nodeType)) return result;
|
|
215
|
-
const
|
|
216
|
-
const isEnumeration = nodeType === _intlayer_types_nodeType.ENUMERATION;
|
|
223
|
+
const isCountSelector = nodeType === _intlayer_types_nodeType.PLURAL || nodeType === _intlayer_types_nodeType.ENUMERATION;
|
|
217
224
|
return (selector) => {
|
|
218
225
|
if (typeof selector === "object" && selector !== null) return result({
|
|
219
226
|
...values,
|
|
220
227
|
...selector
|
|
221
228
|
});
|
|
222
|
-
if (
|
|
229
|
+
if (isCountSelector) return result({
|
|
223
230
|
...values,
|
|
224
231
|
count: selector
|
|
225
232
|
});
|
|
226
|
-
if (isEnumeration && typeof selector === "number") {
|
|
227
|
-
const mergedValues = {
|
|
228
|
-
count: selector,
|
|
229
|
-
...values
|
|
230
|
-
};
|
|
231
|
-
const selected = result(mergedValues);
|
|
232
|
-
return !areBranchesInterpolated && typeof selected === "function" ? selected(mergedValues) : selected;
|
|
233
|
-
}
|
|
234
233
|
const selected = result(selector);
|
|
235
|
-
return !areBranchesInterpolated &&
|
|
234
|
+
return !areBranchesInterpolated && isAwaitingValues(selected) ? selected(values) : selected;
|
|
236
235
|
};
|
|
237
236
|
};
|
|
238
237
|
/**
|
|
@@ -283,7 +282,7 @@ const selectPlugin = process.env.INTLAYER_NODE_TYPE_SELECT === "false" ? fallbac
|
|
|
283
282
|
return (arg) => {
|
|
284
283
|
const value = typeof arg === "string" ? arg : arg?.value;
|
|
285
284
|
const subResult = require_interpreter_getSelect.getSelect(result, value);
|
|
286
|
-
if (
|
|
285
|
+
if (isAwaitingValues(subResult) && typeof arg === "object") return subResult(arg);
|
|
287
286
|
return subResult;
|
|
288
287
|
};
|
|
289
288
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.cjs","names":["NodeTypes","getTranslation","getEnumeration","isInterpolableWrapperNode","transformInterpolableNode","getInsertion","getPlural","getCondition","getGender","getSelect","getNestingOptimized","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 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\n/**\n * A plural branch wrapped in an `insertion` node (auto-transformed\n * `{{count}}`) resolves to its inner content: the plural applies the values.\n */\ntype PluralBranch<Branch> = Branch extends {\n nodeType: NodeType | string;\n [NodeTypes.INSERTION]: infer InsertionContent;\n fields: readonly string[];\n}\n ? InsertionContent\n : Branch;\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 PluralBranch<\n T[typeof NodeTypes.PLURAL][keyof T[typeof NodeTypes.PLURAL]]\n >,\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 // The plural interpolates its own branches. A string plugin from an\n // enclosing `insert()` would turn them into functions first.\n const branchPlugins = (props.plugins ?? []).filter(\n (plugin) => plugin.id !== 'insertion-string-plugin'\n );\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 // An `insertion` node below the plural (e.g. auto-transformed\n // `{{count}}` branches) already returns `(values) => …`. Leave its\n // strings untouched, or its template would become a function.\n const isInsideInsertion = subProps.keyPath\n .slice(props.keyPath.length)\n .some((keyPath) => keyPath.type === NodeTypes.INSERTION);\n\n if (isInsideInsertion) {\n return deepTransformNode(node, {\n ...subProps,\n plugins: subProps.plugins?.filter(\n (plugin) => plugin.id !== 'plural-string-plugin'\n ),\n });\n }\n\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 branchPlugins,\n deepTransformNode\n );\n }\n\n const transformedResult = deepTransformNode(node, {\n ...subProps,\n children: node,\n plugins: [\n ...branchPlugins.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: branchPlugins,\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, ...branchPlugins],\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 const result = deepTransformNode(children, {\n ...props,\n children,\n keyPath: newKeyPath,\n plugins: [insertionStringPlugin, ...(props.plugins ?? [])],\n });\n\n return resolveInsertedSelector(children, result);\n },\n };\n\n/** Container nodes resolved by a selector call: `enu(3)`, `cond(true)`, … */\nconst selectorNodeTypes: string[] = [\n NodeTypes.ENUMERATION,\n NodeTypes.CONDITION,\n NodeTypes.PLURAL,\n NodeTypes.GENDER,\n NodeTypes.SELECT,\n];\n\n/**\n * Binds the values of an `insert()` to the selector node it wraps, returning\n * `(selector) => content`. Any other child result is returned unchanged.\n *\n * `areBranchesInterpolated` is set by frameworks that interpolate the branch\n * strings as soon as the values are known: the selected branch is then final\n * content and is never called with the values.\n */\nexport const bindInsertedValues = (\n children: unknown,\n result: unknown,\n values: Record<string, unknown>,\n areBranchesInterpolated = false\n): unknown => {\n const nodeType = (children as { nodeType?: string })?.nodeType;\n if (\n typeof result !== 'function' ||\n !nodeType ||\n !selectorNodeTypes.includes(nodeType)\n ) {\n return result;\n }\n\n const isPlural = nodeType === NodeTypes.PLURAL;\n const isEnumeration = nodeType === NodeTypes.ENUMERATION;\n\n return (selector: unknown) => {\n // Object selectors (`{ count }`, `{ value }`) carry the values along.\n if (typeof selector === 'object' && selector !== null) {\n return result({ ...values, ...selector });\n }\n\n // Plural interpolates its own branches, `{{count}}` included.\n if (isPlural) {\n return result({ ...values, count: selector });\n }\n\n // Enumeration selector is a numeric count (or count range)\n if (isEnumeration && typeof selector === 'number') {\n const mergedValues = { count: selector, ...values };\n const selected = result(mergedValues);\n\n return !areBranchesInterpolated && typeof selected === 'function'\n ? selected(mergedValues)\n : selected;\n }\n\n const selected = result(selector);\n\n return !areBranchesInterpolated && typeof selected === 'function'\n ? selected(values)\n : selected;\n };\n};\n\n/**\n * Shapes the result of `insert()` wrapping a selector node as\n * `(values) => (selector) => content`, so the values reach the selected\n * branch. Any other child result is returned unchanged.\n */\nexport const resolveInsertedSelector = (\n children: unknown,\n result: unknown\n): unknown =>\n typeof result === 'function' &&\n selectorNodeTypes.includes(\n (children as { nodeType?: string })?.nodeType ?? ''\n )\n ? (values: Record<string, unknown>) =>\n bindInsertedValues(children, result, values)\n : result;\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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"}
|
|
1
|
+
{"version":3,"file":"plugins.cjs","names":["NodeTypes","getTranslation","getEnumeration","isInterpolableWrapperNode","transformInterpolableNode","getInsertion","getPlural","getCondition","getGender","getSelect","getNestingOptimized","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 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 * Whether a resolved branch still expects insertion values.\n *\n * Some renderers return callable nodes (Svelte components, Angular proxies)\n * exposing their content on `.value`: those are final and must not be called\n * with the values. A pending insertion either has no `.value` or a function\n * one.\n */\nconst isAwaitingValues = (\n branch: unknown\n): branch is (values: Record<string, unknown>) => unknown => {\n if (typeof branch !== 'function') return false;\n\n const { value } = branch as { value?: unknown };\n\n return value === undefined || typeof value === 'function';\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 // Resolve on the raw content first: only the displayed locale (and\n // the fallback keys it lacks) is ever transformed\n const content = getTranslation(\n node[NodeTypes.TRANSLATION] ?? {},\n locale,\n fallback\n );\n\n return deepTransformNode(content, {\n ...props,\n children: content,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.TRANSLATION, key: locale } as KeyPath,\n ],\n });\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 (isAwaitingValues(subResult) && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * PLURAL PLUGIN\n * --------------------------------------------- */\n\n/**\n * A plural branch wrapped in an `insertion` node (auto-transformed\n * `{{count}}`) resolves to its inner content: the plural applies the values.\n */\ntype PluralBranch<Branch> = Branch extends {\n nodeType: NodeType | string;\n [NodeTypes.INSERTION]: infer InsertionContent;\n fields: readonly string[];\n}\n ? InsertionContent\n : Branch;\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 PluralBranch<\n T[typeof NodeTypes.PLURAL][keyof T[typeof NodeTypes.PLURAL]]\n >,\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 // The plural interpolates its own branches. A string plugin from an\n // enclosing `insert()` would turn them into functions first.\n const branchPlugins = (props.plugins ?? []).filter(\n (plugin) => plugin.id !== 'insertion-string-plugin'\n );\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 // An `insertion` node below the plural (e.g. auto-transformed\n // `{{count}}` branches) already returns `(values) => …`. Leave its\n // strings untouched, or its template would become a function.\n const isInsideInsertion = subProps.keyPath\n .slice(props.keyPath.length)\n .some((keyPath) => keyPath.type === NodeTypes.INSERTION);\n\n if (isInsideInsertion) {\n return deepTransformNode(node, {\n ...subProps,\n plugins: subProps.plugins?.filter(\n (plugin) => plugin.id !== 'plural-string-plugin'\n ),\n });\n }\n\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 branchPlugins,\n deepTransformNode\n );\n }\n\n const transformedResult = deepTransformNode(node, {\n ...subProps,\n children: node,\n plugins: [\n ...branchPlugins.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: branchPlugins,\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, ...branchPlugins],\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 (isAwaitingValues(subResult)) {\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 (isAwaitingValues(subResult) && 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 const result = deepTransformNode(children, {\n ...props,\n children,\n keyPath: newKeyPath,\n plugins: [insertionStringPlugin, ...(props.plugins ?? [])],\n });\n\n return resolveInsertedSelector(children, result);\n },\n };\n\n/** Container nodes resolved by a selector call: `enu(3)`, `cond(true)`, … */\nconst selectorNodeTypes: string[] = [\n NodeTypes.ENUMERATION,\n NodeTypes.CONDITION,\n NodeTypes.PLURAL,\n NodeTypes.GENDER,\n NodeTypes.SELECT,\n];\n\n/**\n * Binds the values of an `insert()` to the selector node it wraps, returning\n * `(selector) => content`. Any other child result is returned unchanged.\n *\n * `areBranchesInterpolated` is set by frameworks that interpolate the branch\n * strings as soon as the values are known: the selected branch is then final\n * content and is never called with the values.\n */\nexport const bindInsertedValues = (\n children: unknown,\n result: unknown,\n values: Record<string, unknown>,\n areBranchesInterpolated = false\n): unknown => {\n const nodeType = (children as { nodeType?: string })?.nodeType;\n if (\n typeof result !== 'function' ||\n !nodeType ||\n !selectorNodeTypes.includes(nodeType)\n ) {\n return result;\n }\n\n const isCountSelector =\n nodeType === NodeTypes.PLURAL || nodeType === NodeTypes.ENUMERATION;\n\n return (selector: unknown) => {\n // Object selectors (`{ count }`, `{ value }`) carry the values along.\n if (typeof selector === 'object' && selector !== null) {\n return result({ ...values, ...selector });\n }\n\n // The count both selects the branch and fills `{{count}}`: the selector\n // wins over a `count` passed with the values.\n if (isCountSelector) {\n return result({ ...values, count: selector });\n }\n\n const selected = result(selector);\n\n return !areBranchesInterpolated && isAwaitingValues(selected)\n ? selected(values)\n : selected;\n };\n};\n\n/**\n * Shapes the result of `insert()` wrapping a selector node as\n * `(values) => (selector) => content`, so the values reach the selected\n * branch. Any other child result is returned unchanged.\n */\nexport const resolveInsertedSelector = (\n children: unknown,\n result: unknown\n): unknown =>\n typeof result === 'function' &&\n selectorNodeTypes.includes(\n (children as { nodeType?: string })?.nodeType ?? ''\n )\n ? (values: Record<string, unknown>) =>\n bindInsertedValues(children, result, values)\n : result;\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 (isAwaitingValues(subResult) && 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), or when most\n * of the content is read anyway: defining a getter per key, then redefining\n * it on first read, costs more than transforming the key outright.\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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"}
|
|
@@ -6,6 +6,12 @@ let _intlayer_config_built = require("@intlayer/config/built");
|
|
|
6
6
|
|
|
7
7
|
//#region src/interpreter/getDictionary.ts
|
|
8
8
|
/**
|
|
9
|
+
* Dictionaries whose transform is running. Content is transformed eagerly, so a
|
|
10
|
+
* dictionary reached again through a `nest()` cycle is transformed lazily
|
|
11
|
+
* instead: its nodes then resolve on read, and the cycle unwinds.
|
|
12
|
+
*/
|
|
13
|
+
const transformsInProgress = /* @__PURE__ */ new WeakSet();
|
|
14
|
+
/**
|
|
9
15
|
* Transforms a dictionary in a single pass, applying each plugin as needed.
|
|
10
16
|
*
|
|
11
17
|
* @param dictionary The dictionary (or qualified dictionary group) to transform.
|
|
@@ -15,21 +21,30 @@ let _intlayer_config_built = require("@intlayer/config/built");
|
|
|
15
21
|
* If omitted, we’ll use a default set of plugins.
|
|
16
22
|
*/
|
|
17
23
|
const getDictionary = (dictionary, localeOrSelector, plugins) => {
|
|
18
|
-
const { locale, selector } = require_dictionaryManipulator_qualifiedDictionary.parseDictionarySelector(localeOrSelector)
|
|
19
|
-
|
|
24
|
+
const { locale, selector } = process.env.INTLAYER_DICTIONARY_SELECTOR !== "false" ? require_dictionaryManipulator_qualifiedDictionary.parseDictionarySelector(localeOrSelector) : {
|
|
25
|
+
locale: localeOrSelector,
|
|
26
|
+
selector: void 0
|
|
27
|
+
};
|
|
28
|
+
const cacheKey = require_interpreter_dictionaryTransformCache.getDictionaryTransformCacheKey(locale ?? _intlayer_config_built.internationalization.defaultLocale, process.env.INTLAYER_DICTIONARY_SELECTOR !== "false" ? require_dictionaryManipulator_qualifiedDictionary.getDictionarySelectorCacheKey(selector) : "", plugins);
|
|
20
29
|
const cached = require_interpreter_dictionaryTransformCache.readTransformCache(dictionary, cacheKey);
|
|
21
30
|
if (cached.hit) return cached.content;
|
|
22
31
|
const appliedPlugins = plugins ?? require_interpreter_getContent_getContent.getBasePlugins(locale);
|
|
23
|
-
const resolved = require_dictionaryManipulator_qualifiedDictionary.resolveQualifiedDictionary(dictionary, selector);
|
|
32
|
+
const resolved = process.env.INTLAYER_DICTIONARY_SELECTOR !== "false" ? require_dictionaryManipulator_qualifiedDictionary.resolveQualifiedDictionary(dictionary, selector) : dictionary;
|
|
24
33
|
const transformDictionary = (resolvedDictionary) => {
|
|
25
34
|
const props = {
|
|
26
35
|
dictionaryKey: resolvedDictionary.key,
|
|
27
36
|
dictionaryPath: resolvedDictionary.filePath,
|
|
28
37
|
keyPath: [],
|
|
29
38
|
plugins: appliedPlugins,
|
|
30
|
-
nestedDictionaries: resolvedDictionary.nestedDictionaries
|
|
39
|
+
nestedDictionaries: resolvedDictionary.nestedDictionaries,
|
|
40
|
+
eager: !transformsInProgress.has(resolvedDictionary)
|
|
31
41
|
};
|
|
32
|
-
|
|
42
|
+
transformsInProgress.add(resolvedDictionary);
|
|
43
|
+
try {
|
|
44
|
+
return require_interpreter_getContent_getContent.getContent(resolvedDictionary.content, props, appliedPlugins);
|
|
45
|
+
} finally {
|
|
46
|
+
if (props.eager) transformsInProgress.delete(resolvedDictionary);
|
|
47
|
+
}
|
|
33
48
|
};
|
|
34
49
|
if (resolved === null) return require_interpreter_dictionaryTransformCache.writeTransformCache(dictionary, cacheKey, null);
|
|
35
50
|
if (Array.isArray(resolved)) return require_interpreter_dictionaryTransformCache.writeTransformCache(dictionary, cacheKey, resolved.map(transformDictionary));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getDictionary.cjs","names":["parseDictionarySelector","getDictionaryTransformCacheKey","internationalization","getDictionarySelectorCacheKey","readTransformCache","getBasePlugins","resolveQualifiedDictionary","getContent","writeTransformCache"],"sources":["../../../src/interpreter/getDictionary.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport 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 getDictionarySelectorCacheKey,\n parseDictionarySelector,\n resolveQualifiedDictionary,\n} from '../dictionaryManipulator/qualifiedDictionary';\nimport {\n getDictionaryTransformCacheKey,\n readTransformCache,\n writeTransformCache,\n} from './dictionaryTransformCache';\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 * @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 }
|
|
1
|
+
{"version":3,"file":"getDictionary.cjs","names":["parseDictionarySelector","getDictionaryTransformCacheKey","internationalization","getDictionarySelectorCacheKey","readTransformCache","getBasePlugins","resolveQualifiedDictionary","getContent","writeTransformCache"],"sources":["../../../src/interpreter/getDictionary.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport 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 getDictionarySelectorCacheKey,\n parseDictionarySelector,\n resolveQualifiedDictionary,\n} from '../dictionaryManipulator/qualifiedDictionary';\nimport {\n getDictionaryTransformCacheKey,\n readTransformCache,\n writeTransformCache,\n} from './dictionaryTransformCache';\nimport type {\n DeepTransformContent,\n IInterpreterPluginState,\n NodeProps,\n Plugins,\n} from './getContent';\nimport { getBasePlugins, getContent } from './getContent/getContent';\n\n/**\n * Dictionaries whose transform is running. Content is transformed eagerly, so a\n * dictionary reached again through a `nest()` cycle is transformed lazily\n * instead: its nodes then resolve on read, and the cycle unwinds.\n */\nconst transformsInProgress = new WeakSet<object>();\n\n/**\n * Transforms a dictionary in a single pass, applying each plugin as needed.\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 // The selector checks stay inline so bundlers can drop the whole\n // qualified-dictionary module when no dictionary declares a qualifier.\n const { locale, selector } =\n process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false'\n ? parseDictionarySelector(localeOrSelector)\n : {\n locale: localeOrSelector as LocalesValues | undefined,\n selector: undefined,\n };\n\n // The base plugins are rebuilt on every call, so they cannot identify\n // themselves — but they are fully determined by the locale, which the key\n // already carries. Only an explicitly passed array needs its own identity.\n const cacheKey = getDictionaryTransformCacheKey(\n locale ?? internationalization.defaultLocale,\n process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false'\n ? getDictionarySelectorCacheKey(selector)\n : '',\n plugins\n );\n\n const cached = readTransformCache<any>(dictionary, cacheKey);\n if (cached.hit) return cached.content;\n\n const appliedPlugins = plugins ?? getBasePlugins(locale);\n\n const resolved =\n process.env.INTLAYER_DICTIONARY_SELECTOR !== 'false'\n ? resolveQualifiedDictionary(dictionary, selector)\n : (dictionary as Dictionary);\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 eager: !transformsInProgress.has(resolvedDictionary),\n };\n\n transformsInProgress.add(resolvedDictionary);\n\n try {\n return getContent(resolvedDictionary.content, props, appliedPlugins);\n } finally {\n if (props.eager) transformsInProgress.delete(resolvedDictionary);\n }\n };\n\n if (resolved === null)\n return writeTransformCache(dictionary, cacheKey, null)!;\n\n if (Array.isArray(resolved)) {\n return writeTransformCache(\n dictionary,\n cacheKey,\n resolved.map(transformDictionary)\n ) as any;\n }\n\n return writeTransformCache(\n dictionary,\n cacheKey,\n transformDictionary(resolved)\n ) as any;\n};\n"],"mappings":";;;;;;;;;;;;AAmCA,MAAM,uCAAuB,IAAI,QAAgB;;;;;;;;;;AAWjD,MAAa,iBAIX,YACA,kBACA,YAKG;CAGH,MAAM,EAAE,QAAQ,aACd,QAAQ,IAAI,iCAAiC,UACzCA,0EAAwB,gBAAgB,IACxC;EACE,QAAQ;EACR,UAAU;CACZ;CAKN,MAAM,WAAWC,4EACf,UAAUC,4CAAqB,eAC/B,QAAQ,IAAI,iCAAiC,UACzCC,gFAA8B,QAAQ,IACtC,IACJ,OACF;CAEA,MAAM,SAASC,gEAAwB,YAAY,QAAQ;CAC3D,IAAI,OAAO,KAAK,OAAO,OAAO;CAE9B,MAAM,iBAAiB,WAAWC,yDAAe,MAAM;CAEvD,MAAM,WACJ,QAAQ,IAAI,iCAAiC,UACzCC,6EAA2B,YAAY,QAAQ,IAC9C;CAEP,MAAM,uBAAuB,uBAAmC;EAC9D,MAAM,QAAmB;GACvB,eAAe,mBAAmB;GAClC,gBAAgB,mBAAmB;GACnC,SAAS,CAAC;GACV,SAAS;GAIT,oBAAoB,mBAAmB;GACvC,OAAO,CAAC,qBAAqB,IAAI,kBAAkB;EACrD;EAEA,qBAAqB,IAAI,kBAAkB;EAE3C,IAAI;GACF,OAAOC,qDAAW,mBAAmB,SAAS,OAAO,cAAc;EACrE,UAAU;GACR,IAAI,MAAM,OAAO,qBAAqB,OAAO,kBAAkB;EACjE;CACF;CAEA,IAAI,aAAa,MACf,OAAOC,iEAAoB,YAAY,UAAU,IAAI;CAEvD,IAAI,MAAM,QAAQ,QAAQ,GACxB,OAAOA,iEACL,YACA,UACA,SAAS,IAAI,mBAAmB,CAClC;CAGF,OAAOA,iEACL,YACA,UACA,oBAAoB,QAAQ,CAC9B;AACF"}
|