import { z } from 'zod'; import { PickSpecifyDesignToken, SpecifyDesignTokenFormat, SDTFEngine, SDTFEngineSerializedMetadata, createSDTFEngine, specifyVectorFormatSchema, specifyBitmapFormatValuesSchema, specifyFontFormatSchema, specifyVectorProviderSchema, specifyBitmapProviderSchema, specifyFontProviderSchema, } from '@specifyapp/specify-design-token-format'; import { SpecifyError, specifyErrors } from '../../errors/index.js'; /* v8 ignore start */ export const SDTFDataBoxSchema = z .object({ type: z.literal('SDTF'), // TODO @Nico: rename to tokenTree graph: z.custom(value => value), metadata: z.custom(value => value).optional(), }) .strict(); export type SDTFDataBox = z.infer; export const SDTFEngineDataBoxSchema = z .object({ type: z.literal('SDTF Engine'), engine: z.custom(), }) .strict(); export type SDTFEngineDataBox = z.infer; export const specifyRepositoryDataBoxSchema = z .object({ type: z.literal('repository'), owner: z.string().startsWith('@'), name: z.string(), }) .strict(); export type SpecifyRepositoryDataBox = z.infer; export const JSONDataBoxSchema = z .object({ type: z.literal('JSON'), json: z.union([ z.record(z.string(), z.unknown()), z.array(z.unknown()), z.string(), z.number(), z.boolean(), z.null(), ]), }) .strict(); export type JSONDataBox = z.infer; export const CustomDataBoxSchema = z .object({ type: z.literal('custom'), data: z.unknown(), }) .strict(); export type CustomDataBox = z.infer; type AssetToken = | PickSpecifyDesignToken<'vector'> | PickSpecifyDesignToken<'vectors'> | PickSpecifyDesignToken<'bitmap'> | PickSpecifyDesignToken<'bitmaps'> | PickSpecifyDesignToken<'font'> | PickSpecifyDesignToken<'textStyle'>; function makeAssetDataBoxSchema() { return < Type extends string | undefined, Format extends z.ZodType | undefined, Provider extends z.ZodType | undefined, Extension extends { [key: string]: z.ZodSchema } | undefined, >({ type, format, extension, provider, }: Partial<{ type: Type; format: Format; extension: Extension; provider: Provider }> = {}) => { return z .object({ type: z.literal((type ?? 'asset') as Type extends undefined ? 'asset' : Type), assets: z.array( z .object({ path: z.array(z.string()), mode: z.string(), url: z.string(), provider: (provider ?? z.string()) as Type extends undefined ? z.ZodString : Provider, format: (format ?? z.string()) as Format extends undefined ? z.ZodString : Format, token: z.custom(value => value), ...((extension ?? {}) as Extension extends undefined ? {} : Extension), }) .strict(), ), }) .strict(); }; } export const VectorDataBoxSchema = makeAssetDataBoxSchema< PickSpecifyDesignToken<'vector'> | PickSpecifyDesignToken<'vectors'> >()({ type: 'vector', format: specifyVectorFormatSchema, provider: specifyVectorProviderSchema, extension: { vector: z.string().optional(), }, }); export type VectorDataBox = z.infer; export const BitmapDataBoxSchema = makeAssetDataBoxSchema< PickSpecifyDesignToken<'bitmap'> | PickSpecifyDesignToken<'bitmaps'> >()({ type: 'bitmap', format: specifyBitmapFormatValuesSchema, provider: specifyBitmapProviderSchema, extension: { bitmap: z.array(z.number()).optional(), }, }); export type BitmapDataBox = z.infer; export const AssetDataBoxSchema = makeAssetDataBoxSchema()({ type: undefined, format: z.union([ specifyBitmapFormatValuesSchema, specifyVectorFormatSchema, specifyFontFormatSchema, ]), provider: z.union([ specifyBitmapProviderSchema, specifyVectorProviderSchema, specifyFontProviderSchema, ]), }); export type AssetDataBox = z.infer; export const parsersEngineDataBoxSchema = z.discriminatedUnion('type', [ SDTFDataBoxSchema, SDTFEngineDataBoxSchema, specifyRepositoryDataBoxSchema, JSONDataBoxSchema, CustomDataBoxSchema, VectorDataBoxSchema, AssetDataBoxSchema, BitmapDataBoxSchema, ]); export const parsersEngineDataBoxSchemaMap = { SDTF: SDTFDataBoxSchema, 'SDTF Engine': SDTFEngineDataBoxSchema, repository: specifyRepositoryDataBoxSchema, JSON: JSONDataBoxSchema, custom: CustomDataBoxSchema, vector: VectorDataBoxSchema, asset: AssetDataBoxSchema, bitmap: BitmapDataBoxSchema, } as const; export type ParsersEngineDataBox = z.infer; export type ParsersEngineDataBoxType = ParsersEngineDataBox['type']; export type PickParsersEngineDataBox = Extract< ParsersEngineDataBox, { type: Type } >; export type PickParsersEngineDataBoxSchema = (typeof parsersEngineDataBoxSchemaMap)[Type]; export function getParsersEngineDataBoxUnionSchema(types: Array) { if (types.length === 0) throw new Error('At least one type must be provided'); if (types.length === 1) return parsersEngineDataBoxSchemaMap[types[0]] as any; return z.union(types.map(type => parsersEngineDataBoxSchemaMap[type]) as any) as any; } export const serializedParsersEngineDataBoxSchema = z.discriminatedUnion('type', [ SDTFDataBoxSchema, specifyRepositoryDataBoxSchema, JSONDataBoxSchema, CustomDataBoxSchema, VectorDataBoxSchema, AssetDataBoxSchema, BitmapDataBoxSchema, ]); export type SerializedParsersEngineDataBox = z.infer; /* v8 ignore stop */ export function getDefaultParsersEngineDataBox( type: ParsersEngineDataBoxType | undefined, ): ParsersEngineDataBox { switch (type) { case 'SDTF Engine': { const t: SDTFEngineDataBox = { type: 'SDTF Engine', engine: createSDTFEngine(), }; return t; } case 'SDTF': case undefined: { const t: SDTFDataBox = { type: 'SDTF', graph: {}, }; return t; } case 'repository': { const t: SpecifyRepositoryDataBox = { type: 'repository', owner: '', name: '', }; return t; } case 'JSON': { const t: JSONDataBox = { type: 'JSON', json: {}, }; return t; } case 'bitmap': { const t: BitmapDataBox = { type: 'bitmap', assets: [], }; return t; } case 'vector': { const t: VectorDataBox = { type: 'vector', assets: [], }; return t; } case 'asset': { const t: AssetDataBox = { type: 'asset', assets: [], }; return t; } case 'custom': { const t: CustomDataBox = { type: 'custom', data: null, }; return t; } default: { const _exhaustiveCheck: never = type; throw new SpecifyError({ errorKey: specifyErrors.PARSERS_ENGINE_UNKNOWN_ERROR.errorKey, publicMessage: `Unknown data box type "${type}".`, }); } } }