orval 8.0.0-rc.2 → 8.0.0-rc.4
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,9 +1,8 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { FormDataArrayHandling, GetterPropType, NamingConvention, OutputClient, OutputHttpClient, OutputMode, PropertySortOrder, RefComponentSuffix, asyncReduce, createLogger, createSuccessMessage, dynamicImport, generateComponentDefinition, generateDependencyImports, generateParameterDefinition, generateSchemasDefinition, generateVerbsOptions, getFileInfo, getFullRoute, getMockFileExtensionByTypeName, getRoute,
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import yaml from "js-yaml";
|
|
2
|
+
import { FormDataArrayHandling, GetterPropType, NamingConvention, OutputClient, OutputHttpClient, OutputMode, PropertySortOrder, RefComponentSuffix, asyncReduce, conventionName, createLogger, createSuccessMessage, dynamicImport, generateComponentDefinition, generateDependencyImports, generateParameterDefinition, generateSchemasDefinition, generateVerbsOptions, getFileInfo, getFullRoute, getMockFileExtensionByTypeName, getRoute, isBoolean, isFunction, isObject, isReference, isString, isUndefined, isUrl, jsDoc, log, logError, pascal, removeFilesAndEmptyFolders, resolveRef, upath, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode } from "@orval/core";
|
|
3
|
+
import { bundle } from "@scalar/json-magic/bundle";
|
|
4
|
+
import { fetchUrls, parseJson, parseYaml, readFiles } from "@scalar/json-magic/bundle/plugins/node";
|
|
5
|
+
import { upgrade, validate } from "@scalar/openapi-parser";
|
|
7
6
|
import * as mock from "@orval/mock";
|
|
8
7
|
import { DEFAULT_MOCK_OPTIONS, generateMockImports } from "@orval/mock";
|
|
9
8
|
import angular from "@orval/angular";
|
|
@@ -13,13 +12,14 @@ import hono from "@orval/hono";
|
|
|
13
12
|
import mcp from "@orval/mcp";
|
|
14
13
|
import query from "@orval/query";
|
|
15
14
|
import swr from "@orval/swr";
|
|
16
|
-
import zod from "@orval/zod";
|
|
15
|
+
import zod, { dereference, generateZodValidationSchemaDefinition, isZodVersionV4, parseZodValidationSchemaDefinition } from "@orval/zod";
|
|
16
|
+
import chalk from "chalk";
|
|
17
17
|
import { ExecaError, execa } from "execa";
|
|
18
|
+
import fs from "fs-extra";
|
|
18
19
|
import { unique } from "remeda";
|
|
19
20
|
import { parseArgsStringToArgv } from "string-argv";
|
|
20
|
-
import https from "node:https";
|
|
21
|
-
import enquirer from "enquirer";
|
|
22
21
|
import { findUp } from "find-up";
|
|
22
|
+
import yaml from "js-yaml";
|
|
23
23
|
import { parse } from "tsconfck";
|
|
24
24
|
import fs$1 from "node:fs";
|
|
25
25
|
import { createJiti } from "jiti";
|
|
@@ -27,7 +27,7 @@ import { createJiti } from "jiti";
|
|
|
27
27
|
//#region package.json
|
|
28
28
|
var name = "orval";
|
|
29
29
|
var description = "A swagger client generator for typescript";
|
|
30
|
-
var version = "8.0.0-rc.
|
|
30
|
+
var version = "8.0.0-rc.4";
|
|
31
31
|
|
|
32
32
|
//#endregion
|
|
33
33
|
//#region src/client.ts
|
|
@@ -59,9 +59,9 @@ const getGeneratorClient = (outputClient, output) => {
|
|
|
59
59
|
if (!generator) throw new Error(`Oups... 🍻. Client not found: ${outputClient}`);
|
|
60
60
|
return generator;
|
|
61
61
|
};
|
|
62
|
-
const generateClientImports = ({ client = DEFAULT_CLIENT, implementation, imports,
|
|
62
|
+
const generateClientImports = ({ client = DEFAULT_CLIENT, implementation, imports, projectName, hasSchemaDir, isAllowSyntheticDefaultImports, hasGlobalMutator, hasTagsMutator, hasParamsSerializerOptions, packageJson, output }) => {
|
|
63
63
|
const { dependencies } = getGeneratorClient(client, output);
|
|
64
|
-
return generateDependencyImports(implementation, dependencies ? [...dependencies(hasGlobalMutator, hasParamsSerializerOptions, packageJson, output.httpClient, hasTagsMutator, output.override), ...imports] : imports,
|
|
64
|
+
return generateDependencyImports(implementation, dependencies ? [...dependencies(hasGlobalMutator, hasParamsSerializerOptions, packageJson, output.httpClient, hasTagsMutator, output.override), ...imports] : imports, projectName, hasSchemaDir, isAllowSyntheticDefaultImports);
|
|
65
65
|
};
|
|
66
66
|
const generateClientHeader = ({ outputClient = DEFAULT_CLIENT, isRequestOptions, isGlobalMutator, isMutator, provideIn, hasAwaitedType, titles, output, verbOptions, tag, clientImplementation }) => {
|
|
67
67
|
const { header } = getGeneratorClient(outputClient, output);
|
|
@@ -172,18 +172,13 @@ const generateExtraFiles = (outputClient = DEFAULT_CLIENT, verbsOptions, output,
|
|
|
172
172
|
|
|
173
173
|
//#endregion
|
|
174
174
|
//#region src/api.ts
|
|
175
|
-
|
|
176
|
-
const api = await asyncReduce(Object.entries(context.
|
|
175
|
+
async function getApiBuilder({ input, output, context }) {
|
|
176
|
+
const api = await asyncReduce(Object.entries(context.spec.paths ?? {}), async (acc, [pathRoute, verbs]) => {
|
|
177
177
|
const route = getRoute(pathRoute);
|
|
178
178
|
let resolvedVerbs = verbs;
|
|
179
|
-
let resolvedContext = context;
|
|
180
179
|
if (isReference(verbs)) {
|
|
181
180
|
const { schema, imports } = resolveRef(verbs, context);
|
|
182
181
|
resolvedVerbs = schema;
|
|
183
|
-
resolvedContext = {
|
|
184
|
-
...context,
|
|
185
|
-
...imports.length > 0 ? { specKey: imports[0].specKey } : {}
|
|
186
|
-
};
|
|
187
182
|
}
|
|
188
183
|
let verbsOptions = await generateVerbsOptions({
|
|
189
184
|
verbs: resolvedVerbs,
|
|
@@ -191,7 +186,7 @@ const getApiBuilder = async ({ input, output, context }) => {
|
|
|
191
186
|
output,
|
|
192
187
|
route,
|
|
193
188
|
pathRoute,
|
|
194
|
-
context
|
|
189
|
+
context
|
|
195
190
|
});
|
|
196
191
|
if (output.override.useDeprecatedOperations === false) verbsOptions = verbsOptions.filter((verb) => {
|
|
197
192
|
return !verb.deprecated;
|
|
@@ -203,13 +198,13 @@ const getApiBuilder = async ({ input, output, context }) => {
|
|
|
203
198
|
acc$1.push(...body.schemas, ...response.schemas);
|
|
204
199
|
return acc$1;
|
|
205
200
|
}, []);
|
|
206
|
-
const fullRoute = getFullRoute(route, verbs.servers ?? context.
|
|
201
|
+
const fullRoute = getFullRoute(route, verbs.servers ?? context.spec.servers, output.baseUrl);
|
|
207
202
|
if (!output.target) throw new Error("Output does not have a target");
|
|
208
203
|
const pathOperations = await generateOperations(output.client, verbsOptions, {
|
|
209
204
|
route: fullRoute,
|
|
210
205
|
pathRoute,
|
|
211
206
|
override: output.override,
|
|
212
|
-
context
|
|
207
|
+
context,
|
|
213
208
|
mock: output.mock,
|
|
214
209
|
output: output.target
|
|
215
210
|
}, output);
|
|
@@ -237,155 +232,146 @@ const getApiBuilder = async ({ input, output, context }) => {
|
|
|
237
232
|
importsMock: generateMockImports,
|
|
238
233
|
extraFiles
|
|
239
234
|
};
|
|
240
|
-
}
|
|
235
|
+
}
|
|
241
236
|
|
|
242
237
|
//#endregion
|
|
243
238
|
//#region src/import-open-api.ts
|
|
244
|
-
|
|
245
|
-
const
|
|
246
|
-
specs: data,
|
|
247
|
-
input,
|
|
248
|
-
workspace
|
|
249
|
-
});
|
|
239
|
+
async function importOpenApi({ spec, input, output, target, workspace, projectName }) {
|
|
240
|
+
const transformedOpenApi = await applyTransformer(spec, input.override.transformer, workspace);
|
|
250
241
|
const schemas = getApiSchemas({
|
|
251
242
|
input,
|
|
252
243
|
output,
|
|
253
244
|
target,
|
|
254
245
|
workspace,
|
|
255
|
-
|
|
246
|
+
spec: transformedOpenApi
|
|
256
247
|
});
|
|
257
248
|
const api = await getApiBuilder({
|
|
258
249
|
input,
|
|
259
250
|
output,
|
|
260
251
|
context: {
|
|
261
|
-
|
|
252
|
+
projectName,
|
|
262
253
|
target,
|
|
263
254
|
workspace,
|
|
264
|
-
|
|
255
|
+
spec: transformedOpenApi,
|
|
265
256
|
output
|
|
266
257
|
}
|
|
267
258
|
});
|
|
268
259
|
return {
|
|
269
260
|
...api,
|
|
270
|
-
schemas:
|
|
271
|
-
...schemas,
|
|
272
|
-
[target]: [...schemas[target] ?? [], ...api.schemas]
|
|
273
|
-
},
|
|
261
|
+
schemas: [...schemas, ...api.schemas],
|
|
274
262
|
target,
|
|
275
|
-
info:
|
|
263
|
+
info: transformedOpenApi.info,
|
|
264
|
+
spec: transformedOpenApi
|
|
276
265
|
};
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
const transformerFn =
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
target,
|
|
293
|
-
workspace,
|
|
294
|
-
specs,
|
|
295
|
-
output
|
|
296
|
-
};
|
|
297
|
-
const schemaDefinition = generateSchemasDefinition(spec.openapi ? spec.components?.schemas : getAllSchemas(spec, specKey), context, output.override.components.schemas.suffix, input.filters);
|
|
298
|
-
const responseDefinition = generateComponentDefinition(spec.components?.responses, context, output.override.components.responses.suffix);
|
|
299
|
-
const bodyDefinition = generateComponentDefinition(spec.components?.requestBodies, context, output.override.components.requestBodies.suffix);
|
|
300
|
-
const parameters = generateParameterDefinition(spec.components?.parameters, context, output.override.components.parameters.suffix);
|
|
301
|
-
const schemas = [
|
|
302
|
-
...schemaDefinition,
|
|
303
|
-
...responseDefinition,
|
|
304
|
-
...bodyDefinition,
|
|
305
|
-
...parameters
|
|
306
|
-
];
|
|
307
|
-
if (schemas.length === 0) return acc;
|
|
308
|
-
acc[specKey] = schemas;
|
|
309
|
-
return acc;
|
|
310
|
-
}, {});
|
|
311
|
-
};
|
|
312
|
-
const getAllSchemas = (spec, specKey) => {
|
|
313
|
-
const keysToOmit = new Set([
|
|
314
|
-
"openapi",
|
|
315
|
-
"info",
|
|
316
|
-
"servers",
|
|
317
|
-
"paths",
|
|
318
|
-
"components",
|
|
319
|
-
"security",
|
|
320
|
-
"tags",
|
|
321
|
-
"externalDocs"
|
|
322
|
-
]);
|
|
323
|
-
const cleanedSpec = Object.fromEntries(Object.entries(spec).filter(([key]) => !keysToOmit.has(key)));
|
|
324
|
-
if (specKey && isSchema(cleanedSpec)) {
|
|
325
|
-
const name$1 = upath.getSchemaFileName(specKey);
|
|
326
|
-
const additionalKeysToOmit = new Set([
|
|
327
|
-
"type",
|
|
328
|
-
"properties",
|
|
329
|
-
"allOf",
|
|
330
|
-
"oneOf",
|
|
331
|
-
"anyOf",
|
|
332
|
-
"items"
|
|
333
|
-
]);
|
|
334
|
-
return {
|
|
335
|
-
[name$1]: cleanedSpec,
|
|
336
|
-
...getAllSchemas(Object.fromEntries(Object.entries(cleanedSpec).filter(([key]) => !additionalKeysToOmit.has(key))))
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
return {
|
|
340
|
-
...Object.entries(cleanedSpec).reduce((acc, [key, value]) => {
|
|
341
|
-
if (!isObject(value)) return acc;
|
|
342
|
-
if (!isSchema(value) && !isReference(value)) return {
|
|
343
|
-
...acc,
|
|
344
|
-
...getAllSchemas(value)
|
|
345
|
-
};
|
|
346
|
-
acc[key] = value;
|
|
347
|
-
return acc;
|
|
348
|
-
}, {}),
|
|
349
|
-
...spec?.components?.schemas
|
|
266
|
+
}
|
|
267
|
+
async function applyTransformer(openApi, transformer, workspace) {
|
|
268
|
+
const transformerFn = transformer ? await dynamicImport(transformer, workspace) : void 0;
|
|
269
|
+
if (!transformerFn) return openApi;
|
|
270
|
+
const transformedOpenApi = transformerFn(openApi);
|
|
271
|
+
const { valid, errors } = await validate(transformedOpenApi);
|
|
272
|
+
if (!valid) throw new Error(`Validation failed`, { cause: errors });
|
|
273
|
+
return transformedOpenApi;
|
|
274
|
+
}
|
|
275
|
+
function getApiSchemas({ input, output, target, workspace, spec }) {
|
|
276
|
+
const context = {
|
|
277
|
+
target,
|
|
278
|
+
workspace,
|
|
279
|
+
spec,
|
|
280
|
+
output
|
|
350
281
|
};
|
|
351
|
-
|
|
282
|
+
const schemaDefinition = generateSchemasDefinition(spec.components?.schemas, context, output.override.components.schemas.suffix, input.filters);
|
|
283
|
+
const responseDefinition = generateComponentDefinition(spec.components?.responses, context, output.override.components.responses.suffix);
|
|
284
|
+
const bodyDefinition = generateComponentDefinition(spec.components?.requestBodies, context, output.override.components.requestBodies.suffix);
|
|
285
|
+
const parameters = generateParameterDefinition(spec.components?.parameters, context, output.override.components.parameters.suffix);
|
|
286
|
+
return [
|
|
287
|
+
...schemaDefinition,
|
|
288
|
+
...responseDefinition,
|
|
289
|
+
...bodyDefinition,
|
|
290
|
+
...parameters
|
|
291
|
+
];
|
|
292
|
+
}
|
|
352
293
|
|
|
353
294
|
//#endregion
|
|
354
295
|
//#region src/import-specs.ts
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const importSpecs = async (workspace, options) => {
|
|
296
|
+
async function resolveSpec(input, parserOptions) {
|
|
297
|
+
const dereferencedData = dereferenceExternalRef(await bundle(input, {
|
|
298
|
+
plugins: [
|
|
299
|
+
readFiles(),
|
|
300
|
+
fetchUrls({ headers: parserOptions?.headers }),
|
|
301
|
+
parseJson(),
|
|
302
|
+
parseYaml()
|
|
303
|
+
],
|
|
304
|
+
treeShake: true
|
|
305
|
+
}));
|
|
306
|
+
const { valid, errors } = await validate(dereferencedData);
|
|
307
|
+
if (!valid) throw new Error("Validation failed", { cause: errors });
|
|
308
|
+
const { specification } = upgrade(dereferencedData);
|
|
309
|
+
return specification;
|
|
310
|
+
}
|
|
311
|
+
async function importSpecs(workspace, options, projectName) {
|
|
372
312
|
const { input, output } = options;
|
|
373
|
-
if (!isString(input.target)) return importOpenApi({
|
|
374
|
-
data: { [workspace]: input.target },
|
|
375
|
-
input,
|
|
376
|
-
output,
|
|
377
|
-
target: workspace,
|
|
378
|
-
workspace
|
|
379
|
-
});
|
|
380
|
-
const isPathUrl = isUrl(input.target);
|
|
381
313
|
return importOpenApi({
|
|
382
|
-
|
|
314
|
+
spec: await resolveSpec(input.target, input.parserOptions),
|
|
383
315
|
input,
|
|
384
316
|
output,
|
|
385
317
|
target: input.target,
|
|
386
|
-
workspace
|
|
318
|
+
workspace,
|
|
319
|
+
projectName
|
|
387
320
|
});
|
|
388
|
-
}
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* The plugins from `@scalar/json-magic` does not dereference $ref.
|
|
324
|
+
* Instead if fetches them and puts them under x-ext, and changes the $ref to point to #x-ext/<name>.
|
|
325
|
+
* This function dereferences those x-ext $ref's.
|
|
326
|
+
*/
|
|
327
|
+
function dereferenceExternalRef(data) {
|
|
328
|
+
const extensions = data["x-ext"] ?? {};
|
|
329
|
+
const UNWANTED_KEYS = new Set(["$schema", "$id"]);
|
|
330
|
+
function scrub(obj) {
|
|
331
|
+
if (obj === null || obj === void 0) return obj;
|
|
332
|
+
if (Array.isArray(obj)) return obj.map((x) => scrub(x));
|
|
333
|
+
if (typeof obj === "object") {
|
|
334
|
+
const rec = obj;
|
|
335
|
+
const out = {};
|
|
336
|
+
for (const [k, v] of Object.entries(rec)) {
|
|
337
|
+
if (UNWANTED_KEYS.has(k)) continue;
|
|
338
|
+
out[k] = scrub(v);
|
|
339
|
+
}
|
|
340
|
+
return out;
|
|
341
|
+
}
|
|
342
|
+
return obj;
|
|
343
|
+
}
|
|
344
|
+
function replaceRefs(obj) {
|
|
345
|
+
if (obj === null || obj === void 0) return obj;
|
|
346
|
+
if (typeof obj === "object") {
|
|
347
|
+
if (Array.isArray(obj)) return obj.map((element) => replaceRefs(element));
|
|
348
|
+
const record = obj;
|
|
349
|
+
if ("$ref" in record && typeof record.$ref === "string") {
|
|
350
|
+
const refValue = record.$ref;
|
|
351
|
+
if (refValue.startsWith("#/x-ext/")) {
|
|
352
|
+
const parts = refValue.replace("#/x-ext/", "").split("/");
|
|
353
|
+
const extKey = parts.shift();
|
|
354
|
+
if (extKey) {
|
|
355
|
+
let refObj = extensions[extKey];
|
|
356
|
+
for (const p of parts) if (refObj && typeof refObj === "object" && p in refObj) refObj = refObj[p];
|
|
357
|
+
else {
|
|
358
|
+
refObj = void 0;
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
361
|
+
if (refObj) return replaceRefs(scrub(refObj));
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
const result$1 = {};
|
|
366
|
+
for (const [key, value] of Object.entries(record)) result$1[key] = replaceRefs(value);
|
|
367
|
+
return result$1;
|
|
368
|
+
}
|
|
369
|
+
return obj;
|
|
370
|
+
}
|
|
371
|
+
const result = {};
|
|
372
|
+
for (const [key, value] of Object.entries(data)) if (key !== "x-ext") result[key] = replaceRefs(value);
|
|
373
|
+
return result;
|
|
374
|
+
}
|
|
389
375
|
|
|
390
376
|
//#endregion
|
|
391
377
|
//#region src/utils/execute-hook.ts
|
|
@@ -409,123 +395,6 @@ async function executeObjectCommand(command, args) {
|
|
|
409
395
|
else if (isFunction(command.command)) await command.command();
|
|
410
396
|
}
|
|
411
397
|
|
|
412
|
-
//#endregion
|
|
413
|
-
//#region src/utils/request.ts
|
|
414
|
-
const request = (urlOptions, data) => {
|
|
415
|
-
return new Promise((resolve, reject) => {
|
|
416
|
-
const req = https.request(urlOptions, (res) => {
|
|
417
|
-
let body = "";
|
|
418
|
-
res.on("data", (chunk) => body += chunk.toString());
|
|
419
|
-
res.on("error", reject);
|
|
420
|
-
res.on("end", () => {
|
|
421
|
-
const response = {
|
|
422
|
-
status: res.statusCode,
|
|
423
|
-
headers: res.headers,
|
|
424
|
-
body: JSON.parse(body)
|
|
425
|
-
};
|
|
426
|
-
if (res.statusCode && res.statusCode >= 200 && res.statusCode <= 299) resolve(response);
|
|
427
|
-
else reject(response);
|
|
428
|
-
});
|
|
429
|
-
});
|
|
430
|
-
req.on("error", reject);
|
|
431
|
-
if (data) req.write(data, "binary");
|
|
432
|
-
req.end();
|
|
433
|
-
});
|
|
434
|
-
};
|
|
435
|
-
|
|
436
|
-
//#endregion
|
|
437
|
-
//#region src/utils/github.ts
|
|
438
|
-
const getGithubSpecReq = ({ accessToken, repo, owner, branch, path: path$1 }) => {
|
|
439
|
-
const payload = JSON.stringify({ query: `query {
|
|
440
|
-
repository(name: "${repo}", owner: "${owner}") {
|
|
441
|
-
object(expression: "${branch}:${path$1}") {
|
|
442
|
-
... on Blob {
|
|
443
|
-
text
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
}` });
|
|
448
|
-
return [{
|
|
449
|
-
method: "POST",
|
|
450
|
-
hostname: "api.github.com",
|
|
451
|
-
path: "/graphql",
|
|
452
|
-
headers: {
|
|
453
|
-
"content-type": "application/json",
|
|
454
|
-
"user-agent": "orval-importer",
|
|
455
|
-
authorization: `bearer ${accessToken}`,
|
|
456
|
-
"Content-Length": payload.length
|
|
457
|
-
}
|
|
458
|
-
}, payload];
|
|
459
|
-
};
|
|
460
|
-
let githubToken = null;
|
|
461
|
-
const getGithubAcessToken = async (githubTokenPath) => {
|
|
462
|
-
if (githubToken) return githubToken;
|
|
463
|
-
if (await fs.pathExists(githubTokenPath)) return fs.readFile(githubTokenPath, "utf8");
|
|
464
|
-
else {
|
|
465
|
-
const answers = await enquirer.prompt([{
|
|
466
|
-
type: "input",
|
|
467
|
-
name: "githubToken",
|
|
468
|
-
message: "Please provide a GitHub token with `repo` rules checked (https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/)"
|
|
469
|
-
}, {
|
|
470
|
-
type: "confirm",
|
|
471
|
-
name: "saveToken",
|
|
472
|
-
message: "Would you like to store your token for the next time? (stored in your node_modules)"
|
|
473
|
-
}]);
|
|
474
|
-
githubToken = answers.githubToken;
|
|
475
|
-
if (answers.saveToken) await fs.outputFile(githubTokenPath, answers.githubToken);
|
|
476
|
-
return answers.githubToken;
|
|
477
|
-
}
|
|
478
|
-
};
|
|
479
|
-
const getGithubOpenApi = async (url) => {
|
|
480
|
-
const githubTokenPath = upath.join(import.meta.dirname, ".githubToken");
|
|
481
|
-
const accessToken = await getGithubAcessToken(githubTokenPath);
|
|
482
|
-
const [info] = url.split("github.com/").slice(-1);
|
|
483
|
-
const [owner, repo, , branch, ...paths] = info.split("/");
|
|
484
|
-
const path$1 = paths.join("/");
|
|
485
|
-
try {
|
|
486
|
-
const { body } = await request(...getGithubSpecReq({
|
|
487
|
-
accessToken,
|
|
488
|
-
repo,
|
|
489
|
-
owner,
|
|
490
|
-
branch,
|
|
491
|
-
path: path$1
|
|
492
|
-
}));
|
|
493
|
-
if (body.errors?.length) {
|
|
494
|
-
if (body.errors?.some((error) => error?.type === "NOT_FOUND")) {
|
|
495
|
-
if ((await enquirer.prompt([{
|
|
496
|
-
type: "confirm",
|
|
497
|
-
name: "removeToken",
|
|
498
|
-
message: "Your token doesn't have the correct permissions, should we remove it?"
|
|
499
|
-
}])).removeToken) await fs.unlink(githubTokenPath);
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
return body.data?.repository?.object.text;
|
|
503
|
-
} catch (error) {
|
|
504
|
-
if (!error.body) throw new Error(`Oups... 🍻. ${error}`);
|
|
505
|
-
if (error.body.message === "Bad credentials") {
|
|
506
|
-
if ((await enquirer.prompt([{
|
|
507
|
-
type: "confirm",
|
|
508
|
-
name: "removeToken",
|
|
509
|
-
message: "Your token doesn't have the correct permissions, should we remove it?"
|
|
510
|
-
}])).removeToken) await fs.unlink(githubTokenPath);
|
|
511
|
-
}
|
|
512
|
-
throw new Error(error.body.message || `Oups... 🍻. ${error}`);
|
|
513
|
-
}
|
|
514
|
-
};
|
|
515
|
-
const githubResolver = {
|
|
516
|
-
order: 199,
|
|
517
|
-
canRead(file) {
|
|
518
|
-
return file.url.includes("github.com");
|
|
519
|
-
},
|
|
520
|
-
read(file) {
|
|
521
|
-
return getGithubOpenApi(file.url);
|
|
522
|
-
}
|
|
523
|
-
};
|
|
524
|
-
|
|
525
|
-
//#endregion
|
|
526
|
-
//#region src/utils/http-resolver.ts
|
|
527
|
-
const httpResolver = { safeUrlResolver: false };
|
|
528
|
-
|
|
529
398
|
//#endregion
|
|
530
399
|
//#region src/utils/package-json.ts
|
|
531
400
|
const loadPackageJson = async (packageJson, workspace = process.cwd()) => {
|
|
@@ -621,7 +490,7 @@ const loadTsconfig = async (tsconfig, workspace = process.cwd()) => {
|
|
|
621
490
|
function defineConfig(options) {
|
|
622
491
|
return options;
|
|
623
492
|
}
|
|
624
|
-
|
|
493
|
+
function createFormData(workspace, formData) {
|
|
625
494
|
const defaultArrayHandling = FormDataArrayHandling.SERIALIZE;
|
|
626
495
|
if (formData === void 0) return {
|
|
627
496
|
disabled: false,
|
|
@@ -646,8 +515,17 @@ const createFormData = (workspace, formData) => {
|
|
|
646
515
|
mutator: normalizeMutator(workspace, formData),
|
|
647
516
|
arrayHandling: defaultArrayHandling
|
|
648
517
|
};
|
|
649
|
-
}
|
|
650
|
-
|
|
518
|
+
}
|
|
519
|
+
function normalizeSchemasOption(schemas, workspace) {
|
|
520
|
+
if (!schemas) return;
|
|
521
|
+
if (isString(schemas)) return normalizePath(schemas, workspace);
|
|
522
|
+
const types = Array.isArray(schemas.type) ? schemas.type : [schemas.type];
|
|
523
|
+
return {
|
|
524
|
+
path: normalizePath(schemas.path, workspace),
|
|
525
|
+
type: types
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
async function normalizeOptions(optionsExport, workspace = process.cwd(), globalOptions = {}) {
|
|
651
529
|
const options = await (isFunction(optionsExport) ? optionsExport() : optionsExport);
|
|
652
530
|
if (!options.input) throw new Error(chalk.red(`Config require an input`));
|
|
653
531
|
if (!options.output) throw new Error(chalk.red(`Config require an output`));
|
|
@@ -680,15 +558,13 @@ const normalizeOptions = async (optionsExport, workspace = process.cwd(), global
|
|
|
680
558
|
const normalizedOptions = {
|
|
681
559
|
input: {
|
|
682
560
|
target: globalOptions.input ? normalizePathOrUrl(globalOptions.input, process.cwd()) : normalizePathOrUrl(inputOptions.target, workspace),
|
|
683
|
-
validation: inputOptions.validation || false,
|
|
684
561
|
override: { transformer: normalizePath(inputOptions.override?.transformer, workspace) },
|
|
685
|
-
|
|
686
|
-
parserOptions:
|
|
687
|
-
filters: inputOptions.filters
|
|
562
|
+
filters: inputOptions.filters,
|
|
563
|
+
parserOptions: inputOptions.parserOptions
|
|
688
564
|
},
|
|
689
565
|
output: {
|
|
690
566
|
target: globalOptions.output ? normalizePath(globalOptions.output, process.cwd()) : normalizePath(outputOptions.target, outputWorkspace),
|
|
691
|
-
schemas:
|
|
567
|
+
schemas: normalizeSchemasOption(outputOptions.schemas, outputWorkspace),
|
|
692
568
|
namingConvention: outputOptions.namingConvention || NamingConvention.CAMEL_CASE,
|
|
693
569
|
fileExtension: outputOptions.fileExtension || defaultFileExtension,
|
|
694
570
|
workspace: outputOptions.workspace ? outputWorkspace : void 0,
|
|
@@ -785,12 +661,15 @@ const normalizeOptions = async (optionsExport, workspace = process.cwd(), global
|
|
|
785
661
|
fetch: {
|
|
786
662
|
includeHttpResponseReturnType: outputOptions.override?.fetch?.includeHttpResponseReturnType ?? true,
|
|
787
663
|
forceSuccessResponse: outputOptions.override?.fetch?.forceSuccessResponse ?? false,
|
|
664
|
+
useZodSchemaResponse: outputOptions.override?.fetch?.useZodSchemaResponse ?? false,
|
|
665
|
+
runtimeValidation: outputOptions.override?.fetch?.runtimeValidation ?? false,
|
|
788
666
|
...outputOptions.override?.fetch
|
|
789
667
|
},
|
|
790
668
|
useDates: outputOptions.override?.useDates || false,
|
|
791
669
|
useDeprecatedOperations: outputOptions.override?.useDeprecatedOperations ?? true,
|
|
792
670
|
enumGenerationType: outputOptions.override?.enumGenerationType ?? "const",
|
|
793
|
-
suppressReadonlyModifier: outputOptions.override?.suppressReadonlyModifier || false
|
|
671
|
+
suppressReadonlyModifier: outputOptions.override?.suppressReadonlyModifier || false,
|
|
672
|
+
aliasCombinedTypes: outputOptions.override?.aliasCombinedTypes ?? false
|
|
794
673
|
},
|
|
795
674
|
allParamsOptional: outputOptions.allParamsOptional ?? false,
|
|
796
675
|
urlEncodeParameters: outputOptions.urlEncodeParameters ?? false,
|
|
@@ -802,15 +681,8 @@ const normalizeOptions = async (optionsExport, workspace = process.cwd(), global
|
|
|
802
681
|
if (!normalizedOptions.input.target) throw new Error(chalk.red(`Config require an input target`));
|
|
803
682
|
if (!normalizedOptions.output.target && !normalizedOptions.output.schemas) throw new Error(chalk.red(`Config require an output target or schemas`));
|
|
804
683
|
return normalizedOptions;
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
validate: true,
|
|
808
|
-
resolve: {
|
|
809
|
-
github: githubResolver,
|
|
810
|
-
http: httpResolver
|
|
811
|
-
}
|
|
812
|
-
};
|
|
813
|
-
const normalizeMutator = (workspace, mutator) => {
|
|
684
|
+
}
|
|
685
|
+
function normalizeMutator(workspace, mutator) {
|
|
814
686
|
if (isObject(mutator)) {
|
|
815
687
|
if (!mutator.path) throw new Error(chalk.red(`Mutator need a path`));
|
|
816
688
|
return {
|
|
@@ -824,16 +696,16 @@ const normalizeMutator = (workspace, mutator) => {
|
|
|
824
696
|
default: true
|
|
825
697
|
};
|
|
826
698
|
return mutator;
|
|
827
|
-
}
|
|
828
|
-
|
|
699
|
+
}
|
|
700
|
+
function normalizePathOrUrl(path$1, workspace) {
|
|
829
701
|
if (isString(path$1) && !isUrl(path$1)) return normalizePath(path$1, workspace);
|
|
830
702
|
return path$1;
|
|
831
|
-
}
|
|
832
|
-
|
|
703
|
+
}
|
|
704
|
+
function normalizePath(path$1, workspace) {
|
|
833
705
|
if (!isString(path$1)) return path$1;
|
|
834
706
|
return upath.resolve(workspace, path$1);
|
|
835
|
-
}
|
|
836
|
-
|
|
707
|
+
}
|
|
708
|
+
function normalizeOperationsAndTags(operationsOrTags, workspace, global) {
|
|
837
709
|
return Object.fromEntries(Object.entries(operationsOrTags).map(([key, { transformer, mutator, formData, formUrlEncoded, paramsSerializer, query: query$1, zod: zod$1, ...rest }]) => {
|
|
838
710
|
return [key, {
|
|
839
711
|
...rest,
|
|
@@ -878,16 +750,16 @@ const normalizeOperationsAndTags = (operationsOrTags, workspace, global) => {
|
|
|
878
750
|
...paramsSerializer ? { paramsSerializer: normalizeMutator(workspace, paramsSerializer) } : {}
|
|
879
751
|
}];
|
|
880
752
|
}));
|
|
881
|
-
}
|
|
882
|
-
|
|
753
|
+
}
|
|
754
|
+
function normalizeOutputMode(mode) {
|
|
883
755
|
if (!mode) return OutputMode.SINGLE;
|
|
884
756
|
if (!Object.values(OutputMode).includes(mode)) {
|
|
885
757
|
createLogger().warn(chalk.yellow(`Unknown the provided mode => ${mode}`));
|
|
886
758
|
return OutputMode.SINGLE;
|
|
887
759
|
}
|
|
888
760
|
return mode;
|
|
889
|
-
}
|
|
890
|
-
|
|
761
|
+
}
|
|
762
|
+
function normalizeHooks(hooks) {
|
|
891
763
|
return Object.keys(hooks).reduce((acc, key) => {
|
|
892
764
|
if (isString(hooks[key])) return {
|
|
893
765
|
...acc,
|
|
@@ -907,19 +779,19 @@ const normalizeHooks = (hooks) => {
|
|
|
907
779
|
};
|
|
908
780
|
return acc;
|
|
909
781
|
}, {});
|
|
910
|
-
}
|
|
911
|
-
|
|
782
|
+
}
|
|
783
|
+
function normalizeHonoOptions(hono$1 = {}, workspace) {
|
|
912
784
|
return {
|
|
913
785
|
...hono$1.handlers ? { handlers: upath.resolve(workspace, hono$1.handlers) } : {},
|
|
914
786
|
compositeRoute: hono$1.compositeRoute ?? "",
|
|
915
787
|
validator: hono$1.validator ?? true,
|
|
916
788
|
validatorOutputPath: hono$1.validatorOutputPath ? upath.resolve(workspace, hono$1.validatorOutputPath) : ""
|
|
917
789
|
};
|
|
918
|
-
}
|
|
919
|
-
|
|
790
|
+
}
|
|
791
|
+
function normalizeJSDocOptions(jsdoc = {}) {
|
|
920
792
|
return { ...jsdoc };
|
|
921
|
-
}
|
|
922
|
-
|
|
793
|
+
}
|
|
794
|
+
function normalizeQueryOptions(queryOptions = {}, outputWorkspace, globalOptions = {}) {
|
|
923
795
|
if (queryOptions.options) console.warn("[WARN] Using query options is deprecated and will be removed in a future major release. Please use queryOptions or mutationOptions instead.");
|
|
924
796
|
return {
|
|
925
797
|
...isUndefined(queryOptions.usePrefetch) ? {} : { usePrefetch: queryOptions.usePrefetch },
|
|
@@ -953,14 +825,16 @@ const normalizeQueryOptions = (queryOptions = {}, outputWorkspace, globalOptions
|
|
|
953
825
|
...isUndefined(globalOptions.version) ? {} : { version: globalOptions.version },
|
|
954
826
|
...isUndefined(queryOptions.version) ? {} : { version: queryOptions.version }
|
|
955
827
|
};
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
]
|
|
828
|
+
}
|
|
829
|
+
function getDefaultFilesHeader({ title, description: description$1, version: version$1 } = {}) {
|
|
830
|
+
return [
|
|
831
|
+
`Generated by ${name} v${version} 🍺`,
|
|
832
|
+
`Do not edit manually.`,
|
|
833
|
+
...title ? [title] : [],
|
|
834
|
+
...description$1 ? [description$1] : [],
|
|
835
|
+
...version$1 ? [`OpenAPI spec version: ${version$1}`] : []
|
|
836
|
+
];
|
|
837
|
+
}
|
|
964
838
|
|
|
965
839
|
//#endregion
|
|
966
840
|
//#region src/utils/watcher.ts
|
|
@@ -997,60 +871,169 @@ async function startWatcher(watchOptions, watchFn, defaultTarget = ".") {
|
|
|
997
871
|
});
|
|
998
872
|
}
|
|
999
873
|
|
|
874
|
+
//#endregion
|
|
875
|
+
//#region src/write-zod-specs.ts
|
|
876
|
+
function generateZodSchemaFileContent(header, schemaName, zodContent) {
|
|
877
|
+
return `${header}import { z as zod } from 'zod';
|
|
878
|
+
|
|
879
|
+
export const ${schemaName} = ${zodContent}
|
|
880
|
+
|
|
881
|
+
export type ${schemaName} = zod.infer<typeof ${schemaName}>;
|
|
882
|
+
`;
|
|
883
|
+
}
|
|
884
|
+
async function writeZodSchemaIndex(schemasPath, fileExtension, header, schemaNames, namingConvention, shouldMergeExisting = false) {
|
|
885
|
+
const importFileExtension = fileExtension.replace(/\.ts$/, "");
|
|
886
|
+
const indexPath = upath.join(schemasPath, `index${fileExtension}`);
|
|
887
|
+
let existingExports = "";
|
|
888
|
+
if (shouldMergeExisting && await fs.pathExists(indexPath)) {
|
|
889
|
+
const existingContent = await fs.readFile(indexPath, "utf-8");
|
|
890
|
+
const headerMatch = existingContent.match(/^(\/\*\*[\s\S]*?\*\/\n)?/);
|
|
891
|
+
const headerPart = headerMatch ? headerMatch[0] : "";
|
|
892
|
+
existingExports = existingContent.substring(headerPart.length).trim();
|
|
893
|
+
}
|
|
894
|
+
const newExports = schemaNames.map((schemaName) => {
|
|
895
|
+
return `export * from './${conventionName(schemaName, namingConvention)}${importFileExtension}';`;
|
|
896
|
+
}).sort().join("\n");
|
|
897
|
+
const allExports = existingExports ? `${existingExports}\n${newExports}` : newExports;
|
|
898
|
+
const uniqueExports = [...new Set(allExports.split("\n"))].filter((line) => line.trim()).sort().join("\n");
|
|
899
|
+
await fs.outputFile(indexPath, `${header}\n${uniqueExports}\n`);
|
|
900
|
+
}
|
|
901
|
+
async function writeZodSchemas(builder, schemasPath, fileExtension, header, output) {
|
|
902
|
+
const schemasWithOpenApiDef = builder.schemas.filter((s) => s.schema);
|
|
903
|
+
await Promise.all(schemasWithOpenApiDef.map(async (generatorSchema) => {
|
|
904
|
+
const { name: name$1, schema: schemaObject } = generatorSchema;
|
|
905
|
+
if (!schemaObject) return;
|
|
906
|
+
const fileName = conventionName(name$1, output.namingConvention);
|
|
907
|
+
const filePath = upath.join(schemasPath, `${fileName}${fileExtension}`);
|
|
908
|
+
const context = {
|
|
909
|
+
spec: builder.spec,
|
|
910
|
+
target: builder.target,
|
|
911
|
+
workspace: "",
|
|
912
|
+
output
|
|
913
|
+
};
|
|
914
|
+
const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
|
|
915
|
+
const strict = typeof output.override?.zod?.strict === "object" ? output.override.zod.strict.body ?? false : output.override?.zod?.strict ?? false;
|
|
916
|
+
const coerce = typeof output.override?.zod?.coerce === "object" ? output.override.zod.coerce.body ?? false : output.override?.zod?.coerce ?? false;
|
|
917
|
+
const parsedZodDefinition = parseZodValidationSchemaDefinition(generateZodValidationSchemaDefinition(dereference(schemaObject, context), context, name$1, strict, isZodV4, { required: true }), context, coerce, strict, isZodV4);
|
|
918
|
+
const fileContent = generateZodSchemaFileContent(header, name$1, parsedZodDefinition.consts ? `${parsedZodDefinition.consts}\n${parsedZodDefinition.zod}` : parsedZodDefinition.zod);
|
|
919
|
+
await fs.outputFile(filePath, fileContent);
|
|
920
|
+
}));
|
|
921
|
+
if (output.indexFiles) await writeZodSchemaIndex(schemasPath, fileExtension, header, schemasWithOpenApiDef.map((schema) => schema.name), output.namingConvention, false);
|
|
922
|
+
}
|
|
923
|
+
async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension, header, output, context) {
|
|
924
|
+
const verbOptionsArray = Object.values(verbOptions);
|
|
925
|
+
if (verbOptionsArray.length === 0) return;
|
|
926
|
+
const isZodV4 = !!output.packageJson && isZodVersionV4(output.packageJson);
|
|
927
|
+
const strict = typeof output.override?.zod?.strict === "object" ? output.override.zod.strict.body ?? false : output.override?.zod?.strict ?? false;
|
|
928
|
+
const coerce = typeof output.override?.zod?.coerce === "object" ? output.override.zod.coerce.body ?? false : output.override?.zod?.coerce ?? false;
|
|
929
|
+
const generateVerbsSchemas = verbOptionsArray.flatMap((verbOption) => {
|
|
930
|
+
const operation = verbOption.originalOperation;
|
|
931
|
+
const bodySchema = operation.requestBody && "content" in operation.requestBody ? operation.requestBody.content["application/json"]?.schema : void 0;
|
|
932
|
+
const bodySchemas = bodySchema ? [{
|
|
933
|
+
name: `${pascal(verbOption.operationName)}Body`,
|
|
934
|
+
schema: dereference(bodySchema, context)
|
|
935
|
+
}] : [];
|
|
936
|
+
const queryParams = operation.parameters?.filter((p) => "in" in p && p.in === "query");
|
|
937
|
+
const queryParamsSchemas = queryParams && queryParams.length > 0 ? [{
|
|
938
|
+
name: `${pascal(verbOption.operationName)}Params`,
|
|
939
|
+
schema: {
|
|
940
|
+
type: "object",
|
|
941
|
+
properties: Object.fromEntries(queryParams.filter((p) => "schema" in p && p.schema).map((p) => [p.name, dereference(p.schema, context)])),
|
|
942
|
+
required: queryParams.filter((p) => p.required).map((p) => p.name)
|
|
943
|
+
}
|
|
944
|
+
}] : [];
|
|
945
|
+
const headerParams = operation.parameters?.filter((p) => "in" in p && p.in === "header");
|
|
946
|
+
const headerParamsSchemas = headerParams && headerParams.length > 0 ? [{
|
|
947
|
+
name: `${pascal(verbOption.operationName)}Headers`,
|
|
948
|
+
schema: {
|
|
949
|
+
type: "object",
|
|
950
|
+
properties: Object.fromEntries(headerParams.filter((p) => "schema" in p && p.schema).map((p) => [p.name, dereference(p.schema, context)])),
|
|
951
|
+
required: headerParams.filter((p) => p.required).map((p) => p.name)
|
|
952
|
+
}
|
|
953
|
+
}] : [];
|
|
954
|
+
return [
|
|
955
|
+
...bodySchemas,
|
|
956
|
+
...queryParamsSchemas,
|
|
957
|
+
...headerParamsSchemas
|
|
958
|
+
];
|
|
959
|
+
});
|
|
960
|
+
await Promise.all(generateVerbsSchemas.map(async ({ name: name$1, schema }) => {
|
|
961
|
+
const fileName = conventionName(name$1, output.namingConvention);
|
|
962
|
+
const filePath = upath.join(schemasPath, `${fileName}${fileExtension}`);
|
|
963
|
+
const parsedZodDefinition = parseZodValidationSchemaDefinition(generateZodValidationSchemaDefinition(schema, context, name$1, strict, isZodV4, { required: true }), context, coerce, strict, isZodV4);
|
|
964
|
+
const fileContent = generateZodSchemaFileContent(header, name$1, parsedZodDefinition.consts ? `${parsedZodDefinition.consts}\n${parsedZodDefinition.zod}` : parsedZodDefinition.zod);
|
|
965
|
+
await fs.outputFile(filePath, fileContent);
|
|
966
|
+
}));
|
|
967
|
+
if (output.indexFiles && generateVerbsSchemas.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, generateVerbsSchemas.map((s) => s.name), output.namingConvention, true);
|
|
968
|
+
}
|
|
969
|
+
|
|
1000
970
|
//#endregion
|
|
1001
971
|
//#region src/write-specs.ts
|
|
1002
|
-
|
|
972
|
+
function getHeader(option, info) {
|
|
1003
973
|
if (!option) return "";
|
|
1004
974
|
const header = option(info);
|
|
1005
975
|
return Array.isArray(header) ? jsDoc({ description: header }) : header;
|
|
1006
|
-
}
|
|
1007
|
-
|
|
976
|
+
}
|
|
977
|
+
async function writeSpecs(builder, workspace, options, projectName) {
|
|
1008
978
|
const { info = {
|
|
1009
979
|
title: "",
|
|
1010
980
|
version: 0
|
|
1011
981
|
}, schemas, target } = builder;
|
|
1012
982
|
const { output } = options;
|
|
1013
983
|
const projectTitle = projectName ?? info.title;
|
|
1014
|
-
const specsName = Object.keys(schemas).reduce((acc, specKey) => {
|
|
1015
|
-
acc[specKey] = upath.getSpecName(specKey, target).slice(1).split("/").join("-");
|
|
1016
|
-
return acc;
|
|
1017
|
-
}, {});
|
|
1018
984
|
const header = getHeader(output.override.header, info);
|
|
1019
|
-
if (output.schemas) {
|
|
1020
|
-
const
|
|
1021
|
-
const
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
985
|
+
if (output.schemas) if (isString(output.schemas)) {
|
|
986
|
+
const fileExtension = output.fileExtension || ".ts";
|
|
987
|
+
const schemaPath = output.schemas;
|
|
988
|
+
await writeSchemas({
|
|
989
|
+
schemaPath,
|
|
990
|
+
schemas,
|
|
991
|
+
target,
|
|
992
|
+
namingConvention: output.namingConvention,
|
|
993
|
+
fileExtension,
|
|
994
|
+
header,
|
|
995
|
+
indexFiles: output.indexFiles
|
|
996
|
+
});
|
|
997
|
+
} else {
|
|
998
|
+
const types = Array.isArray(output.schemas.type) ? output.schemas.type : [output.schemas.type];
|
|
999
|
+
for (const schemaType of types) if (schemaType === "typescript") {
|
|
1000
|
+
const fileExtension = output.fileExtension || ".ts";
|
|
1001
|
+
await writeSchemas({
|
|
1002
|
+
schemaPath: output.schemas.path,
|
|
1003
|
+
schemas,
|
|
1030
1004
|
target,
|
|
1031
1005
|
namingConvention: output.namingConvention,
|
|
1032
1006
|
fileExtension,
|
|
1033
|
-
specsName,
|
|
1034
|
-
specKey,
|
|
1035
|
-
isRootKey: isRootKey(specKey, target),
|
|
1036
1007
|
header,
|
|
1037
1008
|
indexFiles: output.indexFiles
|
|
1038
1009
|
});
|
|
1039
|
-
})
|
|
1010
|
+
} else if (schemaType === "zod") {
|
|
1011
|
+
const fileExtension = ".zod.ts";
|
|
1012
|
+
await writeZodSchemas(builder, output.schemas.path, fileExtension, header, output);
|
|
1013
|
+
if (builder.verbOptions) await writeZodSchemasFromVerbs(builder.verbOptions, output.schemas.path, fileExtension, header, output, {
|
|
1014
|
+
spec: builder.spec,
|
|
1015
|
+
target: builder.target,
|
|
1016
|
+
workspace,
|
|
1017
|
+
output
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1040
1020
|
}
|
|
1041
1021
|
let implementationPaths = [];
|
|
1042
1022
|
if (output.target) implementationPaths = await getWriteMode(output.mode)({
|
|
1043
1023
|
builder,
|
|
1044
1024
|
workspace,
|
|
1045
1025
|
output,
|
|
1046
|
-
|
|
1026
|
+
projectName,
|
|
1047
1027
|
header,
|
|
1048
1028
|
needSchema: !output.schemas && output.client !== "zod"
|
|
1049
1029
|
});
|
|
1050
1030
|
if (output.workspace) {
|
|
1051
1031
|
const workspacePath = output.workspace;
|
|
1052
1032
|
const imports = implementationPaths.filter((path$1) => !output.mock || !path$1.endsWith(`.${getMockFileExtensionByTypeName(output.mock)}.ts`)).map((path$1) => upath.relativeSafe(workspacePath, getFileInfo(path$1).pathWithoutExtension));
|
|
1053
|
-
if (output.schemas)
|
|
1033
|
+
if (output.schemas) {
|
|
1034
|
+
const schemasPath = typeof output.schemas === "string" ? output.schemas : output.schemas.path;
|
|
1035
|
+
imports.push(upath.relativeSafe(workspacePath, getFileInfo(schemasPath).dirname));
|
|
1036
|
+
}
|
|
1054
1037
|
if (output.indexFiles) {
|
|
1055
1038
|
const indexFile = upath.join(workspacePath, "/index.ts");
|
|
1056
1039
|
if (await fs.pathExists(indexFile)) {
|
|
@@ -1065,7 +1048,7 @@ const writeSpecs = async (builder, workspace, options, projectName) => {
|
|
|
1065
1048
|
await Promise.all(builder.extraFiles.map(async (file) => fs.outputFile(file.path, file.content)));
|
|
1066
1049
|
implementationPaths = [...implementationPaths, ...builder.extraFiles.map((file) => file.path)];
|
|
1067
1050
|
}
|
|
1068
|
-
const paths = [...output.schemas ? [getFileInfo(output.schemas).dirname] : [], ...implementationPaths];
|
|
1051
|
+
const paths = [...output.schemas ? [getFileInfo(typeof output.schemas === "string" ? output.schemas : output.schemas.path).dirname] : [], ...implementationPaths];
|
|
1069
1052
|
if (options.hooks.afterAllFilesWrite) await executeHook("afterAllFilesWrite", options.hooks.afterAllFilesWrite, paths);
|
|
1070
1053
|
if (output.prettier) try {
|
|
1071
1054
|
await execa("prettier", ["--write", ...paths]);
|
|
@@ -1110,8 +1093,8 @@ const writeSpecs = async (builder, workspace, options, projectName) => {
|
|
|
1110
1093
|
log(chalk.yellow(message));
|
|
1111
1094
|
}
|
|
1112
1095
|
createSuccessMessage(projectTitle);
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1096
|
+
}
|
|
1097
|
+
function getWriteMode(mode) {
|
|
1115
1098
|
switch (mode) {
|
|
1116
1099
|
case OutputMode.SPLIT: return writeSplitMode;
|
|
1117
1100
|
case OutputMode.TAGS: return writeTagsMode;
|
|
@@ -1119,7 +1102,7 @@ const getWriteMode = (mode) => {
|
|
|
1119
1102
|
case OutputMode.SINGLE:
|
|
1120
1103
|
default: return writeSingleMode;
|
|
1121
1104
|
}
|
|
1122
|
-
}
|
|
1105
|
+
}
|
|
1123
1106
|
|
|
1124
1107
|
//#endregion
|
|
1125
1108
|
//#region src/generate-spec.ts
|
|
@@ -1149,7 +1132,7 @@ async function generateSpec(workspace, options, projectName) {
|
|
|
1149
1132
|
], getFileInfo(options.output.schemas).dirname);
|
|
1150
1133
|
log(`${projectName} Cleaning output folder`);
|
|
1151
1134
|
}
|
|
1152
|
-
await writeSpecs(await importSpecs(workspace, options), workspace, options, projectName);
|
|
1135
|
+
await writeSpecs(await importSpecs(workspace, options, projectName), workspace, options, projectName);
|
|
1153
1136
|
}
|
|
1154
1137
|
|
|
1155
1138
|
//#endregion
|
|
@@ -1205,4 +1188,4 @@ async function loadConfigFile(configFilePath) {
|
|
|
1205
1188
|
|
|
1206
1189
|
//#endregion
|
|
1207
1190
|
export { defineConfig as a, name as c, startWatcher as i, version as l, loadConfigFile as n, normalizeOptions as o, generateSpec as r, description as s, findConfigFile as t };
|
|
1208
|
-
//# sourceMappingURL=config-
|
|
1191
|
+
//# sourceMappingURL=config-DQWtHEeF.mjs.map
|