{"version":3,"sources":["../../../../src/interpreter/getContent/plugins.ts"],"sourcesContent":["import type { Locales, LocalesValues } from '@intlayer/config/client';\nimport type {\n  ConditionContent,\n  EnumerationContent,\n  FileContent,\n  InsertionContent,\n  NestedContent,\n  TranslationContent,\n} from '../../transpiler';\nimport { type DictionaryKeys, type KeyPath, NodeType } from '../../types/index';\nimport { getCondition } from '../getCondition';\nimport { getEnumeration } from '../getEnumeration';\nimport { getInsertion } from '../getInsertion';\nimport { type GetNestingResult, getNesting } from '../getNesting';\nimport { getTranslation } from '../getTranslation';\n\n/** ---------------------------------------------\n *  PLUGIN DEFINITION\n *  --------------------------------------------- */\n\n/**\n * A plugin/transformer that can optionally transform a node during a single DFS pass.\n * - `canHandle` decides if the node is transformable by this plugin.\n * - `transform` returns the transformed node (and does not recurse further).\n *\n * > `transformFn` is a function that can be used to deeply transform inside the plugin.\n */\nexport type Plugins = {\n  id: string;\n  canHandle: (node: any) => boolean;\n  transform: (\n    node: any,\n    props: NodeProps,\n    transformFn: (node: any, props: NodeProps) => any\n  ) => any;\n};\n\n/** ---------------------------------------------\n *  TRANSLATION PLUGIN\n *  --------------------------------------------- */\n\nexport type TranslationCond<T, S> = T extends {\n  nodeType: NodeType | string;\n  [NodeType.Translation]: object;\n}\n  ? DeepTransformContent<\n      T[NodeType.Translation][keyof T[NodeType.Translation]],\n      S\n    >\n  : never;\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const translationPlugin = (\n  locale: LocalesValues,\n  fallback: boolean = true\n): Plugins => ({\n  id: 'translation-plugin',\n  canHandle: (node) =>\n    typeof node === 'object' && node?.nodeType === NodeType.Translation,\n  transform: (node: TranslationContent, props, deepTransformNode) => {\n    const result = structuredClone(node[NodeType.Translation]);\n\n    for (const key in result) {\n      const childProps = {\n        ...props,\n        children: result[key as unknown as keyof typeof result],\n        keyPath: [\n          ...props.keyPath,\n          { type: NodeType.Translation, key } as KeyPath,\n        ],\n      };\n      result[key as unknown as keyof typeof result] = deepTransformNode(\n        result[key as unknown as keyof typeof result],\n        childProps\n      );\n    }\n    return getTranslation(result, locale, fallback);\n  },\n});\n\n/** ---------------------------------------------\n *  ENUMERATION PLUGIN\n *  --------------------------------------------- */\n\nexport type EnumerationCond<T, S> = T extends {\n  nodeType: NodeType | string;\n  [NodeType.Enumeration]: object;\n}\n  ? (\n      quantity: number\n    ) => DeepTransformContent<\n      T[NodeType.Enumeration][keyof T[NodeType.Enumeration]],\n      S\n    >\n  : never;\n\n/** Enumeration plugin. Replaces node with a function that takes quantity => string. */\nexport const enumerationPlugin: Plugins = {\n  id: 'enumeration-plugin',\n  canHandle: (node) =>\n    typeof node === 'object' && node?.nodeType === NodeType.Enumeration,\n  transform: (node: EnumerationContent, props, deepTransformNode) => {\n    const result = structuredClone(node[NodeType.Enumeration]);\n\n    for (const key in result) {\n      const child = result[key as unknown as keyof typeof result];\n      const childProps = {\n        ...props,\n        children: child,\n        keyPath: [\n          ...props.keyPath,\n          { type: NodeType.Enumeration, key } as KeyPath,\n        ],\n      };\n      result[key as unknown as keyof typeof result] = deepTransformNode(\n        child,\n        childProps\n      );\n    }\n\n    return (quantity: number) => getEnumeration(result, quantity);\n  },\n};\n\n/** ---------------------------------------------\n *  CONDITION PLUGIN\n *  --------------------------------------------- */\n\nexport type ConditionCond<T, S> = T extends {\n  nodeType: NodeType | string;\n  [NodeType.Condition]: object;\n}\n  ? (\n      value: boolean\n    ) => DeepTransformContent<\n      T[NodeType.Condition][keyof T[NodeType.Condition]],\n      S\n    >\n  : never;\n\n/** Condition plugin. Replaces node with a function that takes boolean => string. */\nexport const conditionPlugin: Plugins = {\n  id: 'condition-plugin',\n  canHandle: (node) =>\n    typeof node === 'object' && node?.nodeType === NodeType.Condition,\n  transform: (node: ConditionContent, props, deepTransformNode) => {\n    const result = structuredClone(node[NodeType.Condition]);\n\n    for (const key in result) {\n      const child = result[key as keyof typeof result];\n      const childProps = {\n        ...props,\n        children: child,\n        keyPath: [\n          ...props.keyPath,\n          { type: NodeType.Condition, key } as KeyPath,\n        ],\n      };\n      result[key as unknown as keyof typeof result] = deepTransformNode(\n        child,\n        childProps\n      );\n    }\n\n    return (value: boolean) => getCondition(result, value);\n  },\n};\n\n/** ---------------------------------------------\n *  INSERTION PLUGIN\n *  --------------------------------------------- */\n\nexport type InsertionCond<T, S> = T extends {\n  nodeType: NodeType | string;\n  [NodeType.Insertion]: infer I;\n  fields?: infer U;\n}\n  ? U extends readonly string[]\n    ? (data: Record<U[number], string | number>) => DeepTransformContent<I, S>\n    : (data: Record<string, string | number>) => DeepTransformContent<I, S>\n  : never;\n\nexport const insertionPlugin: Plugins = {\n  id: 'insertion-plugin',\n  canHandle: (node) =>\n    typeof node === 'object' && node?.nodeType === NodeType.Insertion,\n  transform: (node: InsertionContent, props, deepTransformNode) => {\n    const newKeyPath: KeyPath[] = [\n      ...props.keyPath,\n      {\n        type: NodeType.Insertion,\n      },\n    ];\n\n    const children = node[NodeType.Insertion];\n\n    /** Insertion string plugin. Replaces string node with a component that render the insertion. */\n    const insertionStringPlugin: Plugins = {\n      id: 'insertion-string-plugin',\n      canHandle: (node) => typeof node === 'string',\n      transform: (node: string, subProps, deepTransformNode) => {\n        const transformedResult = deepTransformNode(node, {\n          ...subProps,\n          children: node,\n          plugins: [\n            ...(props.plugins ?? ([] as Plugins[])).filter(\n              (plugin) => plugin.id !== 'intlayer-node-plugin'\n            ),\n          ],\n        });\n\n        return (values: {\n          [K in InsertionContent['fields'][number]]: string | number;\n        }) => {\n          const children = getInsertion(transformedResult, values);\n\n          return deepTransformNode(children, {\n            ...subProps,\n            plugins: props.plugins,\n            children,\n          });\n        };\n      },\n    };\n\n    return deepTransformNode(children, {\n      ...props,\n      children,\n      keyPath: newKeyPath,\n      plugins: [insertionStringPlugin, ...(props.plugins ?? [])],\n    });\n  },\n};\n\n/** ---------------------------------------------\n *  NESTED PLUGIN\n *  --------------------------------------------- */\n\nexport type NestedCond<T, S> = T extends {\n  nodeType: NodeType | string;\n  [NodeType.Nested]: infer U;\n}\n  ? U extends {\n      dictionaryKey: infer K extends DictionaryKeys;\n      path?: infer P;\n    }\n    ? GetNestingResult<K, P, S>\n    : never\n  : never;\n\n/** Nested plugin. Replaces node with the result of `getNesting`. */\nexport const nestedPlugin: Plugins = {\n  id: 'nested-plugin',\n  canHandle: (node) =>\n    typeof node === 'object' && node?.nodeType === NodeType.Nested,\n  transform: (node: NestedContent, props) =>\n    getNesting(node.nested.dictionaryKey, node.nested.path, props),\n};\n\n// /** ---------------------------------------------\n//  *  FILE PLUGIN\n//  *  --------------------------------------------- */\n\nexport type FileCond<T> = T extends {\n  nodeType: NodeType | string;\n  [NodeType.File]: string;\n  content?: string;\n}\n  ? string\n  : never;\n\n/** File plugin. Replaces node with the result of `getNesting`. */\nexport const filePlugin: Plugins = {\n  id: 'file-plugin',\n  canHandle: (node) =>\n    typeof node === 'object' && node?.nodeType === NodeType.File,\n  transform: (node: FileContent, props, deepTransform) =>\n    deepTransform(node.content, {\n      ...props,\n      children: node.content,\n    }),\n};\n\n/**\n * PLUGIN RESULT\n */\n\n/**\n * Interface that defines the properties of a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface NodeProps {\n  dictionaryKey: string;\n  keyPath: KeyPath[];\n  plugins?: Plugins[];\n  locale?: Locales;\n  dictionaryPath?: string;\n  children?: any;\n}\n\n/**\n * Interface that defines the plugins that can be used to transform a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface IInterpreterPlugin<T, S> {\n  translation: TranslationCond<T, S>;\n  insertion: InsertionCond<T, S>;\n  enumeration: EnumerationCond<T, S>;\n  condition: ConditionCond<T, S>;\n  nested: NestedCond<T, S>;\n  // file: FileCond<T>;\n}\n\n/**\n * Allow to avoid overwriting import from `intlayer` package when `IInterpreterPlugin<T>` interface is augmented in another package, such as `react-intlayer`.\n */\nexport type IInterpreterPluginState = {\n  translation: true;\n  enumeration: true;\n  condition: true;\n  insertion: true;\n  nested: true;\n  // file: true;\n};\n\n/**\n * Utility type to check if a plugin can be applied to a node.\n */\ntype CheckApplyPlugin<T, K extends keyof IInterpreterPlugin<T, S>, S> =\n  // Test if the key is a key of S.\n  K extends keyof 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>[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>[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> =\n  // Turn any read-only array into a plain mutable array\n  T extends ReadonlyArray<infer U>\n    ? Array<DeepTransformContent<U, S>>\n    : T extends object\n      ? { [K in keyof T]: DeepTransformContent<T[K], S> }\n      : T;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\nexport type DeepTransformContent<T, S = IInterpreterPluginState> =\n  // Check if there is a plugin for T:\n  CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S>, S> extends never\n    ? // No plugin was found, so try to transform T recursively:\n      Traverse<T, S>\n    : // A plugin was found – use the plugin’s transformation.\n      IInterpreterPlugin<T, S>[keyof IInterpreterPlugin<T, S>];\n"],"mappings":"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","names":["node","deepTransformNode","children"]}