From bd3ee982b2ccbdd9f1871873aef58cfc19fda815 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 7 Oct 2024 01:13:58 +0800 Subject: [PATCH 1/2] feat: zod plugin handles models --- packages/openapi-ts/package.json | 3 +- packages/openapi-ts/src/compiler/index.ts | 155 ------------- .../openapi-ts/src/generate/files/index.ts | 163 ++++++++++++++ .../openapi-ts/src/generate/files/name.ts | 80 +++++++ .../openapi-ts/src/generate/files/types.ts | 33 +++ packages/openapi-ts/src/generate/indexFile.ts | 3 +- packages/openapi-ts/src/generate/plugins.ts | 2 +- packages/openapi-ts/src/generate/schemas.ts | 3 +- packages/openapi-ts/src/generate/services.ts | 3 +- packages/openapi-ts/src/generate/types.ts | 16 +- packages/openapi-ts/src/plugins/zod/plugin.ts | 209 +++++++++++++++++- packages/openapi-ts/src/types/utils.ts | 2 +- pnpm-lock.yaml | 59 ++--- 13 files changed, 532 insertions(+), 199 deletions(-) create mode 100644 packages/openapi-ts/src/generate/files/index.ts create mode 100644 packages/openapi-ts/src/generate/files/name.ts create mode 100644 packages/openapi-ts/src/generate/files/types.ts diff --git a/packages/openapi-ts/package.json b/packages/openapi-ts/package.json index e298a0fbd..651f4dcf2 100644 --- a/packages/openapi-ts/package.json +++ b/packages/openapi-ts/package.json @@ -110,6 +110,7 @@ "rxjs": "7.8.1", "ts-node": "10.9.2", "tslib": "2.6.3", - "typescript": "5.5.3" + "typescript": "5.5.3", + "zod": "3.23.8" } } diff --git a/packages/openapi-ts/src/compiler/index.ts b/packages/openapi-ts/src/compiler/index.ts index 5b61fe262..7a880cf1f 100644 --- a/packages/openapi-ts/src/compiler/index.ts +++ b/packages/openapi-ts/src/compiler/index.ts @@ -1,9 +1,3 @@ -import { type PathLike, rmSync, writeFileSync } from 'node:fs'; -import path from 'node:path'; - -import type ts from 'typescript'; - -import { ensureDirSync } from '../generate/utils'; import * as classes from './classes'; import * as convert from './convert'; import * as module from './module'; @@ -18,155 +12,6 @@ export type { FunctionParameter } from './types'; export type { Comments } from './utils'; export type { ClassElement, Node, TypeNode } from 'typescript'; -const splitNameAndExtension = (fileName: string) => { - const match = fileName.match(/\.[0-9a-z]+$/i); - const extension = match ? match[0].slice(1) : ''; - const name = fileName.slice( - 0, - fileName.length - (extension ? extension.length + 1 : 0), - ); - return { extension, name }; -}; - -export class TypeScriptFile { - private _headers: Array = []; - private _imports = new Map< - string, - Map - >(); - private _items: Array = []; - private _name: string; - private _path: PathLike; - - public constructor({ - dir, - name, - header = true, - }: { - dir: string; - header?: boolean; - name: string; - }) { - this._name = this._setName(name); - this._path = path.resolve(dir, this.getName()); - - if (header) { - this._headers = [ - ...this._headers, - '// This file is auto-generated by @hey-api/openapi-ts', - ]; - } - } - - public add(...nodes: Array) { - this._items = [...this._items, ...nodes]; - } - - /** - * Adds an import to the provided module. Handles duplication, returns added import. - */ - public import({ - module, - ...importedItem - }: utils.ImportExportItemObject & { - module: string; - }): utils.ImportExportItemObject { - let moduleMap = this._imports.get(module); - - if (!moduleMap) { - moduleMap = new Map(); - this._imports.set(module, moduleMap); - } - - const match = moduleMap.get(importedItem.name); - if (match) { - return match; - } - - moduleMap.set(importedItem.name, importedItem); - return importedItem; - } - - public getName(withExtension = true) { - if (withExtension) { - return this._name; - } - - const { name } = splitNameAndExtension(this._name); - return name; - } - - public isEmpty() { - return !this._items.length; - } - - public remove(options?: Parameters[1]) { - rmSync(this._path, options); - } - - /** - * Removes last node form the stack. Works as undo. - */ - public removeNode() { - this._items = this._items.slice(0, this._items.length - 1); - } - - private _setName(fileName: string) { - if (fileName.includes('index')) { - return fileName; - } - - const { extension, name } = splitNameAndExtension(fileName); - return [name, 'gen', extension].filter(Boolean).join('.'); - } - - public toString(separator: string = '\n') { - let output: string[] = []; - if (this._headers.length) { - output = [...output, this._headers.join('\n')]; - } - let importsStringArray: string[] = []; - for (const [_module, moduleMap] of this._imports.entries()) { - const imports = Array.from(moduleMap.values()); - const node = compiler.namedImportDeclarations({ - imports, - module: _module, - }); - importsStringArray = [ - ...importsStringArray, - utils.tsNodeToString({ node }), - ]; - } - if (importsStringArray.length) { - output = [...output, importsStringArray.join('\n')]; - } - output = [ - ...output, - ...this._items.map((node) => - typeof node === 'string' - ? node - : utils.tsNodeToString({ node, unescape: true }), - ), - ]; - return output.join(separator); - } - - public write(separator = '\n') { - if (this.isEmpty()) { - this.remove({ force: true }); - return; - } - - let dir = this._path; - if (typeof this._path === 'string') { - const parts = this._path.split(path.sep); - dir = parts.slice(0, parts.length - 1).join(path.sep); - } - ensureDirSync(dir); - writeFileSync(this._path, this.toString(separator)); - } -} - export const compiler = { anonymousFunction: types.createAnonymousFunction, arrayLiteralExpression: types.createArrayLiteralExpression, diff --git a/packages/openapi-ts/src/generate/files/index.ts b/packages/openapi-ts/src/generate/files/index.ts new file mode 100644 index 000000000..f1c5f917e --- /dev/null +++ b/packages/openapi-ts/src/generate/files/index.ts @@ -0,0 +1,163 @@ +import { type PathLike, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +import type ts from 'typescript'; + +import { compiler } from '../../compiler'; +import { + type ImportExportItemObject, + tsNodeToString, +} from '../../compiler/utils'; +import { ensureDirSync } from '../utils'; +import { ensureUniqueIdentifier, splitNameAndExtension } from './name'; +import type { Namespaces } from './types'; + +export class TypeScriptFile { + private _headers: Array = []; + private _imports = new Map>(); + private _items: Array = []; + private _name: string; + private _path: PathLike; + + public namespaces: Namespaces = { + type: {}, + value: {}, + }; + + public constructor({ + dir, + name, + header = true, + }: { + dir: string; + header?: boolean; + name: string; + }) { + this._name = this._setName(name); + this._path = path.resolve(dir, this.getName()); + + if (header) { + this._headers = [ + ...this._headers, + '// This file is auto-generated by @hey-api/openapi-ts', + ]; + } + } + + public add(...nodes: Array) { + this._items = [...this._items, ...nodes]; + } + + public ensureUniqueIdentifier({ + namespace, + ...args + }: Omit[0], 'namespace'> & { + namespace: keyof Namespaces; + }) { + return ensureUniqueIdentifier({ + namespace: this.namespaces[namespace], + ...args, + }); + } + + /** + * Adds an import to the provided module. Handles duplication, returns added import. + */ + public import({ + module, + ...importedItem + }: ImportExportItemObject & { + module: string; + }): ImportExportItemObject { + let moduleMap = this._imports.get(module); + + if (!moduleMap) { + moduleMap = new Map(); + this._imports.set(module, moduleMap); + } + + const match = moduleMap.get(importedItem.name); + if (match) { + return match; + } + + moduleMap.set(importedItem.name, importedItem); + return importedItem; + } + + public getName(withExtension = true) { + if (withExtension) { + return this._name; + } + + const { name } = splitNameAndExtension(this._name); + return name; + } + + public isEmpty() { + return !this._items.length; + } + + public remove(options?: Parameters[1]) { + rmSync(this._path, options); + } + + /** + * Removes last node form the stack. Works as undo. + */ + public removeNode() { + this._items = this._items.slice(0, this._items.length - 1); + } + + private _setName(fileName: string) { + if (fileName.includes('index')) { + return fileName; + } + + const { extension, name } = splitNameAndExtension(fileName); + return [name, 'gen', extension].filter(Boolean).join('.'); + } + + public toString(separator: string = '\n') { + let output: string[] = []; + if (this._headers.length) { + output = [...output, this._headers.join('\n')]; + } + let importsStringArray: string[] = []; + for (const [_module, moduleMap] of this._imports.entries()) { + const imports = Array.from(moduleMap.values()); + const node = compiler.namedImportDeclarations({ + imports, + module: _module, + }); + importsStringArray = [...importsStringArray, tsNodeToString({ node })]; + } + if (importsStringArray.length) { + output = [...output, importsStringArray.join('\n')]; + } + output = [ + ...output, + ...this._items.map((node) => + typeof node === 'string' + ? node + : tsNodeToString({ node, unescape: true }), + ), + ]; + return output.join(separator); + } + + public write(separator = '\n') { + if (this.isEmpty()) { + this.remove({ force: true }); + return; + } + + let dir = this._path; + if (typeof this._path === 'string') { + const parts = this._path.split(path.sep); + dir = parts.slice(0, parts.length - 1).join(path.sep); + } + ensureDirSync(dir); + writeFileSync(this._path, this.toString(separator)); + } +} diff --git a/packages/openapi-ts/src/generate/files/name.ts b/packages/openapi-ts/src/generate/files/name.ts new file mode 100644 index 000000000..b6a1207c6 --- /dev/null +++ b/packages/openapi-ts/src/generate/files/name.ts @@ -0,0 +1,80 @@ +import type { ModelMeta } from '../../openApi'; +import type { EnsureUniqueIdentifierResult, Namespace } from './types'; + +export const ensureUniqueIdentifier = ({ + count = 1, + create = false, + meta, + nameTransformer, + namespace, +}: { + count?: number; + create?: boolean; + meta?: ModelMeta; + nameTransformer?: (value: string) => string; + namespace: Namespace; +}): EnsureUniqueIdentifierResult => { + if (!meta) { + return { + created: false, + name: '', + }; + } + + const refValue = namespace[meta.$ref]; + if (refValue) { + return { + created: false, + name: refValue.name, + }; + } + + let name = meta.name; + if (nameTransformer) { + name = nameTransformer(name); + } + if (count > 1) { + name = `${name}${count}`; + } + + const nameValue = namespace[name]; + if (!nameValue) { + if (create) { + namespace[name] = meta; + namespace[meta.$ref] = meta; + + return { + created: true, + name, + }; + } + } else if (nameValue.$ref === meta.$ref) { + return { + created: false, + name, + }; + } else { + return ensureUniqueIdentifier({ + count: count + 1, + create, + meta, + nameTransformer, + namespace, + }); + } + + return { + created: false, + name: '', + }; +}; + +export const splitNameAndExtension = (fileName: string) => { + const match = fileName.match(/\.[0-9a-z]+$/i); + const extension = match ? match[0].slice(1) : ''; + const name = fileName.slice( + 0, + fileName.length - (extension ? extension.length + 1 : 0), + ); + return { extension, name }; +}; diff --git a/packages/openapi-ts/src/generate/files/types.ts b/packages/openapi-ts/src/generate/files/types.ts new file mode 100644 index 000000000..99100a6bc --- /dev/null +++ b/packages/openapi-ts/src/generate/files/types.ts @@ -0,0 +1,33 @@ +import type { ModelMeta } from '../../openApi'; + +export type Namespace = Record; + +export interface Namespaces { + /** + * Type namespace. Types, interfaces, and type aliases exist here. + * @example + * ```ts + * export type Foo = string; + * ``` + */ + type: Namespace; + /** + * Value namespace. Variables, functions, classes, and constants exist here. + * @example + * ```js + * export const foo = ''; + * ``` + */ + value: Namespace; +} + +export interface EnsureUniqueIdentifierResult { + /** + * Did this function add a new property to the file's `identifiers` map? + */ + created: boolean; + /** + * Unique name for the resource. + */ + name: string; +} diff --git a/packages/openapi-ts/src/generate/indexFile.ts b/packages/openapi-ts/src/generate/indexFile.ts index 87d18d4e0..fbc2045c8 100644 --- a/packages/openapi-ts/src/generate/indexFile.ts +++ b/packages/openapi-ts/src/generate/indexFile.ts @@ -1,6 +1,7 @@ -import { compiler, TypeScriptFile } from '../compiler'; +import { compiler } from '../compiler'; import type { Files } from '../types/utils'; import { getConfig } from '../utils/config'; +import { TypeScriptFile } from './files'; export const generateIndexFile = async ({ files, diff --git a/packages/openapi-ts/src/generate/plugins.ts b/packages/openapi-ts/src/generate/plugins.ts index 597f07737..87e5cce29 100644 --- a/packages/openapi-ts/src/generate/plugins.ts +++ b/packages/openapi-ts/src/generate/plugins.ts @@ -1,9 +1,9 @@ import path from 'node:path'; -import { TypeScriptFile } from '../compiler'; import type { Client } from '../types/client'; import type { Files } from '../types/utils'; import { getConfig, isLegacyClient } from '../utils/config'; +import { TypeScriptFile } from './files'; export const generatePlugins = async ({ client, diff --git a/packages/openapi-ts/src/generate/schemas.ts b/packages/openapi-ts/src/generate/schemas.ts index bb2221244..7990119b6 100644 --- a/packages/openapi-ts/src/generate/schemas.ts +++ b/packages/openapi-ts/src/generate/schemas.ts @@ -1,8 +1,9 @@ -import { compiler, TypeScriptFile } from '../compiler'; +import { compiler } from '../compiler'; import type { OpenApi, OpenApiV2Schema, OpenApiV3Schema } from '../openApi'; import { ensureValidTypeScriptJavaScriptIdentifier } from '../openApi'; import type { Files } from '../types/utils'; import { getConfig } from '../utils/config'; +import { TypeScriptFile } from './files'; const ensureValidSchemaOutput = ( schema: unknown, diff --git a/packages/openapi-ts/src/generate/services.ts b/packages/openapi-ts/src/generate/services.ts index 07ce7cc58..a7f0c0022 100644 --- a/packages/openapi-ts/src/generate/services.ts +++ b/packages/openapi-ts/src/generate/services.ts @@ -4,7 +4,7 @@ import type { FunctionParameter, Node, } from '../compiler'; -import { compiler, TypeScriptFile } from '../compiler'; +import { compiler } from '../compiler'; import type { FunctionTypeParameter, ObjectValue } from '../compiler/types'; import { isOperationParameterRequired } from '../openApi'; import type { @@ -23,6 +23,7 @@ import { transformServiceName } from '../utils/transform'; import { setUniqueTypeName } from '../utils/type'; import { unique } from '../utils/unique'; import { clientModulePath, clientOptionsTypeName } from './client'; +import { TypeScriptFile } from './files'; type OnNode = (node: Node) => void; type OnImport = (name: string) => void; diff --git a/packages/openapi-ts/src/generate/types.ts b/packages/openapi-ts/src/generate/types.ts index 0be310b43..f6161eedf 100644 --- a/packages/openapi-ts/src/generate/types.ts +++ b/packages/openapi-ts/src/generate/types.ts @@ -1,14 +1,13 @@ import type { EnumDeclaration } from 'typescript'; -import { - type Comments, - compiler, - type Node, - TypeScriptFile, -} from '../compiler'; +import { type Comments, compiler, type Node } from '../compiler'; import { isOperationParameterRequired } from '../openApi'; -import type { Method, Model, OperationParameter } from '../types/client'; -import type { Client } from '../types/client'; +import type { + Client, + Method, + Model, + OperationParameter, +} from '../types/client'; import type { Files } from '../types/utils'; import { getConfig, isLegacyClient } from '../utils/config'; import { enumEntry, enumUnionType } from '../utils/enum'; @@ -19,6 +18,7 @@ import { type SetUniqueTypeNameResult, toType, } from '../utils/type'; +import { TypeScriptFile } from './files'; import { operationDataTypeName, operationErrorTypeName, diff --git a/packages/openapi-ts/src/plugins/zod/plugin.ts b/packages/openapi-ts/src/plugins/zod/plugin.ts index 1d98afbb5..2bcf76b5f 100644 --- a/packages/openapi-ts/src/plugins/zod/plugin.ts +++ b/packages/openapi-ts/src/plugins/zod/plugin.ts @@ -1,6 +1,211 @@ +import { compiler } from '../../compiler'; +import type { TypeScriptFile } from '../../generate/files'; +import type { Client, Model } from '../../types/client'; import type { PluginHandler } from '../types'; import type { PluginConfig } from './types'; -export const handler: PluginHandler = ({ plugin }) => { - console.warn(plugin); +interface TypesProps { + client: Client; + file: TypeScriptFile; + model: Model; + onRemoveNode?: VoidFunction; +} + +const processArray = ({ file, model }: TypesProps) => { + const identifier = file.ensureUniqueIdentifier({ + create: true, + meta: model.meta, + namespace: 'value', + }); + + if (!identifier.created) { + return; + } + + const zArrayExpression = compiler.callExpression({ + functionName: compiler.propertyAccessExpression({ + expression: 'z', + name: 'array', + }), + parameters: [ + compiler.callExpression({ + functionName: compiler.propertyAccessExpression({ + expression: 'z', + name: model.base, + }), + }), + ], + }); + + if (model.base === 'string' || model.base === 'boolean') { + const statement = compiler.constVariable({ + exportConst: true, + expression: zArrayExpression, + name: identifier.name, + }); + file.add(statement); + return; + } + + if (model.base === 'number') { + let expression = zArrayExpression; + + if (model.minItems && model.maxItems && model.minItems === model.maxItems) { + expression = compiler.callExpression({ + functionName: compiler.propertyAccessExpression({ + expression, + name: 'length', + }), + parameters: [compiler.ots.number(model.minItems)], + }); + } else { + if (model.minItems) { + expression = compiler.callExpression({ + functionName: compiler.propertyAccessExpression({ + expression, + name: 'min', + }), + parameters: [compiler.ots.number(model.minItems)], + }); + } + + if (model.maxItems) { + expression = compiler.callExpression({ + functionName: compiler.propertyAccessExpression({ + expression, + name: 'max', + }), + parameters: [compiler.ots.number(model.maxItems)], + }); + } + } + + const statement = compiler.constVariable({ + exportConst: true, + expression, + name: identifier.name, + }); + file.add(statement); + return; + } + + // console.warn('array!', model.base, model.name) + const statement = compiler.constVariable({ + exportConst: true, + expression: compiler.callExpression({ + functionName: compiler.propertyAccessExpression({ + expression: 'z', + name: 'object', + }), + parameters: [ + compiler.objectExpression({ + multiLine: true, + obj: [], + }), + ], + }), + name: identifier.name, + }); + file.add(statement); +}; + +const processGeneric = ({ file, model }: TypesProps) => { + const identifier = file.ensureUniqueIdentifier({ + create: true, + meta: model.meta, + namespace: 'value', + }); + + if (!identifier.created) { + return; + } + + if (model.base === 'string') { + const statement = compiler.constVariable({ + exportConst: true, + expression: compiler.callExpression({ + functionName: compiler.propertyAccessExpression({ + expression: 'z', + name: 'string', + }), + }), + name: identifier.name, + }); + file.add(statement); + return; + } + + if (model.base === 'boolean') { + // console.warn(model) + const statement = compiler.constVariable({ + exportConst: true, + expression: compiler.callExpression({ + functionName: compiler.propertyAccessExpression({ + expression: 'z', + name: 'boolean', + }), + }), + name: identifier.name, + }); + file.add(statement); + return; + } + + // console.warn(model.base) + const statement = compiler.constVariable({ + exportConst: true, + expression: compiler.callExpression({ + functionName: compiler.propertyAccessExpression({ + expression: 'z', + name: 'object', + }), + parameters: [ + compiler.objectExpression({ + multiLine: true, + obj: [], + }), + ], + }), + name: identifier.name, + }); + file.add(statement); +}; + +const processModel = (props: TypesProps) => { + switch (props.model.export) { + case 'all-of': + case 'any-of': + case 'one-of': + case 'interface': + // return processComposition(props); + return; + case 'array': + return processArray(props); + case 'enum': + // return processEnum(props); + return; + default: + return processGeneric(props); + } +}; + +export const handler: PluginHandler = ({ + client, + files, + plugin, +}) => { + const file = files[plugin.name]; + + file.import({ + module: 'zod', + name: 'z', + }); + + for (const model of client.models) { + processModel({ + client, + file, + model, + }); + } }; diff --git a/packages/openapi-ts/src/types/utils.ts b/packages/openapi-ts/src/types/utils.ts index 5081c2c9a..63dae222d 100644 --- a/packages/openapi-ts/src/types/utils.ts +++ b/packages/openapi-ts/src/types/utils.ts @@ -1,4 +1,4 @@ -import type { TypeScriptFile } from '../compiler'; +import type { TypeScriptFile } from '../generate/files'; type ExtractFromArray = T extends Discriminator ? Required diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b4baad027..7e7147f48 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -568,6 +568,9 @@ importers: typescript: specifier: 5.5.3 version: 5.5.3 + zod: + specifier: 3.23.8 + version: 3.23.8 packages: @@ -8509,7 +8512,7 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.1703.7(chokidar@3.6.0) - '@angular-devkit/build-webpack': 0.1703.7(chokidar@3.6.0)(webpack-dev-server@4.15.1(webpack@5.90.3(esbuild@0.23.1)))(webpack@5.90.3(esbuild@0.20.1)) + '@angular-devkit/build-webpack': 0.1703.7(chokidar@3.6.0)(webpack-dev-server@4.15.1(webpack@5.90.3(esbuild@0.20.1)))(webpack@5.90.3(esbuild@0.20.1)) '@angular-devkit/core': 17.3.7(chokidar@3.6.0) '@angular/compiler-cli': 17.3.9(@angular/compiler@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.7)))(typescript@5.5.3) '@babel/core': 7.24.0 @@ -8567,9 +8570,9 @@ snapshots: undici: 6.11.1 vite: 5.1.7(@types/node@20.14.10)(less@4.2.0)(sass@1.71.1)(terser@5.29.1) watchpack: 2.4.0 - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) webpack-dev-middleware: 6.1.2(webpack@5.90.3(esbuild@0.20.1)) - webpack-dev-server: 4.15.1(webpack@5.90.3(esbuild@0.23.1)) + webpack-dev-server: 4.15.1(webpack@5.90.3(esbuild@0.20.1)) webpack-merge: 5.10.0 webpack-subresource-integrity: 5.1.0(webpack@5.90.3(esbuild@0.20.1)) optionalDependencies: @@ -8594,12 +8597,12 @@ snapshots: - utf-8-validate - webpack-cli - '@angular-devkit/build-webpack@0.1703.7(chokidar@3.6.0)(webpack-dev-server@4.15.1(webpack@5.90.3(esbuild@0.23.1)))(webpack@5.90.3(esbuild@0.20.1))': + '@angular-devkit/build-webpack@0.1703.7(chokidar@3.6.0)(webpack-dev-server@4.15.1(webpack@5.90.3(esbuild@0.20.1)))(webpack@5.90.3(esbuild@0.20.1))': dependencies: '@angular-devkit/architect': 0.1703.7(chokidar@3.6.0) rxjs: 7.8.1 - webpack: 5.90.3(esbuild@0.20.1) - webpack-dev-server: 4.15.1(webpack@5.90.3(esbuild@0.23.1)) + webpack: 5.90.3(esbuild@0.23.1) + webpack-dev-server: 4.15.1(webpack@5.90.3(esbuild@0.20.1)) transitivePeerDependencies: - chokidar @@ -10409,7 +10412,7 @@ snapshots: dependencies: '@angular/compiler-cli': 17.3.9(@angular/compiler@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.7)))(typescript@5.5.3) typescript: 5.5.3 - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) '@nodelib/fs.scandir@2.1.5': dependencies: @@ -12548,7 +12551,7 @@ snapshots: '@babel/core': 7.24.0 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) babel-plugin-istanbul@6.1.1: dependencies: @@ -12985,7 +12988,7 @@ snapshots: normalize-path: 3.0.0 schema-utils: 4.2.0 serialize-javascript: 6.0.2 - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) core-js-compat@3.37.1: dependencies: @@ -13037,7 +13040,7 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.6.2 optionalDependencies: - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) css-select@5.1.0: dependencies: @@ -14456,7 +14459,7 @@ snapshots: dependencies: klona: 2.0.6 less: 4.2.0 - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) less@4.2.0: dependencies: @@ -14481,7 +14484,7 @@ snapshots: dependencies: webpack-sources: 3.2.3 optionalDependencies: - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) lilconfig@2.1.0: {} @@ -14700,7 +14703,7 @@ snapshots: dependencies: schema-utils: 4.2.0 tapable: 2.2.1 - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) minimalistic-assert@1.0.1: {} @@ -15300,7 +15303,7 @@ snapshots: postcss: 8.4.35 semver: 7.6.2 optionalDependencies: - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) transitivePeerDependencies: - typescript @@ -15758,7 +15761,7 @@ snapshots: neo-async: 2.6.2 optionalDependencies: sass: 1.71.1 - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) sass@1.71.1: dependencies: @@ -15992,7 +15995,7 @@ snapshots: dependencies: iconv-lite: 0.6.3 source-map-js: 1.2.0 - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) source-map-support@0.5.21: dependencies: @@ -16349,16 +16352,16 @@ snapshots: term-size@2.2.1: {} - terser-webpack-plugin@5.3.10(esbuild@0.20.1)(webpack@5.90.3(esbuild@0.23.1)): + terser-webpack-plugin@5.3.10(esbuild@0.23.1)(webpack@5.90.3(esbuild@0.20.1)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.29.1 - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) optionalDependencies: - esbuild: 0.20.1 + esbuild: 0.23.1 terser@5.29.1: dependencies: @@ -17072,14 +17075,14 @@ snapshots: webidl-conversions@7.0.0: {} - webpack-dev-middleware@5.3.4(webpack@5.90.3(esbuild@0.23.1)): + webpack-dev-middleware@5.3.4(webpack@5.90.3(esbuild@0.20.1)): dependencies: colorette: 2.0.20 memfs: 3.5.3 mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.2.0 - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) webpack-dev-middleware@6.1.2(webpack@5.90.3(esbuild@0.20.1)): dependencies: @@ -17089,9 +17092,9 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.2.0 optionalDependencies: - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) - webpack-dev-server@4.15.1(webpack@5.90.3(esbuild@0.23.1)): + webpack-dev-server@4.15.1(webpack@5.90.3(esbuild@0.20.1)): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -17121,10 +17124,10 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 5.3.4(webpack@5.90.3(esbuild@0.23.1)) + webpack-dev-middleware: 5.3.4(webpack@5.90.3(esbuild@0.20.1)) ws: 8.17.1 optionalDependencies: - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) transitivePeerDependencies: - bufferutil - debug @@ -17142,9 +17145,9 @@ snapshots: webpack-subresource-integrity@5.1.0(webpack@5.90.3(esbuild@0.20.1)): dependencies: typed-assert: 1.0.9 - webpack: 5.90.3(esbuild@0.20.1) + webpack: 5.90.3(esbuild@0.23.1) - webpack@5.90.3(esbuild@0.20.1): + webpack@5.90.3(esbuild@0.23.1): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.5 @@ -17167,7 +17170,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(esbuild@0.20.1)(webpack@5.90.3(esbuild@0.23.1)) + terser-webpack-plugin: 5.3.10(esbuild@0.23.1)(webpack@5.90.3(esbuild@0.20.1)) watchpack: 2.4.0 webpack-sources: 3.2.3 transitivePeerDependencies: From 14c804ff7300a232c63852152a9ab62d2c46ffbe Mon Sep 17 00:00:00 2001 From: Lubos Date: Tue, 8 Oct 2024 12:18:08 +0800 Subject: [PATCH 2/2] chore: progress on the experimental parser --- packages/openapi-ts/src/compiler/index.ts | 2 + packages/openapi-ts/src/compiler/typedef.ts | 113 +- packages/openapi-ts/src/compiler/types.ts | 111 +- packages/openapi-ts/src/compiler/utils.ts | 19 +- .../src/generate/__tests__/index.spec.ts | 2 +- .../src/generate/__tests__/output.spec.ts | 10 +- .../src/generate/__tests__/services.spec.ts | 26 +- .../src/generate/__tests__/types.spec.ts | 3 +- .../openapi-ts/src/generate/files/index.ts | 41 +- .../openapi-ts/src/generate/files/name.ts | 62 +- packages/openapi-ts/src/generate/output.ts | 115 +- packages/openapi-ts/src/generate/plugins.ts | 24 +- packages/openapi-ts/src/generate/services.ts | 230 +- packages/openapi-ts/src/generate/types.ts | 1146 +++++- packages/openapi-ts/src/index.ts | 89 +- packages/openapi-ts/src/ir/context.ts | 74 + packages/openapi-ts/src/ir/ir.d.ts | 129 + packages/openapi-ts/src/ir/parameter.ts | 35 + packages/openapi-ts/src/ir/utils.ts | 25 + .../src/openApi/3.0.3/parser/index.ts | 5 +- .../3.0.3/types/{spec.ts => spec.d.ts} | 0 .../openapi-ts/src/openApi/3.1.0/index.ts | 2 + .../src/openApi/3.1.0/parser/index.ts | 217 + .../src/openApi/3.1.0/parser/mediaType.ts | 40 + .../src/openApi/3.1.0/parser/operation.ts | 199 + .../src/openApi/3.1.0/parser/parameter.ts | 163 + .../src/openApi/3.1.0/parser/schema.ts | 787 ++++ .../types/json-schema-draft-2020-12.d.ts | 366 ++ .../openApi/3.1.0/types/spec-extensions.d.ts | 41 + .../types/spec.ts => 3.1.0/types/spec.d.ts} | 25 +- packages/openapi-ts/src/openApi/3.1/index.ts | 2 - .../src/openApi/3.1/parser/index.ts | 82 - .../src/openApi/3.1/parser/operation.ts | 39 - .../src/openApi/__tests__/index.spec.ts | 20 +- .../src/openApi/common/interfaces/config.ts | 13 - .../src/openApi/common/parser/operation.ts | 2 +- .../src/openApi/common/parser/sanitize.ts | 27 +- packages/openapi-ts/src/openApi/config.ts | 103 +- packages/openapi-ts/src/openApi/index.ts | 48 +- .../v2/parser/getOperationParameter.ts | 4 +- .../v2/parser/getOperationParameters.ts | 8 +- .../src/openApi/v2/parser/getOperations.ts | 17 +- .../src/openApi/v2/parser/operation.ts | 12 +- .../src/openApi/v3/parser/discriminator.ts | 4 +- .../src/openApi/v3/parser/getModels.ts | 4 +- .../v3/parser/getOperationParameter.ts | 4 +- .../v3/parser/getOperationParameters.ts | 8 +- .../src/openApi/v3/parser/getOperations.ts | 17 +- .../src/openApi/v3/parser/operation.ts | 12 +- .../src/plugins/@hey-api/schemas/config.ts | 1 + .../src/plugins/@hey-api/schemas/types.ts | 3 +- .../src/plugins/@hey-api/services/config.ts | 1 + .../src/plugins/@hey-api/services/types.ts | 3 +- .../src/plugins/@hey-api/types/config.ts | 1 + .../src/plugins/@hey-api/types/types.ts | 3 +- .../plugins/@tanstack/query-core/plugin.ts | 358 +- .../plugins/@tanstack/react-query/config.ts | 3 +- .../plugins/@tanstack/react-query/types.ts | 3 +- .../plugins/@tanstack/solid-query/config.ts | 3 +- .../plugins/@tanstack/solid-query/types.ts | 3 +- .../plugins/@tanstack/svelte-query/config.ts | 3 +- .../plugins/@tanstack/svelte-query/types.ts | 3 +- .../src/plugins/@tanstack/vue-query/config.ts | 3 +- .../src/plugins/@tanstack/vue-query/types.ts | 3 +- packages/openapi-ts/src/plugins/types.ts | 12 +- packages/openapi-ts/src/plugins/zod/config.ts | 1 + packages/openapi-ts/src/plugins/zod/plugin.ts | 8 +- packages/openapi-ts/src/plugins/zod/types.ts | 3 +- packages/openapi-ts/src/types/config.ts | 8 +- .../src/utils/__tests__/parse.spec.ts | 10 +- .../src/utils/__tests__/postprocess.spec.ts | 13 +- packages/openapi-ts/src/utils/handlebars.ts | 11 +- packages/openapi-ts/src/utils/parse.ts | 68 - packages/openapi-ts/src/utils/ref.ts | 35 + packages/openapi-ts/src/utils/transform.ts | 11 +- packages/openapi-ts/src/utils/type.ts | 3 +- .../asClass/@tanstack/react-query.gen.ts | 80 +- .../axios/@tanstack/react-query.gen.ts | 80 +- .../fetch/@tanstack/react-query.gen.ts | 80 +- .../asClass/@tanstack/solid-query.gen.ts | 80 +- .../axios/@tanstack/solid-query.gen.ts | 80 +- .../fetch/@tanstack/solid-query.gen.ts | 80 +- .../asClass/@tanstack/svelte-query.gen.ts | 80 +- .../axios/@tanstack/svelte-query.gen.ts | 80 +- .../fetch/@tanstack/svelte-query.gen.ts | 80 +- .../asClass/@tanstack/vue-query.gen.ts | 80 +- .../axios/@tanstack/vue-query.gen.ts | 80 +- .../fetch/@tanstack/vue-query.gen.ts | 80 +- packages/openapi-ts/test/performance.spec.ts | 11 +- packages/openapi-ts/test/sample.cjs | 20 +- packages/openapi-ts/test/spec/3.1.0/full.json | 3622 +++++++++++++++++ pnpm-lock.yaml | 101 +- 92 files changed, 8661 insertions(+), 1157 deletions(-) create mode 100644 packages/openapi-ts/src/ir/context.ts create mode 100644 packages/openapi-ts/src/ir/ir.d.ts create mode 100644 packages/openapi-ts/src/ir/parameter.ts create mode 100644 packages/openapi-ts/src/ir/utils.ts rename packages/openapi-ts/src/openApi/3.0.3/types/{spec.ts => spec.d.ts} (100%) create mode 100644 packages/openapi-ts/src/openApi/3.1.0/index.ts create mode 100644 packages/openapi-ts/src/openApi/3.1.0/parser/index.ts create mode 100644 packages/openapi-ts/src/openApi/3.1.0/parser/mediaType.ts create mode 100644 packages/openapi-ts/src/openApi/3.1.0/parser/operation.ts create mode 100644 packages/openapi-ts/src/openApi/3.1.0/parser/parameter.ts create mode 100644 packages/openapi-ts/src/openApi/3.1.0/parser/schema.ts create mode 100644 packages/openapi-ts/src/openApi/3.1.0/types/json-schema-draft-2020-12.d.ts create mode 100644 packages/openapi-ts/src/openApi/3.1.0/types/spec-extensions.d.ts rename packages/openapi-ts/src/openApi/{3.1/types/spec.ts => 3.1.0/types/spec.d.ts} (98%) delete mode 100644 packages/openapi-ts/src/openApi/3.1/index.ts delete mode 100644 packages/openapi-ts/src/openApi/3.1/parser/index.ts delete mode 100644 packages/openapi-ts/src/openApi/3.1/parser/operation.ts delete mode 100644 packages/openapi-ts/src/openApi/common/interfaces/config.ts delete mode 100644 packages/openapi-ts/src/utils/parse.ts create mode 100644 packages/openapi-ts/src/utils/ref.ts create mode 100644 packages/openapi-ts/test/spec/3.1.0/full.json diff --git a/packages/openapi-ts/src/compiler/index.ts b/packages/openapi-ts/src/compiler/index.ts index 7a880cf1f..40df6749d 100644 --- a/packages/openapi-ts/src/compiler/index.ts +++ b/packages/openapi-ts/src/compiler/index.ts @@ -32,10 +32,12 @@ export const compiler = { indexedAccessTypeNode: types.createIndexedAccessTypeNode, isTsNode: utils.isTsNode, keywordTypeNode: types.createKeywordTypeNode, + literalTypeNode: types.createLiteralTypeNode, methodDeclaration: classes.createMethodDeclaration, namedImportDeclarations: module.createNamedImportDeclarations, namespaceDeclaration: types.createNamespaceDeclaration, nodeToString: utils.tsNodeToString, + null: types.createNull, objectExpression: types.createObjectType, ots: utils.ots, propertyAccessExpression: types.createPropertyAccessExpression, diff --git a/packages/openapi-ts/src/compiler/typedef.ts b/packages/openapi-ts/src/compiler/typedef.ts index 20fd4131c..6a0465694 100644 --- a/packages/openapi-ts/src/compiler/typedef.ts +++ b/packages/openapi-ts/src/compiler/typedef.ts @@ -1,7 +1,18 @@ import ts from 'typescript'; -import { createTypeNode, createTypeReferenceNode } from './types'; -import { addLeadingComments, type Comments, tsNodeToString } from './utils'; +import { validTypescriptIdentifierRegExp } from '../utils/regexp'; +import { + createKeywordTypeNode, + createStringLiteral, + createTypeNode, + createTypeReferenceNode, +} from './types'; +import { + addLeadingComments, + type Comments, + createIdentifier, + tsNodeToString, +} from './utils'; const nullNode = createTypeReferenceNode({ typeName: 'null' }); @@ -38,40 +49,83 @@ const maybeNullable = ({ * @returns ts.TypeLiteralNode | ts.TypeUnionNode */ export const createTypeInterfaceNode = ({ + indexProperty, isNullable, properties, + useLegacyResolution, }: { + /** + * Adds an index signature if defined. + * @example + * ```ts + * type IndexProperty = { + * [key: string]: string + * } + * ``` + */ + indexProperty?: Property; isNullable?: boolean; properties: Property[]; + useLegacyResolution: boolean; }) => { - const node = ts.factory.createTypeLiteralNode( - properties.map((property) => { - const modifiers: readonly ts.Modifier[] | undefined = property.isReadOnly - ? [ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword)] - : undefined; + const propertyTypes: Array = []; + + const members: Array = properties.map((property) => { + const modifiers: readonly ts.Modifier[] | undefined = property.isReadOnly + ? [ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword)] + : undefined; + + const questionToken: ts.QuestionToken | undefined = + property.isRequired !== false + ? undefined + : ts.factory.createToken(ts.SyntaxKind.QuestionToken); + + const type: ts.TypeNode | undefined = createTypeNode(property.type); + propertyTypes.push(type); - const questionToken: ts.QuestionToken | undefined = - property.isRequired !== false - ? undefined - : ts.factory.createToken(ts.SyntaxKind.QuestionToken); + const signature = ts.factory.createPropertySignature( + modifiers, + useLegacyResolution || + property.name.match(validTypescriptIdentifierRegExp) + ? property.name + : createStringLiteral({ text: property.name }), + questionToken, + type, + ); - const type: ts.TypeNode | undefined = createTypeNode(property.type); + addLeadingComments({ + comments: property.comment, + node: signature, + }); - const signature = ts.factory.createPropertySignature( - modifiers, - property.name, - questionToken, - type, - ); + return signature; + }); - addLeadingComments({ - comments: property.comment, - node: signature, - }); + if (indexProperty) { + const modifiers: readonly ts.Modifier[] | undefined = + indexProperty.isReadOnly + ? [ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword)] + : undefined; + const indexSignature = ts.factory.createIndexSignature( + modifiers, + [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + createIdentifier({ text: indexProperty.name }), + undefined, + createKeywordTypeNode({ + keyword: 'string', + }), + undefined, + ), + ], + createTypeNode(indexProperty.type), + ); + members.push(indexSignature); + } - return signature; - }), - ); + const node = ts.factory.createTypeLiteralNode(members); return maybeNullable({ isNullable, node }); }; @@ -140,6 +194,7 @@ export const createTypeRecordNode = ( keys: (any | ts.TypeNode)[], values: (any | ts.TypeNode)[], isNullable: boolean = false, + useLegacyResolution: boolean = true, ) => { const keyNode = createTypeUnionNode({ types: keys, @@ -157,6 +212,7 @@ export const createTypeRecordNode = ( type: valueNode, }, ], + useLegacyResolution, }); return maybeNullable({ isNullable, node }); }; @@ -168,11 +224,14 @@ export const createTypeRecordNode = ( * @returns ts.TypeReferenceNode | ts.UnionTypeNode */ export const createTypeArrayNode = ( - types: (any | ts.TypeNode)[], + types: (any | ts.TypeNode)[] | ts.TypeNode | string, isNullable: boolean = false, ) => { const node = createTypeReferenceNode({ - typeArguments: [createTypeUnionNode({ types })], + typeArguments: [ + // @ts-ignore + Array.isArray(types) ? createTypeUnionNode({ types }) : types, + ], typeName: 'Array', }); return maybeNullable({ isNullable, node }); diff --git a/packages/openapi-ts/src/compiler/types.ts b/packages/openapi-ts/src/compiler/types.ts index 2637a24f3..9b228f446 100644 --- a/packages/openapi-ts/src/compiler/types.ts +++ b/packages/openapi-ts/src/compiler/types.ts @@ -1,5 +1,6 @@ import ts from 'typescript'; +import { escapeName } from '../utils/escape'; import { validTypescriptIdentifierRegExp } from '../utils/regexp'; import { addLeadingComments, @@ -110,6 +111,8 @@ export const createPropertyAccessExpression = ({ return node; }; +export const createNull = (): ts.NullLiteral => ts.factory.createNull(); + /** * Convert an unknown value to an expression. * @param identifiers - list of keys that are treated as identifiers. @@ -132,7 +135,7 @@ export const toExpression = ({ value: T; }): ts.Expression | undefined => { if (value === null) { - return ts.factory.createNull(); + return createNull(); } if (Array.isArray(value)) { @@ -252,16 +255,25 @@ export const toParameterDeclarations = (parameters: FunctionParameter[]) => export const createKeywordTypeNode = ({ keyword, }: { - keyword: 'any' | 'boolean' | 'string'; + keyword: 'any' | 'boolean' | 'number' | 'string' | 'undefined' | 'unknown'; }) => { let kind: ts.KeywordTypeSyntaxKind = ts.SyntaxKind.AnyKeyword; switch (keyword) { case 'boolean': kind = ts.SyntaxKind.BooleanKeyword; break; + case 'number': + kind = ts.SyntaxKind.NumberKeyword; + break; case 'string': kind = ts.SyntaxKind.StringKeyword; break; + case 'undefined': + kind = ts.SyntaxKind.UndefinedKeyword; + break; + case 'unknown': + kind = ts.SyntaxKind.UnknownKeyword; + break; } return ts.factory.createKeywordTypeNode(kind); }; @@ -288,6 +300,15 @@ export const toTypeParameters = (types: FunctionTypeParameter[]) => ), ); +export const createLiteralTypeNode = ({ + literal, +}: { + literal: ts.LiteralTypeNode['literal']; +}) => { + const node = ts.factory.createLiteralTypeNode(literal); + return node; +}; + /** * Create arrow function type expression. */ @@ -559,30 +580,32 @@ export const createObjectType = < }) .filter(isType); - const expression = ts.factory.createObjectLiteralExpression( + const node = ts.factory.createObjectLiteralExpression( properties as any[], multiLine, ); addLeadingComments({ comments, - node: expression, + node, }); - return expression; + return node; }; /** * Create enum declaration. Example `export enum T = { X, Y };` - * @param comments - comments to add to each property of enum. + * @param comments - comments to add to each property. * @param leadingComment - leading comment to add to enum. * @param name - the name of the enum. * @param obj - the object representing the enum. - * @returns + * @returns ts.EnumDeclaration */ -export const createEnumDeclaration = ({ - comments, - leadingComment, +export const createEnumDeclaration = < + T extends Record | Array, +>({ + comments: enumMemberComments = {}, + leadingComment: comments, name, obj, }: { @@ -591,29 +614,46 @@ export const createEnumDeclaration = ({ name: string; obj: T; }): ts.EnumDeclaration => { - const declaration = ts.factory.createEnumDeclaration( - [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], - createIdentifier({ text: name }), - Object.entries(obj).map(([key, value]) => { - const initializer = toExpression({ unescape: true, value }); - const assignment = ts.factory.createEnumMember(key, initializer); - const comment = comments?.[key]; - - addLeadingComments({ - comments: comment, - node: assignment, + const members: Array = Array.isArray(obj) + ? obj.map((value) => { + const enumMember = ts.factory.createEnumMember( + escapeName(value.key), + toExpression({ + value: value.value, + }), + ); + + addLeadingComments({ + comments: value.comments, + node: enumMember, + }); + + return enumMember; + }) + : Object.entries(obj).map(([key, value]) => { + const initializer = toExpression({ unescape: true, value }); + const enumMember = ts.factory.createEnumMember(key, initializer); + + addLeadingComments({ + comments: enumMemberComments[key], + node: enumMember, + }); + + return enumMember; }); - return assignment; - }), + const node = ts.factory.createEnumDeclaration( + [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], + createIdentifier({ text: name }), + members, ); addLeadingComments({ - comments: leadingComment, - node: declaration, + comments, + node, }); - return declaration; + return node; }; /** @@ -622,14 +662,12 @@ export const createEnumDeclaration = ({ * @param nodes - the nodes in the namespace. * @returns */ -export const createNamespaceDeclaration = < - T extends Array, ->({ +export const createNamespaceDeclaration = ({ name, statements, }: { name: string; - statements: T; + statements: Array; }) => ts.factory.createModuleDeclaration( [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], @@ -649,8 +687,17 @@ export const createIndexedAccessTypeNode = ({ return node; }; -export const createStringLiteral = ({ text }: { text: string }) => { - const node = ts.factory.createStringLiteral(text); +export const createStringLiteral = ({ + isSingleQuote, + text, +}: { + isSingleQuote?: boolean; + text: string; +}) => { + if (isSingleQuote === undefined) { + isSingleQuote = !text.includes("'"); + } + const node = ts.factory.createStringLiteral(text, isSingleQuote); return node; }; diff --git a/packages/openapi-ts/src/compiler/utils.ts b/packages/openapi-ts/src/compiler/utils.ts index 54331fc4a..a0a690a21 100644 --- a/packages/openapi-ts/src/compiler/utils.ts +++ b/packages/openapi-ts/src/compiler/utils.ts @@ -2,6 +2,7 @@ import ts from 'typescript'; import { getConfig } from '../utils/config'; import { unescapeName } from '../utils/escape'; +import { createStringLiteral } from './types'; export interface ImportExportItemObject { alias?: string; @@ -9,22 +10,15 @@ export interface ImportExportItemObject { name: string; } -export const CONFIG = { - newLine: ts.NewLineKind.LineFeed, - scriptKind: ts.ScriptKind.TS, - scriptTarget: ts.ScriptTarget.ES2015, - useSingleQuotes: true, -}; - -const printer = ts.createPrinter({ newLine: CONFIG.newLine }); +const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); export const createSourceFile = (sourceText: string) => ts.createSourceFile( '', sourceText, - CONFIG.scriptTarget, + ts.ScriptTarget.ES2015, undefined, - CONFIG.scriptKind, + ts.ScriptKind.TS, ); const blankSourceFile = createSourceFile(''); @@ -145,10 +139,7 @@ export const ots = { if (text.startsWith('`')) { return createIdentifier({ text }); } - return ts.factory.createStringLiteral( - text, - text.includes("'") ? false : CONFIG.useSingleQuotes, - ); + return createStringLiteral({ text }); }, }; diff --git a/packages/openapi-ts/src/generate/__tests__/index.spec.ts b/packages/openapi-ts/src/generate/__tests__/index.spec.ts index 805434d95..33bd2c9cf 100644 --- a/packages/openapi-ts/src/generate/__tests__/index.spec.ts +++ b/packages/openapi-ts/src/generate/__tests__/index.spec.ts @@ -3,8 +3,8 @@ import path from 'node:path'; import { describe, expect, it, vi } from 'vitest'; -import { TypeScriptFile } from '../../compiler'; import { setConfig } from '../../utils/config'; +import { TypeScriptFile } from '../files'; import { generateIndexFile } from '../indexFile'; vi.mock('node:fs'); diff --git a/packages/openapi-ts/src/generate/__tests__/output.spec.ts b/packages/openapi-ts/src/generate/__tests__/output.spec.ts index bde837308..ce3a7c0b4 100644 --- a/packages/openapi-ts/src/generate/__tests__/output.spec.ts +++ b/packages/openapi-ts/src/generate/__tests__/output.spec.ts @@ -2,6 +2,7 @@ import { mkdirSync, rmSync, writeFileSync } from 'node:fs'; import { describe, expect, it, vi } from 'vitest'; +import type { Client } from '../../types/client'; import { setConfig } from '../../utils/config'; import { generateOutput } from '../output'; import { mockTemplates, openApi } from './mocks'; @@ -33,7 +34,7 @@ describe('generateOutput', () => { useOptions: false, }); - const client: Parameters[1] = { + const client: Client = { models: [], server: 'http://localhost:8080', services: [], @@ -41,7 +42,12 @@ describe('generateOutput', () => { version: 'v1', }; - await generateOutput(openApi, client, mockTemplates); + await generateOutput({ + client, + context: undefined, + openApi, + templates: mockTemplates, + }); expect(rmSync).toHaveBeenCalled(); expect(mkdirSync).toHaveBeenCalled(); diff --git a/packages/openapi-ts/src/generate/__tests__/services.spec.ts b/packages/openapi-ts/src/generate/__tests__/services.spec.ts index 6a92eca90..dfd3ed290 100644 --- a/packages/openapi-ts/src/generate/__tests__/services.spec.ts +++ b/packages/openapi-ts/src/generate/__tests__/services.spec.ts @@ -3,10 +3,10 @@ import path from 'node:path'; import { describe, expect, it, vi } from 'vitest'; -import { TypeScriptFile } from '../../compiler'; import type { Operation } from '../../types/client'; import type { Files } from '../../types/utils'; import { setConfig } from '../../utils/config'; +import { TypeScriptFile } from '../files'; import { generateServices } from '../services'; vi.mock('node:fs'); @@ -80,7 +80,11 @@ describe('generateServices', () => { name: 'types.ts', }); - await generateServices({ client, files }); + await generateServices({ + client, + context: undefined, + files, + }); files.services.write(); @@ -162,7 +166,11 @@ describe('methodNameBuilder', () => { name: 'types.ts', }); - await generateServices({ client, files }); + await generateServices({ + client, + context: undefined, + files, + }); files.services.write(); @@ -206,7 +214,11 @@ describe('methodNameBuilder', () => { name: 'types.ts', }); - await generateServices({ client, files }); + await generateServices({ + client, + context: undefined, + files, + }); files.services.write(); @@ -252,7 +264,11 @@ describe('methodNameBuilder', () => { name: 'types.ts', }); - await generateServices({ client, files }); + await generateServices({ + client, + context: undefined, + files, + }); files.services.write(); diff --git a/packages/openapi-ts/src/generate/__tests__/types.spec.ts b/packages/openapi-ts/src/generate/__tests__/types.spec.ts index c083060e6..46e97188e 100644 --- a/packages/openapi-ts/src/generate/__tests__/types.spec.ts +++ b/packages/openapi-ts/src/generate/__tests__/types.spec.ts @@ -3,8 +3,8 @@ import path from 'node:path'; import { describe, expect, it, vi } from 'vitest'; -import { TypeScriptFile } from '../../compiler'; import { setConfig } from '../../utils/config'; +import { TypeScriptFile } from '../files'; import { generateTypes } from '../types'; vi.mock('node:fs'); @@ -75,6 +75,7 @@ describe('generateTypes', () => { await generateTypes({ client, + context: undefined, files, }); diff --git a/packages/openapi-ts/src/generate/files/index.ts b/packages/openapi-ts/src/generate/files/index.ts index f1c5f917e..c10ec9530 100644 --- a/packages/openapi-ts/src/generate/files/index.ts +++ b/packages/openapi-ts/src/generate/files/index.ts @@ -8,6 +8,8 @@ import { type ImportExportItemObject, tsNodeToString, } from '../../compiler/utils'; +import { ensureValidTypeScriptJavaScriptIdentifier } from '../../openApi'; +import { reservedWordsRegExp } from '../../utils/regexp'; import { ensureDirSync } from '../utils'; import { ensureUniqueIdentifier, splitNameAndExtension } from './name'; import type { Namespaces } from './types'; @@ -26,8 +28,8 @@ export class TypeScriptFile { public constructor({ dir, - name, header = true, + name, }: { dir: string; header?: boolean; @@ -37,25 +39,37 @@ export class TypeScriptFile { this._path = path.resolve(dir, this.getName()); if (header) { - this._headers = [ - ...this._headers, + this._headers.push( '// This file is auto-generated by @hey-api/openapi-ts', - ]; + ); } } public add(...nodes: Array) { - this._items = [...this._items, ...nodes]; + this._items = this._items.concat(nodes); } - public ensureUniqueIdentifier({ + public identifier({ namespace, ...args }: Omit[0], 'namespace'> & { namespace: keyof Namespaces; }) { + let validNameTransformer: ((name: string) => string) | undefined; + switch (namespace) { + // TODO: parser - add case transformers + case 'type': + case 'value': + validNameTransformer = (name) => + ensureValidTypeScriptJavaScriptIdentifier(name).replace( + reservedWordsRegExp, + '_$1', + ); + break; + } return ensureUniqueIdentifier({ namespace: this.namespaces[namespace], + validNameTransformer, ...args, }); } @@ -121,28 +135,27 @@ export class TypeScriptFile { public toString(separator: string = '\n') { let output: string[] = []; if (this._headers.length) { - output = [...output, this._headers.join('\n')]; + output.push(this._headers.join('\n')); } - let importsStringArray: string[] = []; + const importsStringArray: string[] = []; for (const [_module, moduleMap] of this._imports.entries()) { const imports = Array.from(moduleMap.values()); const node = compiler.namedImportDeclarations({ imports, module: _module, }); - importsStringArray = [...importsStringArray, tsNodeToString({ node })]; + importsStringArray.push(tsNodeToString({ node })); } if (importsStringArray.length) { - output = [...output, importsStringArray.join('\n')]; + output.push(importsStringArray.join('\n')); } - output = [ - ...output, - ...this._items.map((node) => + output = output.concat( + this._items.map((node) => typeof node === 'string' ? node : tsNodeToString({ node, unescape: true }), ), - ]; + ); return output.join(separator); } diff --git a/packages/openapi-ts/src/generate/files/name.ts b/packages/openapi-ts/src/generate/files/name.ts index b6a1207c6..e45964fc1 100644 --- a/packages/openapi-ts/src/generate/files/name.ts +++ b/packages/openapi-ts/src/generate/files/name.ts @@ -1,27 +1,29 @@ -import type { ModelMeta } from '../../openApi'; import type { EnsureUniqueIdentifierResult, Namespace } from './types'; export const ensureUniqueIdentifier = ({ + $ref, count = 1, create = false, - meta, - nameTransformer, namespace, + validNameTransformer, }: { + $ref: string; count?: number; create?: boolean; - meta?: ModelMeta; - nameTransformer?: (value: string) => string; namespace: Namespace; + validNameTransformer?: (value: string) => string; }): EnsureUniqueIdentifierResult => { - if (!meta) { + const parts = $ref.split('/'); + let name = parts[parts.length - 1] || ''; + + if (!name) { return { created: false, name: '', }; } - const refValue = namespace[meta.$ref]; + const refValue = namespace[$ref]; if (refValue) { return { created: false, @@ -29,43 +31,45 @@ export const ensureUniqueIdentifier = ({ }; } - let name = meta.name; - if (nameTransformer) { - name = nameTransformer(name); - } if (count > 1) { name = `${name}${count}`; } - const nameValue = namespace[name]; - if (!nameValue) { - if (create) { - namespace[name] = meta; - namespace[meta.$ref] = meta; - + let nameValue = namespace[name]; + if (nameValue) { + if (nameValue.$ref === $ref) { return { - created: true, - name, + created: false, + name: nameValue.name, }; } - } else if (nameValue.$ref === meta.$ref) { - return { - created: false, - name, - }; - } else { + return ensureUniqueIdentifier({ + $ref, count: count + 1, create, - meta, - nameTransformer, namespace, + validNameTransformer, }); } + if (!create) { + return { + created: false, + name: '', + }; + } + + nameValue = { + $ref, + name: validNameTransformer ? validNameTransformer(name) : name, + }; + namespace[name] = nameValue; + namespace[nameValue.$ref] = nameValue; + return { - created: false, - name: '', + created: true, + name: nameValue.name, }; }; diff --git a/packages/openapi-ts/src/generate/output.ts b/packages/openapi-ts/src/generate/output.ts index aa34b8534..cfec98192 100644 --- a/packages/openapi-ts/src/generate/output.ts +++ b/packages/openapi-ts/src/generate/output.ts @@ -1,5 +1,6 @@ import path from 'node:path'; +import type { IRContext } from '../ir/context'; import type { OpenApi } from '../openApi'; import type { Client } from '../types/client'; import type { Files } from '../types/utils'; @@ -21,23 +22,32 @@ import { generateTypes } from './types'; * @param client Client containing models, schemas, and services * @param templates Templates wrapper with all loaded Handlebars templates */ -export const generateOutput = async ( - openApi: OpenApi, - client: Client, - templates: Templates, -): Promise => { +export const generateOutput = async ({ + client, + context, + openApi, + templates, +}: { + client: Client | undefined; + context: IRContext | undefined; + openApi: OpenApi; + templates: Templates; +}): Promise => { const config = getConfig(); - if (config.services.include && config.services.asClass) { - const regexp = new RegExp(config.services.include); - client.services = client.services.filter((service) => - regexp.test(service.name), - ); - } + // TODO: parser - handle IR + if (client) { + if (config.services.include && config.services.asClass) { + const regexp = new RegExp(config.services.include); + client.services = client.services.filter((service) => + regexp.test(service.name), + ); + } - if (config.types.include) { - const regexp = new RegExp(config.types.include); - client.models = client.models.filter((model) => regexp.test(model.name)); + if (config.types.include) { + const regexp = new RegExp(config.types.include); + client.models = client.models.filter((model) => regexp.test(model.name)); + } } const outputPath = path.resolve(config.output.path); @@ -47,45 +57,62 @@ export const generateOutput = async ( await generateClient(outputPath, config.client.name); // types.gen.ts - await generateTypes({ client, files }); + await generateTypes({ + client, + context, + files, + }); // schemas.gen.ts await generateSchemas({ files, openApi }); // transformers - if ( - config.services.export && - client.services.length && - config.types.dates === 'types+transform' - ) { - await generateResponseTransformers({ - client, - onNode: (node) => { - files.types?.add(node); - }, - onRemoveNode: () => { - files.types?.removeNode(); - }, - }); + // TODO: parser - handle IR + if (client) { + if ( + config.services.export && + client.services.length && + config.types.dates === 'types+transform' + ) { + await generateResponseTransformers({ + client, + onNode: (node) => { + files.types?.add(node); + }, + onRemoveNode: () => { + files.types?.removeNode(); + }, + }); + } } // services.gen.ts - await generateServices({ client, files }); + await generateServices({ + client, + context, + files, + }); // deprecated files - await generateClientClass(openApi, outputPath, client, templates); - await generateCore( - path.resolve(config.output.path, 'core'), - client, - templates, - ); + if (client) { + await generateClientClass(openApi, outputPath, client, templates); + await generateCore( + path.resolve(config.output.path, 'core'), + client, + templates, + ); + } // index.ts. Any files generated after this won't be included in exports // from the index file. await generateIndexFile({ files }); // plugins - await generatePlugins({ client, files }); + await generatePlugins({ + client, + context, + files, + }); Object.entries(files).forEach(([name, file]) => { if (config.dryRun) { @@ -98,4 +125,18 @@ export const generateOutput = async ( file.write('\n\n'); } }); + + if (context) { + Object.entries(context.files).forEach(([name, file]) => { + if (config.dryRun) { + return; + } + + if (name === 'index') { + file.write(); + } else { + file.write('\n\n'); + } + }); + } }; diff --git a/packages/openapi-ts/src/generate/plugins.ts b/packages/openapi-ts/src/generate/plugins.ts index 87e5cce29..e9c5d1b74 100644 --- a/packages/openapi-ts/src/generate/plugins.ts +++ b/packages/openapi-ts/src/generate/plugins.ts @@ -1,5 +1,6 @@ import path from 'node:path'; +import type { IRContext } from '../ir/context'; import type { Client } from '../types/client'; import type { Files } from '../types/utils'; import { getConfig, isLegacyClient } from '../utils/config'; @@ -8,8 +9,10 @@ import { TypeScriptFile } from './files'; export const generatePlugins = async ({ client, files, + context, }: { - client: Client; + client: Client | undefined; + context: IRContext | undefined; files: Files; }) => { const config = getConfig(); @@ -29,10 +32,19 @@ export const generatePlugins = async ({ dir: outputDir, name: `${outputParts[outputParts.length - 1]}.ts`, }); - plugin.handler({ - client, - files, - plugin: plugin as never, - }); + + if (context) { + plugin.handler_experimental({ + context, + files, + plugin: plugin as never, + }); + } else if (client) { + plugin.handler({ + client, + files, + plugin: plugin as never, + }); + } } }; diff --git a/packages/openapi-ts/src/generate/services.ts b/packages/openapi-ts/src/generate/services.ts index a7f0c0022..7bd9a7e8f 100644 --- a/packages/openapi-ts/src/generate/services.ts +++ b/packages/openapi-ts/src/generate/services.ts @@ -6,6 +6,12 @@ import type { } from '../compiler'; import { compiler } from '../compiler'; import type { FunctionTypeParameter, ObjectValue } from '../compiler/types'; +import type { IRContext } from '../ir/context'; +import type { + IROperationObject, + IRPathItemObject, + IRPathsObject, +} from '../ir/ir'; import { isOperationParameterRequired } from '../openApi'; import type { Client, @@ -14,6 +20,7 @@ import type { OperationParameter, Service, } from '../types/client'; +import type { Config } from '../types/config'; import type { Files } from '../types/utils'; import { camelCase } from '../utils/camelCase'; import { getConfig, isLegacyClient } from '../utils/config'; @@ -24,6 +31,7 @@ import { setUniqueTypeName } from '../utils/type'; import { unique } from '../utils/unique'; import { clientModulePath, clientOptionsTypeName } from './client'; import { TypeScriptFile } from './files'; +import { irRef } from './types'; type OnNode = (node: Node) => void; type OnImport = (name: string) => void; @@ -59,12 +67,49 @@ export const generateImport = ({ export const modelResponseTransformerTypeName = (name: string) => `${name}ModelResponseTransformer`; +interface OperationIRRef { + /** + * Operation ID + */ + id: string; +} + +const operationIrRef = ({ + id, + type, +}: OperationIRRef & { + type: 'data' | 'error' | 'response'; +}): string => { + let affix = ''; + switch (type) { + case 'data': + affix = 'Data'; + break; + case 'error': + affix = 'Error'; + break; + case 'response': + affix = 'Response'; + break; + } + return `${irRef}${camelCase({ + input: id, + pascalCase: true, + })}${affix}`; +}; + +export const operationDataRef = ({ id }: OperationIRRef): string => + operationIrRef({ id, type: 'data' }); + export const operationDataTypeName = (name: string) => `${camelCase({ input: name, pascalCase: true, })}Data`; +export const operationErrorRef = ({ id }: OperationIRRef): string => + operationIrRef({ id, type: 'error' }); + export const operationErrorTypeName = (name: string) => `${camelCase({ input: name, @@ -75,6 +120,9 @@ export const operationErrorTypeName = (name: string) => export const operationResponseTransformerTypeName = (name: string) => `${name}Transformer`; +export const operationResponseRef = ({ id }: OperationIRRef): string => + operationIrRef({ id, type: 'response' }); + export const operationResponseTypeName = (name: string) => `${camelCase({ input: name, @@ -464,21 +512,26 @@ const toRequestOptions = ( }); }; -export const toOperationName = ( - operation: Operation, - handleIllegal: boolean, -) => { - const config = getConfig(); - +export const toOperationName = ({ + config, + id, + operation, + handleIllegal, +}: { + config: Config; + handleIllegal?: boolean; + id: string; + operation: IROperationObject | Operation; +}) => { if (config.services.methodNameBuilder) { return config.services.methodNameBuilder(operation); } - if (handleIllegal && operation.name.match(reservedWordsRegExp)) { - return `${operation.name}_`; + if (handleIllegal && id.match(reservedWordsRegExp)) { + return `${id}_`; } - return operation.name; + return id; }; const toOperationStatements = ( @@ -652,7 +705,12 @@ const processService = ({ comment: toOperationComment(operation), exportConst: true, expression, - name: toOperationName(operation, true), + name: toOperationName({ + config, + handleIllegal: true, + id: operation.name, + operation, + }), }); onNode(statement); } @@ -665,7 +723,11 @@ const processService = ({ comment: toOperationComment(operation), isStatic: config.name === undefined && config.client.name !== 'legacy/angular', - name: toOperationName(operation, false), + name: toOperationName({ + config, + id: operation.name, + operation, + }), parameters: toOperationParamType(client, operation), returnType: !isLegacy ? undefined @@ -724,21 +786,46 @@ const processService = ({ ? { args: [{ providedIn: 'root' }], name: 'Injectable' } : undefined, members, - name: transformServiceName(service.name), + name: transformServiceName({ + config, + name: service.name, + }), }); onNode(statement); }; -const checkPrerequisites = ({ files }: { files: Files }) => { - const config = getConfig(); +const checkPrerequisites = ({ + context, + files, +}: { + context: IRContext | undefined; + files: Files; +}) => { + if (!context) { + const config = getConfig(); - if (!config.client.name) { + if (!config.client.name) { + throw new Error( + '🚫 client needs to be set to generate services - which HTTP client do you want to use?', + ); + } + + if (!files.types) { + throw new Error( + '🚫 types need to be exported to generate services - enable type generation', + ); + } + + return; + } + + if (!context.config.client.name) { throw new Error( '🚫 client needs to be set to generate services - which HTTP client do you want to use?', ); } - if (!files.types) { + if (!context.file({ id: 'types' })) { throw new Error( '🚫 types need to be exported to generate services - enable type generation', ); @@ -747,9 +834,11 @@ const checkPrerequisites = ({ files }: { files: Files }) => { export const generateServices = async ({ client, + context, files, }: { - client: Client; + client: Client | undefined; + context: IRContext | undefined; files: Files; }): Promise => { const config = getConfig(); @@ -758,7 +847,7 @@ export const generateServices = async ({ return; } - checkPrerequisites({ files }); + checkPrerequisites({ context, files }); const isLegacy = isLegacyClient(config); @@ -855,27 +944,90 @@ export const generateServices = async ({ files.services.add(statement); } - for (const service of client.services) { - processService({ - client, - onClientImport: (imported) => { - files.services.import({ - module: clientModulePath({ sourceOutput: servicesOutput }), - name: imported, - }); - }, - onImport: (imported) => { - files.services.import({ - // this detection could be done safer, but it shouldn't cause any issues - asType: !imported.endsWith('Transformer'), - module: `./${files.types.getName(false)}`, - name: imported, + if (client) { + for (const service of client.services) { + processService({ + client, + onClientImport: (imported) => { + files.services.import({ + module: clientModulePath({ sourceOutput: servicesOutput }), + name: imported, + }); + }, + onImport: (imported) => { + files.services.import({ + // this detection could be done safer, but it shouldn't cause any issues + asType: !imported.endsWith('Transformer'), + module: `./${files.types.getName(false)}`, + name: imported, + }); + }, + onNode: (node) => { + files.services.add(node); + }, + service, + }); + } + return; + } + + if (!context) { + return; + } + + // TODO: parser - generate services + for (const path in context.ir.paths) { + const pathItem = context.ir.paths[path as keyof IRPathsObject]; + // console.warn(pathItem) + + for (const method in pathItem) { + const operation = pathItem[method as keyof IRPathItemObject]!; + + if (operation.parameters) { + const identifier = context.file({ id: 'types' })!.identifier({ + $ref: operationDataRef({ id: operation.id }), + namespace: 'type', }); - }, - onNode: (node) => { - files.services.add(node); - }, - service, - }); + if (identifier.name) { + files.services.import({ + // this detection could be done safer, but it shouldn't cause any issues + asType: !identifier.name.endsWith('Transformer'), + module: `./${context.file({ id: 'types' })!.getName(false)}`, + name: identifier.name, + }); + } + } + + // if (!isLegacy) { + // generateImport({ + // client, + // meta: { + // // TODO: this should be exact ref to operation for consistency, + // // but name should work too as operation ID is unique + // $ref: operation.name, + // name: operation.name, + // }, + // nameTransformer: operationErrorTypeName, + // onImport, + // }); + // } + + // const successResponses = operation.responses.filter((response) => + // response.responseTypes.includes('success'), + // ); + // if (successResponses.length) { + // generateImport({ + // client, + // meta: { + // // TODO: this should be exact ref to operation for consistency, + // // but name should work too as operation ID is unique + // $ref: operation.name, + // name: operation.name, + // }, + // nameTransformer: operationResponseTypeName, + // onImport, + // }); + // } + } } }; diff --git a/packages/openapi-ts/src/generate/types.ts b/packages/openapi-ts/src/generate/types.ts index f6161eedf..9913306d0 100644 --- a/packages/openapi-ts/src/generate/types.ts +++ b/packages/openapi-ts/src/generate/types.ts @@ -1,7 +1,21 @@ import type { EnumDeclaration } from 'typescript'; +import type ts from 'typescript'; +import type { Property } from '../compiler'; import { type Comments, compiler, type Node } from '../compiler'; -import { isOperationParameterRequired } from '../openApi'; +import type { IRContext } from '../ir/context'; +import type { + IROperationObject, + IRParameterObject, + IRPathsObject, + IRResponseObject, + IRSchemaObject, +} from '../ir/ir'; +import { addItemsToSchema } from '../ir/utils'; +import { + ensureValidTypeScriptJavaScriptIdentifier, + isOperationParameterRequired, +} from '../openApi'; import type { Client, Method, @@ -12,6 +26,7 @@ import type { Files } from '../types/utils'; import { getConfig, isLegacyClient } from '../utils/config'; import { enumEntry, enumUnionType } from '../utils/enum'; import { escapeComment } from '../utils/escape'; +import { isRefOpenApiComponent } from '../utils/ref'; import { sortByName, sorterByName } from '../utils/sort'; import { setUniqueTypeName, @@ -20,8 +35,11 @@ import { } from '../utils/type'; import { TypeScriptFile } from './files'; import { + operationDataRef, operationDataTypeName, + operationErrorRef, operationErrorTypeName, + operationResponseRef, operationResponseTypeName, } from './services'; @@ -32,8 +50,16 @@ export interface TypesProps { onRemoveNode?: VoidFunction; } +interface SchemaWithType['type']> + extends Omit { + type: Extract['type'], T>; +} + const treeName = '$OpenApiTs'; +export const irRef = '#/ir/'; +const typesId = 'types'; + export const emptyModel: Model = { $refs: [], base: '', @@ -600,29 +626,1121 @@ const processServiceTypes = ({ } }; +const parseSchemaJsDoc = ({ schema }: { schema: IRSchemaObject }) => { + const comments = [ + schema.description && escapeComment(schema.description), + schema.deprecated && '@deprecated', + ]; + return comments; +}; + +const addJavaScriptEnum = ({ + $ref, + context, + schema, +}: { + $ref: string; + context: IRContext; + schema: SchemaWithType<'enum'>; +}) => { + const identifier = context.file({ id: typesId })!.identifier({ + $ref, + create: true, + namespace: 'value', + }); + + // TODO: parser - this is the old parser behavior where we would NOT + // print nested enum identifiers if they already exist. This is a + // blocker for referencing these identifiers within the file as + // we cannot guarantee just because they have a duplicate identifier, + // they have a duplicate value. + if (!identifier.created) { + return; + } + + const enumObject = schemaToEnumObject({ schema }); + + const expression = compiler.objectExpression({ + multiLine: true, + obj: enumObject.obj, + }); + const node = compiler.constVariable({ + assertion: 'const', + comment: parseSchemaJsDoc({ schema }), + exportConst: true, + expression, + name: identifier.name, + }); + return node; +}; + +const schemaToEnumObject = ({ schema }: { schema: IRSchemaObject }) => { + const typeofItems: Array< + | 'string' + | 'number' + | 'bigint' + | 'boolean' + | 'symbol' + | 'undefined' + | 'object' + | 'function' + > = []; + + const obj = (schema.items ?? []).map((item) => { + const typeOfItemConst = typeof item.const; + + if (!typeofItems.includes(typeOfItemConst)) { + typeofItems.push(typeOfItemConst); + } + + let key; + if (item.title) { + key = item.title; + } else if (typeOfItemConst === 'number') { + key = `_${item.const}`; + } else if (typeOfItemConst === 'boolean') { + const valid = typeOfItemConst ? 'true' : 'false'; + key = valid.toLocaleUpperCase(); + } else { + let valid = ensureValidTypeScriptJavaScriptIdentifier( + item.const as string, + ); + if (!valid) { + // TODO: parser - abstract empty string handling + valid = 'empty_string'; + } + key = valid.toLocaleUpperCase(); + } + return { + comments: parseSchemaJsDoc({ schema: item }), + key, + value: item.const, + }; + }); + + return { + obj, + typeofItems, + }; +}; + +const addTypeEnum = ({ + $ref, + context, + schema, +}: { + $ref: string; + context: IRContext; + schema: SchemaWithType<'enum'>; +}) => { + const identifier = context.file({ id: typesId })!.identifier({ + $ref, + create: true, + namespace: 'type', + }); + + // TODO: parser - this is the old parser behavior where we would NOT + // print nested enum identifiers if they already exist. This is a + // blocker for referencing these identifiers within the file as + // we cannot guarantee just because they have a duplicate identifier, + // they have a duplicate value. + if ( + !identifier.created && + context.config.types.enums !== 'typescript+namespace' + ) { + return; + } + + const node = compiler.typeAliasDeclaration({ + comment: parseSchemaJsDoc({ schema }), + exportType: true, + name: identifier.name, + type: schemaToType({ + context, + schema: { + ...schema, + type: undefined, + }, + }), + }); + return node; +}; + +const addTypeScriptEnum = ({ + $ref, + context, + schema, +}: { + $ref: string; + context: IRContext; + schema: SchemaWithType<'enum'>; +}) => { + const identifier = context.file({ id: typesId })!.identifier({ + $ref, + create: true, + namespace: 'value', + }); + + // TODO: parser - this is the old parser behavior where we would NOT + // print nested enum identifiers if they already exist. This is a + // blocker for referencing these identifiers within the file as + // we cannot guarantee just because they have a duplicate identifier, + // they have a duplicate value. + if ( + !identifier.created && + context.config.types.enums !== 'typescript+namespace' + ) { + return; + } + + const enumObject = schemaToEnumObject({ schema }); + + // TypeScript enums support only string and number values so we need to fallback to types + if ( + enumObject.typeofItems.filter( + (type) => type !== 'number' && type !== 'string', + ).length + ) { + const node = addTypeEnum({ + $ref, + context, + schema, + }); + return node; + } + + const node = compiler.enumDeclaration({ + leadingComment: parseSchemaJsDoc({ schema }), + name: identifier.name, + obj: enumObject.obj, + }); + return node; +}; + +const arrayTypeToIdentifier = ({ + context, + namespace, + schema, +}: { + context: IRContext; + namespace: Array; + schema: SchemaWithType<'array'>; +}) => { + if (!schema.items) { + return compiler.typeArrayNode( + compiler.keywordTypeNode({ + keyword: 'unknown', + }), + ); + } + + return compiler.typeArrayNode( + schemaToType({ + context, + namespace, + schema: { + ...schema, + type: undefined, + }, + }), + ); +}; + +const booleanTypeToIdentifier = ({ + schema, +}: { + context: IRContext; + namespace: Array; + schema: SchemaWithType<'boolean'>; +}) => { + if (schema.const !== undefined) { + return compiler.literalTypeNode({ + literal: compiler.ots.boolean(schema.const as boolean), + }); + } + + return compiler.keywordTypeNode({ + keyword: 'boolean', + }); +}; + +const enumTypeToIdentifier = ({ + $ref, + context, + namespace, + schema, +}: { + $ref?: string; + context: IRContext; + namespace: Array; + schema: SchemaWithType<'enum'>; +}): ts.TypeNode => { + // TODO: parser - add option to inline enums + if ($ref) { + const isRefComponent = isRefOpenApiComponent($ref); + + // when enums are disabled (default), emit only reusable components + // as types, otherwise the output would be broken if we skipped all enums + if (!context.config.types.enums && isRefComponent) { + const typeNode = addTypeEnum({ + $ref, + context, + schema, + }); + if (typeNode) { + context.file({ id: typesId })!.add(typeNode); + } + } + + if (context.config.types.enums === 'javascript') { + const typeNode = addTypeEnum({ + $ref, + context, + schema, + }); + if (typeNode) { + context.file({ id: typesId })!.add(typeNode); + } + + const objectNode = addJavaScriptEnum({ + $ref, + context, + schema, + }); + if (objectNode) { + context.file({ id: typesId })!.add(objectNode); + } + } + + if (context.config.types.enums === 'typescript') { + const enumNode = addTypeScriptEnum({ + $ref, + context, + schema, + }); + if (enumNode) { + context.file({ id: typesId })!.add(enumNode); + } + } + + if (context.config.types.enums === 'typescript+namespace') { + const enumNode = addTypeScriptEnum({ + $ref, + context, + schema, + }); + if (enumNode) { + if (isRefComponent) { + context.file({ id: typesId })!.add(enumNode); + } else { + // emit enum inside TypeScript namespace + namespace.push(enumNode); + } + } + } + } + + const type = schemaToType({ + context, + schema: { + ...schema, + type: undefined, + }, + }); + return type; +}; + +const numberTypeToIdentifier = ({ + schema, +}: { + context: IRContext; + namespace: Array; + schema: SchemaWithType<'number'>; +}) => { + if (schema.const !== undefined) { + return compiler.literalTypeNode({ + literal: compiler.ots.number(schema.const as number), + }); + } + + return compiler.keywordTypeNode({ + keyword: 'number', + }); +}; + +const objectTypeToIdentifier = ({ + context, + namespace, + schema, +}: { + context: IRContext; + namespace: Array; + schema: SchemaWithType<'object'>; +}) => { + let indexProperty: Property | undefined; + const schemaProperties: Array = []; + const indexPropertyItems: Array = []; + const required = schema.required ?? []; + let hasOptionalProperties = false; + + for (const name in schema.properties) { + const property = schema.properties[name]; + const isRequired = required.includes(name); + schemaProperties.push({ + comment: parseSchemaJsDoc({ schema: property }), + isReadOnly: property.accessScope === 'read', + isRequired, + name, + type: schemaToType({ + $ref: `${irRef}${name}`, + context, + namespace, + schema: property, + }), + }); + indexPropertyItems.push(property); + + if (!isRequired) { + hasOptionalProperties = true; + } + } + + if (schema.additionalProperties) { + indexPropertyItems.unshift(schema.additionalProperties); + + if (hasOptionalProperties) { + indexPropertyItems.push({ + type: 'void', + }); + } + + indexProperty = { + isRequired: true, + name: 'key', + type: schemaToType({ + context, + namespace, + schema: { + items: indexPropertyItems, + logicalOperator: 'or', + }, + }), + }; + } + + return compiler.typeInterfaceNode({ + indexProperty, + properties: schemaProperties, + useLegacyResolution: false, + }); +}; + +const stringTypeToIdentifier = ({ + schema, +}: { + context: IRContext; + namespace: Array; + schema: SchemaWithType<'string'>; +}) => { + if (schema.const !== undefined) { + return compiler.literalTypeNode({ + literal: compiler.stringLiteral({ text: schema.const as string }), + }); + } + + if (schema.format) { + if (schema.format === 'binary') { + return compiler.typeUnionNode({ + types: [ + compiler.typeReferenceNode({ + typeName: 'Blob', + }), + compiler.typeReferenceNode({ + typeName: 'File', + }), + ], + }); + } + } + + return compiler.keywordTypeNode({ + keyword: 'string', + }); +}; + +const tupleTypeToIdentifier = ({ + context, + namespace, + schema, +}: { + context: IRContext; + namespace: Array; + schema: SchemaWithType<'tuple'>; +}) => { + const itemTypes: Array = []; + + for (const item of schema.items ?? []) { + itemTypes.push( + schemaToType({ + context, + namespace, + schema: item, + }), + ); + } + + return compiler.typeTupleNode({ + types: itemTypes, + }); +}; + +const schemaTypeToIdentifier = ({ + $ref, + context, + namespace, + schema, +}: { + $ref?: string; + context: IRContext; + namespace: Array; + schema: IRSchemaObject; +}): ts.TypeNode => { + switch (schema.type as Required['type']) { + case 'array': + return arrayTypeToIdentifier({ + context, + namespace, + schema: schema as SchemaWithType<'array'>, + }); + case 'boolean': + return booleanTypeToIdentifier({ + context, + namespace, + schema: schema as SchemaWithType<'boolean'>, + }); + case 'enum': + return enumTypeToIdentifier({ + $ref, + context, + namespace, + schema: schema as SchemaWithType<'enum'>, + }); + case 'null': + return compiler.literalTypeNode({ + literal: compiler.null(), + }); + case 'number': + return numberTypeToIdentifier({ + context, + namespace, + schema: schema as SchemaWithType<'number'>, + }); + case 'object': + return objectTypeToIdentifier({ + context, + namespace, + schema: schema as SchemaWithType<'object'>, + }); + case 'string': + return stringTypeToIdentifier({ + context, + namespace, + schema: schema as SchemaWithType<'string'>, + }); + case 'tuple': + return tupleTypeToIdentifier({ + context, + namespace, + schema: schema as SchemaWithType<'tuple'>, + }); + case 'unknown': + return compiler.keywordTypeNode({ + keyword: 'unknown', + }); + case 'void': + return compiler.keywordTypeNode({ + keyword: 'undefined', + }); + } +}; + +/** + * Ensure we don't produce redundant types, e.g. string | string. + */ +const deduplicateSchema = ({ + schema, +}: { + schema: IRSchemaObject; +}): IRSchemaObject => { + if (!schema.items) { + return schema; + } + + const uniqueItems: Array = []; + const typeIds: Array = []; + + for (const item of schema.items) { + // skip nested schemas for now, handle if necessary + if ( + item.type === 'boolean' || + item.type === 'null' || + item.type === 'number' || + item.type === 'string' || + item.type === 'unknown' || + item.type === 'void' + ) { + const typeId = `${item.$ref ?? ''}${item.type ?? ''}${item.const ?? ''}`; + if (!typeIds.includes(typeId)) { + typeIds.push(typeId); + uniqueItems.push(item); + } + continue; + } + + uniqueItems.push(item); + } + + schema.items = uniqueItems; + + if ( + schema.items.length <= 1 && + schema.type !== 'array' && + schema.type !== 'enum' && + schema.type !== 'tuple' + ) { + // bring the only item up to clean up the schema + const liftedSchema = schema.items[0]; + delete schema.logicalOperator; + delete schema.items; + schema = { + ...schema, + ...liftedSchema, + }; + } + + // exclude unknown if it's the only type left + if (schema.type === 'unknown') { + return {}; + } + + return schema; +}; + +const irParametersToIrSchema = ({ + parameters, +}: { + parameters: Record; +}): IRSchemaObject => { + const irSchema: IRSchemaObject = { + type: 'object', + }; + + if (parameters) { + const properties: Record = {}; + const required: Array = []; + + for (const name in parameters) { + const parameter = parameters[name]; + + properties[name] = deduplicateSchema({ + schema: parameter.schema, + }); + + if (parameter.required) { + required.push(name); + } + } + + irSchema.properties = properties; + + if (required.length) { + irSchema.required = required; + } + } + + return irSchema; +}; + +const operationToDataType = ({ + context, + operation, +}: { + context: IRContext; + operation: IROperationObject; +}) => { + const data: IRSchemaObject = { + type: 'object', + }; + const dataRequired: Array = []; + + if (operation.body) { + if (!data.properties) { + data.properties = {}; + } + + data.properties.body = operation.body.schema; + + if (operation.body.required) { + dataRequired.push('body'); + } + } + + if (operation.parameters) { + if (!data.properties) { + data.properties = {}; + } + + // TODO: parser - handle cookie parameters + + if (operation.parameters.header) { + data.properties.headers = irParametersToIrSchema({ + parameters: operation.parameters.header, + }); + + if (data.properties.headers.required) { + dataRequired.push('headers'); + } + } + + if (operation.parameters.path) { + data.properties.path = irParametersToIrSchema({ + parameters: operation.parameters.path, + }); + + if (data.properties.path.required) { + dataRequired.push('path'); + } + } + + if (operation.parameters.query) { + data.properties.query = irParametersToIrSchema({ + parameters: operation.parameters.query, + }); + + if (data.properties.query.required) { + dataRequired.push('query'); + } + } + } + + data.required = dataRequired; + + if (data.properties) { + const identifier = context.file({ id: typesId })!.identifier({ + $ref: operationDataRef({ id: operation.id }), + create: true, + namespace: 'type', + }); + const node = compiler.typeAliasDeclaration({ + exportType: true, + name: identifier.name, + type: schemaToType({ + context, + schema: data, + }), + }); + context.file({ id: typesId })!.add(node); + } +}; + +type StatusGroup = '1XX' | '2XX' | '3XX' | '4XX' | '5XX' | 'default'; + +const statusCodeToGroup = ({ + statusCode, +}: { + statusCode: string; +}): StatusGroup => { + switch (statusCode) { + case '1XX': + return '1XX'; + case '2XX': + return '2XX'; + case '3XX': + return '3XX'; + case '4XX': + return '4XX'; + case '5XX': + return '5XX'; + case 'default': + return 'default'; + default: + return `${statusCode[0]}XX` as StatusGroup; + } +}; + +const operationToResponseTypes = ({ + context, + operation, +}: { + context: IRContext; + operation: IROperationObject; +}) => { + if (!operation.responses) { + return; + } + + const errors: IRSchemaObject = {}; + const errorsItems: Array = []; + + const responses: IRSchemaObject = {}; + const responsesItems: Array = []; + + let defaultResponse: IRResponseObject | undefined; + + for (const name in operation.responses) { + const response = operation.responses[name]!; + + switch (statusCodeToGroup({ statusCode: name })) { + case '1XX': + case '3XX': + // TODO: parser - handle informational and redirection status codes + break; + case '2XX': + responsesItems.push(response.schema); + break; + case '4XX': + case '5XX': + errorsItems.push(response.schema); + break; + case 'default': + // store default response to be evaluated last + defaultResponse = response; + break; + } + } + + // infer default response type + if (defaultResponse) { + let inferred = false; + + // assume default is intended for success if none exists yet + if (!responsesItems.length) { + responsesItems.push(defaultResponse.schema); + inferred = true; + } + + const description = ( + defaultResponse.schema.description ?? '' + ).toLocaleLowerCase(); + const $ref = (defaultResponse.schema.$ref ?? '').toLocaleLowerCase(); + + // TODO: parser - this could be rewritten using regular expressions + const successKeywords = ['success']; + if ( + successKeywords.some( + (keyword) => description.includes(keyword) || $ref.includes(keyword), + ) + ) { + responsesItems.push(defaultResponse.schema); + inferred = true; + } + + // TODO: parser - this could be rewritten using regular expressions + const errorKeywords = ['error', 'problem']; + if ( + errorKeywords.some( + (keyword) => description.includes(keyword) || $ref.includes(keyword), + ) + ) { + errorsItems.push(defaultResponse.schema); + inferred = true; + } + + // if no keyword match, assume default schema is intended for error + if (!inferred) { + errorsItems.push(defaultResponse.schema); + } + } + + addItemsToSchema({ + items: errorsItems, + schema: errors, + }); + + addItemsToSchema({ + items: responsesItems, + schema: responses, + }); + + if (errors.items) { + const deduplicatedSchema = deduplicateSchema({ + schema: errors, + }); + if (Object.keys(deduplicatedSchema).length) { + const identifier = context.file({ id: typesId })!.identifier({ + $ref: operationErrorRef({ id: operation.id }), + create: true, + namespace: 'type', + }); + const node = compiler.typeAliasDeclaration({ + exportType: true, + name: identifier.name, + type: schemaToType({ + context, + schema: deduplicatedSchema, + }), + }); + context.file({ id: typesId })!.add(node); + } + } + + if (responses.items) { + const deduplicatedSchema = deduplicateSchema({ + schema: responses, + }); + if (Object.keys(deduplicatedSchema).length) { + const identifier = context.file({ id: typesId })!.identifier({ + $ref: operationResponseRef({ id: operation.id }), + create: true, + namespace: 'type', + }); + const node = compiler.typeAliasDeclaration({ + exportType: true, + name: identifier.name, + type: schemaToType({ + context, + schema: deduplicatedSchema, + }), + }); + context.file({ id: typesId })!.add(node); + } + } +}; + +const operationToType = ({ + context, + operation, +}: { + context: IRContext; + operation: IROperationObject; +}) => { + operationToDataType({ + context, + operation, + }); + + operationToResponseTypes({ + context, + operation, + }); +}; + +const schemaToType = ({ + $ref, + context, + namespace = [], + schema, +}: { + $ref?: string; + context: IRContext; + namespace?: Array; + schema: IRSchemaObject; +}): ts.TypeNode => { + let type: ts.TypeNode | undefined; + + if (schema.$ref) { + const identifier = context.file({ id: typesId })!.identifier({ + $ref: schema.$ref, + create: true, + namespace: 'type', + }); + type = compiler.typeReferenceNode({ + typeName: identifier.name, + }); + } else if (schema.type) { + type = schemaTypeToIdentifier({ + $ref, + context, + namespace, + schema, + }); + } else if (schema.items) { + const itemTypes = schema.items.map((item) => + schemaToType({ + context, + namespace, + schema: item, + }), + ); + type = + schema.logicalOperator === 'and' + ? compiler.typeIntersectionNode({ types: itemTypes }) + : compiler.typeUnionNode({ types: itemTypes }); + } else { + // catch-all fallback for failed schemas + type = schemaTypeToIdentifier({ + context, + namespace, + schema: { + type: 'unknown', + }, + }); + } + + // emit nodes only if $ref points to a reusable component + if ($ref && isRefOpenApiComponent($ref)) { + // emit namespace if it has any members + if (namespace.length) { + const identifier = context.file({ id: typesId })!.identifier({ + $ref, + create: true, + namespace: 'value', + }); + const node = compiler.namespaceDeclaration({ + name: identifier.name, + statements: namespace, + }); + context.file({ id: typesId })!.add(node); + } + + // enum handler emits its own artifacts + if (schema.type !== 'enum') { + const identifier = context.file({ id: typesId })!.identifier({ + $ref, + create: true, + namespace: 'type', + }); + const node = compiler.typeAliasDeclaration({ + comment: parseSchemaJsDoc({ schema }), + exportType: true, + name: identifier.name, + type, + }); + context.file({ id: typesId })!.add(node); + } + } + + return type; +}; + export const generateTypes = async ({ client, + context, files, }: { - client: Client; + client: Client | undefined; + context: IRContext | undefined; files: Files; }): Promise => { - const config = getConfig(); + if (client) { + const config = getConfig(); - if (config.types.export) { - files.types = new TypeScriptFile({ - dir: config.output.path, - name: 'types.ts', - }); + if (config.types.export) { + files.types = new TypeScriptFile({ + dir: config.output.path, + name: 'types.ts', + }); + } + + const onNode: TypesProps['onNode'] = (node) => { + files.types?.add(node); + }; + + for (const model of client.models) { + processModel({ client, model, onNode }); + } + + processServiceTypes({ client, onNode }); + return; } - const onNode: TypesProps['onNode'] = (node) => { - files.types?.add(node); - }; + if (!context) { + return; + } + + // TODO: parser - once types are a plugin, this logic can be simplified + if (!context.config.types.export) { + return; + } + + context.createFile({ + id: typesId, + path: 'types', + }); + + if (context.ir.components) { + for (const name in context.ir.components.schemas) { + const schema = context.ir.components.schemas[name]; + + schemaToType({ + $ref: `#/components/schemas/${name}`, + context, + schema, + }); + } + + for (const name in context.ir.components.parameters) { + const parameter = context.ir.components.parameters[name]; - for (const model of client.models) { - processModel({ client, model, onNode }); + schemaToType({ + $ref: `#/components/parameters/${name}`, + context, + schema: parameter.schema, + }); + } } - processServiceTypes({ client, onNode }); + if (context.config.services.export || context.config.types.tree) { + for (const path in context.ir.paths) { + const pathItem = context.ir.paths[path as keyof IRPathsObject]; + + if (pathItem.delete) { + operationToType({ + context, + operation: pathItem.delete, + }); + } + + if (pathItem.get) { + operationToType({ + context, + operation: pathItem.get, + }); + } + + if (pathItem.head) { + operationToType({ + context, + operation: pathItem.head, + }); + } + + if (pathItem.options) { + operationToType({ + context, + operation: pathItem.options, + }); + } + + if (pathItem.patch) { + operationToType({ + context, + operation: pathItem.patch, + }); + } + + if (pathItem.post) { + operationToType({ + context, + operation: pathItem.post, + }); + } + + if (pathItem.put) { + operationToType({ + context, + operation: pathItem.put, + }); + } + + if (pathItem.trace) { + operationToType({ + context, + operation: pathItem.trace, + }); + } + } + + // TODO: parser - document removal of tree? migrate it? + } }; diff --git a/packages/openapi-ts/src/index.ts b/packages/openapi-ts/src/index.ts index 3519fb843..cc7930c7e 100644 --- a/packages/openapi-ts/src/index.ts +++ b/packages/openapi-ts/src/index.ts @@ -4,7 +4,15 @@ import { loadConfig } from 'c12'; import { sync } from 'cross-spawn'; import { generateOutput } from './generate/output'; +import type { IRContext } from './ir/context'; import { parse, parseExperimental } from './openApi'; +import type { ParserConfig } from './openApi/config'; +import { + operationFilterFn, + operationNameFn, + operationParameterFilterFn, + operationParameterNameFn, +} from './openApi/config'; import { defaultPluginConfigs } from './plugins'; import type { Client } from './types/client'; import type { ClientConfig, Config, UserConfig } from './types/config'; @@ -12,12 +20,6 @@ import { CLIENTS } from './types/config'; import { getConfig, isLegacyClient, setConfig } from './utils/config'; import { getOpenApiSpec } from './utils/getOpenApiSpec'; import { registerHandlebarTemplates } from './utils/handlebars'; -import { - operationFilterFn, - operationNameFn, - operationParameterFilterFn, - operationParameterNameFn, -} from './utils/parse'; import { Performance, PerformanceReport } from './utils/performance'; import { postProcessClient } from './utils/postprocess'; @@ -339,46 +341,57 @@ export async function createClient( >); Performance.end('openapi'); - if (config.experimental_parser) { - Performance.start('experimental_parser'); - parseExperimental({ + let client: Client | undefined; + let context: IRContext | undefined; + + Performance.start('parser'); + const parserConfig: ParserConfig = { + filterFn: { + operation: operationFilterFn, + operationParameter: operationParameterFilterFn, + }, + nameFn: { + operation: operationNameFn, + operationParameter: operationParameterNameFn, + }, + }; + if (config.experimental_parser && !isLegacyClient(config)) { + context = parseExperimental({ + config, + parserConfig, spec: openApi, }); - Performance.end('experimental_parser'); - } else { - Performance.start('parser'); + } + + if (!context) { const parsed = parse({ - config: { - filterFn: { - operation: operationFilterFn, - operationParameter: operationParameterFilterFn, - }, - nameFn: { - operation: operationNameFn, - operationParameter: operationParameterNameFn, - }, - }, openApi, + parserConfig, }); - const client = postProcessClient(parsed); - Performance.end('parser'); - - logClientMessage(); + client = postProcessClient(parsed); + } + Performance.end('parser'); - Performance.start('generator'); - await generateOutput(openApi, client, templates); - Performance.end('generator'); + logClientMessage(); - Performance.start('postprocess'); - if (!config.dryRun) { - processOutput(); + Performance.start('generator'); + await generateOutput({ + client, + context, + openApi, + templates, + }); + Performance.end('generator'); - console.log('✨ Done! Your client is located in:', config.output.path); - } - Performance.end('postprocess'); + Performance.start('postprocess'); + if (!config.dryRun) { + processOutput(); - return client; + console.log('✨ Done! Your client is located in:', config.output.path); } + Performance.end('postprocess'); + + return context || client; }; const clients: Array = []; @@ -386,7 +399,7 @@ export async function createClient( const pClients = configs.map((config) => pCreateClient(config)); for (const pClient of pClients) { const client = await pClient(); - if (client) { + if (client && 'version' in client) { clients.push(client); } } @@ -423,5 +436,5 @@ export default { }; export type { OpenApiV3_0_3 } from './openApi/3.0.3'; -export type { OpenApiV3_1 } from './openApi/3.1'; +export type { OpenApiV3_1_0 } from './openApi/3.1.0'; export type { UserConfig } from './types/config'; diff --git a/packages/openapi-ts/src/ir/context.ts b/packages/openapi-ts/src/ir/context.ts new file mode 100644 index 000000000..84d1e8c3c --- /dev/null +++ b/packages/openapi-ts/src/ir/context.ts @@ -0,0 +1,74 @@ +import path from 'node:path'; + +import { TypeScriptFile } from '../generate/files'; +import type { ParserConfig } from '../openApi/config'; +import type { Config } from '../types/config'; +import type { Files } from '../types/utils'; +import { resolveRef } from '../utils/ref'; +import type { IR } from './ir'; + +interface ContextFile { + /** + * Unique file identifier. + */ + id: string; + /** + * Relative file path to the output path. + * @example + * 'bar/foo.ts' + */ + path: string; +} + +export class IRContext = any> { + public config: Config; + public files: Files; + public ir: IR; + public parserConfig: ParserConfig; + public spec: Spec; + + constructor({ + config, + parserConfig, + spec, + }: { + config: Config; + parserConfig: ParserConfig; + spec: Spec; + }) { + this.config = config; + this.files = {}; + this.ir = {}; + this.parserConfig = parserConfig; + this.spec = spec; + } + + /** + * Create and return a new TypeScript file. Also set the current file context + * to the newly created file. + */ + public createFile(file: ContextFile): TypeScriptFile { + const outputParts = file.path.split('/'); + const outputDir = path.resolve( + this.config.output.path, + ...outputParts.slice(0, outputParts.length - 1), + ); + const createdFile = new TypeScriptFile({ + dir: outputDir, + name: `${outputParts[outputParts.length - 1]}.ts`, + }); + this.files[file.id] = createdFile; + return createdFile; + } + + public file({ id }: Pick): TypeScriptFile | undefined { + return this.files[id]; + } + + public resolveRef($ref: string) { + return resolveRef({ + $ref, + spec: this.spec, + }); + } +} diff --git a/packages/openapi-ts/src/ir/ir.d.ts b/packages/openapi-ts/src/ir/ir.d.ts new file mode 100644 index 000000000..38811c476 --- /dev/null +++ b/packages/openapi-ts/src/ir/ir.d.ts @@ -0,0 +1,129 @@ +import type { JsonSchemaDraft2020_12 } from '../openApi/3.1.0/types/json-schema-draft-2020-12'; + +export interface IR { + components?: IRComponentsObject; + paths?: IRPathsObject; +} + +interface IRComponentsObject { + parameters?: Record; + schemas?: Record; +} + +interface IRPathsObject { + [path: `/${string}`]: IRPathItemObject; +} + +interface IRPathItemObject { + delete?: IROperationObject; + get?: IROperationObject; + head?: IROperationObject; + options?: IROperationObject; + patch?: IROperationObject; + post?: IROperationObject; + put?: IROperationObject; + trace?: IROperationObject; +} + +export interface IROperationObject { + body?: IRBodyObject; + deprecated?: boolean; + description?: string; + id: string; + parameters?: IRParametersObject; + responses?: IRResponsesObject; + // TODO: parser - add more properties + // security?: ReadonlyArray; + // servers?: ReadonlyArray; + summary?: string; + tags?: ReadonlyArray; +} + +export interface IRBodyObject { + required?: boolean; + schema: IRSchemaObject; +} + +export interface IRParametersObject { + cookie?: Record; + header?: Record; + path?: Record; + query?: Record; +} + +export interface IRParameterObject { + /** + * Endpoint parameters must specify their location. + */ + location: 'cookie' | 'header' | 'path' | 'query'; + name: string; + required?: boolean; + schema: IRSchemaObject; +} + +export interface IRResponsesObject { + /** + * Any {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#http-status-codes HTTP status code} can be used as the property name, but only one property per code, to describe the expected response for that HTTP status code. This field MUST be enclosed in quotation marks (for example, "200") for compatibility between JSON and YAML. To define a range of response codes, this field MAY contain the uppercase wildcard character `X`. For example, `2XX` represents all response codes between `[200-299]`. Only the following range definitions are allowed: `1XX`, `2XX`, `3XX`, `4XX`, and `5XX`. If a response is defined using an explicit code, the explicit code definition takes precedence over the range definition for that code. + */ + [statusCode: string]: IRResponseObject | undefined; + /** + * The documentation of responses other than the ones declared for specific HTTP response codes. Use this field to cover undeclared responses. + */ + default?: IRResponseObject; +} + +export interface IRResponseObject { + // TODO: parser - handle headers, links, and possibly other media types? + schema: IRSchemaObject; +} + +export interface IRSchemaObject + extends Pick< + JsonSchemaDraft2020_12, + '$ref' | 'const' | 'deprecated' | 'description' | 'required' | 'title' + > { + /** + * If the schema is intended to be used as an object property, it can be + * marked as read-only or write-only. + */ + accessScope?: 'read' | 'write'; + /** + * If type is `object`, `additionalProperties` can be used to either define + * a schema for properties not included in `properties` or disallow such + * properties altogether. + */ + additionalProperties?: IRSchemaObject | false; + /** + * Any string value is accepted as `format`. + */ + format?: JsonSchemaDraft2020_12['format'] | 'binary' | 'integer'; + /** + * If schema resolves into multiple items instead of a simple `type`, they + * will be included in `items` array. + */ + items?: ReadonlyArray; + /** + * When resolving a list of items, we need to know the relationship between + * them. `logicalOperator` specifies this logical relationship. + * @default 'or' + */ + logicalOperator?: 'and' | 'or'; + /** + * When type is `object`, `properties` will contain a map of its properties. + */ + properties?: Record; + /** + * Each schema eventually resolves into `type`. + */ + type?: + | 'array' + | 'boolean' + | 'enum' + | 'null' + | 'number' + | 'object' + | 'string' + | 'tuple' + | 'unknown' + | 'void'; +} diff --git a/packages/openapi-ts/src/ir/parameter.ts b/packages/openapi-ts/src/ir/parameter.ts new file mode 100644 index 000000000..76613d258 --- /dev/null +++ b/packages/openapi-ts/src/ir/parameter.ts @@ -0,0 +1,35 @@ +import type { IRParametersObject } from './ir'; + +export const hasParametersObjectRequired = ( + parameters: IRParametersObject | undefined, +): boolean => { + if (!parameters) { + return false; + } + + for (const name in parameters.cookie) { + if (parameters.cookie[name].required) { + return true; + } + } + + for (const name in parameters.header) { + if (parameters.header[name].required) { + return true; + } + } + + for (const name in parameters.path) { + if (parameters.path[name].required) { + return true; + } + } + + for (const name in parameters.query) { + if (parameters.query[name].required) { + return true; + } + } + + return false; +}; diff --git a/packages/openapi-ts/src/ir/utils.ts b/packages/openapi-ts/src/ir/utils.ts new file mode 100644 index 000000000..4a4822bee --- /dev/null +++ b/packages/openapi-ts/src/ir/utils.ts @@ -0,0 +1,25 @@ +import type { IRSchemaObject } from './ir'; + +/** + * Simply adds `items` to the schema. Also handles setting the logical operator + * and avoids setting it for a single item or tuples. + */ +export const addItemsToSchema = ({ + items, + schema, +}: { + items: Array; + schema: IRSchemaObject; +}) => { + if (!items.length) { + return; + } + + schema.items = items; + + if (items.length === 1 || schema.type === 'tuple') { + return; + } + + schema.logicalOperator = 'or'; +}; diff --git a/packages/openapi-ts/src/openApi/3.0.3/parser/index.ts b/packages/openapi-ts/src/openApi/3.0.3/parser/index.ts index 873231950..b5d0220ce 100644 --- a/packages/openapi-ts/src/openApi/3.0.3/parser/index.ts +++ b/packages/openapi-ts/src/openApi/3.0.3/parser/index.ts @@ -1,6 +1,7 @@ +import type { IRContext } from '../../../ir/context'; import type { OpenApiV3_0_3 } from '../types/spec'; -export const parseV3_0_3 = (spec: OpenApiV3_0_3) => { +export const parseV3_0_3 = (context: IRContext): undefined => { // TODO - console.log(spec); + console.log(context.spec); }; diff --git a/packages/openapi-ts/src/openApi/3.0.3/types/spec.ts b/packages/openapi-ts/src/openApi/3.0.3/types/spec.d.ts similarity index 100% rename from packages/openapi-ts/src/openApi/3.0.3/types/spec.ts rename to packages/openapi-ts/src/openApi/3.0.3/types/spec.d.ts diff --git a/packages/openapi-ts/src/openApi/3.1.0/index.ts b/packages/openapi-ts/src/openApi/3.1.0/index.ts new file mode 100644 index 000000000..9dde9ead8 --- /dev/null +++ b/packages/openapi-ts/src/openApi/3.1.0/index.ts @@ -0,0 +1,2 @@ +export { parseV3_1_0 } from './parser'; +export type { OpenApiV3_1_0 } from './types/spec'; diff --git a/packages/openapi-ts/src/openApi/3.1.0/parser/index.ts b/packages/openapi-ts/src/openApi/3.1.0/parser/index.ts new file mode 100644 index 000000000..d83aa6d2f --- /dev/null +++ b/packages/openapi-ts/src/openApi/3.1.0/parser/index.ts @@ -0,0 +1,217 @@ +import type { IRContext } from '../../../ir/context'; +import type { + OpenApiV3_1_0, + ParameterObject, + PathItemObject, + PathsObject, +} from '../types/spec'; +import { parseOperation } from './operation'; +import { + mergeParametersObjects, + parametersArrayToObject, + parseParameter, +} from './parameter'; +import { parseSchema } from './schema'; + +export const parseV3_1_0 = (context: IRContext) => { + const operationIds = new Map(); + + for (const path in context.spec.paths) { + const pathItem = context.spec.paths[path as keyof PathsObject]; + + const finalPathItem = pathItem.$ref + ? { + ...context.resolveRef(pathItem.$ref), + ...pathItem, + } + : pathItem; + + const operationArgs: Omit[0], 'method'> = + { + context, + operation: { + description: finalPathItem.description, + id: '', + parameters: parametersArrayToObject({ + context, + parameters: finalPathItem.parameters, + }), + servers: finalPathItem.servers, + summary: finalPathItem.summary, + }, + operationIds, + path: path as keyof PathsObject, + }; + + if (finalPathItem.delete) { + parseOperation({ + ...operationArgs, + method: 'delete', + operation: { + ...operationArgs.operation, + ...finalPathItem.delete, + parameters: mergeParametersObjects({ + source: parametersArrayToObject({ + context, + parameters: finalPathItem.delete.parameters, + }), + target: operationArgs.operation.parameters, + }), + }, + }); + } + + if (finalPathItem.get) { + parseOperation({ + ...operationArgs, + method: 'get', + operation: { + ...operationArgs.operation, + ...finalPathItem.get, + parameters: mergeParametersObjects({ + source: parametersArrayToObject({ + context, + parameters: finalPathItem.get.parameters, + }), + target: operationArgs.operation.parameters, + }), + }, + }); + } + + if (finalPathItem.head) { + parseOperation({ + ...operationArgs, + method: 'head', + operation: { + ...operationArgs.operation, + ...finalPathItem.head, + parameters: mergeParametersObjects({ + source: parametersArrayToObject({ + context, + parameters: finalPathItem.head.parameters, + }), + target: operationArgs.operation.parameters, + }), + }, + }); + } + + if (finalPathItem.options) { + parseOperation({ + ...operationArgs, + method: 'options', + operation: { + ...operationArgs.operation, + ...finalPathItem.options, + parameters: mergeParametersObjects({ + source: parametersArrayToObject({ + context, + parameters: finalPathItem.options.parameters, + }), + target: operationArgs.operation.parameters, + }), + }, + }); + } + + if (finalPathItem.patch) { + parseOperation({ + ...operationArgs, + method: 'patch', + operation: { + ...operationArgs.operation, + ...finalPathItem.patch, + parameters: mergeParametersObjects({ + source: parametersArrayToObject({ + context, + parameters: finalPathItem.patch.parameters, + }), + target: operationArgs.operation.parameters, + }), + }, + }); + } + + if (finalPathItem.post) { + parseOperation({ + ...operationArgs, + method: 'post', + operation: { + ...operationArgs.operation, + ...finalPathItem.post, + parameters: mergeParametersObjects({ + source: parametersArrayToObject({ + context, + parameters: finalPathItem.post.parameters, + }), + target: operationArgs.operation.parameters, + }), + }, + }); + } + + if (finalPathItem.put) { + parseOperation({ + ...operationArgs, + method: 'put', + operation: { + ...operationArgs.operation, + ...finalPathItem.put, + parameters: mergeParametersObjects({ + source: parametersArrayToObject({ + context, + parameters: finalPathItem.put.parameters, + }), + target: operationArgs.operation.parameters, + }), + }, + }); + } + + if (finalPathItem.trace) { + parseOperation({ + ...operationArgs, + method: 'trace', + operation: { + ...operationArgs.operation, + ...finalPathItem.trace, + parameters: mergeParametersObjects({ + source: parametersArrayToObject({ + context, + parameters: finalPathItem.trace.parameters, + }), + target: operationArgs.operation.parameters, + }), + }, + }); + } + } + + // TODO: parser - handle more component types, old parser handles only parameters and schemas + if (context.spec.components) { + for (const name in context.spec.components.parameters) { + const parameterOrReference = context.spec.components.parameters[name]; + const parameter = + '$ref' in parameterOrReference + ? context.resolveRef(parameterOrReference.$ref) + : parameterOrReference; + + parseParameter({ + context, + name, + parameter, + }); + } + + for (const name in context.spec.components.schemas) { + const schema = context.spec.components.schemas[name]; + + parseSchema({ + context, + name, + schema, + }); + } + } +}; diff --git a/packages/openapi-ts/src/openApi/3.1.0/parser/mediaType.ts b/packages/openapi-ts/src/openApi/3.1.0/parser/mediaType.ts new file mode 100644 index 000000000..34cdef04f --- /dev/null +++ b/packages/openapi-ts/src/openApi/3.1.0/parser/mediaType.ts @@ -0,0 +1,40 @@ +import type { MediaTypeObject, SchemaObject } from '../types/spec'; + +const SUPPORTED_MEDIA_TYPES = [ + 'application/json-patch+json', + 'application/json', + 'application/ld+json', + 'application/x-www-form-urlencoded', + 'audio/*', + 'multipart/batch', + 'multipart/form-data', + 'multipart/mixed', + 'multipart/related', + 'text/json', + 'text/plain', + 'video/*', +] as const; + +type MediaType = (typeof SUPPORTED_MEDIA_TYPES)[number]; + +interface Content { + mediaType: MediaType; + schema: SchemaObject | undefined; +} + +export const getMediaTypeSchema = ({ + content, +}: { + content: Record | undefined; +}): Content | undefined => { + for (const rawMediaType in content) { + const mediaTypeContent = content[rawMediaType]; + const mediaType: MediaType = rawMediaType.split(';')[0].trim() as MediaType; + if (SUPPORTED_MEDIA_TYPES.includes(mediaType)) { + return { + mediaType, + schema: mediaTypeContent.schema, + }; + } + } +}; diff --git a/packages/openapi-ts/src/openApi/3.1.0/parser/operation.ts b/packages/openapi-ts/src/openApi/3.1.0/parser/operation.ts new file mode 100644 index 000000000..9f9a09f63 --- /dev/null +++ b/packages/openapi-ts/src/openApi/3.1.0/parser/operation.ts @@ -0,0 +1,199 @@ +import type { IRContext } from '../../../ir/context'; +import type { IROperationObject, IRPathsObject } from '../../../ir/ir'; +import type { + OperationObject, + PathItemObject, + RequestBodyObject, + ResponseObject, +} from '../types/spec'; +import { getMediaTypeSchema } from './mediaType'; +import { schemaToIrSchema } from './schema'; + +interface Operation + extends Omit, + Pick {} + +const parseOperationJsDoc = ({ + irOperation, + operation, +}: { + irOperation: IROperationObject; + operation: Operation; +}) => { + if (operation.deprecated !== undefined) { + irOperation.deprecated = operation.deprecated; + } + + if (operation.description) { + irOperation.description = operation.description; + } + + if (operation.summary) { + irOperation.summary = operation.summary; + } + + if (operation.tags && operation.tags.length) { + irOperation.tags = operation.tags; + } +}; + +const initIrOperation = ({ + operation, +}: { + operation: Operation; +}): IROperationObject => { + const irOperation: IROperationObject = { + id: operation.id, + }; + + parseOperationJsDoc({ + irOperation, + operation, + }); + + return irOperation; +}; + +const operationToIrOperation = ({ + context, + operation, +}: { + context: IRContext; + operation: Operation; +}): IROperationObject => { + const irOperation = initIrOperation({ operation }); + + if (operation.parameters) { + irOperation.parameters = operation.parameters; + } + + if (operation.requestBody) { + const requestBodyObject = + '$ref' in operation.requestBody + ? context.resolveRef(operation.requestBody.$ref) + : operation.requestBody; + const content = getMediaTypeSchema({ + content: requestBodyObject.content, + }); + if (content) { + irOperation.body = { + schema: schemaToIrSchema({ + context, + schema: { + description: requestBodyObject.description, + ...content.schema, + }, + }), + }; + + if (requestBodyObject.required) { + irOperation.body.required = requestBodyObject.required; + } + } + } + + for (const name in operation.responses) { + const response = operation.responses[name]!; + const responseObject = + '$ref' in response + ? context.resolveRef(response.$ref) + : response; + const content = getMediaTypeSchema({ + content: responseObject.content, + }); + if (content) { + if (!irOperation.responses) { + irOperation.responses = {}; + } + + irOperation.responses[name] = { + schema: schemaToIrSchema({ + context, + schema: { + description: responseObject.description, + ...content.schema, + }, + }), + }; + } else if (name === '204') { + if (!irOperation.responses) { + irOperation.responses = {}; + } + + irOperation.responses[name] = { + schema: { + description: responseObject.description, + type: 'void', + }, + }; + } + } + + // TODO: parser - handle security + // baz: operation.security + + // TODO: parser - handle servers + // qux: operation.servers + + return irOperation; +}; + +export const parseOperation = ({ + context, + method, + operation, + operationIds, + path, +}: { + context: IRContext; + method: Extract< + keyof PathItemObject, + 'delete' | 'get' | 'head' | 'options' | 'patch' | 'post' | 'put' | 'trace' + >; + operation: Operation; + operationIds: Map; + path: keyof IRPathsObject; +}) => { + const operationKey = `${method.toUpperCase()} ${path}`; + + // TODO: parser - move services to plugin, cleaner syntax + if ( + !context.parserConfig.filterFn.operation({ + config: context.config, + operationKey, + }) + ) { + return; + } + + // TODO: parser - support throw on duplicate + if (operation.operationId) { + if (operationIds.has(operation.operationId)) { + console.warn( + `❗️ Duplicate operationId: ${operation.operationId} in ${operationKey}. Please ensure your operation IDs are unique. This behavior is not supported and will likely lead to unexpected results.`, + ); + } else { + operationIds.set(operation.operationId, operationKey); + } + } + + if (!context.ir.paths) { + context.ir.paths = {}; + } + + if (!context.ir.paths[path]) { + context.ir.paths[path] = {}; + } + + operation.id = context.parserConfig.nameFn.operation({ + config: context.config, + method, + operationId: operation.operationId, + path, + }); + + context.ir.paths[path][method] = operationToIrOperation({ + context, + operation, + }); +}; diff --git a/packages/openapi-ts/src/openApi/3.1.0/parser/parameter.ts b/packages/openapi-ts/src/openApi/3.1.0/parser/parameter.ts new file mode 100644 index 000000000..076e41019 --- /dev/null +++ b/packages/openapi-ts/src/openApi/3.1.0/parser/parameter.ts @@ -0,0 +1,163 @@ +import type { IRContext } from '../../../ir/context'; +import type { IRParameterObject, IRParametersObject } from '../../../ir/ir'; +import type { ParameterObject, ReferenceObject } from '../types/spec'; +import { getMediaTypeSchema } from './mediaType'; +import { schemaToIrSchema } from './schema'; + +export const parametersArrayToObject = ({ + context, + parameters, +}: { + context: IRContext; + parameters?: ReadonlyArray; +}): IRParametersObject | undefined => { + if (!parameters || !Object.keys(parameters).length) { + return; + } + + const parametersObject: IRParametersObject = {}; + + for (const parameterOrReference of parameters) { + const parameter = + '$ref' in parameterOrReference + ? context.resolveRef(parameterOrReference.$ref) + : parameterOrReference; + + if (!parametersObject[parameter.in]) { + parametersObject[parameter.in] = {}; + } + + parametersObject[parameter.in]![parameter.name] = parameterToIrParameter({ + context, + parameter, + }); + } + + return parametersObject; +}; + +export const mergeParametersObjects = ({ + source, + target, +}: { + source: IRParametersObject | undefined; + target: IRParametersObject | undefined; +}): IRParametersObject | undefined => { + const result = { ...target }; + + if (source) { + if (source.cookie) { + if (result.cookie) { + result.cookie = { + ...result.cookie, + ...source.cookie, + }; + } else { + result.cookie = source.cookie; + } + } + + if (source.header) { + if (result.header) { + result.header = { + ...result.header, + ...source.header, + }; + } else { + result.header = source.header; + } + } + + if (source.path) { + if (result.path) { + result.path = { + ...result.path, + ...source.path, + }; + } else { + result.path = source.path; + } + } + + if (source.query) { + if (result.query) { + result.query = { + ...result.query, + ...source.query, + }; + } else { + result.query = source.query; + } + } + } + + if (!Object.keys(result).length) { + return; + } + + return result; +}; + +const parameterToIrParameter = ({ + context, + parameter, +}: { + context: IRContext; + parameter: ParameterObject; +}): IRParameterObject => { + // TODO: parser - fix + let schema = parameter.schema; + + if (!schema) { + const content = getMediaTypeSchema({ + content: parameter.content, + }); + if (content) { + schema = content.schema; + } + } + + const irSchema = schemaToIrSchema({ + context, + schema: { + deprecated: parameter.deprecated, + description: parameter.description, + ...schema, + }, + }); + + const irParameter: IRParameterObject = { + location: parameter.in, + name: parameter.name, + schema: irSchema, + }; + + if (parameter.required) { + irParameter.required = parameter.required; + } + + return irParameter; +}; + +export const parseParameter = ({ + context, + name, + parameter, +}: { + context: IRContext; + name: string; + parameter: ParameterObject; +}) => { + if (!context.ir.components) { + context.ir.components = {}; + } + + if (!context.ir.components.parameters) { + context.ir.components.parameters = {}; + } + + context.ir.components.parameters[name] = parameterToIrParameter({ + context, + parameter, + }); +}; diff --git a/packages/openapi-ts/src/openApi/3.1.0/parser/schema.ts b/packages/openapi-ts/src/openApi/3.1.0/parser/schema.ts new file mode 100644 index 000000000..04a63e4eb --- /dev/null +++ b/packages/openapi-ts/src/openApi/3.1.0/parser/schema.ts @@ -0,0 +1,787 @@ +import type { IRContext } from '../../../ir/context'; +import type { IRSchemaObject } from '../../../ir/ir'; +import { addItemsToSchema } from '../../../ir/utils'; +import type { SchemaObject } from '../types/spec'; + +type SchemaWithRequired> = Omit< + SchemaObject, + K +> & + Pick, K>; + +type SchemaType = Extract['type'], string>; + +const getSchemaTypes = ({ + schema, +}: { + schema: SchemaObject; +}): ReadonlyArray => + typeof schema.type === 'string' ? [schema.type] : schema.type ?? []; + +const parseSchemaMeta = ({ + irSchema, + schema, +}: { + irSchema: IRSchemaObject; + schema: SchemaObject; +}) => { + if (schema.const !== undefined) { + irSchema.const = schema.const; + + // try to infer schema type + if (!schema.type) { + if (schema.const === null) { + irSchema.type = 'null'; + } else { + switch (typeof schema.const) { + case 'bigint': + case 'number': + irSchema.type = 'number'; + break; + case 'boolean': + irSchema.type = 'boolean'; + break; + case 'string': + irSchema.type = 'string'; + break; + } + } + } + } + + if (schema.format) { + irSchema.format = schema.format; + } + + if (schema.readOnly) { + irSchema.accessScope = 'read'; + } else if (schema.writeOnly) { + irSchema.accessScope = 'write'; + } + + if (schema.title) { + irSchema.title = schema.title; + } +}; + +const parseArray = ({ + context, + irSchema = {}, + schema, +}: { + context: IRContext; + irSchema?: IRSchemaObject; + schema: SchemaObject; +}): IRSchemaObject => { + if ( + (schema.prefixItems && schema.prefixItems.length) || + (schema.maxItems && schema.maxItems === schema.minItems) + ) { + irSchema.type = 'tuple'; + } else { + irSchema.type = 'array'; + } + + let schemaItems: Array = []; + + for (const item of schema.prefixItems ?? []) { + schemaItems.push( + schemaToIrSchema({ + context, + schema: item, + }), + ); + } + + if (schema.items) { + const isComposedSchema = Boolean( + schema.items.allOf || schema.items.anyOf || schema.items.oneOf, + ); + const irItemsSchema = schemaToIrSchema({ + context, + schema: schema.items, + }); + + if ( + !schemaItems.length && + schema.maxItems && + schema.maxItems === schema.minItems + ) { + schemaItems = Array(schema.maxItems).fill(irItemsSchema); + } else { + if (isComposedSchema) { + // bring composition up to avoid incorrectly nested arrays + irSchema = { + ...irSchema, + ...irItemsSchema, + }; + } else { + schemaItems.push(irItemsSchema); + } + } + } + + addItemsToSchema({ + items: schemaItems, + schema: irSchema, + }); + + return irSchema; +}; + +const parseBoolean = ({ + irSchema = {}, +}: { + context: IRContext; + irSchema?: IRSchemaObject; + schema: SchemaObject; +}): IRSchemaObject => { + irSchema.type = 'boolean'; + + return irSchema; +}; + +const parseNull = ({ + irSchema = {}, +}: { + context: IRContext; + irSchema?: IRSchemaObject; + schema: SchemaObject; +}) => { + irSchema.type = 'null'; + + return irSchema; +}; + +const parseNumber = ({ + irSchema = {}, +}: { + context: IRContext; + irSchema?: IRSchemaObject; + schema: SchemaObject; +}): IRSchemaObject => { + irSchema.type = 'number'; + + return irSchema; +}; + +const parseObject = ({ + context, + irSchema = {}, + schema, +}: { + context: IRContext; + irSchema?: IRSchemaObject; + schema: SchemaObject; +}): IRSchemaObject => { + irSchema.type = 'object'; + + const schemaProperties: Record = {}; + + for (const name in schema.properties) { + const property = schema.properties[name]; + if (typeof property === 'boolean') { + // TODO: parser - handle boolean properties + } else { + schemaProperties[name] = schemaToIrSchema({ + context, + schema: property, + }); + } + } + + if (Object.keys(schemaProperties).length) { + irSchema.properties = schemaProperties; + } + + if (schema.additionalProperties !== undefined) { + if (typeof schema.additionalProperties === 'boolean') { + if (schema.additionalProperties) { + // no need to add "any" additional properties if there are no defined properties + if (irSchema.properties) { + irSchema.additionalProperties = { + type: 'unknown', + }; + } + } else { + // TODO: parser - handle additional properties: false + } + } else { + const irAdditionalPropertiesSchema = schemaToIrSchema({ + context, + schema: schema.additionalProperties, + }); + // no need to add "any" additional properties if there are no defined properties + if ( + irSchema.properties || + irAdditionalPropertiesSchema.type !== 'unknown' + ) { + irSchema.additionalProperties = irAdditionalPropertiesSchema; + } + } + } + + if (schema.required) { + irSchema.required = schema.required; + } + + return irSchema; +}; + +const parseString = ({ + irSchema = {}, +}: { + context: IRContext; + irSchema?: IRSchemaObject; + schema: SchemaObject; +}): IRSchemaObject => { + irSchema.type = 'string'; + + return irSchema; +}; + +const parseSchemaJsDoc = ({ + irSchema, + schema, +}: { + irSchema: IRSchemaObject; + schema: SchemaObject; +}) => { + if (schema.deprecated !== undefined) { + irSchema.deprecated = schema.deprecated; + } + + if (schema.description) { + irSchema.description = schema.description; + } +}; + +const initIrSchema = ({ schema }: { schema: SchemaObject }): IRSchemaObject => { + const irSchema: IRSchemaObject = {}; + + parseSchemaJsDoc({ + irSchema, + schema, + }); + + return irSchema; +}; + +const parseAllOf = ({ + context, + schema, +}: { + context: IRContext; + schema: SchemaWithRequired<'allOf'>; +}): IRSchemaObject => { + let irSchema = initIrSchema({ schema }); + + const schemaItems: Array = []; + const schemaTypes = getSchemaTypes({ schema }); + + const compositionSchemas = schema.allOf; + + for (const compositionSchema of compositionSchemas) { + schemaItems.push( + schemaToIrSchema({ + context, + schema: compositionSchema, + }), + ); + } + + if (schemaTypes.includes('object')) { + const irObjectSchema = parseOneType({ + context, + schema: { + ...schema, + type: 'object', + }, + }); + + if (irObjectSchema.properties) { + for (const requiredProperty of irObjectSchema.required ?? []) { + if (!irObjectSchema.properties[requiredProperty]) { + for (const compositionSchema of compositionSchemas) { + // TODO: parser - this could be probably resolved more accurately + const finalCompositionSchema = compositionSchema.$ref + ? context.resolveRef(compositionSchema.$ref) + : compositionSchema; + + if ( + getSchemaTypes({ schema: finalCompositionSchema }).includes( + 'object', + ) + ) { + const irCompositionSchema = parseOneType({ + context, + schema: { + ...finalCompositionSchema, + type: 'object', + }, + }); + + if (irCompositionSchema.properties?.[requiredProperty]) { + irObjectSchema.properties[requiredProperty] = + irCompositionSchema.properties[requiredProperty]; + break; + } + } + } + } + } + schemaItems.push(irObjectSchema); + } + } + + if (schemaItems.length) { + irSchema.items = schemaItems; + irSchema.logicalOperator = 'and'; + } + + if (schemaTypes.includes('null')) { + // nest composition to avoid producing an intersection with null + const nestedItems: Array = [ + { + type: 'null', + }, + ]; + + if (schemaItems.length) { + nestedItems.unshift(irSchema); + } + + irSchema = { + items: nestedItems, + logicalOperator: 'or', + }; + } + + if (schema.discriminator) { + // TODO: parser - support discriminator + // TODO: parser - maybe abstract discriminator from oneOf, anyOf, and allOf + } + + return irSchema; +}; + +const parseAnyOf = ({ + context, + schema, +}: { + context: IRContext; + schema: SchemaWithRequired<'anyOf'>; +}): IRSchemaObject => { + let irSchema = initIrSchema({ schema }); + + const schemaItems: Array = []; + const schemaTypes = getSchemaTypes({ schema }); + + for (const anyOf of schema.anyOf) { + schemaItems.push( + schemaToIrSchema({ + context, + schema: anyOf, + }), + ); + } + + if (schemaTypes.includes('null')) { + schemaItems.push({ type: 'null' }); + } + + addItemsToSchema({ + items: schemaItems, + schema: irSchema, + }); + + if (schemaTypes.includes('object')) { + // nest composition to avoid producing a union with object properties + const irObjectSchema = parseOneType({ + context, + schema: { + ...schema, + type: 'object', + }, + }); + + if (irObjectSchema.properties) { + irSchema = { + items: [irSchema, irObjectSchema], + logicalOperator: 'and', + }; + } + } + + if (schema.discriminator) { + // TODO: parser - support discriminator + // TODO: parser - maybe abstract discriminator from oneOf, anyOf, and allOf + } + + return irSchema; +}; + +const parseEnum = ({ + context, + schema, +}: { + context: IRContext; + schema: SchemaWithRequired<'enum'>; +}): IRSchemaObject => { + const irSchema = initIrSchema({ schema }); + + irSchema.type = 'enum'; + + const schemaItems: Array = []; + + for (const [index, enumValue] of schema.enum.entries()) { + const typeOfEnumValue = typeof enumValue; + if ( + typeOfEnumValue === 'string' || + typeOfEnumValue === 'number' || + typeOfEnumValue === 'boolean' + ) { + schemaItems.push( + parseOneType({ + context, + schema: { + const: enumValue, + description: schema['x-enum-descriptions']?.[index], + title: + schema['x-enum-varnames']?.[index] ?? + schema['x-enumNames']?.[index], + type: typeOfEnumValue, + }, + }), + ); + } else { + console.warn( + '🚨', + `unhandled "${typeOfEnumValue}" typeof value "${enumValue}" for enum`, + schema.enum, + ); + } + } + + addItemsToSchema({ + items: schemaItems, + schema: irSchema, + }); + + return irSchema; +}; + +const parseOneOf = ({ + context, + schema, +}: { + context: IRContext; + schema: SchemaWithRequired<'oneOf'>; +}): IRSchemaObject => { + let irSchema = initIrSchema({ schema }); + + let schemaItems: Array = []; + const schemaTypes = getSchemaTypes({ schema }); + + for (const oneOf of schema.oneOf) { + const irOneOfSchema = schemaToIrSchema({ + context, + schema: oneOf, + }); + + // since we know oneOf will be using "or" logical operator, if the parsed + // composition schema also has an "or" operator, we can bring it up + // to avoid unnecessary brackets + if (irOneOfSchema.logicalOperator === 'or' && irOneOfSchema.items) { + schemaItems = schemaItems.concat(irOneOfSchema.items); + } else { + schemaItems.push(irOneOfSchema); + } + } + + if (schemaTypes.includes('null')) { + schemaItems.push({ type: 'null' }); + } + + addItemsToSchema({ + items: schemaItems, + schema: irSchema, + }); + + if (schemaTypes.includes('object')) { + // nest composition to avoid producing a union with object properties + const irObjectSchema = parseOneType({ + context, + schema: { + ...schema, + type: 'object', + }, + }); + + if (irObjectSchema.properties) { + irSchema = { + items: [irSchema, irObjectSchema], + logicalOperator: 'and', + }; + } + } + + if (schema.discriminator) { + // TODO: parser - support discriminator + // TODO: parser - maybe abstract discriminator from oneOf, anyOf, and allOf + } + + return irSchema; +}; + +const parseRef = ({ + schema, +}: { + context: IRContext; + schema: SchemaWithRequired<'$ref'>; +}): IRSchemaObject => { + const irSchema = initIrSchema({ schema }); + + // refs using unicode characters become encoded, didn't investigate why + // but the suspicion is this comes from `@apidevtools/json-schema-ref-parser` + irSchema.$ref = decodeURI(schema.$ref); + + return irSchema; +}; + +const parseOneType = ({ + context, + irSchema, + schema, +}: { + context: IRContext; + irSchema?: IRSchemaObject; + schema: Omit & { + type: SchemaType; + }; +}): IRSchemaObject => { + if (!irSchema) { + irSchema = initIrSchema({ schema }); + + parseSchemaMeta({ + irSchema, + schema, + }); + } + + switch (schema.type) { + case 'array': + return parseArray({ + context, + irSchema, + schema, + }); + case 'boolean': + return parseBoolean({ + context, + irSchema, + schema, + }); + case 'integer': + case 'number': + return parseNumber({ + context, + irSchema, + schema, + }); + case 'null': + return parseNull({ + context, + irSchema, + schema, + }); + case 'object': + return parseObject({ + context, + irSchema, + schema, + }); + case 'string': + return parseString({ + context, + irSchema, + schema, + }); + } +}; + +const parseManyTypes = ({ + context, + irSchema, + schema, +}: { + context: IRContext; + irSchema?: IRSchemaObject; + schema: Omit & { + type: ReadonlyArray; + }; +}): IRSchemaObject => { + if (!irSchema) { + irSchema = initIrSchema({ schema }); + + parseSchemaMeta({ + irSchema, + schema, + }); + } + + const schemaItems: Array = []; + + for (const type of schema.type) { + schemaItems.push( + parseOneType({ + context, + irSchema: {}, + schema: { + ...schema, + type, + }, + }), + ); + } + + addItemsToSchema({ + items: schemaItems, + schema: irSchema, + }); + + return irSchema; +}; + +const parseType = ({ + context, + schema, +}: { + context: IRContext; + schema: SchemaWithRequired<'type'>; +}): IRSchemaObject => { + const irSchema = initIrSchema({ schema }); + + parseSchemaMeta({ + irSchema, + schema, + }); + + const schemaTypes = getSchemaTypes({ schema }); + + if (schemaTypes.length === 1) { + return parseOneType({ + context, + irSchema, + schema: { + ...schema, + type: schemaTypes[0], + }, + }); + } + + return parseManyTypes({ + context, + irSchema, + schema: { + ...schema, + type: schemaTypes, + }, + }); +}; + +const parseUnknown = ({ + schema, +}: { + context: IRContext; + schema: SchemaObject; +}): IRSchemaObject => { + const irSchema = initIrSchema({ schema }); + + irSchema.type = 'unknown'; + + parseSchemaMeta({ + irSchema, + schema, + }); + + return irSchema; +}; + +export const schemaToIrSchema = ({ + context, + schema, +}: { + context: IRContext; + schema: SchemaObject; +}): IRSchemaObject => { + if (schema.$ref) { + return parseRef({ + context, + schema: schema as SchemaWithRequired<'$ref'>, + }); + } + + if (schema.enum) { + return parseEnum({ + context, + schema: schema as SchemaWithRequired<'enum'>, + }); + } + + if (schema.allOf) { + return parseAllOf({ + context, + schema: schema as SchemaWithRequired<'allOf'>, + }); + } + + if (schema.anyOf) { + return parseAnyOf({ + context, + schema: schema as SchemaWithRequired<'anyOf'>, + }); + } + + if (schema.oneOf) { + return parseOneOf({ + context, + schema: schema as SchemaWithRequired<'oneOf'>, + }); + } + + if (schema.type) { + return parseType({ + context, + schema: schema as SchemaWithRequired<'type'>, + }); + } + + return parseUnknown({ + context, + schema, + }); +}; + +export const parseSchema = ({ + context, + name, + schema, +}: { + context: IRContext; + name: string; + schema: SchemaObject; +}) => { + if (!context.ir.components) { + context.ir.components = {}; + } + + if (!context.ir.components.schemas) { + context.ir.components.schemas = {}; + } + + context.ir.components.schemas[name] = schemaToIrSchema({ + context, + schema, + }); +}; diff --git a/packages/openapi-ts/src/openApi/3.1.0/types/json-schema-draft-2020-12.d.ts b/packages/openapi-ts/src/openApi/3.1.0/types/json-schema-draft-2020-12.d.ts new file mode 100644 index 000000000..b98ca31ec --- /dev/null +++ b/packages/openapi-ts/src/openApi/3.1.0/types/json-schema-draft-2020-12.d.ts @@ -0,0 +1,366 @@ +import type { + EnumExtensions, + OpenApiSchemaExtensions, +} from './spec-extensions'; + +// TODO: left out some keywords related to structuring a complex schema and declaring a dialect +export interface JsonSchemaDraft2020_12 + extends ArrayKeywords, + NumberKeywords, + ObjectKeywords, + StringKeywords, + EnumExtensions, + OpenApiSchemaExtensions { + /** + * The `$comment` {@link https://json-schema.org/learn/glossary#keyword keyword} is strictly intended for adding comments to a schema. Its value must always be a string. Unlike the annotations `title`, `description`, and `examples`, JSON schema {@link https://json-schema.org/learn/glossary#implementation implementations} aren't allowed to attach any meaning or behavior to it whatsoever, and may even strip them at any time. Therefore, they are useful for leaving notes to future editors of a JSON schema, but should not be used to communicate to users of the schema. + */ + $comment?: string; + /** + * A schema can reference another schema using the `$ref` keyword. The value of `$ref` is a URI-reference that is resolved against the schema's {@link https://json-schema.org/understanding-json-schema/structuring#base-uri Base URI}. When evaluating a `$ref`, an implementation uses the resolved identifier to retrieve the referenced schema and applies that schema to the {@link https://json-schema.org/learn/glossary#instance instance}. + * + * The `$ref` keyword may be used to create recursive schemas that refer to themselves. + */ + $ref?: string; + /** + * `allOf`: (AND) Must be valid against _all_ of the {@link https://json-schema.org/learn/glossary#subschema subschemas} + * + * To validate against `allOf`, the given data must be valid against all of the given subschemas. + * + * {@link https://json-schema.org/understanding-json-schema/reference/combining#allof allOf} can not be used to "extend" a schema to add more details to it in the sense of object-oriented inheritance. {@link https://json-schema.org/learn/glossary#instance Instances} must independently be valid against "all of" the schemas in the `allOf`. See the section on {@link https://json-schema.org/understanding-json-schema/reference/object#extending Extending Closed Schemas} for more information. + */ + allOf?: ReadonlyArray; + /** + * `anyOf`: (OR) Must be valid against _any_ of the subschemas + * + * To validate against `anyOf`, the given data must be valid against any (one or more) of the given subschemas. + */ + anyOf?: ReadonlyArray; + /** + * The `const` keyword is used to restrict a value to a single value. + */ + const?: unknown; + /** + * The `contentEncoding` keyword specifies the encoding used to store the contents, as specified in {@link https://tools.ietf.org/html/rfc2045 RFC 2054, part 6.1} and {@link https://datatracker.ietf.org/doc/html/rfc4648 RFC 4648}. + * + * The acceptable values are `quoted-printable`, `base16`, `base32`, and `base64`. If not specified, the encoding is the same as the containing JSON document. + * + * Without getting into the low-level details of each of these encodings, there are really only two options useful for modern usage: + * - If the content is encoded in the same encoding as the enclosing JSON document (which for practical purposes, is almost always UTF-8), leave `contentEncoding` unspecified, and include the content in a string as-is. This includes text-based content types, such as `text/html` or `application/xml`. + * - If the content is binary data, set `contentEncoding` to `base64` and encode the contents using {@link https://tools.ietf.org/html/rfc4648 Base64}. This would include many image types, such as `image/png` or audio types, such as `audio/mpeg`. + */ + contentEncoding?: 'base16' | 'base32' | 'base64' | 'quoted-printable'; + /** + * The `contentMediaType` keyword specifies the MIME type of the contents of a string, as described in {@link https://tools.ietf.org/html/rfc2046 RFC 2046}. There is a list of {@link http://www.iana.org/assignments/media-types/media-types.xhtml MIME types officially registered by the IANA}, but the set of types supported will be application and operating system dependent. Mozilla Developer Network also maintains a {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types shorter list of MIME types that are important for the web} + */ + contentMediaType?: string; + /** + * The `default` keyword specifies a default value. This value is not used to fill in missing values during the validation process. Non-validation tools such as documentation generators or form generators may use this value to give hints to users about how to use a value. However, `default` is typically used to express that if a value is missing, then the value is semantically the same as if the value was present with the default value. The value of `default` should validate against the schema in which it resides, but that isn't required. + */ + default?: unknown; + /** + * The `dependentRequired` {@link https://json-schema.org/learn/glossary#keyword keyword} conditionally requires that certain properties must be present if a given property is present in an object. For example, suppose we have a {@link https://json-schema.org/learn/glossary#schema schema} representing a customer. If you have their credit card number, you also want to ensure you have a billing address. If you don't have their credit card number, a billing address would not be required. We represent this dependency of one property on another using the `dependentRequired` keyword. The value of the `dependentRequired` keyword is an object. Each entry in the object maps from the name of a property, _p_, to an array of strings listing properties that are required if _p_ is present. + */ + dependentRequired?: Record>; + /** + * The `dependentSchemas` keyword conditionally applies a {@link https://json-schema.org/learn/glossary#subschema subschema} when a given property is present. This schema is applied in the same way {@link https://json-schema.org/understanding-json-schema/reference/combining#allof allOf} applies schemas. Nothing is merged or extended. Both schemas apply independently. + */ + dependentSchemas?: Record; + /** + * The `deprecated` keyword is a boolean that indicates that the {@link https://json-schema.org/learn/glossary#instance instance} value the keyword applies to should not be used and may be removed in the future. + */ + deprecated?: boolean; + /** + * The `title` and `description` keywords must be strings. A "title" will preferably be short, whereas a "description" will provide a more lengthy explanation about the purpose of the data described by the schema. + */ + description?: string; + /** + * The `if`, `then` and `else` keywords allow the application of a subschema based on the outcome of another schema, much like the `if`/`then`/`else` constructs you've probably seen in traditional programming languages. + * + * If `if` is valid, `then` must also be valid (and `else` is ignored.) If `if` is invalid, `else` must also be valid (and `then` is ignored). + * + * If `then` or `else` is not defined, `if` behaves as if they have a value of `true`. + * + * If `then` and/or `else` appear in a schema without `if`, `then` and `else` are ignored. + */ + else?: JsonSchemaDraft2020_12; + /** + * The `enum` {@link https://json-schema.org/learn/glossary#keyword keyword} is used to restrict a value to a fixed set of values. It must be an array with at least one element, where each element is unique. + * + * You can use `enum` even without a type, to accept values of different types. + */ + enum?: ReadonlyArray; + /** + * The `examples` keyword is a place to provide an array of examples that validate against the schema. This isn't used for validation, but may help with explaining the effect and purpose of the schema to a reader. Each entry should validate against the schema in which it resides, but that isn't strictly required. There is no need to duplicate the `default` value in the `examples` array, since `default` will be treated as another example. + */ + examples?: ReadonlyArray; + /** + * The `format` keyword allows for basic semantic identification of certain kinds of string values that are commonly used. For example, because JSON doesn't have a "DateTime" type, dates need to be encoded as strings. `format` allows the schema author to indicate that the string value should be interpreted as a date. By default, `format` is just an annotation and does not effect validation. + * + * Optionally, validator {@link https://json-schema.org/learn/glossary#implementation implementations} can provide a configuration option to enable `format` to function as an assertion rather than just an annotation. That means that validation will fail if, for example, a value with a `date` format isn't in a form that can be parsed as a date. This can allow values to be constrained beyond what the other tools in JSON Schema, including {@link https://json-schema.org/understanding-json-schema/reference/regular_expressions Regular Expressions} can do. + * + * There is a bias toward networking-related formats in the JSON Schema specification, most likely due to its heritage in web technologies. However, custom formats may also be used, as long as the parties exchanging the JSON documents also exchange information about the custom format types. A JSON Schema validator will ignore any format type that it does not understand. + */ + format?: JsonSchemaFormats; + /** + * The `if`, `then` and `else` keywords allow the application of a subschema based on the outcome of another schema, much like the `if`/`then`/`else` constructs you've probably seen in traditional programming languages. + * + * If `if` is valid, `then` must also be valid (and `else` is ignored.) If `if` is invalid, `else` must also be valid (and `then` is ignored). + * + * If `then` or `else` is not defined, `if` behaves as if they have a value of `true`. + * + * If `then` and/or `else` appear in a schema without `if`, `then` and `else` are ignored. + */ + if?: JsonSchemaDraft2020_12; + /** + * `not`: (NOT) Must _not_ be valid against the given schema + * + * The `not` keyword declares that an instance validates if it doesn't validate against the given subschema. + */ + not?: JsonSchemaDraft2020_12; + /** + * `oneOf`: (XOR) Must be valid against _exactly one_ of the subschemas + * + * To validate against `oneOf`, the given data must be valid against exactly one of the given subschemas. + * + * Careful consideration should be taken when using `oneOf` entries as the nature of it requires verification of _every_ sub-schema which can lead to increased processing times. Prefer `anyOf` where possible. + */ + oneOf?: ReadonlyArray; + /** + * The boolean keywords `readOnly` and `writeOnly` are typically used in an API context. `readOnly` indicates that a value should not be modified. It could be used to indicate that a `PUT` request that changes a value would result in a `400 Bad Request` response. `writeOnly` indicates that a value may be set, but will remain hidden. In could be used to indicate you can set a value with a `PUT` request, but it would not be included when retrieving that record with a `GET` request. + */ + readOnly?: boolean; + /** + * The `if`, `then` and `else` keywords allow the application of a subschema based on the outcome of another schema, much like the `if`/`then`/`else` constructs you've probably seen in traditional programming languages. + * + * If `if` is valid, `then` must also be valid (and `else` is ignored.) If `if` is invalid, `else` must also be valid (and `then` is ignored). + * + * If `then` or `else` is not defined, `if` behaves as if they have a value of `true`. + * + * If `then` and/or `else` appear in a schema without `if`, `then` and `else` are ignored. + */ + then?: JsonSchemaDraft2020_12; + /** + * The `title` and `description` keywords must be strings. A "title" will preferably be short, whereas a "description" will provide a more lengthy explanation about the purpose of the data described by the schema. + */ + title?: string; + /** + * If it is an array, it must be an array of strings, where each string is the name of one of the basic types, and each element is unique. In this case, the JSON snippet is valid if it matches any of the given types. + */ + type?: JsonSchemaTypes | ReadonlyArray; + /** + * The boolean keywords `readOnly` and `writeOnly` are typically used in an API context. `readOnly` indicates that a value should not be modified. It could be used to indicate that a `PUT` request that changes a value would result in a `400 Bad Request` response. `writeOnly` indicates that a value may be set, but will remain hidden. In could be used to indicate you can set a value with a `PUT` request, but it would not be included when retrieving that record with a `GET` request. + */ + writeOnly?: boolean; +} + +interface ArrayKeywords { + /** + * While the `items` schema must be valid for every item in the array, the `contains` schema only needs to validate against one or more items in the array. + */ + contains?: JsonSchemaDraft2020_12; + /** + * List validation is useful for arrays of arbitrary length where each item matches the same schema. For this kind of array, set the `items` {@link https://json-schema.org/learn/glossary#keyword keyword} to a single schema that will be used to validate all of the items in the array. + * + * The `items` keyword can be used to control whether it's valid to have additional items in a tuple beyond what is defined in `prefixItems`. The value of the `items` keyword is a schema that all additional items must pass in order for the keyword to validate. + * + * Note that `items` doesn't "see inside" any {@link https://json-schema.org/learn/glossary#instance instances} of `allOf`, `anyOf`, or `oneOf` in the same {@link https://json-schema.org/learn/glossary#subschema subschema}. + */ + items?: JsonSchemaDraft2020_12 | false; + /** + * `minContains` and `maxContains` can be used with `contains` to further specify how many times a schema matches a `contains` constraint. These keywords can be any non-negative number including zero. + */ + maxContains?: number; + /** + * The length of the array can be specified using the `minItems` and `maxItems` keywords. The value of each keyword must be a non-negative number. These keywords work whether doing {@link https://json-schema.org/understanding-json-schema/reference/array#items list validation} or {@link https://json-schema.org/understanding-json-schema/reference/array#tupleValidation tuple-validation}. + */ + maxItems?: number; + /** + * `minContains` and `maxContains` can be used with `contains` to further specify how many times a schema matches a `contains` constraint. These keywords can be any non-negative number including zero. + */ + minContains?: number; + /** + * The length of the array can be specified using the `minItems` and `maxItems` keywords. The value of each keyword must be a non-negative number. These keywords work whether doing {@link https://json-schema.org/understanding-json-schema/reference/array#items list validation} or {@link https://json-schema.org/understanding-json-schema/reference/array#tupleValidation tuple-validation}. + */ + minItems?: number; + /** + * `prefixItems` is an array, where each item is a schema that corresponds to each index of the document's array. That is, an array where the first element validates the first element of the input array, the second element validates the second element of the input array, etc. + */ + prefixItems?: ReadonlyArray; + /** + * The `unevaluatedItems` keyword is useful mainly when you want to add or disallow extra items to an array. + * + * `unevaluatedItems` applies to any values not evaluated by an `items`, `prefixItems`, or `contains` keyword. Just as `unevaluatedProperties` affects only properties in an object, `unevaluatedItems` affects only items in an array. + * + * Watch out! The word "unevaluated" _does not mean_ "not evaluated by `items`, `prefixItems`, or `contains`." "Unevaluated" means "not successfully evaluated", or "does not evaluate to true". + * + * Like with `items`, if you set `unevaluatedItems` to false, you can disallow extra items in the array. + */ + unevaluatedItems?: JsonSchemaDraft2020_12 | false; + /** + * A schema can ensure that each of the items in an array is unique. Simply set the `uniqueItems` keyword to `true`. + */ + uniqueItems?: boolean; +} + +interface NumberKeywords { + /** + * Ranges of numbers are specified using a combination of the `minimum` and `maximum` keywords, (or `exclusiveMinimum` and `exclusiveMaximum` for expressing exclusive range). + * + * If _x_ is the value being validated, the following must hold true: + * + * ``` + * x ≥ minimum + * x > exclusiveMinimum + * x ≤ maximum + * x < exclusiveMaximum + * ``` + * + * While you can specify both of `minimum` and `exclusiveMinimum` or both of `maximum` and `exclusiveMaximum`, it doesn't really make sense to do so. + */ + exclusiveMaximum?: number; + /** + * Ranges of numbers are specified using a combination of the `minimum` and `maximum` keywords, (or `exclusiveMinimum` and `exclusiveMaximum` for expressing exclusive range). + * + * If _x_ is the value being validated, the following must hold true: + * + * ``` + * x ≥ minimum + * x > exclusiveMinimum + * x ≤ maximum + * x < exclusiveMaximum + * ``` + * + * While you can specify both of `minimum` and `exclusiveMinimum` or both of `maximum` and `exclusiveMaximum`, it doesn't really make sense to do so. + */ + exclusiveMinimum?: number; + /** + * Ranges of numbers are specified using a combination of the `minimum` and `maximum` keywords, (or `exclusiveMinimum` and `exclusiveMaximum` for expressing exclusive range). + * + * If _x_ is the value being validated, the following must hold true: + * + * ``` + * x ≥ minimum + * x > exclusiveMinimum + * x ≤ maximum + * x < exclusiveMaximum + * ``` + * + * While you can specify both of `minimum` and `exclusiveMinimum` or both of `maximum` and `exclusiveMaximum`, it doesn't really make sense to do so. + */ + maximum?: number; + /** + * Ranges of numbers are specified using a combination of the `minimum` and `maximum` keywords, (or `exclusiveMinimum` and `exclusiveMaximum` for expressing exclusive range). + * + * If _x_ is the value being validated, the following must hold true: + * + * ``` + * x ≥ minimum + * x > exclusiveMinimum + * x ≤ maximum + * x < exclusiveMaximum + * ``` + * + * While you can specify both of `minimum` and `exclusiveMinimum` or both of `maximum` and `exclusiveMaximum`, it doesn't really make sense to do so. + */ + minimum?: number; + /** + * Numbers can be restricted to a multiple of a given number, using the `multipleOf` keyword. It may be set to any positive number. The multiple can be a floating point number. + */ + multipleOf?: number; +} + +interface ObjectKeywords { + /** + * The `additionalProperties` keyword is used to control the handling of extra stuff, that is, properties whose names are not listed in the `properties` keyword or match any of the regular expressions in the `patternProperties` keyword. By default any additional properties are allowed. + * + * The value of the `additionalProperties` keyword is a schema that will be used to validate any properties in the {@link https://json-schema.org/learn/glossary#instance instance} that are not matched by `properties` or `patternProperties`. Setting the `additionalProperties` schema to `false` means no additional properties will be allowed. + * + * It's important to note that `additionalProperties` only recognizes properties declared in the same {@link https://json-schema.org/learn/glossary#subschema subschema} as itself. So, `additionalProperties` can restrict you from "extending" a schema using {@link https://json-schema.org/understanding-json-schema/reference/combining combining} keywords such as {@link https://json-schema.org/understanding-json-schema/reference/combining#allof allOf}. + */ + additionalProperties?: JsonSchemaDraft2020_12 | false; + /** + * The number of properties on an object can be restricted using the `minProperties` and `maxProperties` keywords. Each of these must be a non-negative integer. + */ + maxProperties?: number; + /** + * The number of properties on an object can be restricted using the `minProperties` and `maxProperties` keywords. Each of these must be a non-negative integer. + */ + minProperties?: number; + /** + * Sometimes you want to say that, given a particular kind of property name, the value should match a particular schema. That's where `patternProperties` comes in: it maps regular expressions to schemas. If a property name matches the given regular expression, the property value must validate against the corresponding schema. + */ + patternProperties?: Record; + /** + * The properties (key-value pairs) on an object are defined using the `properties` {@link https://json-schema.org/learn/glossary#keyword keyword}. The value of `properties` is an object, where each key is the name of a property and each value is a {@link https://json-schema.org/learn/glossary#schema schema} used to validate that property. Any property that doesn't match any of the property names in the `properties` keyword is ignored by this keyword. + */ + properties?: Record; + /** + * The names of properties can be validated against a schema, irrespective of their values. This can be useful if you don't want to enforce specific properties, but you want to make sure that the names of those properties follow a specific convention. You might, for example, want to enforce that all names are valid ASCII tokens so they can be used as attributes in a particular programming language. + * + * Since object keys must always be strings anyway, it is implied that the schema given to `propertyNames` is always at least: + * + * ```json + * { "type": "string" } + * ``` + */ + propertyNames?: JsonSchemaDraft2020_12; + /** + * By default, the properties defined by the `properties` keyword are not required. However, one can provide a list of required properties using the `required` keyword. + * + * The `required` keyword takes an array of zero or more strings. Each of these strings must be unique. + */ + required?: ReadonlyArray; + /** + * The `unevaluatedProperties` keyword is similar to `additionalProperties` except that it can recognize properties declared in subschemas. So, the example from the previous section can be rewritten without the need to redeclare properties. + * + * `unevaluatedProperties` works by collecting any properties that are successfully validated when processing the schemas and using those as the allowed list of properties. This allows you to do more complex things like conditionally adding properties. + */ + unevaluatedProperties?: JsonSchemaDraft2020_12 | false; +} + +interface StringKeywords { + /** + * The length of a string can be constrained using the `minLength` and `maxLength` {@link https://json-schema.org/learn/glossary#keyword keywords}. For both keywords, the value must be a non-negative number. + */ + maxLength?: number; + /** + * The length of a string can be constrained using the `minLength` and `maxLength` {@link https://json-schema.org/learn/glossary#keyword keywords}. For both keywords, the value must be a non-negative number. + */ + minLength?: number; + /** + * The `pattern` keyword is used to restrict a string to a particular regular expression. The regular expression syntax is the one defined in JavaScript ({@link https://www.ecma-international.org/publications-and-standards/standards/ecma-262/ ECMA 262} specifically) with Unicode support. See {@link https://json-schema.org/understanding-json-schema/reference/regular_expressions Regular Expressions} for more information. + */ + pattern?: string; +} + +type JsonSchemaFormats = + | 'date' + | 'date-time' + | 'duration' + | 'email' + | 'hostname' + | 'idn-email' + | 'idn-hostname' + | 'ipv4' + | 'ipv6' + | 'iri' + | 'iri-reference' + | 'json-pointer' + | 'regex' + | 'relative-json-pointer' + | 'time' + | 'uri' + | 'uri-reference' + | 'uri-template' + | 'uuid' + // eslint-disable-next-line @typescript-eslint/ban-types + | (string & {}); + +type JsonSchemaTypes = + | 'array' + | 'boolean' + | 'integer' + | 'null' + | 'number' + | 'object' + | 'string'; diff --git a/packages/openapi-ts/src/openApi/3.1.0/types/spec-extensions.d.ts b/packages/openapi-ts/src/openApi/3.1.0/types/spec-extensions.d.ts new file mode 100644 index 000000000..2b00de6b9 --- /dev/null +++ b/packages/openapi-ts/src/openApi/3.1.0/types/spec-extensions.d.ts @@ -0,0 +1,41 @@ +import type { + DiscriminatorObject, + ExternalDocumentationObject, + XMLObject, +} from './spec'; + +export interface EnumExtensions { + /** + * `x-enum-descriptions` are {@link https://stackoverflow.com/a/66471626 supported} by OpenAPI Generator. + */ + 'x-enum-descriptions'?: ReadonlyArray; + /** + * `x-enum-varnames` are {@link https://stackoverflow.com/a/66471626 supported} by OpenAPI Generator. + */ + 'x-enum-varnames'?: ReadonlyArray; + /** + * {@link https://github.com/RicoSuter/NSwag NSwag} generates `x-enumNames` field containing custom enum names. + */ + 'x-enumNames'?: ReadonlyArray; +} + +export interface OpenApiSchemaExtensions { + /** + * Adds support for polymorphism. The discriminator is an object name that is used to differentiate between other schemas which may satisfy the payload description. See {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#composition-and-inheritance-polymorphism Composition and Inheritance} for more details. + */ + discriminator?: DiscriminatorObject; + /** + * A free-form property to include an example of an instance for this schema. To represent examples that cannot be naturally represented in JSON or YAML, a string value can be used to contain the example with escaping where necessary. + * + * **Deprecated**: The `example` property has been deprecated in favor of the JSON Schema `examples` keyword. Use of `example` is discouraged, and later versions of this specification may remove it. + */ + example?: unknown; + /** + * Additional external documentation for this schema. + */ + externalDocs?: ExternalDocumentationObject; + /** + * This MAY be used only on properties schemas. It has no effect on root schemas. Adds additional metadata to describe the XML representation of this property. + */ + xml?: XMLObject; +} diff --git a/packages/openapi-ts/src/openApi/3.1/types/spec.ts b/packages/openapi-ts/src/openApi/3.1.0/types/spec.d.ts similarity index 98% rename from packages/openapi-ts/src/openApi/3.1/types/spec.ts rename to packages/openapi-ts/src/openApi/3.1.0/types/spec.d.ts index 322224bb8..4d49f9c84 100644 --- a/packages/openapi-ts/src/openApi/3.1/types/spec.ts +++ b/packages/openapi-ts/src/openApi/3.1.0/types/spec.d.ts @@ -1,9 +1,11 @@ +import type { JsonSchemaDraft2020_12 } from './json-schema-draft-2020-12'; + /** * This is the root object of the {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#openapi-document OpenAPI document}. * * This object MAY be extended with {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specification-extensions Specification Extensions}. */ -export interface OpenApiV3_1 { +export interface OpenApiV3_1_0 { /** * An element to hold various schemas for the document. */ @@ -1651,26 +1653,7 @@ export interface ResponsesObject { * * This object MAY be extended with {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specification-extensions Specification Extensions}, though as noted, additional properties MAY omit the `x-` prefix within this object. */ -export interface SchemaObject { - /** - * Adds support for polymorphism. The discriminator is an object name that is used to differentiate between other schemas which may satisfy the payload description. See {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#composition-and-inheritance-polymorphism Composition and Inheritance} for more details. - */ - discriminator?: DiscriminatorObject; - /** - * A free-form property to include an example of an instance for this schema. To represent examples that cannot be naturally represented in JSON or YAML, a string value can be used to contain the example with escaping where necessary. - * - * **Deprecated**: The `example` property has been deprecated in favor of the JSON Schema `examples` keyword. Use of `example` is discouraged, and later versions of this specification may remove it. - */ - example?: unknown; - /** - * Additional external documentation for this schema. - */ - externalDocs?: ExternalDocumentationObject; - /** - * This MAY be used only on properties schemas. It has no effect on root schemas. Adds additional metadata to describe the XML representation of this property. - */ - xml?: XMLObject; -} +export interface SchemaObject extends JsonSchemaDraft2020_12 {} /** * Lists the required security schemes to execute this operation. The name used for each property MUST correspond to a security scheme declared in the {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#componentsSecuritySchemes Security Schemes} under the {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#components-object Components Object}. diff --git a/packages/openapi-ts/src/openApi/3.1/index.ts b/packages/openapi-ts/src/openApi/3.1/index.ts deleted file mode 100644 index 89a9e7a9a..000000000 --- a/packages/openapi-ts/src/openApi/3.1/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { parseV3_1 } from './parser'; -export type { OpenApiV3_1 } from './types/spec'; diff --git a/packages/openapi-ts/src/openApi/3.1/parser/index.ts b/packages/openapi-ts/src/openApi/3.1/parser/index.ts deleted file mode 100644 index 71a34194b..000000000 --- a/packages/openapi-ts/src/openApi/3.1/parser/index.ts +++ /dev/null @@ -1,82 +0,0 @@ -import type { OpenApiV3_1, PathsObject } from '../types/spec'; -import { parseOperation } from './operation'; - -export const parseV3_1 = (spec: OpenApiV3_1) => { - const operationIds = new Map(); - - for (const path in spec.paths) { - const pathItem = spec.paths[path as keyof PathsObject]; - - if (pathItem.delete) { - parseOperation({ - method: 'DELETE', - operation: pathItem.delete, - operationIds, - path, - }); - } - - if (pathItem.get) { - parseOperation({ - method: 'GET', - operation: pathItem.get, - operationIds, - path, - }); - } - - if (pathItem.head) { - parseOperation({ - method: 'HEAD', - operation: pathItem.head, - operationIds, - path, - }); - } - - if (pathItem.options) { - parseOperation({ - method: 'OPTIONS', - operation: pathItem.options, - operationIds, - path, - }); - } - - if (pathItem.patch) { - parseOperation({ - method: 'PATCH', - operation: pathItem.patch, - operationIds, - path, - }); - } - - if (pathItem.post) { - parseOperation({ - method: 'POST', - operation: pathItem.post, - operationIds, - path, - }); - } - - if (pathItem.put) { - parseOperation({ - method: 'PUT', - operation: pathItem.put, - operationIds, - path, - }); - } - - if (pathItem.trace) { - parseOperation({ - method: 'TRACE', - operation: pathItem.trace, - operationIds, - path, - }); - } - } -}; diff --git a/packages/openapi-ts/src/openApi/3.1/parser/operation.ts b/packages/openapi-ts/src/openApi/3.1/parser/operation.ts deleted file mode 100644 index cc7e86538..000000000 --- a/packages/openapi-ts/src/openApi/3.1/parser/operation.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { getConfig } from '../../../utils/config'; -import type { OperationObject } from '../types/spec'; - -export const parseOperation = ({ - method, - operation, - operationIds, - path, -}: { - method: string; - operation: OperationObject; - operationIds: Map; - path: string; -}) => { - const operationKey = `${method} ${path}`; - - const config = getConfig(); - - // TODO: filter function, move services to plugin, cleaner syntax - const regexp = config.services.filter - ? new RegExp(config.services.filter) - : undefined; - if (regexp && !regexp.test(operationKey)) { - return; - } - - // TODO: support throw on duplicate - if (operation.operationId) { - if (operationIds.has(operation.operationId)) { - console.warn( - `❗️ Duplicate operationId: ${operation.operationId} in ${operationKey}. Please ensure your operation IDs are unique. This behavior is not supported and will likely lead to unexpected results.`, - ); - } else { - operationIds.set(operation.operationId, operationKey); - } - } - - console.log(operation); -}; diff --git a/packages/openapi-ts/src/openApi/__tests__/index.spec.ts b/packages/openapi-ts/src/openApi/__tests__/index.spec.ts index 30e0ca4e7..7faee4c5f 100644 --- a/packages/openapi-ts/src/openApi/__tests__/index.spec.ts +++ b/packages/openapi-ts/src/openApi/__tests__/index.spec.ts @@ -1,11 +1,15 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; import { type OpenApi, parse } from '..'; -import type { Config } from '../common/interfaces/config'; +import type { ParserConfig } from '../config'; import * as parseV2 from '../v2'; import * as parseV3 from '../v3'; -const config: Config = { +const parserConfig: ParserConfig = { + filterFn: { + operation: () => true, + operationParameter: () => true, + }, nameFn: { operation: () => 'operation', operationParameter: () => 'operationParameter', @@ -28,7 +32,7 @@ describe('parse', () => { paths: {}, swagger: '2', }; - parse({ config, openApi: spec }); + parse({ openApi: spec, parserConfig }); expect(spy).toHaveBeenCalledWith(spec); const spec2: OpenApi = { @@ -39,7 +43,7 @@ describe('parse', () => { paths: {}, swagger: '2.0', }; - parse({ config, openApi: spec2 }); + parse({ openApi: spec2, parserConfig }); expect(spy).toHaveBeenCalledWith(spec2); }); @@ -54,7 +58,7 @@ describe('parse', () => { openapi: '3', paths: {}, }; - parse({ config, openApi: spec }); + parse({ openApi: spec, parserConfig }); expect(spy).toHaveBeenCalledWith(spec); const spec2: OpenApi = { @@ -65,7 +69,7 @@ describe('parse', () => { openapi: '3.0', paths: {}, }; - parse({ config, openApi: spec2 }); + parse({ openApi: spec2, parserConfig }); expect(spy).toHaveBeenCalledWith(spec2); const spec3: OpenApi = { @@ -76,13 +80,13 @@ describe('parse', () => { openapi: '3.1.0', paths: {}, }; - parse({ config, openApi: spec3 }); + parse({ openApi: spec3, parserConfig }); expect(spy).toHaveBeenCalledWith(spec3); }); it('throws on unknown version', () => { // @ts-expect-error - expect(() => parse({ config, openApi: { foo: 'bar' } })).toThrow( + expect(() => parse({ openApi: { foo: 'bar' }, parserConfig })).toThrow( `Unsupported OpenAPI specification: ${JSON.stringify({ foo: 'bar' }, null, 2)}`, ); }); diff --git a/packages/openapi-ts/src/openApi/common/interfaces/config.ts b/packages/openapi-ts/src/openApi/common/interfaces/config.ts deleted file mode 100644 index 03f1fb771..000000000 --- a/packages/openapi-ts/src/openApi/common/interfaces/config.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { Operation, OperationParameter } from './client'; - -export interface Config { - debug?: boolean; - filterFn?: { - operation?: (operationKey: string) => boolean; - operationParameter?: (parameter: OperationParameter) => boolean; - }; - nameFn: { - operation: (operation: Omit) => string; - operationParameter: (parameter: Omit) => string; - }; -} diff --git a/packages/openapi-ts/src/openApi/common/parser/operation.ts b/packages/openapi-ts/src/openApi/common/parser/operation.ts index f6cf6f2ea..37d910ca8 100644 --- a/packages/openapi-ts/src/openApi/common/parser/operation.ts +++ b/packages/openapi-ts/src/openApi/common/parser/operation.ts @@ -7,7 +7,7 @@ export const getOperationKey = (operation: { method: string; path: string; }) => { - const operationKey = `${operation.method} ${operation.path}`; + const operationKey = `${operation.method.toUpperCase()} ${operation.path}`; return operationKey; }; diff --git a/packages/openapi-ts/src/openApi/common/parser/sanitize.ts b/packages/openapi-ts/src/openApi/common/parser/sanitize.ts index 05271bbff..49f7d5154 100644 --- a/packages/openapi-ts/src/openApi/common/parser/sanitize.ts +++ b/packages/openapi-ts/src/openApi/common/parser/sanitize.ts @@ -1,29 +1,12 @@ import { illegalStartCharactersRegExp } from '../../../utils/regexp'; -/** - * Sanitizes names of types, so they are valid TypeScript identifiers of a certain form. - * - * 1: Remove any leading characters that are illegal as starting character of a TypeScript identifier. - * 2: Replace illegal characters in remaining part of type name with underscore (_). - * - * Step 1 should perhaps instead also replace illegal characters with underscore, or prefix with it, like sanitizeEnumName - * does. The way this is now one could perhaps end up removing all characters, if all are illegal start characters. It - * would be sort of a breaking change to do so, though, previously generated code might change then. - * - * JavaScript identifier regexp pattern retrieved from https://developer.mozilla.org/docs/Web/JavaScript/Reference/Lexical_grammar#identifiers - */ -const replaceInvalidTypeScriptJavaScriptIdentifier = (name: string) => - name - .replace(illegalStartCharactersRegExp, '') - .replace(/[^$\u200c\u200d\p{ID_Continue}]/gu, '_'); - export const ensureValidTypeScriptJavaScriptIdentifier = (name: string) => { illegalStartCharactersRegExp.lastIndex = 0; - const startsWithIllegalCharacter = illegalStartCharactersRegExp.test(name); - // avoid removing all characters in case they're all illegal - const input = startsWithIllegalCharacter ? `_${name}` : name; - const cleaned = replaceInvalidTypeScriptJavaScriptIdentifier(input); - return cleaned; + const replaced = name.replace(/[^$\u200c\u200d\p{ID_Continue}]/gu, '_'); + const startsWithIllegalCharacter = + illegalStartCharactersRegExp.test(replaced); + const valid = startsWithIllegalCharacter ? `_${replaced}` : replaced; + return valid; }; /** diff --git a/packages/openapi-ts/src/openApi/config.ts b/packages/openapi-ts/src/openApi/config.ts index b557a1a53..584db8781 100644 --- a/packages/openapi-ts/src/openApi/config.ts +++ b/packages/openapi-ts/src/openApi/config.ts @@ -1,10 +1,103 @@ -import type { Config } from './common/interfaces/config'; +import type { Config } from '../types/config'; +import { camelCase } from '../utils/camelCase'; +import { getConfig, isLegacyClient } from '../utils/config'; +import { transformTypeKeyName } from '../utils/type'; +import type { OperationParameter } from './common/interfaces/client'; +import { sanitizeNamespaceIdentifier } from './common/parser/sanitize'; -let _config: Config; +export interface ParserConfig { + debug?: boolean; + filterFn: { + operation: typeof operationFilterFn; + operationParameter: typeof operationParameterFilterFn; + }; + nameFn: { + operation: typeof operationNameFn; + operationParameter: typeof operationParameterNameFn; + }; +} -export const getConfig = () => _config; +let _config: ParserConfig; -export const setConfig = (config: Config) => { +export const getParserConfig = () => _config; + +export const setParserConfig = (config: ParserConfig) => { _config = config; - return getConfig(); + return getParserConfig(); +}; + +export const operationFilterFn = ({ + config, + operationKey, +}: { + config: Config; + operationKey: string; +}): boolean => { + const regexp = config.services.filter + ? new RegExp(config.services.filter) + : undefined; + return !regexp || regexp.test(operationKey); +}; + +export const operationParameterFilterFn = ( + parameter: OperationParameter, +): boolean => { + const config = getConfig(); + + // legacy clients ignore the "api-version" param since we do not want to + // add it as the first/default parameter for each of the service calls + return !isLegacyClient(config) || parameter.prop !== 'api-version'; +}; + +/** + * Convert the input value to a correct operation (method) class name. + * This will use the operation ID - if available - and otherwise fallback + * on a generated name from the URL + */ +export const operationNameFn = ({ + config, + method, + operationId, + path, +}: { + config: Config; + method: string; + operationId: string | undefined; + path: string; +}): string => { + if (config.services.operationId && operationId) { + return camelCase({ + input: sanitizeNamespaceIdentifier(operationId), + }); + } + + let urlWithoutPlaceholders = path; + + // legacy clients ignore the "api-version" param since we do not want to + // add it as the first/default parameter for each of the service calls + if (isLegacyClient(config)) { + urlWithoutPlaceholders = urlWithoutPlaceholders.replace( + /[^/]*?{api-version}.*?\//g, + '', + ); + } + + urlWithoutPlaceholders = urlWithoutPlaceholders + .replace(/{(.*?)}/g, 'by-$1') + // replace slashes with hyphens for camelcase method at the end + .replace(/[/:]/g, '-'); + + return camelCase({ + input: `${method}-${urlWithoutPlaceholders}`, + }); +}; + +export const operationParameterNameFn = ( + parameter: Omit, +): string => { + const config = getConfig(); + + return !isLegacyClient(config) + ? parameter.prop + : transformTypeKeyName(parameter.prop); }; diff --git a/packages/openapi-ts/src/openApi/index.ts b/packages/openapi-ts/src/openApi/index.ts index d97cee768..8796a5a06 100644 --- a/packages/openapi-ts/src/openApi/index.ts +++ b/packages/openapi-ts/src/openApi/index.ts @@ -1,9 +1,11 @@ +import { IRContext } from '../ir/context'; +import type { Config } from '../types/config'; import { type OpenApiV3_0_3, parseV3_0_3 } from './3.0.3'; -import { type OpenApiV3_1, parseV3_1 } from './3.1'; +import { type OpenApiV3_1_0, parseV3_1_0 } from './3.1.0'; import type { Client } from './common/interfaces/client'; -import type { Config } from './common/interfaces/config'; import type { OpenApi } from './common/interfaces/OpenApi'; -import { setConfig } from './config'; +import type { ParserConfig } from './config'; +import { setParserConfig } from './config'; import { parse as parseV2 } from './v2'; import { parse as parseV3 } from './v3'; @@ -17,7 +19,6 @@ export type { OperationParameter, OperationResponse, } from './common/interfaces/client'; -export type { Config } from './common/interfaces/config'; export type { OpenApi } from './common/interfaces/OpenApi'; export { isOperationParameterRequired } from './common/parser/operation'; export { @@ -36,12 +37,12 @@ export type { OpenApiSchema as OpenApiV3Schema } from './v3/interfaces/OpenApiSc */ export function parse({ openApi, - config, + parserConfig, }: { - config: Config; openApi: OpenApi; + parserConfig: ParserConfig; }): Client { - setConfig(config); + setParserConfig(parserConfig); if ('openapi' in openApi) { return parseV3(openApi); @@ -56,15 +57,36 @@ export function parse({ ); } -export const parseExperimental = ({ spec }: { spec: unknown }) => { - const s = spec as OpenApiV3_0_3 | OpenApiV3_1; +// TODO: parser - add JSDoc comment +export const parseExperimental = ({ + config, + parserConfig, + spec, +}: { + config: Config; + parserConfig: ParserConfig; + spec: unknown; +}) => { + const context = new IRContext({ + config, + parserConfig, + spec: spec as OpenApiV3_0_3 | OpenApiV3_1_0, + }); - switch (s.openapi) { + switch (context.spec.openapi) { case '3.0.3': - return parseV3_0_3(s); + parseV3_0_3(context as IRContext); + break; case '3.1.0': - return parseV3_1(s); + parseV3_1_0(context as IRContext); + break; default: - throw new Error('Unsupported OpenAPI specification'); + // TODO: parser - uncomment after removing legacy parser. + // For now, we fall back to legacy parser if spec version + // is not supported + break; + // throw new Error('Unsupported OpenAPI specification'); } + + return context; }; diff --git a/packages/openapi-ts/src/openApi/v2/parser/getOperationParameter.ts b/packages/openapi-ts/src/openApi/v2/parser/getOperationParameter.ts index 9c1aa9cf6..f90bbfee7 100644 --- a/packages/openapi-ts/src/openApi/v2/parser/getOperationParameter.ts +++ b/packages/openapi-ts/src/openApi/v2/parser/getOperationParameter.ts @@ -5,7 +5,7 @@ import { getEnums } from '../../common/parser/getEnums'; import { getPattern } from '../../common/parser/getPattern'; import { getRef } from '../../common/parser/getRef'; import { getType } from '../../common/parser/type'; -import { getConfig } from '../../config'; +import { getParserConfig } from '../../config'; import type { OpenApi } from '../interfaces/OpenApi'; import type { OpenApiParameter } from '../interfaces/OpenApiParameter'; import type { OpenApiSchema } from '../interfaces/OpenApiSchema'; @@ -20,7 +20,7 @@ export const getOperationParameter = ({ parameter: OpenApiParameter; types: Client['types']; }): OperationParameter => { - const config = getConfig(); + const config = getParserConfig(); const operationParameterWithoutName: Omit = { $refs: [], diff --git a/packages/openapi-ts/src/openApi/v2/parser/getOperationParameters.ts b/packages/openapi-ts/src/openApi/v2/parser/getOperationParameters.ts index 429843a36..5860877b8 100644 --- a/packages/openapi-ts/src/openApi/v2/parser/getOperationParameters.ts +++ b/packages/openapi-ts/src/openApi/v2/parser/getOperationParameters.ts @@ -1,7 +1,7 @@ import type { Client } from '../../../types/client'; import type { OperationParameters } from '../../common/interfaces/client'; import { getRef } from '../../common/parser/getRef'; -import { getConfig } from '../../config'; +import { getParserConfig } from '../../config'; import type { OpenApi } from '../interfaces/OpenApi'; import type { OpenApiParameter } from '../interfaces/OpenApiParameter'; import { getOperationParameter } from './getOperationParameter'; @@ -17,7 +17,7 @@ export const getOperationParameters = ({ parameters: OpenApiParameter[]; types: Client['types']; }): OperationParameters => { - const config = getConfig(); + const config = getParserConfig(); const operationParameters: OperationParameters = { $refs: [], @@ -42,9 +42,7 @@ export const getOperationParameters = ({ types, }); - const skip = - config.filterFn?.operationParameter && - !config.filterFn?.operationParameter(parameter); + const skip = !config.filterFn.operationParameter(parameter); if (!allowedIn.includes(parameterDef.in) || skip) { return; } diff --git a/packages/openapi-ts/src/openApi/v2/parser/getOperations.ts b/packages/openapi-ts/src/openApi/v2/parser/getOperations.ts index 696eae6ff..5bbf3f2ea 100644 --- a/packages/openapi-ts/src/openApi/v2/parser/getOperations.ts +++ b/packages/openapi-ts/src/openApi/v2/parser/getOperations.ts @@ -1,7 +1,8 @@ +import { getConfig } from '../../../utils/config'; import type { Client, Operation } from '../../common/interfaces/client'; import { getOperationKey } from '../../common/parser/operation'; import { allowedServiceMethods } from '../../common/parser/service'; -import { getConfig } from '../../config'; +import { getParserConfig } from '../../config'; import type { OpenApi } from '../interfaces/OpenApi'; import { getOperationParameters } from './getOperationParameters'; import { getOperation } from './operation'; @@ -13,7 +14,7 @@ export const getOperations = ({ openApi: OpenApi; types: Client['types']; }): Operation[] => { - const config = getConfig(); + const config = getParserConfig(); const operationIds = new Map(); const operations: Operation[] = []; @@ -26,11 +27,11 @@ export const getOperations = ({ types, }); - for (const key in pathItem) { - const method = key as Lowercase; + for (const name in pathItem) { + const method = name as Lowercase; const operationKey = getOperationKey({ - method: method.toUpperCase(), + method, path, }); @@ -48,8 +49,10 @@ export const getOperations = ({ } if ( - !config.filterFn?.operation || - config.filterFn?.operation(operationKey) + config.filterFn.operation({ + config: getConfig(), + operationKey, + }) ) { const operation = getOperation({ method, diff --git a/packages/openapi-ts/src/openApi/v2/parser/operation.ts b/packages/openapi-ts/src/openApi/v2/parser/operation.ts index 9288d6df2..f175dadee 100644 --- a/packages/openapi-ts/src/openApi/v2/parser/operation.ts +++ b/packages/openapi-ts/src/openApi/v2/parser/operation.ts @@ -1,11 +1,12 @@ import type { Client } from '../../../types/client'; +import { getConfig } from '../../../utils/config'; import type { Operation, OperationParameters, } from '../../common/interfaces/client'; import { getOperationResponseHeader } from '../../common/parser/operation'; import { toSortedByRequired } from '../../common/parser/sort'; -import { getConfig } from '../../config'; +import { getParserConfig } from '../../config'; import type { OpenApi } from '../interfaces/OpenApi'; import type { OpenApiOperation } from '../interfaces/OpenApiOperation'; import { getOperationParameters } from './getOperationParameters'; @@ -26,7 +27,7 @@ export const getOperation = ({ types: Client['types']; url: string; }): Operation => { - const config = getConfig(); + const config = getParserConfig(); const operationWithoutName: Omit = { $refs: [], @@ -50,7 +51,12 @@ export const getOperation = ({ }; const operation = { ...operationWithoutName, - name: config.nameFn.operation(operationWithoutName), + name: config.nameFn.operation({ + config: getConfig(), + method: operationWithoutName.method, + operationId: op.operationId, + path: operationWithoutName.path, + }), }; if (op.parameters) { diff --git a/packages/openapi-ts/src/openApi/v3/parser/discriminator.ts b/packages/openapi-ts/src/openApi/v3/parser/discriminator.ts index 6e1f81180..7eebb899e 100644 --- a/packages/openapi-ts/src/openApi/v3/parser/discriminator.ts +++ b/packages/openapi-ts/src/openApi/v3/parser/discriminator.ts @@ -6,8 +6,8 @@ import type { OpenApiDiscriminator } from '../interfaces/OpenApiDiscriminator'; const inverseDictionary = (map: Dictionary): Dictionary => { const m2: Dictionary = {}; - for (const key in map) { - m2[map[key]] = key; + for (const name in map) { + m2[map[name]] = name; } return m2; }; diff --git a/packages/openapi-ts/src/openApi/v3/parser/getModels.ts b/packages/openapi-ts/src/openApi/v3/parser/getModels.ts index 745ce788a..c96a47637 100644 --- a/packages/openapi-ts/src/openApi/v3/parser/getModels.ts +++ b/packages/openapi-ts/src/openApi/v3/parser/getModels.ts @@ -1,6 +1,6 @@ import type { Client } from '../../../types/client'; import { getParametersMeta, getSchemasMeta } from '../../../utils/meta'; -import { getConfig } from '../../config'; +import { getParserConfig } from '../../config'; import type { OpenApi } from '../interfaces/OpenApi'; import { getModel } from './getModel'; import { getParameterSchema } from './parameter'; @@ -8,7 +8,7 @@ import { getParameterSchema } from './parameter'; export const getModels = ( openApi: OpenApi, ): Pick => { - const config = getConfig(); + const config = getParserConfig(); const types: Client['types'] = {}; let models: Client['models'] = []; diff --git a/packages/openapi-ts/src/openApi/v3/parser/getOperationParameter.ts b/packages/openapi-ts/src/openApi/v3/parser/getOperationParameter.ts index f7ceabb65..01788a443 100644 --- a/packages/openapi-ts/src/openApi/v3/parser/getOperationParameter.ts +++ b/packages/openapi-ts/src/openApi/v3/parser/getOperationParameter.ts @@ -6,7 +6,7 @@ import { getDefault } from '../../common/parser/getDefault'; import { getPattern } from '../../common/parser/getPattern'; import { getRef } from '../../common/parser/getRef'; import { getType } from '../../common/parser/type'; -import { getConfig } from '../../config'; +import { getParserConfig } from '../../config'; import type { OpenApi } from '../interfaces/OpenApi'; import type { OpenApiParameter } from '../interfaces/OpenApiParameter'; import type { OpenApiSchema } from '../interfaces/OpenApiSchema'; @@ -23,7 +23,7 @@ export const getOperationParameter = ({ parameter: OpenApiParameter; types: Client['types']; }): OperationParameter => { - const config = getConfig(); + const config = getParserConfig(); const operationParameterWithoutName: Omit = { $refs: [], diff --git a/packages/openapi-ts/src/openApi/v3/parser/getOperationParameters.ts b/packages/openapi-ts/src/openApi/v3/parser/getOperationParameters.ts index e637d7922..edc2196b4 100644 --- a/packages/openapi-ts/src/openApi/v3/parser/getOperationParameters.ts +++ b/packages/openapi-ts/src/openApi/v3/parser/getOperationParameters.ts @@ -1,7 +1,7 @@ import type { Client } from '../../../types/client'; import type { OperationParameters } from '../../common/interfaces/client'; import { getRef } from '../../common/parser/getRef'; -import { getConfig } from '../../config'; +import { getParserConfig } from '../../config'; import type { OpenApi } from '../interfaces/OpenApi'; import type { OpenApiParameter } from '../interfaces/OpenApiParameter'; import { getOperationParameter } from './getOperationParameter'; @@ -17,7 +17,7 @@ export const getOperationParameters = ({ parameters: OpenApiParameter[]; types: Client['types']; }): OperationParameters => { - const config = getConfig(); + const config = getParserConfig(); const operationParameters: OperationParameters = { $refs: [], @@ -42,9 +42,7 @@ export const getOperationParameters = ({ types, }); - const skip = - config.filterFn?.operationParameter && - !config.filterFn?.operationParameter(parameter); + const skip = !config.filterFn.operationParameter(parameter); if (!allowedIn.includes(parameterDef.in) || skip) { return; } diff --git a/packages/openapi-ts/src/openApi/v3/parser/getOperations.ts b/packages/openapi-ts/src/openApi/v3/parser/getOperations.ts index 696eae6ff..5bbf3f2ea 100644 --- a/packages/openapi-ts/src/openApi/v3/parser/getOperations.ts +++ b/packages/openapi-ts/src/openApi/v3/parser/getOperations.ts @@ -1,7 +1,8 @@ +import { getConfig } from '../../../utils/config'; import type { Client, Operation } from '../../common/interfaces/client'; import { getOperationKey } from '../../common/parser/operation'; import { allowedServiceMethods } from '../../common/parser/service'; -import { getConfig } from '../../config'; +import { getParserConfig } from '../../config'; import type { OpenApi } from '../interfaces/OpenApi'; import { getOperationParameters } from './getOperationParameters'; import { getOperation } from './operation'; @@ -13,7 +14,7 @@ export const getOperations = ({ openApi: OpenApi; types: Client['types']; }): Operation[] => { - const config = getConfig(); + const config = getParserConfig(); const operationIds = new Map(); const operations: Operation[] = []; @@ -26,11 +27,11 @@ export const getOperations = ({ types, }); - for (const key in pathItem) { - const method = key as Lowercase; + for (const name in pathItem) { + const method = name as Lowercase; const operationKey = getOperationKey({ - method: method.toUpperCase(), + method, path, }); @@ -48,8 +49,10 @@ export const getOperations = ({ } if ( - !config.filterFn?.operation || - config.filterFn?.operation(operationKey) + config.filterFn.operation({ + config: getConfig(), + operationKey, + }) ) { const operation = getOperation({ method, diff --git a/packages/openapi-ts/src/openApi/v3/parser/operation.ts b/packages/openapi-ts/src/openApi/v3/parser/operation.ts index 4bdb53978..18df25ae1 100644 --- a/packages/openapi-ts/src/openApi/v3/parser/operation.ts +++ b/packages/openapi-ts/src/openApi/v3/parser/operation.ts @@ -1,4 +1,5 @@ import type { Client } from '../../../types/client'; +import { getConfig } from '../../../utils/config'; import type { Operation, OperationParameter, @@ -7,7 +8,7 @@ import type { import { getRef } from '../../common/parser/getRef'; import { getOperationResponseHeader } from '../../common/parser/operation'; import { toSortedByRequired } from '../../common/parser/sort'; -import { getConfig } from '../../config'; +import { getParserConfig } from '../../config'; import type { OpenApi } from '../interfaces/OpenApi'; import type { OpenApiOperation } from '../interfaces/OpenApiOperation'; import type { OpenApiRequestBody } from '../interfaces/OpenApiRequestBody'; @@ -53,7 +54,7 @@ export const getOperation = ({ types: Client['types']; url: string; }): Operation => { - const config = getConfig(); + const config = getParserConfig(); const operationWithoutName: Omit = { $refs: [], @@ -77,7 +78,12 @@ export const getOperation = ({ }; const operation = { ...operationWithoutName, - name: config.nameFn.operation(operationWithoutName), + name: config.nameFn.operation({ + config: getConfig(), + method: operationWithoutName.method, + operationId: op.operationId, + path: operationWithoutName.path, + }), }; if (op.parameters) { diff --git a/packages/openapi-ts/src/plugins/@hey-api/schemas/config.ts b/packages/openapi-ts/src/plugins/@hey-api/schemas/config.ts index 93402a94d..1079bbdff 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/schemas/config.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/schemas/config.ts @@ -2,6 +2,7 @@ import type { PluginConfig } from './types'; export const defaultConfig: Required = { handler: () => {}, + handler_experimental: () => {}, name: '@hey-api/schemas', output: 'schemas', }; diff --git a/packages/openapi-ts/src/plugins/@hey-api/schemas/types.ts b/packages/openapi-ts/src/plugins/@hey-api/schemas/types.ts index 766b5cf07..ecfc8cad1 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/schemas/types.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/schemas/types.ts @@ -1,4 +1,4 @@ -import type { PluginHandler } from '../../types'; +import type { PluginHandler, PluginHandlerExperimental } from '../../types'; interface Config { /** @@ -14,6 +14,7 @@ interface Config { export interface PluginConfig extends Config { handler: PluginHandler; + handler_experimental?: PluginHandlerExperimental; } export interface UserConfig extends Omit {} diff --git a/packages/openapi-ts/src/plugins/@hey-api/services/config.ts b/packages/openapi-ts/src/plugins/@hey-api/services/config.ts index cbab7d1a3..5f33b457a 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/services/config.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/services/config.ts @@ -2,6 +2,7 @@ import type { PluginConfig } from './types'; export const defaultConfig: Required = { handler: () => {}, + handler_experimental: () => {}, name: '@hey-api/services', output: 'services', }; diff --git a/packages/openapi-ts/src/plugins/@hey-api/services/types.ts b/packages/openapi-ts/src/plugins/@hey-api/services/types.ts index 6527815d4..17f320698 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/services/types.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/services/types.ts @@ -1,4 +1,4 @@ -import type { PluginHandler } from '../../types'; +import type { PluginHandler, PluginHandlerExperimental } from '../../types'; interface Config { /** @@ -14,6 +14,7 @@ interface Config { export interface PluginConfig extends Config { handler: PluginHandler; + handler_experimental?: PluginHandlerExperimental; } export interface UserConfig extends Omit {} diff --git a/packages/openapi-ts/src/plugins/@hey-api/types/config.ts b/packages/openapi-ts/src/plugins/@hey-api/types/config.ts index 1780178d1..4bc33926e 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/types/config.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/types/config.ts @@ -2,6 +2,7 @@ import type { PluginConfig } from './types'; export const defaultConfig: Required = { handler: () => {}, + handler_experimental: () => {}, name: '@hey-api/types', output: 'types', }; diff --git a/packages/openapi-ts/src/plugins/@hey-api/types/types.ts b/packages/openapi-ts/src/plugins/@hey-api/types/types.ts index b1ba128d0..90b180000 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/types/types.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/types/types.ts @@ -1,4 +1,4 @@ -import type { PluginHandler } from '../../types'; +import type { PluginHandler, PluginHandlerExperimental } from '../../types'; interface Config { /** @@ -14,6 +14,7 @@ interface Config { export interface PluginConfig extends Config { handler: PluginHandler; + handler_experimental?: PluginHandlerExperimental; } export interface UserConfig extends Omit {} diff --git a/packages/openapi-ts/src/plugins/@tanstack/query-core/plugin.ts b/packages/openapi-ts/src/plugins/@tanstack/query-core/plugin.ts index 3bf2dc3f4..8b92f6050 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/query-core/plugin.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/query-core/plugin.ts @@ -16,6 +16,8 @@ import { toOperationName, } from '../../../generate/services'; import { relativeModulePath } from '../../../generate/utils'; +import type { IROperationObject, IRPathsObject } from '../../../ir/ir'; +import { hasParametersObjectRequired } from '../../../ir/parameter'; import { isOperationParameterRequired } from '../../../openApi'; import { getOperationKey } from '../../../openApi/common/parser/operation'; import type { Client } from '../../../types/client'; @@ -25,26 +27,62 @@ import type { Operation, OperationParameter, } from '../../../types/client'; +import type { Config } from '../../../types/config'; import type { Files } from '../../../types/utils'; import { getConfig } from '../../../utils/config'; +import { getServiceName } from '../../../utils/postprocess'; import { transformServiceName } from '../../../utils/transform'; -import type { PluginHandler } from '../../types'; +import type { PluginHandler, PluginHandlerExperimental } from '../../types'; import type { PluginConfig as ReactQueryPluginConfig } from '../react-query'; import type { PluginConfig as SolidQueryPluginConfig } from '../solid-query'; import type { PluginConfig as SvelteQueryPluginConfig } from '../svelte-query'; import type { PluginConfig as VueQueryPluginConfig } from '../vue-query'; const toInfiniteQueryOptionsName = (operation: Operation) => - `${toOperationName(operation, false)}InfiniteOptions`; + `${toOperationName({ + config: getConfig(), + id: operation.name, + operation, + })}InfiniteOptions`; const toMutationOptionsName = (operation: Operation) => - `${toOperationName(operation, false)}Mutation`; - -const toQueryOptionsName = (operation: Operation) => - `${toOperationName(operation, false)}Options`; - -const toQueryKeyName = (operation: Operation, isInfinite?: boolean) => - `${toOperationName(operation, false)}${isInfinite ? 'Infinite' : ''}QueryKey`; + `${toOperationName({ + config: getConfig(), + id: operation.name, + operation, + })}Mutation`; + +const toQueryOptionsName = ({ + config, + id, + operation, +}: { + config: Config; + id: string; + operation: IROperationObject | Operation; +}) => + `${toOperationName({ + config, + id, + operation, + })}Options`; + +const toQueryKeyName = ({ + config, + id, + operation, + isInfinite, +}: { + config: Config; + id: string; + isInfinite?: boolean; + operation: IROperationObject | Operation; +}) => + `${toOperationName({ + config, + id, + operation, + })}${isInfinite ? 'Infinite' : ''}QueryKey`; const checkPrerequisites = ({ files }: { files: Files }) => { if (!files.services) { @@ -473,7 +511,10 @@ const createQueryKeyType = ({ file }: { file: Files[keyof Files] }) => { compiler.typeReferenceNode({ typeName: `Pick<${TOptionsType}, '${getClientBaseUrlKey()}' | 'body' | 'headers' | 'path' | 'query'>`, }), - compiler.typeInterfaceNode({ properties }), + compiler.typeInterfaceNode({ + properties, + useLegacyResolution: true, + }), ], }), ], @@ -624,17 +665,17 @@ const createTypeResponse = ({ const createQueryKeyLiteral = ({ isInfinite, - operation, + id, }: { + id: string; isInfinite?: boolean; - operation: Operation; }) => { const queryKeyLiteral = compiler.arrayLiteralExpression({ elements: [ compiler.callExpression({ functionName: createQueryKeyFn, parameters: [ - compiler.stringLiteral({ text: operation.name }), + compiler.ots.string(id), 'options', isInfinite ? compiler.ots.boolean(true) : undefined, ], @@ -692,8 +733,17 @@ export const handler: PluginHandler< processedOperations.set(operationKey, true); const queryFn = [ - config.services.asClass && transformServiceName(service.name), - toOperationName(operation, !config.services.asClass), + config.services.asClass && + transformServiceName({ + config, + name: service.name, + }), + toOperationName({ + config, + handleIllegal: !config.services.asClass, + id: operation.name, + operation, + }), ] .filter(Boolean) .join('.'); @@ -741,10 +791,14 @@ export const handler: PluginHandler< }, ], statements: createQueryKeyLiteral({ - operation, + id: operation.name, }), }), - name: toQueryKeyName(operation), + name: toQueryKeyName({ + config, + id: operation.name, + operation, + }), }); file.add(queryKeyStatement); @@ -811,7 +865,11 @@ export const handler: PluginHandler< { key: 'queryKey', value: compiler.callExpression({ - functionName: toQueryKeyName(operation), + functionName: toQueryKeyName({ + config, + id: operation.name, + operation, + }), parameters: ['options'], }), }, @@ -827,7 +885,11 @@ export const handler: PluginHandler< comment: [], exportConst: true, expression, - name: toQueryOptionsName(operation), + name: toQueryOptionsName({ + config, + id: operation.name, + operation, + }), // TODO: add type error // TODO: AxiosError }); @@ -943,11 +1005,16 @@ export const handler: PluginHandler< ], returnType: typeQueryKey, statements: createQueryKeyLiteral({ + id: operation.name, isInfinite: true, - operation, }), }), - name: toQueryKeyName(operation, true), + name: toQueryKeyName({ + config, + id: operation.name, + isInfinite: true, + operation, + }), }); file.add(queryKeyStatement); @@ -1001,9 +1068,7 @@ export const handler: PluginHandler< text: 'pageParam', }), operator: '===', - right: compiler.stringLiteral({ - text: 'object', - }), + right: compiler.ots.string('object'), }), whenFalse: compiler.objectExpression({ multiLine: true, @@ -1073,7 +1138,12 @@ export const handler: PluginHandler< { key: 'queryKey', value: compiler.callExpression({ - functionName: toQueryKeyName(operation, true), + functionName: toQueryKeyName({ + config, + id: operation.name, + isInfinite: true, + operation, + }), parameters: ['options'], }), }, @@ -1229,3 +1299,241 @@ export const handler: PluginHandler< } } }; + +export const handler_experimental: PluginHandlerExperimental< + | ReactQueryPluginConfig + | SolidQueryPluginConfig + | SvelteQueryPluginConfig + | VueQueryPluginConfig +> = ({ context, files, plugin }) => { + checkPrerequisites({ files }); + + const file = files[plugin.name]; + + // file.import({ + // asType: true, + // module: clientModulePath({ sourceOutput: plugin.output }), + // name: clientOptionsTypeName(), + // }); + + // const typesModulePath = relativeModulePath({ + // moduleOutput: files.types.getName(false), + // sourceOutput: plugin.output, + // }); + + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const mutationsType = + plugin.name === '@tanstack/svelte-query' || + plugin.name === '@tanstack/solid-query' + ? 'MutationOptions' + : 'UseMutationOptions'; + + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unused-vars + let typeInfiniteData!: ImportExportItem; + // let hasCreateInfiniteParamsFunction = false; + let hasCreateQueryKeyParamsFunction = false; + // eslint-disable-next-line prefer-const + let hasInfiniteQueries = false; + // let hasMutations = false; + let hasQueries = false; + + for (const path in context.ir.paths) { + const pathItem = context.ir.paths[path as keyof IRPathsObject]; + + const queryOperations: ReadonlyArray = [ + pathItem.get, + pathItem.post, + ].filter(Boolean) as ReadonlyArray; + + // console.warn(pathItem) + let hasUsedQueryFn = false; + + // queries + if (plugin.queryOptions) { + for (const operation of queryOperations) { + const queryFn = [ + context.config.services.asClass && + transformServiceName({ + config: context.config, + // TODO: parser - handle import from services, it will be enough to + // know one service that contains this operation + // name: service.name, + name: getServiceName('TODO'), + }), + toOperationName({ + config: context.config, + handleIllegal: !context.config.services.asClass, + id: operation.id, + operation, + }), + ] + .filter(Boolean) + .join('.'); + + if (!hasQueries) { + hasQueries = true; + + if (!hasCreateQueryKeyParamsFunction) { + createQueryKeyType({ file }); + createQueryKeyFunction({ file }); + hasCreateQueryKeyParamsFunction = true; + } + + file.import({ + module: plugin.name, + name: queryOptionsFn, + }); + } + + hasUsedQueryFn = true; + + // TODO: parser - update this after rewriting services + const typeData = 'TODO'; + // const { typeData } = createTypeData({ + // client, + // file, + // operation, + // typesModulePath, + // }); + + const isRequired = hasParametersObjectRequired(operation.parameters); + + const queryKeyStatement = compiler.constVariable({ + exportConst: true, + expression: compiler.arrowFunction({ + parameters: [ + { + isRequired, + name: 'options', + type: typeData, + }, + ], + statements: createQueryKeyLiteral({ + id: operation.id, + }), + }), + name: toQueryKeyName({ + config: context.config, + id: operation.id, + operation, + }), + }); + file.add(queryKeyStatement); + + const expression = compiler.arrowFunction({ + parameters: [ + { + isRequired, + name: 'options', + type: typeData, + }, + ], + statements: [ + compiler.returnFunctionCall({ + args: [ + compiler.objectExpression({ + obj: [ + { + key: 'queryFn', + value: compiler.arrowFunction({ + async: true, + multiLine: true, + parameters: [ + { + destructure: [ + { + name: 'queryKey', + }, + ], + }, + ], + statements: [ + compiler.constVariable({ + destructure: true, + expression: compiler.awaitExpression({ + expression: compiler.callExpression({ + functionName: queryFn, + parameters: [ + compiler.objectExpression({ + multiLine: true, + obj: [ + { + spread: 'options', + }, + { + spread: 'queryKey[0]', + }, + { + key: 'throwOnError', + value: true, + }, + ], + }), + ], + }), + }), + name: 'data', + }), + compiler.returnVariable({ + expression: 'data', + }), + ], + }), + }, + { + key: 'queryKey', + value: compiler.callExpression({ + functionName: toQueryKeyName({ + config: context.config, + id: operation.id, + operation, + }), + parameters: ['options'], + }), + }, + ], + }), + ], + name: queryOptionsFn, + }), + ], + }); + const statement = compiler.constVariable({ + // TODO: describe options, same as the actual function call + comment: [], + exportConst: true, + expression, + name: toQueryOptionsName({ + config: context.config, + id: operation.id, + operation, + }), + // TODO: add type error + // TODO: AxiosError + }); + file.add(statement); + } + } + + // const servicesModulePath = relativeModulePath({ + // moduleOutput: files.services.getName(false), + // sourceOutput: plugin.output, + // }); + + if (hasQueries || hasInfiniteQueries) { + // file.import({ + // module: servicesModulePath, + // name: 'client', + // }); + } + + if (hasUsedQueryFn) { + // file.import({ + // module: servicesModulePath, + // name: queryFn.split('.')[0], + // }); + } + } +}; diff --git a/packages/openapi-ts/src/plugins/@tanstack/react-query/config.ts b/packages/openapi-ts/src/plugins/@tanstack/react-query/config.ts index 201ea42bd..47f10e99c 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/react-query/config.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/react-query/config.ts @@ -1,8 +1,9 @@ -import { handler } from '../query-core/plugin'; +import { handler, handler_experimental } from '../query-core/plugin'; import type { PluginConfig } from './types'; export const defaultConfig: Required = { handler, + handler_experimental, infiniteQueryOptions: true, mutationOptions: true, name: '@tanstack/react-query', diff --git a/packages/openapi-ts/src/plugins/@tanstack/react-query/types.ts b/packages/openapi-ts/src/plugins/@tanstack/react-query/types.ts index 46138e3dc..9cfc8f2d5 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/react-query/types.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/react-query/types.ts @@ -1,4 +1,4 @@ -import type { PluginHandler } from '../../types'; +import type { PluginHandler, PluginHandlerExperimental } from '../../types'; interface Config { /** @@ -30,6 +30,7 @@ interface Config { export interface PluginConfig extends Config { handler: PluginHandler; + handler_experimental?: PluginHandlerExperimental; } export interface UserConfig extends Omit {} diff --git a/packages/openapi-ts/src/plugins/@tanstack/solid-query/config.ts b/packages/openapi-ts/src/plugins/@tanstack/solid-query/config.ts index ea62b47ce..8de06edc0 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/solid-query/config.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/solid-query/config.ts @@ -1,8 +1,9 @@ -import { handler } from '../query-core/plugin'; +import { handler, handler_experimental } from '../query-core/plugin'; import type { PluginConfig } from './types'; export const defaultConfig: Required = { handler, + handler_experimental, infiniteQueryOptions: true, mutationOptions: true, name: '@tanstack/solid-query', diff --git a/packages/openapi-ts/src/plugins/@tanstack/solid-query/types.ts b/packages/openapi-ts/src/plugins/@tanstack/solid-query/types.ts index 8826a6885..dcf53b9f1 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/solid-query/types.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/solid-query/types.ts @@ -1,4 +1,4 @@ -import type { PluginHandler } from '../../types'; +import type { PluginHandler, PluginHandlerExperimental } from '../../types'; interface Config { /** @@ -30,6 +30,7 @@ interface Config { export interface PluginConfig extends Config { handler: PluginHandler; + handler_experimental?: PluginHandlerExperimental; } export interface UserConfig extends Omit {} diff --git a/packages/openapi-ts/src/plugins/@tanstack/svelte-query/config.ts b/packages/openapi-ts/src/plugins/@tanstack/svelte-query/config.ts index cd6f0f6a4..46b04a4e6 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/svelte-query/config.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/svelte-query/config.ts @@ -1,8 +1,9 @@ -import { handler } from '../query-core/plugin'; +import { handler, handler_experimental } from '../query-core/plugin'; import type { PluginConfig } from './types'; export const defaultConfig: Required = { handler, + handler_experimental, infiniteQueryOptions: true, mutationOptions: true, name: '@tanstack/svelte-query', diff --git a/packages/openapi-ts/src/plugins/@tanstack/svelte-query/types.ts b/packages/openapi-ts/src/plugins/@tanstack/svelte-query/types.ts index 7549daf79..4fbe82223 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/svelte-query/types.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/svelte-query/types.ts @@ -1,4 +1,4 @@ -import type { PluginHandler } from '../../types'; +import type { PluginHandler, PluginHandlerExperimental } from '../../types'; interface Config { /** @@ -30,6 +30,7 @@ interface Config { export interface PluginConfig extends Config { handler: PluginHandler; + handler_experimental?: PluginHandlerExperimental; } export interface UserConfig extends Omit {} diff --git a/packages/openapi-ts/src/plugins/@tanstack/vue-query/config.ts b/packages/openapi-ts/src/plugins/@tanstack/vue-query/config.ts index 2e516cfc5..b66b90cf9 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/vue-query/config.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/vue-query/config.ts @@ -1,8 +1,9 @@ -import { handler } from '../query-core/plugin'; +import { handler, handler_experimental } from '../query-core/plugin'; import type { PluginConfig } from './types'; export const defaultConfig: Required = { handler, + handler_experimental, infiniteQueryOptions: true, mutationOptions: true, name: '@tanstack/vue-query', diff --git a/packages/openapi-ts/src/plugins/@tanstack/vue-query/types.ts b/packages/openapi-ts/src/plugins/@tanstack/vue-query/types.ts index 27b0530aa..94f414d6a 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/vue-query/types.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/vue-query/types.ts @@ -1,4 +1,4 @@ -import type { PluginHandler } from '../../types'; +import type { PluginHandler, PluginHandlerExperimental } from '../../types'; interface Config { /** @@ -30,6 +30,7 @@ interface Config { export interface PluginConfig extends Config { handler: PluginHandler; + handler_experimental?: PluginHandlerExperimental; } export interface UserConfig extends Omit {} diff --git a/packages/openapi-ts/src/plugins/types.ts b/packages/openapi-ts/src/plugins/types.ts index c9f3cfae3..2dbb78212 100644 --- a/packages/openapi-ts/src/plugins/types.ts +++ b/packages/openapi-ts/src/plugins/types.ts @@ -1,10 +1,17 @@ +import type { IRContext } from '../ir/context'; import type { Client } from '../types/client'; import type { Files } from '../types/utils'; export type PluginHandler = (args: { client: Client; files: Files; - plugin: Omit, 'handler'>; + plugin: Omit, 'handler' | 'handler_experimental'>; +}) => void; + +export type PluginHandlerExperimental = (args: { + context: IRContext; + files: Files; + plugin: Omit, 'handler' | 'handler_experimental'>; }) => void; type KeyTypes = string | number | symbol; @@ -21,6 +28,9 @@ export type DefaultPluginConfigsMap< > = { [K in U]: { handler: PluginHandler>>; + handler_experimental?: PluginHandlerExperimental< + Required> + >; name: string; output?: string; }; diff --git a/packages/openapi-ts/src/plugins/zod/config.ts b/packages/openapi-ts/src/plugins/zod/config.ts index 61ee8f763..1dc743971 100644 --- a/packages/openapi-ts/src/plugins/zod/config.ts +++ b/packages/openapi-ts/src/plugins/zod/config.ts @@ -3,6 +3,7 @@ import type { PluginConfig } from './types'; export const defaultConfig: Required = { handler, + handler_experimental: () => {}, name: 'zod', output: 'zod', }; diff --git a/packages/openapi-ts/src/plugins/zod/plugin.ts b/packages/openapi-ts/src/plugins/zod/plugin.ts index 2bcf76b5f..d8e33ab3b 100644 --- a/packages/openapi-ts/src/plugins/zod/plugin.ts +++ b/packages/openapi-ts/src/plugins/zod/plugin.ts @@ -12,9 +12,9 @@ interface TypesProps { } const processArray = ({ file, model }: TypesProps) => { - const identifier = file.ensureUniqueIdentifier({ + const identifier = file.identifier({ + $ref: model.meta?.$ref || '', create: true, - meta: model.meta, namespace: 'value', }); @@ -110,9 +110,9 @@ const processArray = ({ file, model }: TypesProps) => { }; const processGeneric = ({ file, model }: TypesProps) => { - const identifier = file.ensureUniqueIdentifier({ + const identifier = file.identifier({ + $ref: model.meta?.$ref || '', create: true, - meta: model.meta, namespace: 'value', }); diff --git a/packages/openapi-ts/src/plugins/zod/types.ts b/packages/openapi-ts/src/plugins/zod/types.ts index c20240657..6faeafe70 100644 --- a/packages/openapi-ts/src/plugins/zod/types.ts +++ b/packages/openapi-ts/src/plugins/zod/types.ts @@ -1,4 +1,4 @@ -import type { PluginHandler } from '../types'; +import type { PluginHandler, PluginHandlerExperimental } from '../types'; interface Config { /** @@ -14,6 +14,7 @@ interface Config { export interface PluginConfig extends Config { handler: PluginHandler; + handler_experimental?: PluginHandlerExperimental; } export interface UserConfig extends Omit {} diff --git a/packages/openapi-ts/src/types/config.ts b/packages/openapi-ts/src/types/config.ts index ba4e4b2d0..0dc29209c 100644 --- a/packages/openapi-ts/src/types/config.ts +++ b/packages/openapi-ts/src/types/config.ts @@ -1,3 +1,4 @@ +import type { IROperationObject } from '../ir/ir'; import type { OpenApiV2Schema, OpenApiV3Schema } from '../openApi'; import type { ClientPlugins, UserPlugins } from '../plugins/'; import type { Operation } from '../types/client'; @@ -175,9 +176,11 @@ export interface ClientConfig { */ include?: string; /** - * Customise the name of methods within the service. By default, {@link Operation.name} is used. + * Customise the name of methods within the service. By default, {@link IROperationObject.id} or {@link Operation.name} is used. */ - methodNameBuilder?: (operation: Operation) => string; + methodNameBuilder?: ( + operation: IROperationObject | Operation, + ) => string; /** * Customize the generated service class names. The name variable is * obtained from your OpenAPI specification tags. @@ -186,6 +189,7 @@ export interface ClientConfig { * @default '{{name}}Service' */ name?: string; + // TODO: parser - rename operationId option to something like inferId?: boolean /** * Use operation ID to generate operation names? * @default true diff --git a/packages/openapi-ts/src/utils/__tests__/parse.spec.ts b/packages/openapi-ts/src/utils/__tests__/parse.spec.ts index 02cb74ac8..d3d383dd2 100644 --- a/packages/openapi-ts/src/utils/__tests__/parse.spec.ts +++ b/packages/openapi-ts/src/utils/__tests__/parse.spec.ts @@ -1,8 +1,7 @@ import { describe, expect, it } from 'vitest'; -import type { Operation } from '../../openApi'; +import { operationNameFn } from '../../openApi/config'; import { setConfig } from '../config'; -import { operationNameFn } from '../parse'; describe('operationNameFn', () => { const optionsCommon: Parameters[0] = { @@ -277,7 +276,12 @@ describe('operationNameFn', () => { ({ url, method, options, operationId, expected }) => { setConfig(options); expect( - operationNameFn({ id: operationId, method, path: url } as Operation), + operationNameFn({ + config: options, + method, + operationId, + path: url, + }), ).toBe(expected); }, ); diff --git a/packages/openapi-ts/src/utils/__tests__/postprocess.spec.ts b/packages/openapi-ts/src/utils/__tests__/postprocess.spec.ts index 43d8ef2e2..2d70d2339 100644 --- a/packages/openapi-ts/src/utils/__tests__/postprocess.spec.ts +++ b/packages/openapi-ts/src/utils/__tests__/postprocess.spec.ts @@ -1,9 +1,14 @@ import { describe, expect, it } from 'vitest'; -import { type Config, parse } from '../../openApi'; +import { parse } from '../../openApi'; +import type { ParserConfig } from '../../openApi/config'; import { getServiceName, postProcessClient } from '../postprocess'; -const config: Config = { +const parserConfig: ParserConfig = { + filterFn: { + operation: () => true, + operationParameter: () => true, + }, nameFn: { operation: () => 'operation', operationParameter: () => 'operationParameter', @@ -31,7 +36,6 @@ describe('getServiceName', () => { describe('getServices', () => { it('should create a unnamed service if tags are empty', () => { const parserClient = parse({ - config, openApi: { info: { title: 'x', @@ -54,6 +58,7 @@ describe('getServices', () => { }, }, }, + parserConfig, }); const { services } = postProcessClient(parserClient); @@ -65,7 +70,6 @@ describe('getServices', () => { describe('getServices', () => { it('should create a unnamed service if tags are empty', () => { const parserClient = parse({ - config, openApi: { info: { title: 'x', @@ -88,6 +92,7 @@ describe('getServices', () => { }, }, }, + parserConfig, }); const { services } = postProcessClient(parserClient); diff --git a/packages/openapi-ts/src/utils/handlebars.ts b/packages/openapi-ts/src/utils/handlebars.ts index d1b92b72b..2a4f9781a 100644 --- a/packages/openapi-ts/src/utils/handlebars.ts +++ b/packages/openapi-ts/src/utils/handlebars.ts @@ -89,6 +89,7 @@ import xhrRequest from '../legacy/handlebars/compiled/core/xhr/request.js'; // @ts-ignore import xhrSendRequest from '../legacy/handlebars/compiled/core/xhr/sendRequest.js'; import { camelCase } from './camelCase'; +import { getConfig } from './config'; import { transformServiceName } from './transform'; export const registerHandlebarHelpers = (): void => { @@ -133,7 +134,15 @@ export const registerHandlebarHelpers = (): void => { }, ); - Handlebars.registerHelper('transformServiceName', transformServiceName); + Handlebars.registerHelper( + 'transformServiceName', + function (this: unknown, name: string) { + return transformServiceName({ + config: getConfig(), + name, + }); + }, + ); }; export interface Templates { diff --git a/packages/openapi-ts/src/utils/parse.ts b/packages/openapi-ts/src/utils/parse.ts deleted file mode 100644 index f288854fd..000000000 --- a/packages/openapi-ts/src/utils/parse.ts +++ /dev/null @@ -1,68 +0,0 @@ -import type { Operation, OperationParameter } from '../openApi'; -import { sanitizeNamespaceIdentifier } from '../openApi'; -import { camelCase } from './camelCase'; -import { getConfig, isLegacyClient } from './config'; -import { transformTypeKeyName } from './type'; - -export const operationFilterFn = (operationKey: string): boolean => { - const config = getConfig(); - const regexp = config.services.filter - ? new RegExp(config.services.filter) - : undefined; - return !regexp || regexp.test(operationKey); -}; - -export const operationParameterFilterFn = ( - parameter: OperationParameter, -): boolean => { - const config = getConfig(); - - // legacy clients ignore the "api-version" param since we do not want to - // add it as the first/default parameter for each of the service calls - return !isLegacyClient(config) || parameter.prop !== 'api-version'; -}; - -/** - * Convert the input value to a correct operation (method) class name. - * This will use the operation ID - if available - and otherwise fallback - * on a generated name from the URL - */ -export const operationNameFn = (operation: Omit): string => { - const config = getConfig(); - - if (config.services.operationId && operation.id) { - return camelCase({ - input: sanitizeNamespaceIdentifier(operation.id), - }); - } - - let urlWithoutPlaceholders = operation.path; - - // legacy clients ignore the "api-version" param since we do not want to - // add it as the first/default parameter for each of the service calls - if (isLegacyClient(config)) { - urlWithoutPlaceholders = urlWithoutPlaceholders.replace( - /[^/]*?{api-version}.*?\//g, - '', - ); - } - - urlWithoutPlaceholders = urlWithoutPlaceholders - .replace(/{(.*?)}/g, 'by-$1') - // replace slashes with hyphens for camelcase method at the end - .replace(/[/:]/g, '-'); - - return camelCase({ - input: `${operation.method}-${urlWithoutPlaceholders}`, - }); -}; - -export const operationParameterNameFn = ( - parameter: Omit, -): string => { - const config = getConfig(); - - return !isLegacyClient(config) - ? parameter.prop - : transformTypeKeyName(parameter.prop); -}; diff --git a/packages/openapi-ts/src/utils/ref.ts b/packages/openapi-ts/src/utils/ref.ts new file mode 100644 index 000000000..72b714030 --- /dev/null +++ b/packages/openapi-ts/src/utils/ref.ts @@ -0,0 +1,35 @@ +export const irRef = '#/ir/'; + +export const isRefOpenApiComponent = ($ref: string): boolean => { + const parts = refToParts($ref); + // reusable components are nested within components// + return parts.length === 3 && parts[0] === 'components'; +}; + +const refToParts = ($ref: string): string[] => { + // Remove the leading `#` and split by `/` to traverse the object + const parts = $ref.replace(/^#\//, '').split('/'); + return parts; +}; + +export const resolveRef = ({ + $ref, + spec, +}: { + $ref: string; + spec: Record; +}): T => { + const parts = refToParts($ref); + + let current = spec; + + for (const part of parts) { + const p = part as keyof typeof current; + if (current[p] === undefined) { + throw new Error(`Reference not found: ${$ref}`); + } + current = current[p]; + } + + return current as T; +}; diff --git a/packages/openapi-ts/src/utils/transform.ts b/packages/openapi-ts/src/utils/transform.ts index bee18de83..ef402bf67 100644 --- a/packages/openapi-ts/src/utils/transform.ts +++ b/packages/openapi-ts/src/utils/transform.ts @@ -1,13 +1,20 @@ import { ensureValidTypeScriptJavaScriptIdentifier } from '../openApi'; +import type { Config } from '../types/config'; import { camelCase } from './camelCase'; import { getConfig } from './config'; import { reservedWordsRegExp } from './regexp'; -export const transformServiceName = (name: string) => { - const config = getConfig(); +export const transformServiceName = ({ + config, + name, +}: { + config: Config; + name: string; +}) => { if (config.services.name) { return config.services.name.replace('{{name}}', name); } + return name; }; diff --git a/packages/openapi-ts/src/utils/type.ts b/packages/openapi-ts/src/utils/type.ts index 09676bb2c..072e72514 100644 --- a/packages/openapi-ts/src/utils/type.ts +++ b/packages/openapi-ts/src/utils/type.ts @@ -98,7 +98,7 @@ const typeEnum = (model: Model) => { const typeDict = (model: Model) => { const type = model.link && !Array.isArray(model.link) ? toType(model.link) : base(model); - return compiler.typeRecordNode(['string'], [type], model.isNullable); + return compiler.typeRecordNode(['string'], [type], model.isNullable, true); }; const typeUnionOrIntersection = ({ @@ -187,6 +187,7 @@ const typeInterface = (model: Model) => { return compiler.typeInterfaceNode({ isNullable: model.isNullable, properties, + useLegacyResolution: !config.experimental_parser, }); }; diff --git a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/react-query/asClass/@tanstack/react-query.gen.ts b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/react-query/asClass/@tanstack/react-query.gen.ts index 0eb58fabe..72c3ce947 100644 --- a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/react-query/asClass/@tanstack/react-query.gen.ts +++ b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/react-query/asClass/@tanstack/react-query.gen.ts @@ -33,7 +33,7 @@ const createQueryKey = (id: string, options?: TOptions }; export const collectionFormatQueryKey = (options: Options) => [ - createQueryKey("collectionFormat", options) + createQueryKey('collectionFormat', options) ]; export const collectionFormatOptions = (options: Options) => { return queryOptions({ @@ -49,7 +49,7 @@ export const collectionFormatOptions = (options: Options) }); }; export const complexTypesQueryKey = (options: Options) => [ - createQueryKey("complexTypes", options) + createQueryKey('complexTypes', options) ]; export const complexTypesOptions = (options: Options) => { return queryOptions({ @@ -75,7 +75,7 @@ export const complexParamsMutation = () => { const mutationOptions: UseMutationO }; return mutationOptions; }; export const exportQueryKey = (options?: Options) => [ - createQueryKey("export", options) + createQueryKey('export', options) ]; export const exportOptions = (options?: Options) => { return queryOptions({ @@ -91,7 +91,7 @@ export const exportOptions = (options?: Options) => { return queryOptions({ }); }; export const importQueryKey = (options: Options) => [ - createQueryKey("import", options) + createQueryKey('import', options) ]; export const importOptions = (options: Options) => { return queryOptions({ @@ -117,7 +117,7 @@ export const importMutation = () => { const mutationOptions: UseMutationOptions< }; return mutationOptions; }; export const getApiVbyApiVersionSimpleOperationQueryKey = (options: Options) => [ - createQueryKey("getApiVbyApiVersionSimpleOperation", options) + createQueryKey('getApiVbyApiVersionSimpleOperation', options) ]; export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => { return queryOptions({ @@ -133,7 +133,7 @@ export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => [ - createQueryKey("callWithDefaultParameters", options) + createQueryKey('callWithDefaultParameters', options) ]; export const callWithDefaultParametersOptions = (options?: Options) => { return queryOptions({ @@ -149,7 +149,7 @@ export const callWithDefaultParametersOptions = (options?: Options) => [ - createQueryKey("callWithDefaultOptionalParameters", options) + createQueryKey('callWithDefaultOptionalParameters', options) ]; export const callWithDefaultOptionalParametersOptions = (options?: Options) => { return queryOptions({ @@ -185,7 +185,7 @@ export const callToTestOrderOfParamsMutation = () => { const mutationOptions: Us }; return mutationOptions; }; export const deprecatedCallQueryKey = (options: Options) => [ - createQueryKey("deprecatedCall", options) + createQueryKey('deprecatedCall', options) ]; export const deprecatedCallOptions = (options: Options) => { return queryOptions({ @@ -211,7 +211,7 @@ export const deprecatedCallMutation = () => { const mutationOptions: UseMutation }; return mutationOptions; }; export const callWithDescriptionsQueryKey = (options?: Options) => [ - createQueryKey("callWithDescriptions", options) + createQueryKey('callWithDescriptions', options) ]; export const callWithDescriptionsOptions = (options?: Options) => { return queryOptions({ @@ -237,7 +237,7 @@ export const callWithDescriptionsMutation = () => { const mutationOptions: UseMu }; return mutationOptions; }; export const duplicateNameQueryKey = (options?: Options) => [ - createQueryKey("duplicateName", options) + createQueryKey('duplicateName', options) ]; export const duplicateNameOptions = (options?: Options) => { return queryOptions({ @@ -253,7 +253,7 @@ export const duplicateNameOptions = (options?: Options) => { return queryOptions }); }; export const duplicateName1QueryKey = (options?: Options) => [ - createQueryKey("duplicateName1", options) + createQueryKey('duplicateName1', options) ]; export const duplicateName1Options = (options?: Options) => { return queryOptions({ @@ -299,7 +299,7 @@ export const duplicateName3Mutation = () => { const mutationOptions: UseMutation }; return mutationOptions; }; export const testErrorCodeQueryKey = (options: Options) => [ - createQueryKey("testErrorCode", options) + createQueryKey('testErrorCode', options) ]; export const testErrorCodeOptions = (options: Options) => { return queryOptions({ @@ -325,7 +325,7 @@ export const testErrorCodeMutation = () => { const mutationOptions: UseMutationO }; return mutationOptions; }; export const fileResponseQueryKey = (options: Options) => [ - createQueryKey("fileResponse", options) + createQueryKey('fileResponse', options) ]; export const fileResponseOptions = (options: Options) => { return queryOptions({ @@ -341,7 +341,7 @@ export const fileResponseOptions = (options: Options) => { ret }); }; export const postApiVbyApiVersionFormDataQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionFormData", options) + createQueryKey('postApiVbyApiVersionFormData', options) ]; export const postApiVbyApiVersionFormDataOptions = (options?: Options) => { return queryOptions({ @@ -367,7 +367,7 @@ export const postApiVbyApiVersionFormDataMutation = () => { const mutationOption }; return mutationOptions; }; export const callWithResultFromHeaderQueryKey = (options?: Options) => [ - createQueryKey("callWithResultFromHeader", options) + createQueryKey('callWithResultFromHeader', options) ]; export const callWithResultFromHeaderOptions = (options?: Options) => { return queryOptions({ @@ -393,7 +393,7 @@ export const callWithResultFromHeaderMutation = () => { const mutationOptions: U }; return mutationOptions; }; export const multipartRequestQueryKey = (options?: Options) => [ - createQueryKey("multipartRequest", options) + createQueryKey('multipartRequest', options) ]; export const multipartRequestOptions = (options?: Options) => { return queryOptions({ @@ -419,7 +419,7 @@ export const multipartRequestMutation = () => { const mutationOptions: UseMutati }; return mutationOptions; }; export const multipartResponseQueryKey = (options?: Options) => [ - createQueryKey("multipartResponse", options) + createQueryKey('multipartResponse', options) ]; export const multipartResponseOptions = (options?: Options) => { return queryOptions({ @@ -435,7 +435,7 @@ export const multipartResponseOptions = (options?: Options) => { return queryOpt }); }; export const dummyAQueryKey = (options?: Options) => [ - createQueryKey("dummyA", options) + createQueryKey('dummyA', options) ]; export const dummyAOptions = (options?: Options) => { return queryOptions({ @@ -451,7 +451,7 @@ export const dummyAOptions = (options?: Options) => { return queryOptions({ }); }; export const dummyBQueryKey = (options?: Options) => [ - createQueryKey("dummyB", options) + createQueryKey('dummyB', options) ]; export const dummyBOptions = (options?: Options) => { return queryOptions({ @@ -467,7 +467,7 @@ export const dummyBOptions = (options?: Options) => { return queryOptions({ }); }; export const callWithNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithNoContentResponse", options) + createQueryKey('callWithNoContentResponse', options) ]; export const callWithNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -483,7 +483,7 @@ export const callWithNoContentResponseOptions = (options?: Options) => { return }); }; export const callWithResponseAndNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponseAndNoContentResponse", options) + createQueryKey('callWithResponseAndNoContentResponse', options) ]; export const callWithResponseAndNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -499,7 +499,7 @@ export const callWithResponseAndNoContentResponseOptions = (options?: Options) = }); }; export const nonAsciiæøåÆøÅöôêÊ字符串QueryKey = (options: Options) => [ - createQueryKey("nonAsciiæøåÆøÅöôêÊ字符串", options) + createQueryKey('nonAsciiæøåÆøÅöôêÊ字符串', options) ]; export const nonAsciiæøåÆøÅöôêÊ字符串Options = (options: Options) => { return queryOptions({ @@ -545,7 +545,7 @@ export const deleteFooMutation = () => { const mutationOptions: UseMutationOptio }; return mutationOptions; }; export const callWithParametersQueryKey = (options: Options) => [ - createQueryKey("callWithParameters", options) + createQueryKey('callWithParameters', options) ]; export const callWithParametersOptions = (options: Options) => { return queryOptions({ @@ -590,7 +590,7 @@ const createInfiniteParams = [0], 'body' | 'hea }; export const callWithParametersInfiniteQueryKey = (options: Options): QueryKey> => [ - createQueryKey("callWithParameters", options, true) + createQueryKey('callWithParameters', options, true) ]; export const callWithParametersInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, string | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -598,7 +598,7 @@ export const callWithParametersInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { cursor: pageParam } @@ -625,7 +625,7 @@ export const callWithParametersMutation = () => { const mutationOptions: UseMuta }; return mutationOptions; }; export const callWithWeirdParameterNamesQueryKey = (options: Options) => [ - createQueryKey("callWithWeirdParameterNames", options) + createQueryKey('callWithWeirdParameterNames', options) ]; export const callWithWeirdParameterNamesOptions = (options: Options) => { return queryOptions({ @@ -651,7 +651,7 @@ export const callWithWeirdParameterNamesMutation = () => { const mutationOptions }; return mutationOptions; }; export const getCallWithOptionalParamQueryKey = (options: Options) => [ - createQueryKey("getCallWithOptionalParam", options) + createQueryKey('getCallWithOptionalParam', options) ]; export const getCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -667,7 +667,7 @@ export const getCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("getCallWithOptionalParam", options, true) + createQueryKey('getCallWithOptionalParam', options, true) ]; export const getCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -675,7 +675,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { page: pageParam } @@ -692,7 +692,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options) => [ - createQueryKey("postCallWithOptionalParam", options) + createQueryKey('postCallWithOptionalParam', options) ]; export const postCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -708,7 +708,7 @@ export const postCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("postCallWithOptionalParam", options, true) + createQueryKey('postCallWithOptionalParam', options, true) ]; export const postCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -716,7 +716,7 @@ export const postCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { body: { offset: pageParam } @@ -743,7 +743,7 @@ export const postCallWithOptionalParamMutation = () => { const mutationOptions: }; return mutationOptions; }; export const postApiVbyApiVersionRequestBodyQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionRequestBody", options) + createQueryKey('postApiVbyApiVersionRequestBody', options) ]; export const postApiVbyApiVersionRequestBodyOptions = (options?: Options) => { return queryOptions({ @@ -769,7 +769,7 @@ export const postApiVbyApiVersionRequestBodyMutation = () => { const mutationOpt }; return mutationOptions; }; export const callWithResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponse", options) + createQueryKey('callWithResponse', options) ]; export const callWithResponseOptions = (options?: Options) => { return queryOptions({ @@ -785,7 +785,7 @@ export const callWithResponseOptions = (options?: Options) => { return queryOpti }); }; export const callWithDuplicateResponsesQueryKey = (options?: Options) => [ - createQueryKey("callWithDuplicateResponses", options) + createQueryKey('callWithDuplicateResponses', options) ]; export const callWithDuplicateResponsesOptions = (options?: Options) => { return queryOptions({ @@ -821,7 +821,7 @@ export const callWithResponsesMutation = () => { const mutationOptions: UseMutat }; return mutationOptions; }; export const apiVVersionOdataControllerCountQueryKey = (options?: Options) => [ - createQueryKey("apiVVersionOdataControllerCount", options) + createQueryKey('apiVVersionOdataControllerCount', options) ]; export const apiVVersionOdataControllerCountOptions = (options?: Options) => { return queryOptions({ @@ -837,7 +837,7 @@ export const apiVVersionOdataControllerCountOptions = (options?: Options) => { r }); }; export const getCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("getCallWithoutParametersAndResponse", options) + createQueryKey('getCallWithoutParametersAndResponse', options) ]; export const getCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -863,7 +863,7 @@ export const putCallWithoutParametersAndResponseMutation = () => { const mutatio }; return mutationOptions; }; export const postCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("postCallWithoutParametersAndResponse", options) + createQueryKey('postCallWithoutParametersAndResponse', options) ]; export const postCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -909,7 +909,7 @@ export const patchCallWithoutParametersAndResponseMutation = () => { const mutat }; return mutationOptions; }; export const typesQueryKey = (options: Options) => [ - createQueryKey("types", options) + createQueryKey('types', options) ]; export const typesOptions = (options: Options) => { return queryOptions({ @@ -925,7 +925,7 @@ export const typesOptions = (options: Options) => { return queryOptio }); }; export const uploadFileQueryKey = (options: Options) => [ - createQueryKey("uploadFile", options) + createQueryKey('uploadFile', options) ]; export const uploadFileOptions = (options: Options) => { return queryOptions({ diff --git a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/react-query/axios/@tanstack/react-query.gen.ts b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/react-query/axios/@tanstack/react-query.gen.ts index a33a8d62a..be7954a6c 100644 --- a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/react-query/axios/@tanstack/react-query.gen.ts +++ b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/react-query/axios/@tanstack/react-query.gen.ts @@ -34,7 +34,7 @@ const createQueryKey = (id: string, options?: TOptions }; export const exportQueryKey = (options?: Options) => [ - createQueryKey("export", options) + createQueryKey('export', options) ]; export const exportOptions = (options?: Options) => { return queryOptions({ @@ -50,7 +50,7 @@ export const exportOptions = (options?: Options) => { return queryOptions({ }); }; export const importQueryKey = (options: Options) => [ - createQueryKey("import", options) + createQueryKey('import', options) ]; export const importOptions = (options: Options) => { return queryOptions({ @@ -76,7 +76,7 @@ export const importMutation = () => { const mutationOptions: UseMutationOptions< }; return mutationOptions; }; export const apiVVersionOdataControllerCountQueryKey = (options?: Options) => [ - createQueryKey("apiVVersionOdataControllerCount", options) + createQueryKey('apiVVersionOdataControllerCount', options) ]; export const apiVVersionOdataControllerCountOptions = (options?: Options) => { return queryOptions({ @@ -92,7 +92,7 @@ export const apiVVersionOdataControllerCountOptions = (options?: Options) => { r }); }; export const getApiVbyApiVersionSimpleOperationQueryKey = (options: Options) => [ - createQueryKey("getApiVbyApiVersionSimpleOperation", options) + createQueryKey('getApiVbyApiVersionSimpleOperation', options) ]; export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => { return queryOptions({ @@ -108,7 +108,7 @@ export const getApiVbyApiVersionSimpleOperationOptions = (options: Options [ - createQueryKey("getCallWithoutParametersAndResponse", options) + createQueryKey('getCallWithoutParametersAndResponse', options) ]; export const getCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -134,7 +134,7 @@ export const putCallWithoutParametersAndResponseMutation = () => { const mutatio }; return mutationOptions; }; export const postCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("postCallWithoutParametersAndResponse", options) + createQueryKey('postCallWithoutParametersAndResponse', options) ]; export const postCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -190,7 +190,7 @@ export const deleteFooMutation = () => { const mutationOptions: UseMutationOptio }; return mutationOptions; }; export const callWithDescriptionsQueryKey = (options?: Options) => [ - createQueryKey("callWithDescriptions", options) + createQueryKey('callWithDescriptions', options) ]; export const callWithDescriptionsOptions = (options?: Options) => { return queryOptions({ @@ -216,7 +216,7 @@ export const callWithDescriptionsMutation = () => { const mutationOptions: UseMu }; return mutationOptions; }; export const deprecatedCallQueryKey = (options: Options) => [ - createQueryKey("deprecatedCall", options) + createQueryKey('deprecatedCall', options) ]; export const deprecatedCallOptions = (options: Options) => { return queryOptions({ @@ -242,7 +242,7 @@ export const deprecatedCallMutation = () => { const mutationOptions: UseMutation }; return mutationOptions; }; export const callWithParametersQueryKey = (options: Options) => [ - createQueryKey("callWithParameters", options) + createQueryKey('callWithParameters', options) ]; export const callWithParametersOptions = (options: Options) => { return queryOptions({ @@ -287,7 +287,7 @@ const createInfiniteParams = [0], 'body' | 'hea }; export const callWithParametersInfiniteQueryKey = (options: Options): QueryKey> => [ - createQueryKey("callWithParameters", options, true) + createQueryKey('callWithParameters', options, true) ]; export const callWithParametersInfiniteOptions = (options: Options) => { return infiniteQueryOptions, InfiniteData, QueryKey>, string | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -295,7 +295,7 @@ export const callWithParametersInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { cursor: pageParam } @@ -322,7 +322,7 @@ export const callWithParametersMutation = () => { const mutationOptions: UseMuta }; return mutationOptions; }; export const callWithWeirdParameterNamesQueryKey = (options: Options) => [ - createQueryKey("callWithWeirdParameterNames", options) + createQueryKey('callWithWeirdParameterNames', options) ]; export const callWithWeirdParameterNamesOptions = (options: Options) => { return queryOptions({ @@ -348,7 +348,7 @@ export const callWithWeirdParameterNamesMutation = () => { const mutationOptions }; return mutationOptions; }; export const getCallWithOptionalParamQueryKey = (options: Options) => [ - createQueryKey("getCallWithOptionalParam", options) + createQueryKey('getCallWithOptionalParam', options) ]; export const getCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -364,7 +364,7 @@ export const getCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("getCallWithOptionalParam", options, true) + createQueryKey('getCallWithOptionalParam', options, true) ]; export const getCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, InfiniteData, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -372,7 +372,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { page: pageParam } @@ -389,7 +389,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options) => [ - createQueryKey("postCallWithOptionalParam", options) + createQueryKey('postCallWithOptionalParam', options) ]; export const postCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -405,7 +405,7 @@ export const postCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("postCallWithOptionalParam", options, true) + createQueryKey('postCallWithOptionalParam', options, true) ]; export const postCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, InfiniteData, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -413,7 +413,7 @@ export const postCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { body: { offset: pageParam } @@ -440,7 +440,7 @@ export const postCallWithOptionalParamMutation = () => { const mutationOptions: }; return mutationOptions; }; export const postApiVbyApiVersionRequestBodyQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionRequestBody", options) + createQueryKey('postApiVbyApiVersionRequestBody', options) ]; export const postApiVbyApiVersionRequestBodyOptions = (options?: Options) => { return queryOptions({ @@ -466,7 +466,7 @@ export const postApiVbyApiVersionRequestBodyMutation = () => { const mutationOpt }; return mutationOptions; }; export const postApiVbyApiVersionFormDataQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionFormData", options) + createQueryKey('postApiVbyApiVersionFormData', options) ]; export const postApiVbyApiVersionFormDataOptions = (options?: Options) => { return queryOptions({ @@ -492,7 +492,7 @@ export const postApiVbyApiVersionFormDataMutation = () => { const mutationOption }; return mutationOptions; }; export const callWithDefaultParametersQueryKey = (options?: Options) => [ - createQueryKey("callWithDefaultParameters", options) + createQueryKey('callWithDefaultParameters', options) ]; export const callWithDefaultParametersOptions = (options?: Options) => { return queryOptions({ @@ -508,7 +508,7 @@ export const callWithDefaultParametersOptions = (options?: Options) => [ - createQueryKey("callWithDefaultOptionalParameters", options) + createQueryKey('callWithDefaultOptionalParameters', options) ]; export const callWithDefaultOptionalParametersOptions = (options?: Options) => { return queryOptions({ @@ -544,7 +544,7 @@ export const callToTestOrderOfParamsMutation = () => { const mutationOptions: Us }; return mutationOptions; }; export const duplicateNameQueryKey = (options?: Options) => [ - createQueryKey("duplicateName", options) + createQueryKey('duplicateName', options) ]; export const duplicateNameOptions = (options?: Options) => { return queryOptions({ @@ -560,7 +560,7 @@ export const duplicateNameOptions = (options?: Options) => { return queryOptions }); }; export const duplicateName1QueryKey = (options?: Options) => [ - createQueryKey("duplicateName1", options) + createQueryKey('duplicateName1', options) ]; export const duplicateName1Options = (options?: Options) => { return queryOptions({ @@ -606,7 +606,7 @@ export const duplicateName3Mutation = () => { const mutationOptions: UseMutation }; return mutationOptions; }; export const callWithNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithNoContentResponse", options) + createQueryKey('callWithNoContentResponse', options) ]; export const callWithNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -622,7 +622,7 @@ export const callWithNoContentResponseOptions = (options?: Options) => { return }); }; export const callWithResponseAndNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponseAndNoContentResponse", options) + createQueryKey('callWithResponseAndNoContentResponse', options) ]; export const callWithResponseAndNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -638,7 +638,7 @@ export const callWithResponseAndNoContentResponseOptions = (options?: Options) = }); }; export const dummyAQueryKey = (options?: Options) => [ - createQueryKey("dummyA", options) + createQueryKey('dummyA', options) ]; export const dummyAOptions = (options?: Options) => { return queryOptions({ @@ -654,7 +654,7 @@ export const dummyAOptions = (options?: Options) => { return queryOptions({ }); }; export const dummyBQueryKey = (options?: Options) => [ - createQueryKey("dummyB", options) + createQueryKey('dummyB', options) ]; export const dummyBOptions = (options?: Options) => { return queryOptions({ @@ -670,7 +670,7 @@ export const dummyBOptions = (options?: Options) => { return queryOptions({ }); }; export const callWithResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponse", options) + createQueryKey('callWithResponse', options) ]; export const callWithResponseOptions = (options?: Options) => { return queryOptions({ @@ -686,7 +686,7 @@ export const callWithResponseOptions = (options?: Options) => { return queryOpti }); }; export const callWithDuplicateResponsesQueryKey = (options?: Options) => [ - createQueryKey("callWithDuplicateResponses", options) + createQueryKey('callWithDuplicateResponses', options) ]; export const callWithDuplicateResponsesOptions = (options?: Options) => { return queryOptions({ @@ -722,7 +722,7 @@ export const callWithResponsesMutation = () => { const mutationOptions: UseMutat }; return mutationOptions; }; export const collectionFormatQueryKey = (options: Options) => [ - createQueryKey("collectionFormat", options) + createQueryKey('collectionFormat', options) ]; export const collectionFormatOptions = (options: Options) => { return queryOptions({ @@ -738,7 +738,7 @@ export const collectionFormatOptions = (options: Options) }); }; export const typesQueryKey = (options: Options) => [ - createQueryKey("types", options) + createQueryKey('types', options) ]; export const typesOptions = (options: Options) => { return queryOptions({ @@ -754,7 +754,7 @@ export const typesOptions = (options: Options) => { return queryOptio }); }; export const uploadFileQueryKey = (options: Options) => [ - createQueryKey("uploadFile", options) + createQueryKey('uploadFile', options) ]; export const uploadFileOptions = (options: Options) => { return queryOptions({ @@ -780,7 +780,7 @@ export const uploadFileMutation = () => { const mutationOptions: UseMutationOpti }; return mutationOptions; }; export const fileResponseQueryKey = (options: Options) => [ - createQueryKey("fileResponse", options) + createQueryKey('fileResponse', options) ]; export const fileResponseOptions = (options: Options) => { return queryOptions({ @@ -796,7 +796,7 @@ export const fileResponseOptions = (options: Options) => { ret }); }; export const complexTypesQueryKey = (options: Options) => [ - createQueryKey("complexTypes", options) + createQueryKey('complexTypes', options) ]; export const complexTypesOptions = (options: Options) => { return queryOptions({ @@ -812,7 +812,7 @@ export const complexTypesOptions = (options: Options) => { ret }); }; export const multipartRequestQueryKey = (options?: Options) => [ - createQueryKey("multipartRequest", options) + createQueryKey('multipartRequest', options) ]; export const multipartRequestOptions = (options?: Options) => { return queryOptions({ @@ -838,7 +838,7 @@ export const multipartRequestMutation = () => { const mutationOptions: UseMutati }; return mutationOptions; }; export const multipartResponseQueryKey = (options?: Options) => [ - createQueryKey("multipartResponse", options) + createQueryKey('multipartResponse', options) ]; export const multipartResponseOptions = (options?: Options) => { return queryOptions({ @@ -864,7 +864,7 @@ export const complexParamsMutation = () => { const mutationOptions: UseMutationO }; return mutationOptions; }; export const callWithResultFromHeaderQueryKey = (options?: Options) => [ - createQueryKey("callWithResultFromHeader", options) + createQueryKey('callWithResultFromHeader', options) ]; export const callWithResultFromHeaderOptions = (options?: Options) => { return queryOptions({ @@ -890,7 +890,7 @@ export const callWithResultFromHeaderMutation = () => { const mutationOptions: U }; return mutationOptions; }; export const testErrorCodeQueryKey = (options: Options) => [ - createQueryKey("testErrorCode", options) + createQueryKey('testErrorCode', options) ]; export const testErrorCodeOptions = (options: Options) => { return queryOptions({ @@ -916,7 +916,7 @@ export const testErrorCodeMutation = () => { const mutationOptions: UseMutationO }; return mutationOptions; }; export const nonAsciiæøåÆøÅöôêÊ字符串QueryKey = (options: Options) => [ - createQueryKey("nonAsciiæøåÆøÅöôêÊ字符串", options) + createQueryKey('nonAsciiæøåÆøÅöôêÊ字符串', options) ]; export const nonAsciiæøåÆøÅöôêÊ字符串Options = (options: Options) => { return queryOptions({ diff --git a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/react-query/fetch/@tanstack/react-query.gen.ts b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/react-query/fetch/@tanstack/react-query.gen.ts index 52f35325d..2764b821a 100644 --- a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/react-query/fetch/@tanstack/react-query.gen.ts +++ b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/react-query/fetch/@tanstack/react-query.gen.ts @@ -33,7 +33,7 @@ const createQueryKey = (id: string, options?: TOptions }; export const exportQueryKey = (options?: Options) => [ - createQueryKey("export", options) + createQueryKey('export', options) ]; export const exportOptions = (options?: Options) => { return queryOptions({ @@ -49,7 +49,7 @@ export const exportOptions = (options?: Options) => { return queryOptions({ }); }; export const importQueryKey = (options: Options) => [ - createQueryKey("import", options) + createQueryKey('import', options) ]; export const importOptions = (options: Options) => { return queryOptions({ @@ -75,7 +75,7 @@ export const importMutation = () => { const mutationOptions: UseMutationOptions< }; return mutationOptions; }; export const apiVVersionOdataControllerCountQueryKey = (options?: Options) => [ - createQueryKey("apiVVersionOdataControllerCount", options) + createQueryKey('apiVVersionOdataControllerCount', options) ]; export const apiVVersionOdataControllerCountOptions = (options?: Options) => { return queryOptions({ @@ -91,7 +91,7 @@ export const apiVVersionOdataControllerCountOptions = (options?: Options) => { r }); }; export const getApiVbyApiVersionSimpleOperationQueryKey = (options: Options) => [ - createQueryKey("getApiVbyApiVersionSimpleOperation", options) + createQueryKey('getApiVbyApiVersionSimpleOperation', options) ]; export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => { return queryOptions({ @@ -107,7 +107,7 @@ export const getApiVbyApiVersionSimpleOperationOptions = (options: Options [ - createQueryKey("getCallWithoutParametersAndResponse", options) + createQueryKey('getCallWithoutParametersAndResponse', options) ]; export const getCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -133,7 +133,7 @@ export const putCallWithoutParametersAndResponseMutation = () => { const mutatio }; return mutationOptions; }; export const postCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("postCallWithoutParametersAndResponse", options) + createQueryKey('postCallWithoutParametersAndResponse', options) ]; export const postCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -189,7 +189,7 @@ export const deleteFooMutation = () => { const mutationOptions: UseMutationOptio }; return mutationOptions; }; export const callWithDescriptionsQueryKey = (options?: Options) => [ - createQueryKey("callWithDescriptions", options) + createQueryKey('callWithDescriptions', options) ]; export const callWithDescriptionsOptions = (options?: Options) => { return queryOptions({ @@ -215,7 +215,7 @@ export const callWithDescriptionsMutation = () => { const mutationOptions: UseMu }; return mutationOptions; }; export const deprecatedCallQueryKey = (options: Options) => [ - createQueryKey("deprecatedCall", options) + createQueryKey('deprecatedCall', options) ]; export const deprecatedCallOptions = (options: Options) => { return queryOptions({ @@ -241,7 +241,7 @@ export const deprecatedCallMutation = () => { const mutationOptions: UseMutation }; return mutationOptions; }; export const callWithParametersQueryKey = (options: Options) => [ - createQueryKey("callWithParameters", options) + createQueryKey('callWithParameters', options) ]; export const callWithParametersOptions = (options: Options) => { return queryOptions({ @@ -286,7 +286,7 @@ const createInfiniteParams = [0], 'body' | 'hea }; export const callWithParametersInfiniteQueryKey = (options: Options): QueryKey> => [ - createQueryKey("callWithParameters", options, true) + createQueryKey('callWithParameters', options, true) ]; export const callWithParametersInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, string | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -294,7 +294,7 @@ export const callWithParametersInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { cursor: pageParam } @@ -321,7 +321,7 @@ export const callWithParametersMutation = () => { const mutationOptions: UseMuta }; return mutationOptions; }; export const callWithWeirdParameterNamesQueryKey = (options: Options) => [ - createQueryKey("callWithWeirdParameterNames", options) + createQueryKey('callWithWeirdParameterNames', options) ]; export const callWithWeirdParameterNamesOptions = (options: Options) => { return queryOptions({ @@ -347,7 +347,7 @@ export const callWithWeirdParameterNamesMutation = () => { const mutationOptions }; return mutationOptions; }; export const getCallWithOptionalParamQueryKey = (options: Options) => [ - createQueryKey("getCallWithOptionalParam", options) + createQueryKey('getCallWithOptionalParam', options) ]; export const getCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -363,7 +363,7 @@ export const getCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("getCallWithOptionalParam", options, true) + createQueryKey('getCallWithOptionalParam', options, true) ]; export const getCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -371,7 +371,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { page: pageParam } @@ -388,7 +388,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options) => [ - createQueryKey("postCallWithOptionalParam", options) + createQueryKey('postCallWithOptionalParam', options) ]; export const postCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -404,7 +404,7 @@ export const postCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("postCallWithOptionalParam", options, true) + createQueryKey('postCallWithOptionalParam', options, true) ]; export const postCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -412,7 +412,7 @@ export const postCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { body: { offset: pageParam } @@ -439,7 +439,7 @@ export const postCallWithOptionalParamMutation = () => { const mutationOptions: }; return mutationOptions; }; export const postApiVbyApiVersionRequestBodyQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionRequestBody", options) + createQueryKey('postApiVbyApiVersionRequestBody', options) ]; export const postApiVbyApiVersionRequestBodyOptions = (options?: Options) => { return queryOptions({ @@ -465,7 +465,7 @@ export const postApiVbyApiVersionRequestBodyMutation = () => { const mutationOpt }; return mutationOptions; }; export const postApiVbyApiVersionFormDataQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionFormData", options) + createQueryKey('postApiVbyApiVersionFormData', options) ]; export const postApiVbyApiVersionFormDataOptions = (options?: Options) => { return queryOptions({ @@ -491,7 +491,7 @@ export const postApiVbyApiVersionFormDataMutation = () => { const mutationOption }; return mutationOptions; }; export const callWithDefaultParametersQueryKey = (options?: Options) => [ - createQueryKey("callWithDefaultParameters", options) + createQueryKey('callWithDefaultParameters', options) ]; export const callWithDefaultParametersOptions = (options?: Options) => { return queryOptions({ @@ -507,7 +507,7 @@ export const callWithDefaultParametersOptions = (options?: Options) => [ - createQueryKey("callWithDefaultOptionalParameters", options) + createQueryKey('callWithDefaultOptionalParameters', options) ]; export const callWithDefaultOptionalParametersOptions = (options?: Options) => { return queryOptions({ @@ -543,7 +543,7 @@ export const callToTestOrderOfParamsMutation = () => { const mutationOptions: Us }; return mutationOptions; }; export const duplicateNameQueryKey = (options?: Options) => [ - createQueryKey("duplicateName", options) + createQueryKey('duplicateName', options) ]; export const duplicateNameOptions = (options?: Options) => { return queryOptions({ @@ -559,7 +559,7 @@ export const duplicateNameOptions = (options?: Options) => { return queryOptions }); }; export const duplicateName1QueryKey = (options?: Options) => [ - createQueryKey("duplicateName1", options) + createQueryKey('duplicateName1', options) ]; export const duplicateName1Options = (options?: Options) => { return queryOptions({ @@ -605,7 +605,7 @@ export const duplicateName3Mutation = () => { const mutationOptions: UseMutation }; return mutationOptions; }; export const callWithNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithNoContentResponse", options) + createQueryKey('callWithNoContentResponse', options) ]; export const callWithNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -621,7 +621,7 @@ export const callWithNoContentResponseOptions = (options?: Options) => { return }); }; export const callWithResponseAndNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponseAndNoContentResponse", options) + createQueryKey('callWithResponseAndNoContentResponse', options) ]; export const callWithResponseAndNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -637,7 +637,7 @@ export const callWithResponseAndNoContentResponseOptions = (options?: Options) = }); }; export const dummyAQueryKey = (options?: Options) => [ - createQueryKey("dummyA", options) + createQueryKey('dummyA', options) ]; export const dummyAOptions = (options?: Options) => { return queryOptions({ @@ -653,7 +653,7 @@ export const dummyAOptions = (options?: Options) => { return queryOptions({ }); }; export const dummyBQueryKey = (options?: Options) => [ - createQueryKey("dummyB", options) + createQueryKey('dummyB', options) ]; export const dummyBOptions = (options?: Options) => { return queryOptions({ @@ -669,7 +669,7 @@ export const dummyBOptions = (options?: Options) => { return queryOptions({ }); }; export const callWithResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponse", options) + createQueryKey('callWithResponse', options) ]; export const callWithResponseOptions = (options?: Options) => { return queryOptions({ @@ -685,7 +685,7 @@ export const callWithResponseOptions = (options?: Options) => { return queryOpti }); }; export const callWithDuplicateResponsesQueryKey = (options?: Options) => [ - createQueryKey("callWithDuplicateResponses", options) + createQueryKey('callWithDuplicateResponses', options) ]; export const callWithDuplicateResponsesOptions = (options?: Options) => { return queryOptions({ @@ -721,7 +721,7 @@ export const callWithResponsesMutation = () => { const mutationOptions: UseMutat }; return mutationOptions; }; export const collectionFormatQueryKey = (options: Options) => [ - createQueryKey("collectionFormat", options) + createQueryKey('collectionFormat', options) ]; export const collectionFormatOptions = (options: Options) => { return queryOptions({ @@ -737,7 +737,7 @@ export const collectionFormatOptions = (options: Options) }); }; export const typesQueryKey = (options: Options) => [ - createQueryKey("types", options) + createQueryKey('types', options) ]; export const typesOptions = (options: Options) => { return queryOptions({ @@ -753,7 +753,7 @@ export const typesOptions = (options: Options) => { return queryOptio }); }; export const uploadFileQueryKey = (options: Options) => [ - createQueryKey("uploadFile", options) + createQueryKey('uploadFile', options) ]; export const uploadFileOptions = (options: Options) => { return queryOptions({ @@ -779,7 +779,7 @@ export const uploadFileMutation = () => { const mutationOptions: UseMutationOpti }; return mutationOptions; }; export const fileResponseQueryKey = (options: Options) => [ - createQueryKey("fileResponse", options) + createQueryKey('fileResponse', options) ]; export const fileResponseOptions = (options: Options) => { return queryOptions({ @@ -795,7 +795,7 @@ export const fileResponseOptions = (options: Options) => { ret }); }; export const complexTypesQueryKey = (options: Options) => [ - createQueryKey("complexTypes", options) + createQueryKey('complexTypes', options) ]; export const complexTypesOptions = (options: Options) => { return queryOptions({ @@ -811,7 +811,7 @@ export const complexTypesOptions = (options: Options) => { ret }); }; export const multipartRequestQueryKey = (options?: Options) => [ - createQueryKey("multipartRequest", options) + createQueryKey('multipartRequest', options) ]; export const multipartRequestOptions = (options?: Options) => { return queryOptions({ @@ -837,7 +837,7 @@ export const multipartRequestMutation = () => { const mutationOptions: UseMutati }; return mutationOptions; }; export const multipartResponseQueryKey = (options?: Options) => [ - createQueryKey("multipartResponse", options) + createQueryKey('multipartResponse', options) ]; export const multipartResponseOptions = (options?: Options) => { return queryOptions({ @@ -863,7 +863,7 @@ export const complexParamsMutation = () => { const mutationOptions: UseMutationO }; return mutationOptions; }; export const callWithResultFromHeaderQueryKey = (options?: Options) => [ - createQueryKey("callWithResultFromHeader", options) + createQueryKey('callWithResultFromHeader', options) ]; export const callWithResultFromHeaderOptions = (options?: Options) => { return queryOptions({ @@ -889,7 +889,7 @@ export const callWithResultFromHeaderMutation = () => { const mutationOptions: U }; return mutationOptions; }; export const testErrorCodeQueryKey = (options: Options) => [ - createQueryKey("testErrorCode", options) + createQueryKey('testErrorCode', options) ]; export const testErrorCodeOptions = (options: Options) => { return queryOptions({ @@ -915,7 +915,7 @@ export const testErrorCodeMutation = () => { const mutationOptions: UseMutationO }; return mutationOptions; }; export const nonAsciiæøåÆøÅöôêÊ字符串QueryKey = (options: Options) => [ - createQueryKey("nonAsciiæøåÆøÅöôêÊ字符串", options) + createQueryKey('nonAsciiæøåÆøÅöôêÊ字符串', options) ]; export const nonAsciiæøåÆøÅöôêÊ字符串Options = (options: Options) => { return queryOptions({ diff --git a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/solid-query/asClass/@tanstack/solid-query.gen.ts b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/solid-query/asClass/@tanstack/solid-query.gen.ts index 9bcba823a..1bb01abab 100644 --- a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/solid-query/asClass/@tanstack/solid-query.gen.ts +++ b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/solid-query/asClass/@tanstack/solid-query.gen.ts @@ -33,7 +33,7 @@ const createQueryKey = (id: string, options?: TOptions }; export const collectionFormatQueryKey = (options: Options) => [ - createQueryKey("collectionFormat", options) + createQueryKey('collectionFormat', options) ]; export const collectionFormatOptions = (options: Options) => { return queryOptions({ @@ -49,7 +49,7 @@ export const collectionFormatOptions = (options: Options) }); }; export const complexTypesQueryKey = (options: Options) => [ - createQueryKey("complexTypes", options) + createQueryKey('complexTypes', options) ]; export const complexTypesOptions = (options: Options) => { return queryOptions({ @@ -75,7 +75,7 @@ export const complexParamsMutation = () => { const mutationOptions: MutationOpti }; return mutationOptions; }; export const exportQueryKey = (options?: Options) => [ - createQueryKey("export", options) + createQueryKey('export', options) ]; export const exportOptions = (options?: Options) => { return queryOptions({ @@ -91,7 +91,7 @@ export const exportOptions = (options?: Options) => { return queryOptions({ }); }; export const importQueryKey = (options: Options) => [ - createQueryKey("import", options) + createQueryKey('import', options) ]; export const importOptions = (options: Options) => { return queryOptions({ @@ -117,7 +117,7 @@ export const importMutation = () => { const mutationOptions: MutationOptions) => [ - createQueryKey("getApiVbyApiVersionSimpleOperation", options) + createQueryKey('getApiVbyApiVersionSimpleOperation', options) ]; export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => { return queryOptions({ @@ -133,7 +133,7 @@ export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => [ - createQueryKey("callWithDefaultParameters", options) + createQueryKey('callWithDefaultParameters', options) ]; export const callWithDefaultParametersOptions = (options?: Options) => { return queryOptions({ @@ -149,7 +149,7 @@ export const callWithDefaultParametersOptions = (options?: Options) => [ - createQueryKey("callWithDefaultOptionalParameters", options) + createQueryKey('callWithDefaultOptionalParameters', options) ]; export const callWithDefaultOptionalParametersOptions = (options?: Options) => { return queryOptions({ @@ -185,7 +185,7 @@ export const callToTestOrderOfParamsMutation = () => { const mutationOptions: Mu }; return mutationOptions; }; export const deprecatedCallQueryKey = (options: Options) => [ - createQueryKey("deprecatedCall", options) + createQueryKey('deprecatedCall', options) ]; export const deprecatedCallOptions = (options: Options) => { return queryOptions({ @@ -211,7 +211,7 @@ export const deprecatedCallMutation = () => { const mutationOptions: MutationOpt }; return mutationOptions; }; export const callWithDescriptionsQueryKey = (options?: Options) => [ - createQueryKey("callWithDescriptions", options) + createQueryKey('callWithDescriptions', options) ]; export const callWithDescriptionsOptions = (options?: Options) => { return queryOptions({ @@ -237,7 +237,7 @@ export const callWithDescriptionsMutation = () => { const mutationOptions: Mutat }; return mutationOptions; }; export const duplicateNameQueryKey = (options?: Options) => [ - createQueryKey("duplicateName", options) + createQueryKey('duplicateName', options) ]; export const duplicateNameOptions = (options?: Options) => { return queryOptions({ @@ -253,7 +253,7 @@ export const duplicateNameOptions = (options?: Options) => { return queryOptions }); }; export const duplicateName1QueryKey = (options?: Options) => [ - createQueryKey("duplicateName1", options) + createQueryKey('duplicateName1', options) ]; export const duplicateName1Options = (options?: Options) => { return queryOptions({ @@ -299,7 +299,7 @@ export const duplicateName3Mutation = () => { const mutationOptions: MutationOpt }; return mutationOptions; }; export const testErrorCodeQueryKey = (options: Options) => [ - createQueryKey("testErrorCode", options) + createQueryKey('testErrorCode', options) ]; export const testErrorCodeOptions = (options: Options) => { return queryOptions({ @@ -325,7 +325,7 @@ export const testErrorCodeMutation = () => { const mutationOptions: MutationOpti }; return mutationOptions; }; export const fileResponseQueryKey = (options: Options) => [ - createQueryKey("fileResponse", options) + createQueryKey('fileResponse', options) ]; export const fileResponseOptions = (options: Options) => { return queryOptions({ @@ -341,7 +341,7 @@ export const fileResponseOptions = (options: Options) => { ret }); }; export const postApiVbyApiVersionFormDataQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionFormData", options) + createQueryKey('postApiVbyApiVersionFormData', options) ]; export const postApiVbyApiVersionFormDataOptions = (options?: Options) => { return queryOptions({ @@ -367,7 +367,7 @@ export const postApiVbyApiVersionFormDataMutation = () => { const mutationOption }; return mutationOptions; }; export const callWithResultFromHeaderQueryKey = (options?: Options) => [ - createQueryKey("callWithResultFromHeader", options) + createQueryKey('callWithResultFromHeader', options) ]; export const callWithResultFromHeaderOptions = (options?: Options) => { return queryOptions({ @@ -393,7 +393,7 @@ export const callWithResultFromHeaderMutation = () => { const mutationOptions: M }; return mutationOptions; }; export const multipartRequestQueryKey = (options?: Options) => [ - createQueryKey("multipartRequest", options) + createQueryKey('multipartRequest', options) ]; export const multipartRequestOptions = (options?: Options) => { return queryOptions({ @@ -419,7 +419,7 @@ export const multipartRequestMutation = () => { const mutationOptions: MutationO }; return mutationOptions; }; export const multipartResponseQueryKey = (options?: Options) => [ - createQueryKey("multipartResponse", options) + createQueryKey('multipartResponse', options) ]; export const multipartResponseOptions = (options?: Options) => { return queryOptions({ @@ -435,7 +435,7 @@ export const multipartResponseOptions = (options?: Options) => { return queryOpt }); }; export const dummyAQueryKey = (options?: Options) => [ - createQueryKey("dummyA", options) + createQueryKey('dummyA', options) ]; export const dummyAOptions = (options?: Options) => { return queryOptions({ @@ -451,7 +451,7 @@ export const dummyAOptions = (options?: Options) => { return queryOptions({ }); }; export const dummyBQueryKey = (options?: Options) => [ - createQueryKey("dummyB", options) + createQueryKey('dummyB', options) ]; export const dummyBOptions = (options?: Options) => { return queryOptions({ @@ -467,7 +467,7 @@ export const dummyBOptions = (options?: Options) => { return queryOptions({ }); }; export const callWithNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithNoContentResponse", options) + createQueryKey('callWithNoContentResponse', options) ]; export const callWithNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -483,7 +483,7 @@ export const callWithNoContentResponseOptions = (options?: Options) => { return }); }; export const callWithResponseAndNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponseAndNoContentResponse", options) + createQueryKey('callWithResponseAndNoContentResponse', options) ]; export const callWithResponseAndNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -499,7 +499,7 @@ export const callWithResponseAndNoContentResponseOptions = (options?: Options) = }); }; export const nonAsciiæøåÆøÅöôêÊ字符串QueryKey = (options: Options) => [ - createQueryKey("nonAsciiæøåÆøÅöôêÊ字符串", options) + createQueryKey('nonAsciiæøåÆøÅöôêÊ字符串', options) ]; export const nonAsciiæøåÆøÅöôêÊ字符串Options = (options: Options) => { return queryOptions({ @@ -545,7 +545,7 @@ export const deleteFooMutation = () => { const mutationOptions: MutationOptions< }; return mutationOptions; }; export const callWithParametersQueryKey = (options: Options) => [ - createQueryKey("callWithParameters", options) + createQueryKey('callWithParameters', options) ]; export const callWithParametersOptions = (options: Options) => { return queryOptions({ @@ -590,7 +590,7 @@ const createInfiniteParams = [0], 'body' | 'hea }; export const callWithParametersInfiniteQueryKey = (options: Options): QueryKey> => [ - createQueryKey("callWithParameters", options, true) + createQueryKey('callWithParameters', options, true) ]; export const callWithParametersInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, string | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -598,7 +598,7 @@ export const callWithParametersInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { cursor: pageParam } @@ -625,7 +625,7 @@ export const callWithParametersMutation = () => { const mutationOptions: Mutatio }; return mutationOptions; }; export const callWithWeirdParameterNamesQueryKey = (options: Options) => [ - createQueryKey("callWithWeirdParameterNames", options) + createQueryKey('callWithWeirdParameterNames', options) ]; export const callWithWeirdParameterNamesOptions = (options: Options) => { return queryOptions({ @@ -651,7 +651,7 @@ export const callWithWeirdParameterNamesMutation = () => { const mutationOptions }; return mutationOptions; }; export const getCallWithOptionalParamQueryKey = (options: Options) => [ - createQueryKey("getCallWithOptionalParam", options) + createQueryKey('getCallWithOptionalParam', options) ]; export const getCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -667,7 +667,7 @@ export const getCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("getCallWithOptionalParam", options, true) + createQueryKey('getCallWithOptionalParam', options, true) ]; export const getCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -675,7 +675,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { page: pageParam } @@ -692,7 +692,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options) => [ - createQueryKey("postCallWithOptionalParam", options) + createQueryKey('postCallWithOptionalParam', options) ]; export const postCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -708,7 +708,7 @@ export const postCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("postCallWithOptionalParam", options, true) + createQueryKey('postCallWithOptionalParam', options, true) ]; export const postCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -716,7 +716,7 @@ export const postCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { body: { offset: pageParam } @@ -743,7 +743,7 @@ export const postCallWithOptionalParamMutation = () => { const mutationOptions: }; return mutationOptions; }; export const postApiVbyApiVersionRequestBodyQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionRequestBody", options) + createQueryKey('postApiVbyApiVersionRequestBody', options) ]; export const postApiVbyApiVersionRequestBodyOptions = (options?: Options) => { return queryOptions({ @@ -769,7 +769,7 @@ export const postApiVbyApiVersionRequestBodyMutation = () => { const mutationOpt }; return mutationOptions; }; export const callWithResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponse", options) + createQueryKey('callWithResponse', options) ]; export const callWithResponseOptions = (options?: Options) => { return queryOptions({ @@ -785,7 +785,7 @@ export const callWithResponseOptions = (options?: Options) => { return queryOpti }); }; export const callWithDuplicateResponsesQueryKey = (options?: Options) => [ - createQueryKey("callWithDuplicateResponses", options) + createQueryKey('callWithDuplicateResponses', options) ]; export const callWithDuplicateResponsesOptions = (options?: Options) => { return queryOptions({ @@ -821,7 +821,7 @@ export const callWithResponsesMutation = () => { const mutationOptions: Mutation }; return mutationOptions; }; export const apiVVersionOdataControllerCountQueryKey = (options?: Options) => [ - createQueryKey("apiVVersionOdataControllerCount", options) + createQueryKey('apiVVersionOdataControllerCount', options) ]; export const apiVVersionOdataControllerCountOptions = (options?: Options) => { return queryOptions({ @@ -837,7 +837,7 @@ export const apiVVersionOdataControllerCountOptions = (options?: Options) => { r }); }; export const getCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("getCallWithoutParametersAndResponse", options) + createQueryKey('getCallWithoutParametersAndResponse', options) ]; export const getCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -863,7 +863,7 @@ export const putCallWithoutParametersAndResponseMutation = () => { const mutatio }; return mutationOptions; }; export const postCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("postCallWithoutParametersAndResponse", options) + createQueryKey('postCallWithoutParametersAndResponse', options) ]; export const postCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -909,7 +909,7 @@ export const patchCallWithoutParametersAndResponseMutation = () => { const mutat }; return mutationOptions; }; export const typesQueryKey = (options: Options) => [ - createQueryKey("types", options) + createQueryKey('types', options) ]; export const typesOptions = (options: Options) => { return queryOptions({ @@ -925,7 +925,7 @@ export const typesOptions = (options: Options) => { return queryOptio }); }; export const uploadFileQueryKey = (options: Options) => [ - createQueryKey("uploadFile", options) + createQueryKey('uploadFile', options) ]; export const uploadFileOptions = (options: Options) => { return queryOptions({ diff --git a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/solid-query/axios/@tanstack/solid-query.gen.ts b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/solid-query/axios/@tanstack/solid-query.gen.ts index e9a4a7263..ba45e2cc5 100644 --- a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/solid-query/axios/@tanstack/solid-query.gen.ts +++ b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/solid-query/axios/@tanstack/solid-query.gen.ts @@ -34,7 +34,7 @@ const createQueryKey = (id: string, options?: TOptions }; export const exportQueryKey = (options?: Options) => [ - createQueryKey("export", options) + createQueryKey('export', options) ]; export const exportOptions = (options?: Options) => { return queryOptions({ @@ -50,7 +50,7 @@ export const exportOptions = (options?: Options) => { return queryOptions({ }); }; export const importQueryKey = (options: Options) => [ - createQueryKey("import", options) + createQueryKey('import', options) ]; export const importOptions = (options: Options) => { return queryOptions({ @@ -76,7 +76,7 @@ export const importMutation = () => { const mutationOptions: MutationOptions [ - createQueryKey("apiVVersionOdataControllerCount", options) + createQueryKey('apiVVersionOdataControllerCount', options) ]; export const apiVVersionOdataControllerCountOptions = (options?: Options) => { return queryOptions({ @@ -92,7 +92,7 @@ export const apiVVersionOdataControllerCountOptions = (options?: Options) => { r }); }; export const getApiVbyApiVersionSimpleOperationQueryKey = (options: Options) => [ - createQueryKey("getApiVbyApiVersionSimpleOperation", options) + createQueryKey('getApiVbyApiVersionSimpleOperation', options) ]; export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => { return queryOptions({ @@ -108,7 +108,7 @@ export const getApiVbyApiVersionSimpleOperationOptions = (options: Options [ - createQueryKey("getCallWithoutParametersAndResponse", options) + createQueryKey('getCallWithoutParametersAndResponse', options) ]; export const getCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -134,7 +134,7 @@ export const putCallWithoutParametersAndResponseMutation = () => { const mutatio }; return mutationOptions; }; export const postCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("postCallWithoutParametersAndResponse", options) + createQueryKey('postCallWithoutParametersAndResponse', options) ]; export const postCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -190,7 +190,7 @@ export const deleteFooMutation = () => { const mutationOptions: MutationOptions< }; return mutationOptions; }; export const callWithDescriptionsQueryKey = (options?: Options) => [ - createQueryKey("callWithDescriptions", options) + createQueryKey('callWithDescriptions', options) ]; export const callWithDescriptionsOptions = (options?: Options) => { return queryOptions({ @@ -216,7 +216,7 @@ export const callWithDescriptionsMutation = () => { const mutationOptions: Mutat }; return mutationOptions; }; export const deprecatedCallQueryKey = (options: Options) => [ - createQueryKey("deprecatedCall", options) + createQueryKey('deprecatedCall', options) ]; export const deprecatedCallOptions = (options: Options) => { return queryOptions({ @@ -242,7 +242,7 @@ export const deprecatedCallMutation = () => { const mutationOptions: MutationOpt }; return mutationOptions; }; export const callWithParametersQueryKey = (options: Options) => [ - createQueryKey("callWithParameters", options) + createQueryKey('callWithParameters', options) ]; export const callWithParametersOptions = (options: Options) => { return queryOptions({ @@ -287,7 +287,7 @@ const createInfiniteParams = [0], 'body' | 'hea }; export const callWithParametersInfiniteQueryKey = (options: Options): QueryKey> => [ - createQueryKey("callWithParameters", options, true) + createQueryKey('callWithParameters', options, true) ]; export const callWithParametersInfiniteOptions = (options: Options) => { return infiniteQueryOptions, InfiniteData, QueryKey>, string | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -295,7 +295,7 @@ export const callWithParametersInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { cursor: pageParam } @@ -322,7 +322,7 @@ export const callWithParametersMutation = () => { const mutationOptions: Mutatio }; return mutationOptions; }; export const callWithWeirdParameterNamesQueryKey = (options: Options) => [ - createQueryKey("callWithWeirdParameterNames", options) + createQueryKey('callWithWeirdParameterNames', options) ]; export const callWithWeirdParameterNamesOptions = (options: Options) => { return queryOptions({ @@ -348,7 +348,7 @@ export const callWithWeirdParameterNamesMutation = () => { const mutationOptions }; return mutationOptions; }; export const getCallWithOptionalParamQueryKey = (options: Options) => [ - createQueryKey("getCallWithOptionalParam", options) + createQueryKey('getCallWithOptionalParam', options) ]; export const getCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -364,7 +364,7 @@ export const getCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("getCallWithOptionalParam", options, true) + createQueryKey('getCallWithOptionalParam', options, true) ]; export const getCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, InfiniteData, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -372,7 +372,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { page: pageParam } @@ -389,7 +389,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options) => [ - createQueryKey("postCallWithOptionalParam", options) + createQueryKey('postCallWithOptionalParam', options) ]; export const postCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -405,7 +405,7 @@ export const postCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("postCallWithOptionalParam", options, true) + createQueryKey('postCallWithOptionalParam', options, true) ]; export const postCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, InfiniteData, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -413,7 +413,7 @@ export const postCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { body: { offset: pageParam } @@ -440,7 +440,7 @@ export const postCallWithOptionalParamMutation = () => { const mutationOptions: }; return mutationOptions; }; export const postApiVbyApiVersionRequestBodyQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionRequestBody", options) + createQueryKey('postApiVbyApiVersionRequestBody', options) ]; export const postApiVbyApiVersionRequestBodyOptions = (options?: Options) => { return queryOptions({ @@ -466,7 +466,7 @@ export const postApiVbyApiVersionRequestBodyMutation = () => { const mutationOpt }; return mutationOptions; }; export const postApiVbyApiVersionFormDataQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionFormData", options) + createQueryKey('postApiVbyApiVersionFormData', options) ]; export const postApiVbyApiVersionFormDataOptions = (options?: Options) => { return queryOptions({ @@ -492,7 +492,7 @@ export const postApiVbyApiVersionFormDataMutation = () => { const mutationOption }; return mutationOptions; }; export const callWithDefaultParametersQueryKey = (options?: Options) => [ - createQueryKey("callWithDefaultParameters", options) + createQueryKey('callWithDefaultParameters', options) ]; export const callWithDefaultParametersOptions = (options?: Options) => { return queryOptions({ @@ -508,7 +508,7 @@ export const callWithDefaultParametersOptions = (options?: Options) => [ - createQueryKey("callWithDefaultOptionalParameters", options) + createQueryKey('callWithDefaultOptionalParameters', options) ]; export const callWithDefaultOptionalParametersOptions = (options?: Options) => { return queryOptions({ @@ -544,7 +544,7 @@ export const callToTestOrderOfParamsMutation = () => { const mutationOptions: Mu }; return mutationOptions; }; export const duplicateNameQueryKey = (options?: Options) => [ - createQueryKey("duplicateName", options) + createQueryKey('duplicateName', options) ]; export const duplicateNameOptions = (options?: Options) => { return queryOptions({ @@ -560,7 +560,7 @@ export const duplicateNameOptions = (options?: Options) => { return queryOptions }); }; export const duplicateName1QueryKey = (options?: Options) => [ - createQueryKey("duplicateName1", options) + createQueryKey('duplicateName1', options) ]; export const duplicateName1Options = (options?: Options) => { return queryOptions({ @@ -606,7 +606,7 @@ export const duplicateName3Mutation = () => { const mutationOptions: MutationOpt }; return mutationOptions; }; export const callWithNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithNoContentResponse", options) + createQueryKey('callWithNoContentResponse', options) ]; export const callWithNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -622,7 +622,7 @@ export const callWithNoContentResponseOptions = (options?: Options) => { return }); }; export const callWithResponseAndNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponseAndNoContentResponse", options) + createQueryKey('callWithResponseAndNoContentResponse', options) ]; export const callWithResponseAndNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -638,7 +638,7 @@ export const callWithResponseAndNoContentResponseOptions = (options?: Options) = }); }; export const dummyAQueryKey = (options?: Options) => [ - createQueryKey("dummyA", options) + createQueryKey('dummyA', options) ]; export const dummyAOptions = (options?: Options) => { return queryOptions({ @@ -654,7 +654,7 @@ export const dummyAOptions = (options?: Options) => { return queryOptions({ }); }; export const dummyBQueryKey = (options?: Options) => [ - createQueryKey("dummyB", options) + createQueryKey('dummyB', options) ]; export const dummyBOptions = (options?: Options) => { return queryOptions({ @@ -670,7 +670,7 @@ export const dummyBOptions = (options?: Options) => { return queryOptions({ }); }; export const callWithResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponse", options) + createQueryKey('callWithResponse', options) ]; export const callWithResponseOptions = (options?: Options) => { return queryOptions({ @@ -686,7 +686,7 @@ export const callWithResponseOptions = (options?: Options) => { return queryOpti }); }; export const callWithDuplicateResponsesQueryKey = (options?: Options) => [ - createQueryKey("callWithDuplicateResponses", options) + createQueryKey('callWithDuplicateResponses', options) ]; export const callWithDuplicateResponsesOptions = (options?: Options) => { return queryOptions({ @@ -722,7 +722,7 @@ export const callWithResponsesMutation = () => { const mutationOptions: Mutation }; return mutationOptions; }; export const collectionFormatQueryKey = (options: Options) => [ - createQueryKey("collectionFormat", options) + createQueryKey('collectionFormat', options) ]; export const collectionFormatOptions = (options: Options) => { return queryOptions({ @@ -738,7 +738,7 @@ export const collectionFormatOptions = (options: Options) }); }; export const typesQueryKey = (options: Options) => [ - createQueryKey("types", options) + createQueryKey('types', options) ]; export const typesOptions = (options: Options) => { return queryOptions({ @@ -754,7 +754,7 @@ export const typesOptions = (options: Options) => { return queryOptio }); }; export const uploadFileQueryKey = (options: Options) => [ - createQueryKey("uploadFile", options) + createQueryKey('uploadFile', options) ]; export const uploadFileOptions = (options: Options) => { return queryOptions({ @@ -780,7 +780,7 @@ export const uploadFileMutation = () => { const mutationOptions: MutationOptions }; return mutationOptions; }; export const fileResponseQueryKey = (options: Options) => [ - createQueryKey("fileResponse", options) + createQueryKey('fileResponse', options) ]; export const fileResponseOptions = (options: Options) => { return queryOptions({ @@ -796,7 +796,7 @@ export const fileResponseOptions = (options: Options) => { ret }); }; export const complexTypesQueryKey = (options: Options) => [ - createQueryKey("complexTypes", options) + createQueryKey('complexTypes', options) ]; export const complexTypesOptions = (options: Options) => { return queryOptions({ @@ -812,7 +812,7 @@ export const complexTypesOptions = (options: Options) => { ret }); }; export const multipartRequestQueryKey = (options?: Options) => [ - createQueryKey("multipartRequest", options) + createQueryKey('multipartRequest', options) ]; export const multipartRequestOptions = (options?: Options) => { return queryOptions({ @@ -838,7 +838,7 @@ export const multipartRequestMutation = () => { const mutationOptions: MutationO }; return mutationOptions; }; export const multipartResponseQueryKey = (options?: Options) => [ - createQueryKey("multipartResponse", options) + createQueryKey('multipartResponse', options) ]; export const multipartResponseOptions = (options?: Options) => { return queryOptions({ @@ -864,7 +864,7 @@ export const complexParamsMutation = () => { const mutationOptions: MutationOpti }; return mutationOptions; }; export const callWithResultFromHeaderQueryKey = (options?: Options) => [ - createQueryKey("callWithResultFromHeader", options) + createQueryKey('callWithResultFromHeader', options) ]; export const callWithResultFromHeaderOptions = (options?: Options) => { return queryOptions({ @@ -890,7 +890,7 @@ export const callWithResultFromHeaderMutation = () => { const mutationOptions: M }; return mutationOptions; }; export const testErrorCodeQueryKey = (options: Options) => [ - createQueryKey("testErrorCode", options) + createQueryKey('testErrorCode', options) ]; export const testErrorCodeOptions = (options: Options) => { return queryOptions({ @@ -916,7 +916,7 @@ export const testErrorCodeMutation = () => { const mutationOptions: MutationOpti }; return mutationOptions; }; export const nonAsciiæøåÆøÅöôêÊ字符串QueryKey = (options: Options) => [ - createQueryKey("nonAsciiæøåÆøÅöôêÊ字符串", options) + createQueryKey('nonAsciiæøåÆøÅöôêÊ字符串', options) ]; export const nonAsciiæøåÆøÅöôêÊ字符串Options = (options: Options) => { return queryOptions({ diff --git a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/solid-query/fetch/@tanstack/solid-query.gen.ts b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/solid-query/fetch/@tanstack/solid-query.gen.ts index f21725166..239e18d06 100644 --- a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/solid-query/fetch/@tanstack/solid-query.gen.ts +++ b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/solid-query/fetch/@tanstack/solid-query.gen.ts @@ -33,7 +33,7 @@ const createQueryKey = (id: string, options?: TOptions }; export const exportQueryKey = (options?: Options) => [ - createQueryKey("export", options) + createQueryKey('export', options) ]; export const exportOptions = (options?: Options) => { return queryOptions({ @@ -49,7 +49,7 @@ export const exportOptions = (options?: Options) => { return queryOptions({ }); }; export const importQueryKey = (options: Options) => [ - createQueryKey("import", options) + createQueryKey('import', options) ]; export const importOptions = (options: Options) => { return queryOptions({ @@ -75,7 +75,7 @@ export const importMutation = () => { const mutationOptions: MutationOptions [ - createQueryKey("apiVVersionOdataControllerCount", options) + createQueryKey('apiVVersionOdataControllerCount', options) ]; export const apiVVersionOdataControllerCountOptions = (options?: Options) => { return queryOptions({ @@ -91,7 +91,7 @@ export const apiVVersionOdataControllerCountOptions = (options?: Options) => { r }); }; export const getApiVbyApiVersionSimpleOperationQueryKey = (options: Options) => [ - createQueryKey("getApiVbyApiVersionSimpleOperation", options) + createQueryKey('getApiVbyApiVersionSimpleOperation', options) ]; export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => { return queryOptions({ @@ -107,7 +107,7 @@ export const getApiVbyApiVersionSimpleOperationOptions = (options: Options [ - createQueryKey("getCallWithoutParametersAndResponse", options) + createQueryKey('getCallWithoutParametersAndResponse', options) ]; export const getCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -133,7 +133,7 @@ export const putCallWithoutParametersAndResponseMutation = () => { const mutatio }; return mutationOptions; }; export const postCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("postCallWithoutParametersAndResponse", options) + createQueryKey('postCallWithoutParametersAndResponse', options) ]; export const postCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -189,7 +189,7 @@ export const deleteFooMutation = () => { const mutationOptions: MutationOptions< }; return mutationOptions; }; export const callWithDescriptionsQueryKey = (options?: Options) => [ - createQueryKey("callWithDescriptions", options) + createQueryKey('callWithDescriptions', options) ]; export const callWithDescriptionsOptions = (options?: Options) => { return queryOptions({ @@ -215,7 +215,7 @@ export const callWithDescriptionsMutation = () => { const mutationOptions: Mutat }; return mutationOptions; }; export const deprecatedCallQueryKey = (options: Options) => [ - createQueryKey("deprecatedCall", options) + createQueryKey('deprecatedCall', options) ]; export const deprecatedCallOptions = (options: Options) => { return queryOptions({ @@ -241,7 +241,7 @@ export const deprecatedCallMutation = () => { const mutationOptions: MutationOpt }; return mutationOptions; }; export const callWithParametersQueryKey = (options: Options) => [ - createQueryKey("callWithParameters", options) + createQueryKey('callWithParameters', options) ]; export const callWithParametersOptions = (options: Options) => { return queryOptions({ @@ -286,7 +286,7 @@ const createInfiniteParams = [0], 'body' | 'hea }; export const callWithParametersInfiniteQueryKey = (options: Options): QueryKey> => [ - createQueryKey("callWithParameters", options, true) + createQueryKey('callWithParameters', options, true) ]; export const callWithParametersInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, string | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -294,7 +294,7 @@ export const callWithParametersInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { cursor: pageParam } @@ -321,7 +321,7 @@ export const callWithParametersMutation = () => { const mutationOptions: Mutatio }; return mutationOptions; }; export const callWithWeirdParameterNamesQueryKey = (options: Options) => [ - createQueryKey("callWithWeirdParameterNames", options) + createQueryKey('callWithWeirdParameterNames', options) ]; export const callWithWeirdParameterNamesOptions = (options: Options) => { return queryOptions({ @@ -347,7 +347,7 @@ export const callWithWeirdParameterNamesMutation = () => { const mutationOptions }; return mutationOptions; }; export const getCallWithOptionalParamQueryKey = (options: Options) => [ - createQueryKey("getCallWithOptionalParam", options) + createQueryKey('getCallWithOptionalParam', options) ]; export const getCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -363,7 +363,7 @@ export const getCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("getCallWithOptionalParam", options, true) + createQueryKey('getCallWithOptionalParam', options, true) ]; export const getCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -371,7 +371,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { page: pageParam } @@ -388,7 +388,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options) => [ - createQueryKey("postCallWithOptionalParam", options) + createQueryKey('postCallWithOptionalParam', options) ]; export const postCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -404,7 +404,7 @@ export const postCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("postCallWithOptionalParam", options, true) + createQueryKey('postCallWithOptionalParam', options, true) ]; export const postCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -412,7 +412,7 @@ export const postCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { body: { offset: pageParam } @@ -439,7 +439,7 @@ export const postCallWithOptionalParamMutation = () => { const mutationOptions: }; return mutationOptions; }; export const postApiVbyApiVersionRequestBodyQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionRequestBody", options) + createQueryKey('postApiVbyApiVersionRequestBody', options) ]; export const postApiVbyApiVersionRequestBodyOptions = (options?: Options) => { return queryOptions({ @@ -465,7 +465,7 @@ export const postApiVbyApiVersionRequestBodyMutation = () => { const mutationOpt }; return mutationOptions; }; export const postApiVbyApiVersionFormDataQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionFormData", options) + createQueryKey('postApiVbyApiVersionFormData', options) ]; export const postApiVbyApiVersionFormDataOptions = (options?: Options) => { return queryOptions({ @@ -491,7 +491,7 @@ export const postApiVbyApiVersionFormDataMutation = () => { const mutationOption }; return mutationOptions; }; export const callWithDefaultParametersQueryKey = (options?: Options) => [ - createQueryKey("callWithDefaultParameters", options) + createQueryKey('callWithDefaultParameters', options) ]; export const callWithDefaultParametersOptions = (options?: Options) => { return queryOptions({ @@ -507,7 +507,7 @@ export const callWithDefaultParametersOptions = (options?: Options) => [ - createQueryKey("callWithDefaultOptionalParameters", options) + createQueryKey('callWithDefaultOptionalParameters', options) ]; export const callWithDefaultOptionalParametersOptions = (options?: Options) => { return queryOptions({ @@ -543,7 +543,7 @@ export const callToTestOrderOfParamsMutation = () => { const mutationOptions: Mu }; return mutationOptions; }; export const duplicateNameQueryKey = (options?: Options) => [ - createQueryKey("duplicateName", options) + createQueryKey('duplicateName', options) ]; export const duplicateNameOptions = (options?: Options) => { return queryOptions({ @@ -559,7 +559,7 @@ export const duplicateNameOptions = (options?: Options) => { return queryOptions }); }; export const duplicateName1QueryKey = (options?: Options) => [ - createQueryKey("duplicateName1", options) + createQueryKey('duplicateName1', options) ]; export const duplicateName1Options = (options?: Options) => { return queryOptions({ @@ -605,7 +605,7 @@ export const duplicateName3Mutation = () => { const mutationOptions: MutationOpt }; return mutationOptions; }; export const callWithNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithNoContentResponse", options) + createQueryKey('callWithNoContentResponse', options) ]; export const callWithNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -621,7 +621,7 @@ export const callWithNoContentResponseOptions = (options?: Options) => { return }); }; export const callWithResponseAndNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponseAndNoContentResponse", options) + createQueryKey('callWithResponseAndNoContentResponse', options) ]; export const callWithResponseAndNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -637,7 +637,7 @@ export const callWithResponseAndNoContentResponseOptions = (options?: Options) = }); }; export const dummyAQueryKey = (options?: Options) => [ - createQueryKey("dummyA", options) + createQueryKey('dummyA', options) ]; export const dummyAOptions = (options?: Options) => { return queryOptions({ @@ -653,7 +653,7 @@ export const dummyAOptions = (options?: Options) => { return queryOptions({ }); }; export const dummyBQueryKey = (options?: Options) => [ - createQueryKey("dummyB", options) + createQueryKey('dummyB', options) ]; export const dummyBOptions = (options?: Options) => { return queryOptions({ @@ -669,7 +669,7 @@ export const dummyBOptions = (options?: Options) => { return queryOptions({ }); }; export const callWithResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponse", options) + createQueryKey('callWithResponse', options) ]; export const callWithResponseOptions = (options?: Options) => { return queryOptions({ @@ -685,7 +685,7 @@ export const callWithResponseOptions = (options?: Options) => { return queryOpti }); }; export const callWithDuplicateResponsesQueryKey = (options?: Options) => [ - createQueryKey("callWithDuplicateResponses", options) + createQueryKey('callWithDuplicateResponses', options) ]; export const callWithDuplicateResponsesOptions = (options?: Options) => { return queryOptions({ @@ -721,7 +721,7 @@ export const callWithResponsesMutation = () => { const mutationOptions: Mutation }; return mutationOptions; }; export const collectionFormatQueryKey = (options: Options) => [ - createQueryKey("collectionFormat", options) + createQueryKey('collectionFormat', options) ]; export const collectionFormatOptions = (options: Options) => { return queryOptions({ @@ -737,7 +737,7 @@ export const collectionFormatOptions = (options: Options) }); }; export const typesQueryKey = (options: Options) => [ - createQueryKey("types", options) + createQueryKey('types', options) ]; export const typesOptions = (options: Options) => { return queryOptions({ @@ -753,7 +753,7 @@ export const typesOptions = (options: Options) => { return queryOptio }); }; export const uploadFileQueryKey = (options: Options) => [ - createQueryKey("uploadFile", options) + createQueryKey('uploadFile', options) ]; export const uploadFileOptions = (options: Options) => { return queryOptions({ @@ -779,7 +779,7 @@ export const uploadFileMutation = () => { const mutationOptions: MutationOptions }; return mutationOptions; }; export const fileResponseQueryKey = (options: Options) => [ - createQueryKey("fileResponse", options) + createQueryKey('fileResponse', options) ]; export const fileResponseOptions = (options: Options) => { return queryOptions({ @@ -795,7 +795,7 @@ export const fileResponseOptions = (options: Options) => { ret }); }; export const complexTypesQueryKey = (options: Options) => [ - createQueryKey("complexTypes", options) + createQueryKey('complexTypes', options) ]; export const complexTypesOptions = (options: Options) => { return queryOptions({ @@ -811,7 +811,7 @@ export const complexTypesOptions = (options: Options) => { ret }); }; export const multipartRequestQueryKey = (options?: Options) => [ - createQueryKey("multipartRequest", options) + createQueryKey('multipartRequest', options) ]; export const multipartRequestOptions = (options?: Options) => { return queryOptions({ @@ -837,7 +837,7 @@ export const multipartRequestMutation = () => { const mutationOptions: MutationO }; return mutationOptions; }; export const multipartResponseQueryKey = (options?: Options) => [ - createQueryKey("multipartResponse", options) + createQueryKey('multipartResponse', options) ]; export const multipartResponseOptions = (options?: Options) => { return queryOptions({ @@ -863,7 +863,7 @@ export const complexParamsMutation = () => { const mutationOptions: MutationOpti }; return mutationOptions; }; export const callWithResultFromHeaderQueryKey = (options?: Options) => [ - createQueryKey("callWithResultFromHeader", options) + createQueryKey('callWithResultFromHeader', options) ]; export const callWithResultFromHeaderOptions = (options?: Options) => { return queryOptions({ @@ -889,7 +889,7 @@ export const callWithResultFromHeaderMutation = () => { const mutationOptions: M }; return mutationOptions; }; export const testErrorCodeQueryKey = (options: Options) => [ - createQueryKey("testErrorCode", options) + createQueryKey('testErrorCode', options) ]; export const testErrorCodeOptions = (options: Options) => { return queryOptions({ @@ -915,7 +915,7 @@ export const testErrorCodeMutation = () => { const mutationOptions: MutationOpti }; return mutationOptions; }; export const nonAsciiæøåÆøÅöôêÊ字符串QueryKey = (options: Options) => [ - createQueryKey("nonAsciiæøåÆøÅöôêÊ字符串", options) + createQueryKey('nonAsciiæøåÆøÅöôêÊ字符串', options) ]; export const nonAsciiæøåÆøÅöôêÊ字符串Options = (options: Options) => { return queryOptions({ diff --git a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/svelte-query/asClass/@tanstack/svelte-query.gen.ts b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/svelte-query/asClass/@tanstack/svelte-query.gen.ts index 8b87b22dc..dba3f22ab 100644 --- a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/svelte-query/asClass/@tanstack/svelte-query.gen.ts +++ b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/svelte-query/asClass/@tanstack/svelte-query.gen.ts @@ -33,7 +33,7 @@ const createQueryKey = (id: string, options?: TOptions }; export const collectionFormatQueryKey = (options: Options) => [ - createQueryKey("collectionFormat", options) + createQueryKey('collectionFormat', options) ]; export const collectionFormatOptions = (options: Options) => { return queryOptions({ @@ -49,7 +49,7 @@ export const collectionFormatOptions = (options: Options) }); }; export const complexTypesQueryKey = (options: Options) => [ - createQueryKey("complexTypes", options) + createQueryKey('complexTypes', options) ]; export const complexTypesOptions = (options: Options) => { return queryOptions({ @@ -75,7 +75,7 @@ export const complexParamsMutation = () => { const mutationOptions: MutationOpti }; return mutationOptions; }; export const exportQueryKey = (options?: Options) => [ - createQueryKey("export", options) + createQueryKey('export', options) ]; export const exportOptions = (options?: Options) => { return queryOptions({ @@ -91,7 +91,7 @@ export const exportOptions = (options?: Options) => { return queryOptions({ }); }; export const importQueryKey = (options: Options) => [ - createQueryKey("import", options) + createQueryKey('import', options) ]; export const importOptions = (options: Options) => { return queryOptions({ @@ -117,7 +117,7 @@ export const importMutation = () => { const mutationOptions: MutationOptions) => [ - createQueryKey("getApiVbyApiVersionSimpleOperation", options) + createQueryKey('getApiVbyApiVersionSimpleOperation', options) ]; export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => { return queryOptions({ @@ -133,7 +133,7 @@ export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => [ - createQueryKey("callWithDefaultParameters", options) + createQueryKey('callWithDefaultParameters', options) ]; export const callWithDefaultParametersOptions = (options?: Options) => { return queryOptions({ @@ -149,7 +149,7 @@ export const callWithDefaultParametersOptions = (options?: Options) => [ - createQueryKey("callWithDefaultOptionalParameters", options) + createQueryKey('callWithDefaultOptionalParameters', options) ]; export const callWithDefaultOptionalParametersOptions = (options?: Options) => { return queryOptions({ @@ -185,7 +185,7 @@ export const callToTestOrderOfParamsMutation = () => { const mutationOptions: Mu }; return mutationOptions; }; export const deprecatedCallQueryKey = (options: Options) => [ - createQueryKey("deprecatedCall", options) + createQueryKey('deprecatedCall', options) ]; export const deprecatedCallOptions = (options: Options) => { return queryOptions({ @@ -211,7 +211,7 @@ export const deprecatedCallMutation = () => { const mutationOptions: MutationOpt }; return mutationOptions; }; export const callWithDescriptionsQueryKey = (options?: Options) => [ - createQueryKey("callWithDescriptions", options) + createQueryKey('callWithDescriptions', options) ]; export const callWithDescriptionsOptions = (options?: Options) => { return queryOptions({ @@ -237,7 +237,7 @@ export const callWithDescriptionsMutation = () => { const mutationOptions: Mutat }; return mutationOptions; }; export const duplicateNameQueryKey = (options?: Options) => [ - createQueryKey("duplicateName", options) + createQueryKey('duplicateName', options) ]; export const duplicateNameOptions = (options?: Options) => { return queryOptions({ @@ -253,7 +253,7 @@ export const duplicateNameOptions = (options?: Options) => { return queryOptions }); }; export const duplicateName1QueryKey = (options?: Options) => [ - createQueryKey("duplicateName1", options) + createQueryKey('duplicateName1', options) ]; export const duplicateName1Options = (options?: Options) => { return queryOptions({ @@ -299,7 +299,7 @@ export const duplicateName3Mutation = () => { const mutationOptions: MutationOpt }; return mutationOptions; }; export const testErrorCodeQueryKey = (options: Options) => [ - createQueryKey("testErrorCode", options) + createQueryKey('testErrorCode', options) ]; export const testErrorCodeOptions = (options: Options) => { return queryOptions({ @@ -325,7 +325,7 @@ export const testErrorCodeMutation = () => { const mutationOptions: MutationOpti }; return mutationOptions; }; export const fileResponseQueryKey = (options: Options) => [ - createQueryKey("fileResponse", options) + createQueryKey('fileResponse', options) ]; export const fileResponseOptions = (options: Options) => { return queryOptions({ @@ -341,7 +341,7 @@ export const fileResponseOptions = (options: Options) => { ret }); }; export const postApiVbyApiVersionFormDataQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionFormData", options) + createQueryKey('postApiVbyApiVersionFormData', options) ]; export const postApiVbyApiVersionFormDataOptions = (options?: Options) => { return queryOptions({ @@ -367,7 +367,7 @@ export const postApiVbyApiVersionFormDataMutation = () => { const mutationOption }; return mutationOptions; }; export const callWithResultFromHeaderQueryKey = (options?: Options) => [ - createQueryKey("callWithResultFromHeader", options) + createQueryKey('callWithResultFromHeader', options) ]; export const callWithResultFromHeaderOptions = (options?: Options) => { return queryOptions({ @@ -393,7 +393,7 @@ export const callWithResultFromHeaderMutation = () => { const mutationOptions: M }; return mutationOptions; }; export const multipartRequestQueryKey = (options?: Options) => [ - createQueryKey("multipartRequest", options) + createQueryKey('multipartRequest', options) ]; export const multipartRequestOptions = (options?: Options) => { return queryOptions({ @@ -419,7 +419,7 @@ export const multipartRequestMutation = () => { const mutationOptions: MutationO }; return mutationOptions; }; export const multipartResponseQueryKey = (options?: Options) => [ - createQueryKey("multipartResponse", options) + createQueryKey('multipartResponse', options) ]; export const multipartResponseOptions = (options?: Options) => { return queryOptions({ @@ -435,7 +435,7 @@ export const multipartResponseOptions = (options?: Options) => { return queryOpt }); }; export const dummyAQueryKey = (options?: Options) => [ - createQueryKey("dummyA", options) + createQueryKey('dummyA', options) ]; export const dummyAOptions = (options?: Options) => { return queryOptions({ @@ -451,7 +451,7 @@ export const dummyAOptions = (options?: Options) => { return queryOptions({ }); }; export const dummyBQueryKey = (options?: Options) => [ - createQueryKey("dummyB", options) + createQueryKey('dummyB', options) ]; export const dummyBOptions = (options?: Options) => { return queryOptions({ @@ -467,7 +467,7 @@ export const dummyBOptions = (options?: Options) => { return queryOptions({ }); }; export const callWithNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithNoContentResponse", options) + createQueryKey('callWithNoContentResponse', options) ]; export const callWithNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -483,7 +483,7 @@ export const callWithNoContentResponseOptions = (options?: Options) => { return }); }; export const callWithResponseAndNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponseAndNoContentResponse", options) + createQueryKey('callWithResponseAndNoContentResponse', options) ]; export const callWithResponseAndNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -499,7 +499,7 @@ export const callWithResponseAndNoContentResponseOptions = (options?: Options) = }); }; export const nonAsciiæøåÆøÅöôêÊ字符串QueryKey = (options: Options) => [ - createQueryKey("nonAsciiæøåÆøÅöôêÊ字符串", options) + createQueryKey('nonAsciiæøåÆøÅöôêÊ字符串', options) ]; export const nonAsciiæøåÆøÅöôêÊ字符串Options = (options: Options) => { return queryOptions({ @@ -545,7 +545,7 @@ export const deleteFooMutation = () => { const mutationOptions: MutationOptions< }; return mutationOptions; }; export const callWithParametersQueryKey = (options: Options) => [ - createQueryKey("callWithParameters", options) + createQueryKey('callWithParameters', options) ]; export const callWithParametersOptions = (options: Options) => { return queryOptions({ @@ -590,7 +590,7 @@ const createInfiniteParams = [0], 'body' | 'hea }; export const callWithParametersInfiniteQueryKey = (options: Options): QueryKey> => [ - createQueryKey("callWithParameters", options, true) + createQueryKey('callWithParameters', options, true) ]; export const callWithParametersInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, string | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -598,7 +598,7 @@ export const callWithParametersInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { cursor: pageParam } @@ -625,7 +625,7 @@ export const callWithParametersMutation = () => { const mutationOptions: Mutatio }; return mutationOptions; }; export const callWithWeirdParameterNamesQueryKey = (options: Options) => [ - createQueryKey("callWithWeirdParameterNames", options) + createQueryKey('callWithWeirdParameterNames', options) ]; export const callWithWeirdParameterNamesOptions = (options: Options) => { return queryOptions({ @@ -651,7 +651,7 @@ export const callWithWeirdParameterNamesMutation = () => { const mutationOptions }; return mutationOptions; }; export const getCallWithOptionalParamQueryKey = (options: Options) => [ - createQueryKey("getCallWithOptionalParam", options) + createQueryKey('getCallWithOptionalParam', options) ]; export const getCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -667,7 +667,7 @@ export const getCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("getCallWithOptionalParam", options, true) + createQueryKey('getCallWithOptionalParam', options, true) ]; export const getCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -675,7 +675,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { page: pageParam } @@ -692,7 +692,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options) => [ - createQueryKey("postCallWithOptionalParam", options) + createQueryKey('postCallWithOptionalParam', options) ]; export const postCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -708,7 +708,7 @@ export const postCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("postCallWithOptionalParam", options, true) + createQueryKey('postCallWithOptionalParam', options, true) ]; export const postCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -716,7 +716,7 @@ export const postCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { body: { offset: pageParam } @@ -743,7 +743,7 @@ export const postCallWithOptionalParamMutation = () => { const mutationOptions: }; return mutationOptions; }; export const postApiVbyApiVersionRequestBodyQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionRequestBody", options) + createQueryKey('postApiVbyApiVersionRequestBody', options) ]; export const postApiVbyApiVersionRequestBodyOptions = (options?: Options) => { return queryOptions({ @@ -769,7 +769,7 @@ export const postApiVbyApiVersionRequestBodyMutation = () => { const mutationOpt }; return mutationOptions; }; export const callWithResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponse", options) + createQueryKey('callWithResponse', options) ]; export const callWithResponseOptions = (options?: Options) => { return queryOptions({ @@ -785,7 +785,7 @@ export const callWithResponseOptions = (options?: Options) => { return queryOpti }); }; export const callWithDuplicateResponsesQueryKey = (options?: Options) => [ - createQueryKey("callWithDuplicateResponses", options) + createQueryKey('callWithDuplicateResponses', options) ]; export const callWithDuplicateResponsesOptions = (options?: Options) => { return queryOptions({ @@ -821,7 +821,7 @@ export const callWithResponsesMutation = () => { const mutationOptions: Mutation }; return mutationOptions; }; export const apiVVersionOdataControllerCountQueryKey = (options?: Options) => [ - createQueryKey("apiVVersionOdataControllerCount", options) + createQueryKey('apiVVersionOdataControllerCount', options) ]; export const apiVVersionOdataControllerCountOptions = (options?: Options) => { return queryOptions({ @@ -837,7 +837,7 @@ export const apiVVersionOdataControllerCountOptions = (options?: Options) => { r }); }; export const getCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("getCallWithoutParametersAndResponse", options) + createQueryKey('getCallWithoutParametersAndResponse', options) ]; export const getCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -863,7 +863,7 @@ export const putCallWithoutParametersAndResponseMutation = () => { const mutatio }; return mutationOptions; }; export const postCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("postCallWithoutParametersAndResponse", options) + createQueryKey('postCallWithoutParametersAndResponse', options) ]; export const postCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -909,7 +909,7 @@ export const patchCallWithoutParametersAndResponseMutation = () => { const mutat }; return mutationOptions; }; export const typesQueryKey = (options: Options) => [ - createQueryKey("types", options) + createQueryKey('types', options) ]; export const typesOptions = (options: Options) => { return queryOptions({ @@ -925,7 +925,7 @@ export const typesOptions = (options: Options) => { return queryOptio }); }; export const uploadFileQueryKey = (options: Options) => [ - createQueryKey("uploadFile", options) + createQueryKey('uploadFile', options) ]; export const uploadFileOptions = (options: Options) => { return queryOptions({ diff --git a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/svelte-query/axios/@tanstack/svelte-query.gen.ts b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/svelte-query/axios/@tanstack/svelte-query.gen.ts index 005864147..494dc2180 100644 --- a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/svelte-query/axios/@tanstack/svelte-query.gen.ts +++ b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/svelte-query/axios/@tanstack/svelte-query.gen.ts @@ -34,7 +34,7 @@ const createQueryKey = (id: string, options?: TOptions }; export const exportQueryKey = (options?: Options) => [ - createQueryKey("export", options) + createQueryKey('export', options) ]; export const exportOptions = (options?: Options) => { return queryOptions({ @@ -50,7 +50,7 @@ export const exportOptions = (options?: Options) => { return queryOptions({ }); }; export const importQueryKey = (options: Options) => [ - createQueryKey("import", options) + createQueryKey('import', options) ]; export const importOptions = (options: Options) => { return queryOptions({ @@ -76,7 +76,7 @@ export const importMutation = () => { const mutationOptions: MutationOptions [ - createQueryKey("apiVVersionOdataControllerCount", options) + createQueryKey('apiVVersionOdataControllerCount', options) ]; export const apiVVersionOdataControllerCountOptions = (options?: Options) => { return queryOptions({ @@ -92,7 +92,7 @@ export const apiVVersionOdataControllerCountOptions = (options?: Options) => { r }); }; export const getApiVbyApiVersionSimpleOperationQueryKey = (options: Options) => [ - createQueryKey("getApiVbyApiVersionSimpleOperation", options) + createQueryKey('getApiVbyApiVersionSimpleOperation', options) ]; export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => { return queryOptions({ @@ -108,7 +108,7 @@ export const getApiVbyApiVersionSimpleOperationOptions = (options: Options [ - createQueryKey("getCallWithoutParametersAndResponse", options) + createQueryKey('getCallWithoutParametersAndResponse', options) ]; export const getCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -134,7 +134,7 @@ export const putCallWithoutParametersAndResponseMutation = () => { const mutatio }; return mutationOptions; }; export const postCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("postCallWithoutParametersAndResponse", options) + createQueryKey('postCallWithoutParametersAndResponse', options) ]; export const postCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -190,7 +190,7 @@ export const deleteFooMutation = () => { const mutationOptions: MutationOptions< }; return mutationOptions; }; export const callWithDescriptionsQueryKey = (options?: Options) => [ - createQueryKey("callWithDescriptions", options) + createQueryKey('callWithDescriptions', options) ]; export const callWithDescriptionsOptions = (options?: Options) => { return queryOptions({ @@ -216,7 +216,7 @@ export const callWithDescriptionsMutation = () => { const mutationOptions: Mutat }; return mutationOptions; }; export const deprecatedCallQueryKey = (options: Options) => [ - createQueryKey("deprecatedCall", options) + createQueryKey('deprecatedCall', options) ]; export const deprecatedCallOptions = (options: Options) => { return queryOptions({ @@ -242,7 +242,7 @@ export const deprecatedCallMutation = () => { const mutationOptions: MutationOpt }; return mutationOptions; }; export const callWithParametersQueryKey = (options: Options) => [ - createQueryKey("callWithParameters", options) + createQueryKey('callWithParameters', options) ]; export const callWithParametersOptions = (options: Options) => { return queryOptions({ @@ -287,7 +287,7 @@ const createInfiniteParams = [0], 'body' | 'hea }; export const callWithParametersInfiniteQueryKey = (options: Options): QueryKey> => [ - createQueryKey("callWithParameters", options, true) + createQueryKey('callWithParameters', options, true) ]; export const callWithParametersInfiniteOptions = (options: Options) => { return infiniteQueryOptions, InfiniteData, QueryKey>, string | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -295,7 +295,7 @@ export const callWithParametersInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { cursor: pageParam } @@ -322,7 +322,7 @@ export const callWithParametersMutation = () => { const mutationOptions: Mutatio }; return mutationOptions; }; export const callWithWeirdParameterNamesQueryKey = (options: Options) => [ - createQueryKey("callWithWeirdParameterNames", options) + createQueryKey('callWithWeirdParameterNames', options) ]; export const callWithWeirdParameterNamesOptions = (options: Options) => { return queryOptions({ @@ -348,7 +348,7 @@ export const callWithWeirdParameterNamesMutation = () => { const mutationOptions }; return mutationOptions; }; export const getCallWithOptionalParamQueryKey = (options: Options) => [ - createQueryKey("getCallWithOptionalParam", options) + createQueryKey('getCallWithOptionalParam', options) ]; export const getCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -364,7 +364,7 @@ export const getCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("getCallWithOptionalParam", options, true) + createQueryKey('getCallWithOptionalParam', options, true) ]; export const getCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, InfiniteData, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -372,7 +372,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { page: pageParam } @@ -389,7 +389,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options) => [ - createQueryKey("postCallWithOptionalParam", options) + createQueryKey('postCallWithOptionalParam', options) ]; export const postCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -405,7 +405,7 @@ export const postCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("postCallWithOptionalParam", options, true) + createQueryKey('postCallWithOptionalParam', options, true) ]; export const postCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, InfiniteData, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -413,7 +413,7 @@ export const postCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { body: { offset: pageParam } @@ -440,7 +440,7 @@ export const postCallWithOptionalParamMutation = () => { const mutationOptions: }; return mutationOptions; }; export const postApiVbyApiVersionRequestBodyQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionRequestBody", options) + createQueryKey('postApiVbyApiVersionRequestBody', options) ]; export const postApiVbyApiVersionRequestBodyOptions = (options?: Options) => { return queryOptions({ @@ -466,7 +466,7 @@ export const postApiVbyApiVersionRequestBodyMutation = () => { const mutationOpt }; return mutationOptions; }; export const postApiVbyApiVersionFormDataQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionFormData", options) + createQueryKey('postApiVbyApiVersionFormData', options) ]; export const postApiVbyApiVersionFormDataOptions = (options?: Options) => { return queryOptions({ @@ -492,7 +492,7 @@ export const postApiVbyApiVersionFormDataMutation = () => { const mutationOption }; return mutationOptions; }; export const callWithDefaultParametersQueryKey = (options?: Options) => [ - createQueryKey("callWithDefaultParameters", options) + createQueryKey('callWithDefaultParameters', options) ]; export const callWithDefaultParametersOptions = (options?: Options) => { return queryOptions({ @@ -508,7 +508,7 @@ export const callWithDefaultParametersOptions = (options?: Options) => [ - createQueryKey("callWithDefaultOptionalParameters", options) + createQueryKey('callWithDefaultOptionalParameters', options) ]; export const callWithDefaultOptionalParametersOptions = (options?: Options) => { return queryOptions({ @@ -544,7 +544,7 @@ export const callToTestOrderOfParamsMutation = () => { const mutationOptions: Mu }; return mutationOptions; }; export const duplicateNameQueryKey = (options?: Options) => [ - createQueryKey("duplicateName", options) + createQueryKey('duplicateName', options) ]; export const duplicateNameOptions = (options?: Options) => { return queryOptions({ @@ -560,7 +560,7 @@ export const duplicateNameOptions = (options?: Options) => { return queryOptions }); }; export const duplicateName1QueryKey = (options?: Options) => [ - createQueryKey("duplicateName1", options) + createQueryKey('duplicateName1', options) ]; export const duplicateName1Options = (options?: Options) => { return queryOptions({ @@ -606,7 +606,7 @@ export const duplicateName3Mutation = () => { const mutationOptions: MutationOpt }; return mutationOptions; }; export const callWithNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithNoContentResponse", options) + createQueryKey('callWithNoContentResponse', options) ]; export const callWithNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -622,7 +622,7 @@ export const callWithNoContentResponseOptions = (options?: Options) => { return }); }; export const callWithResponseAndNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponseAndNoContentResponse", options) + createQueryKey('callWithResponseAndNoContentResponse', options) ]; export const callWithResponseAndNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -638,7 +638,7 @@ export const callWithResponseAndNoContentResponseOptions = (options?: Options) = }); }; export const dummyAQueryKey = (options?: Options) => [ - createQueryKey("dummyA", options) + createQueryKey('dummyA', options) ]; export const dummyAOptions = (options?: Options) => { return queryOptions({ @@ -654,7 +654,7 @@ export const dummyAOptions = (options?: Options) => { return queryOptions({ }); }; export const dummyBQueryKey = (options?: Options) => [ - createQueryKey("dummyB", options) + createQueryKey('dummyB', options) ]; export const dummyBOptions = (options?: Options) => { return queryOptions({ @@ -670,7 +670,7 @@ export const dummyBOptions = (options?: Options) => { return queryOptions({ }); }; export const callWithResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponse", options) + createQueryKey('callWithResponse', options) ]; export const callWithResponseOptions = (options?: Options) => { return queryOptions({ @@ -686,7 +686,7 @@ export const callWithResponseOptions = (options?: Options) => { return queryOpti }); }; export const callWithDuplicateResponsesQueryKey = (options?: Options) => [ - createQueryKey("callWithDuplicateResponses", options) + createQueryKey('callWithDuplicateResponses', options) ]; export const callWithDuplicateResponsesOptions = (options?: Options) => { return queryOptions({ @@ -722,7 +722,7 @@ export const callWithResponsesMutation = () => { const mutationOptions: Mutation }; return mutationOptions; }; export const collectionFormatQueryKey = (options: Options) => [ - createQueryKey("collectionFormat", options) + createQueryKey('collectionFormat', options) ]; export const collectionFormatOptions = (options: Options) => { return queryOptions({ @@ -738,7 +738,7 @@ export const collectionFormatOptions = (options: Options) }); }; export const typesQueryKey = (options: Options) => [ - createQueryKey("types", options) + createQueryKey('types', options) ]; export const typesOptions = (options: Options) => { return queryOptions({ @@ -754,7 +754,7 @@ export const typesOptions = (options: Options) => { return queryOptio }); }; export const uploadFileQueryKey = (options: Options) => [ - createQueryKey("uploadFile", options) + createQueryKey('uploadFile', options) ]; export const uploadFileOptions = (options: Options) => { return queryOptions({ @@ -780,7 +780,7 @@ export const uploadFileMutation = () => { const mutationOptions: MutationOptions }; return mutationOptions; }; export const fileResponseQueryKey = (options: Options) => [ - createQueryKey("fileResponse", options) + createQueryKey('fileResponse', options) ]; export const fileResponseOptions = (options: Options) => { return queryOptions({ @@ -796,7 +796,7 @@ export const fileResponseOptions = (options: Options) => { ret }); }; export const complexTypesQueryKey = (options: Options) => [ - createQueryKey("complexTypes", options) + createQueryKey('complexTypes', options) ]; export const complexTypesOptions = (options: Options) => { return queryOptions({ @@ -812,7 +812,7 @@ export const complexTypesOptions = (options: Options) => { ret }); }; export const multipartRequestQueryKey = (options?: Options) => [ - createQueryKey("multipartRequest", options) + createQueryKey('multipartRequest', options) ]; export const multipartRequestOptions = (options?: Options) => { return queryOptions({ @@ -838,7 +838,7 @@ export const multipartRequestMutation = () => { const mutationOptions: MutationO }; return mutationOptions; }; export const multipartResponseQueryKey = (options?: Options) => [ - createQueryKey("multipartResponse", options) + createQueryKey('multipartResponse', options) ]; export const multipartResponseOptions = (options?: Options) => { return queryOptions({ @@ -864,7 +864,7 @@ export const complexParamsMutation = () => { const mutationOptions: MutationOpti }; return mutationOptions; }; export const callWithResultFromHeaderQueryKey = (options?: Options) => [ - createQueryKey("callWithResultFromHeader", options) + createQueryKey('callWithResultFromHeader', options) ]; export const callWithResultFromHeaderOptions = (options?: Options) => { return queryOptions({ @@ -890,7 +890,7 @@ export const callWithResultFromHeaderMutation = () => { const mutationOptions: M }; return mutationOptions; }; export const testErrorCodeQueryKey = (options: Options) => [ - createQueryKey("testErrorCode", options) + createQueryKey('testErrorCode', options) ]; export const testErrorCodeOptions = (options: Options) => { return queryOptions({ @@ -916,7 +916,7 @@ export const testErrorCodeMutation = () => { const mutationOptions: MutationOpti }; return mutationOptions; }; export const nonAsciiæøåÆøÅöôêÊ字符串QueryKey = (options: Options) => [ - createQueryKey("nonAsciiæøåÆøÅöôêÊ字符串", options) + createQueryKey('nonAsciiæøåÆøÅöôêÊ字符串', options) ]; export const nonAsciiæøåÆøÅöôêÊ字符串Options = (options: Options) => { return queryOptions({ diff --git a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/svelte-query/fetch/@tanstack/svelte-query.gen.ts b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/svelte-query/fetch/@tanstack/svelte-query.gen.ts index 7e8acff83..7efbd2c71 100644 --- a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/svelte-query/fetch/@tanstack/svelte-query.gen.ts +++ b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/svelte-query/fetch/@tanstack/svelte-query.gen.ts @@ -33,7 +33,7 @@ const createQueryKey = (id: string, options?: TOptions }; export const exportQueryKey = (options?: Options) => [ - createQueryKey("export", options) + createQueryKey('export', options) ]; export const exportOptions = (options?: Options) => { return queryOptions({ @@ -49,7 +49,7 @@ export const exportOptions = (options?: Options) => { return queryOptions({ }); }; export const importQueryKey = (options: Options) => [ - createQueryKey("import", options) + createQueryKey('import', options) ]; export const importOptions = (options: Options) => { return queryOptions({ @@ -75,7 +75,7 @@ export const importMutation = () => { const mutationOptions: MutationOptions [ - createQueryKey("apiVVersionOdataControllerCount", options) + createQueryKey('apiVVersionOdataControllerCount', options) ]; export const apiVVersionOdataControllerCountOptions = (options?: Options) => { return queryOptions({ @@ -91,7 +91,7 @@ export const apiVVersionOdataControllerCountOptions = (options?: Options) => { r }); }; export const getApiVbyApiVersionSimpleOperationQueryKey = (options: Options) => [ - createQueryKey("getApiVbyApiVersionSimpleOperation", options) + createQueryKey('getApiVbyApiVersionSimpleOperation', options) ]; export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => { return queryOptions({ @@ -107,7 +107,7 @@ export const getApiVbyApiVersionSimpleOperationOptions = (options: Options [ - createQueryKey("getCallWithoutParametersAndResponse", options) + createQueryKey('getCallWithoutParametersAndResponse', options) ]; export const getCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -133,7 +133,7 @@ export const putCallWithoutParametersAndResponseMutation = () => { const mutatio }; return mutationOptions; }; export const postCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("postCallWithoutParametersAndResponse", options) + createQueryKey('postCallWithoutParametersAndResponse', options) ]; export const postCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -189,7 +189,7 @@ export const deleteFooMutation = () => { const mutationOptions: MutationOptions< }; return mutationOptions; }; export const callWithDescriptionsQueryKey = (options?: Options) => [ - createQueryKey("callWithDescriptions", options) + createQueryKey('callWithDescriptions', options) ]; export const callWithDescriptionsOptions = (options?: Options) => { return queryOptions({ @@ -215,7 +215,7 @@ export const callWithDescriptionsMutation = () => { const mutationOptions: Mutat }; return mutationOptions; }; export const deprecatedCallQueryKey = (options: Options) => [ - createQueryKey("deprecatedCall", options) + createQueryKey('deprecatedCall', options) ]; export const deprecatedCallOptions = (options: Options) => { return queryOptions({ @@ -241,7 +241,7 @@ export const deprecatedCallMutation = () => { const mutationOptions: MutationOpt }; return mutationOptions; }; export const callWithParametersQueryKey = (options: Options) => [ - createQueryKey("callWithParameters", options) + createQueryKey('callWithParameters', options) ]; export const callWithParametersOptions = (options: Options) => { return queryOptions({ @@ -286,7 +286,7 @@ const createInfiniteParams = [0], 'body' | 'hea }; export const callWithParametersInfiniteQueryKey = (options: Options): QueryKey> => [ - createQueryKey("callWithParameters", options, true) + createQueryKey('callWithParameters', options, true) ]; export const callWithParametersInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, string | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -294,7 +294,7 @@ export const callWithParametersInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { cursor: pageParam } @@ -321,7 +321,7 @@ export const callWithParametersMutation = () => { const mutationOptions: Mutatio }; return mutationOptions; }; export const callWithWeirdParameterNamesQueryKey = (options: Options) => [ - createQueryKey("callWithWeirdParameterNames", options) + createQueryKey('callWithWeirdParameterNames', options) ]; export const callWithWeirdParameterNamesOptions = (options: Options) => { return queryOptions({ @@ -347,7 +347,7 @@ export const callWithWeirdParameterNamesMutation = () => { const mutationOptions }; return mutationOptions; }; export const getCallWithOptionalParamQueryKey = (options: Options) => [ - createQueryKey("getCallWithOptionalParam", options) + createQueryKey('getCallWithOptionalParam', options) ]; export const getCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -363,7 +363,7 @@ export const getCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("getCallWithOptionalParam", options, true) + createQueryKey('getCallWithOptionalParam', options, true) ]; export const getCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -371,7 +371,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { page: pageParam } @@ -388,7 +388,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options) => [ - createQueryKey("postCallWithOptionalParam", options) + createQueryKey('postCallWithOptionalParam', options) ]; export const postCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -404,7 +404,7 @@ export const postCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("postCallWithOptionalParam", options, true) + createQueryKey('postCallWithOptionalParam', options, true) ]; export const postCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -412,7 +412,7 @@ export const postCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { body: { offset: pageParam } @@ -439,7 +439,7 @@ export const postCallWithOptionalParamMutation = () => { const mutationOptions: }; return mutationOptions; }; export const postApiVbyApiVersionRequestBodyQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionRequestBody", options) + createQueryKey('postApiVbyApiVersionRequestBody', options) ]; export const postApiVbyApiVersionRequestBodyOptions = (options?: Options) => { return queryOptions({ @@ -465,7 +465,7 @@ export const postApiVbyApiVersionRequestBodyMutation = () => { const mutationOpt }; return mutationOptions; }; export const postApiVbyApiVersionFormDataQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionFormData", options) + createQueryKey('postApiVbyApiVersionFormData', options) ]; export const postApiVbyApiVersionFormDataOptions = (options?: Options) => { return queryOptions({ @@ -491,7 +491,7 @@ export const postApiVbyApiVersionFormDataMutation = () => { const mutationOption }; return mutationOptions; }; export const callWithDefaultParametersQueryKey = (options?: Options) => [ - createQueryKey("callWithDefaultParameters", options) + createQueryKey('callWithDefaultParameters', options) ]; export const callWithDefaultParametersOptions = (options?: Options) => { return queryOptions({ @@ -507,7 +507,7 @@ export const callWithDefaultParametersOptions = (options?: Options) => [ - createQueryKey("callWithDefaultOptionalParameters", options) + createQueryKey('callWithDefaultOptionalParameters', options) ]; export const callWithDefaultOptionalParametersOptions = (options?: Options) => { return queryOptions({ @@ -543,7 +543,7 @@ export const callToTestOrderOfParamsMutation = () => { const mutationOptions: Mu }; return mutationOptions; }; export const duplicateNameQueryKey = (options?: Options) => [ - createQueryKey("duplicateName", options) + createQueryKey('duplicateName', options) ]; export const duplicateNameOptions = (options?: Options) => { return queryOptions({ @@ -559,7 +559,7 @@ export const duplicateNameOptions = (options?: Options) => { return queryOptions }); }; export const duplicateName1QueryKey = (options?: Options) => [ - createQueryKey("duplicateName1", options) + createQueryKey('duplicateName1', options) ]; export const duplicateName1Options = (options?: Options) => { return queryOptions({ @@ -605,7 +605,7 @@ export const duplicateName3Mutation = () => { const mutationOptions: MutationOpt }; return mutationOptions; }; export const callWithNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithNoContentResponse", options) + createQueryKey('callWithNoContentResponse', options) ]; export const callWithNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -621,7 +621,7 @@ export const callWithNoContentResponseOptions = (options?: Options) => { return }); }; export const callWithResponseAndNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponseAndNoContentResponse", options) + createQueryKey('callWithResponseAndNoContentResponse', options) ]; export const callWithResponseAndNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -637,7 +637,7 @@ export const callWithResponseAndNoContentResponseOptions = (options?: Options) = }); }; export const dummyAQueryKey = (options?: Options) => [ - createQueryKey("dummyA", options) + createQueryKey('dummyA', options) ]; export const dummyAOptions = (options?: Options) => { return queryOptions({ @@ -653,7 +653,7 @@ export const dummyAOptions = (options?: Options) => { return queryOptions({ }); }; export const dummyBQueryKey = (options?: Options) => [ - createQueryKey("dummyB", options) + createQueryKey('dummyB', options) ]; export const dummyBOptions = (options?: Options) => { return queryOptions({ @@ -669,7 +669,7 @@ export const dummyBOptions = (options?: Options) => { return queryOptions({ }); }; export const callWithResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponse", options) + createQueryKey('callWithResponse', options) ]; export const callWithResponseOptions = (options?: Options) => { return queryOptions({ @@ -685,7 +685,7 @@ export const callWithResponseOptions = (options?: Options) => { return queryOpti }); }; export const callWithDuplicateResponsesQueryKey = (options?: Options) => [ - createQueryKey("callWithDuplicateResponses", options) + createQueryKey('callWithDuplicateResponses', options) ]; export const callWithDuplicateResponsesOptions = (options?: Options) => { return queryOptions({ @@ -721,7 +721,7 @@ export const callWithResponsesMutation = () => { const mutationOptions: Mutation }; return mutationOptions; }; export const collectionFormatQueryKey = (options: Options) => [ - createQueryKey("collectionFormat", options) + createQueryKey('collectionFormat', options) ]; export const collectionFormatOptions = (options: Options) => { return queryOptions({ @@ -737,7 +737,7 @@ export const collectionFormatOptions = (options: Options) }); }; export const typesQueryKey = (options: Options) => [ - createQueryKey("types", options) + createQueryKey('types', options) ]; export const typesOptions = (options: Options) => { return queryOptions({ @@ -753,7 +753,7 @@ export const typesOptions = (options: Options) => { return queryOptio }); }; export const uploadFileQueryKey = (options: Options) => [ - createQueryKey("uploadFile", options) + createQueryKey('uploadFile', options) ]; export const uploadFileOptions = (options: Options) => { return queryOptions({ @@ -779,7 +779,7 @@ export const uploadFileMutation = () => { const mutationOptions: MutationOptions }; return mutationOptions; }; export const fileResponseQueryKey = (options: Options) => [ - createQueryKey("fileResponse", options) + createQueryKey('fileResponse', options) ]; export const fileResponseOptions = (options: Options) => { return queryOptions({ @@ -795,7 +795,7 @@ export const fileResponseOptions = (options: Options) => { ret }); }; export const complexTypesQueryKey = (options: Options) => [ - createQueryKey("complexTypes", options) + createQueryKey('complexTypes', options) ]; export const complexTypesOptions = (options: Options) => { return queryOptions({ @@ -811,7 +811,7 @@ export const complexTypesOptions = (options: Options) => { ret }); }; export const multipartRequestQueryKey = (options?: Options) => [ - createQueryKey("multipartRequest", options) + createQueryKey('multipartRequest', options) ]; export const multipartRequestOptions = (options?: Options) => { return queryOptions({ @@ -837,7 +837,7 @@ export const multipartRequestMutation = () => { const mutationOptions: MutationO }; return mutationOptions; }; export const multipartResponseQueryKey = (options?: Options) => [ - createQueryKey("multipartResponse", options) + createQueryKey('multipartResponse', options) ]; export const multipartResponseOptions = (options?: Options) => { return queryOptions({ @@ -863,7 +863,7 @@ export const complexParamsMutation = () => { const mutationOptions: MutationOpti }; return mutationOptions; }; export const callWithResultFromHeaderQueryKey = (options?: Options) => [ - createQueryKey("callWithResultFromHeader", options) + createQueryKey('callWithResultFromHeader', options) ]; export const callWithResultFromHeaderOptions = (options?: Options) => { return queryOptions({ @@ -889,7 +889,7 @@ export const callWithResultFromHeaderMutation = () => { const mutationOptions: M }; return mutationOptions; }; export const testErrorCodeQueryKey = (options: Options) => [ - createQueryKey("testErrorCode", options) + createQueryKey('testErrorCode', options) ]; export const testErrorCodeOptions = (options: Options) => { return queryOptions({ @@ -915,7 +915,7 @@ export const testErrorCodeMutation = () => { const mutationOptions: MutationOpti }; return mutationOptions; }; export const nonAsciiæøåÆøÅöôêÊ字符串QueryKey = (options: Options) => [ - createQueryKey("nonAsciiæøåÆøÅöôêÊ字符串", options) + createQueryKey('nonAsciiæøåÆøÅöôêÊ字符串', options) ]; export const nonAsciiæøåÆøÅöôêÊ字符串Options = (options: Options) => { return queryOptions({ diff --git a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/vue-query/asClass/@tanstack/vue-query.gen.ts b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/vue-query/asClass/@tanstack/vue-query.gen.ts index 3e416b24d..b92eb03c7 100644 --- a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/vue-query/asClass/@tanstack/vue-query.gen.ts +++ b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/vue-query/asClass/@tanstack/vue-query.gen.ts @@ -33,7 +33,7 @@ const createQueryKey = (id: string, options?: TOptions }; export const collectionFormatQueryKey = (options: Options) => [ - createQueryKey("collectionFormat", options) + createQueryKey('collectionFormat', options) ]; export const collectionFormatOptions = (options: Options) => { return queryOptions({ @@ -49,7 +49,7 @@ export const collectionFormatOptions = (options: Options) }); }; export const complexTypesQueryKey = (options: Options) => [ - createQueryKey("complexTypes", options) + createQueryKey('complexTypes', options) ]; export const complexTypesOptions = (options: Options) => { return queryOptions({ @@ -75,7 +75,7 @@ export const complexParamsMutation = () => { const mutationOptions: UseMutationO }; return mutationOptions; }; export const exportQueryKey = (options?: Options) => [ - createQueryKey("export", options) + createQueryKey('export', options) ]; export const exportOptions = (options?: Options) => { return queryOptions({ @@ -91,7 +91,7 @@ export const exportOptions = (options?: Options) => { return queryOptions({ }); }; export const importQueryKey = (options: Options) => [ - createQueryKey("import", options) + createQueryKey('import', options) ]; export const importOptions = (options: Options) => { return queryOptions({ @@ -117,7 +117,7 @@ export const importMutation = () => { const mutationOptions: UseMutationOptions< }; return mutationOptions; }; export const getApiVbyApiVersionSimpleOperationQueryKey = (options: Options) => [ - createQueryKey("getApiVbyApiVersionSimpleOperation", options) + createQueryKey('getApiVbyApiVersionSimpleOperation', options) ]; export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => { return queryOptions({ @@ -133,7 +133,7 @@ export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => [ - createQueryKey("callWithDefaultParameters", options) + createQueryKey('callWithDefaultParameters', options) ]; export const callWithDefaultParametersOptions = (options?: Options) => { return queryOptions({ @@ -149,7 +149,7 @@ export const callWithDefaultParametersOptions = (options?: Options) => [ - createQueryKey("callWithDefaultOptionalParameters", options) + createQueryKey('callWithDefaultOptionalParameters', options) ]; export const callWithDefaultOptionalParametersOptions = (options?: Options) => { return queryOptions({ @@ -185,7 +185,7 @@ export const callToTestOrderOfParamsMutation = () => { const mutationOptions: Us }; return mutationOptions; }; export const deprecatedCallQueryKey = (options: Options) => [ - createQueryKey("deprecatedCall", options) + createQueryKey('deprecatedCall', options) ]; export const deprecatedCallOptions = (options: Options) => { return queryOptions({ @@ -211,7 +211,7 @@ export const deprecatedCallMutation = () => { const mutationOptions: UseMutation }; return mutationOptions; }; export const callWithDescriptionsQueryKey = (options?: Options) => [ - createQueryKey("callWithDescriptions", options) + createQueryKey('callWithDescriptions', options) ]; export const callWithDescriptionsOptions = (options?: Options) => { return queryOptions({ @@ -237,7 +237,7 @@ export const callWithDescriptionsMutation = () => { const mutationOptions: UseMu }; return mutationOptions; }; export const duplicateNameQueryKey = (options?: Options) => [ - createQueryKey("duplicateName", options) + createQueryKey('duplicateName', options) ]; export const duplicateNameOptions = (options?: Options) => { return queryOptions({ @@ -253,7 +253,7 @@ export const duplicateNameOptions = (options?: Options) => { return queryOptions }); }; export const duplicateName1QueryKey = (options?: Options) => [ - createQueryKey("duplicateName1", options) + createQueryKey('duplicateName1', options) ]; export const duplicateName1Options = (options?: Options) => { return queryOptions({ @@ -299,7 +299,7 @@ export const duplicateName3Mutation = () => { const mutationOptions: UseMutation }; return mutationOptions; }; export const testErrorCodeQueryKey = (options: Options) => [ - createQueryKey("testErrorCode", options) + createQueryKey('testErrorCode', options) ]; export const testErrorCodeOptions = (options: Options) => { return queryOptions({ @@ -325,7 +325,7 @@ export const testErrorCodeMutation = () => { const mutationOptions: UseMutationO }; return mutationOptions; }; export const fileResponseQueryKey = (options: Options) => [ - createQueryKey("fileResponse", options) + createQueryKey('fileResponse', options) ]; export const fileResponseOptions = (options: Options) => { return queryOptions({ @@ -341,7 +341,7 @@ export const fileResponseOptions = (options: Options) => { ret }); }; export const postApiVbyApiVersionFormDataQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionFormData", options) + createQueryKey('postApiVbyApiVersionFormData', options) ]; export const postApiVbyApiVersionFormDataOptions = (options?: Options) => { return queryOptions({ @@ -367,7 +367,7 @@ export const postApiVbyApiVersionFormDataMutation = () => { const mutationOption }; return mutationOptions; }; export const callWithResultFromHeaderQueryKey = (options?: Options) => [ - createQueryKey("callWithResultFromHeader", options) + createQueryKey('callWithResultFromHeader', options) ]; export const callWithResultFromHeaderOptions = (options?: Options) => { return queryOptions({ @@ -393,7 +393,7 @@ export const callWithResultFromHeaderMutation = () => { const mutationOptions: U }; return mutationOptions; }; export const multipartRequestQueryKey = (options?: Options) => [ - createQueryKey("multipartRequest", options) + createQueryKey('multipartRequest', options) ]; export const multipartRequestOptions = (options?: Options) => { return queryOptions({ @@ -419,7 +419,7 @@ export const multipartRequestMutation = () => { const mutationOptions: UseMutati }; return mutationOptions; }; export const multipartResponseQueryKey = (options?: Options) => [ - createQueryKey("multipartResponse", options) + createQueryKey('multipartResponse', options) ]; export const multipartResponseOptions = (options?: Options) => { return queryOptions({ @@ -435,7 +435,7 @@ export const multipartResponseOptions = (options?: Options) => { return queryOpt }); }; export const dummyAQueryKey = (options?: Options) => [ - createQueryKey("dummyA", options) + createQueryKey('dummyA', options) ]; export const dummyAOptions = (options?: Options) => { return queryOptions({ @@ -451,7 +451,7 @@ export const dummyAOptions = (options?: Options) => { return queryOptions({ }); }; export const dummyBQueryKey = (options?: Options) => [ - createQueryKey("dummyB", options) + createQueryKey('dummyB', options) ]; export const dummyBOptions = (options?: Options) => { return queryOptions({ @@ -467,7 +467,7 @@ export const dummyBOptions = (options?: Options) => { return queryOptions({ }); }; export const callWithNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithNoContentResponse", options) + createQueryKey('callWithNoContentResponse', options) ]; export const callWithNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -483,7 +483,7 @@ export const callWithNoContentResponseOptions = (options?: Options) => { return }); }; export const callWithResponseAndNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponseAndNoContentResponse", options) + createQueryKey('callWithResponseAndNoContentResponse', options) ]; export const callWithResponseAndNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -499,7 +499,7 @@ export const callWithResponseAndNoContentResponseOptions = (options?: Options) = }); }; export const nonAsciiæøåÆøÅöôêÊ字符串QueryKey = (options: Options) => [ - createQueryKey("nonAsciiæøåÆøÅöôêÊ字符串", options) + createQueryKey('nonAsciiæøåÆøÅöôêÊ字符串', options) ]; export const nonAsciiæøåÆøÅöôêÊ字符串Options = (options: Options) => { return queryOptions({ @@ -545,7 +545,7 @@ export const deleteFooMutation = () => { const mutationOptions: UseMutationOptio }; return mutationOptions; }; export const callWithParametersQueryKey = (options: Options) => [ - createQueryKey("callWithParameters", options) + createQueryKey('callWithParameters', options) ]; export const callWithParametersOptions = (options: Options) => { return queryOptions({ @@ -590,7 +590,7 @@ const createInfiniteParams = [0], 'body' | 'hea }; export const callWithParametersInfiniteQueryKey = (options: Options): QueryKey> => [ - createQueryKey("callWithParameters", options, true) + createQueryKey('callWithParameters', options, true) ]; export const callWithParametersInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, string | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -598,7 +598,7 @@ export const callWithParametersInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { cursor: pageParam } @@ -625,7 +625,7 @@ export const callWithParametersMutation = () => { const mutationOptions: UseMuta }; return mutationOptions; }; export const callWithWeirdParameterNamesQueryKey = (options: Options) => [ - createQueryKey("callWithWeirdParameterNames", options) + createQueryKey('callWithWeirdParameterNames', options) ]; export const callWithWeirdParameterNamesOptions = (options: Options) => { return queryOptions({ @@ -651,7 +651,7 @@ export const callWithWeirdParameterNamesMutation = () => { const mutationOptions }; return mutationOptions; }; export const getCallWithOptionalParamQueryKey = (options: Options) => [ - createQueryKey("getCallWithOptionalParam", options) + createQueryKey('getCallWithOptionalParam', options) ]; export const getCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -667,7 +667,7 @@ export const getCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("getCallWithOptionalParam", options, true) + createQueryKey('getCallWithOptionalParam', options, true) ]; export const getCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -675,7 +675,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { page: pageParam } @@ -692,7 +692,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options) => [ - createQueryKey("postCallWithOptionalParam", options) + createQueryKey('postCallWithOptionalParam', options) ]; export const postCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -708,7 +708,7 @@ export const postCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("postCallWithOptionalParam", options, true) + createQueryKey('postCallWithOptionalParam', options, true) ]; export const postCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -716,7 +716,7 @@ export const postCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { body: { offset: pageParam } @@ -743,7 +743,7 @@ export const postCallWithOptionalParamMutation = () => { const mutationOptions: }; return mutationOptions; }; export const postApiVbyApiVersionRequestBodyQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionRequestBody", options) + createQueryKey('postApiVbyApiVersionRequestBody', options) ]; export const postApiVbyApiVersionRequestBodyOptions = (options?: Options) => { return queryOptions({ @@ -769,7 +769,7 @@ export const postApiVbyApiVersionRequestBodyMutation = () => { const mutationOpt }; return mutationOptions; }; export const callWithResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponse", options) + createQueryKey('callWithResponse', options) ]; export const callWithResponseOptions = (options?: Options) => { return queryOptions({ @@ -785,7 +785,7 @@ export const callWithResponseOptions = (options?: Options) => { return queryOpti }); }; export const callWithDuplicateResponsesQueryKey = (options?: Options) => [ - createQueryKey("callWithDuplicateResponses", options) + createQueryKey('callWithDuplicateResponses', options) ]; export const callWithDuplicateResponsesOptions = (options?: Options) => { return queryOptions({ @@ -821,7 +821,7 @@ export const callWithResponsesMutation = () => { const mutationOptions: UseMutat }; return mutationOptions; }; export const apiVVersionOdataControllerCountQueryKey = (options?: Options) => [ - createQueryKey("apiVVersionOdataControllerCount", options) + createQueryKey('apiVVersionOdataControllerCount', options) ]; export const apiVVersionOdataControllerCountOptions = (options?: Options) => { return queryOptions({ @@ -837,7 +837,7 @@ export const apiVVersionOdataControllerCountOptions = (options?: Options) => { r }); }; export const getCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("getCallWithoutParametersAndResponse", options) + createQueryKey('getCallWithoutParametersAndResponse', options) ]; export const getCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -863,7 +863,7 @@ export const putCallWithoutParametersAndResponseMutation = () => { const mutatio }; return mutationOptions; }; export const postCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("postCallWithoutParametersAndResponse", options) + createQueryKey('postCallWithoutParametersAndResponse', options) ]; export const postCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -909,7 +909,7 @@ export const patchCallWithoutParametersAndResponseMutation = () => { const mutat }; return mutationOptions; }; export const typesQueryKey = (options: Options) => [ - createQueryKey("types", options) + createQueryKey('types', options) ]; export const typesOptions = (options: Options) => { return queryOptions({ @@ -925,7 +925,7 @@ export const typesOptions = (options: Options) => { return queryOptio }); }; export const uploadFileQueryKey = (options: Options) => [ - createQueryKey("uploadFile", options) + createQueryKey('uploadFile', options) ]; export const uploadFileOptions = (options: Options) => { return queryOptions({ diff --git a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/vue-query/axios/@tanstack/vue-query.gen.ts b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/vue-query/axios/@tanstack/vue-query.gen.ts index 36fe96402..5315986cf 100644 --- a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/vue-query/axios/@tanstack/vue-query.gen.ts +++ b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/vue-query/axios/@tanstack/vue-query.gen.ts @@ -34,7 +34,7 @@ const createQueryKey = (id: string, options?: TOptions }; export const exportQueryKey = (options?: Options) => [ - createQueryKey("export", options) + createQueryKey('export', options) ]; export const exportOptions = (options?: Options) => { return queryOptions({ @@ -50,7 +50,7 @@ export const exportOptions = (options?: Options) => { return queryOptions({ }); }; export const importQueryKey = (options: Options) => [ - createQueryKey("import", options) + createQueryKey('import', options) ]; export const importOptions = (options: Options) => { return queryOptions({ @@ -76,7 +76,7 @@ export const importMutation = () => { const mutationOptions: UseMutationOptions< }; return mutationOptions; }; export const apiVVersionOdataControllerCountQueryKey = (options?: Options) => [ - createQueryKey("apiVVersionOdataControllerCount", options) + createQueryKey('apiVVersionOdataControllerCount', options) ]; export const apiVVersionOdataControllerCountOptions = (options?: Options) => { return queryOptions({ @@ -92,7 +92,7 @@ export const apiVVersionOdataControllerCountOptions = (options?: Options) => { r }); }; export const getApiVbyApiVersionSimpleOperationQueryKey = (options: Options) => [ - createQueryKey("getApiVbyApiVersionSimpleOperation", options) + createQueryKey('getApiVbyApiVersionSimpleOperation', options) ]; export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => { return queryOptions({ @@ -108,7 +108,7 @@ export const getApiVbyApiVersionSimpleOperationOptions = (options: Options [ - createQueryKey("getCallWithoutParametersAndResponse", options) + createQueryKey('getCallWithoutParametersAndResponse', options) ]; export const getCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -134,7 +134,7 @@ export const putCallWithoutParametersAndResponseMutation = () => { const mutatio }; return mutationOptions; }; export const postCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("postCallWithoutParametersAndResponse", options) + createQueryKey('postCallWithoutParametersAndResponse', options) ]; export const postCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -190,7 +190,7 @@ export const deleteFooMutation = () => { const mutationOptions: UseMutationOptio }; return mutationOptions; }; export const callWithDescriptionsQueryKey = (options?: Options) => [ - createQueryKey("callWithDescriptions", options) + createQueryKey('callWithDescriptions', options) ]; export const callWithDescriptionsOptions = (options?: Options) => { return queryOptions({ @@ -216,7 +216,7 @@ export const callWithDescriptionsMutation = () => { const mutationOptions: UseMu }; return mutationOptions; }; export const deprecatedCallQueryKey = (options: Options) => [ - createQueryKey("deprecatedCall", options) + createQueryKey('deprecatedCall', options) ]; export const deprecatedCallOptions = (options: Options) => { return queryOptions({ @@ -242,7 +242,7 @@ export const deprecatedCallMutation = () => { const mutationOptions: UseMutation }; return mutationOptions; }; export const callWithParametersQueryKey = (options: Options) => [ - createQueryKey("callWithParameters", options) + createQueryKey('callWithParameters', options) ]; export const callWithParametersOptions = (options: Options) => { return queryOptions({ @@ -287,7 +287,7 @@ const createInfiniteParams = [0], 'body' | 'hea }; export const callWithParametersInfiniteQueryKey = (options: Options): QueryKey> => [ - createQueryKey("callWithParameters", options, true) + createQueryKey('callWithParameters', options, true) ]; export const callWithParametersInfiniteOptions = (options: Options) => { return infiniteQueryOptions, InfiniteData, QueryKey>, string | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -295,7 +295,7 @@ export const callWithParametersInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { cursor: pageParam } @@ -322,7 +322,7 @@ export const callWithParametersMutation = () => { const mutationOptions: UseMuta }; return mutationOptions; }; export const callWithWeirdParameterNamesQueryKey = (options: Options) => [ - createQueryKey("callWithWeirdParameterNames", options) + createQueryKey('callWithWeirdParameterNames', options) ]; export const callWithWeirdParameterNamesOptions = (options: Options) => { return queryOptions({ @@ -348,7 +348,7 @@ export const callWithWeirdParameterNamesMutation = () => { const mutationOptions }; return mutationOptions; }; export const getCallWithOptionalParamQueryKey = (options: Options) => [ - createQueryKey("getCallWithOptionalParam", options) + createQueryKey('getCallWithOptionalParam', options) ]; export const getCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -364,7 +364,7 @@ export const getCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("getCallWithOptionalParam", options, true) + createQueryKey('getCallWithOptionalParam', options, true) ]; export const getCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, InfiniteData, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -372,7 +372,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { page: pageParam } @@ -389,7 +389,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options) => [ - createQueryKey("postCallWithOptionalParam", options) + createQueryKey('postCallWithOptionalParam', options) ]; export const postCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -405,7 +405,7 @@ export const postCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("postCallWithOptionalParam", options, true) + createQueryKey('postCallWithOptionalParam', options, true) ]; export const postCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, InfiniteData, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -413,7 +413,7 @@ export const postCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { body: { offset: pageParam } @@ -440,7 +440,7 @@ export const postCallWithOptionalParamMutation = () => { const mutationOptions: }; return mutationOptions; }; export const postApiVbyApiVersionRequestBodyQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionRequestBody", options) + createQueryKey('postApiVbyApiVersionRequestBody', options) ]; export const postApiVbyApiVersionRequestBodyOptions = (options?: Options) => { return queryOptions({ @@ -466,7 +466,7 @@ export const postApiVbyApiVersionRequestBodyMutation = () => { const mutationOpt }; return mutationOptions; }; export const postApiVbyApiVersionFormDataQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionFormData", options) + createQueryKey('postApiVbyApiVersionFormData', options) ]; export const postApiVbyApiVersionFormDataOptions = (options?: Options) => { return queryOptions({ @@ -492,7 +492,7 @@ export const postApiVbyApiVersionFormDataMutation = () => { const mutationOption }; return mutationOptions; }; export const callWithDefaultParametersQueryKey = (options?: Options) => [ - createQueryKey("callWithDefaultParameters", options) + createQueryKey('callWithDefaultParameters', options) ]; export const callWithDefaultParametersOptions = (options?: Options) => { return queryOptions({ @@ -508,7 +508,7 @@ export const callWithDefaultParametersOptions = (options?: Options) => [ - createQueryKey("callWithDefaultOptionalParameters", options) + createQueryKey('callWithDefaultOptionalParameters', options) ]; export const callWithDefaultOptionalParametersOptions = (options?: Options) => { return queryOptions({ @@ -544,7 +544,7 @@ export const callToTestOrderOfParamsMutation = () => { const mutationOptions: Us }; return mutationOptions; }; export const duplicateNameQueryKey = (options?: Options) => [ - createQueryKey("duplicateName", options) + createQueryKey('duplicateName', options) ]; export const duplicateNameOptions = (options?: Options) => { return queryOptions({ @@ -560,7 +560,7 @@ export const duplicateNameOptions = (options?: Options) => { return queryOptions }); }; export const duplicateName1QueryKey = (options?: Options) => [ - createQueryKey("duplicateName1", options) + createQueryKey('duplicateName1', options) ]; export const duplicateName1Options = (options?: Options) => { return queryOptions({ @@ -606,7 +606,7 @@ export const duplicateName3Mutation = () => { const mutationOptions: UseMutation }; return mutationOptions; }; export const callWithNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithNoContentResponse", options) + createQueryKey('callWithNoContentResponse', options) ]; export const callWithNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -622,7 +622,7 @@ export const callWithNoContentResponseOptions = (options?: Options) => { return }); }; export const callWithResponseAndNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponseAndNoContentResponse", options) + createQueryKey('callWithResponseAndNoContentResponse', options) ]; export const callWithResponseAndNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -638,7 +638,7 @@ export const callWithResponseAndNoContentResponseOptions = (options?: Options) = }); }; export const dummyAQueryKey = (options?: Options) => [ - createQueryKey("dummyA", options) + createQueryKey('dummyA', options) ]; export const dummyAOptions = (options?: Options) => { return queryOptions({ @@ -654,7 +654,7 @@ export const dummyAOptions = (options?: Options) => { return queryOptions({ }); }; export const dummyBQueryKey = (options?: Options) => [ - createQueryKey("dummyB", options) + createQueryKey('dummyB', options) ]; export const dummyBOptions = (options?: Options) => { return queryOptions({ @@ -670,7 +670,7 @@ export const dummyBOptions = (options?: Options) => { return queryOptions({ }); }; export const callWithResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponse", options) + createQueryKey('callWithResponse', options) ]; export const callWithResponseOptions = (options?: Options) => { return queryOptions({ @@ -686,7 +686,7 @@ export const callWithResponseOptions = (options?: Options) => { return queryOpti }); }; export const callWithDuplicateResponsesQueryKey = (options?: Options) => [ - createQueryKey("callWithDuplicateResponses", options) + createQueryKey('callWithDuplicateResponses', options) ]; export const callWithDuplicateResponsesOptions = (options?: Options) => { return queryOptions({ @@ -722,7 +722,7 @@ export const callWithResponsesMutation = () => { const mutationOptions: UseMutat }; return mutationOptions; }; export const collectionFormatQueryKey = (options: Options) => [ - createQueryKey("collectionFormat", options) + createQueryKey('collectionFormat', options) ]; export const collectionFormatOptions = (options: Options) => { return queryOptions({ @@ -738,7 +738,7 @@ export const collectionFormatOptions = (options: Options) }); }; export const typesQueryKey = (options: Options) => [ - createQueryKey("types", options) + createQueryKey('types', options) ]; export const typesOptions = (options: Options) => { return queryOptions({ @@ -754,7 +754,7 @@ export const typesOptions = (options: Options) => { return queryOptio }); }; export const uploadFileQueryKey = (options: Options) => [ - createQueryKey("uploadFile", options) + createQueryKey('uploadFile', options) ]; export const uploadFileOptions = (options: Options) => { return queryOptions({ @@ -780,7 +780,7 @@ export const uploadFileMutation = () => { const mutationOptions: UseMutationOpti }; return mutationOptions; }; export const fileResponseQueryKey = (options: Options) => [ - createQueryKey("fileResponse", options) + createQueryKey('fileResponse', options) ]; export const fileResponseOptions = (options: Options) => { return queryOptions({ @@ -796,7 +796,7 @@ export const fileResponseOptions = (options: Options) => { ret }); }; export const complexTypesQueryKey = (options: Options) => [ - createQueryKey("complexTypes", options) + createQueryKey('complexTypes', options) ]; export const complexTypesOptions = (options: Options) => { return queryOptions({ @@ -812,7 +812,7 @@ export const complexTypesOptions = (options: Options) => { ret }); }; export const multipartRequestQueryKey = (options?: Options) => [ - createQueryKey("multipartRequest", options) + createQueryKey('multipartRequest', options) ]; export const multipartRequestOptions = (options?: Options) => { return queryOptions({ @@ -838,7 +838,7 @@ export const multipartRequestMutation = () => { const mutationOptions: UseMutati }; return mutationOptions; }; export const multipartResponseQueryKey = (options?: Options) => [ - createQueryKey("multipartResponse", options) + createQueryKey('multipartResponse', options) ]; export const multipartResponseOptions = (options?: Options) => { return queryOptions({ @@ -864,7 +864,7 @@ export const complexParamsMutation = () => { const mutationOptions: UseMutationO }; return mutationOptions; }; export const callWithResultFromHeaderQueryKey = (options?: Options) => [ - createQueryKey("callWithResultFromHeader", options) + createQueryKey('callWithResultFromHeader', options) ]; export const callWithResultFromHeaderOptions = (options?: Options) => { return queryOptions({ @@ -890,7 +890,7 @@ export const callWithResultFromHeaderMutation = () => { const mutationOptions: U }; return mutationOptions; }; export const testErrorCodeQueryKey = (options: Options) => [ - createQueryKey("testErrorCode", options) + createQueryKey('testErrorCode', options) ]; export const testErrorCodeOptions = (options: Options) => { return queryOptions({ @@ -916,7 +916,7 @@ export const testErrorCodeMutation = () => { const mutationOptions: UseMutationO }; return mutationOptions; }; export const nonAsciiæøåÆøÅöôêÊ字符串QueryKey = (options: Options) => [ - createQueryKey("nonAsciiæøåÆøÅöôêÊ字符串", options) + createQueryKey('nonAsciiæøåÆøÅöôêÊ字符串', options) ]; export const nonAsciiæøåÆøÅöôêÊ字符串Options = (options: Options) => { return queryOptions({ diff --git a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/vue-query/fetch/@tanstack/vue-query.gen.ts b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/vue-query/fetch/@tanstack/vue-query.gen.ts index 91765a95e..90edc0dba 100644 --- a/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/vue-query/fetch/@tanstack/vue-query.gen.ts +++ b/packages/openapi-ts/test/__snapshots__/plugins/@tanstack/vue-query/fetch/@tanstack/vue-query.gen.ts @@ -33,7 +33,7 @@ const createQueryKey = (id: string, options?: TOptions }; export const exportQueryKey = (options?: Options) => [ - createQueryKey("export", options) + createQueryKey('export', options) ]; export const exportOptions = (options?: Options) => { return queryOptions({ @@ -49,7 +49,7 @@ export const exportOptions = (options?: Options) => { return queryOptions({ }); }; export const importQueryKey = (options: Options) => [ - createQueryKey("import", options) + createQueryKey('import', options) ]; export const importOptions = (options: Options) => { return queryOptions({ @@ -75,7 +75,7 @@ export const importMutation = () => { const mutationOptions: UseMutationOptions< }; return mutationOptions; }; export const apiVVersionOdataControllerCountQueryKey = (options?: Options) => [ - createQueryKey("apiVVersionOdataControllerCount", options) + createQueryKey('apiVVersionOdataControllerCount', options) ]; export const apiVVersionOdataControllerCountOptions = (options?: Options) => { return queryOptions({ @@ -91,7 +91,7 @@ export const apiVVersionOdataControllerCountOptions = (options?: Options) => { r }); }; export const getApiVbyApiVersionSimpleOperationQueryKey = (options: Options) => [ - createQueryKey("getApiVbyApiVersionSimpleOperation", options) + createQueryKey('getApiVbyApiVersionSimpleOperation', options) ]; export const getApiVbyApiVersionSimpleOperationOptions = (options: Options) => { return queryOptions({ @@ -107,7 +107,7 @@ export const getApiVbyApiVersionSimpleOperationOptions = (options: Options [ - createQueryKey("getCallWithoutParametersAndResponse", options) + createQueryKey('getCallWithoutParametersAndResponse', options) ]; export const getCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -133,7 +133,7 @@ export const putCallWithoutParametersAndResponseMutation = () => { const mutatio }; return mutationOptions; }; export const postCallWithoutParametersAndResponseQueryKey = (options?: Options) => [ - createQueryKey("postCallWithoutParametersAndResponse", options) + createQueryKey('postCallWithoutParametersAndResponse', options) ]; export const postCallWithoutParametersAndResponseOptions = (options?: Options) => { return queryOptions({ @@ -189,7 +189,7 @@ export const deleteFooMutation = () => { const mutationOptions: UseMutationOptio }; return mutationOptions; }; export const callWithDescriptionsQueryKey = (options?: Options) => [ - createQueryKey("callWithDescriptions", options) + createQueryKey('callWithDescriptions', options) ]; export const callWithDescriptionsOptions = (options?: Options) => { return queryOptions({ @@ -215,7 +215,7 @@ export const callWithDescriptionsMutation = () => { const mutationOptions: UseMu }; return mutationOptions; }; export const deprecatedCallQueryKey = (options: Options) => [ - createQueryKey("deprecatedCall", options) + createQueryKey('deprecatedCall', options) ]; export const deprecatedCallOptions = (options: Options) => { return queryOptions({ @@ -241,7 +241,7 @@ export const deprecatedCallMutation = () => { const mutationOptions: UseMutation }; return mutationOptions; }; export const callWithParametersQueryKey = (options: Options) => [ - createQueryKey("callWithParameters", options) + createQueryKey('callWithParameters', options) ]; export const callWithParametersOptions = (options: Options) => { return queryOptions({ @@ -286,7 +286,7 @@ const createInfiniteParams = [0], 'body' | 'hea }; export const callWithParametersInfiniteQueryKey = (options: Options): QueryKey> => [ - createQueryKey("callWithParameters", options, true) + createQueryKey('callWithParameters', options, true) ]; export const callWithParametersInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, string | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -294,7 +294,7 @@ export const callWithParametersInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { cursor: pageParam } @@ -321,7 +321,7 @@ export const callWithParametersMutation = () => { const mutationOptions: UseMuta }; return mutationOptions; }; export const callWithWeirdParameterNamesQueryKey = (options: Options) => [ - createQueryKey("callWithWeirdParameterNames", options) + createQueryKey('callWithWeirdParameterNames', options) ]; export const callWithWeirdParameterNamesOptions = (options: Options) => { return queryOptions({ @@ -347,7 +347,7 @@ export const callWithWeirdParameterNamesMutation = () => { const mutationOptions }; return mutationOptions; }; export const getCallWithOptionalParamQueryKey = (options: Options) => [ - createQueryKey("getCallWithOptionalParam", options) + createQueryKey('getCallWithOptionalParam', options) ]; export const getCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -363,7 +363,7 @@ export const getCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("getCallWithOptionalParam", options, true) + createQueryKey('getCallWithOptionalParam', options, true) ]; export const getCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -371,7 +371,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { query: { page: pageParam } @@ -388,7 +388,7 @@ export const getCallWithOptionalParamInfiniteOptions = (options: Options) => [ - createQueryKey("postCallWithOptionalParam", options) + createQueryKey('postCallWithOptionalParam', options) ]; export const postCallWithOptionalParamOptions = (options: Options) => { return queryOptions({ @@ -404,7 +404,7 @@ export const postCallWithOptionalParamOptions = (options: Options): QueryKey> => [ - createQueryKey("postCallWithOptionalParam", options, true) + createQueryKey('postCallWithOptionalParam', options, true) ]; export const postCallWithOptionalParamInfiniteOptions = (options: Options) => { return infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( @@ -412,7 +412,7 @@ export const postCallWithOptionalParamInfiniteOptions = (options: Options { // @ts-ignore - const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === "object" ? pageParam : { + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { body: { offset: pageParam } @@ -439,7 +439,7 @@ export const postCallWithOptionalParamMutation = () => { const mutationOptions: }; return mutationOptions; }; export const postApiVbyApiVersionRequestBodyQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionRequestBody", options) + createQueryKey('postApiVbyApiVersionRequestBody', options) ]; export const postApiVbyApiVersionRequestBodyOptions = (options?: Options) => { return queryOptions({ @@ -465,7 +465,7 @@ export const postApiVbyApiVersionRequestBodyMutation = () => { const mutationOpt }; return mutationOptions; }; export const postApiVbyApiVersionFormDataQueryKey = (options?: Options) => [ - createQueryKey("postApiVbyApiVersionFormData", options) + createQueryKey('postApiVbyApiVersionFormData', options) ]; export const postApiVbyApiVersionFormDataOptions = (options?: Options) => { return queryOptions({ @@ -491,7 +491,7 @@ export const postApiVbyApiVersionFormDataMutation = () => { const mutationOption }; return mutationOptions; }; export const callWithDefaultParametersQueryKey = (options?: Options) => [ - createQueryKey("callWithDefaultParameters", options) + createQueryKey('callWithDefaultParameters', options) ]; export const callWithDefaultParametersOptions = (options?: Options) => { return queryOptions({ @@ -507,7 +507,7 @@ export const callWithDefaultParametersOptions = (options?: Options) => [ - createQueryKey("callWithDefaultOptionalParameters", options) + createQueryKey('callWithDefaultOptionalParameters', options) ]; export const callWithDefaultOptionalParametersOptions = (options?: Options) => { return queryOptions({ @@ -543,7 +543,7 @@ export const callToTestOrderOfParamsMutation = () => { const mutationOptions: Us }; return mutationOptions; }; export const duplicateNameQueryKey = (options?: Options) => [ - createQueryKey("duplicateName", options) + createQueryKey('duplicateName', options) ]; export const duplicateNameOptions = (options?: Options) => { return queryOptions({ @@ -559,7 +559,7 @@ export const duplicateNameOptions = (options?: Options) => { return queryOptions }); }; export const duplicateName1QueryKey = (options?: Options) => [ - createQueryKey("duplicateName1", options) + createQueryKey('duplicateName1', options) ]; export const duplicateName1Options = (options?: Options) => { return queryOptions({ @@ -605,7 +605,7 @@ export const duplicateName3Mutation = () => { const mutationOptions: UseMutation }; return mutationOptions; }; export const callWithNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithNoContentResponse", options) + createQueryKey('callWithNoContentResponse', options) ]; export const callWithNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -621,7 +621,7 @@ export const callWithNoContentResponseOptions = (options?: Options) => { return }); }; export const callWithResponseAndNoContentResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponseAndNoContentResponse", options) + createQueryKey('callWithResponseAndNoContentResponse', options) ]; export const callWithResponseAndNoContentResponseOptions = (options?: Options) => { return queryOptions({ @@ -637,7 +637,7 @@ export const callWithResponseAndNoContentResponseOptions = (options?: Options) = }); }; export const dummyAQueryKey = (options?: Options) => [ - createQueryKey("dummyA", options) + createQueryKey('dummyA', options) ]; export const dummyAOptions = (options?: Options) => { return queryOptions({ @@ -653,7 +653,7 @@ export const dummyAOptions = (options?: Options) => { return queryOptions({ }); }; export const dummyBQueryKey = (options?: Options) => [ - createQueryKey("dummyB", options) + createQueryKey('dummyB', options) ]; export const dummyBOptions = (options?: Options) => { return queryOptions({ @@ -669,7 +669,7 @@ export const dummyBOptions = (options?: Options) => { return queryOptions({ }); }; export const callWithResponseQueryKey = (options?: Options) => [ - createQueryKey("callWithResponse", options) + createQueryKey('callWithResponse', options) ]; export const callWithResponseOptions = (options?: Options) => { return queryOptions({ @@ -685,7 +685,7 @@ export const callWithResponseOptions = (options?: Options) => { return queryOpti }); }; export const callWithDuplicateResponsesQueryKey = (options?: Options) => [ - createQueryKey("callWithDuplicateResponses", options) + createQueryKey('callWithDuplicateResponses', options) ]; export const callWithDuplicateResponsesOptions = (options?: Options) => { return queryOptions({ @@ -721,7 +721,7 @@ export const callWithResponsesMutation = () => { const mutationOptions: UseMutat }; return mutationOptions; }; export const collectionFormatQueryKey = (options: Options) => [ - createQueryKey("collectionFormat", options) + createQueryKey('collectionFormat', options) ]; export const collectionFormatOptions = (options: Options) => { return queryOptions({ @@ -737,7 +737,7 @@ export const collectionFormatOptions = (options: Options) }); }; export const typesQueryKey = (options: Options) => [ - createQueryKey("types", options) + createQueryKey('types', options) ]; export const typesOptions = (options: Options) => { return queryOptions({ @@ -753,7 +753,7 @@ export const typesOptions = (options: Options) => { return queryOptio }); }; export const uploadFileQueryKey = (options: Options) => [ - createQueryKey("uploadFile", options) + createQueryKey('uploadFile', options) ]; export const uploadFileOptions = (options: Options) => { return queryOptions({ @@ -779,7 +779,7 @@ export const uploadFileMutation = () => { const mutationOptions: UseMutationOpti }; return mutationOptions; }; export const fileResponseQueryKey = (options: Options) => [ - createQueryKey("fileResponse", options) + createQueryKey('fileResponse', options) ]; export const fileResponseOptions = (options: Options) => { return queryOptions({ @@ -795,7 +795,7 @@ export const fileResponseOptions = (options: Options) => { ret }); }; export const complexTypesQueryKey = (options: Options) => [ - createQueryKey("complexTypes", options) + createQueryKey('complexTypes', options) ]; export const complexTypesOptions = (options: Options) => { return queryOptions({ @@ -811,7 +811,7 @@ export const complexTypesOptions = (options: Options) => { ret }); }; export const multipartRequestQueryKey = (options?: Options) => [ - createQueryKey("multipartRequest", options) + createQueryKey('multipartRequest', options) ]; export const multipartRequestOptions = (options?: Options) => { return queryOptions({ @@ -837,7 +837,7 @@ export const multipartRequestMutation = () => { const mutationOptions: UseMutati }; return mutationOptions; }; export const multipartResponseQueryKey = (options?: Options) => [ - createQueryKey("multipartResponse", options) + createQueryKey('multipartResponse', options) ]; export const multipartResponseOptions = (options?: Options) => { return queryOptions({ @@ -863,7 +863,7 @@ export const complexParamsMutation = () => { const mutationOptions: UseMutationO }; return mutationOptions; }; export const callWithResultFromHeaderQueryKey = (options?: Options) => [ - createQueryKey("callWithResultFromHeader", options) + createQueryKey('callWithResultFromHeader', options) ]; export const callWithResultFromHeaderOptions = (options?: Options) => { return queryOptions({ @@ -889,7 +889,7 @@ export const callWithResultFromHeaderMutation = () => { const mutationOptions: U }; return mutationOptions; }; export const testErrorCodeQueryKey = (options: Options) => [ - createQueryKey("testErrorCode", options) + createQueryKey('testErrorCode', options) ]; export const testErrorCodeOptions = (options: Options) => { return queryOptions({ @@ -915,7 +915,7 @@ export const testErrorCodeMutation = () => { const mutationOptions: UseMutationO }; return mutationOptions; }; export const nonAsciiæøåÆøÅöôêÊ字符串QueryKey = (options: Options) => [ - createQueryKey("nonAsciiæøåÆøÅöôêÊ字符串", options) + createQueryKey('nonAsciiæøåÆøÅöôêÊ字符串', options) ]; export const nonAsciiæøåÆøÅöôêÊ字符串Options = (options: Options) => { return queryOptions({ diff --git a/packages/openapi-ts/test/performance.spec.ts b/packages/openapi-ts/test/performance.spec.ts index bfb4a6f92..98624af15 100644 --- a/packages/openapi-ts/test/performance.spec.ts +++ b/packages/openapi-ts/test/performance.spec.ts @@ -4,6 +4,7 @@ import { createClient } from '../src/index'; import { Performance } from '../src/utils/performance'; const V3_SPEC_PATH = './test/spec/v3.json'; +const V3_1_SPEC_PATH = './test/spec/3.1.0/full.json'; const OUTPUT_PREFIX = './test/generated/'; @@ -40,19 +41,19 @@ describe('performance', () => { expect(measures[0].duration).toBeLessThanOrEqual(500); }); - it('parses spec under 300ms (experimental)', async () => { + it('parses spec under 500ms (experimental)', async () => { Performance.clear(); await createClient({ client: '@hey-api/client-fetch', experimental_parser: true, - input: V3_SPEC_PATH, + input: V3_1_SPEC_PATH, output: toOutputPath('perf'), }); - Performance.measure('experimental_parser'); - const measures = Performance.getEntriesByName('experimental_parser'); + Performance.measure('parser'); + const measures = Performance.getEntriesByName('parser'); - expect(measures[0].duration).toBeLessThanOrEqual(300); + expect(measures[0].duration).toBeLessThanOrEqual(500); }); }); diff --git a/packages/openapi-ts/test/sample.cjs b/packages/openapi-ts/test/sample.cjs index d5c394e33..5f2e18160 100644 --- a/packages/openapi-ts/test/sample.cjs +++ b/packages/openapi-ts/test/sample.cjs @@ -11,19 +11,21 @@ const main = async () => { // debug: true, // experimental_parser: true, // input: './test/spec/v3-transforms.json', - input: './test/spec/v3.json', - // input: './test/spec/3.1.0/required-all-of-ref.json', + // input: './test/spec/v3.json', + input: './test/spec/3.1.0/full.json', // input: './test/spec/v2.json', // input: 'https://mongodb-mms-prod-build-server.s3.amazonaws.com/openapi/2caffd88277a4e27c95dcefc7e3b6a63a3b03297-v2-2023-11-15.json', // name: 'foo', output: { + format: 'prettier', + lint: 'eslint', path: './test/generated/sample/', }, - plugins: [ - // '@tanstack/react-query', - // '@hey-api/services', - 'zod', - ], + // plugins: [ + // '@tanstack/react-query', + // // '@hey-api/services', + // // 'zod', + // ], schemas: { export: false, }, @@ -36,7 +38,9 @@ const main = async () => { }, types: { // dates: 'types+transform', - // enums: 'javascript', + // enums: 'typescript', + // enums: 'typescript+namespace', + enums: 'javascript', // export: false, // include: // '^(_400|CompositionWithOneOfAndProperties)', diff --git a/packages/openapi-ts/test/spec/3.1.0/full.json b/packages/openapi-ts/test/spec/3.1.0/full.json new file mode 100644 index 000000000..6e8be8aa2 --- /dev/null +++ b/packages/openapi-ts/test/spec/3.1.0/full.json @@ -0,0 +1,3622 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "swagger", + "version": "v1.0" + }, + "servers": [ + { + "url": "http://localhost:3000/base" + } + ], + "paths": { + "/api/v{api-version}/no-tag": { + "tags": [], + "get": { + "operationId": "export" + }, + "post": { + "operationId": "import", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "oneOf": [ + { + "$ref": "#/components/schemas/ModelWithReadOnlyAndWriteOnly" + }, + { + "$ref": "#/components/schemas/ModelWithArrayReadOnlyAndWriteOnly" + } + ] + } + } + } + }, + "responses": { + "default": { + "description": "Default success response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithReadOnlyAndWriteOnly" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json; type=collection": { + "schema": { + "$ref": "#/components/schemas/Model-From.Zendesk" + } + } + } + } + } + } + }, + "/api/v{api-version}/simple/$count": { + "get": { + "tags": ["Simple"], + "operationId": "api/v{version}/ODataController/$count", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json; type=collection": { + "schema": { + "$ref": "#/components/schemas/Model-From.Zendesk" + } + } + } + } + } + } + }, + "/api/v{api-version}/simple:operation": { + "get": { + "parameters": [ + { + "description": "foo in method", + "in": "path", + "name": "foo_param", + "required": true, + "schema": { + "oneOf": [ + { + "type": "string" + }, + { + "format": "uuid", + "type": "string" + } + ] + } + } + ], + "responses": { + "default": { + "description": "Default error response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithBoolean" + } + } + } + }, + "200": { + "description": "Response is a simple number", + "content": { + "application/json": { + "schema": { + "type": "number" + } + } + } + } + } + } + }, + "/api/v{api-version}/simple": { + "get": { + "tags": ["Simple"], + "operationId": "GetCallWithoutParametersAndResponse" + }, + "put": { + "tags": ["Simple"], + "operationId": "PutCallWithoutParametersAndResponse" + }, + "post": { + "tags": ["Simple"], + "operationId": "PostCallWithoutParametersAndResponse" + }, + "delete": { + "tags": ["Simple"], + "operationId": "DeleteCallWithoutParametersAndResponse" + }, + "options": { + "tags": ["Simple"], + "operationId": "OptionsCallWithoutParametersAndResponse" + }, + "head": { + "tags": ["Simple"], + "operationId": "HeadCallWithoutParametersAndResponse" + }, + "patch": { + "tags": ["Simple"], + "operationId": "PatchCallWithoutParametersAndResponse" + } + }, + "/api/v{api-version}/foo/{foo_param}/bar/{BarParam}": { + "delete": { + "tags": ["Parameters"], + "operationId": "deleteFoo", + "parameters": [ + { + "description": "foo in method", + "in": "path", + "name": "foo_param", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "bar in method", + "in": "path", + "name": "BarParam", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Parameter with illegal characters", + "name": "x-Foo-Bar", + "in": "header", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithString" + } + } + } + } + ] + }, + "parameters": [ + { + "description": "foo in global parameters", + "in": "path", + "name": "foo_param", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "bar in global parameters", + "in": "path", + "name": "BarParam", + "required": true, + "schema": { + "type": "string" + } + } + ] + }, + "/api/v{api-version}/descriptions/": { + "post": { + "tags": ["Descriptions"], + "operationId": "CallWithDescriptions", + "parameters": [ + { + "description": "Testing multiline comments in string: First line\nSecond line\n\nFourth line", + "name": "parameterWithBreaks", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "description": "Testing backticks in string: `backticks` and ```multiple backticks``` should work", + "name": "parameterWithBackticks", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "description": "Testing slashes in string: \\backwards\\\\\\ and /forwards/// should work", + "name": "parameterWithSlashes", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "description": "Testing expression placeholders in string: ${expression} should work", + "name": "parameterWithExpressionPlaceholders", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "description": "Testing quotes in string: 'single quote''' and \"double quotes\"\"\" should work", + "name": "parameterWithQuotes", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "description": "Testing reserved characters in string: /* inline */ and /** inline **/ should work", + "name": "parameterWithReservedCharacters", + "in": "query", + "schema": { + "type": "string" + } + } + ] + } + }, + "/api/v{api-version}/parameters/deprecated": { + "post": { + "tags": ["Deprecated"], + "deprecated": true, + "operationId": "DeprecatedCall", + "parameters": [ + { + "deprecated": true, + "description": "This parameter is deprecated", + "name": "parameter", + "in": "header", + "required": true, + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/DeprecatedModel" + }, + { + "type": "null" + } + ] + } + } + ] + } + }, + "/api/v{api-version}/parameters/{parameterPath}": { + "post": { + "tags": ["Parameters"], + "operationId": "CallWithParameters", + "parameters": [ + { + "description": "This is the parameter that goes into the header", + "name": "parameterHeader", + "in": "header", + "required": true, + "schema": { + "type": ["string", "null"] + } + }, + { + "required": false, + "schema": { + "$ref": "#/components/schemas/ModelWithNestedArrayEnumsDataFoo" + }, + "name": "foo_ref_enum", + "in": "query" + }, + { + "required": true, + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ModelWithNestedArrayEnumsDataFoo" + } + ] + }, + "name": "foo_all_of_enum", + "in": "query" + }, + { + "description": "This is the parameter that goes into the query params", + "name": "cursor", + "in": "query", + "required": true, + "schema": { + "type": ["string", "null"] + } + }, + { + "description": "This is the parameter that goes into the cookie", + "name": "parameterCookie", + "in": "cookie", + "required": true, + "schema": { + "type": ["string", "null"] + } + }, + { + "description": "This is the parameter that goes into the path", + "name": "parameterPath", + "in": "path", + "required": true, + "schema": { + "type": ["string", "null"] + } + }, + { + "description": "api-version should be required in standalone clients", + "name": "api-version", + "in": "path", + "required": true, + "schema": { + "type": ["string", "null"] + } + } + ], + "requestBody": { + "description": "This is the parameter that goes into the body", + "required": true, + "content": { + "application/json": { + "schema": { + "properties": {}, + "type": ["object", "null"] + } + } + } + } + } + }, + "/api/v{api-version}/parameters/{parameter.path.1}/{parameter-path-2}/{PARAMETER-PATH-3}": { + "post": { + "tags": ["Parameters"], + "operationId": "CallWithWeirdParameterNames", + "parameters": [ + { + "description": "This is the parameter that goes into the path", + "name": "parameter.path.1", + "in": "path", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "This is the parameter that goes into the path", + "name": "parameter-path-2", + "in": "path", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "This is the parameter that goes into the path", + "name": "PARAMETER-PATH-3", + "in": "path", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "This is the parameter with a reserved keyword", + "name": "default", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "This is the parameter that goes into the request header", + "name": "parameter.header", + "in": "header", + "required": true, + "schema": { + "type": ["string", "null"] + } + }, + { + "description": "This is the parameter that goes into the request query params", + "name": "parameter-query", + "in": "query", + "required": true, + "schema": { + "type": ["string", "null"] + } + }, + { + "description": "This is the parameter that goes into the cookie", + "name": "PARAMETER-COOKIE", + "in": "cookie", + "required": true, + "schema": { + "type": ["string", "null"] + } + }, + { + "description": "api-version should be required in standalone clients", + "name": "api-version", + "in": "path", + "required": true, + "schema": { + "type": ["string", "null"] + } + } + ], + "requestBody": { + "description": "This is the parameter that goes into the body", + "required": true, + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/ModelWithString" + }, + { + "type": "null" + } + ] + } + } + } + } + } + }, + "/api/v{api-version}/parameters/": { + "get": { + "tags": ["Parameters"], + "operationId": "GetCallWithOptionalParam", + "parameters": [ + { + "description": "This is an optional parameter", + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "number" + } + } + ], + "requestBody": { + "description": "This is a required parameter", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithOneOfEnum" + } + } + } + } + }, + "post": { + "tags": ["Parameters"], + "operationId": "PostCallWithOptionalParam", + "parameters": [ + { + "description": "This is a required parameter", + "name": "parameter", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/Pageable" + } + } + ], + "requestBody": { + "description": "This is an optional parameter", + "required": false, + "content": { + "application/json": { + "schema": { + "properties": { + "offset": { + "required": true, + "type": ["number", "null"] + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Response is a simple number", + "content": { + "application/json": { + "schema": { + "type": "number" + } + } + } + }, + "204": { + "description": "Success" + } + } + } + }, + "/api/v{api-version}/requestBody/": { + "post": { + "tags": ["RequestBody"], + "parameters": [ + { + "$ref": "#/components/parameters/SimpleParameter" + } + ], + "requestBody": { + "$ref": "#/components/requestBodies/SimpleRequestBody" + } + } + }, + "/api/v{api-version}/formData/": { + "post": { + "tags": ["FormData"], + "parameters": [ + { + "$ref": "#/components/parameters/SimpleParameter" + } + ], + "requestBody": { + "$ref": "#/components/requestBodies/SimpleFormData" + } + } + }, + "/api/v{api-version}/defaults": { + "get": { + "tags": ["Defaults"], + "operationId": "CallWithDefaultParameters", + "parameters": [ + { + "description": "This is a simple string with default value", + "name": "parameterString", + "in": "query", + "schema": { + "default": "Hello World!", + "type": ["string", "null"] + } + }, + { + "description": "This is a simple number with default value", + "name": "parameterNumber", + "in": "query", + "schema": { + "default": 123, + "type": ["number", "null"] + } + }, + { + "description": "This is a simple boolean with default value", + "name": "parameterBoolean", + "in": "query", + "schema": { + "default": true, + "type": ["boolean", "null"] + } + }, + { + "description": "This is a simple enum with default value", + "name": "parameterEnum", + "in": "query", + "schema": { + "enum": ["Success", "Warning", "Error"], + "default": 0 + } + }, + { + "description": "This is a simple model with default value", + "name": "parameterModel", + "in": "query", + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/ModelWithString", + "default": { + "prop": "Hello World!" + } + }, + { + "type": "null" + } + ] + } + } + ] + }, + "post": { + "tags": ["Defaults"], + "operationId": "CallWithDefaultOptionalParameters", + "parameters": [ + { + "description": "This is a simple string that is optional with default value", + "name": "parameterString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "Hello World!" + } + }, + { + "description": "This is a simple number that is optional with default value", + "name": "parameterNumber", + "in": "query", + "required": false, + "schema": { + "type": "number", + "default": 123 + } + }, + { + "description": "This is a simple boolean that is optional with default value", + "name": "parameterBoolean", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + }, + { + "description": "This is a simple enum that is optional with default value", + "name": "parameterEnum", + "in": "query", + "required": false, + "schema": { + "enum": ["Success", "Warning", "Error"], + "default": 0 + } + }, + { + "description": "This is a simple model that is optional with default value", + "name": "parameterModel", + "in": "query", + "required": false, + "schema": { + "$ref": "#/components/schemas/ModelWithString", + "default": { + "prop": "Hello World!" + } + } + } + ] + }, + "put": { + "tags": ["Defaults"], + "operationId": "CallToTestOrderOfParams", + "parameters": [ + { + "description": "This is a optional string with default", + "name": "parameterOptionalStringWithDefault", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "Hello World!" + } + }, + { + "description": "This is a optional string with empty default", + "name": "parameterOptionalStringWithEmptyDefault", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "" + } + }, + { + "description": "This is a optional string with no default", + "name": "parameterOptionalStringWithNoDefault", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "This is a string with default", + "name": "parameterStringWithDefault", + "in": "query", + "required": true, + "schema": { + "type": "string", + "default": "Hello World!" + } + }, + { + "description": "This is a string with empty default", + "name": "parameterStringWithEmptyDefault", + "in": "query", + "required": true, + "schema": { + "type": "string", + "default": "" + } + }, + { + "description": "This is a string with no default", + "name": "parameterStringWithNoDefault", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "This is a string that can be null with no default", + "name": "parameterStringNullableWithNoDefault", + "in": "query", + "required": false, + "schema": { + "type": ["string", "null"] + } + }, + { + "description": "This is a string that can be null with default", + "name": "parameterStringNullableWithDefault", + "in": "query", + "required": false, + "schema": { + "default": null, + "type": ["string", "null"] + } + } + ] + } + }, + "/api/v{api-version}/duplicate": { + "get": { + "tags": ["Duplicate"], + "operationId": "DuplicateName" + }, + "post": { + "tags": ["Duplicate"], + "operationId": "DuplicateName" + }, + "put": { + "tags": ["Duplicate"], + "operationId": "DuplicateName" + }, + "delete": { + "tags": ["Duplicate"], + "operationId": "DuplicateName" + } + }, + "/api/v{api-version}/no-content": { + "get": { + "tags": ["NoContent"], + "operationId": "CallWithNoContentResponse", + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/api/v{api-version}/multiple-tags/response-and-no-content": { + "get": { + "tags": ["Response", "NoContent"], + "operationId": "CallWithResponseAndNoContentResponse", + "responses": { + "200": { + "description": "Response is a simple number", + "content": { + "application/json": { + "schema": { + "type": "number" + } + } + } + }, + "204": { + "description": "Success" + } + } + } + }, + "/api/v{api-version}/multiple-tags/a": { + "get": { + "tags": ["MultipleTags1", "MultipleTags2"], + "operationId": "DummyA", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400" + } + } + } + } + } + } + }, + "/api/v{api-version}/multiple-tags/b": { + "get": { + "tags": ["MultipleTags1", "MultipleTags2", "MultipleTags3"], + "operationId": "DummyB", + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/api/v{api-version}/response": { + "get": { + "tags": ["Response"], + "operationId": "CallWithResponse", + "responses": { + "default": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/import" + } + } + } + } + } + }, + "post": { + "tags": ["Response"], + "operationId": "CallWithDuplicateResponses", + "responses": { + "default": { + "description": "Default error response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithBoolean" + } + } + } + }, + "200": { + "description": "Message for 200 response", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ModelWithBoolean" + }, + { + "$ref": "#/components/schemas/ModelWithInteger" + } + ] + } + } + } + }, + "201": { + "description": "Message for 201 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithString" + } + } + } + }, + "202": { + "description": "Message for 202 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithString" + } + } + } + }, + "4XX": { + "description": "Message for 4XX errors", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DictionaryWithArray" + } + } + } + }, + "500": { + "description": "Message for 500 error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithStringError" + } + } + } + }, + "501": { + "description": "Message for 501 error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithStringError" + } + } + } + }, + "502": { + "description": "Message for 502 error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithStringError" + } + } + } + } + } + }, + "put": { + "tags": ["Response"], + "operationId": "CallWithResponses", + "responses": { + "default": { + "description": "Message for default response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithStringError" + } + } + } + }, + "200": { + "description": "Message for 200 response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "@namespace.string": { + "type": "string", + "readOnly": true + }, + "@namespace.integer": { + "type": "integer", + "readOnly": true + }, + "value": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelWithString" + }, + "readOnly": true + } + } + } + } + } + }, + "201": { + "description": "Message for 201 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelThatExtends" + } + } + } + }, + "202": { + "description": "Message for 202 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelThatExtendsExtends" + } + } + } + }, + "500": { + "description": "Message for 500 error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithStringError" + } + } + } + }, + "501": { + "description": "Message for 501 error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithStringError" + } + } + } + }, + "502": { + "description": "Message for 502 error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithStringError" + } + } + } + } + } + } + }, + "/api/v{api-version}/collectionFormat": { + "get": { + "tags": ["CollectionFormat"], + "operationId": "CollectionFormat", + "parameters": [ + { + "description": "This is an array parameter that is sent as csv format (comma-separated values)", + "name": "parameterArrayCSV", + "in": "query", + "required": true, + "schema": { + "type": ["array", "null"], + "items": { + "type": "string" + } + }, + "collectionFormat": "csv" + }, + { + "description": "This is an array parameter that is sent as ssv format (space-separated values)", + "name": "parameterArraySSV", + "in": "query", + "required": true, + "schema": { + "type": ["array", "null"], + "items": { + "type": "string" + } + }, + "collectionFormat": "ssv" + }, + { + "description": "This is an array parameter that is sent as tsv format (tab-separated values)", + "name": "parameterArrayTSV", + "in": "query", + "required": true, + "schema": { + "type": ["array", "null"], + "items": { + "type": "string" + } + }, + "collectionFormat": "tsv" + }, + { + "description": "This is an array parameter that is sent as pipes format (pipe-separated values)", + "name": "parameterArrayPipes", + "in": "query", + "required": true, + "schema": { + "type": ["array", "null"], + "items": { + "type": "string" + } + }, + "collectionFormat": "pipes" + }, + { + "description": "This is an array parameter that is sent as multi format (multiple parameter instances)", + "name": "parameterArrayMulti", + "in": "query", + "required": true, + "schema": { + "type": ["array", "null"], + "items": { + "type": "string" + } + }, + "collectionFormat": "multi" + } + ] + } + }, + "/api/v{api-version}/types": { + "get": { + "tags": ["Types"], + "operationId": "Types", + "parameters": [ + { + "description": "This is a number parameter", + "name": "parameterNumber", + "in": "query", + "required": true, + "schema": { + "type": "number", + "default": 123 + } + }, + { + "description": "This is a string parameter", + "name": "parameterString", + "in": "query", + "required": true, + "schema": { + "type": ["string", "null"], + "default": "default" + } + }, + { + "description": "This is a boolean parameter", + "name": "parameterBoolean", + "in": "query", + "required": true, + "schema": { + "type": ["boolean", "null"], + "default": true + } + }, + { + "description": "This is an object parameter", + "name": "parameterObject", + "in": "query", + "required": true, + "schema": { + "type": ["object", "null"], + "default": null + } + }, + { + "description": "This is an array parameter", + "name": "parameterArray", + "in": "query", + "required": true, + "schema": { + "type": ["array", "null"], + "items": { + "type": "string" + } + } + }, + { + "description": "This is a dictionary parameter", + "name": "parameterDictionary", + "in": "query", + "required": true, + "schema": { + "type": ["object", "null"], + "items": { + "type": "string" + } + } + }, + { + "description": "This is an enum parameter", + "name": "parameterEnum", + "in": "query", + "required": true, + "schema": { + "oneOf": [ + { + "enum": ["Success", "Warning", "Error"] + }, + { + "type": "null" + } + ] + } + }, + { + "description": "This is a number parameter", + "name": "id", + "in": "path", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Response is a simple number", + "content": { + "application/json": { + "schema": { + "type": "number" + } + } + } + }, + "201": { + "description": "Response is a simple string", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "202": { + "description": "Response is a simple boolean", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "203": { + "description": "Response is a simple object", + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/api/v{api-version}/upload": { + "post": { + "tags": ["Upload"], + "operationId": "UploadFile", + "parameters": [ + { + "description": "api-version should be required in standalone clients", + "name": "api-version", + "in": "path", + "required": true, + "schema": { + "type": ["string", "null"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "description": "Supply a file reference for upload", + "schema": { + "format": "binary", + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + } + } + }, + "/api/v{api-version}/file/{id}": { + "get": { + "tags": ["FileResponse"], + "operationId": "FileResponse", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "api-version should be required in standalone clients", + "name": "api-version", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "audio/*": { + "schema": { + "format": "binary", + "type": "string" + } + }, + "video/*": { + "schema": { + "format": "binary", + "type": "string" + } + } + } + } + } + } + }, + "/api/v{api-version}/complex": { + "get": { + "tags": ["Complex"], + "operationId": "ComplexTypes", + "parameters": [ + { + "description": "Parameter containing object", + "name": "parameterObject", + "in": "query", + "required": true, + "schema": { + "type": "object", + "properties": { + "first": { + "type": "object", + "properties": { + "second": { + "type": "object", + "properties": { + "third": { + "type": "string" + } + } + } + } + } + } + } + }, + { + "description": "Parameter containing reference", + "name": "parameterReference", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/ModelWithString" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelWithString" + } + } + } + } + }, + "400": { + "description": "400 `server` error" + }, + "500": { + "description": "500 server error" + } + } + } + }, + "/api/v{api-version}/multipart": { + "post": { + "tags": ["multipart"], + "operationId": "MultipartRequest", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "content": { + "type": "string", + "format": "binary" + }, + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/ModelWithString" + }, + { + "type": "null" + } + ] + } + } + }, + "encoding": { + "content": { + "style": "form" + }, + "data": { + "style": "form" + } + } + } + } + } + }, + "get": { + "tags": ["multipart"], + "operationId": "MultipartResponse", + "responses": { + "200": { + "description": "OK", + "content": { + "multipart/mixed": { + "schema": { + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "metadata": { + "type": "object", + "properties": { + "foo": { + "type": "string" + }, + "bar": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + }, + "/api/v{api-version}/complex/{id}": { + "put": { + "tags": ["Complex"], + "operationId": "ComplexParams", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "description": "api-version should be required in standalone clients", + "name": "api-version", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json-patch+json": { + "schema": { + "required": ["key", "name", "parameters", "type"], + "type": "object", + "properties": { + "key": { + "maxLength": 64, + "pattern": "^[a-zA-Z0-9_]*$", + "type": ["string", "null"], + "readOnly": true + }, + "name": { + "maxLength": 255, + "type": ["string", "null"] + }, + "enabled": { + "type": "boolean", + "default": true + }, + "type": { + "enum": ["Monkey", "Horse", "Bird"], + "type": "string", + "readOnly": true + }, + "listOfModels": { + "type": ["array", "null"], + "items": { + "$ref": "#/components/schemas/ModelWithString" + } + }, + "listOfStrings": { + "type": ["array", "null"], + "items": { + "type": "string" + } + }, + "parameters": { + "type": "object", + "oneOf": [ + { + "$ref": "#/components/schemas/ModelWithString" + }, + { + "$ref": "#/components/schemas/ModelWithEnum" + }, + { + "$ref": "#/components/schemas/ModelWithArray" + }, + { + "$ref": "#/components/schemas/ModelWithDictionary" + } + ] + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "name": { + "type": ["string", "null"], + "readOnly": true + } + }, + "readOnly": true + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json; type=collection": { + "schema": { + "$ref": "#/components/schemas/ModelWithString" + } + } + } + } + } + } + }, + "/api/v{api-version}/header": { + "post": { + "tags": ["Header"], + "operationId": "CallWithResultFromHeader", + "responses": { + "200": { + "description": "Successful response", + "headers": { + "operation-location": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "400 server error" + }, + "500": { + "description": "500 server error" + } + } + } + }, + "/api/v{api-version}/error": { + "post": { + "tags": ["Error"], + "operationId": "testErrorCode", + "parameters": [ + { + "description": "Status code to return", + "name": "status", + "in": "query", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Custom message: Successful response" + }, + "500": { + "description": "Custom message: Internal Server Error" + }, + "501": { + "description": "Custom message: Not Implemented" + }, + "502": { + "description": "Custom message: Bad Gateway" + }, + "503": { + "description": "Custom message: Service Unavailable" + } + } + } + }, + "/api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串": { + "post": { + "tags": ["Non-Ascii-æøåÆØÅöôêÊ"], + "operationId": "nonAsciiæøåÆØÅöôêÊ字符串", + "parameters": [ + { + "description": "Dummy input param", + "name": "nonAsciiParamæøåÆØÅöôêÊ", + "in": "query", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NonAsciiStringæøåÆØÅöôêÊ字符串" + } + } + } + } + } + } + }, + "put": { + "tags": ["Non-Ascii-æøåÆØÅöôêÊ"], + "summary": "Login User", + "operationId": "putWithFormUrlEncoded", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/ArrayWithStrings" + } + } + }, + "required": true + } + } + } + }, + "components": { + "requestBodies": { + "SimpleRequestBody": { + "x-body-name": "foo", + "description": "A reusable request body", + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithString" + } + } + } + }, + "SimpleFormData": { + "description": "A reusable request body", + "required": false, + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/ModelWithString" + } + } + } + } + }, + "parameters": { + "SimpleParameter": { + "description": "This is a reusable parameter", + "name": "parameter", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + "x-Foo-Bar": { + "description": "Parameter with illegal characters", + "name": "x-Foo-Bar", + "in": "header", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithString" + } + } + } + } + }, + "schemas": { + "camelCaseCommentWithBreaks": { + "description": "Testing multiline comments in string: First line\nSecond line\n\nFourth line", + "type": "integer" + }, + "CommentWithBreaks": { + "description": "Testing multiline comments in string: First line\nSecond line\n\nFourth line", + "type": "integer" + }, + "CommentWithBackticks": { + "description": "Testing backticks in string: `backticks` and ```multiple backticks``` should work", + "type": "integer" + }, + "CommentWithBackticksAndQuotes": { + "description": "Testing backticks and quotes in string: `backticks`, 'quotes', \"double quotes\" and ```multiple backticks``` should work", + "type": "integer" + }, + "CommentWithSlashes": { + "description": "Testing slashes in string: \\backwards\\\\\\ and /forwards/// should work", + "type": "integer" + }, + "CommentWithExpressionPlaceholders": { + "description": "Testing expression placeholders in string: ${expression} should work", + "type": "integer" + }, + "CommentWithQuotes": { + "description": "Testing quotes in string: 'single quote''' and \"double quotes\"\"\" should work", + "type": "integer" + }, + "CommentWithReservedCharacters": { + "description": "Testing reserved characters in string: /* inline */ and /** inline **/ should work", + "type": "integer" + }, + "SimpleInteger": { + "description": "This is a simple number", + "type": "integer" + }, + "SimpleBoolean": { + "description": "This is a simple boolean", + "type": "boolean" + }, + "SimpleString": { + "description": "This is a simple string", + "type": "string" + }, + "NonAsciiStringæøåÆØÅöôêÊ字符串": { + "description": "A string with non-ascii (unicode) characters valid in typescript identifiers (æøåÆØÅöÔèÈ字符串)", + "type": "string" + }, + "SimpleFile": { + "description": "This is a simple file", + "format": "binary", + "type": "string" + }, + "SimpleReference": { + "description": "This is a simple reference", + "$ref": "#/components/schemas/ModelWithString" + }, + "SimpleStringWithPattern": { + "description": "This is a simple string", + "maxLength": 64, + "pattern": "^[a-zA-Z0-9_]*$", + "type": ["string", "null"] + }, + "EnumWithStrings": { + "description": "This is a simple enum with strings", + "enum": [ + "Success", + "Warning", + "Error", + "'Single Quote'", + "\"Double Quotes\"", + "Non-ascii: øæåôöØÆÅÔÖ字符串" + ] + }, + "EnumWithReplacedCharacters": { + "enum": [ + "'Single Quote'", + "\"Double Quotes\"", + "øæåôöØÆÅÔÖ字符串", + 3.1, + "" + ], + "type": "string" + }, + "EnumWithNumbers": { + "description": "This is a simple enum with numbers", + "enum": [ + 1, 2, 3, 1.1, 1.2, 1.3, 100, 200, 300, -100, -200, -300, -1.1, -1.2, + -1.3 + ], + "default": 200 + }, + "EnumFromDescription": { + "description": "Success=1,Warning=2,Error=3", + "type": "number" + }, + "EnumWithExtensions": { + "description": "This is a simple enum with numbers", + "enum": [200, 400, 500], + "x-enum-varnames": ["CUSTOM_SUCCESS", "CUSTOM_WARNING", "CUSTOM_ERROR"], + "x-enum-descriptions": [ + "Used when the status of something is successful", + "Used when the status of something has a warning", + "Used when the status of something has an error" + ] + }, + "EnumWithXEnumNames": { + "enum": [0, 1, 2], + "x-enumNames": ["zero", "one", "two"] + }, + "ArrayWithNumbers": { + "description": "This is a simple array with numbers", + "type": "array", + "items": { + "type": "integer" + } + }, + "ArrayWithBooleans": { + "description": "This is a simple array with booleans", + "type": "array", + "items": { + "type": "boolean" + } + }, + "ArrayWithStrings": { + "description": "This is a simple array with strings", + "type": "array", + "items": { + "type": "string" + }, + "default": ["test"] + }, + "ArrayWithReferences": { + "description": "This is a simple array with references", + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelWithString" + } + }, + "ArrayWithArray": { + "description": "This is a simple array containing an array", + "type": "array", + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelWithString" + } + } + }, + "ArrayWithProperties": { + "description": "This is a simple array with properties", + "type": "array", + "items": { + "type": "object", + "properties": { + "16x16": { + "$ref": "#/components/schemas/camelCaseCommentWithBreaks" + }, + "bar": { + "type": "string" + } + } + } + }, + "ArrayWithAnyOfProperties": { + "description": "This is a simple array with any of properties", + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "foo": { + "type": "string", + "default": "test" + } + } + }, + { + "type": "object", + "properties": { + "bar": { + "type": "string" + } + } + } + ] + } + }, + "AnyOfAnyAndNull": { + "type": "object", + "properties": { + "data": { + "anyOf": [ + {}, + { + "type": "null" + } + ] + } + } + }, + "AnyOfArrays": { + "description": "This is a simple array with any of properties", + "type": "object", + "properties": { + "results": { + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "foo": { + "type": "string" + } + } + }, + { + "type": "object", + "properties": { + "bar": { + "type": "string" + } + } + } + ] + }, + "type": "array" + } + } + }, + "DictionaryWithString": { + "description": "This is a string dictionary", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "DictionaryWithPropertiesAndAdditionalProperties": { + "type": "object", + "properties": { + "foo": { + "type": "number" + }, + "bar": { + "type": "boolean" + } + }, + "additionalProperties": { + "type": "string" + } + }, + "DictionaryWithReference": { + "description": "This is a string reference", + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/ModelWithString" + } + }, + "DictionaryWithArray": { + "description": "This is a complex dictionary", + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelWithString" + } + } + }, + "DictionaryWithDictionary": { + "description": "This is a string dictionary", + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "DictionaryWithProperties": { + "description": "This is a complex dictionary", + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "foo": { + "type": "string" + }, + "bar": { + "type": "string" + } + } + } + }, + "ModelWithInteger": { + "description": "This is a model with one number property", + "type": "object", + "properties": { + "prop": { + "description": "This is a simple number property", + "type": "integer" + } + } + }, + "ModelWithBoolean": { + "description": "This is a model with one boolean property", + "type": "object", + "properties": { + "prop": { + "description": "This is a simple boolean property", + "type": "boolean" + } + } + }, + "ModelWithString": { + "description": "This is a model with one string property", + "type": "object", + "properties": { + "prop": { + "description": "This is a simple string property", + "type": "string" + } + } + }, + "ModelWithStringError": { + "description": "This is a model with one string property", + "type": "object", + "properties": { + "prop": { + "description": "This is a simple string property", + "type": "string" + } + } + }, + "Model-From.Zendesk": { + "description": "`Comment` or `VoiceComment`. The JSON object for adding voice comments to tickets is different. See [Adding voice comments to tickets](/documentation/ticketing/managing-tickets/adding-voice-comments-to-tickets)", + "type": "string" + }, + "ModelWithNullableString": { + "description": "This is a model with one string property", + "type": "object", + "required": ["nullableRequiredProp1", "nullableRequiredProp2"], + "properties": { + "nullableProp1": { + "description": "This is a simple string property", + "type": ["string", "null"] + }, + "nullableRequiredProp1": { + "description": "This is a simple string property", + "type": ["string", "null"] + }, + "nullableProp2": { + "description": "This is a simple string property", + "type": ["string", "null"] + }, + "nullableRequiredProp2": { + "description": "This is a simple string property", + "type": ["string", "null"] + }, + "foo_bar-enum": { + "description": "This is a simple enum with strings", + "enum": ["Success", "Warning", "Error", "ØÆÅ字符串"] + } + } + }, + "ModelWithEnum": { + "description": "This is a model with one enum", + "type": "object", + "properties": { + "foo_bar-enum": { + "description": "This is a simple enum with strings", + "enum": ["Success", "Warning", "Error", "ØÆÅ字符串"] + }, + "statusCode": { + "description": "These are the HTTP error code enums", + "enum": [ + "100", + "200 FOO", + "300 FOO_BAR", + "400 foo-bar", + "500 foo.bar", + "600 foo&bar" + ] + }, + "bool": { + "description": "Simple boolean enum", + "type": "boolean", + "enum": [true] + } + } + }, + "ModelWithEnumWithHyphen": { + "description": "This is a model with one enum with escaped name", + "type": "object", + "properties": { + "foo-bar-baz-qux": { + "type": "string", + "enum": ["3.0"], + "title": "Foo-Bar-Baz-Qux", + "default": "3.0" + } + } + }, + "ModelWithEnumFromDescription": { + "description": "This is a model with one enum", + "type": "object", + "properties": { + "test": { + "type": "integer", + "description": "Success=1,Warning=2,Error=3" + } + } + }, + "ModelWithNestedEnums": { + "description": "This is a model with nested enums", + "type": "object", + "properties": { + "dictionaryWithEnum": { + "type": "object", + "additionalProperties": { + "enum": ["Success", "Warning", "Error"] + } + }, + "dictionaryWithEnumFromDescription": { + "type": "object", + "additionalProperties": { + "type": "integer", + "description": "Success=1,Warning=2,Error=3" + } + }, + "arrayWithEnum": { + "type": "array", + "items": { + "enum": ["Success", "Warning", "Error"] + } + }, + "arrayWithDescription": { + "type": "array", + "items": { + "type": "integer", + "description": "Success=1,Warning=2,Error=3" + } + }, + "foo_bar-enum": { + "description": "This is a simple enum with strings", + "enum": ["Success", "Warning", "Error", "ØÆÅ字符串"] + } + } + }, + "ModelWithReference": { + "description": "This is a model with one property containing a reference", + "type": "object", + "properties": { + "prop": { + "$ref": "#/components/schemas/ModelWithProperties" + } + } + }, + "ModelWithArrayReadOnlyAndWriteOnly": { + "description": "This is a model with one property containing an array", + "type": "object", + "properties": { + "prop": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelWithReadOnlyAndWriteOnly" + } + }, + "propWithFile": { + "type": "array", + "items": { + "format": "binary", + "type": "string" + } + }, + "propWithNumber": { + "type": "array", + "items": { + "type": "number" + } + } + } + }, + "ModelWithArray": { + "description": "This is a model with one property containing an array", + "type": "object", + "properties": { + "prop": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelWithString" + } + }, + "propWithFile": { + "type": "array", + "items": { + "format": "binary", + "type": "string" + } + }, + "propWithNumber": { + "type": "array", + "items": { + "type": "number" + } + } + } + }, + "ModelWithDictionary": { + "description": "This is a model with one property containing a dictionary", + "type": "object", + "properties": { + "prop": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "DeprecatedModel": { + "deprecated": true, + "description": "This is a deprecated model with a deprecated property", + "type": "object", + "properties": { + "prop": { + "deprecated": true, + "description": "This is a deprecated property", + "type": "string" + } + } + }, + "ModelWithCircularReference": { + "description": "This is a model with one property containing a circular reference", + "type": "object", + "properties": { + "prop": { + "$ref": "#/components/schemas/ModelWithCircularReference" + } + } + }, + "CompositionWithOneOf": { + "description": "This is a model with one property with a 'one of' relationship", + "type": "object", + "properties": { + "propA": { + "type": "object", + "oneOf": [ + { + "$ref": "#/components/schemas/ModelWithString" + }, + { + "$ref": "#/components/schemas/ModelWithEnum" + }, + { + "$ref": "#/components/schemas/ModelWithArray" + }, + { + "$ref": "#/components/schemas/ModelWithDictionary" + } + ] + } + } + }, + "CompositionWithOneOfAnonymous": { + "description": "This is a model with one property with a 'one of' relationship where the options are not $ref", + "type": "object", + "properties": { + "propA": { + "type": "object", + "oneOf": [ + { + "description": "Anonymous object type", + "type": "object", + "properties": { + "propA": { + "type": "string" + } + } + }, + { + "description": "Anonymous string type", + "type": "string" + }, + { + "description": "Anonymous integer type", + "type": "integer" + } + ] + } + } + }, + "ModelCircle": { + "description": "Circle", + "type": "object", + "required": ["kind"], + "properties": { + "kind": { + "type": "string" + }, + "radius": { + "type": "number" + } + } + }, + "ModelSquare": { + "description": "Square", + "type": "object", + "required": ["kind"], + "properties": { + "kind": { + "type": "string" + }, + "sideLength": { + "type": "number" + } + } + }, + "CompositionWithOneOfDiscriminator": { + "description": "This is a model with one property with a 'one of' relationship where the options are not $ref", + "type": "object", + "oneOf": [ + { + "$ref": "#/components/schemas/ModelCircle" + }, + { + "$ref": "#/components/schemas/ModelSquare" + } + ], + "discriminator": { + "propertyName": "kind", + "mapping": { + "circle": "#/components/schemas/ModelCircle", + "square": "#/components/schemas/ModelSquare" + } + } + }, + "CompositionWithAnyOf": { + "description": "This is a model with one property with a 'any of' relationship", + "type": "object", + "properties": { + "propA": { + "type": "object", + "anyOf": [ + { + "$ref": "#/components/schemas/ModelWithString" + }, + { + "$ref": "#/components/schemas/ModelWithEnum" + }, + { + "$ref": "#/components/schemas/ModelWithArray" + }, + { + "$ref": "#/components/schemas/ModelWithDictionary" + } + ] + } + } + }, + "CompositionWithAnyOfAnonymous": { + "description": "This is a model with one property with a 'any of' relationship where the options are not $ref", + "type": "object", + "properties": { + "propA": { + "type": "object", + "anyOf": [ + { + "description": "Anonymous object type", + "type": "object", + "properties": { + "propA": { + "type": "string" + } + } + }, + { + "description": "Anonymous string type", + "type": "string" + }, + { + "description": "Anonymous integer type", + "type": "integer" + } + ] + } + } + }, + "CompositionWithNestedAnyAndTypeNull": { + "description": "This is a model with nested 'any of' property with a type null", + "type": "object", + "properties": { + "propA": { + "type": "object", + "anyOf": [ + { + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/ModelWithDictionary" + }, + { + "type": "null" + } + ] + }, + "type": "array" + }, + { + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/ModelWithArray" + }, + { + "type": "null" + } + ] + }, + "type": "array" + } + ] + } + } + }, + "3e-num_1Период": { + "enum": ["Bird", "Dog"], + "type": "string" + }, + "ConstValue": { + "type": "string", + "const": "ConstValue" + }, + "CompositionWithNestedAnyOfAndNull": { + "description": "This is a model with one property with a 'any of' relationship where the options are not $ref", + "type": "object", + "properties": { + "propA": { + "anyOf": [ + { + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/3e-num_1Период" + }, + { + "$ref": "#/components/schemas/ConstValue" + } + ] + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Scopes" + } + } + }, + "CompositionWithOneOfAndNullable": { + "description": "This is a model with one property with a 'one of' relationship", + "type": "object", + "properties": { + "propA": { + "type": ["object", "null"], + "oneOf": [ + { + "type": "object", + "properties": { + "boolean": { + "type": "boolean" + } + } + }, + { + "$ref": "#/components/schemas/ModelWithEnum" + }, + { + "$ref": "#/components/schemas/ModelWithArray" + }, + { + "$ref": "#/components/schemas/ModelWithDictionary" + } + ] + } + } + }, + "CompositionWithOneOfAndSimpleDictionary": { + "description": "This is a model that contains a simple dictionary within composition", + "type": "object", + "properties": { + "propA": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "additionalProperties": { + "type": "number" + } + } + ] + } + } + }, + "CompositionWithOneOfAndSimpleArrayDictionary": { + "description": "This is a model that contains a dictionary of simple arrays within composition", + "type": "object", + "properties": { + "propA": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "boolean" + } + } + } + ] + } + } + }, + "CompositionWithOneOfAndComplexArrayDictionary": { + "description": "This is a model that contains a dictionary of complex arrays (composited) within composition", + "type": "object", + "properties": { + "propA": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + } + } + ] + } + } + }, + "CompositionWithAllOfAndNullable": { + "description": "This is a model with one property with a 'all of' relationship", + "type": "object", + "properties": { + "propA": { + "type": ["object", "null"], + "allOf": [ + { + "type": "object", + "properties": { + "boolean": { + "type": "boolean" + } + } + }, + { + "$ref": "#/components/schemas/ModelWithEnum" + }, + { + "$ref": "#/components/schemas/ModelWithArray" + }, + { + "$ref": "#/components/schemas/ModelWithDictionary" + } + ] + } + } + }, + "CompositionWithAnyOfAndNullable": { + "description": "This is a model with one property with a 'any of' relationship", + "type": "object", + "properties": { + "propA": { + "type": ["object", "null"], + "anyOf": [ + { + "type": "object", + "properties": { + "boolean": { + "type": "boolean" + } + } + }, + { + "$ref": "#/components/schemas/ModelWithEnum" + }, + { + "$ref": "#/components/schemas/ModelWithArray" + }, + { + "$ref": "#/components/schemas/ModelWithDictionary" + } + ] + } + } + }, + "CompositionBaseModel": { + "description": "This is a base model with two simple optional properties", + "type": "object", + "properties": { + "firstName": { + "type": "string" + }, + "lastname": { + "type": "string" + } + } + }, + "CompositionExtendedModel": { + "description": "This is a model that extends the base model", + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/CompositionBaseModel" + } + ], + "properties": { + "age": { + "type": "number" + } + }, + "required": ["firstName", "lastname", "age"] + }, + "ModelWithProperties": { + "description": "This is a model with one nested property", + "type": "object", + "required": ["required", "requiredAndReadOnly", "requiredAndNullable"], + "properties": { + "required": { + "type": "string" + }, + "requiredAndReadOnly": { + "type": "string", + "readOnly": true + }, + "requiredAndNullable": { + "type": ["string", "null"] + }, + "string": { + "type": "string" + }, + "number": { + "type": "number" + }, + "boolean": { + "type": "boolean" + }, + "reference": { + "$ref": "#/components/schemas/ModelWithString" + }, + "property with space": { + "type": "string" + }, + "default": { + "type": "string" + }, + "try": { + "type": "string" + }, + "@namespace.string": { + "type": "string", + "readOnly": true + }, + "@namespace.integer": { + "type": "integer", + "readOnly": true + } + } + }, + "ModelWithNestedProperties": { + "description": "This is a model with one nested property", + "type": "object", + "required": ["first"], + "properties": { + "first": { + "type": ["object", "null"], + "required": ["second"], + "readOnly": true, + "properties": { + "second": { + "type": ["object", "null"], + "required": ["third"], + "readOnly": true, + "properties": { + "third": { + "type": ["string", "null"], + "required": true, + "readOnly": true + } + } + } + } + } + } + }, + "ModelWithDuplicateProperties": { + "description": "This is a model with duplicated properties", + "type": "object", + "properties": { + "prop": { + "$ref": "#/components/schemas/ModelWithString" + }, + "prop": { + "$ref": "#/components/schemas/ModelWithString" + }, + "prop": { + "$ref": "#/components/schemas/ModelWithString" + } + } + }, + "ModelWithOrderedProperties": { + "description": "This is a model with ordered properties", + "type": "object", + "properties": { + "zebra": { + "type": "string" + }, + "apple": { + "type": "string" + }, + "hawaii": { + "type": "string" + } + } + }, + "ModelWithDuplicateImports": { + "description": "This is a model with duplicated imports", + "type": "object", + "properties": { + "propA": { + "$ref": "#/components/schemas/ModelWithString" + }, + "propB": { + "$ref": "#/components/schemas/ModelWithString" + }, + "propC": { + "$ref": "#/components/schemas/ModelWithString" + } + } + }, + "ModelThatExtends": { + "description": "This is a model that extends another model", + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/ModelWithString" + }, + { + "type": "object", + "properties": { + "propExtendsA": { + "type": "string" + }, + "propExtendsB": { + "$ref": "#/components/schemas/ModelWithString" + } + } + } + ] + }, + "ModelThatExtendsExtends": { + "description": "This is a model that extends another model", + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/ModelWithString" + }, + { + "$ref": "#/components/schemas/ModelThatExtends" + }, + { + "type": "object", + "properties": { + "propExtendsC": { + "type": "string" + }, + "propExtendsD": { + "$ref": "#/components/schemas/ModelWithString" + } + } + } + ] + }, + "ModelWithPattern": { + "description": "This is a model that contains a some patterns", + "type": "object", + "required": ["key", "name"], + "properties": { + "key": { + "maxLength": 64, + "pattern": "^[a-zA-Z0-9_]*$", + "type": "string" + }, + "name": { + "maxLength": 255, + "type": "string" + }, + "enabled": { + "type": "boolean", + "readOnly": true + }, + "modified": { + "type": "string", + "format": "date-time", + "readOnly": true + }, + "id": { + "type": "string", + "pattern": "^\\d{2}-\\d{3}-\\d{4}$" + }, + "text": { + "type": "string", + "pattern": "^\\w+$" + }, + "patternWithSingleQuotes": { + "type": "string", + "pattern": "^[a-zA-Z0-9']*$" + }, + "patternWithNewline": { + "type": "string", + "pattern": "aaa\nbbb" + }, + "patternWithBacktick": { + "type": "string", + "pattern": "aaa`bbb" + } + } + }, + "File": { + "required": ["mime"], + "type": "object", + "properties": { + "id": { + "title": "Id", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "updated_at": { + "title": "Updated at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "mime": { + "title": "Mime", + "type": "string", + "maxLength": 24, + "minLength": 1 + }, + "file": { + "title": "File", + "type": "string", + "readOnly": true, + "format": "uri" + } + } + }, + "default": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, + "Pageable": { + "type": "object", + "properties": { + "page": { + "minimum": 0, + "type": "integer", + "format": "int32", + "default": 0 + }, + "size": { + "minimum": 1, + "type": "integer", + "format": "int32" + }, + "sort": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "FreeFormObjectWithoutAdditionalProperties": { + "description": "This is a free-form object without additionalProperties.", + "type": "object" + }, + "FreeFormObjectWithAdditionalPropertiesEqTrue": { + "description": "This is a free-form object with additionalProperties: true.", + "type": "object", + "additionalProperties": true + }, + "FreeFormObjectWithAdditionalPropertiesEqEmptyObject": { + "description": "This is a free-form object with additionalProperties: {}.", + "type": "object", + "additionalProperties": {} + }, + "ModelWithConst": { + "type": "object", + "properties": { + "String": { + "const": "String" + }, + "number": { + "const": 0 + }, + "null": { + "const": null + }, + "withType": { + "type": "string", + "const": "Some string" + } + } + }, + "ModelWithAdditionalPropertiesEqTrue": { + "description": "This is a model with one property and additionalProperties: true", + "type": "object", + "properties": { + "prop": { + "description": "This is a simple string property", + "type": "string" + } + }, + "additionalProperties": true + }, + "NestedAnyOfArraysNullable": { + "properties": { + "nullableArray": { + "anyOf": [ + { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "type": "array" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "CompositionWithOneOfAndProperties": { + "type": "object", + "oneOf": [ + { + "type": "object", + "required": ["foo"], + "properties": { + "foo": { + "$ref": "#/components/parameters/SimpleParameter" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": ["bar"], + "properties": { + "bar": { + "$ref": "#/components/schemas/NonAsciiStringæøåÆØÅöôêÊ字符串" + } + }, + "additionalProperties": false + } + ], + "required": ["baz", "qux"], + "properties": { + "baz": { + "type": ["integer", "null"], + "format": "uint16", + "minimum": 0.0 + }, + "qux": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + }, + "NullableObject": { + "type": ["object", "null"], + "description": "An object that can be null", + "properties": { + "foo": { + "type": "string" + } + }, + "default": null + }, + "CharactersInDescription": { + "type": "string", + "description": "Some % character" + }, + "ModelWithNullableObject": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/NullableObject" + } + } + }, + "ModelWithOneOfEnum": { + "oneOf": [ + { + "type": "object", + "required": ["foo"], + "properties": { + "foo": { + "type": "string", + "enum": ["Bar"] + } + } + }, + { + "type": "object", + "required": ["foo"], + "properties": { + "foo": { + "type": "string", + "enum": ["Baz"] + } + } + }, + { + "type": "object", + "required": ["foo"], + "properties": { + "foo": { + "type": "string", + "enum": ["Qux"] + } + } + }, + { + "type": "object", + "required": ["content", "foo"], + "properties": { + "content": { + "type": "string", + "format": "date-time" + }, + "foo": { + "type": "string", + "enum": ["Quux"] + } + } + }, + { + "type": "object", + "required": ["content", "foo"], + "properties": { + "content": { + "type": "array", + "prefixItems": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "string" + } + ], + "maxItems": 2, + "minItems": 2 + }, + "foo": { + "type": "string", + "enum": ["Corge"] + } + } + } + ] + }, + "ModelWithNestedArrayEnumsDataFoo": { + "enum": ["foo", "bar"], + "type": "string" + }, + "ModelWithNestedArrayEnumsDataBar": { + "enum": ["baz", "qux"], + "type": "string" + }, + "ModelWithNestedArrayEnumsData": { + "type": "object", + "properties": { + "foo": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelWithNestedArrayEnumsDataFoo" + } + }, + "bar": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelWithNestedArrayEnumsDataBar" + } + } + } + }, + "ModelWithNestedArrayEnums": { + "type": "object", + "properties": { + "array_strings": { + "type": "array", + "items": { + "type": "string" + } + }, + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/ModelWithNestedArrayEnumsData" + } + ] + } + } + }, + "ModelWithNestedCompositionEnums": { + "type": "object", + "properties": { + "foo": { + "allOf": [ + { + "$ref": "#/components/schemas/ModelWithNestedArrayEnumsDataFoo" + } + ] + } + } + }, + "ModelWithReadOnlyAndWriteOnly": { + "type": "object", + "required": ["foo", "bar", "baz"], + "properties": { + "foo": { + "type": "string" + }, + "bar": { + "readOnly": true, + "type": "string" + }, + "baz": { + "type": "string", + "writeOnly": true + } + } + }, + "ModelWithConstantSizeArray": { + "type": "array", + "items": { + "type": "number" + }, + "minItems": 2, + "maxItems": 2 + }, + "ModelWithAnyOfConstantSizeArray": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "minItems": 3, + "maxItems": 3 + }, + "ModelWithPrefixItemsConstantSizeArray": { + "type": "array", + "prefixItems": [ + { + "$ref": "#/components/schemas/ModelWithInteger" + }, + { + "oneOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + { + "type": "string" + } + ] + }, + "ModelWithAnyOfConstantSizeArrayNullable": { + "type": ["array"], + "items": { + "oneOf": [ + { + "type": ["number", "null"] + }, + { + "type": "string" + } + ] + }, + "minItems": 3, + "maxItems": 3 + }, + "ModelWithAnyOfConstantSizeArrayWithNSizeAndOptions": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "number" + }, + { + "$ref": "#/components/schemas/import" + } + ] + }, + "minItems": 2, + "maxItems": 2 + }, + "ModelWithAnyOfConstantSizeArrayAndIntersect": { + "type": "array", + "items": { + "allOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "minItems": 2, + "maxItems": 2 + }, + "ModelWithNumericEnumUnion": { + "type": "object", + "properties": { + "value": { + "type": "number", + "description": "Период", + "enum": [-10, -1, 0, 1, 3, 6, 12] + } + } + }, + "ModelWithBackticksInDescription": { + "description": "Some description with `back ticks`", + "type": "object", + "properties": { + "template": { + "type": "string", + "description": "The template `that` should be used for parsing and importing the contents of the CSV file.\n\n

There is one placeholder currently supported:

  • ${x} - refers to the n-th column in the CSV file, e.g. ${1}, ${2}, ...)

Example of a correct JSON template:

\n
\n[\n  {\n    \"resourceType\": \"Asset\",\n    \"identifier\": {\n      \"name\": \"${1}\",\n      \"domain\": {\n        \"name\": \"${2}\",\n        \"community\": {\n          \"name\": \"Some Community\"\n        }\n      }\n    },\n    \"attributes\" : {\n      \"00000000-0000-0000-0000-000000003115\" : [ {\n        \"value\" : \"${3}\" \n      } ],\n      \"00000000-0000-0000-0000-000000000222\" : [ {\n        \"value\" : \"${4}\"\n      } ]\n    }\n  }\n]\n
" + } + } + }, + "ModelWithOneOfAndProperties": { + "type": "object", + "oneOf": [ + { + "$ref": "#/components/parameters/SimpleParameter" + }, + { + "$ref": "#/components/schemas/NonAsciiStringæøåÆØÅöôêÊ字符串" + } + ], + "required": ["baz", "qux"], + "properties": { + "baz": { + "type": ["integer", "null"], + "format": "uint16", + "minimum": 0.0 + }, + "qux": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + }, + "ParameterSimpleParameterUnused": { + "description": "Model used to test deduplication strategy (unused)", + "type": "string" + }, + "PostServiceWithEmptyTagResponse": { + "description": "Model used to test deduplication strategy", + "type": "string" + }, + "PostServiceWithEmptyTagResponse2": { + "description": "Model used to test deduplication strategy", + "type": "string" + }, + "DeleteFooData": { + "description": "Model used to test deduplication strategy", + "type": "string" + }, + "DeleteFooData2": { + "description": "Model used to test deduplication strategy", + "type": "string" + }, + "import": { + "description": "Model with restricted keyword name", + "type": "string" + }, + "400": { + "description": "Model with number-only name", + "type": "string" + }, + "SchemaWithFormRestrictedKeys": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "x-enum-descriptions": { + "type": "string" + }, + "x-enum-varnames": { + "type": "string" + }, + "x-enumNames": { + "type": "string" + }, + "title": { + "type": "string" + }, + "object": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "x-enum-descriptions": { + "type": "string" + }, + "x-enum-varnames": { + "type": "string" + }, + "x-enumNames": { + "type": "string" + }, + "title": { + "type": "string" + } + } + }, + "array": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "x-enum-descriptions": { + "type": "string" + }, + "x-enum-varnames": { + "type": "string" + }, + "x-enumNames": { + "type": "string" + }, + "title": { + "type": "string" + } + } + } + } + } + }, + "io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions": { + "description": "This schema was giving PascalCase transformations a hard time", + "properties": { + "preconditions": { + "allOf": [ + { + "$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Preconditions" + } + ], + "description": "Must be fulfilled before a deletion is carried out. If not possible, a 409 Conflict status will be returned." + } + }, + "type": "object" + }, + "io.k8s.apimachinery.pkg.apis.meta.v1.Preconditions": { + "description": "This schema was giving PascalCase transformations a hard time", + "properties": { + "resourceVersion": { + "description": "Specifies the target ResourceVersion", + "type": "string" + }, + "uid": { + "description": "Specifies the target UID.", + "type": "string" + } + }, + "type": "object" + }, + "AdditionalPropertiesUnknownIssue": { + "type": "object", + "properties": {}, + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "AdditionalPropertiesUnknownIssue2": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "AdditionalPropertiesUnknownIssue3": { + "type": "object", + "allOf": [ + { + "type": "string" + }, + { + "type": "object", + "required": ["entries"], + "properties": { + "entries": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/AdditionalPropertiesUnknownIssue" + } + } + } + } + ] + }, + "AdditionalPropertiesIntegerIssue": { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "integer" + } + }, + "additionalProperties": { + "type": "integer" + } + }, + "OneOfAllOfIssue": { + "oneOf": [ + { + "allOf": [ + { + "oneOf": [ + { + "$ref": "#/components/schemas/ConstValue" + }, + { + "$ref": "#/components/schemas/Generic.Schema.Duplicate.Issue`1[System.Boolean]" + } + ] + }, + { + "$ref": "#/components/schemas/3e-num_1Период" + } + ] + }, + { + "$ref": "#/components/schemas/Generic.Schema.Duplicate.Issue`1[System.String]" + } + ] + }, + "Generic.Schema.Duplicate.Issue`1[System.Boolean]": { + "type": "object", + "properties": { + "item": { + "type": "boolean" + }, + "error": { + "type": ["string", "null"] + }, + "hasError": { + "type": "boolean", + "readOnly": true + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "Generic.Schema.Duplicate.Issue`1[System.String]": { + "type": "object", + "properties": { + "item": { + "type": ["string", "null"] + }, + "error": { + "type": ["string", "null"] + }, + "hasError": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + } + } + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5237e9dda..a054d0f53 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8521,7 +8521,7 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.1703.7(chokidar@3.6.0) - '@angular-devkit/build-webpack': 0.1703.7(chokidar@3.6.0)(webpack-dev-server@4.15.1(webpack@5.90.3(esbuild@0.20.1)))(webpack@5.90.3(esbuild@0.20.1)) + '@angular-devkit/build-webpack': 0.1703.7(chokidar@3.6.0)(webpack-dev-server@4.15.1(webpack@5.90.3))(webpack@5.90.3(esbuild@0.20.1)) '@angular-devkit/core': 17.3.7(chokidar@3.6.0) '@angular/compiler-cli': 17.3.9(@angular/compiler@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.7)))(typescript@5.5.3) '@babel/core': 7.24.0 @@ -8579,9 +8579,9 @@ snapshots: undici: 6.11.1 vite: 5.1.7(@types/node@20.14.10)(less@4.2.0)(sass@1.71.1)(terser@5.29.1) watchpack: 2.4.0 - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) webpack-dev-middleware: 6.1.2(webpack@5.90.3(esbuild@0.20.1)) - webpack-dev-server: 4.15.1(webpack@5.90.3(esbuild@0.20.1)) + webpack-dev-server: 4.15.1(webpack@5.90.3) webpack-merge: 5.10.0 webpack-subresource-integrity: 5.1.0(webpack@5.90.3(esbuild@0.20.1)) optionalDependencies: @@ -8606,12 +8606,12 @@ snapshots: - utf-8-validate - webpack-cli - '@angular-devkit/build-webpack@0.1703.7(chokidar@3.6.0)(webpack-dev-server@4.15.1(webpack@5.90.3(esbuild@0.20.1)))(webpack@5.90.3(esbuild@0.20.1))': + '@angular-devkit/build-webpack@0.1703.7(chokidar@3.6.0)(webpack-dev-server@4.15.1(webpack@5.90.3))(webpack@5.90.3(esbuild@0.20.1))': dependencies: '@angular-devkit/architect': 0.1703.7(chokidar@3.6.0) rxjs: 7.8.1 - webpack: 5.90.3(esbuild@0.23.1) - webpack-dev-server: 4.15.1(webpack@5.90.3(esbuild@0.20.1)) + webpack: 5.90.3(esbuild@0.20.1) + webpack-dev-server: 4.15.1(webpack@5.90.3) transitivePeerDependencies: - chokidar @@ -10421,7 +10421,7 @@ snapshots: dependencies: '@angular/compiler-cli': 17.3.9(@angular/compiler@17.3.9(@angular/core@17.3.9(rxjs@7.8.1)(zone.js@0.14.7)))(typescript@5.5.3) typescript: 5.5.3 - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) '@nodelib/fs.scandir@2.1.5': dependencies: @@ -12564,7 +12564,7 @@ snapshots: '@babel/core': 7.24.0 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) babel-plugin-istanbul@6.1.1: dependencies: @@ -13003,7 +13003,7 @@ snapshots: normalize-path: 3.0.0 schema-utils: 4.2.0 serialize-javascript: 6.0.2 - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) core-js-compat@3.37.1: dependencies: @@ -13055,7 +13055,7 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.6.2 optionalDependencies: - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) css-select@5.1.0: dependencies: @@ -13068,7 +13068,7 @@ snapshots: css-tree@2.3.1: dependencies: mdn-data: 2.0.30 - source-map-js: 1.2.0 + source-map-js: 1.2.1 css-what@6.1.0: {} @@ -14476,7 +14476,7 @@ snapshots: dependencies: klona: 2.0.6 less: 4.2.0 - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) less@4.2.0: dependencies: @@ -14501,7 +14501,7 @@ snapshots: dependencies: webpack-sources: 3.2.3 optionalDependencies: - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) lilconfig@2.1.0: {} @@ -14720,7 +14720,7 @@ snapshots: dependencies: schema-utils: 4.2.0 tapable: 2.2.1 - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) minimalistic-assert@1.0.1: {} @@ -15269,11 +15269,25 @@ snapshots: read-cache: 1.0.0 resolve: 1.22.8 + postcss-import@15.1.0(postcss@8.4.47): + dependencies: + postcss: 8.4.47 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + optional: true + postcss-js@4.0.1(postcss@8.4.39): dependencies: camelcase-css: 2.0.1 postcss: 8.4.39 + postcss-js@4.0.1(postcss@8.4.47): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.47 + optional: true + postcss-load-config@3.1.4(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)): dependencies: lilconfig: 2.1.0 @@ -15298,6 +15312,15 @@ snapshots: postcss: 8.4.39 ts-node: 10.9.2(@types/node@20.14.5)(typescript@5.5.3) + postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)): + dependencies: + lilconfig: 3.1.2 + yaml: 2.4.5 + optionalDependencies: + postcss: 8.4.47 + ts-node: 10.9.2(@types/node@20.14.10)(typescript@5.5.3) + optional: true + postcss-load-config@6.0.1(jiti@2.3.1)(postcss@8.4.47)(tsx@4.19.1)(yaml@2.4.5): dependencies: lilconfig: 3.1.2 @@ -15314,7 +15337,7 @@ snapshots: postcss: 8.4.35 semver: 7.6.2 optionalDependencies: - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) transitivePeerDependencies: - typescript @@ -15346,6 +15369,12 @@ snapshots: postcss: 8.4.39 postcss-selector-parser: 6.1.0 + postcss-nested@6.0.1(postcss@8.4.47): + dependencies: + postcss: 8.4.47 + postcss-selector-parser: 6.1.0 + optional: true + postcss-safe-parser@6.0.0(postcss@8.4.39): dependencies: postcss: 8.4.39 @@ -15774,7 +15803,7 @@ snapshots: neo-async: 2.6.2 optionalDependencies: sass: 1.71.1 - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) sass@1.71.1: dependencies: @@ -16008,7 +16037,7 @@ snapshots: dependencies: iconv-lite: 0.6.3 source-map-js: 1.2.0 - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) source-map-support@0.5.21: dependencies: @@ -16232,7 +16261,7 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 '@types/estree': 1.0.5 - acorn: 8.12.0 + acorn: 8.12.1 aria-query: 5.3.0 axobject-query: 4.1.0 code-red: 1.0.4 @@ -16298,12 +16327,12 @@ snapshots: micromatch: 4.0.7 normalize-path: 3.0.0 object-hash: 3.0.0 - picocolors: 1.0.1 - postcss: 8.4.39 - postcss-import: 15.1.0(postcss@8.4.39) - postcss-js: 4.0.1(postcss@8.4.39) - postcss-load-config: 4.0.2(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) - postcss-nested: 6.0.1(postcss@8.4.39) + picocolors: 1.1.0 + postcss: 8.4.47 + postcss-import: 15.1.0(postcss@8.4.47) + postcss-js: 4.0.1(postcss@8.4.47) + postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) + postcss-nested: 6.0.1(postcss@8.4.47) postcss-selector-parser: 6.1.0 resolve: 1.22.8 sucrase: 3.35.0 @@ -16365,16 +16394,16 @@ snapshots: term-size@2.2.1: {} - terser-webpack-plugin@5.3.10(esbuild@0.23.1)(webpack@5.90.3(esbuild@0.20.1)): + terser-webpack-plugin@5.3.10(esbuild@0.20.1)(webpack@5.90.3): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.29.1 - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) optionalDependencies: - esbuild: 0.23.1 + esbuild: 0.20.1 terser@5.29.1: dependencies: @@ -17088,14 +17117,14 @@ snapshots: webidl-conversions@7.0.0: {} - webpack-dev-middleware@5.3.4(webpack@5.90.3(esbuild@0.20.1)): + webpack-dev-middleware@5.3.4(webpack@5.90.3): dependencies: colorette: 2.0.20 memfs: 3.5.3 mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.2.0 - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) webpack-dev-middleware@6.1.2(webpack@5.90.3(esbuild@0.20.1)): dependencies: @@ -17105,9 +17134,9 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.2.0 optionalDependencies: - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) - webpack-dev-server@4.15.1(webpack@5.90.3(esbuild@0.20.1)): + webpack-dev-server@4.15.1(webpack@5.90.3): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -17137,10 +17166,10 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 5.3.4(webpack@5.90.3(esbuild@0.20.1)) + webpack-dev-middleware: 5.3.4(webpack@5.90.3) ws: 8.17.1 optionalDependencies: - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) transitivePeerDependencies: - bufferutil - debug @@ -17158,9 +17187,9 @@ snapshots: webpack-subresource-integrity@5.1.0(webpack@5.90.3(esbuild@0.20.1)): dependencies: typed-assert: 1.0.9 - webpack: 5.90.3(esbuild@0.23.1) + webpack: 5.90.3(esbuild@0.20.1) - webpack@5.90.3(esbuild@0.23.1): + webpack@5.90.3(esbuild@0.20.1): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.5 @@ -17183,7 +17212,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(esbuild@0.23.1)(webpack@5.90.3(esbuild@0.20.1)) + terser-webpack-plugin: 5.3.10(esbuild@0.20.1)(webpack@5.90.3) watchpack: 2.4.0 webpack-sources: 3.2.3 transitivePeerDependencies: