@spec2ts/openapi-client 4.0.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { i as usage, n as describe, r as handler, t as builder } from "../command-Djig04Ub.mjs";
2
+ import { i as usage, n as describe, r as handler, t as builder } from "../command-C4XUi5ys.mjs";
3
3
  import yargs from "yargs";
4
4
  import { hideBin } from "yargs/helpers";
5
5
  //#region src/bin/oapi2tsclient.ts
@@ -1,4 +1,4 @@
1
- import { t as OApiGeneratorOptions } from "../openapi-generator-DfC4jH9J.mjs";
1
+ import { t as OApiGeneratorOptions } from "../openapi-generator-B6yW0z4d.mjs";
2
2
  import { Argv } from "yargs";
3
3
  //#region src/cli/command.d.ts
4
4
  interface BuildClientFromOpenApiOptions extends OApiGeneratorOptions {
@@ -1,2 +1,2 @@
1
- import { i as usage, n as describe, r as handler, t as builder } from "../command-Djig04Ub.mjs";
1
+ import { i as usage, n as describe, r as handler, t as builder } from "../command-C4XUi5ys.mjs";
2
2
  export { builder, describe, handler, usage };
@@ -1,7 +1,7 @@
1
- import { n as generateClientFromFile } from "./openapi-generator-DwzcjKrv.mjs";
2
- import * as path from "path";
1
+ import { n as generateClientFromFile } from "./openapi-generator-IB_huQ-a.mjs";
3
2
  import { cli, printer } from "@spec2ts/core";
4
- import { promises } from "fs";
3
+ import path from "node:path";
4
+ import fs from "node:fs/promises";
5
5
  //#region src/cli/command.ts
6
6
  const usage = "$0 <input..>";
7
7
  const describe = "Generate TypeScript HTTP client from OpenAPI specification";
@@ -137,7 +137,7 @@ async function generatePackage(output, options) {
137
137
  pkg.devDependencies["@types/node"] = "*";
138
138
  }
139
139
  if (options.packagePrivate) pkg.private = options.packagePrivate;
140
- await promises.writeFile(path.join(outputDir, "package.json"), JSON.stringify(pkg, null, 2), "utf8");
140
+ await fs.writeFile(path.join(outputDir, "package.json"), JSON.stringify(pkg, null, 2), "utf8");
141
141
  }
142
142
  //#endregion
143
143
  export { usage as i, describe as n, handler as r, builder as t };
package/dist/index.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { i as generateClientFromFile, n as SeparatedClientResult, r as generateClient, t as OApiGeneratorOptions } from "./openapi-generator-DfC4jH9J.mjs";
1
+ import { i as generateClientFromFile, n as SeparatedClientResult, r as generateClient, t as OApiGeneratorOptions } from "./openapi-generator-B6yW0z4d.mjs";
2
2
  export { OApiGeneratorOptions, SeparatedClientResult, generateClient, generateClientFromFile };
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { n as generateClientFromFile, t as generateClient } from "./openapi-generator-DwzcjKrv.mjs";
1
+ import { n as generateClientFromFile, t as generateClient } from "./openapi-generator-IB_huQ-a.mjs";
2
2
  export { generateClient, generateClientFromFile };
@@ -1,5 +1,5 @@
1
1
  import { ParserOptions } from "@spec2ts/jsonschema";
2
- import * as ts from "typescript";
2
+ import ts from "typescript";
3
3
  import { OpenAPIObject } from "openapi3-ts/oas31";
4
4
  //#region src/lib/openapi-generator.d.ts
5
5
  interface OApiGeneratorOptions extends ParserOptions {
@@ -0,0 +1,414 @@
1
+ import $RefParser from "@apidevtools/json-schema-ref-parser";
2
+ import * as core from "@spec2ts/core";
3
+ import { createContext, getTypeFromSchema, isReference, resolveReference } from "@spec2ts/jsonschema";
4
+ import { getOperationName, getResponseName, parseReference } from "@spec2ts/openapi";
5
+ import path from "node:path";
6
+ import ts from "typescript";
7
+ //#region src/lib/util.ts
8
+ function camelCase(str) {
9
+ const words = str.match(/[A-Z\xC0-\xD6\xD8-\xDE_$]?[a-z\xDF-\xF6\xF8-\xFF_$]+|[A-Z\xC0-\xD6\xD8-\xDE_$]+(?![a-z\xDF-\xF6\xF8-\xFF_$])|\d+/g);
10
+ if (!words) return "";
11
+ let result = "";
12
+ const len = words.length;
13
+ for (let i = 0; i < len; i++) {
14
+ let tmp = words[i].toLowerCase();
15
+ if (i !== 0) tmp = tmp[0].toUpperCase() + tmp.substr(1);
16
+ result += tmp;
17
+ }
18
+ return result;
19
+ }
20
+ //#endregion
21
+ //#region src/lib/core-parser.ts
22
+ const methods = [
23
+ "GET",
24
+ "PUT",
25
+ "POST",
26
+ "DELETE",
27
+ "OPTIONS",
28
+ "HEAD",
29
+ "PATCH",
30
+ "TRACE"
31
+ ];
32
+ const contentTypes = {
33
+ "*/*": "json",
34
+ "application/json": "json",
35
+ "application/x-www-form-urlencoded": "form",
36
+ "multipart/form-data": "multipart"
37
+ };
38
+ function parseOperation(path, item, method, operation, context) {
39
+ const result = {
40
+ name: getOperationVar(method, path, operation.operationId, context),
41
+ paramsVars: {},
42
+ args: [],
43
+ query: [],
44
+ header: [],
45
+ response: core.keywordType.void
46
+ };
47
+ parseArgs(result, item, operation, context);
48
+ parseResponses(result, path, method, operation, context);
49
+ return result;
50
+ }
51
+ function parseArgs(result, item, operation, context) {
52
+ parseParameters(result, item, operation, context);
53
+ if (operation.requestBody) parseRequestBody(result, operation.requestBody, context);
54
+ result.args.push(core.createParameter("options", {
55
+ type: ts.factory.createTypeReferenceNode("RequestOptions", void 0),
56
+ questionToken: true
57
+ }));
58
+ }
59
+ function parseResponses(result, path, method, operation, context) {
60
+ const operationName = getOperationName(method, path, operation.operationId, context);
61
+ if (operation.responses) {
62
+ result.response = getTypeFromResponses(operationName, operation.responses, context);
63
+ result.responseJSON = isJSONResponse(operation.responses, context);
64
+ result.responseVoid = result.response === core.keywordType.void;
65
+ } else {
66
+ result.response = core.keywordType.unknown;
67
+ result.responseJSON = false;
68
+ result.responseVoid = false;
69
+ }
70
+ }
71
+ function parseParameters(result, item, operation, context) {
72
+ const parameters = fixDeepObjects([...resolveReferences(item.parameters, context), ...resolveReferences(operation.parameters, context)]);
73
+ result.query = parameters.filter((p) => p.in === "query");
74
+ result.header = parameters.filter((p) => p.in === "header");
75
+ const argNames = result.paramsVars = createParametersNames(parameters);
76
+ let objectBindingParams = parameters;
77
+ if (context.options.inlineRequired) {
78
+ const [required, optional] = splitParameters(parameters);
79
+ objectBindingParams = optional;
80
+ required.forEach((p) => {
81
+ result.args.push(core.createParameter(argNames[p.name], { type: getTypeFromSchema(p.schema, context) }));
82
+ });
83
+ }
84
+ if (!objectBindingParams.length) return;
85
+ result.args.push(core.createParameter(core.createObjectBinding(objectBindingParams.map(({ name }) => ({ name: argNames[name] }))), {
86
+ initializer: objectBindingParams.some((p) => p.required) ? void 0 : ts.factory.createObjectLiteralExpression(),
87
+ type: ts.factory.createTypeLiteralNode(objectBindingParams.map((p) => core.createPropertySignature({
88
+ name: argNames[p.name],
89
+ questionToken: !p.required,
90
+ type: getTypeFromSchema(p.schema, context)
91
+ })))
92
+ }));
93
+ }
94
+ function parseRequestBody(result, requestBody, context) {
95
+ const [schema, mode] = getSchemaFromContent(resolveReference(requestBody, context).content);
96
+ const type = getTypeFromSchema(schema, context);
97
+ const bodyVar = result.bodyVar = camelCase(type.name || getReferenceName(schema) || "body");
98
+ result.bodyMode = mode;
99
+ result.args.push(core.createParameter(bodyVar, { type }));
100
+ }
101
+ function createParametersNames(parameters) {
102
+ const argNames = {};
103
+ parameters.forEach(({ name }) => {
104
+ const stripped = camelCase(name.replace(/.+\./, ""));
105
+ argNames[name] = stripped in argNames ? camelCase(name) : stripped;
106
+ });
107
+ return argNames;
108
+ }
109
+ function splitParameters(parameters) {
110
+ const required = [];
111
+ const optional = [];
112
+ parameters.forEach((p) => {
113
+ if (p.required) required.push(p);
114
+ else optional.push(p);
115
+ });
116
+ return [required, optional];
117
+ }
118
+ function getTypeFromResponses(operationName, res, context) {
119
+ const codes = Object.keys(res);
120
+ const types = [];
121
+ codes.forEach((code) => {
122
+ const isOK = isOKResponse(code, codes.length);
123
+ const type = getTypeFromResponse(res[code], context);
124
+ if (!type) console.log(res[code]);
125
+ if (ts.isTypeReferenceNode(type) || core.isKeywordTypeNode(type)) {
126
+ if (isOK) types.push(type);
127
+ } else {
128
+ const name = getResponseName(operationName, code, context);
129
+ context.aliases.push(core.createTypeOrInterfaceDeclaration({
130
+ modifiers: [core.modifier.export],
131
+ name,
132
+ type
133
+ }));
134
+ if (isOK) types.push(ts.factory.createTypeReferenceNode(name, void 0));
135
+ }
136
+ });
137
+ if (types.length === 1) return types[0];
138
+ return ts.factory.createUnionTypeNode(types);
139
+ }
140
+ function isJSONResponse(responses, context) {
141
+ const codes = Object.keys(responses);
142
+ const resCode = codes.find((code) => isOKResponse(code, codes.length));
143
+ if (!resCode) return false;
144
+ const response = resolveReference(responses[resCode], context);
145
+ return !!response?.content?.["application/json"] || !!response?.content?.["*/*"];
146
+ }
147
+ function isOKResponse(code, codesCount) {
148
+ return codesCount === 1 || parseInt(code, 10) < 400;
149
+ }
150
+ function isMethod(method) {
151
+ return methods.includes(method);
152
+ }
153
+ function getTypeFromResponse(res, context) {
154
+ res = resolveReference(res, context);
155
+ if (!res?.content) return core.keywordType.void;
156
+ return getTypeFromSchema(getSchemaFromContent(res.content)[0], context);
157
+ }
158
+ function getSchemaFromContent(content) {
159
+ const res = Object.entries(contentTypes).find(([t]) => t in content);
160
+ let schema;
161
+ let mode;
162
+ if (res) {
163
+ const [contentType, contentMode] = res;
164
+ mode = contentMode;
165
+ schema = content?.[contentType]?.schema;
166
+ }
167
+ return [schema || { type: "string" }, mode];
168
+ }
169
+ function resolveReferences(array, context) {
170
+ return array?.map((ref) => resolveReference(ref, context)) ?? [];
171
+ }
172
+ function getReferenceName(obj) {
173
+ if (isReference(obj)) return camelCase(obj.$ref.split("/").slice(-1)[0]);
174
+ }
175
+ /**
176
+ * Despite its name, OpenApi's `deepObject` serialization does not support
177
+ * deeply nested objects. As a workaround we detect parameters that contain
178
+ * square brackets and merge them into a single object.
179
+ */
180
+ function fixDeepObjects(params) {
181
+ const res = [];
182
+ const merged = {};
183
+ params.forEach((p) => {
184
+ const m = /^(.+?)\[(.*?)\]/.exec(p.name);
185
+ if (!m) {
186
+ res.push(p);
187
+ return;
188
+ }
189
+ const [, name, prop] = m;
190
+ let obj = merged[name];
191
+ if (!obj) {
192
+ obj = merged[name] = {
193
+ name,
194
+ in: p.in,
195
+ style: "deepObject",
196
+ schema: {
197
+ type: "object",
198
+ properties: {}
199
+ }
200
+ };
201
+ res.push(obj);
202
+ }
203
+ obj.schema.properties[prop] = p.schema;
204
+ });
205
+ return res;
206
+ }
207
+ function getOperationVar(verb, path, operationId, context) {
208
+ const id = getOperationVarId(operationId);
209
+ if (id) return id;
210
+ return getPathVar(`${verb} ${path}`, context);
211
+ }
212
+ function getPathVar(path, context) {
213
+ path = path.replace(/\{(.+?)\}/, "by $1").replace(/\{(.+?)\}/g, "and $1");
214
+ let name = camelCase(path);
215
+ const count = context.names[name] = (context.names[name] || 0) + 1;
216
+ if (count > 1) name += count;
217
+ return name;
218
+ }
219
+ function getOperationVarId(id) {
220
+ if (!id) return;
221
+ if (id.match(/[^\w\s]/)) return;
222
+ id = camelCase(id);
223
+ if (core.isValidIdentifier(id)) return id;
224
+ }
225
+ //#endregion
226
+ //#region src/lib/server-parser.ts
227
+ function parseServers(servers) {
228
+ const props = servers.map((server, i) => [serverName(server, i), generateServerExpression(server)]);
229
+ return core.createObjectLiteral(props);
230
+ }
231
+ function defaultBaseUrl(servers) {
232
+ return ts.factory.createStringLiteral(defaultUrl(servers[0]));
233
+ }
234
+ function serverName(server, index) {
235
+ return server.description ? camelCase(server.description.replace(/\W+/, " ")) : `server${index + 1}`;
236
+ }
237
+ function generateServerExpression(server) {
238
+ return server.variables ? createServerFunction(server.url, server.variables) : ts.factory.createStringLiteral(server.url);
239
+ }
240
+ function createServerFunction(template, vars) {
241
+ const params = [core.createParameter(core.createObjectBinding(Object.entries(vars || {}).map(([name, value]) => {
242
+ return {
243
+ name,
244
+ initializer: createLiteral(value.default)
245
+ };
246
+ })), { type: ts.factory.createTypeLiteralNode(Object.entries(vars || {}).map(([name, value]) => {
247
+ return core.createPropertySignature({
248
+ name,
249
+ type: value.enum ? ts.factory.createUnionTypeNode(createUnion(value.enum)) : ts.factory.createUnionTypeNode([
250
+ core.keywordType.string,
251
+ core.keywordType.number,
252
+ core.keywordType.boolean
253
+ ])
254
+ });
255
+ })) })];
256
+ return core.createArrowFunction(params, createTemplate(template));
257
+ }
258
+ function createUnion(strs) {
259
+ return strs.map((e) => ts.factory.createLiteralTypeNode(createLiteral(e)));
260
+ }
261
+ function createTemplate(url) {
262
+ const tokens = url.split(/{([\s\S]+?)}/g);
263
+ const spans = [];
264
+ const len = tokens.length;
265
+ for (let i = 1; i < len; i += 2) {
266
+ const template_factory = i === len - 2 ? ts.factory.createTemplateTail.bind(ts.factory) : ts.factory.createTemplateMiddle.bind(ts.factory);
267
+ spans.push(ts.factory.createTemplateSpan(ts.factory.createIdentifier(tokens[i]), template_factory(tokens[i + 1])));
268
+ }
269
+ return ts.factory.createTemplateExpression(ts.factory.createTemplateHead(tokens[0]), spans);
270
+ }
271
+ function createLiteral(v) {
272
+ switch (typeof v) {
273
+ case "string": return ts.factory.createStringLiteral(v);
274
+ case "boolean": return v ? ts.factory.createTrue() : ts.factory.createFalse();
275
+ case "number": return ts.factory.createNumericLiteral(String(v));
276
+ }
277
+ }
278
+ function defaultUrl(server) {
279
+ if (!server) return "/";
280
+ const { url, variables } = server;
281
+ if (!variables) return url;
282
+ return url.replace(/\{(.+?)\}/g, (m, name) => variables[name] ? String(variables[name].default) : m);
283
+ }
284
+ //#endregion
285
+ //#region src/lib/core-generator.ts
286
+ function generateServers(file, { servers }, context) {
287
+ servers = servers || [];
288
+ if (context.options.baseUrl) servers = [{ url: context.options.baseUrl }];
289
+ const serversConst = core.findFirstVariableStatement(file.statements, "servers");
290
+ const defaultsConst = core.findFirstVariableStatement(file.statements, "defaults");
291
+ if (!serversConst || !defaultsConst) throw new Error("Invalid template: missing servers or defaults const");
292
+ file = core.replaceSourceFileStatement(file, serversConst, core.updateVariableStatementValue(serversConst, "servers", parseServers(servers)));
293
+ file = core.replaceSourceFileStatement(file, defaultsConst, core.updateVariableStatementPropertyValue(defaultsConst, "defaults", "baseUrl", defaultBaseUrl(servers)));
294
+ return file;
295
+ }
296
+ function generateDefaults(file, context) {
297
+ if (context.options.importFetch) {
298
+ const defaultsConst = core.findFirstVariableStatement(file.statements, "defaults");
299
+ if (!defaultsConst) throw new Error("Invalid template: missing defaults const");
300
+ file = core.prependSourceFileStatements(file, core.createDefaultImportDeclaration({
301
+ moduleSpecifier: context.options.importFetch,
302
+ name: "fetch",
303
+ bindings: ["RequestInit", "Headers"]
304
+ }), core.createNamespaceImportDeclaration({
305
+ moduleSpecifier: "form-data",
306
+ name: "FormData"
307
+ }));
308
+ file = core.replaceSourceFileStatement(file, defaultsConst, core.updateVariableStatementPropertyValue(defaultsConst, "defaults", "fetch", core.toExpression("fetch")));
309
+ }
310
+ return file;
311
+ }
312
+ function generateFunctions(file, spec, context) {
313
+ const paths = Object.fromEntries(Object.entries(spec.paths ?? {}).filter(([path]) => !context.options.prefix || path.startsWith(context.options.prefix)));
314
+ const functions = Object.entries(paths).map(([path, pathSpec]) => {
315
+ const item = resolveReference(pathSpec, context);
316
+ return Object.entries(item).filter(([verb]) => isMethod(verb.toUpperCase())).map(([verb, entry]) => generateFunction(path, item, verb.toUpperCase(), entry, context));
317
+ }).flat();
318
+ if (context.options.typesPath && context.typesFile) {
319
+ context.typesFile = core.updateSourceFileStatements(context.typesFile, context.aliases);
320
+ file = core.updateSourceFileStatements(file, [
321
+ core.createNamedImportDeclaration({
322
+ isTypeOnly: true,
323
+ moduleSpecifier: context.options.typesPath,
324
+ bindings: context.aliases.map((a) => a.name.text)
325
+ }),
326
+ ...file.statements,
327
+ ...functions
328
+ ]);
329
+ } else file = core.appendSourceFileStatements(file, ...context.aliases, ...functions);
330
+ return file;
331
+ }
332
+ function generateFunction(path, item, method, operation, context) {
333
+ const { name, query, header, paramsVars, args, bodyMode, bodyVar, response, responseVoid, responseJSON } = parseOperation(path, item, method, operation, context);
334
+ const url = generateUrl(path, generateQs(query, paramsVars));
335
+ const init = [ts.factory.createSpreadAssignment(ts.factory.createIdentifier("options"))];
336
+ if (method !== "GET") init.push(ts.factory.createPropertyAssignment("method", ts.factory.createStringLiteral(method)));
337
+ if (bodyVar) init.push(core.createPropertyAssignment("body", ts.factory.createIdentifier(bodyVar)));
338
+ if (header.length) init.push(ts.factory.createPropertyAssignment("headers", ts.factory.createObjectLiteralExpression([ts.factory.createSpreadAssignment(ts.factory.createPropertyAccessChain(ts.factory.createIdentifier("options"), core.questionDotToken, ts.factory.createIdentifier("headers"))), ...header.map(({ name }) => core.createPropertyAssignment(name, ts.factory.createIdentifier(paramsVars[name])))], true)));
339
+ const fetchArgs = [url];
340
+ if (init.length) {
341
+ const initObj = ts.factory.createObjectLiteralExpression(init, true);
342
+ fetchArgs.push(bodyMode ? callFunction("http", bodyMode, [initObj]) : initObj);
343
+ }
344
+ return core.addComment(core.createFunctionDeclaration(name, {
345
+ modifiers: [core.modifier.export, core.modifier.async],
346
+ type: ts.factory.createTypeReferenceNode("Promise", [ts.factory.createTypeReferenceNode("ApiResponse", [response])])
347
+ }, args, core.block(ts.factory.createReturnStatement(ts.factory.createAwaitExpression(callFunction("http", responseJSON ? "fetchJson" : responseVoid ? "fetchVoid" : "fetch", fetchArgs))))), operation.summary || operation.description);
348
+ }
349
+ function generateQs(parameters, paramsVars) {
350
+ if (!parameters.length) return;
351
+ const paramsByFormatter = groupByFormatter(parameters);
352
+ return callFunction("QS", "query", Object.entries(paramsByFormatter).map(([format, params]) => {
353
+ return callFunction("QS", format, [core.createObjectLiteral(params.map((p) => [p.name, paramsVars[p.name]]))]);
354
+ }));
355
+ }
356
+ function generateUrl(path, qs) {
357
+ const spans = [];
358
+ const head = path.replace(/(.*?)\{(.+?)\}(.*?)(?=\{|$)/g, (_, head, name, literal) => {
359
+ const expression = camelCase(name);
360
+ spans.push({
361
+ expression: ts.factory.createIdentifier(expression),
362
+ literal
363
+ });
364
+ return head;
365
+ });
366
+ if (qs) spans.push({
367
+ expression: qs,
368
+ literal: ""
369
+ });
370
+ return core.createTemplateString(head, spans);
371
+ }
372
+ function callFunction(ns, name, args) {
373
+ return core.createCall(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(ns), name), { args });
374
+ }
375
+ function groupByFormatter(parameters) {
376
+ const res = {};
377
+ parameters.forEach((param) => {
378
+ const formatter = getFormatter(param);
379
+ res[formatter] = res[formatter] || [];
380
+ res[formatter].push(param);
381
+ });
382
+ return res;
383
+ }
384
+ function getFormatter({ style, explode }) {
385
+ if (style === "spaceDelimited") return "space";
386
+ if (style === "pipeDelimited") return "pipe";
387
+ if (style === "deepObject") return "deep";
388
+ if (style === "form") return explode === false ? "form" : "explode";
389
+ return explode ? "explode" : "form";
390
+ }
391
+ //#endregion
392
+ //#region src/lib/openapi-generator.ts
393
+ async function generateClientFromFile(file, options = {}) {
394
+ return generateClient(await $RefParser.parse(file), {
395
+ cwd: path.resolve(path.dirname(file)) + "/",
396
+ ...options
397
+ });
398
+ }
399
+ async function generateClient(spec, options = {}) {
400
+ if (!options.parseReference) options.parseReference = parseReference;
401
+ const context = await createContext(spec, options);
402
+ let file = await core.createSourceFileFromFile(import.meta.dirname + "/templates/_client.tpl.ts");
403
+ if (context.options.typesPath) context.typesFile = ts.createSourceFile("types.ts", "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
404
+ file = generateServers(file, spec, context);
405
+ file = generateDefaults(file, context);
406
+ file = generateFunctions(file, spec, context);
407
+ if (context.options.typesPath) return {
408
+ client: file,
409
+ types: context.typesFile
410
+ };
411
+ return file;
412
+ }
413
+ //#endregion
414
+ export { generateClientFromFile as n, generateClient as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spec2ts/openapi-client",
3
- "version": "4.0.0",
3
+ "version": "4.0.1",
4
4
  "description": "Utility to convert OpenAPI v3 specifications to Typescript HTTP client using TypeScript native compiler",
5
5
  "keywords": [
6
6
  "ast",
@@ -70,9 +70,10 @@
70
70
  "prepublishOnly": "npm run test:prepublish && npm run build"
71
71
  },
72
72
  "dependencies": {
73
- "@spec2ts/core": "^4.0.0",
74
- "@spec2ts/jsonschema": "^4.0.0",
75
- "@spec2ts/openapi": "^4.0.0",
73
+ "@apidevtools/json-schema-ref-parser": "^10.1.0",
74
+ "@spec2ts/core": "^4.0.1",
75
+ "@spec2ts/jsonschema": "^4.0.1",
76
+ "@spec2ts/openapi": "^4.0.1",
76
77
  "openapi3-ts": "^4.6.0",
77
78
  "typescript": "^6.0.0",
78
79
  "yargs": "^18.0.0"