{"version":3,"file":"copy.mjs","names":[],"sources":["../../../src/libs/i18n/copy.ts"],"sourcesContent":["import z from \"zod\";\nimport type {\n\tAdminCopyDescriptor,\n\tAdminCopyInput,\n\tCopyDescriptor,\n\tCopyInput,\n\tLiteralCopy,\n\tRegisteredCopyTranslationKey,\n\tServerCopyDescriptor,\n\tTranslatableCopy,\n\tTranslationScope,\n\tTranslationValues,\n} from \"./types.js\";\n\nconst translationValuesSchema = z\n\t.record(z.string(), z.union([z.string(), z.number()]).optional())\n\t.optional();\n\ntype DefineCopyOptions = {\n\tdata?: TranslationValues;\n\tdefaultMessage?: string;\n};\n\ntype AdminCopyKey = `admin:${string}`;\ntype ServerCopyKey = `server:${string}`;\ntype RegisteredAdminCopyKey = Extract<\n\tRegisteredCopyTranslationKey,\n\tAdminCopyKey\n>;\ntype RegisteredServerCopyKey = Extract<\n\tRegisteredCopyTranslationKey,\n\tServerCopyKey\n>;\n\ntype DefineCopy = {\n\t(\n\t\tprefixedKey: RegisteredAdminCopyKey,\n\t\toptions?: DefineCopyOptions,\n\t): AdminCopyDescriptor;\n\t(\n\t\tprefixedKey: RegisteredServerCopyKey,\n\t\toptions?: DefineCopyOptions,\n\t): ServerCopyDescriptor;\n\t(prefixedKey: AdminCopyKey, options?: DefineCopyOptions): AdminCopyDescriptor;\n\t(\n\t\tprefixedKey: ServerCopyKey,\n\t\toptions?: DefineCopyOptions,\n\t): ServerCopyDescriptor;\n\t(prefixedKey: string, options?: DefineCopyOptions): CopyDescriptor;\n};\n\ntype CopyHelper = DefineCopy & {\n\tliteral: (value: string, values?: TranslationValues) => LiteralCopy;\n};\n\n/**\n * Parses a prefixed translation key into the scope used by the translation\n * store and the unprefixed key stored in translation files.\n */\nexport const parseCopyKey = (key: string) => {\n\tconst separatorIndex = key.indexOf(\":\");\n\tconst scope = key.slice(0, separatorIndex);\n\tconst translationKey = key.slice(separatorIndex + 1);\n\n\tif (\n\t\tseparatorIndex === -1 ||\n\t\t(scope !== \"admin\" && scope !== \"server\") ||\n\t\ttranslationKey.trim().length === 0\n\t) {\n\t\tthrow new Error(\n\t\t\t`Lucid copy keys must start with \"admin:\" or \"server:\". Received \"${key}\".`,\n\t\t);\n\t}\n\n\treturn {\n\t\tscope: scope as TranslationScope,\n\t\tkey: translationKey,\n\t};\n};\n\n/**\n * Zod schema for any Lucid translation descriptor created by `copy`.\n */\nexport const copyDescriptorSchema = z\n\t.object({\n\t\ttype: z.literal(\"lucid.copy\"),\n\t\tscope: z.enum([\"admin\", \"server\"]),\n\t\tkey: z.string().trim().min(1),\n\t\tvalues: translationValuesSchema,\n\t\tdefaultMessage: z.string().optional(),\n\t})\n\t.strict();\n\n/**\n * Zod schema for admin UI copy descriptors.\n */\nexport const adminCopyDescriptorSchema = copyDescriptorSchema.extend({\n\tscope: z.literal(\"admin\"),\n});\n\n/**\n * Zod schema for server/API copy descriptors.\n */\nexport const serverCopyDescriptorSchema = copyDescriptorSchema.extend({\n\tscope: z.literal(\"server\"),\n});\n\n/**\n * Zod schema for literal copy that can still receive interpolation data.\n */\nexport const literalCopySchema = z\n\t.object({\n\t\ttype: z.literal(\"lucid.literal\"),\n\t\tvalue: z.string(),\n\t\tvalues: translationValuesSchema,\n\t})\n\t.strict();\n\n/**\n * Zod schema for any value Lucid can resolve through a translator.\n */\nexport const translatableCopySchema = z.union([\n\tcopyDescriptorSchema,\n\tliteralCopySchema,\n]);\n\n/**\n * Normalises copy authored in config into Lucid's internal descriptor shape.\n *\n * Plain strings become literal copy (`copy.literal`) so they flow through the\n * same translator pipeline as descriptors. Existing descriptors/literals and\n * nullish values pass through untouched.\n *\n * @example\n * ```ts\n * normalizeCopy(\"Posts\"); // { type: \"lucid.literal\", value: \"Posts\" }\n * normalizeCopy(copy(\"admin:collections.posts.name\")); // unchanged\n * ```\n */\nexport function normalizeCopy<T extends TranslatableCopy>(\n\tvalue: T | string,\n): T | LiteralCopy;\nexport function normalizeCopy<T extends TranslatableCopy>(\n\tvalue: T | string | null,\n): T | LiteralCopy | null;\nexport function normalizeCopy<T extends TranslatableCopy>(\n\tvalue: T | string | undefined,\n): T | LiteralCopy | undefined;\nexport function normalizeCopy<T extends TranslatableCopy>(\n\tvalue: T | string | null | undefined,\n): T | LiteralCopy | null | undefined;\nexport function normalizeCopy(\n\tvalue: string | TranslatableCopy | null | undefined,\n) {\n\tif (value === null || value === undefined) return value;\n\tif (typeof value === \"string\") {\n\t\treturn { type: \"lucid.literal\", value } satisfies LiteralCopy;\n\t}\n\treturn value;\n}\n\n/**\n * Schema for copy authored in config: accepts a plain string, a copy\n * descriptor, or a literal, and normalises strings into literal copy.\n *\n * The static output is typed as {@link CopyInput} so processed config types stay\n * compatible with their authored counterparts; at runtime the value is always a\n * descriptor or literal.\n */\nexport const copyInputSchema = z\n\t.union([z.string(), copyDescriptorSchema, literalCopySchema])\n\t.transform((value): CopyInput => normalizeCopy(value));\n\n/**\n * Admin-scoped variant of {@link copyInputSchema}. Use this anywhere config\n * accepts admin UI copy so authors can pass a string instead of `copy(...)`.\n */\nexport const adminCopyInputSchema = z\n\t.union([z.string(), adminCopyDescriptorSchema, literalCopySchema])\n\t.transform((value): AdminCopyInput => normalizeCopy(value));\n\n/**\n * Schema for already-normalised admin copy as it appears in API responses\n * (descriptor or literal — never a bare string). Use this in resource schemas.\n */\nexport const resolvedAdminCopySchema = z.union([\n\tadminCopyDescriptorSchema,\n\tliteralCopySchema,\n]);\n\n/**\n * Defines translatable copy without resolving it immediately.\n *\n * Prefix keys with `admin:` for admin UI copy and `server:` for API/service\n * copy. The prefix chooses the translation group; translation files still store\n * the unprefixed key.\n *\n * @example\n * ```ts\n * import { copy } from \"@lucidcms/core\";\n *\n * const label = copy(\"admin:collections.posts.name\", {\n *   defaultMessage: \"Posts\",\n * });\n *\n * const message = copy(\"server:posts.not.found\", {\n *   data: { id: 12 },\n *   defaultMessage: \"Post {{id}} was not found.\",\n * });\n * ```\n */\nfunction defineCopy(\n\tprefixedKey: RegisteredAdminCopyKey,\n\toptions?: DefineCopyOptions,\n): AdminCopyDescriptor;\nfunction defineCopy(\n\tprefixedKey: RegisteredServerCopyKey,\n\toptions?: DefineCopyOptions,\n): ServerCopyDescriptor;\nfunction defineCopy(\n\tprefixedKey: AdminCopyKey,\n\toptions?: DefineCopyOptions,\n): AdminCopyDescriptor;\nfunction defineCopy(\n\tprefixedKey: ServerCopyKey,\n\toptions?: DefineCopyOptions,\n): ServerCopyDescriptor;\nfunction defineCopy(\n\tprefixedKey: string,\n\toptions?: DefineCopyOptions,\n): CopyDescriptor;\nfunction defineCopy(\n\tprefixedKey: string,\n\toptions?: DefineCopyOptions,\n): CopyDescriptor {\n\tconst { scope, key } = parseCopyKey(prefixedKey);\n\n\treturn {\n\t\ttype: \"lucid.copy\",\n\t\tscope,\n\t\tkey,\n\t\t...(options?.data ? { values: options.data } : {}),\n\t\t...(options?.defaultMessage\n\t\t\t? { defaultMessage: options.defaultMessage }\n\t\t\t: {}),\n\t};\n}\n\n/**\n * Describes already-written copy while keeping the value compatible with APIs\n * that accept translatable descriptors.\n */\nexport const copy: CopyHelper = Object.assign(defineCopy, {\n\tliteral: (value: string, values?: TranslationValues): LiteralCopy => ({\n\t\ttype: \"lucid.literal\",\n\t\tvalue,\n\t\t...(values ? { values } : {}),\n\t}),\n});\n\n/**\n * Checks whether a value is a Lucid admin/server copy descriptor.\n *\n * @example\n * ```ts\n * if (isCopyDescriptor(value)) {\n *   console.log(value.key);\n * }\n * ```\n */\nexport const isCopyDescriptor = (value: unknown): value is CopyDescriptor =>\n\tcopyDescriptorSchema.safeParse(value).success;\n\n/**\n * Checks whether a value can be resolved by Lucid's translation helpers.\n *\n * @example\n * ```ts\n * if (isTranslatableCopy(value)) {\n *   const message = translate(value);\n * }\n * ```\n */\nexport const isTranslatableCopy = (value: unknown): value is TranslatableCopy =>\n\ttranslatableCopySchema.safeParse(value).success;\n\nexport type { AdminCopyDescriptor, ServerCopyDescriptor };\n"],"mappings":"mBAcA,MAAM,EAA0B,EAC9B,OAAO,EAAE,OAAO,EAAG,EAAE,MAAM,CAAC,EAAE,OAAO,EAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAChE,SAAS,EA2CE,EAAgB,GAAgB,CAC5C,IAAM,EAAiB,EAAI,QAAQ,GAAG,EAChC,EAAQ,EAAI,MAAM,EAAG,CAAc,EACnC,EAAiB,EAAI,MAAM,EAAiB,CAAC,EAEnD,GACC,IAAmB,IAClB,IAAU,SAAW,IAAU,UAChC,EAAe,KAAK,CAAC,CAAC,SAAW,EAEjC,MAAU,MACT,oEAAoE,EAAI,GACzE,EAGD,MAAO,CACC,QACP,IAAK,CACN,CACD,EAKa,EAAuB,EAClC,OAAO,CACP,KAAM,EAAE,QAAQ,YAAY,EAC5B,MAAO,EAAE,KAAK,CAAC,QAAS,QAAQ,CAAC,EACjC,IAAK,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAC5B,OAAQ,EACR,eAAgB,EAAE,OAAO,CAAC,CAAC,SAAS,CACrC,CAAC,CAAC,CACD,OAAO,EAKI,EAA4B,EAAqB,OAAO,CACpE,MAAO,EAAE,QAAQ,OAAO,CACzB,CAAC,EAKyC,EAAqB,OAAO,CACrE,MAAO,EAAE,QAAQ,QAAQ,CAC1B,CAAC,EAKD,MAAa,EAAoB,EAC/B,OAAO,CACP,KAAM,EAAE,QAAQ,eAAe,EAC/B,MAAO,EAAE,OAAO,EAChB,OAAQ,CACT,CAAC,CAAC,CACD,OAAO,EAKI,EAAyB,EAAE,MAAM,CAC7C,EACA,CACD,CAAC,EA2BD,SAAgB,EACf,EACC,CAKD,OAJI,GAAU,KAAoC,EAC9C,OAAO,GAAU,SACb,CAAE,KAAM,gBAAiB,OAAM,EAEhC,CACR,CAU+B,EAC7B,MAAM,CAAC,EAAE,OAAO,EAAG,EAAsB,CAAiB,CAAC,CAAC,CAC5D,UAAW,GAAqB,EAAc,CAAK,CAAC,EAMtD,MAAa,EAAuB,EAClC,MAAM,CAAC,EAAE,OAAO,EAAG,EAA2B,CAAiB,CAAC,CAAC,CACjE,UAAW,GAA0B,EAAc,CAAK,CAAC,EAM9C,EAA0B,EAAE,MAAM,CAC9C,EACA,CACD,CAAC,EA2CD,SAAS,EACR,EACA,EACiB,CACjB,GAAM,CAAE,QAAO,OAAQ,EAAa,CAAW,EAE/C,MAAO,CACN,KAAM,aACN,QACA,MACA,GAAI,GAAS,KAAO,CAAE,OAAQ,EAAQ,IAAK,EAAI,CAAC,EAChD,GAAI,GAAS,eACV,CAAE,eAAgB,EAAQ,cAAe,EACzC,CAAC,CACL,CACD,CAMA,MAAa,EAAmB,OAAO,OAAO,EAAY,CACzD,SAAU,EAAe,KAA6C,CACrE,KAAM,gBACN,QACA,GAAI,EAAS,CAAE,QAAO,EAAI,CAAC,CAC5B,EACD,CAAC,EAyBY,EAAsB,GAClC,EAAuB,UAAU,CAAK,CAAC,CAAC"}