fork of hey-api/openapi-ts because I need some additional things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore: add Zod compatibility version

Lubos 2b3b6459 482cab45

+1425 -1386
+1 -1
examples/openapi-ts-nuxt/package.json
··· 16 16 "nuxt": "3.14.1592", 17 17 "vue": "3.5.13", 18 18 "vue-router": "4.5.0", 19 - "zod": "3.23.8" 19 + "zod": "3.25.0" 20 20 }, 21 21 "devDependencies": { 22 22 "vite": "6.2.7"
+1 -1
examples/openapi-ts-sample/package.json
··· 18 18 "react": "19.0.0", 19 19 "react-dom": "19.0.0", 20 20 "valibot": "1.1.0", 21 - "zod": "3.23.8" 21 + "zod": "3.25.0" 22 22 }, 23 23 "devDependencies": { 24 24 "@config/vite-base": "workspace:*",
+2 -1
packages/openapi-ts-tests/package.json
··· 6 6 "scripts": { 7 7 "test:coverage": "vitest run --config vitest.config.unit.ts --coverage", 8 8 "test:e2e:disabled": "vitest run --config vitest.config.e2e.ts", 9 + "test:sample": "openapi-ts -i ./test/spec/3.1.x/validators.yaml -o ./test/generated/sample", 9 10 "test:types": "tsc -p tsconfig.test.json --noEmit", 10 11 "test:update": "vitest watch --config vitest.config.unit.ts --update", 11 12 "test:watch": "vitest watch --config vitest.config.unit.ts", ··· 56 57 "typescript": "5.8.3", 57 58 "valibot": "1.1.0", 58 59 "vue": "3.5.13", 59 - "zod": "3.23.8" 60 + "zod": "3.25.0" 60 61 } 61 62 }
+6 -4
packages/openapi-ts-tests/test/openapi-ts.config.ts
··· 174 174 // responseStyle: 'data', 175 175 // transformer: '@hey-api/transformers', 176 176 // transformer: true, 177 - validator: { 178 - request: 'zod', 179 - response: 'zod', 180 - }, 177 + validator: 'zod', 178 + // validator: { 179 + // request: 'zod', 180 + // response: 'zod', 181 + // }, 181 182 }, 182 183 { 183 184 // bigInt: true, ··· 227 228 { 228 229 // case: 'snake_case', 229 230 // comments: false, 231 + // compatibilityVersion: 4, 230 232 dates: { 231 233 offset: true, 232 234 },
+3 -1
packages/openapi-ts/package.json
··· 94 94 "color-support": "1.1.3", 95 95 "commander": "13.0.0", 96 96 "handlebars": "4.7.8", 97 - "open": "10.1.2" 97 + "open": "10.1.2", 98 + "semver": "7.7.2" 98 99 }, 99 100 "peerDependencies": { 100 101 "typescript": "^5.5.3" ··· 104 105 "@types/bun": "1.2.19", 105 106 "@types/cross-spawn": "6.0.6", 106 107 "@types/express": "4.17.21", 108 + "@types/semver": "7.7.0", 107 109 "axios": "1.8.2", 108 110 "cross-spawn": "7.0.5", 109 111 "eslint": "9.17.0",
+17 -10
packages/openapi-ts/src/config/init.ts
··· 9 9 import { getLogs } from './logs'; 10 10 import { mergeConfigs } from './merge'; 11 11 import { getOutput } from './output'; 12 + import { getProjectDependencies } from './packages'; 12 13 import { getParser } from './parser'; 13 14 import { getPlugins } from './plugins'; 14 15 ··· 17 18 */ 18 19 export const initConfigs = async ( 19 20 userConfig: UserConfig | undefined, 20 - ): Promise< 21 - ReadonlyArray<{ 21 + ): Promise<{ 22 + dependencies: Record<string, string>; 23 + results: ReadonlyArray<{ 22 24 config: Config; 23 25 errors: ReadonlyArray<Error>; 24 - }> 25 - > => { 26 + }>; 27 + }> => { 26 28 let configurationFile: string | undefined = undefined; 27 29 if (userConfig?.configFile) { 28 30 const parts = userConfig.configFile.split('.'); 29 31 configurationFile = parts.slice(0, parts.length - 1).join('.'); 30 32 } 31 33 32 - const { config: configFromFile } = await loadConfig<UserConfig>({ 33 - configFile: configurationFile, 34 - name: 'openapi-ts', 35 - }); 34 + const { config: configFromFile, configFile: loadedConfigFile } = 35 + await loadConfig<UserConfig>({ 36 + configFile: configurationFile, 37 + name: 'openapi-ts', 38 + }); 39 + 40 + const dependencies = getProjectDependencies( 41 + Object.keys(configFromFile).length ? loadedConfigFile : undefined, 42 + ); 36 43 37 44 const userConfigs: ReadonlyArray<UserConfig> = Array.isArray(userConfig) 38 45 ? userConfig ··· 97 104 let plugins: Pick<Config, 'plugins' | 'pluginOrder'>; 98 105 99 106 try { 100 - plugins = getPlugins(userConfig); 107 + plugins = getPlugins({ dependencies, userConfig }); 101 108 } catch (error) { 102 109 errors.push(error); 103 110 plugins = { ··· 134 141 }); 135 142 } 136 143 137 - return results; 144 + return { dependencies, results }; 138 145 };
+46
packages/openapi-ts/src/config/packages.ts
··· 1 + import fs from 'node:fs'; 2 + import path from 'node:path'; 3 + 4 + /** 5 + * Finds and reads the project's package.json file by searching upwards from the config file location, 6 + * or from process.cwd() if no config file is provided. 7 + * This ensures we get the correct dependencies even in monorepo setups. 8 + * 9 + * @param configFilePath - The path to the configuration file (e.g., openapi-ts.config.ts) 10 + * @returns An object containing all project dependencies (dependencies, devDependencies, peerDependencies, optionalDependencies) 11 + */ 12 + export const getProjectDependencies = ( 13 + configFilePath?: string, 14 + ): Record<string, string> => { 15 + let currentDir = configFilePath 16 + ? path.dirname(configFilePath) 17 + : process.cwd(); 18 + 19 + while (currentDir !== path.dirname(currentDir)) { 20 + const packageJsonPath = path.join(currentDir, 'package.json'); 21 + 22 + if (fs.existsSync(packageJsonPath)) { 23 + try { 24 + const packageJson = JSON.parse( 25 + fs.readFileSync(packageJsonPath, 'utf8'), 26 + ); 27 + return { 28 + ...packageJson.dependencies, 29 + ...packageJson.devDependencies, 30 + ...packageJson.peerDependencies, 31 + ...packageJson.optionalDependencies, 32 + }; 33 + } catch { 34 + // Silently ignore JSON parsing errors and continue searching 35 + } 36 + } 37 + 38 + const parentDir = path.dirname(currentDir); 39 + if (parentDir === currentDir) { 40 + break; 41 + } 42 + currentDir = parentDir; 43 + } 44 + 45 + return {}; 46 + };
+1 -1
packages/openapi-ts/src/config/parser.ts
··· 1 1 import type { Config, UserConfig } from '../types/config'; 2 - import { valueToObject } from './utils'; 2 + import { valueToObject } from './utils/config'; 3 3 4 4 export const defaultPaginationKeywords = [ 5 5 'after',
+13 -5
packages/openapi-ts/src/config/plugins.ts
··· 5 5 PluginNames, 6 6 } from '../plugins/types'; 7 7 import type { Config, UserConfig } from '../types/config'; 8 - import { valueToObject } from './utils'; 8 + import { valueToObject } from './utils/config'; 9 + import { packageFactory } from './utils/package'; 9 10 10 11 /** 11 12 * Default plugins used to generate artifacts if plugins aren't specified. ··· 16 17 ] as const satisfies ReadonlyArray<PluginNames>; 17 18 18 19 const getPluginsConfig = ({ 20 + dependencies, 19 21 userPlugins, 20 22 userPluginsConfig, 21 23 }: { 24 + dependencies: Record<string, string>; 22 25 userPlugins: ReadonlyArray<AnyPluginName>; 23 26 userPluginsConfig: Config['plugins']; 24 27 }): Pick<Config, 'plugins' | 'pluginOrder'> => { ··· 61 64 62 65 if (plugin.resolveConfig) { 63 66 const context: PluginContext = { 67 + package: packageFactory(dependencies), 64 68 pluginByTag: (tag, props = {}) => { 65 69 const { defaultPlugin, errorMessage } = props; 66 70 ··· 135 139 ); 136 140 }; 137 141 138 - export const getPlugins = ( 139 - userConfig: UserConfig, 140 - ): Pick<Config, 'plugins' | 'pluginOrder'> => { 142 + export const getPlugins = ({ 143 + dependencies, 144 + userConfig, 145 + }: { 146 + dependencies: Record<string, string>; 147 + userConfig: UserConfig; 148 + }): Pick<Config, 'plugins' | 'pluginOrder'> => { 141 149 const userPluginsConfig: Config['plugins'] = {}; 142 150 143 151 let definedPlugins: UserConfig['plugins'] = defaultPlugins; ··· 185 193 }) 186 194 .filter(Boolean); 187 195 188 - return getPluginsConfig({ userPlugins, userPluginsConfig }); 196 + return getPluginsConfig({ dependencies, userPlugins, userPluginsConfig }); 189 197 };
packages/openapi-ts/src/config/utils.ts packages/openapi-ts/src/config/utils/config.ts
+52
packages/openapi-ts/src/config/utils/package.ts
··· 1 + import type { RangeOptions, SemVer } from 'semver'; 2 + import * as semver from 'semver'; 3 + 4 + export type Package = { 5 + /** 6 + * Get the installed version of a package. 7 + * @param name The name of the package to get the version for. 8 + * @returns A SemVer object containing version information, or undefined if the package is not installed 9 + * or the version string is invalid. 10 + */ 11 + getVersion: (name: string) => SemVer | undefined; 12 + /** 13 + * Check if a given package is installed in the project. 14 + * @param name The name of the package to check. 15 + */ 16 + isInstalled: (name: string) => boolean; 17 + /** 18 + * Check if the installed version of a package or a given SemVer object satisfies a semver range. 19 + * @param nameOrVersion The name of the package to check, or a SemVer object. 20 + * @param range The semver range to check against. 21 + * @returns True if the version satisfies the range, false otherwise. 22 + */ 23 + satisfies: ( 24 + nameOrVersion: string | SemVer, 25 + range: string, 26 + optionsOrLoose?: boolean | RangeOptions, 27 + ) => boolean; 28 + }; 29 + 30 + export const packageFactory = ( 31 + dependencies: Record<string, string>, 32 + ): Package => ({ 33 + getVersion: (name) => { 34 + const version = dependencies[name]; 35 + try { 36 + if (version) { 37 + return semver.parse(version) || undefined; 38 + } 39 + } catch { 40 + // noop 41 + } 42 + return; 43 + }, 44 + isInstalled: (name) => Boolean(dependencies[name]), 45 + satisfies: (nameOrVersion, range, optionsOrLoose) => { 46 + const version = 47 + typeof nameOrVersion === 'string' 48 + ? dependencies[nameOrVersion] 49 + : nameOrVersion; 50 + return version ? semver.satisfies(version, range, optionsOrLoose) : false; 51 + }, 52 + });
+4 -2
packages/openapi-ts/src/createClient.ts
··· 167 167 168 168 export const createClient = async ({ 169 169 config, 170 + dependencies, 170 171 templates, 171 172 watch: _watch, 172 173 }: { 173 174 config: Config; 175 + dependencies: Record<string, string>; 174 176 templates: Templates; 175 177 /** 176 178 * Always falsy on the first run, truthy on subsequent runs. ··· 226 228 !isLegacyClient(config) && 227 229 !legacyNameFromConfig(config) 228 230 ) { 229 - context = parseOpenApiSpec({ config, spec: data }); 231 + context = parseOpenApiSpec({ config, dependencies, spec: data }); 230 232 } 231 233 232 234 // fallback to legacy parser ··· 262 264 263 265 if (config.input.watch.enabled && typeof inputPath.path === 'string') { 264 266 setTimeout(() => { 265 - createClient({ config, templates, watch }); 267 + createClient({ config, dependencies, templates, watch }); 266 268 }, config.input.watch.interval); 267 269 } 268 270
+9 -2
packages/openapi-ts/src/index.ts
··· 41 41 Performance.start('createClient'); 42 42 43 43 Performance.start('config'); 44 - for (const result of await initConfigs(resolvedConfig)) { 44 + const configResults = await initConfigs(resolvedConfig); 45 + for (const result of configResults.results) { 45 46 configs.push(result.config); 46 47 if (result.errors.length) { 47 48 throw result.errors[0]; ··· 54 55 Performance.end('handlebars'); 55 56 56 57 const clients = await Promise.all( 57 - configs.map((config) => pCreateClient({ config, templates })), 58 + configs.map((config) => 59 + pCreateClient({ 60 + config, 61 + dependencies: configResults.dependencies, 62 + templates, 63 + }), 64 + ), 58 65 ); 59 66 const result = clients.filter((client) => Boolean(client)) as ReadonlyArray< 60 67 Client | IR.Context
+19 -1
packages/openapi-ts/src/ir/context.ts
··· 1 1 import path from 'node:path'; 2 2 3 + import type { Package } from '../config/utils/package'; 4 + import { packageFactory } from '../config/utils/package'; 3 5 import { GeneratedFile } from '../generate/file'; 4 6 import type { PluginConfigMap } from '../plugins/config'; 5 7 import { PluginInstance } from '../plugins/shared/utils/instance'; ··· 47 49 */ 48 50 public ir: IR.Model = {}; 49 51 /** 52 + * The package metadata and utilities for the current context, constructed 53 + * from the provided dependencies. Used for managing package-related 54 + * information such as name, version, and dependency resolution during 55 + * code generation. 56 + */ 57 + public package: Package; 58 + /** 50 59 * A map of registered plugin instances, keyed by plugin name. Plugins are 51 60 * registered through the `registerPlugin` method and can be accessed by 52 61 * their configured name from the config. ··· 59 68 */ 60 69 public spec: Spec; 61 70 62 - constructor({ config, spec }: { config: Config; spec: Spec }) { 71 + constructor({ 72 + config, 73 + dependencies, 74 + spec, 75 + }: { 76 + config: Config; 77 + dependencies: Record<string, string>; 78 + spec: Spec; 79 + }) { 63 80 this.config = config; 81 + this.package = packageFactory(dependencies); 64 82 this.spec = spec; 65 83 } 66 84
+3
packages/openapi-ts/src/openApi/index.ts
··· 63 63 */ 64 64 export const parseOpenApiSpec = ({ 65 65 config, 66 + dependencies, 66 67 spec, 67 68 }: { 68 69 config: Config; 70 + dependencies: Record<string, string>; 69 71 spec: unknown; 70 72 }): IR.Context | undefined => { 71 73 const context = new IRContext({ 72 74 config, 75 + dependencies, 73 76 spec: spec as OpenApi.V2_0_X | OpenApi.V3_0_X | OpenApi.V3_1_X, 74 77 }); 75 78
+8
packages/openapi-ts/src/plugins/shared/utils/instance.ts
··· 13 13 private handler: Plugin.Config<T>['handler']; 14 14 public name: T['resolvedConfig']['name']; 15 15 public output: Required<T['config']>['output']; 16 + /** 17 + * The package metadata and utilities for the current context, constructed 18 + * from the provided dependencies. Used for managing package-related 19 + * information such as name, version, and dependency resolution during 20 + * code generation. 21 + */ 22 + public package: IR.Context['package']; 16 23 17 24 public constructor( 18 25 props: Pick< ··· 32 39 this.handler = props.handler; 33 40 this.name = props.name; 34 41 this.output = props.output; 42 + this.package = props.context.package; 35 43 } 36 44 37 45 public createFile(file: IR.ContextFile) {
+5 -3
packages/openapi-ts/src/plugins/types.d.ts
··· 1 - import type { ValueToObject } from '../config/utils'; 1 + import type { ValueToObject } from '../config/utils/config'; 2 + import type { Package } from '../config/utils/package'; 2 3 import type { OpenApi as LegacyOpenApi } from '../openApi'; 3 4 import type { Client as LegacyClient } from '../types/client'; 4 5 import type { Files } from '../types/utils'; ··· 35 36 36 37 type PluginTag = 'client' | 'transformer' | 'validator'; 37 38 38 - export interface PluginContext { 39 + export type PluginContext = { 40 + package: Package; 39 41 pluginByTag: <T extends AnyPluginName | boolean = AnyPluginName>( 40 42 tag: PluginTag, 41 43 props?: { ··· 44 46 }, 45 47 ) => Exclude<T, boolean> | undefined; 46 48 valueToObject: ValueToObject; 47 - } 49 + }; 48 50 49 51 type BaseApi = Record<string, unknown>; 50 52
+50
packages/openapi-ts/src/plugins/zod/config.ts
··· 1 + import colors from 'ansi-colors'; 2 + 1 3 import { definePluginConfig, mappers } from '../shared/utils/config'; 2 4 import { api } from './api'; 3 5 import { handler } from './plugin'; 4 6 import type { ZodPlugin } from './types'; 7 + 8 + type CompatibilityVersion = NonNullable< 9 + ZodPlugin['Config']['config']['compatibilityVersion'] 10 + >; 5 11 6 12 export const defaultConfig: ZodPlugin['Config'] = { 7 13 api, ··· 15 21 name: 'zod', 16 22 output: 'zod', 17 23 resolveConfig: (plugin, context) => { 24 + const packageName = 'zod'; 25 + const version = context.package.getVersion(packageName); 26 + 27 + const inferCompatibleVersion = (): CompatibilityVersion => { 28 + if (version && (version.major === 4 || version.major === 3)) { 29 + return version.major; 30 + } 31 + 32 + // default compatibility version 33 + return 4; 34 + }; 35 + 36 + const ensureCompatibleVersion = ( 37 + compatibilityVersion: CompatibilityVersion | undefined, 38 + ): CompatibilityVersion => { 39 + if (!compatibilityVersion) { 40 + return inferCompatibleVersion(); 41 + } 42 + 43 + if (!version) { 44 + return compatibilityVersion; 45 + } 46 + 47 + if ( 48 + compatibilityVersion === 4 || 49 + compatibilityVersion === 3 || 50 + compatibilityVersion === 'mini' 51 + ) { 52 + if (!context.package.satisfies(version, '>=3.25.0 <5.0.0')) { 53 + const compatibleVersion = inferCompatibleVersion(); 54 + console.warn( 55 + `🔌 ${colors.yellow('Warning:')} Installed ${colors.cyan(packageName)} ${colors.cyan(`v${version.version}`)} does not support compatibility version ${colors.yellow(String(compatibilityVersion))}, using ${colors.yellow(String(compatibleVersion))}.`, 56 + ); 57 + return compatibleVersion; 58 + } 59 + } 60 + 61 + return compatibilityVersion; 62 + }; 63 + 64 + plugin.config.compatibilityVersion = ensureCompatibleVersion( 65 + plugin.config.compatibilityVersion, 66 + ); 67 + 18 68 plugin.config.dates = context.valueToObject({ 19 69 defaultValue: { 20 70 offset: false,
+1 -1
packages/openapi-ts/src/plugins/zod/export.ts
··· 4 4 import type { IR } from '../../ir/types'; 5 5 import { createSchemaComment } from '../shared/utils/schema'; 6 6 import { identifiers, zodId } from './constants'; 7 - import type { ZodSchema } from './plugin'; 7 + import type { ZodSchema } from './shared/types'; 8 8 import type { ZodPlugin } from './types'; 9 9 10 10 export const exportZodSchema = ({
+6 -6
packages/openapi-ts/src/plugins/zod/operation.ts packages/openapi-ts/src/plugins/zod/v3/operation.ts
··· 1 - import { operationResponsesMap } from '../../ir/operation'; 2 - import type { IR } from '../../ir/types'; 3 - import { buildName } from '../../openApi/shared/utils/name'; 4 - import { zodId } from './constants'; 5 - import { exportZodSchema } from './export'; 1 + import { operationResponsesMap } from '../../../ir/operation'; 2 + import type { IR } from '../../../ir/types'; 3 + import { buildName } from '../../../openApi/shared/utils/name'; 4 + import { zodId } from '../constants'; 5 + import { exportZodSchema } from '../export'; 6 + import type { ZodPlugin } from '../types'; 6 7 import type { State } from './plugin'; 7 8 import { schemaToZodSchema } from './plugin'; 8 - import type { ZodPlugin } from './types'; 9 9 10 10 export const operationToZodSchema = ({ 11 11 operation,
+12 -1032
packages/openapi-ts/src/plugins/zod/plugin.ts
··· 1 - import ts from 'typescript'; 2 - 3 - import { compiler } from '../../compiler'; 4 - import { deduplicateSchema } from '../../ir/schema'; 5 - import type { IR } from '../../ir/types'; 6 - import { buildName } from '../../openApi/shared/utils/name'; 7 - import { refToName } from '../../utils/ref'; 8 - import { numberRegExp } from '../../utils/regexp'; 9 - import { identifiers, zodId } from './constants'; 10 - import { exportZodSchema } from './export'; 11 - import { operationToZodSchema } from './operation'; 12 1 import type { ZodPlugin } from './types'; 13 - 14 - interface SchemaWithType<T extends Required<IR.SchemaObject>['type']> 15 - extends Omit<IR.SchemaObject, 'type'> { 16 - type: Extract<Required<IR.SchemaObject>['type'], T>; 17 - } 18 - 19 - export type State = { 20 - circularReferenceTracker: Array<string>; 21 - hasCircularReference: boolean; 22 - }; 23 - 24 - export type ZodSchema = { 25 - expression: ts.Expression; 26 - typeName?: string; 27 - }; 28 - 29 - const arrayTypeToZodSchema = ({ 30 - plugin, 31 - schema, 32 - state, 33 - }: { 34 - plugin: ZodPlugin['Instance']; 35 - schema: SchemaWithType<'array'>; 36 - state: State; 37 - }): ts.CallExpression => { 38 - const functionName = compiler.propertyAccessExpression({ 39 - expression: identifiers.z, 40 - name: identifiers.array, 41 - }); 42 - 43 - let arrayExpression: ts.CallExpression | undefined; 44 - 45 - if (!schema.items) { 46 - arrayExpression = compiler.callExpression({ 47 - functionName, 48 - parameters: [ 49 - unknownTypeToZodSchema({ 50 - schema: { 51 - type: 'unknown', 52 - }, 53 - }), 54 - ], 55 - }); 56 - } else { 57 - schema = deduplicateSchema({ schema }); 58 - 59 - // at least one item is guaranteed 60 - const itemExpressions = schema.items!.map( 61 - (item) => 62 - schemaToZodSchema({ 63 - plugin, 64 - schema: item, 65 - state, 66 - }).expression, 67 - ); 68 - 69 - if (itemExpressions.length === 1) { 70 - arrayExpression = compiler.callExpression({ 71 - functionName, 72 - parameters: itemExpressions, 73 - }); 74 - } else { 75 - if (schema.logicalOperator === 'and') { 76 - // TODO: parser - handle intersection 77 - // return compiler.typeArrayNode( 78 - // compiler.typeIntersectionNode({ types: itemExpressions }), 79 - // ); 80 - } 81 - 82 - arrayExpression = compiler.callExpression({ 83 - functionName: compiler.propertyAccessExpression({ 84 - expression: identifiers.z, 85 - name: identifiers.array, 86 - }), 87 - parameters: [ 88 - compiler.callExpression({ 89 - functionName: compiler.propertyAccessExpression({ 90 - expression: identifiers.z, 91 - name: identifiers.union, 92 - }), 93 - parameters: [ 94 - compiler.arrayLiteralExpression({ 95 - elements: itemExpressions, 96 - }), 97 - ], 98 - }), 99 - ], 100 - }); 101 - } 102 - } 103 - 104 - if (schema.minItems === schema.maxItems && schema.minItems !== undefined) { 105 - arrayExpression = compiler.callExpression({ 106 - functionName: compiler.propertyAccessExpression({ 107 - expression: arrayExpression, 108 - name: identifiers.length, 109 - }), 110 - parameters: [compiler.valueToExpression({ value: schema.minItems })], 111 - }); 112 - } else { 113 - if (schema.minItems !== undefined) { 114 - arrayExpression = compiler.callExpression({ 115 - functionName: compiler.propertyAccessExpression({ 116 - expression: arrayExpression, 117 - name: identifiers.min, 118 - }), 119 - parameters: [compiler.valueToExpression({ value: schema.minItems })], 120 - }); 121 - } 122 - 123 - if (schema.maxItems !== undefined) { 124 - arrayExpression = compiler.callExpression({ 125 - functionName: compiler.propertyAccessExpression({ 126 - expression: arrayExpression, 127 - name: identifiers.max, 128 - }), 129 - parameters: [compiler.valueToExpression({ value: schema.maxItems })], 130 - }); 131 - } 132 - } 133 - 134 - return arrayExpression; 135 - }; 136 - 137 - const booleanTypeToZodSchema = ({ 138 - schema, 139 - }: { 140 - schema: SchemaWithType<'boolean'>; 141 - }) => { 142 - if (typeof schema.const === 'boolean') { 143 - const expression = compiler.callExpression({ 144 - functionName: compiler.propertyAccessExpression({ 145 - expression: identifiers.z, 146 - name: identifiers.literal, 147 - }), 148 - parameters: [compiler.ots.boolean(schema.const)], 149 - }); 150 - return expression; 151 - } 152 - 153 - const expression = compiler.callExpression({ 154 - functionName: compiler.propertyAccessExpression({ 155 - expression: identifiers.z, 156 - name: identifiers.boolean, 157 - }), 158 - }); 159 - return expression; 160 - }; 161 - 162 - const enumTypeToZodSchema = ({ 163 - schema, 164 - }: { 165 - schema: SchemaWithType<'enum'>; 166 - }): ts.CallExpression => { 167 - const enumMembers: Array<ts.LiteralExpression> = []; 168 - 169 - let isNullable = false; 170 - 171 - for (const item of schema.items ?? []) { 172 - // Zod supports only string enums 173 - if (item.type === 'string' && typeof item.const === 'string') { 174 - enumMembers.push( 175 - compiler.stringLiteral({ 176 - text: item.const, 177 - }), 178 - ); 179 - } else if (item.type === 'null' || item.const === null) { 180 - isNullable = true; 181 - } 182 - } 183 - 184 - if (!enumMembers.length) { 185 - return unknownTypeToZodSchema({ 186 - schema: { 187 - type: 'unknown', 188 - }, 189 - }); 190 - } 191 - 192 - let enumExpression = compiler.callExpression({ 193 - functionName: compiler.propertyAccessExpression({ 194 - expression: identifiers.z, 195 - name: identifiers.enum, 196 - }), 197 - parameters: [ 198 - compiler.arrayLiteralExpression({ 199 - elements: enumMembers, 200 - multiLine: false, 201 - }), 202 - ], 203 - }); 204 - 205 - if (isNullable) { 206 - enumExpression = compiler.callExpression({ 207 - functionName: compiler.propertyAccessExpression({ 208 - expression: enumExpression, 209 - name: identifiers.nullable, 210 - }), 211 - }); 212 - } 213 - 214 - return enumExpression; 215 - }; 216 - 217 - // eslint-disable-next-line @typescript-eslint/no-unused-vars 218 - const neverTypeToZodSchema = (_props: { schema: SchemaWithType<'never'> }) => { 219 - const expression = compiler.callExpression({ 220 - functionName: compiler.propertyAccessExpression({ 221 - expression: identifiers.z, 222 - name: identifiers.never, 223 - }), 224 - }); 225 - return expression; 226 - }; 227 - 228 - // eslint-disable-next-line @typescript-eslint/no-unused-vars 229 - const nullTypeToZodSchema = (_props: { schema: SchemaWithType<'null'> }) => { 230 - const expression = compiler.callExpression({ 231 - functionName: compiler.propertyAccessExpression({ 232 - expression: identifiers.z, 233 - name: identifiers.null, 234 - }), 235 - }); 236 - return expression; 237 - }; 238 - 239 - const numberParameter = ({ 240 - isBigInt, 241 - value, 242 - }: { 243 - isBigInt: boolean; 244 - value: unknown; 245 - }) => { 246 - const expression = compiler.valueToExpression({ value }); 247 - 248 - if ( 249 - isBigInt && 250 - (typeof value === 'bigint' || 251 - typeof value === 'number' || 252 - typeof value === 'string' || 253 - typeof value === 'boolean') 254 - ) { 255 - return compiler.callExpression({ 256 - functionName: 'BigInt', 257 - parameters: [expression], 258 - }); 259 - } 260 - 261 - return expression; 262 - }; 263 - 264 - const numberTypeToZodSchema = ({ 265 - schema, 266 - }: { 267 - schema: SchemaWithType<'integer' | 'number'>; 268 - }) => { 269 - const isBigInt = schema.type === 'integer' && schema.format === 'int64'; 270 - 271 - if (typeof schema.const === 'number') { 272 - // TODO: parser - handle bigint constants 273 - const expression = compiler.callExpression({ 274 - functionName: compiler.propertyAccessExpression({ 275 - expression: identifiers.z, 276 - name: identifiers.literal, 277 - }), 278 - parameters: [compiler.ots.number(schema.const)], 279 - }); 280 - return expression; 281 - } 282 - 283 - let numberExpression = compiler.callExpression({ 284 - functionName: isBigInt 285 - ? compiler.propertyAccessExpression({ 286 - expression: compiler.propertyAccessExpression({ 287 - expression: identifiers.z, 288 - name: identifiers.coerce, 289 - }), 290 - name: identifiers.bigint, 291 - }) 292 - : compiler.propertyAccessExpression({ 293 - expression: identifiers.z, 294 - name: identifiers.number, 295 - }), 296 - }); 297 - 298 - if (!isBigInt && schema.type === 'integer') { 299 - numberExpression = compiler.callExpression({ 300 - functionName: compiler.propertyAccessExpression({ 301 - expression: numberExpression, 302 - name: identifiers.int, 303 - }), 304 - }); 305 - } 306 - 307 - if (schema.exclusiveMinimum !== undefined) { 308 - numberExpression = compiler.callExpression({ 309 - functionName: compiler.propertyAccessExpression({ 310 - expression: numberExpression, 311 - name: identifiers.gt, 312 - }), 313 - parameters: [ 314 - numberParameter({ isBigInt, value: schema.exclusiveMinimum }), 315 - ], 316 - }); 317 - } else if (schema.minimum !== undefined) { 318 - numberExpression = compiler.callExpression({ 319 - functionName: compiler.propertyAccessExpression({ 320 - expression: numberExpression, 321 - name: identifiers.gte, 322 - }), 323 - parameters: [numberParameter({ isBigInt, value: schema.minimum })], 324 - }); 325 - } 326 - 327 - if (schema.exclusiveMaximum !== undefined) { 328 - numberExpression = compiler.callExpression({ 329 - functionName: compiler.propertyAccessExpression({ 330 - expression: numberExpression, 331 - name: identifiers.lt, 332 - }), 333 - parameters: [ 334 - numberParameter({ isBigInt, value: schema.exclusiveMaximum }), 335 - ], 336 - }); 337 - } else if (schema.maximum !== undefined) { 338 - numberExpression = compiler.callExpression({ 339 - functionName: compiler.propertyAccessExpression({ 340 - expression: numberExpression, 341 - name: identifiers.lte, 342 - }), 343 - parameters: [numberParameter({ isBigInt, value: schema.maximum })], 344 - }); 345 - } 346 - 347 - return numberExpression; 348 - }; 349 - 350 - const objectTypeToZodSchema = ({ 351 - plugin, 352 - schema, 353 - state, 354 - }: { 355 - plugin: ZodPlugin['Instance']; 356 - schema: SchemaWithType<'object'>; 357 - state: State; 358 - }): { 359 - anyType: string; 360 - expression: ts.CallExpression; 361 - } => { 362 - // TODO: parser - handle constants 363 - const properties: Array<ts.PropertyAssignment> = []; 364 - 365 - const required = schema.required ?? []; 366 - 367 - for (const name in schema.properties) { 368 - const property = schema.properties[name]!; 369 - const isRequired = required.includes(name); 370 - 371 - const propertyExpression = schemaToZodSchema({ 372 - optional: !isRequired, 373 - plugin, 374 - schema: property, 375 - state, 376 - }).expression; 377 - 378 - numberRegExp.lastIndex = 0; 379 - let propertyName; 380 - if (numberRegExp.test(name)) { 381 - // For numeric literals, we'll handle negative numbers by using a string literal 382 - // instead of trying to use a PrefixUnaryExpression 383 - propertyName = name.startsWith('-') 384 - ? ts.factory.createStringLiteral(name) 385 - : ts.factory.createNumericLiteral(name); 386 - } else { 387 - propertyName = name; 388 - } 389 - // TODO: parser - abstract safe property name logic 390 - if ( 391 - ((name.match(/^[0-9]/) && name.match(/\D+/g)) || name.match(/\W/g)) && 392 - !name.startsWith("'") && 393 - !name.endsWith("'") 394 - ) { 395 - propertyName = `'${name}'`; 396 - } 397 - properties.push( 398 - compiler.propertyAssignment({ 399 - initializer: propertyExpression, 400 - name: propertyName, 401 - }), 402 - ); 403 - } 404 - 405 - if ( 406 - schema.additionalProperties && 407 - schema.additionalProperties.type === 'object' && 408 - !Object.keys(properties).length 409 - ) { 410 - const zodSchema = schemaToZodSchema({ 411 - plugin, 412 - schema: schema.additionalProperties, 413 - state, 414 - }).expression; 415 - const expression = compiler.callExpression({ 416 - functionName: compiler.propertyAccessExpression({ 417 - expression: identifiers.z, 418 - name: identifiers.record, 419 - }), 420 - parameters: [zodSchema], 421 - }); 422 - return { 423 - anyType: 'AnyZodObject', 424 - expression, 425 - }; 426 - } 427 - 428 - const expression = compiler.callExpression({ 429 - functionName: compiler.propertyAccessExpression({ 430 - expression: identifiers.z, 431 - name: identifiers.object, 432 - }), 433 - parameters: [ts.factory.createObjectLiteralExpression(properties, true)], 434 - }); 435 - return { 436 - anyType: 'AnyZodObject', 437 - expression, 438 - }; 439 - }; 440 - 441 - const stringTypeToZodSchema = ({ 442 - plugin, 443 - schema, 444 - }: { 445 - plugin: ZodPlugin['Instance']; 446 - schema: SchemaWithType<'string'>; 447 - }) => { 448 - if (typeof schema.const === 'string') { 449 - const expression = compiler.callExpression({ 450 - functionName: compiler.propertyAccessExpression({ 451 - expression: identifiers.z, 452 - name: identifiers.literal, 453 - }), 454 - parameters: [compiler.ots.string(schema.const)], 455 - }); 456 - return expression; 457 - } 458 - 459 - let stringExpression = compiler.callExpression({ 460 - functionName: compiler.propertyAccessExpression({ 461 - expression: identifiers.z, 462 - name: identifiers.string, 463 - }), 464 - }); 465 - 466 - if (schema.format) { 467 - switch (schema.format) { 468 - case 'date-time': 469 - stringExpression = compiler.callExpression({ 470 - functionName: compiler.propertyAccessExpression({ 471 - expression: stringExpression, 472 - name: identifiers.datetime, 473 - }), 474 - parameters: plugin.config.dates.offset 475 - ? [ 476 - compiler.objectExpression({ 477 - obj: [ 478 - { 479 - key: 'offset', 480 - value: true, 481 - }, 482 - ], 483 - }), 484 - ] 485 - : [], 486 - }); 487 - break; 488 - case 'ipv4': 489 - case 'ipv6': 490 - stringExpression = compiler.callExpression({ 491 - functionName: compiler.propertyAccessExpression({ 492 - expression: stringExpression, 493 - name: identifiers.ip, 494 - }), 495 - }); 496 - break; 497 - case 'uri': 498 - stringExpression = compiler.callExpression({ 499 - functionName: compiler.propertyAccessExpression({ 500 - expression: stringExpression, 501 - name: identifiers.url, 502 - }), 503 - }); 504 - break; 505 - case 'date': 506 - case 'email': 507 - case 'time': 508 - case 'uuid': 509 - stringExpression = compiler.callExpression({ 510 - functionName: compiler.propertyAccessExpression({ 511 - expression: stringExpression, 512 - name: compiler.identifier({ text: schema.format }), 513 - }), 514 - }); 515 - break; 516 - } 517 - } 518 - 519 - if (schema.minLength === schema.maxLength && schema.minLength !== undefined) { 520 - stringExpression = compiler.callExpression({ 521 - functionName: compiler.propertyAccessExpression({ 522 - expression: stringExpression, 523 - name: identifiers.length, 524 - }), 525 - parameters: [compiler.valueToExpression({ value: schema.minLength })], 526 - }); 527 - } else { 528 - if (schema.minLength !== undefined) { 529 - stringExpression = compiler.callExpression({ 530 - functionName: compiler.propertyAccessExpression({ 531 - expression: stringExpression, 532 - name: identifiers.min, 533 - }), 534 - parameters: [compiler.valueToExpression({ value: schema.minLength })], 535 - }); 536 - } 537 - 538 - if (schema.maxLength !== undefined) { 539 - stringExpression = compiler.callExpression({ 540 - functionName: compiler.propertyAccessExpression({ 541 - expression: stringExpression, 542 - name: identifiers.max, 543 - }), 544 - parameters: [compiler.valueToExpression({ value: schema.maxLength })], 545 - }); 546 - } 547 - } 548 - 549 - if (schema.pattern) { 550 - stringExpression = compiler.callExpression({ 551 - functionName: compiler.propertyAccessExpression({ 552 - expression: stringExpression, 553 - name: identifiers.regex, 554 - }), 555 - parameters: [compiler.regularExpressionLiteral({ text: schema.pattern })], 556 - }); 557 - } 558 - 559 - return stringExpression; 560 - }; 561 - 562 - const tupleTypeToZodSchema = ({ 563 - plugin, 564 - schema, 565 - state, 566 - }: { 567 - plugin: ZodPlugin['Instance']; 568 - schema: SchemaWithType<'tuple'>; 569 - state: State; 570 - }) => { 571 - if (schema.const && Array.isArray(schema.const)) { 572 - const tupleElements = schema.const.map((value) => 573 - compiler.callExpression({ 574 - functionName: compiler.propertyAccessExpression({ 575 - expression: identifiers.z, 576 - name: identifiers.literal, 577 - }), 578 - parameters: [compiler.valueToExpression({ value })], 579 - }), 580 - ); 581 - const expression = compiler.callExpression({ 582 - functionName: compiler.propertyAccessExpression({ 583 - expression: identifiers.z, 584 - name: identifiers.tuple, 585 - }), 586 - parameters: [ 587 - compiler.arrayLiteralExpression({ 588 - elements: tupleElements, 589 - }), 590 - ], 591 - }); 592 - return expression; 593 - } 594 - 595 - const tupleElements: Array<ts.Expression> = []; 596 - 597 - for (const item of schema.items ?? []) { 598 - tupleElements.push( 599 - schemaToZodSchema({ 600 - plugin, 601 - schema: item, 602 - state, 603 - }).expression, 604 - ); 605 - } 606 - 607 - const expression = compiler.callExpression({ 608 - functionName: compiler.propertyAccessExpression({ 609 - expression: identifiers.z, 610 - name: identifiers.tuple, 611 - }), 612 - parameters: [ 613 - compiler.arrayLiteralExpression({ 614 - elements: tupleElements, 615 - }), 616 - ], 617 - }); 618 - return expression; 619 - }; 620 - 621 - // eslint-disable-next-line @typescript-eslint/no-unused-vars 622 - const undefinedTypeToZodSchema = (_props: { 623 - schema: SchemaWithType<'undefined'>; 624 - }) => { 625 - const expression = compiler.callExpression({ 626 - functionName: compiler.propertyAccessExpression({ 627 - expression: identifiers.z, 628 - name: identifiers.undefined, 629 - }), 630 - }); 631 - return expression; 632 - }; 633 - 634 - // eslint-disable-next-line @typescript-eslint/no-unused-vars 635 - const unknownTypeToZodSchema = (_props: { 636 - schema: SchemaWithType<'unknown'>; 637 - }) => { 638 - const expression = compiler.callExpression({ 639 - functionName: compiler.propertyAccessExpression({ 640 - expression: identifiers.z, 641 - name: identifiers.unknown, 642 - }), 643 - }); 644 - return expression; 645 - }; 646 - 647 - // eslint-disable-next-line @typescript-eslint/no-unused-vars 648 - const voidTypeToZodSchema = (_props: { schema: SchemaWithType<'void'> }) => { 649 - const expression = compiler.callExpression({ 650 - functionName: compiler.propertyAccessExpression({ 651 - expression: identifiers.z, 652 - name: identifiers.void, 653 - }), 654 - }); 655 - return expression; 656 - }; 657 - 658 - const schemaTypeToZodSchema = ({ 659 - plugin, 660 - schema, 661 - state, 662 - }: { 663 - plugin: ZodPlugin['Instance']; 664 - schema: IR.SchemaObject; 665 - state: State; 666 - }): { 667 - anyType?: string; 668 - expression: ts.Expression; 669 - } => { 670 - switch (schema.type as Required<IR.SchemaObject>['type']) { 671 - case 'array': 672 - return { 673 - expression: arrayTypeToZodSchema({ 674 - plugin, 675 - schema: schema as SchemaWithType<'array'>, 676 - state, 677 - }), 678 - }; 679 - case 'boolean': 680 - return { 681 - expression: booleanTypeToZodSchema({ 682 - schema: schema as SchemaWithType<'boolean'>, 683 - }), 684 - }; 685 - case 'enum': 686 - return { 687 - expression: enumTypeToZodSchema({ 688 - schema: schema as SchemaWithType<'enum'>, 689 - }), 690 - }; 691 - case 'integer': 692 - case 'number': 693 - return { 694 - expression: numberTypeToZodSchema({ 695 - schema: schema as SchemaWithType<'integer' | 'number'>, 696 - }), 697 - }; 698 - case 'never': 699 - return { 700 - expression: neverTypeToZodSchema({ 701 - schema: schema as SchemaWithType<'never'>, 702 - }), 703 - }; 704 - case 'null': 705 - return { 706 - expression: nullTypeToZodSchema({ 707 - schema: schema as SchemaWithType<'null'>, 708 - }), 709 - }; 710 - case 'object': 711 - return objectTypeToZodSchema({ 712 - plugin, 713 - schema: schema as SchemaWithType<'object'>, 714 - state, 715 - }); 716 - case 'string': 717 - return { 718 - expression: stringTypeToZodSchema({ 719 - plugin, 720 - schema: schema as SchemaWithType<'string'>, 721 - }), 722 - }; 723 - case 'tuple': 724 - return { 725 - expression: tupleTypeToZodSchema({ 726 - plugin, 727 - schema: schema as SchemaWithType<'tuple'>, 728 - state, 729 - }), 730 - }; 731 - case 'undefined': 732 - return { 733 - expression: undefinedTypeToZodSchema({ 734 - schema: schema as SchemaWithType<'undefined'>, 735 - }), 736 - }; 737 - case 'unknown': 738 - return { 739 - expression: unknownTypeToZodSchema({ 740 - schema: schema as SchemaWithType<'unknown'>, 741 - }), 742 - }; 743 - case 'void': 744 - return { 745 - expression: voidTypeToZodSchema({ 746 - schema: schema as SchemaWithType<'void'>, 747 - }), 748 - }; 749 - } 750 - }; 751 - 752 - export const schemaToZodSchema = ({ 753 - optional, 754 - plugin, 755 - schema, 756 - state, 757 - }: { 758 - /** 759 - * Accept `optional` to handle optional object properties. We can't handle 760 - * this inside the object function because `.optional()` must come before 761 - * `.default()` which is handled in this function. 762 - */ 763 - optional?: boolean; 764 - plugin: ZodPlugin['Instance']; 765 - schema: IR.SchemaObject; 766 - state: State; 767 - }): ZodSchema => { 768 - const file = plugin.context.file({ id: zodId })!; 769 - 770 - let zodSchema: Partial<ZodSchema> = {}; 771 - 772 - if (schema.$ref) { 773 - const isCircularReference = state.circularReferenceTracker.includes( 774 - schema.$ref, 775 - ); 776 - state.circularReferenceTracker.push(schema.$ref); 777 - 778 - const id = plugin.api.getId({ type: 'ref', value: schema.$ref }); 779 - 780 - if (isCircularReference) { 781 - const expression = file.addNodeReference(id, { 782 - factory: (text) => compiler.identifier({ text }), 783 - }); 784 - zodSchema.expression = compiler.callExpression({ 785 - functionName: compiler.propertyAccessExpression({ 786 - expression: identifiers.z, 787 - name: identifiers.lazy, 788 - }), 789 - parameters: [ 790 - compiler.arrowFunction({ 791 - statements: [compiler.returnStatement({ expression })], 792 - }), 793 - ], 794 - }); 795 - state.hasCircularReference = true; 796 - } else if (!file.getName(id)) { 797 - // if $ref hasn't been processed yet, inline it to avoid the 798 - // "Block-scoped variable used before its declaration." error 799 - // this could be (maybe?) fixed by reshuffling the generation order 800 - const ref = plugin.context.resolveIrRef<IR.SchemaObject>(schema.$ref); 801 - handleComponent({ 802 - id: schema.$ref, 803 - plugin, 804 - schema: ref, 805 - state, 806 - }); 807 - } 808 - 809 - if (!isCircularReference) { 810 - const expression = file.addNodeReference(id, { 811 - factory: (text) => compiler.identifier({ text }), 812 - }); 813 - zodSchema.expression = expression; 814 - } 815 - 816 - state.circularReferenceTracker.pop(); 817 - } else if (schema.type) { 818 - const zSchema = schemaTypeToZodSchema({ plugin, schema, state }); 819 - zodSchema.expression = zSchema.expression; 820 - zodSchema.typeName = zSchema.anyType; 2 + import { handlerV3 } from './v3/plugin'; 821 3 822 - if (plugin.config.metadata && schema.description) { 823 - zodSchema.expression = compiler.callExpression({ 824 - functionName: compiler.propertyAccessExpression({ 825 - expression: zodSchema.expression, 826 - name: identifiers.describe, 827 - }), 828 - parameters: [compiler.stringLiteral({ text: schema.description })], 829 - }); 830 - } 831 - } else if (schema.items) { 832 - schema = deduplicateSchema({ schema }); 4 + export const handler: ZodPlugin['Handler'] = (args) => { 5 + const { plugin } = args; 833 6 834 - if (schema.items) { 835 - const itemTypes = schema.items.map( 836 - (item) => 837 - schemaToZodSchema({ 838 - plugin, 839 - schema: item, 840 - state, 841 - }).expression, 842 - ); 843 - 844 - if (schema.logicalOperator === 'and') { 845 - const firstSchema = schema.items[0]!; 846 - // we want to add an intersection, but not every schema can use the same API. 847 - // if the first item contains another array or not an object, we cannot use 848 - // `.merge()` as that does not exist on `.union()` and non-object schemas. 849 - if ( 850 - firstSchema.logicalOperator === 'or' || 851 - (firstSchema.type && firstSchema.type !== 'object') 852 - ) { 853 - zodSchema.expression = compiler.callExpression({ 854 - functionName: compiler.propertyAccessExpression({ 855 - expression: identifiers.z, 856 - name: identifiers.intersection, 857 - }), 858 - parameters: itemTypes, 859 - }); 860 - } else { 861 - zodSchema.expression = itemTypes[0]; 862 - itemTypes.slice(1).forEach((item) => { 863 - zodSchema.expression = compiler.callExpression({ 864 - functionName: compiler.propertyAccessExpression({ 865 - expression: zodSchema.expression!, 866 - name: identifiers.and, 867 - }), 868 - parameters: [item], 869 - }); 870 - }); 871 - } 872 - } else { 873 - zodSchema.expression = compiler.callExpression({ 874 - functionName: compiler.propertyAccessExpression({ 875 - expression: identifiers.z, 876 - name: identifiers.union, 877 - }), 878 - parameters: [ 879 - compiler.arrayLiteralExpression({ 880 - elements: itemTypes, 881 - }), 882 - ], 883 - }); 884 - } 885 - } else { 886 - zodSchema = schemaToZodSchema({ plugin, schema, state }); 887 - } 888 - } else { 889 - // catch-all fallback for failed schemas 890 - const zSchema = schemaTypeToZodSchema({ 891 - plugin, 892 - schema: { 893 - type: 'unknown', 894 - }, 895 - state, 896 - }); 897 - zodSchema.expression = zSchema.expression; 898 - zodSchema.typeName = zSchema.anyType; 7 + switch (plugin.config.compatibilityVersion) { 8 + case 3: 9 + return handlerV3(args); 10 + case 4: 11 + case 'mini': 12 + default: 13 + // TODO: handle Zod 4 14 + // TODO: handle Zod Mini 15 + return handlerV3(args); 899 16 } 900 - 901 - if (zodSchema.expression) { 902 - if (schema.accessScope === 'read') { 903 - zodSchema.expression = compiler.callExpression({ 904 - functionName: compiler.propertyAccessExpression({ 905 - expression: zodSchema.expression, 906 - name: identifiers.readonly, 907 - }), 908 - }); 909 - } 910 - 911 - if (optional) { 912 - zodSchema.expression = compiler.callExpression({ 913 - functionName: compiler.propertyAccessExpression({ 914 - expression: zodSchema.expression, 915 - name: identifiers.optional, 916 - }), 917 - }); 918 - } 919 - 920 - if (schema.default !== undefined) { 921 - const isBigInt = schema.type === 'integer' && schema.format === 'int64'; 922 - const callParameter = numberParameter({ 923 - isBigInt, 924 - value: schema.default, 925 - }); 926 - if (callParameter) { 927 - zodSchema.expression = compiler.callExpression({ 928 - functionName: compiler.propertyAccessExpression({ 929 - expression: zodSchema.expression, 930 - name: identifiers.default, 931 - }), 932 - parameters: [callParameter], 933 - }); 934 - } 935 - } 936 - } 937 - 938 - if (state.hasCircularReference) { 939 - if (!zodSchema.typeName) { 940 - zodSchema.typeName = 'ZodTypeAny'; 941 - } 942 - } else { 943 - zodSchema.typeName = undefined; 944 - } 945 - 946 - return zodSchema as ZodSchema; 947 - }; 948 - 949 - const handleComponent = ({ 950 - id, 951 - plugin, 952 - schema, 953 - state, 954 - }: { 955 - id: string; 956 - plugin: ZodPlugin['Instance']; 957 - schema: IR.SchemaObject; 958 - state?: State; 959 - }): void => { 960 - if (!state) { 961 - state = { 962 - circularReferenceTracker: [id], 963 - hasCircularReference: false, 964 - }; 965 - } 966 - 967 - const file = plugin.context.file({ id: zodId })!; 968 - const schemaId = plugin.api.getId({ type: 'ref', value: id }); 969 - 970 - if (file.getName(schemaId)) return; 971 - 972 - const zodSchema = schemaToZodSchema({ plugin, schema, state }); 973 - const typeInferId = plugin.config.definitions.types.infer.enabled 974 - ? plugin.api.getId({ type: 'type-infer-ref', value: id }) 975 - : undefined; 976 - exportZodSchema({ 977 - plugin, 978 - schema, 979 - schemaId, 980 - typeInferId, 981 - zodSchema, 982 - }); 983 - const baseName = refToName(id); 984 - file.updateNodeReferences( 985 - schemaId, 986 - buildName({ 987 - config: plugin.config.definitions, 988 - name: baseName, 989 - }), 990 - ); 991 - if (typeInferId) { 992 - file.updateNodeReferences( 993 - typeInferId, 994 - buildName({ 995 - config: plugin.config.definitions.types.infer, 996 - name: baseName, 997 - }), 998 - ); 999 - } 1000 - }; 1001 - 1002 - export const handler: ZodPlugin['Handler'] = ({ plugin }) => { 1003 - const file = plugin.createFile({ 1004 - case: plugin.config.case, 1005 - id: zodId, 1006 - path: plugin.output, 1007 - }); 1008 - 1009 - file.import({ 1010 - module: 'zod', 1011 - name: 'z', 1012 - }); 1013 - 1014 - plugin.forEach('operation', 'parameter', 'requestBody', 'schema', (event) => { 1015 - if (event.type === 'operation') { 1016 - operationToZodSchema({ operation: event.operation, plugin }); 1017 - } else if (event.type === 'parameter') { 1018 - handleComponent({ 1019 - id: event.$ref, 1020 - plugin, 1021 - schema: event.parameter.schema, 1022 - }); 1023 - } else if (event.type === 'requestBody') { 1024 - handleComponent({ 1025 - id: event.$ref, 1026 - plugin, 1027 - schema: event.requestBody.schema, 1028 - }); 1029 - } else if (event.type === 'schema') { 1030 - handleComponent({ 1031 - id: event.$ref, 1032 - plugin, 1033 - schema: event.schema, 1034 - }); 1035 - } 1036 - }); 1037 17 };
+6
packages/openapi-ts/src/plugins/zod/shared/types.d.ts
··· 1 + import type ts from 'typescript'; 2 + 3 + export type ZodSchema = { 4 + expression: ts.Expression; 5 + typeName?: string; 6 + };
+22
packages/openapi-ts/src/plugins/zod/types.d.ts
··· 16 16 */ 17 17 comments?: boolean; 18 18 /** 19 + * The compatibility version to target for generated output. 20 + * 21 + * Can be: 22 + * - `4`: [Zod 4](https://zod.dev/packages/zod) (default). 23 + * - `3`: [Zod 3](https://v3.zod.dev/). 24 + * - `'mini'`: [Zod Mini](https://zod.dev/packages/mini). 25 + * 26 + * @default 4 27 + */ 28 + compatibilityVersion?: 3 | 4 | 'mini'; 29 + /** 19 30 * Configuration for date handling in generated Zod schemas. 20 31 * 21 32 * Controls how date values are processed and validated using Zod's ··· 336 347 * @default true 337 348 */ 338 349 comments: boolean; 350 + /** 351 + * The compatibility version to target for generated output. 352 + * 353 + * Can be: 354 + * - `4`: [Zod 4](https://zod.dev/packages/zod) (default). 355 + * - `3`: [Zod 3](https://v3.zod.dev/). 356 + * - `'mini'`: [Zod Mini](https://zod.dev/packages/mini). 357 + * 358 + * @default 4 359 + */ 360 + compatibilityVersion: 3 | 4 | 'mini'; 339 361 /** 340 362 * Configuration for date handling in generated Zod schemas. 341 363 *
+1033
packages/openapi-ts/src/plugins/zod/v3/plugin.ts
··· 1 + import ts from 'typescript'; 2 + 3 + import { compiler } from '../../../compiler'; 4 + import { deduplicateSchema } from '../../../ir/schema'; 5 + import type { IR } from '../../../ir/types'; 6 + import { buildName } from '../../../openApi/shared/utils/name'; 7 + import { refToName } from '../../../utils/ref'; 8 + import { numberRegExp } from '../../../utils/regexp'; 9 + import { identifiers, zodId } from '../constants'; 10 + import { exportZodSchema } from '../export'; 11 + import type { ZodSchema } from '../shared/types'; 12 + import type { ZodPlugin } from '../types'; 13 + import { operationToZodSchema } from './operation'; 14 + 15 + interface SchemaWithType<T extends Required<IR.SchemaObject>['type']> 16 + extends Omit<IR.SchemaObject, 'type'> { 17 + type: Extract<Required<IR.SchemaObject>['type'], T>; 18 + } 19 + 20 + export type State = { 21 + circularReferenceTracker: Array<string>; 22 + hasCircularReference: boolean; 23 + }; 24 + 25 + const arrayTypeToZodSchema = ({ 26 + plugin, 27 + schema, 28 + state, 29 + }: { 30 + plugin: ZodPlugin['Instance']; 31 + schema: SchemaWithType<'array'>; 32 + state: State; 33 + }): ts.CallExpression => { 34 + const functionName = compiler.propertyAccessExpression({ 35 + expression: identifiers.z, 36 + name: identifiers.array, 37 + }); 38 + 39 + let arrayExpression: ts.CallExpression | undefined; 40 + 41 + if (!schema.items) { 42 + arrayExpression = compiler.callExpression({ 43 + functionName, 44 + parameters: [ 45 + unknownTypeToZodSchema({ 46 + schema: { 47 + type: 'unknown', 48 + }, 49 + }), 50 + ], 51 + }); 52 + } else { 53 + schema = deduplicateSchema({ schema }); 54 + 55 + // at least one item is guaranteed 56 + const itemExpressions = schema.items!.map( 57 + (item) => 58 + schemaToZodSchema({ 59 + plugin, 60 + schema: item, 61 + state, 62 + }).expression, 63 + ); 64 + 65 + if (itemExpressions.length === 1) { 66 + arrayExpression = compiler.callExpression({ 67 + functionName, 68 + parameters: itemExpressions, 69 + }); 70 + } else { 71 + if (schema.logicalOperator === 'and') { 72 + // TODO: parser - handle intersection 73 + // return compiler.typeArrayNode( 74 + // compiler.typeIntersectionNode({ types: itemExpressions }), 75 + // ); 76 + } 77 + 78 + arrayExpression = compiler.callExpression({ 79 + functionName: compiler.propertyAccessExpression({ 80 + expression: identifiers.z, 81 + name: identifiers.array, 82 + }), 83 + parameters: [ 84 + compiler.callExpression({ 85 + functionName: compiler.propertyAccessExpression({ 86 + expression: identifiers.z, 87 + name: identifiers.union, 88 + }), 89 + parameters: [ 90 + compiler.arrayLiteralExpression({ 91 + elements: itemExpressions, 92 + }), 93 + ], 94 + }), 95 + ], 96 + }); 97 + } 98 + } 99 + 100 + if (schema.minItems === schema.maxItems && schema.minItems !== undefined) { 101 + arrayExpression = compiler.callExpression({ 102 + functionName: compiler.propertyAccessExpression({ 103 + expression: arrayExpression, 104 + name: identifiers.length, 105 + }), 106 + parameters: [compiler.valueToExpression({ value: schema.minItems })], 107 + }); 108 + } else { 109 + if (schema.minItems !== undefined) { 110 + arrayExpression = compiler.callExpression({ 111 + functionName: compiler.propertyAccessExpression({ 112 + expression: arrayExpression, 113 + name: identifiers.min, 114 + }), 115 + parameters: [compiler.valueToExpression({ value: schema.minItems })], 116 + }); 117 + } 118 + 119 + if (schema.maxItems !== undefined) { 120 + arrayExpression = compiler.callExpression({ 121 + functionName: compiler.propertyAccessExpression({ 122 + expression: arrayExpression, 123 + name: identifiers.max, 124 + }), 125 + parameters: [compiler.valueToExpression({ value: schema.maxItems })], 126 + }); 127 + } 128 + } 129 + 130 + return arrayExpression; 131 + }; 132 + 133 + const booleanTypeToZodSchema = ({ 134 + schema, 135 + }: { 136 + schema: SchemaWithType<'boolean'>; 137 + }) => { 138 + if (typeof schema.const === 'boolean') { 139 + const expression = compiler.callExpression({ 140 + functionName: compiler.propertyAccessExpression({ 141 + expression: identifiers.z, 142 + name: identifiers.literal, 143 + }), 144 + parameters: [compiler.ots.boolean(schema.const)], 145 + }); 146 + return expression; 147 + } 148 + 149 + const expression = compiler.callExpression({ 150 + functionName: compiler.propertyAccessExpression({ 151 + expression: identifiers.z, 152 + name: identifiers.boolean, 153 + }), 154 + }); 155 + return expression; 156 + }; 157 + 158 + const enumTypeToZodSchema = ({ 159 + schema, 160 + }: { 161 + schema: SchemaWithType<'enum'>; 162 + }): ts.CallExpression => { 163 + const enumMembers: Array<ts.LiteralExpression> = []; 164 + 165 + let isNullable = false; 166 + 167 + for (const item of schema.items ?? []) { 168 + // Zod supports only string enums 169 + if (item.type === 'string' && typeof item.const === 'string') { 170 + enumMembers.push( 171 + compiler.stringLiteral({ 172 + text: item.const, 173 + }), 174 + ); 175 + } else if (item.type === 'null' || item.const === null) { 176 + isNullable = true; 177 + } 178 + } 179 + 180 + if (!enumMembers.length) { 181 + return unknownTypeToZodSchema({ 182 + schema: { 183 + type: 'unknown', 184 + }, 185 + }); 186 + } 187 + 188 + let enumExpression = compiler.callExpression({ 189 + functionName: compiler.propertyAccessExpression({ 190 + expression: identifiers.z, 191 + name: identifiers.enum, 192 + }), 193 + parameters: [ 194 + compiler.arrayLiteralExpression({ 195 + elements: enumMembers, 196 + multiLine: false, 197 + }), 198 + ], 199 + }); 200 + 201 + if (isNullable) { 202 + enumExpression = compiler.callExpression({ 203 + functionName: compiler.propertyAccessExpression({ 204 + expression: enumExpression, 205 + name: identifiers.nullable, 206 + }), 207 + }); 208 + } 209 + 210 + return enumExpression; 211 + }; 212 + 213 + // eslint-disable-next-line @typescript-eslint/no-unused-vars 214 + const neverTypeToZodSchema = (_props: { schema: SchemaWithType<'never'> }) => { 215 + const expression = compiler.callExpression({ 216 + functionName: compiler.propertyAccessExpression({ 217 + expression: identifiers.z, 218 + name: identifiers.never, 219 + }), 220 + }); 221 + return expression; 222 + }; 223 + 224 + // eslint-disable-next-line @typescript-eslint/no-unused-vars 225 + const nullTypeToZodSchema = (_props: { schema: SchemaWithType<'null'> }) => { 226 + const expression = compiler.callExpression({ 227 + functionName: compiler.propertyAccessExpression({ 228 + expression: identifiers.z, 229 + name: identifiers.null, 230 + }), 231 + }); 232 + return expression; 233 + }; 234 + 235 + const numberParameter = ({ 236 + isBigInt, 237 + value, 238 + }: { 239 + isBigInt: boolean; 240 + value: unknown; 241 + }) => { 242 + const expression = compiler.valueToExpression({ value }); 243 + 244 + if ( 245 + isBigInt && 246 + (typeof value === 'bigint' || 247 + typeof value === 'number' || 248 + typeof value === 'string' || 249 + typeof value === 'boolean') 250 + ) { 251 + return compiler.callExpression({ 252 + functionName: 'BigInt', 253 + parameters: [expression], 254 + }); 255 + } 256 + 257 + return expression; 258 + }; 259 + 260 + const numberTypeToZodSchema = ({ 261 + schema, 262 + }: { 263 + schema: SchemaWithType<'integer' | 'number'>; 264 + }) => { 265 + const isBigInt = schema.type === 'integer' && schema.format === 'int64'; 266 + 267 + if (typeof schema.const === 'number') { 268 + // TODO: parser - handle bigint constants 269 + const expression = compiler.callExpression({ 270 + functionName: compiler.propertyAccessExpression({ 271 + expression: identifiers.z, 272 + name: identifiers.literal, 273 + }), 274 + parameters: [compiler.ots.number(schema.const)], 275 + }); 276 + return expression; 277 + } 278 + 279 + let numberExpression = compiler.callExpression({ 280 + functionName: isBigInt 281 + ? compiler.propertyAccessExpression({ 282 + expression: compiler.propertyAccessExpression({ 283 + expression: identifiers.z, 284 + name: identifiers.coerce, 285 + }), 286 + name: identifiers.bigint, 287 + }) 288 + : compiler.propertyAccessExpression({ 289 + expression: identifiers.z, 290 + name: identifiers.number, 291 + }), 292 + }); 293 + 294 + if (!isBigInt && schema.type === 'integer') { 295 + numberExpression = compiler.callExpression({ 296 + functionName: compiler.propertyAccessExpression({ 297 + expression: numberExpression, 298 + name: identifiers.int, 299 + }), 300 + }); 301 + } 302 + 303 + if (schema.exclusiveMinimum !== undefined) { 304 + numberExpression = compiler.callExpression({ 305 + functionName: compiler.propertyAccessExpression({ 306 + expression: numberExpression, 307 + name: identifiers.gt, 308 + }), 309 + parameters: [ 310 + numberParameter({ isBigInt, value: schema.exclusiveMinimum }), 311 + ], 312 + }); 313 + } else if (schema.minimum !== undefined) { 314 + numberExpression = compiler.callExpression({ 315 + functionName: compiler.propertyAccessExpression({ 316 + expression: numberExpression, 317 + name: identifiers.gte, 318 + }), 319 + parameters: [numberParameter({ isBigInt, value: schema.minimum })], 320 + }); 321 + } 322 + 323 + if (schema.exclusiveMaximum !== undefined) { 324 + numberExpression = compiler.callExpression({ 325 + functionName: compiler.propertyAccessExpression({ 326 + expression: numberExpression, 327 + name: identifiers.lt, 328 + }), 329 + parameters: [ 330 + numberParameter({ isBigInt, value: schema.exclusiveMaximum }), 331 + ], 332 + }); 333 + } else if (schema.maximum !== undefined) { 334 + numberExpression = compiler.callExpression({ 335 + functionName: compiler.propertyAccessExpression({ 336 + expression: numberExpression, 337 + name: identifiers.lte, 338 + }), 339 + parameters: [numberParameter({ isBigInt, value: schema.maximum })], 340 + }); 341 + } 342 + 343 + return numberExpression; 344 + }; 345 + 346 + const objectTypeToZodSchema = ({ 347 + plugin, 348 + schema, 349 + state, 350 + }: { 351 + plugin: ZodPlugin['Instance']; 352 + schema: SchemaWithType<'object'>; 353 + state: State; 354 + }): { 355 + anyType: string; 356 + expression: ts.CallExpression; 357 + } => { 358 + // TODO: parser - handle constants 359 + const properties: Array<ts.PropertyAssignment> = []; 360 + 361 + const required = schema.required ?? []; 362 + 363 + for (const name in schema.properties) { 364 + const property = schema.properties[name]!; 365 + const isRequired = required.includes(name); 366 + 367 + const propertyExpression = schemaToZodSchema({ 368 + optional: !isRequired, 369 + plugin, 370 + schema: property, 371 + state, 372 + }).expression; 373 + 374 + numberRegExp.lastIndex = 0; 375 + let propertyName; 376 + if (numberRegExp.test(name)) { 377 + // For numeric literals, we'll handle negative numbers by using a string literal 378 + // instead of trying to use a PrefixUnaryExpression 379 + propertyName = name.startsWith('-') 380 + ? ts.factory.createStringLiteral(name) 381 + : ts.factory.createNumericLiteral(name); 382 + } else { 383 + propertyName = name; 384 + } 385 + // TODO: parser - abstract safe property name logic 386 + if ( 387 + ((name.match(/^[0-9]/) && name.match(/\D+/g)) || name.match(/\W/g)) && 388 + !name.startsWith("'") && 389 + !name.endsWith("'") 390 + ) { 391 + propertyName = `'${name}'`; 392 + } 393 + properties.push( 394 + compiler.propertyAssignment({ 395 + initializer: propertyExpression, 396 + name: propertyName, 397 + }), 398 + ); 399 + } 400 + 401 + if ( 402 + schema.additionalProperties && 403 + schema.additionalProperties.type === 'object' && 404 + !Object.keys(properties).length 405 + ) { 406 + const zodSchema = schemaToZodSchema({ 407 + plugin, 408 + schema: schema.additionalProperties, 409 + state, 410 + }).expression; 411 + const expression = compiler.callExpression({ 412 + functionName: compiler.propertyAccessExpression({ 413 + expression: identifiers.z, 414 + name: identifiers.record, 415 + }), 416 + parameters: [zodSchema], 417 + }); 418 + return { 419 + anyType: 'AnyZodObject', 420 + expression, 421 + }; 422 + } 423 + 424 + const expression = compiler.callExpression({ 425 + functionName: compiler.propertyAccessExpression({ 426 + expression: identifiers.z, 427 + name: identifiers.object, 428 + }), 429 + parameters: [ts.factory.createObjectLiteralExpression(properties, true)], 430 + }); 431 + return { 432 + anyType: 'AnyZodObject', 433 + expression, 434 + }; 435 + }; 436 + 437 + const stringTypeToZodSchema = ({ 438 + plugin, 439 + schema, 440 + }: { 441 + plugin: ZodPlugin['Instance']; 442 + schema: SchemaWithType<'string'>; 443 + }) => { 444 + if (typeof schema.const === 'string') { 445 + const expression = compiler.callExpression({ 446 + functionName: compiler.propertyAccessExpression({ 447 + expression: identifiers.z, 448 + name: identifiers.literal, 449 + }), 450 + parameters: [compiler.ots.string(schema.const)], 451 + }); 452 + return expression; 453 + } 454 + 455 + let stringExpression = compiler.callExpression({ 456 + functionName: compiler.propertyAccessExpression({ 457 + expression: identifiers.z, 458 + name: identifiers.string, 459 + }), 460 + }); 461 + 462 + if (schema.format) { 463 + switch (schema.format) { 464 + case 'date-time': 465 + stringExpression = compiler.callExpression({ 466 + functionName: compiler.propertyAccessExpression({ 467 + expression: stringExpression, 468 + name: identifiers.datetime, 469 + }), 470 + parameters: plugin.config.dates.offset 471 + ? [ 472 + compiler.objectExpression({ 473 + obj: [ 474 + { 475 + key: 'offset', 476 + value: true, 477 + }, 478 + ], 479 + }), 480 + ] 481 + : [], 482 + }); 483 + break; 484 + case 'ipv4': 485 + case 'ipv6': 486 + stringExpression = compiler.callExpression({ 487 + functionName: compiler.propertyAccessExpression({ 488 + expression: stringExpression, 489 + name: identifiers.ip, 490 + }), 491 + }); 492 + break; 493 + case 'uri': 494 + stringExpression = compiler.callExpression({ 495 + functionName: compiler.propertyAccessExpression({ 496 + expression: stringExpression, 497 + name: identifiers.url, 498 + }), 499 + }); 500 + break; 501 + case 'date': 502 + case 'email': 503 + case 'time': 504 + case 'uuid': 505 + stringExpression = compiler.callExpression({ 506 + functionName: compiler.propertyAccessExpression({ 507 + expression: stringExpression, 508 + name: compiler.identifier({ text: schema.format }), 509 + }), 510 + }); 511 + break; 512 + } 513 + } 514 + 515 + if (schema.minLength === schema.maxLength && schema.minLength !== undefined) { 516 + stringExpression = compiler.callExpression({ 517 + functionName: compiler.propertyAccessExpression({ 518 + expression: stringExpression, 519 + name: identifiers.length, 520 + }), 521 + parameters: [compiler.valueToExpression({ value: schema.minLength })], 522 + }); 523 + } else { 524 + if (schema.minLength !== undefined) { 525 + stringExpression = compiler.callExpression({ 526 + functionName: compiler.propertyAccessExpression({ 527 + expression: stringExpression, 528 + name: identifiers.min, 529 + }), 530 + parameters: [compiler.valueToExpression({ value: schema.minLength })], 531 + }); 532 + } 533 + 534 + if (schema.maxLength !== undefined) { 535 + stringExpression = compiler.callExpression({ 536 + functionName: compiler.propertyAccessExpression({ 537 + expression: stringExpression, 538 + name: identifiers.max, 539 + }), 540 + parameters: [compiler.valueToExpression({ value: schema.maxLength })], 541 + }); 542 + } 543 + } 544 + 545 + if (schema.pattern) { 546 + stringExpression = compiler.callExpression({ 547 + functionName: compiler.propertyAccessExpression({ 548 + expression: stringExpression, 549 + name: identifiers.regex, 550 + }), 551 + parameters: [compiler.regularExpressionLiteral({ text: schema.pattern })], 552 + }); 553 + } 554 + 555 + return stringExpression; 556 + }; 557 + 558 + const tupleTypeToZodSchema = ({ 559 + plugin, 560 + schema, 561 + state, 562 + }: { 563 + plugin: ZodPlugin['Instance']; 564 + schema: SchemaWithType<'tuple'>; 565 + state: State; 566 + }) => { 567 + if (schema.const && Array.isArray(schema.const)) { 568 + const tupleElements = schema.const.map((value) => 569 + compiler.callExpression({ 570 + functionName: compiler.propertyAccessExpression({ 571 + expression: identifiers.z, 572 + name: identifiers.literal, 573 + }), 574 + parameters: [compiler.valueToExpression({ value })], 575 + }), 576 + ); 577 + const expression = compiler.callExpression({ 578 + functionName: compiler.propertyAccessExpression({ 579 + expression: identifiers.z, 580 + name: identifiers.tuple, 581 + }), 582 + parameters: [ 583 + compiler.arrayLiteralExpression({ 584 + elements: tupleElements, 585 + }), 586 + ], 587 + }); 588 + return expression; 589 + } 590 + 591 + const tupleElements: Array<ts.Expression> = []; 592 + 593 + for (const item of schema.items ?? []) { 594 + tupleElements.push( 595 + schemaToZodSchema({ 596 + plugin, 597 + schema: item, 598 + state, 599 + }).expression, 600 + ); 601 + } 602 + 603 + const expression = compiler.callExpression({ 604 + functionName: compiler.propertyAccessExpression({ 605 + expression: identifiers.z, 606 + name: identifiers.tuple, 607 + }), 608 + parameters: [ 609 + compiler.arrayLiteralExpression({ 610 + elements: tupleElements, 611 + }), 612 + ], 613 + }); 614 + return expression; 615 + }; 616 + 617 + // eslint-disable-next-line @typescript-eslint/no-unused-vars 618 + const undefinedTypeToZodSchema = (_props: { 619 + schema: SchemaWithType<'undefined'>; 620 + }) => { 621 + const expression = compiler.callExpression({ 622 + functionName: compiler.propertyAccessExpression({ 623 + expression: identifiers.z, 624 + name: identifiers.undefined, 625 + }), 626 + }); 627 + return expression; 628 + }; 629 + 630 + // eslint-disable-next-line @typescript-eslint/no-unused-vars 631 + const unknownTypeToZodSchema = (_props: { 632 + schema: SchemaWithType<'unknown'>; 633 + }) => { 634 + const expression = compiler.callExpression({ 635 + functionName: compiler.propertyAccessExpression({ 636 + expression: identifiers.z, 637 + name: identifiers.unknown, 638 + }), 639 + }); 640 + return expression; 641 + }; 642 + 643 + // eslint-disable-next-line @typescript-eslint/no-unused-vars 644 + const voidTypeToZodSchema = (_props: { schema: SchemaWithType<'void'> }) => { 645 + const expression = compiler.callExpression({ 646 + functionName: compiler.propertyAccessExpression({ 647 + expression: identifiers.z, 648 + name: identifiers.void, 649 + }), 650 + }); 651 + return expression; 652 + }; 653 + 654 + const schemaTypeToZodSchema = ({ 655 + plugin, 656 + schema, 657 + state, 658 + }: { 659 + plugin: ZodPlugin['Instance']; 660 + schema: IR.SchemaObject; 661 + state: State; 662 + }): { 663 + anyType?: string; 664 + expression: ts.Expression; 665 + } => { 666 + switch (schema.type as Required<IR.SchemaObject>['type']) { 667 + case 'array': 668 + return { 669 + expression: arrayTypeToZodSchema({ 670 + plugin, 671 + schema: schema as SchemaWithType<'array'>, 672 + state, 673 + }), 674 + }; 675 + case 'boolean': 676 + return { 677 + expression: booleanTypeToZodSchema({ 678 + schema: schema as SchemaWithType<'boolean'>, 679 + }), 680 + }; 681 + case 'enum': 682 + return { 683 + expression: enumTypeToZodSchema({ 684 + schema: schema as SchemaWithType<'enum'>, 685 + }), 686 + }; 687 + case 'integer': 688 + case 'number': 689 + return { 690 + expression: numberTypeToZodSchema({ 691 + schema: schema as SchemaWithType<'integer' | 'number'>, 692 + }), 693 + }; 694 + case 'never': 695 + return { 696 + expression: neverTypeToZodSchema({ 697 + schema: schema as SchemaWithType<'never'>, 698 + }), 699 + }; 700 + case 'null': 701 + return { 702 + expression: nullTypeToZodSchema({ 703 + schema: schema as SchemaWithType<'null'>, 704 + }), 705 + }; 706 + case 'object': 707 + return objectTypeToZodSchema({ 708 + plugin, 709 + schema: schema as SchemaWithType<'object'>, 710 + state, 711 + }); 712 + case 'string': 713 + return { 714 + expression: stringTypeToZodSchema({ 715 + plugin, 716 + schema: schema as SchemaWithType<'string'>, 717 + }), 718 + }; 719 + case 'tuple': 720 + return { 721 + expression: tupleTypeToZodSchema({ 722 + plugin, 723 + schema: schema as SchemaWithType<'tuple'>, 724 + state, 725 + }), 726 + }; 727 + case 'undefined': 728 + return { 729 + expression: undefinedTypeToZodSchema({ 730 + schema: schema as SchemaWithType<'undefined'>, 731 + }), 732 + }; 733 + case 'unknown': 734 + return { 735 + expression: unknownTypeToZodSchema({ 736 + schema: schema as SchemaWithType<'unknown'>, 737 + }), 738 + }; 739 + case 'void': 740 + return { 741 + expression: voidTypeToZodSchema({ 742 + schema: schema as SchemaWithType<'void'>, 743 + }), 744 + }; 745 + } 746 + }; 747 + 748 + export const schemaToZodSchema = ({ 749 + optional, 750 + plugin, 751 + schema, 752 + state, 753 + }: { 754 + /** 755 + * Accept `optional` to handle optional object properties. We can't handle 756 + * this inside the object function because `.optional()` must come before 757 + * `.default()` which is handled in this function. 758 + */ 759 + optional?: boolean; 760 + plugin: ZodPlugin['Instance']; 761 + schema: IR.SchemaObject; 762 + state: State; 763 + }): ZodSchema => { 764 + const file = plugin.context.file({ id: zodId })!; 765 + 766 + let zodSchema: Partial<ZodSchema> = {}; 767 + 768 + if (schema.$ref) { 769 + const isCircularReference = state.circularReferenceTracker.includes( 770 + schema.$ref, 771 + ); 772 + state.circularReferenceTracker.push(schema.$ref); 773 + 774 + const id = plugin.api.getId({ type: 'ref', value: schema.$ref }); 775 + 776 + if (isCircularReference) { 777 + const expression = file.addNodeReference(id, { 778 + factory: (text) => compiler.identifier({ text }), 779 + }); 780 + zodSchema.expression = compiler.callExpression({ 781 + functionName: compiler.propertyAccessExpression({ 782 + expression: identifiers.z, 783 + name: identifiers.lazy, 784 + }), 785 + parameters: [ 786 + compiler.arrowFunction({ 787 + statements: [compiler.returnStatement({ expression })], 788 + }), 789 + ], 790 + }); 791 + state.hasCircularReference = true; 792 + } else if (!file.getName(id)) { 793 + // if $ref hasn't been processed yet, inline it to avoid the 794 + // "Block-scoped variable used before its declaration." error 795 + // this could be (maybe?) fixed by reshuffling the generation order 796 + const ref = plugin.context.resolveIrRef<IR.SchemaObject>(schema.$ref); 797 + handleComponent({ 798 + id: schema.$ref, 799 + plugin, 800 + schema: ref, 801 + state, 802 + }); 803 + } 804 + 805 + if (!isCircularReference) { 806 + const expression = file.addNodeReference(id, { 807 + factory: (text) => compiler.identifier({ text }), 808 + }); 809 + zodSchema.expression = expression; 810 + } 811 + 812 + state.circularReferenceTracker.pop(); 813 + } else if (schema.type) { 814 + const zSchema = schemaTypeToZodSchema({ plugin, schema, state }); 815 + zodSchema.expression = zSchema.expression; 816 + zodSchema.typeName = zSchema.anyType; 817 + 818 + if (plugin.config.metadata && schema.description) { 819 + zodSchema.expression = compiler.callExpression({ 820 + functionName: compiler.propertyAccessExpression({ 821 + expression: zodSchema.expression, 822 + name: identifiers.describe, 823 + }), 824 + parameters: [compiler.stringLiteral({ text: schema.description })], 825 + }); 826 + } 827 + } else if (schema.items) { 828 + schema = deduplicateSchema({ schema }); 829 + 830 + if (schema.items) { 831 + const itemTypes = schema.items.map( 832 + (item) => 833 + schemaToZodSchema({ 834 + plugin, 835 + schema: item, 836 + state, 837 + }).expression, 838 + ); 839 + 840 + if (schema.logicalOperator === 'and') { 841 + const firstSchema = schema.items[0]!; 842 + // we want to add an intersection, but not every schema can use the same API. 843 + // if the first item contains another array or not an object, we cannot use 844 + // `.merge()` as that does not exist on `.union()` and non-object schemas. 845 + if ( 846 + firstSchema.logicalOperator === 'or' || 847 + (firstSchema.type && firstSchema.type !== 'object') 848 + ) { 849 + zodSchema.expression = compiler.callExpression({ 850 + functionName: compiler.propertyAccessExpression({ 851 + expression: identifiers.z, 852 + name: identifiers.intersection, 853 + }), 854 + parameters: itemTypes, 855 + }); 856 + } else { 857 + zodSchema.expression = itemTypes[0]; 858 + itemTypes.slice(1).forEach((item) => { 859 + zodSchema.expression = compiler.callExpression({ 860 + functionName: compiler.propertyAccessExpression({ 861 + expression: zodSchema.expression!, 862 + name: identifiers.and, 863 + }), 864 + parameters: [item], 865 + }); 866 + }); 867 + } 868 + } else { 869 + zodSchema.expression = compiler.callExpression({ 870 + functionName: compiler.propertyAccessExpression({ 871 + expression: identifiers.z, 872 + name: identifiers.union, 873 + }), 874 + parameters: [ 875 + compiler.arrayLiteralExpression({ 876 + elements: itemTypes, 877 + }), 878 + ], 879 + }); 880 + } 881 + } else { 882 + zodSchema = schemaToZodSchema({ plugin, schema, state }); 883 + } 884 + } else { 885 + // catch-all fallback for failed schemas 886 + const zSchema = schemaTypeToZodSchema({ 887 + plugin, 888 + schema: { 889 + type: 'unknown', 890 + }, 891 + state, 892 + }); 893 + zodSchema.expression = zSchema.expression; 894 + zodSchema.typeName = zSchema.anyType; 895 + } 896 + 897 + if (zodSchema.expression) { 898 + if (schema.accessScope === 'read') { 899 + zodSchema.expression = compiler.callExpression({ 900 + functionName: compiler.propertyAccessExpression({ 901 + expression: zodSchema.expression, 902 + name: identifiers.readonly, 903 + }), 904 + }); 905 + } 906 + 907 + if (optional) { 908 + zodSchema.expression = compiler.callExpression({ 909 + functionName: compiler.propertyAccessExpression({ 910 + expression: zodSchema.expression, 911 + name: identifiers.optional, 912 + }), 913 + }); 914 + } 915 + 916 + if (schema.default !== undefined) { 917 + const isBigInt = schema.type === 'integer' && schema.format === 'int64'; 918 + const callParameter = numberParameter({ 919 + isBigInt, 920 + value: schema.default, 921 + }); 922 + if (callParameter) { 923 + zodSchema.expression = compiler.callExpression({ 924 + functionName: compiler.propertyAccessExpression({ 925 + expression: zodSchema.expression, 926 + name: identifiers.default, 927 + }), 928 + parameters: [callParameter], 929 + }); 930 + } 931 + } 932 + } 933 + 934 + if (state.hasCircularReference) { 935 + if (!zodSchema.typeName) { 936 + zodSchema.typeName = 'ZodTypeAny'; 937 + } 938 + } else { 939 + zodSchema.typeName = undefined; 940 + } 941 + 942 + return zodSchema as ZodSchema; 943 + }; 944 + 945 + const handleComponent = ({ 946 + id, 947 + plugin, 948 + schema, 949 + state, 950 + }: { 951 + id: string; 952 + plugin: ZodPlugin['Instance']; 953 + schema: IR.SchemaObject; 954 + state?: State; 955 + }): void => { 956 + if (!state) { 957 + state = { 958 + circularReferenceTracker: [id], 959 + hasCircularReference: false, 960 + }; 961 + } 962 + 963 + const file = plugin.context.file({ id: zodId })!; 964 + const schemaId = plugin.api.getId({ type: 'ref', value: id }); 965 + 966 + if (file.getName(schemaId)) return; 967 + 968 + const zodSchema = schemaToZodSchema({ plugin, schema, state }); 969 + const typeInferId = plugin.config.definitions.types.infer.enabled 970 + ? plugin.api.getId({ type: 'type-infer-ref', value: id }) 971 + : undefined; 972 + exportZodSchema({ 973 + plugin, 974 + schema, 975 + schemaId, 976 + typeInferId, 977 + zodSchema, 978 + }); 979 + const baseName = refToName(id); 980 + file.updateNodeReferences( 981 + schemaId, 982 + buildName({ 983 + config: plugin.config.definitions, 984 + name: baseName, 985 + }), 986 + ); 987 + if (typeInferId) { 988 + file.updateNodeReferences( 989 + typeInferId, 990 + buildName({ 991 + config: plugin.config.definitions.types.infer, 992 + name: baseName, 993 + }), 994 + ); 995 + } 996 + }; 997 + 998 + export const handlerV3: ZodPlugin['Handler'] = ({ plugin }) => { 999 + const file = plugin.createFile({ 1000 + case: plugin.config.case, 1001 + id: zodId, 1002 + path: plugin.output, 1003 + }); 1004 + 1005 + file.import({ 1006 + module: 'zod', 1007 + name: 'z', 1008 + }); 1009 + 1010 + plugin.forEach('operation', 'parameter', 'requestBody', 'schema', (event) => { 1011 + if (event.type === 'operation') { 1012 + operationToZodSchema({ operation: event.operation, plugin }); 1013 + } else if (event.type === 'parameter') { 1014 + handleComponent({ 1015 + id: event.$ref, 1016 + plugin, 1017 + schema: event.parameter.schema, 1018 + }); 1019 + } else if (event.type === 'requestBody') { 1020 + handleComponent({ 1021 + id: event.$ref, 1022 + plugin, 1023 + schema: event.requestBody.schema, 1024 + }); 1025 + } else if (event.type === 'schema') { 1026 + handleComponent({ 1027 + id: event.$ref, 1028 + plugin, 1029 + schema: event.schema, 1030 + }); 1031 + } 1032 + }); 1033 + };
+105 -315
pnpm-lock.yaml
··· 329 329 specifier: 4.5.0 330 330 version: 4.5.0(vue@3.5.13(typescript@5.8.3)) 331 331 zod: 332 - specifier: 3.23.8 333 - version: 3.23.8 332 + specifier: 3.25.0 333 + version: 3.25.0 334 334 devDependencies: 335 335 vite: 336 336 specifier: 6.2.7 ··· 357 357 specifier: 1.1.0 358 358 version: 1.1.0(typescript@5.8.3) 359 359 zod: 360 - specifier: 3.23.8 361 - version: 3.23.8 360 + specifier: 3.25.0 361 + version: 3.25.0 362 362 devDependencies: 363 363 '@config/vite-base': 364 364 specifier: workspace:* ··· 807 807 open: 808 808 specifier: 10.1.2 809 809 version: 10.1.2 810 + semver: 811 + specifier: 7.7.2 812 + version: 7.7.2 810 813 devDependencies: 811 814 '@config/vite-base': 812 815 specifier: workspace:* ··· 820 823 '@types/express': 821 824 specifier: 4.17.21 822 825 version: 4.17.21 826 + '@types/semver': 827 + specifier: 7.7.0 828 + version: 7.7.0 823 829 axios: 824 830 specifier: 1.8.2 825 831 version: 1.8.2 ··· 840 846 version: 3.3.2 841 847 nuxt: 842 848 specifier: 3.14.1592 843 - version: 3.14.1592(@parcel/watcher@2.5.1)(@types/node@22.10.5)(db0@0.3.1)(encoding@0.1.13)(eslint@9.17.0(jiti@2.4.2))(ioredis@5.6.0)(less@4.2.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.41.1)(sass@1.85.0)(terser@5.39.0)(typescript@5.8.3)(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)) 849 + version: 3.14.1592(@parcel/watcher@2.5.1)(@types/node@22.10.5)(db0@0.3.1)(encoding@0.1.13)(eslint@9.17.0(jiti@2.4.2))(ioredis@5.6.0)(less@4.2.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.41.1)(sass@1.85.0)(terser@5.39.0)(typescript@5.8.3)(vite@6.2.7(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.0)) 844 850 prettier: 845 851 specifier: 3.4.2 846 852 version: 3.4.2 ··· 974 980 specifier: 3.5.13 975 981 version: 3.5.13(typescript@5.8.3) 976 982 zod: 977 - specifier: 3.23.8 978 - version: 3.23.8 983 + specifier: 3.25.0 984 + version: 3.25.0 979 985 980 986 packages/vite-plugin: 981 987 devDependencies: ··· 5196 5202 '@types/retry@0.12.2': 5197 5203 resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==} 5198 5204 5199 - '@types/semver@7.5.8': 5200 - resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} 5205 + '@types/semver@7.7.0': 5206 + resolution: {integrity: sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==} 5201 5207 5202 5208 '@types/send@0.17.4': 5203 5209 resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} ··· 10300 10306 engines: {node: '>=10'} 10301 10307 hasBin: true 10302 10308 10309 + semver@7.7.2: 10310 + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} 10311 + engines: {node: '>=10'} 10312 + hasBin: true 10313 + 10303 10314 send@0.19.0: 10304 10315 resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} 10305 10316 engines: {node: '>= 0.8.0'} ··· 12040 12051 zod@3.23.8: 12041 12052 resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} 12042 12053 12054 + zod@3.25.0: 12055 + resolution: {integrity: sha512-ficnZKUW0mlNivqeJkosTEkGbJ6NKCtSaOHGx5aXbtfeWMdRyzXLbAIn19my4C/KB7WPY/p9vlGPt+qpOp6c4Q==} 12056 + 12043 12057 zone.js@0.15.0: 12044 12058 resolution: {integrity: sha512-9oxn0IIjbCZkJ67L+LkhYWRyAy7axphb3VgE2MBDlOqnmHMPWGYMxJxBYFueFq/JGY2GMwS0rU+UCLunEmy5UA==} 12045 12059 ··· 12173 12187 dependencies: 12174 12188 '@ampproject/remapping': 2.3.0 12175 12189 '@angular-devkit/architect': 0.1902.0(chokidar@4.0.3) 12176 - '@angular-devkit/build-webpack': 0.1902.0(chokidar@4.0.3)(webpack-dev-server@5.2.0(webpack@5.98.0(esbuild@0.25.2)))(webpack@5.98.0(esbuild@0.25.0)) 12190 + '@angular-devkit/build-webpack': 0.1902.0(chokidar@4.0.3)(webpack-dev-server@5.2.0(webpack@5.98.0(esbuild@0.25.0)))(webpack@5.98.0(esbuild@0.25.0)) 12177 12191 '@angular-devkit/core': 19.2.0(chokidar@4.0.3) 12178 12192 '@angular/build': 19.2.0(@angular/compiler-cli@19.2.0(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.15.0)))(typescript@5.8.3))(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.15.0)))(@types/node@22.10.5)(chokidar@4.0.3)(jiti@2.4.2)(karma@6.4.4)(less@4.2.2)(postcss@8.5.2)(tailwindcss@3.4.9(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.8.3)))(terser@5.39.0)(typescript@5.8.3)(yaml@2.8.0) 12179 12193 '@angular/compiler-cli': 19.2.0(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.15.0)))(typescript@5.8.3) ··· 12223 12237 tree-kill: 1.2.2 12224 12238 tslib: 2.8.1 12225 12239 typescript: 5.8.3 12226 - webpack: 5.98.0(esbuild@0.25.0) 12227 - webpack-dev-middleware: 7.4.2(webpack@5.98.0(esbuild@0.25.2)) 12228 - webpack-dev-server: 5.2.0(webpack@5.98.0(esbuild@0.25.2)) 12240 + webpack: 5.98.0(esbuild@0.25.2) 12241 + webpack-dev-middleware: 7.4.2(webpack@5.98.0(esbuild@0.25.0)) 12242 + webpack-dev-server: 5.2.0(webpack@5.98.0(esbuild@0.25.0)) 12229 12243 webpack-merge: 6.0.1 12230 12244 webpack-subresource-integrity: 5.1.0(webpack@5.98.0(esbuild@0.25.0)) 12231 12245 optionalDependencies: ··· 12259 12273 dependencies: 12260 12274 '@ampproject/remapping': 2.3.0 12261 12275 '@angular-devkit/architect': 0.1902.0(chokidar@4.0.3) 12262 - '@angular-devkit/build-webpack': 0.1902.0(chokidar@4.0.3)(webpack-dev-server@5.2.0(webpack@5.98.0(esbuild@0.25.2)))(webpack@5.98.0(esbuild@0.25.0)) 12276 + '@angular-devkit/build-webpack': 0.1902.0(chokidar@4.0.3)(webpack-dev-server@5.2.0(webpack@5.98.0(esbuild@0.25.0)))(webpack@5.98.0(esbuild@0.25.0)) 12263 12277 '@angular-devkit/core': 19.2.0(chokidar@4.0.3) 12264 12278 '@angular/build': 19.2.0(@angular/compiler-cli@19.2.0(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.15.0)))(typescript@5.8.3))(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.15.0)))(@types/node@22.10.5)(chokidar@4.0.3)(jiti@2.4.2)(karma@6.4.4)(less@4.2.2)(postcss@8.5.2)(tailwindcss@3.4.9(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.8.3)))(terser@5.39.0)(typescript@5.8.3)(yaml@2.8.0) 12265 12279 '@angular/compiler-cli': 19.2.0(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.15.0)))(typescript@5.8.3) ··· 12309 12323 tree-kill: 1.2.2 12310 12324 tslib: 2.8.1 12311 12325 typescript: 5.8.3 12312 - webpack: 5.98.0(esbuild@0.25.0) 12313 - webpack-dev-middleware: 7.4.2(webpack@5.98.0(esbuild@0.25.2)) 12314 - webpack-dev-server: 5.2.0(webpack@5.98.0(esbuild@0.25.2)) 12326 + webpack: 5.98.0(esbuild@0.25.2) 12327 + webpack-dev-middleware: 7.4.2(webpack@5.98.0(esbuild@0.25.0)) 12328 + webpack-dev-server: 5.2.0(webpack@5.98.0(esbuild@0.25.0)) 12315 12329 webpack-merge: 6.0.1 12316 12330 webpack-subresource-integrity: 5.1.0(webpack@5.98.0(esbuild@0.25.0)) 12317 12331 optionalDependencies: ··· 12341 12355 - webpack-cli 12342 12356 - yaml 12343 12357 12344 - '@angular-devkit/build-webpack@0.1902.0(chokidar@4.0.3)(webpack-dev-server@5.2.0(webpack@5.98.0(esbuild@0.25.2)))(webpack@5.98.0(esbuild@0.25.0))': 12358 + '@angular-devkit/build-webpack@0.1902.0(chokidar@4.0.3)(webpack-dev-server@5.2.0(webpack@5.98.0(esbuild@0.25.0)))(webpack@5.98.0(esbuild@0.25.0))': 12345 12359 dependencies: 12346 12360 '@angular-devkit/architect': 0.1902.0(chokidar@4.0.3) 12347 12361 rxjs: 7.8.1 12348 - webpack: 5.98.0(esbuild@0.25.0) 12349 - webpack-dev-server: 5.2.0(webpack@5.98.0(esbuild@0.25.2)) 12362 + webpack: 5.98.0(esbuild@0.25.2) 12363 + webpack-dev-server: 5.2.0(webpack@5.98.0(esbuild@0.25.0)) 12350 12364 transitivePeerDependencies: 12351 12365 - chokidar 12352 12366 ··· 12544 12558 commander: 10.0.1 12545 12559 marked: 9.1.6 12546 12560 marked-terminal: 7.3.0(marked@9.1.6) 12547 - semver: 7.7.1 12561 + semver: 7.7.2 12548 12562 12549 12563 '@arethetypeswrong/core@0.17.4': 12550 12564 dependencies: ··· 12553 12567 cjs-module-lexer: 1.4.3 12554 12568 fflate: 0.8.2 12555 12569 lru-cache: 10.4.3 12556 - semver: 7.7.1 12570 + semver: 7.7.2 12557 12571 typescript: 5.6.1-rc 12558 12572 validate-npm-package-name: 5.0.1 12559 12573 ··· 13350 13364 outdent: 0.5.0 13351 13365 prettier: 2.8.8 13352 13366 resolve-from: 5.0.0 13353 - semver: 7.7.1 13367 + semver: 7.7.2 13354 13368 13355 13369 '@changesets/assemble-release-plan@6.0.6': 13356 13370 dependencies: ··· 13359 13373 '@changesets/should-skip-package': 0.1.2 13360 13374 '@changesets/types': 6.1.0 13361 13375 '@manypkg/get-packages': 1.1.3 13362 - semver: 7.7.1 13376 + semver: 7.7.2 13363 13377 13364 13378 '@changesets/changelog-git@0.2.1': 13365 13379 dependencies: ··· 13390 13404 '@changesets/types': 6.1.0 13391 13405 '@changesets/write': 0.3.2 13392 13406 '@manypkg/get-packages': 1.1.3 13393 - '@types/semver': 7.5.8 13407 + '@types/semver': 7.7.0 13394 13408 ansi-colors: 4.1.3 13395 13409 ci-info: 3.9.0 13396 13410 enquirer: 2.4.1 ··· 13402 13416 package-manager-detector: 0.2.11 13403 13417 picocolors: 1.1.1 13404 13418 resolve-from: 5.0.0 13405 - semver: 7.7.1 13419 + semver: 7.7.2 13406 13420 spawndamnit: 2.0.0 13407 13421 term-size: 2.2.1 13408 13422 ··· 13425 13439 '@changesets/types': 6.1.0 13426 13440 '@manypkg/get-packages': 1.1.3 13427 13441 picocolors: 1.1.1 13428 - semver: 7.7.1 13442 + semver: 7.7.2 13429 13443 13430 13444 '@changesets/get-github-info@0.6.0(encoding@0.1.13)': 13431 13445 dependencies: ··· 14402 14416 https-proxy-agent: 7.0.6(supports-color@9.4.0) 14403 14417 node-fetch: 2.7.0(encoding@0.1.13) 14404 14418 nopt: 8.1.0 14405 - semver: 7.7.1 14419 + semver: 7.7.2 14406 14420 tar: 7.4.3 14407 14421 transitivePeerDependencies: 14408 14422 - encoding ··· 14541 14555 dependencies: 14542 14556 '@angular/compiler-cli': 19.2.0(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.15.0)))(typescript@5.8.3) 14543 14557 typescript: 5.8.3 14544 - webpack: 5.98.0(esbuild@0.25.0) 14558 + webpack: 5.98.0(esbuild@0.25.2) 14545 14559 14546 14560 '@nodelib/fs.scandir@2.1.5': 14547 14561 dependencies: ··· 14569 14583 14570 14584 '@npmcli/fs@4.0.0': 14571 14585 dependencies: 14572 - semver: 7.7.1 14586 + semver: 7.7.2 14573 14587 14574 14588 '@npmcli/git@6.0.3': 14575 14589 dependencies: ··· 14579 14593 npm-pick-manifest: 10.0.0 14580 14594 proc-log: 5.0.0 14581 14595 promise-retry: 2.0.1 14582 - semver: 7.7.1 14596 + semver: 7.7.2 14583 14597 which: 5.0.0 14584 14598 14585 14599 '@npmcli/installed-package-contents@3.0.0': ··· 14596 14610 hosted-git-info: 8.0.2 14597 14611 json-parse-even-better-errors: 4.0.0 14598 14612 proc-log: 5.0.0 14599 - semver: 7.7.1 14613 + semver: 7.7.2 14600 14614 validate-npm-package-license: 3.0.4 14601 14615 14602 14616 '@npmcli/promise-spawn@8.0.2': ··· 14618 14632 14619 14633 '@nuxt/devalue@2.0.2': {} 14620 14634 14621 - '@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0))': 14622 - dependencies: 14623 - '@nuxt/kit': 3.15.4(magicast@0.3.5) 14624 - '@nuxt/schema': 3.16.2 14625 - execa: 7.2.0 14626 - vite: 5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0) 14627 - transitivePeerDependencies: 14628 - - magicast 14629 - - supports-color 14630 - 14631 14635 '@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(vite@6.2.7(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.0))': 14632 14636 dependencies: 14633 14637 '@nuxt/kit': 3.15.4(magicast@0.3.5) ··· 14649 14653 pkg-types: 1.3.1 14650 14654 prompts: 2.4.2 14651 14655 rc9: 2.1.2 14652 - semver: 7.7.1 14656 + semver: 7.7.2 14653 14657 14654 14658 '@nuxt/devtools@1.7.0(rollup@3.29.5)(vite@6.2.7(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.13(typescript@5.8.3))': 14655 14659 dependencies: ··· 14681 14685 pkg-types: 1.3.1 14682 14686 rc9: 2.1.2 14683 14687 scule: 1.3.0 14684 - semver: 7.7.1 14688 + semver: 7.7.2 14685 14689 simple-git: 3.27.0 14686 14690 sirv: 3.0.1 14687 14691 tinyglobby: 0.2.12 ··· 14698 14702 - utf-8-validate 14699 14703 - vue 14700 14704 14701 - '@nuxt/devtools@1.7.0(rollup@4.41.1)(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0))(vue@3.5.13(typescript@5.8.3))': 14702 - dependencies: 14703 - '@antfu/utils': 0.7.10 14704 - '@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)) 14705 - '@nuxt/devtools-wizard': 1.7.0 14706 - '@nuxt/kit': 3.15.4(magicast@0.3.5) 14707 - '@vue/devtools-core': 7.6.8(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0))(vue@3.5.13(typescript@5.8.3)) 14708 - '@vue/devtools-kit': 7.6.8 14709 - birpc: 0.2.19 14710 - consola: 3.4.2 14711 - cronstrue: 2.56.0 14712 - destr: 2.0.3 14713 - error-stack-parser-es: 0.1.5 14714 - execa: 7.2.0 14715 - fast-npm-meta: 0.2.2 14716 - flatted: 3.3.3 14717 - get-port-please: 3.1.2 14718 - hookable: 5.5.3 14719 - image-meta: 0.2.1 14720 - is-installed-globally: 1.0.0 14721 - launch-editor: 2.10.0 14722 - local-pkg: 0.5.1 14723 - magicast: 0.3.5 14724 - nypm: 0.4.1 14725 - ohash: 1.1.6 14726 - pathe: 1.1.2 14727 - perfect-debounce: 1.0.0 14728 - pkg-types: 1.3.1 14729 - rc9: 2.1.2 14730 - scule: 1.3.0 14731 - semver: 7.7.1 14732 - simple-git: 3.27.0 14733 - sirv: 3.0.1 14734 - tinyglobby: 0.2.12 14735 - unimport: 3.14.6(rollup@4.41.1) 14736 - vite: 5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0) 14737 - vite-plugin-inspect: 0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.41.1)(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)) 14738 - vite-plugin-vue-inspector: 5.3.1(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)) 14739 - which: 3.0.1 14740 - ws: 8.18.1 14741 - transitivePeerDependencies: 14742 - - bufferutil 14743 - - rollup 14744 - - supports-color 14745 - - utf-8-validate 14746 - - vue 14747 - 14748 14705 '@nuxt/devtools@1.7.0(rollup@4.41.1)(vite@6.2.7(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.13(typescript@5.8.3))': 14749 14706 dependencies: 14750 14707 '@antfu/utils': 0.7.10 ··· 14775 14732 pkg-types: 1.3.1 14776 14733 rc9: 2.1.2 14777 14734 scule: 1.3.0 14778 - semver: 7.7.1 14735 + semver: 7.7.2 14779 14736 simple-git: 3.27.0 14780 14737 sirv: 3.0.1 14781 14738 tinyglobby: 0.2.12 ··· 14809 14766 pathe: 1.1.2 14810 14767 pkg-types: 1.3.1 14811 14768 scule: 1.3.0 14812 - semver: 7.7.1 14769 + semver: 7.7.2 14813 14770 ufo: 1.5.4 14814 14771 unctx: 2.4.1 14815 14772 unimport: 3.14.6(rollup@3.29.5) ··· 14836 14793 pathe: 1.1.2 14837 14794 pkg-types: 1.3.1 14838 14795 scule: 1.3.0 14839 - semver: 7.7.1 14796 + semver: 7.7.2 14840 14797 ufo: 1.5.4 14841 14798 unctx: 2.4.1 14842 14799 unimport: 3.14.6(rollup@4.41.1) ··· 14890 14847 pathe: 2.0.3 14891 14848 pkg-types: 2.1.0 14892 14849 scule: 1.3.0 14893 - semver: 7.7.1 14850 + semver: 7.7.2 14894 14851 std-env: 3.8.1 14895 14852 ufo: 1.5.4 14896 14853 unctx: 2.4.1 ··· 16675 16632 16676 16633 '@types/retry@0.12.2': {} 16677 16634 16678 - '@types/semver@7.5.8': {} 16635 + '@types/semver@7.7.0': {} 16679 16636 16680 16637 '@types/send@0.17.4': 16681 16638 dependencies: ··· 16780 16737 debug: 4.4.0(supports-color@9.4.0) 16781 16738 globby: 11.1.0 16782 16739 is-glob: 4.0.3 16783 - semver: 7.7.1 16740 + semver: 7.7.2 16784 16741 tsutils: 3.21.0(typescript@5.8.3) 16785 16742 optionalDependencies: 16786 16743 typescript: 5.8.3 ··· 16795 16752 fast-glob: 3.3.3 16796 16753 is-glob: 4.0.3 16797 16754 minimatch: 9.0.5 16798 - semver: 7.7.1 16755 + semver: 7.7.2 16799 16756 ts-api-utils: 2.0.1(typescript@5.8.3) 16800 16757 typescript: 5.8.3 16801 16758 transitivePeerDependencies: ··· 16805 16762 dependencies: 16806 16763 '@eslint-community/eslint-utils': 4.5.0(eslint@9.17.0(jiti@2.4.2)) 16807 16764 '@types/json-schema': 7.0.15 16808 - '@types/semver': 7.5.8 16765 + '@types/semver': 7.7.0 16809 16766 '@typescript-eslint/scope-manager': 5.62.0 16810 16767 '@typescript-eslint/types': 5.62.0 16811 16768 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) 16812 16769 eslint: 9.17.0(jiti@2.4.2) 16813 16770 eslint-scope: 5.1.1 16814 - semver: 7.7.1 16771 + semver: 7.7.2 16815 16772 transitivePeerDependencies: 16816 16773 - supports-color 16817 16774 - typescript ··· 17091 17048 dependencies: 17092 17049 '@vue/devtools-kit': 7.7.2 17093 17050 17094 - '@vue/devtools-core@7.6.8(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0))(vue@3.5.13(typescript@5.8.3))': 17095 - dependencies: 17096 - '@vue/devtools-kit': 7.7.2 17097 - '@vue/devtools-shared': 7.7.2 17098 - mitt: 3.0.1 17099 - nanoid: 5.1.5 17100 - pathe: 1.1.2 17101 - vite-hot-client: 0.2.4(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)) 17102 - vue: 3.5.13(typescript@5.8.3) 17103 - transitivePeerDependencies: 17104 - - vite 17105 - 17106 17051 '@vue/devtools-core@7.6.8(vite@6.2.7(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.13(typescript@5.8.3))': 17107 17052 dependencies: 17108 17053 '@vue/devtools-kit': 7.7.2 ··· 17643 17588 17644 17589 axios@1.8.2: 17645 17590 dependencies: 17646 - follow-redirects: 1.15.9 17591 + follow-redirects: 1.15.9(debug@4.4.0) 17647 17592 form-data: 4.0.2 17648 17593 proxy-from-env: 1.1.0 17649 17594 transitivePeerDependencies: ··· 17658 17603 '@babel/core': 7.26.9 17659 17604 find-cache-dir: 4.0.0 17660 17605 schema-utils: 4.3.0 17661 - webpack: 5.98.0(esbuild@0.25.0) 17606 + webpack: 5.98.0(esbuild@0.25.2) 17662 17607 17663 17608 babel-plugin-polyfill-corejs2@0.4.12(@babel/core@7.26.9): 17664 17609 dependencies: ··· 18197 18142 normalize-path: 3.0.0 18198 18143 schema-utils: 4.3.0 18199 18144 serialize-javascript: 6.0.2 18200 - webpack: 5.98.0(esbuild@0.25.0) 18145 + webpack: 5.98.0(esbuild@0.25.2) 18201 18146 18202 18147 core-js-compat@3.41.0: 18203 18148 dependencies: ··· 18267 18212 postcss-modules-scope: 3.2.1(postcss@8.4.41) 18268 18213 postcss-modules-values: 4.0.0(postcss@8.4.41) 18269 18214 postcss-value-parser: 4.2.0 18270 - semver: 7.7.1 18215 + semver: 7.7.2 18271 18216 optionalDependencies: 18272 - webpack: 5.98.0(esbuild@0.25.0) 18217 + webpack: 5.98.0(esbuild@0.25.2) 18273 18218 18274 18219 css-select@5.1.0: 18275 18220 dependencies: ··· 18553 18498 '@one-ini/wasm': 0.1.1 18554 18499 commander: 10.0.1 18555 18500 minimatch: 9.0.1 18556 - semver: 7.7.1 18501 + semver: 7.7.2 18557 18502 18558 18503 ee-first@1.1.1: {} 18559 18504 ··· 18927 18872 eslint-compat-utils@0.5.1(eslint@9.17.0(jiti@2.4.2)): 18928 18873 dependencies: 18929 18874 eslint: 9.17.0(jiti@2.4.2) 18930 - semver: 7.7.1 18875 + semver: 7.7.2 18931 18876 18932 18877 eslint-config-next@15.1.6(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3): 18933 18878 dependencies: ··· 18937 18882 '@typescript-eslint/parser': 8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3) 18938 18883 eslint: 9.17.0(jiti@2.4.2) 18939 18884 eslint-import-resolver-node: 0.3.9 18940 - eslint-import-resolver-typescript: 3.8.5(eslint-plugin-import@2.31.0)(eslint@9.17.0(jiti@2.4.2)) 18941 - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-typescript@3.8.5)(eslint@9.17.0(jiti@2.4.2)) 18885 + eslint-import-resolver-typescript: 3.8.5(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)) 18886 + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-typescript@3.8.5(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)) 18942 18887 eslint-plugin-jsx-a11y: 6.10.2(eslint@9.17.0(jiti@2.4.2)) 18943 18888 eslint-plugin-react: 7.37.4(eslint@9.17.0(jiti@2.4.2)) 18944 18889 eslint-plugin-react-hooks: 5.2.0(eslint@9.17.0(jiti@2.4.2)) ··· 18961 18906 transitivePeerDependencies: 18962 18907 - supports-color 18963 18908 18964 - eslint-import-resolver-typescript@3.8.5(eslint-plugin-import@2.31.0)(eslint@9.17.0(jiti@2.4.2)): 18909 + eslint-import-resolver-typescript@3.8.5(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)): 18965 18910 dependencies: 18966 18911 '@nolyfill/is-core-module': 1.0.39 18967 18912 debug: 4.4.0(supports-color@9.4.0) ··· 18972 18917 stable-hash: 0.0.4 18973 18918 tinyglobby: 0.2.12 18974 18919 optionalDependencies: 18975 - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-typescript@3.8.5)(eslint@9.17.0(jiti@2.4.2)) 18920 + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-typescript@3.8.5(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)) 18976 18921 transitivePeerDependencies: 18977 18922 - supports-color 18978 18923 18979 - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.5)(eslint@9.17.0(jiti@2.4.2)): 18924 + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.5(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)): 18980 18925 dependencies: 18981 18926 debug: 3.2.7 18982 18927 optionalDependencies: 18983 18928 '@typescript-eslint/parser': 8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3) 18984 18929 eslint: 9.17.0(jiti@2.4.2) 18985 18930 eslint-import-resolver-node: 0.3.9 18986 - eslint-import-resolver-typescript: 3.8.5(eslint-plugin-import@2.31.0)(eslint@9.17.0(jiti@2.4.2)) 18931 + eslint-import-resolver-typescript: 3.8.5(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)) 18987 18932 transitivePeerDependencies: 18988 18933 - supports-color 18989 18934 18990 - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-typescript@3.8.5)(eslint@9.17.0(jiti@2.4.2)): 18935 + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-typescript@3.8.5(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)): 18991 18936 dependencies: 18992 18937 '@rtsao/scc': 1.1.0 18993 18938 array-includes: 3.1.8 ··· 18998 18943 doctrine: 2.1.0 18999 18944 eslint: 9.17.0(jiti@2.4.2) 19000 18945 eslint-import-resolver-node: 0.3.9 19001 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.5)(eslint@9.17.0(jiti@2.4.2)) 18946 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.5(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)) 19002 18947 hasown: 2.0.2 19003 18948 is-core-module: 2.16.1 19004 18949 is-glob: 4.0.3 ··· 19574 19519 focus-trap@7.6.4: 19575 19520 dependencies: 19576 19521 tabbable: 6.2.0 19577 - 19578 - follow-redirects@1.15.9: {} 19579 19522 19580 19523 follow-redirects@1.15.9(debug@4.4.0): 19581 19524 optionalDependencies: ··· 20160 20103 20161 20104 is-bun-module@1.3.0: 20162 20105 dependencies: 20163 - semver: 7.7.1 20106 + semver: 7.7.2 20164 20107 20165 20108 is-callable@1.2.7: {} 20166 20109 ··· 20359 20302 '@babel/parser': 7.26.10 20360 20303 '@istanbuljs/schema': 0.1.3 20361 20304 istanbul-lib-coverage: 3.2.2 20362 - semver: 7.7.1 20305 + semver: 7.7.2 20363 20306 transitivePeerDependencies: 20364 20307 - supports-color 20365 20308 ··· 20626 20569 dependencies: 20627 20570 less: 4.2.2 20628 20571 optionalDependencies: 20629 - webpack: 5.98.0(esbuild@0.25.0) 20572 + webpack: 5.98.0(esbuild@0.25.2) 20630 20573 20631 20574 less@4.2.2: 20632 20575 dependencies: ··· 20651 20594 dependencies: 20652 20595 webpack-sources: 3.2.3 20653 20596 optionalDependencies: 20654 - webpack: 5.98.0(esbuild@0.25.0) 20597 + webpack: 5.98.0(esbuild@0.25.2) 20655 20598 20656 20599 light-my-request@6.6.0: 20657 20600 dependencies: ··· 20859 20802 20860 20803 make-dir@4.0.0: 20861 20804 dependencies: 20862 - semver: 7.7.1 20805 + semver: 7.7.2 20863 20806 20864 20807 make-error@1.3.6: {} 20865 20808 ··· 20979 20922 dependencies: 20980 20923 schema-utils: 4.3.0 20981 20924 tapable: 2.2.1 20982 - webpack: 5.98.0(esbuild@0.25.0) 20925 + webpack: 5.98.0(esbuild@0.25.2) 20983 20926 20984 20927 minimalistic-assert@1.0.1: {} 20985 20928 ··· 21068 21011 pkg-types: 1.3.1 21069 21012 postcss: 8.5.4 21070 21013 postcss-nested: 6.2.0(postcss@8.5.4) 21071 - semver: 7.7.1 21014 + semver: 7.7.2 21072 21015 tinyglobby: 0.2.12 21073 21016 optionalDependencies: 21074 21017 sass: 1.85.0 ··· 21242 21185 rollup: 4.41.1 21243 21186 rollup-plugin-visualizer: 5.14.0(rollup@4.41.1) 21244 21187 scule: 1.3.0 21245 - semver: 7.7.1 21188 + semver: 7.7.2 21246 21189 serve-placeholder: 2.0.2 21247 21190 serve-static: 1.16.2 21248 21191 source-map: 0.7.4 ··· 21333 21276 make-fetch-happen: 14.0.3 21334 21277 nopt: 8.1.0 21335 21278 proc-log: 5.0.0 21336 - semver: 7.7.1 21279 + semver: 7.7.2 21337 21280 tar: 7.4.3 21338 21281 which: 5.0.0 21339 21282 transitivePeerDependencies: ··· 21361 21304 21362 21305 npm-install-checks@7.1.1: 21363 21306 dependencies: 21364 - semver: 7.7.1 21307 + semver: 7.7.2 21365 21308 21366 21309 npm-normalize-package-bin@3.0.1: {} 21367 21310 ··· 21371 21314 dependencies: 21372 21315 hosted-git-info: 8.0.2 21373 21316 proc-log: 5.0.0 21374 - semver: 7.7.1 21317 + semver: 7.7.2 21375 21318 validate-npm-package-name: 6.0.0 21376 21319 21377 21320 npm-packlist@9.0.0: ··· 21383 21326 npm-install-checks: 7.1.1 21384 21327 npm-normalize-package-bin: 4.0.0 21385 21328 npm-package-arg: 12.0.2 21386 - semver: 7.7.1 21329 + semver: 7.7.2 21387 21330 21388 21331 npm-registry-fetch@18.0.2: 21389 21332 dependencies: ··· 21547 21490 - vue-tsc 21548 21491 - xml2js 21549 21492 21550 - nuxt@3.14.1592(@parcel/watcher@2.5.1)(@types/node@22.10.5)(db0@0.3.1)(encoding@0.1.13)(eslint@9.17.0(jiti@2.4.2))(ioredis@5.6.0)(less@4.2.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.41.1)(sass@1.85.0)(terser@5.39.0)(typescript@5.8.3)(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)): 21551 - dependencies: 21552 - '@nuxt/devalue': 2.0.2 21553 - '@nuxt/devtools': 1.7.0(rollup@4.41.1)(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0))(vue@3.5.13(typescript@5.8.3)) 21554 - '@nuxt/kit': 3.14.1592(magicast@0.3.5)(rollup@4.41.1) 21555 - '@nuxt/schema': 3.14.1592(magicast@0.3.5)(rollup@4.41.1) 21556 - '@nuxt/telemetry': 2.6.5(magicast@0.3.5) 21557 - '@nuxt/vite-builder': 3.14.1592(@types/node@22.10.5)(eslint@9.17.0(jiti@2.4.2))(less@4.2.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.41.1)(sass@1.85.0)(terser@5.39.0)(typescript@5.8.3)(vue@3.5.13(typescript@5.8.3)) 21558 - '@unhead/dom': 1.11.20 21559 - '@unhead/shared': 1.11.20 21560 - '@unhead/ssr': 1.11.20 21561 - '@unhead/vue': 1.11.20(vue@3.5.13(typescript@5.8.3)) 21562 - '@vue/shared': 3.5.13 21563 - acorn: 8.14.0 21564 - c12: 2.0.1(magicast@0.3.5) 21565 - chokidar: 4.0.3 21566 - compatx: 0.1.8 21567 - consola: 3.4.2 21568 - cookie-es: 1.2.2 21569 - defu: 6.1.4 21570 - destr: 2.0.3 21571 - devalue: 5.1.1 21572 - errx: 0.1.0 21573 - esbuild: 0.24.2 21574 - escape-string-regexp: 5.0.0 21575 - estree-walker: 3.0.3 21576 - globby: 14.1.0 21577 - h3: 1.15.1 21578 - hookable: 5.5.3 21579 - ignore: 6.0.2 21580 - impound: 0.2.2(rollup@4.41.1) 21581 - jiti: 2.4.2 21582 - klona: 2.0.6 21583 - knitwork: 1.2.0 21584 - magic-string: 0.30.17 21585 - mlly: 1.7.4 21586 - nanotar: 0.1.1 21587 - nitropack: 2.11.6(encoding@0.1.13)(typescript@5.8.3) 21588 - nuxi: 3.22.5 21589 - nypm: 0.3.12 21590 - ofetch: 1.4.1 21591 - ohash: 1.1.6 21592 - pathe: 1.1.2 21593 - perfect-debounce: 1.0.0 21594 - pkg-types: 1.3.1 21595 - radix3: 1.1.2 21596 - scule: 1.3.0 21597 - semver: 7.7.1 21598 - std-env: 3.8.1 21599 - strip-literal: 2.1.1 21600 - tinyglobby: 0.2.10 21601 - ufo: 1.5.4 21602 - ultrahtml: 1.5.3 21603 - uncrypto: 0.1.3 21604 - unctx: 2.4.1 21605 - unenv: 1.10.0 21606 - unhead: 1.11.20 21607 - unimport: 3.14.6(rollup@4.41.1) 21608 - unplugin: 1.16.1 21609 - unplugin-vue-router: 0.10.9(rollup@4.41.1)(vue-router@4.5.0(vue@3.5.13(typescript@5.8.3)))(vue@3.5.13(typescript@5.8.3)) 21610 - unstorage: 1.15.0(db0@0.3.1)(ioredis@5.6.0) 21611 - untyped: 1.5.2 21612 - vue: 3.5.13(typescript@5.8.3) 21613 - vue-bundle-renderer: 2.1.1 21614 - vue-devtools-stub: 0.1.0 21615 - vue-router: 4.5.0(vue@3.5.13(typescript@5.8.3)) 21616 - optionalDependencies: 21617 - '@parcel/watcher': 2.5.1 21618 - '@types/node': 22.10.5 21619 - transitivePeerDependencies: 21620 - - '@azure/app-configuration' 21621 - - '@azure/cosmos' 21622 - - '@azure/data-tables' 21623 - - '@azure/identity' 21624 - - '@azure/keyvault-secrets' 21625 - - '@azure/storage-blob' 21626 - - '@biomejs/biome' 21627 - - '@capacitor/preferences' 21628 - - '@deno/kv' 21629 - - '@electric-sql/pglite' 21630 - - '@libsql/client' 21631 - - '@netlify/blobs' 21632 - - '@planetscale/database' 21633 - - '@upstash/redis' 21634 - - '@vercel/blob' 21635 - - '@vercel/kv' 21636 - - aws4fetch 21637 - - better-sqlite3 21638 - - bufferutil 21639 - - db0 21640 - - drizzle-orm 21641 - - encoding 21642 - - eslint 21643 - - idb-keyval 21644 - - ioredis 21645 - - less 21646 - - lightningcss 21647 - - magicast 21648 - - meow 21649 - - mysql2 21650 - - optionator 21651 - - rolldown 21652 - - rollup 21653 - - sass 21654 - - sass-embedded 21655 - - sqlite3 21656 - - stylelint 21657 - - stylus 21658 - - sugarss 21659 - - supports-color 21660 - - terser 21661 - - typescript 21662 - - uploadthing 21663 - - utf-8-validate 21664 - - vite 21665 - - vls 21666 - - vti 21667 - - vue-tsc 21668 - - xml2js 21669 - 21670 21493 nuxt@3.14.1592(@parcel/watcher@2.5.1)(@types/node@22.10.5)(db0@0.3.1)(encoding@0.1.13)(eslint@9.17.0(jiti@2.4.2))(ioredis@5.6.0)(less@4.2.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.41.1)(sass@1.85.0)(terser@5.39.0)(typescript@5.8.3)(vite@6.2.7(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.0)): 21671 21494 dependencies: 21672 21495 '@nuxt/devalue': 2.0.2 ··· 22307 22130 cosmiconfig: 9.0.0(typescript@5.8.3) 22308 22131 jiti: 1.21.7 22309 22132 postcss: 8.5.2 22310 - semver: 7.7.1 22133 + semver: 7.7.2 22311 22134 optionalDependencies: 22312 - webpack: 5.98.0(esbuild@0.25.0) 22135 + webpack: 5.98.0(esbuild@0.25.2) 22313 22136 transitivePeerDependencies: 22314 22137 - typescript 22315 22138 ··· 23066 22889 neo-async: 2.6.2 23067 22890 optionalDependencies: 23068 22891 sass: 1.85.0 23069 - webpack: 5.98.0(esbuild@0.25.0) 22892 + webpack: 5.98.0(esbuild@0.25.2) 23070 22893 23071 22894 sass@1.85.0: 23072 22895 dependencies: ··· 23115 22938 lru-cache: 6.0.0 23116 22939 23117 22940 semver@7.7.1: {} 22941 + 22942 + semver@7.7.2: {} 23118 22943 23119 22944 send@0.19.0: 23120 22945 dependencies: ··· 23406 23231 dependencies: 23407 23232 iconv-lite: 0.6.3 23408 23233 source-map-js: 1.2.1 23409 - webpack: 5.98.0(esbuild@0.25.0) 23234 + webpack: 5.98.0(esbuild@0.25.2) 23410 23235 23411 23236 source-map-support@0.5.21: 23412 23237 dependencies: ··· 23787 23612 23788 23613 term-size@2.2.1: {} 23789 23614 23790 - terser-webpack-plugin@5.3.14(esbuild@0.25.0)(webpack@5.98.0(esbuild@0.25.2)): 23615 + terser-webpack-plugin@5.3.14(esbuild@0.25.2)(webpack@5.98.0(esbuild@0.25.0)): 23791 23616 dependencies: 23792 23617 '@jridgewell/trace-mapping': 0.3.25 23793 23618 jest-worker: 27.5.1 23794 23619 schema-utils: 4.3.0 23795 23620 serialize-javascript: 6.0.2 23796 23621 terser: 5.39.0 23797 - webpack: 5.98.0(esbuild@0.25.0) 23622 + webpack: 5.98.0(esbuild@0.25.2) 23798 23623 optionalDependencies: 23799 - esbuild: 0.25.0 23624 + esbuild: 0.25.2 23800 23625 23801 23626 terser@5.39.0: 23802 23627 dependencies: ··· 24475 24300 '@types/unist': 3.0.3 24476 24301 vfile-message: 4.0.2 24477 24302 24478 - vite-hot-client@0.2.4(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)): 24479 - dependencies: 24480 - vite: 5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0) 24481 - 24482 24303 vite-hot-client@0.2.4(vite@6.2.7(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.0)): 24483 24304 dependencies: 24484 24305 vite: 6.2.7(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.0) ··· 24562 24383 - rollup 24563 24384 - supports-color 24564 24385 24565 - vite-plugin-inspect@0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.41.1)(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)): 24566 - dependencies: 24567 - '@antfu/utils': 0.7.10 24568 - '@rollup/pluginutils': 5.1.4(rollup@4.41.1) 24569 - debug: 4.4.0(supports-color@9.4.0) 24570 - error-stack-parser-es: 0.1.5 24571 - fs-extra: 11.3.0 24572 - open: 10.1.0 24573 - perfect-debounce: 1.0.0 24574 - picocolors: 1.1.1 24575 - sirv: 3.0.1 24576 - vite: 5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0) 24577 - optionalDependencies: 24578 - '@nuxt/kit': 3.15.4(magicast@0.3.5) 24579 - transitivePeerDependencies: 24580 - - rollup 24581 - - supports-color 24582 - 24583 24386 vite-plugin-inspect@0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.41.1)(vite@6.2.7(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.0)): 24584 24387 dependencies: 24585 24388 '@antfu/utils': 0.7.10 ··· 24614 24417 - supports-color 24615 24418 - vue 24616 24419 24617 - vite-plugin-vue-inspector@5.3.1(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)): 24618 - dependencies: 24619 - '@babel/core': 7.26.10 24620 - '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.10) 24621 - '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.10) 24622 - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.10) 24623 - '@babel/plugin-transform-typescript': 7.26.8(@babel/core@7.26.10) 24624 - '@vue/babel-plugin-jsx': 1.4.0(@babel/core@7.26.10) 24625 - '@vue/compiler-dom': 3.5.13 24626 - kolorist: 1.8.0 24627 - magic-string: 0.30.17 24628 - vite: 5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.39.0) 24629 - transitivePeerDependencies: 24630 - - supports-color 24631 - 24632 24420 vite-plugin-vue-inspector@5.3.1(vite@6.2.7(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.0)): 24633 24421 dependencies: 24634 24422 '@babel/core': 7.26.10 ··· 24822 24610 vscode-languageclient@7.0.0: 24823 24611 dependencies: 24824 24612 minimatch: 3.1.2 24825 - semver: 7.7.1 24613 + semver: 7.7.2 24826 24614 vscode-languageserver-protocol: 3.16.0 24827 24615 24828 24616 vscode-languageserver-protocol@3.16.0: ··· 24861 24649 espree: 9.6.1 24862 24650 esquery: 1.6.0 24863 24651 lodash: 4.17.21 24864 - semver: 7.7.1 24652 + semver: 7.7.2 24865 24653 transitivePeerDependencies: 24866 24654 - supports-color 24867 24655 ··· 24920 24708 24921 24709 webidl-conversions@7.0.0: {} 24922 24710 24923 - webpack-dev-middleware@7.4.2(webpack@5.98.0(esbuild@0.25.2)): 24711 + webpack-dev-middleware@7.4.2(webpack@5.98.0(esbuild@0.25.0)): 24924 24712 dependencies: 24925 24713 colorette: 2.0.20 24926 24714 memfs: 4.17.0 ··· 24929 24717 range-parser: 1.2.1 24930 24718 schema-utils: 4.3.0 24931 24719 optionalDependencies: 24932 - webpack: 5.98.0(esbuild@0.25.0) 24720 + webpack: 5.98.0(esbuild@0.25.2) 24933 24721 24934 - webpack-dev-server@5.2.0(webpack@5.98.0(esbuild@0.25.2)): 24722 + webpack-dev-server@5.2.0(webpack@5.98.0(esbuild@0.25.0)): 24935 24723 dependencies: 24936 24724 '@types/bonjour': 3.5.13 24937 24725 '@types/connect-history-api-fallback': 1.5.4 ··· 24958 24746 serve-index: 1.9.1 24959 24747 sockjs: 0.3.24 24960 24748 spdy: 4.0.2 24961 - webpack-dev-middleware: 7.4.2(webpack@5.98.0(esbuild@0.25.2)) 24749 + webpack-dev-middleware: 7.4.2(webpack@5.98.0(esbuild@0.25.0)) 24962 24750 ws: 8.18.1 24963 24751 optionalDependencies: 24964 - webpack: 5.98.0(esbuild@0.25.0) 24752 + webpack: 5.98.0(esbuild@0.25.2) 24965 24753 transitivePeerDependencies: 24966 24754 - bufferutil 24967 24755 - debug ··· 24979 24767 webpack-subresource-integrity@5.1.0(webpack@5.98.0(esbuild@0.25.0)): 24980 24768 dependencies: 24981 24769 typed-assert: 1.0.9 24982 - webpack: 5.98.0(esbuild@0.25.0) 24770 + webpack: 5.98.0(esbuild@0.25.2) 24983 24771 24984 24772 webpack-virtual-modules@0.6.2: {} 24985 24773 24986 - webpack@5.98.0(esbuild@0.25.0): 24774 + webpack@5.98.0(esbuild@0.25.2): 24987 24775 dependencies: 24988 24776 '@types/eslint-scope': 3.7.7 24989 24777 '@types/estree': 1.0.6 ··· 25005 24793 neo-async: 2.6.2 25006 24794 schema-utils: 4.3.0 25007 24795 tapable: 2.2.1 25008 - terser-webpack-plugin: 5.3.14(esbuild@0.25.0)(webpack@5.98.0(esbuild@0.25.2)) 24796 + terser-webpack-plugin: 5.3.14(esbuild@0.25.2)(webpack@5.98.0(esbuild@0.25.0)) 25009 24797 watchpack: 2.4.2 25010 24798 webpack-sources: 3.2.3 25011 24799 transitivePeerDependencies: ··· 25227 25015 readable-stream: 4.7.0 25228 25016 25229 25017 zod@3.23.8: {} 25018 + 25019 + zod@3.25.0: {} 25230 25020 25231 25021 zone.js@0.15.0: {} 25232 25022