orval 8.0.0-rc.1 → 8.0.0-rc.3
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.
- package/dist/bin/orval.mjs +82 -0
- package/dist/bin/orval.mjs.map +1 -0
- package/dist/{generate-6oT76j_W.js → config-CJTbXPiX.mjs} +277 -419
- package/dist/config-CJTbXPiX.mjs.map +1 -0
- package/dist/{index.d.ts → index.d.mts} +4 -4
- package/dist/index.mjs +51 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +30 -29
- package/dist/bin/orval.js +0 -62
- package/dist/bin/orval.js.map +0 -1
- package/dist/generate-6oT76j_W.js.map +0 -1
- package/dist/index.js +0 -28
- package/dist/index.js.map +0 -1
- /package/dist/bin/{orval.d.ts → orval.d.mts} +0 -0
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import { ErrorWithTag, FormDataArrayHandling, GetterPropType, NamingConvention, OutputClient, OutputHttpClient, OutputMode, PropertySortOrder, RefComponentSuffix, asyncReduce, createLogger, createSuccessMessage, dynamicImport, generateComponentDefinition, generateDependencyImports, generateParameterDefinition, generateSchemasDefinition, generateVerbsOptions, getFileInfo, getFullRoute, getMockFileExtensionByTypeName, getRoute, ibmOpenapiValidator, isBoolean, isFunction, isObject, isReference, isRootKey, isSchema, isString, isUndefined, isUrl, jsDoc, log, logError, mergeDeep, openApiConverter, pascal, removeFilesAndEmptyFolders, resolveRef, upath, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode } from "@orval/core";
|
|
2
|
-
import fs from "node:fs";
|
|
3
1
|
import path from "node:path";
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import fs$1 from "fs-extra";
|
|
9
|
-
import yaml from "js-yaml";
|
|
2
|
+
import { FormDataArrayHandling, GetterPropType, NamingConvention, OutputClient, OutputHttpClient, OutputMode, PropertySortOrder, RefComponentSuffix, asyncReduce, 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";
|
|
10
6
|
import * as mock from "@orval/mock";
|
|
11
7
|
import { DEFAULT_MOCK_OPTIONS, generateMockImports } from "@orval/mock";
|
|
12
8
|
import angular from "@orval/angular";
|
|
@@ -17,14 +13,23 @@ import mcp from "@orval/mcp";
|
|
|
17
13
|
import query from "@orval/query";
|
|
18
14
|
import swr from "@orval/swr";
|
|
19
15
|
import zod from "@orval/zod";
|
|
20
|
-
import
|
|
21
|
-
import enquirer from "enquirer";
|
|
22
|
-
import { findUp } from "find-up";
|
|
23
|
-
import { parse } from "tsconfck";
|
|
16
|
+
import chalk from "chalk";
|
|
24
17
|
import { ExecaError, execa } from "execa";
|
|
18
|
+
import fs from "fs-extra";
|
|
25
19
|
import { unique } from "remeda";
|
|
26
20
|
import { parseArgsStringToArgv } from "string-argv";
|
|
21
|
+
import { findUp } from "find-up";
|
|
22
|
+
import yaml from "js-yaml";
|
|
23
|
+
import { parse } from "tsconfck";
|
|
24
|
+
import fs$1 from "node:fs";
|
|
25
|
+
import { createJiti } from "jiti";
|
|
26
|
+
|
|
27
|
+
//#region package.json
|
|
28
|
+
var name = "orval";
|
|
29
|
+
var description = "A swagger client generator for typescript";
|
|
30
|
+
var version = "8.0.0-rc.3";
|
|
27
31
|
|
|
32
|
+
//#endregion
|
|
28
33
|
//#region src/client.ts
|
|
29
34
|
const DEFAULT_CLIENT = OutputClient.AXIOS;
|
|
30
35
|
const getGeneratorClient = (outputClient, output) => {
|
|
@@ -54,9 +59,9 @@ const getGeneratorClient = (outputClient, output) => {
|
|
|
54
59
|
if (!generator) throw new Error(`Oups... 🍻. Client not found: ${outputClient}`);
|
|
55
60
|
return generator;
|
|
56
61
|
};
|
|
57
|
-
const generateClientImports = ({ client = DEFAULT_CLIENT, implementation, imports,
|
|
62
|
+
const generateClientImports = ({ client = DEFAULT_CLIENT, implementation, imports, projectName, hasSchemaDir, isAllowSyntheticDefaultImports, hasGlobalMutator, hasTagsMutator, hasParamsSerializerOptions, packageJson, output }) => {
|
|
58
63
|
const { dependencies } = getGeneratorClient(client, output);
|
|
59
|
-
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);
|
|
60
65
|
};
|
|
61
66
|
const generateClientHeader = ({ outputClient = DEFAULT_CLIENT, isRequestOptions, isGlobalMutator, isMutator, provideIn, hasAwaitedType, titles, output, verbOptions, tag, clientImplementation }) => {
|
|
62
67
|
const { header } = getGeneratorClient(outputClient, output);
|
|
@@ -167,18 +172,13 @@ const generateExtraFiles = (outputClient = DEFAULT_CLIENT, verbsOptions, output,
|
|
|
167
172
|
|
|
168
173
|
//#endregion
|
|
169
174
|
//#region src/api.ts
|
|
170
|
-
|
|
171
|
-
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]) => {
|
|
172
177
|
const route = getRoute(pathRoute);
|
|
173
178
|
let resolvedVerbs = verbs;
|
|
174
|
-
let resolvedContext = context;
|
|
175
179
|
if (isReference(verbs)) {
|
|
176
180
|
const { schema, imports } = resolveRef(verbs, context);
|
|
177
181
|
resolvedVerbs = schema;
|
|
178
|
-
resolvedContext = {
|
|
179
|
-
...context,
|
|
180
|
-
...imports.length > 0 ? { specKey: imports[0].specKey } : {}
|
|
181
|
-
};
|
|
182
182
|
}
|
|
183
183
|
let verbsOptions = await generateVerbsOptions({
|
|
184
184
|
verbs: resolvedVerbs,
|
|
@@ -186,7 +186,7 @@ const getApiBuilder = async ({ input, output, context }) => {
|
|
|
186
186
|
output,
|
|
187
187
|
route,
|
|
188
188
|
pathRoute,
|
|
189
|
-
context
|
|
189
|
+
context
|
|
190
190
|
});
|
|
191
191
|
if (output.override.useDeprecatedOperations === false) verbsOptions = verbsOptions.filter((verb) => {
|
|
192
192
|
return !verb.deprecated;
|
|
@@ -198,13 +198,13 @@ const getApiBuilder = async ({ input, output, context }) => {
|
|
|
198
198
|
acc$1.push(...body.schemas, ...response.schemas);
|
|
199
199
|
return acc$1;
|
|
200
200
|
}, []);
|
|
201
|
-
const fullRoute = getFullRoute(route, verbs.servers ?? context.
|
|
201
|
+
const fullRoute = getFullRoute(route, verbs.servers ?? context.spec.servers, output.baseUrl);
|
|
202
202
|
if (!output.target) throw new Error("Output does not have a target");
|
|
203
203
|
const pathOperations = await generateOperations(output.client, verbsOptions, {
|
|
204
204
|
route: fullRoute,
|
|
205
205
|
pathRoute,
|
|
206
206
|
override: output.override,
|
|
207
|
-
context
|
|
207
|
+
context,
|
|
208
208
|
mock: output.mock,
|
|
209
209
|
output: output.target
|
|
210
210
|
}, output);
|
|
@@ -232,278 +232,167 @@ const getApiBuilder = async ({ input, output, context }) => {
|
|
|
232
232
|
importsMock: generateMockImports,
|
|
233
233
|
extraFiles
|
|
234
234
|
};
|
|
235
|
-
}
|
|
235
|
+
}
|
|
236
236
|
|
|
237
237
|
//#endregion
|
|
238
238
|
//#region src/import-open-api.ts
|
|
239
|
-
|
|
240
|
-
const
|
|
241
|
-
specs: data,
|
|
242
|
-
input,
|
|
243
|
-
workspace
|
|
244
|
-
});
|
|
239
|
+
async function importOpenApi({ spec, input, output, target, workspace, projectName }) {
|
|
240
|
+
const transformedOpenApi = await applyTransformer(spec, input.override.transformer, workspace);
|
|
245
241
|
const schemas = getApiSchemas({
|
|
246
242
|
input,
|
|
247
243
|
output,
|
|
248
244
|
target,
|
|
249
245
|
workspace,
|
|
250
|
-
|
|
246
|
+
spec: transformedOpenApi
|
|
251
247
|
});
|
|
252
248
|
const api = await getApiBuilder({
|
|
253
249
|
input,
|
|
254
250
|
output,
|
|
255
251
|
context: {
|
|
256
|
-
|
|
252
|
+
projectName,
|
|
257
253
|
target,
|
|
258
254
|
workspace,
|
|
259
|
-
|
|
255
|
+
spec: transformedOpenApi,
|
|
260
256
|
output
|
|
261
257
|
}
|
|
262
258
|
});
|
|
263
259
|
return {
|
|
264
260
|
...api,
|
|
265
|
-
schemas:
|
|
266
|
-
...schemas,
|
|
267
|
-
[target]: [...schemas[target] ?? [], ...api.schemas]
|
|
268
|
-
},
|
|
261
|
+
schemas: [...schemas, ...api.schemas],
|
|
269
262
|
target,
|
|
270
|
-
info:
|
|
263
|
+
info: transformedOpenApi.info
|
|
271
264
|
};
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const transformerFn =
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
target,
|
|
288
|
-
workspace,
|
|
289
|
-
specs,
|
|
290
|
-
output
|
|
291
|
-
};
|
|
292
|
-
const schemaDefinition = generateSchemasDefinition(spec.openapi ? spec.components?.schemas : getAllSchemas(spec, specKey), context, output.override.components.schemas.suffix, input.filters);
|
|
293
|
-
const responseDefinition = generateComponentDefinition(spec.components?.responses, context, output.override.components.responses.suffix);
|
|
294
|
-
const bodyDefinition = generateComponentDefinition(spec.components?.requestBodies, context, output.override.components.requestBodies.suffix);
|
|
295
|
-
const parameters = generateParameterDefinition(spec.components?.parameters, context, output.override.components.parameters.suffix);
|
|
296
|
-
const schemas = [
|
|
297
|
-
...schemaDefinition,
|
|
298
|
-
...responseDefinition,
|
|
299
|
-
...bodyDefinition,
|
|
300
|
-
...parameters
|
|
301
|
-
];
|
|
302
|
-
if (schemas.length === 0) return acc;
|
|
303
|
-
acc[specKey] = schemas;
|
|
304
|
-
return acc;
|
|
305
|
-
}, {});
|
|
306
|
-
};
|
|
307
|
-
const getAllSchemas = (spec, specKey) => {
|
|
308
|
-
const keysToOmit = new Set([
|
|
309
|
-
"openapi",
|
|
310
|
-
"info",
|
|
311
|
-
"servers",
|
|
312
|
-
"paths",
|
|
313
|
-
"components",
|
|
314
|
-
"security",
|
|
315
|
-
"tags",
|
|
316
|
-
"externalDocs"
|
|
317
|
-
]);
|
|
318
|
-
const cleanedSpec = Object.fromEntries(Object.entries(spec).filter(([key]) => !keysToOmit.has(key)));
|
|
319
|
-
if (specKey && isSchema(cleanedSpec)) {
|
|
320
|
-
const name$1 = upath.getSchemaFileName(specKey);
|
|
321
|
-
const additionalKeysToOmit = new Set([
|
|
322
|
-
"type",
|
|
323
|
-
"properties",
|
|
324
|
-
"allOf",
|
|
325
|
-
"oneOf",
|
|
326
|
-
"anyOf",
|
|
327
|
-
"items"
|
|
328
|
-
]);
|
|
329
|
-
return {
|
|
330
|
-
[name$1]: cleanedSpec,
|
|
331
|
-
...getAllSchemas(Object.fromEntries(Object.entries(cleanedSpec).filter(([key]) => !additionalKeysToOmit.has(key))))
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
return {
|
|
335
|
-
...Object.entries(cleanedSpec).reduce((acc, [key, value]) => {
|
|
336
|
-
if (!isObject(value)) return acc;
|
|
337
|
-
if (!isSchema(value) && !isReference(value)) return {
|
|
338
|
-
...acc,
|
|
339
|
-
...getAllSchemas(value)
|
|
340
|
-
};
|
|
341
|
-
acc[key] = value;
|
|
342
|
-
return acc;
|
|
343
|
-
}, {}),
|
|
344
|
-
...spec?.components?.schemas
|
|
265
|
+
}
|
|
266
|
+
async function applyTransformer(openApi, transformer, workspace) {
|
|
267
|
+
const transformerFn = transformer ? await dynamicImport(transformer, workspace) : void 0;
|
|
268
|
+
if (!transformerFn) return openApi;
|
|
269
|
+
const transformedOpenApi = transformerFn(openApi);
|
|
270
|
+
const { valid, errors } = await validate(transformedOpenApi);
|
|
271
|
+
if (!valid) throw new Error(`Validation failed`, { cause: errors });
|
|
272
|
+
return transformedOpenApi;
|
|
273
|
+
}
|
|
274
|
+
function getApiSchemas({ input, output, target, workspace, spec }) {
|
|
275
|
+
const context = {
|
|
276
|
+
target,
|
|
277
|
+
workspace,
|
|
278
|
+
spec,
|
|
279
|
+
output
|
|
345
280
|
};
|
|
346
|
-
|
|
281
|
+
const schemaDefinition = generateSchemasDefinition(spec.components?.schemas, context, output.override.components.schemas.suffix, input.filters);
|
|
282
|
+
const responseDefinition = generateComponentDefinition(spec.components?.responses, context, output.override.components.responses.suffix);
|
|
283
|
+
const bodyDefinition = generateComponentDefinition(spec.components?.requestBodies, context, output.override.components.requestBodies.suffix);
|
|
284
|
+
const parameters = generateParameterDefinition(spec.components?.parameters, context, output.override.components.parameters.suffix);
|
|
285
|
+
return [
|
|
286
|
+
...schemaDefinition,
|
|
287
|
+
...responseDefinition,
|
|
288
|
+
...bodyDefinition,
|
|
289
|
+
...parameters
|
|
290
|
+
];
|
|
291
|
+
}
|
|
347
292
|
|
|
348
293
|
//#endregion
|
|
349
294
|
//#region src/import-specs.ts
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const importSpecs = async (workspace, options) => {
|
|
295
|
+
async function resolveSpec(input) {
|
|
296
|
+
const dereferencedData = dereferenceExternalRef(await bundle(input, {
|
|
297
|
+
plugins: [
|
|
298
|
+
readFiles(),
|
|
299
|
+
fetchUrls(),
|
|
300
|
+
parseJson(),
|
|
301
|
+
parseYaml()
|
|
302
|
+
],
|
|
303
|
+
treeShake: true
|
|
304
|
+
}));
|
|
305
|
+
const { valid, errors } = await validate(dereferencedData);
|
|
306
|
+
if (!valid) throw new Error("Validation failed", { cause: errors });
|
|
307
|
+
const { specification } = upgrade(dereferencedData);
|
|
308
|
+
return specification;
|
|
309
|
+
}
|
|
310
|
+
async function importSpecs(workspace, options, projectName) {
|
|
367
311
|
const { input, output } = options;
|
|
368
|
-
if (!isString(input.target)) return importOpenApi({
|
|
369
|
-
data: { [workspace]: input.target },
|
|
370
|
-
input,
|
|
371
|
-
output,
|
|
372
|
-
target: workspace,
|
|
373
|
-
workspace
|
|
374
|
-
});
|
|
375
|
-
const isPathUrl = isUrl(input.target);
|
|
376
312
|
return importOpenApi({
|
|
377
|
-
|
|
313
|
+
spec: await resolveSpec(input.target),
|
|
378
314
|
input,
|
|
379
315
|
output,
|
|
380
316
|
target: input.target,
|
|
381
|
-
workspace
|
|
382
|
-
|
|
383
|
-
};
|
|
384
|
-
|
|
385
|
-
//#endregion
|
|
386
|
-
//#region package.json
|
|
387
|
-
var name = "orval";
|
|
388
|
-
var description = "A swagger client generator for typescript";
|
|
389
|
-
var version = "8.0.0-rc.1";
|
|
390
|
-
|
|
391
|
-
//#endregion
|
|
392
|
-
//#region src/utils/request.ts
|
|
393
|
-
const request = (urlOptions, data) => {
|
|
394
|
-
return new Promise((resolve, reject) => {
|
|
395
|
-
const req = https.request(urlOptions, (res) => {
|
|
396
|
-
let body = "";
|
|
397
|
-
res.on("data", (chunk) => body += chunk.toString());
|
|
398
|
-
res.on("error", reject);
|
|
399
|
-
res.on("end", () => {
|
|
400
|
-
const response = {
|
|
401
|
-
status: res.statusCode,
|
|
402
|
-
headers: res.headers,
|
|
403
|
-
body: JSON.parse(body)
|
|
404
|
-
};
|
|
405
|
-
if (res.statusCode && res.statusCode >= 200 && res.statusCode <= 299) resolve(response);
|
|
406
|
-
else reject(response);
|
|
407
|
-
});
|
|
408
|
-
});
|
|
409
|
-
req.on("error", reject);
|
|
410
|
-
if (data) req.write(data, "binary");
|
|
411
|
-
req.end();
|
|
317
|
+
workspace,
|
|
318
|
+
projectName
|
|
412
319
|
});
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
"user-agent": "orval-importer",
|
|
434
|
-
authorization: `bearer ${accessToken}`,
|
|
435
|
-
"Content-Length": payload.length
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* The plugins from `@scalar/json-magic` does not dereference $ref.
|
|
323
|
+
* Instead if fetches them and puts them under x-ext, and changes the $ref to point to #x-ext/<name>.
|
|
324
|
+
* This function dereferences those x-ext $ref's.
|
|
325
|
+
*/
|
|
326
|
+
function dereferenceExternalRef(data) {
|
|
327
|
+
const extensions = data["x-ext"] ?? {};
|
|
328
|
+
const UNWANTED_KEYS = new Set(["$schema", "$id"]);
|
|
329
|
+
function scrub(obj) {
|
|
330
|
+
if (obj === null || obj === void 0) return obj;
|
|
331
|
+
if (Array.isArray(obj)) return obj.map((x) => scrub(x));
|
|
332
|
+
if (typeof obj === "object") {
|
|
333
|
+
const rec = obj;
|
|
334
|
+
const out = {};
|
|
335
|
+
for (const [k, v] of Object.entries(rec)) {
|
|
336
|
+
if (UNWANTED_KEYS.has(k)) continue;
|
|
337
|
+
out[k] = scrub(v);
|
|
338
|
+
}
|
|
339
|
+
return out;
|
|
436
340
|
}
|
|
437
|
-
|
|
438
|
-
};
|
|
439
|
-
let githubToken = null;
|
|
440
|
-
const getGithubAcessToken = async (githubTokenPath) => {
|
|
441
|
-
if (githubToken) return githubToken;
|
|
442
|
-
if (await fs$1.pathExists(githubTokenPath)) return fs$1.readFile(githubTokenPath, "utf8");
|
|
443
|
-
else {
|
|
444
|
-
const answers = await enquirer.prompt([{
|
|
445
|
-
type: "input",
|
|
446
|
-
name: "githubToken",
|
|
447
|
-
message: "Please provide a GitHub token with `repo` rules checked (https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/)"
|
|
448
|
-
}, {
|
|
449
|
-
type: "confirm",
|
|
450
|
-
name: "saveToken",
|
|
451
|
-
message: "Would you like to store your token for the next time? (stored in your node_modules)"
|
|
452
|
-
}]);
|
|
453
|
-
githubToken = answers.githubToken;
|
|
454
|
-
if (answers.saveToken) await fs$1.outputFile(githubTokenPath, answers.githubToken);
|
|
455
|
-
return answers.githubToken;
|
|
341
|
+
return obj;
|
|
456
342
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
message: "Your token doesn't have the correct permissions, should we remove it?"
|
|
478
|
-
}])).removeToken) await fs$1.unlink(githubTokenPath);
|
|
343
|
+
function replaceRefs(obj) {
|
|
344
|
+
if (obj === null || obj === void 0) return obj;
|
|
345
|
+
if (typeof obj === "object") {
|
|
346
|
+
if (Array.isArray(obj)) return obj.map((element) => replaceRefs(element));
|
|
347
|
+
const record = obj;
|
|
348
|
+
if ("$ref" in record && typeof record.$ref === "string") {
|
|
349
|
+
const refValue = record.$ref;
|
|
350
|
+
if (refValue.startsWith("#/x-ext/")) {
|
|
351
|
+
const parts = refValue.replace("#/x-ext/", "").split("/");
|
|
352
|
+
const extKey = parts.shift();
|
|
353
|
+
if (extKey) {
|
|
354
|
+
let refObj = extensions[extKey];
|
|
355
|
+
for (const p of parts) if (refObj && typeof refObj === "object" && p in refObj) refObj = refObj[p];
|
|
356
|
+
else {
|
|
357
|
+
refObj = void 0;
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
if (refObj) return replaceRefs(scrub(refObj));
|
|
361
|
+
}
|
|
362
|
+
}
|
|
479
363
|
}
|
|
364
|
+
const result$1 = {};
|
|
365
|
+
for (const [key, value] of Object.entries(record)) result$1[key] = replaceRefs(value);
|
|
366
|
+
return result$1;
|
|
480
367
|
}
|
|
481
|
-
return
|
|
482
|
-
} catch (error) {
|
|
483
|
-
if (!error.body) throw new Error(`Oups... 🍻. ${error}`);
|
|
484
|
-
if (error.body.message === "Bad credentials") {
|
|
485
|
-
if ((await enquirer.prompt([{
|
|
486
|
-
type: "confirm",
|
|
487
|
-
name: "removeToken",
|
|
488
|
-
message: "Your token doesn't have the correct permissions, should we remove it?"
|
|
489
|
-
}])).removeToken) await fs$1.unlink(githubTokenPath);
|
|
490
|
-
}
|
|
491
|
-
throw new Error(error.body.message || `Oups... 🍻. ${error}`);
|
|
368
|
+
return obj;
|
|
492
369
|
}
|
|
493
|
-
};
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
return file.url.includes("github.com");
|
|
498
|
-
},
|
|
499
|
-
read(file) {
|
|
500
|
-
return getGithubOpenApi(file.url);
|
|
501
|
-
}
|
|
502
|
-
};
|
|
370
|
+
const result = {};
|
|
371
|
+
for (const [key, value] of Object.entries(data)) if (key !== "x-ext") result[key] = replaceRefs(value);
|
|
372
|
+
return result;
|
|
373
|
+
}
|
|
503
374
|
|
|
504
375
|
//#endregion
|
|
505
|
-
//#region src/utils/
|
|
506
|
-
const
|
|
376
|
+
//#region src/utils/execute-hook.ts
|
|
377
|
+
const executeHook = async (name$1, commands = [], args = []) => {
|
|
378
|
+
log(chalk.white(`Running ${name$1} hook...`));
|
|
379
|
+
for (const command of commands) try {
|
|
380
|
+
if (isString(command)) await executeCommand(command, args);
|
|
381
|
+
else if (isFunction(command)) await command(args);
|
|
382
|
+
else if (isObject(command)) await executeObjectCommand(command, args);
|
|
383
|
+
} catch (error) {
|
|
384
|
+
logError(error, `Failed to run ${name$1} hook`);
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
async function executeCommand(command, args) {
|
|
388
|
+
const [cmd, ..._args] = [...parseArgsStringToArgv(command), ...args];
|
|
389
|
+
await execa(cmd, _args);
|
|
390
|
+
}
|
|
391
|
+
async function executeObjectCommand(command, args) {
|
|
392
|
+
if (command.injectGeneratedDirsAndFiles === false) args = [];
|
|
393
|
+
if (isString(command.command)) await executeCommand(command.command, args);
|
|
394
|
+
else if (isFunction(command.command)) await command.command();
|
|
395
|
+
}
|
|
507
396
|
|
|
508
397
|
//#endregion
|
|
509
398
|
//#region src/utils/package-json.ts
|
|
@@ -518,7 +407,7 @@ const loadPackageJson = async (packageJson, workspace = process.cwd()) => {
|
|
|
518
407
|
return;
|
|
519
408
|
}
|
|
520
409
|
const normalizedPath = normalizePath(packageJson, workspace);
|
|
521
|
-
if (fs
|
|
410
|
+
if (fs.existsSync(normalizedPath)) {
|
|
522
411
|
const pkg = await dynamicImport(normalizedPath);
|
|
523
412
|
if (isPackageJson(pkg)) return await maybeReplaceCatalog(pkg, workspace);
|
|
524
413
|
else throw new Error(`Invalid package.json file: ${normalizedPath}`);
|
|
@@ -536,7 +425,7 @@ const maybeReplaceCatalog = async (pkg, workspace) => {
|
|
|
536
425
|
log(`⚠️ ${chalk.yellow("package.json contains pnpm catalog: in dependencies, but no pnpm-workspace.yaml was found.")}`);
|
|
537
426
|
return pkg;
|
|
538
427
|
}
|
|
539
|
-
const file = await fs
|
|
428
|
+
const file = await fs.readFile(filePath, "utf8");
|
|
540
429
|
const pnpmWorkspaceFile = yaml.load(file);
|
|
541
430
|
performSubstitution(pkg.dependencies, pnpmWorkspaceFile);
|
|
542
431
|
performSubstitution(pkg.devDependencies, pnpmWorkspaceFile);
|
|
@@ -582,7 +471,7 @@ const loadTsconfig = async (tsconfig, workspace = process.cwd()) => {
|
|
|
582
471
|
}
|
|
583
472
|
if (isString(tsconfig)) {
|
|
584
473
|
const normalizedPath = normalizePath(tsconfig, workspace);
|
|
585
|
-
if (fs
|
|
474
|
+
if (fs.existsSync(normalizedPath)) {
|
|
586
475
|
const config = await parse(normalizedPath);
|
|
587
476
|
return config.referenced?.find(({ tsconfigFile }) => tsconfigFile === normalizedPath)?.tsconfig || config.tsconfig;
|
|
588
477
|
}
|
|
@@ -600,7 +489,7 @@ const loadTsconfig = async (tsconfig, workspace = process.cwd()) => {
|
|
|
600
489
|
function defineConfig(options) {
|
|
601
490
|
return options;
|
|
602
491
|
}
|
|
603
|
-
|
|
492
|
+
function createFormData(workspace, formData) {
|
|
604
493
|
const defaultArrayHandling = FormDataArrayHandling.SERIALIZE;
|
|
605
494
|
if (formData === void 0) return {
|
|
606
495
|
disabled: false,
|
|
@@ -625,8 +514,8 @@ const createFormData = (workspace, formData) => {
|
|
|
625
514
|
mutator: normalizeMutator(workspace, formData),
|
|
626
515
|
arrayHandling: defaultArrayHandling
|
|
627
516
|
};
|
|
628
|
-
}
|
|
629
|
-
|
|
517
|
+
}
|
|
518
|
+
async function normalizeOptions(optionsExport, workspace = process.cwd(), globalOptions = {}) {
|
|
630
519
|
const options = await (isFunction(optionsExport) ? optionsExport() : optionsExport);
|
|
631
520
|
if (!options.input) throw new Error(chalk.red(`Config require an input`));
|
|
632
521
|
if (!options.output) throw new Error(chalk.red(`Config require an output`));
|
|
@@ -659,10 +548,7 @@ const normalizeOptions = async (optionsExport, workspace = process.cwd(), global
|
|
|
659
548
|
const normalizedOptions = {
|
|
660
549
|
input: {
|
|
661
550
|
target: globalOptions.input ? normalizePathOrUrl(globalOptions.input, process.cwd()) : normalizePathOrUrl(inputOptions.target, workspace),
|
|
662
|
-
validation: inputOptions.validation || false,
|
|
663
551
|
override: { transformer: normalizePath(inputOptions.override?.transformer, workspace) },
|
|
664
|
-
converterOptions: inputOptions.converterOptions ?? {},
|
|
665
|
-
parserOptions: mergeDeep(parserDefaultOptions, inputOptions.parserOptions ?? {}),
|
|
666
552
|
filters: inputOptions.filters
|
|
667
553
|
},
|
|
668
554
|
output: {
|
|
@@ -781,15 +667,8 @@ const normalizeOptions = async (optionsExport, workspace = process.cwd(), global
|
|
|
781
667
|
if (!normalizedOptions.input.target) throw new Error(chalk.red(`Config require an input target`));
|
|
782
668
|
if (!normalizedOptions.output.target && !normalizedOptions.output.schemas) throw new Error(chalk.red(`Config require an output target or schemas`));
|
|
783
669
|
return normalizedOptions;
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
validate: true,
|
|
787
|
-
resolve: {
|
|
788
|
-
github: githubResolver,
|
|
789
|
-
http: httpResolver
|
|
790
|
-
}
|
|
791
|
-
};
|
|
792
|
-
const normalizeMutator = (workspace, mutator) => {
|
|
670
|
+
}
|
|
671
|
+
function normalizeMutator(workspace, mutator) {
|
|
793
672
|
if (isObject(mutator)) {
|
|
794
673
|
if (!mutator.path) throw new Error(chalk.red(`Mutator need a path`));
|
|
795
674
|
return {
|
|
@@ -803,17 +682,17 @@ const normalizeMutator = (workspace, mutator) => {
|
|
|
803
682
|
default: true
|
|
804
683
|
};
|
|
805
684
|
return mutator;
|
|
806
|
-
}
|
|
807
|
-
|
|
685
|
+
}
|
|
686
|
+
function normalizePathOrUrl(path$1, workspace) {
|
|
808
687
|
if (isString(path$1) && !isUrl(path$1)) return normalizePath(path$1, workspace);
|
|
809
688
|
return path$1;
|
|
810
|
-
}
|
|
811
|
-
|
|
689
|
+
}
|
|
690
|
+
function normalizePath(path$1, workspace) {
|
|
812
691
|
if (!isString(path$1)) return path$1;
|
|
813
692
|
return upath.resolve(workspace, path$1);
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
return Object.fromEntries(Object.entries(operationsOrTags).map(([key, { transformer, mutator, formData, formUrlEncoded, paramsSerializer, query: query$1, zod: zod$1
|
|
693
|
+
}
|
|
694
|
+
function normalizeOperationsAndTags(operationsOrTags, workspace, global) {
|
|
695
|
+
return Object.fromEntries(Object.entries(operationsOrTags).map(([key, { transformer, mutator, formData, formUrlEncoded, paramsSerializer, query: query$1, zod: zod$1, ...rest }]) => {
|
|
817
696
|
return [key, {
|
|
818
697
|
...rest,
|
|
819
698
|
...query$1 ? { query: normalizeQueryOptions(query$1, workspace, global.query) } : {},
|
|
@@ -857,16 +736,16 @@ const normalizeOperationsAndTags = (operationsOrTags, workspace, global) => {
|
|
|
857
736
|
...paramsSerializer ? { paramsSerializer: normalizeMutator(workspace, paramsSerializer) } : {}
|
|
858
737
|
}];
|
|
859
738
|
}));
|
|
860
|
-
}
|
|
861
|
-
|
|
739
|
+
}
|
|
740
|
+
function normalizeOutputMode(mode) {
|
|
862
741
|
if (!mode) return OutputMode.SINGLE;
|
|
863
742
|
if (!Object.values(OutputMode).includes(mode)) {
|
|
864
743
|
createLogger().warn(chalk.yellow(`Unknown the provided mode => ${mode}`));
|
|
865
744
|
return OutputMode.SINGLE;
|
|
866
745
|
}
|
|
867
746
|
return mode;
|
|
868
|
-
}
|
|
869
|
-
|
|
747
|
+
}
|
|
748
|
+
function normalizeHooks(hooks) {
|
|
870
749
|
return Object.keys(hooks).reduce((acc, key) => {
|
|
871
750
|
if (isString(hooks[key])) return {
|
|
872
751
|
...acc,
|
|
@@ -886,19 +765,19 @@ const normalizeHooks = (hooks) => {
|
|
|
886
765
|
};
|
|
887
766
|
return acc;
|
|
888
767
|
}, {});
|
|
889
|
-
}
|
|
890
|
-
|
|
768
|
+
}
|
|
769
|
+
function normalizeHonoOptions(hono$1 = {}, workspace) {
|
|
891
770
|
return {
|
|
892
771
|
...hono$1.handlers ? { handlers: upath.resolve(workspace, hono$1.handlers) } : {},
|
|
893
772
|
compositeRoute: hono$1.compositeRoute ?? "",
|
|
894
773
|
validator: hono$1.validator ?? true,
|
|
895
774
|
validatorOutputPath: hono$1.validatorOutputPath ? upath.resolve(workspace, hono$1.validatorOutputPath) : ""
|
|
896
775
|
};
|
|
897
|
-
}
|
|
898
|
-
|
|
776
|
+
}
|
|
777
|
+
function normalizeJSDocOptions(jsdoc = {}) {
|
|
899
778
|
return { ...jsdoc };
|
|
900
|
-
}
|
|
901
|
-
|
|
779
|
+
}
|
|
780
|
+
function normalizeQueryOptions(queryOptions = {}, outputWorkspace, globalOptions = {}) {
|
|
902
781
|
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.");
|
|
903
782
|
return {
|
|
904
783
|
...isUndefined(queryOptions.usePrefetch) ? {} : { usePrefetch: queryOptions.usePrefetch },
|
|
@@ -932,76 +811,66 @@ const normalizeQueryOptions = (queryOptions = {}, outputWorkspace, globalOptions
|
|
|
932
811
|
...isUndefined(globalOptions.version) ? {} : { version: globalOptions.version },
|
|
933
812
|
...isUndefined(queryOptions.version) ? {} : { version: queryOptions.version }
|
|
934
813
|
};
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
]
|
|
814
|
+
}
|
|
815
|
+
function getDefaultFilesHeader({ title, description: description$1, version: version$1 } = {}) {
|
|
816
|
+
return [
|
|
817
|
+
`Generated by ${name} v${version} 🍺`,
|
|
818
|
+
`Do not edit manually.`,
|
|
819
|
+
...title ? [title] : [],
|
|
820
|
+
...description$1 ? [description$1] : [],
|
|
821
|
+
...version$1 ? [`OpenAPI spec version: ${version$1}`] : []
|
|
822
|
+
];
|
|
823
|
+
}
|
|
943
824
|
|
|
944
825
|
//#endregion
|
|
945
826
|
//#region src/utils/watcher.ts
|
|
946
|
-
|
|
827
|
+
/**
|
|
828
|
+
* Start a file watcher and invoke an async callback on file changes.
|
|
829
|
+
*
|
|
830
|
+
* If `watchOptions` is falsy the watcher is not started. Supported shapes:
|
|
831
|
+
* - boolean: when true the `defaultTarget` is watched
|
|
832
|
+
* - string: a single path to watch
|
|
833
|
+
* - string[]: an array of paths to watch
|
|
834
|
+
*
|
|
835
|
+
* @param watchOptions - false to disable watching, or a path/paths to watch
|
|
836
|
+
* @param watchFn - async callback executed on change events
|
|
837
|
+
* @param defaultTarget - path(s) to watch when `watchOptions` is `true` (default: '.')
|
|
838
|
+
* @returns Resolves once the watcher has been started (or immediately if disabled)
|
|
839
|
+
*
|
|
840
|
+
* @example
|
|
841
|
+
* await startWatcher(true, async () => { await buildProject(); }, 'src');
|
|
842
|
+
*/
|
|
843
|
+
async function startWatcher(watchOptions, watchFn, defaultTarget = ".") {
|
|
947
844
|
if (!watchOptions) return;
|
|
948
845
|
const { watch } = await import("chokidar");
|
|
949
846
|
const ignored = ["**/{.git,node_modules}/**"];
|
|
950
|
-
const watchPaths = typeof watchOptions === "boolean" ? defaultTarget :
|
|
847
|
+
const watchPaths = typeof watchOptions === "boolean" ? defaultTarget : watchOptions;
|
|
951
848
|
log(`Watching for changes in ${Array.isArray(watchPaths) ? watchPaths.map((v) => "\"" + v + "\"").join(" | ") : "\"" + watchPaths + "\""}`);
|
|
952
849
|
watch(watchPaths, {
|
|
953
850
|
ignorePermissionErrors: true,
|
|
954
851
|
ignored
|
|
955
|
-
}).on("all",
|
|
852
|
+
}).on("all", (type, file) => {
|
|
956
853
|
log(`Change detected: ${type} ${file}`);
|
|
957
|
-
|
|
958
|
-
await watchFn();
|
|
959
|
-
} catch (error) {
|
|
854
|
+
watchFn().catch((error) => {
|
|
960
855
|
logError(error);
|
|
961
|
-
}
|
|
856
|
+
});
|
|
962
857
|
});
|
|
963
|
-
};
|
|
964
|
-
|
|
965
|
-
//#endregion
|
|
966
|
-
//#region src/utils/execute-hook.ts
|
|
967
|
-
const executeHook = async (name$1, commands = [], args = []) => {
|
|
968
|
-
log(chalk.white(`Running ${name$1} hook...`));
|
|
969
|
-
for (const command of commands) try {
|
|
970
|
-
if (isString(command)) await executeCommand(command, args);
|
|
971
|
-
else if (isFunction(command)) await command(args);
|
|
972
|
-
else if (isObject(command)) await executeObjectCommand(command, args);
|
|
973
|
-
} catch (error) {
|
|
974
|
-
logError(error, `Failed to run ${name$1} hook`);
|
|
975
|
-
}
|
|
976
|
-
};
|
|
977
|
-
async function executeCommand(command, args) {
|
|
978
|
-
const [cmd, ..._args] = [...parseArgsStringToArgv(command), ...args];
|
|
979
|
-
await execa(cmd, _args);
|
|
980
|
-
}
|
|
981
|
-
async function executeObjectCommand(command, args) {
|
|
982
|
-
if (command.injectGeneratedDirsAndFiles === false) args = [];
|
|
983
|
-
if (isString(command.command)) await executeCommand(command.command, args);
|
|
984
|
-
else if (isFunction(command.command)) await command.command();
|
|
985
858
|
}
|
|
986
859
|
|
|
987
860
|
//#endregion
|
|
988
861
|
//#region src/write-specs.ts
|
|
989
|
-
|
|
862
|
+
function getHeader(option, info) {
|
|
990
863
|
if (!option) return "";
|
|
991
864
|
const header = option(info);
|
|
992
865
|
return Array.isArray(header) ? jsDoc({ description: header }) : header;
|
|
993
|
-
}
|
|
994
|
-
|
|
866
|
+
}
|
|
867
|
+
async function writeSpecs(builder, workspace, options, projectName) {
|
|
995
868
|
const { info = {
|
|
996
869
|
title: "",
|
|
997
870
|
version: 0
|
|
998
871
|
}, schemas, target } = builder;
|
|
999
872
|
const { output } = options;
|
|
1000
873
|
const projectTitle = projectName ?? info.title;
|
|
1001
|
-
const specsName = Object.keys(schemas).reduce((acc, specKey) => {
|
|
1002
|
-
acc[specKey] = upath.getSpecName(specKey, target).slice(1).split("/").join("-");
|
|
1003
|
-
return acc;
|
|
1004
|
-
}, {});
|
|
1005
874
|
const header = getHeader(output.override.header, info);
|
|
1006
875
|
if (output.schemas) {
|
|
1007
876
|
const rootSchemaPath = output.schemas;
|
|
@@ -1009,28 +878,23 @@ const writeSpecs = async (builder, workspace, options, projectName) => {
|
|
|
1009
878
|
"tags",
|
|
1010
879
|
"tags-split",
|
|
1011
880
|
"split"
|
|
1012
|
-
].includes(output.mode) ? ".ts" : output.fileExtension
|
|
1013
|
-
await
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
isRootKey: isRootKey(specKey, target),
|
|
1023
|
-
header,
|
|
1024
|
-
indexFiles: output.indexFiles
|
|
1025
|
-
});
|
|
1026
|
-
}));
|
|
881
|
+
].includes(output.mode) ? ".ts" : output.fileExtension;
|
|
882
|
+
await writeSchemas({
|
|
883
|
+
schemaPath: rootSchemaPath,
|
|
884
|
+
schemas,
|
|
885
|
+
target,
|
|
886
|
+
namingConvention: output.namingConvention,
|
|
887
|
+
fileExtension,
|
|
888
|
+
header,
|
|
889
|
+
indexFiles: output.indexFiles
|
|
890
|
+
});
|
|
1027
891
|
}
|
|
1028
892
|
let implementationPaths = [];
|
|
1029
893
|
if (output.target) implementationPaths = await getWriteMode(output.mode)({
|
|
1030
894
|
builder,
|
|
1031
895
|
workspace,
|
|
1032
896
|
output,
|
|
1033
|
-
|
|
897
|
+
projectName,
|
|
1034
898
|
header,
|
|
1035
899
|
needSchema: !output.schemas && output.client !== "zod"
|
|
1036
900
|
});
|
|
@@ -1040,16 +904,16 @@ const writeSpecs = async (builder, workspace, options, projectName) => {
|
|
|
1040
904
|
if (output.schemas) imports.push(upath.relativeSafe(workspacePath, getFileInfo(output.schemas).dirname));
|
|
1041
905
|
if (output.indexFiles) {
|
|
1042
906
|
const indexFile = upath.join(workspacePath, "/index.ts");
|
|
1043
|
-
if (await fs
|
|
1044
|
-
const data = await fs
|
|
907
|
+
if (await fs.pathExists(indexFile)) {
|
|
908
|
+
const data = await fs.readFile(indexFile, "utf8");
|
|
1045
909
|
const importsNotDeclared = imports.filter((imp) => !data.includes(imp));
|
|
1046
|
-
await fs
|
|
1047
|
-
} else await fs
|
|
910
|
+
await fs.appendFile(indexFile, unique(importsNotDeclared).map((imp) => `export * from '${imp}';\n`).join(""));
|
|
911
|
+
} else await fs.outputFile(indexFile, unique(imports).map((imp) => `export * from '${imp}';`).join("\n") + "\n");
|
|
1048
912
|
implementationPaths = [indexFile, ...implementationPaths];
|
|
1049
913
|
}
|
|
1050
914
|
}
|
|
1051
915
|
if (builder.extraFiles.length > 0) {
|
|
1052
|
-
await Promise.all(builder.extraFiles.map(async (file) => fs
|
|
916
|
+
await Promise.all(builder.extraFiles.map(async (file) => fs.outputFile(file.path, file.content)));
|
|
1053
917
|
implementationPaths = [...implementationPaths, ...builder.extraFiles.map((file) => file.path)];
|
|
1054
918
|
}
|
|
1055
919
|
const paths = [...output.schemas ? [getFileInfo(output.schemas).dirname] : [], ...implementationPaths];
|
|
@@ -1097,8 +961,8 @@ const writeSpecs = async (builder, workspace, options, projectName) => {
|
|
|
1097
961
|
log(chalk.yellow(message));
|
|
1098
962
|
}
|
|
1099
963
|
createSuccessMessage(projectTitle);
|
|
1100
|
-
}
|
|
1101
|
-
|
|
964
|
+
}
|
|
965
|
+
function getWriteMode(mode) {
|
|
1102
966
|
switch (mode) {
|
|
1103
967
|
case OutputMode.SPLIT: return writeSplitMode;
|
|
1104
968
|
case OutputMode.TAGS: return writeTagsMode;
|
|
@@ -1106,11 +970,22 @@ const getWriteMode = (mode) => {
|
|
|
1106
970
|
case OutputMode.SINGLE:
|
|
1107
971
|
default: return writeSingleMode;
|
|
1108
972
|
}
|
|
1109
|
-
}
|
|
973
|
+
}
|
|
1110
974
|
|
|
1111
975
|
//#endregion
|
|
1112
|
-
//#region src/generate.ts
|
|
1113
|
-
|
|
976
|
+
//#region src/generate-spec.ts
|
|
977
|
+
/**
|
|
978
|
+
* Generate client/spec files for a single Orval project.
|
|
979
|
+
*
|
|
980
|
+
* @param workspace - Absolute or relative workspace path used to resolve imports.
|
|
981
|
+
* @param options - Normalized generation options for this project.
|
|
982
|
+
* @param projectName - Optional project name used in logging output.
|
|
983
|
+
* @returns A promise that resolves once generation (and optional cleaning) completes.
|
|
984
|
+
*
|
|
985
|
+
* @example
|
|
986
|
+
* await generateSpec(process.cwd(), normalizedOptions, 'my-project');
|
|
987
|
+
*/
|
|
988
|
+
async function generateSpec(workspace, options, projectName) {
|
|
1114
989
|
if (options.output.clean) {
|
|
1115
990
|
const extraPatterns = Array.isArray(options.output.clean) ? options.output.clean : [];
|
|
1116
991
|
if (options.output.target) await removeFilesAndEmptyFolders([
|
|
@@ -1123,44 +998,35 @@ const generateSpec = async (workspace, options, projectName) => {
|
|
|
1123
998
|
"!**/*.d.ts",
|
|
1124
999
|
...extraPatterns
|
|
1125
1000
|
], getFileInfo(options.output.schemas).dirname);
|
|
1126
|
-
log(`${projectName
|
|
1127
|
-
}
|
|
1128
|
-
await writeSpecs(await importSpecs(workspace, options), workspace, options, projectName);
|
|
1129
|
-
};
|
|
1130
|
-
const generateSpecs = async (config, workspace, projectName) => {
|
|
1131
|
-
if (projectName) {
|
|
1132
|
-
const options = config[projectName];
|
|
1133
|
-
if (options) try {
|
|
1134
|
-
await generateSpec(workspace, options, projectName);
|
|
1135
|
-
} catch (error) {
|
|
1136
|
-
throw new ErrorWithTag(error instanceof Error ? error.message : "unknown error", projectName, { cause: error });
|
|
1137
|
-
}
|
|
1138
|
-
else throw new Error("Project not found");
|
|
1139
|
-
return;
|
|
1140
|
-
}
|
|
1141
|
-
let hasErrors;
|
|
1142
|
-
for (const [projectName$1, options] of Object.entries(config)) {
|
|
1143
|
-
if (!options) {
|
|
1144
|
-
hasErrors = true;
|
|
1145
|
-
logError("No options found", projectName$1);
|
|
1146
|
-
continue;
|
|
1147
|
-
}
|
|
1148
|
-
try {
|
|
1149
|
-
await generateSpec(workspace, options, projectName$1);
|
|
1150
|
-
} catch (error) {
|
|
1151
|
-
hasErrors = true;
|
|
1152
|
-
logError(error, projectName$1);
|
|
1153
|
-
}
|
|
1001
|
+
log(`${projectName} Cleaning output folder`);
|
|
1154
1002
|
}
|
|
1155
|
-
|
|
1156
|
-
}
|
|
1003
|
+
await writeSpecs(await importSpecs(workspace, options, projectName), workspace, options, projectName);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
//#endregion
|
|
1007
|
+
//#region src/utils/config.ts
|
|
1008
|
+
/**
|
|
1009
|
+
* Resolve the Orval config file path.
|
|
1010
|
+
*
|
|
1011
|
+
* @param configFilePath - Optional path to the config file (absolute or relative).
|
|
1012
|
+
* @returns The absolute path to the resolved config file.
|
|
1013
|
+
* @throws If a provided path does not exist or if no config file is found.
|
|
1014
|
+
*
|
|
1015
|
+
* @example
|
|
1016
|
+
* // explicit path
|
|
1017
|
+
* const p = findConfigFile('./orval.config.ts');
|
|
1018
|
+
*
|
|
1019
|
+
* @example
|
|
1020
|
+
* // automatic discovery (searches process.cwd())
|
|
1021
|
+
* const p = findConfigFile();
|
|
1022
|
+
*/
|
|
1157
1023
|
function findConfigFile(configFilePath) {
|
|
1158
1024
|
if (configFilePath) {
|
|
1159
|
-
const absolutePath = path.isAbsolute(configFilePath) ? configFilePath : path.resolve(process
|
|
1160
|
-
if (!fs.existsSync(absolutePath)) throw new Error(`Config file ${configFilePath} does not exist`);
|
|
1025
|
+
const absolutePath = path.isAbsolute(configFilePath) ? configFilePath : path.resolve(process.cwd(), configFilePath);
|
|
1026
|
+
if (!fs$1.existsSync(absolutePath)) throw new Error(`Config file ${configFilePath} does not exist`);
|
|
1161
1027
|
return absolutePath;
|
|
1162
1028
|
}
|
|
1163
|
-
const root = process
|
|
1029
|
+
const root = process.cwd();
|
|
1164
1030
|
for (const ext of [
|
|
1165
1031
|
".ts",
|
|
1166
1032
|
".js",
|
|
@@ -1168,34 +1034,26 @@ function findConfigFile(configFilePath) {
|
|
|
1168
1034
|
".mts"
|
|
1169
1035
|
]) {
|
|
1170
1036
|
const fullPath = path.resolve(root, `orval.config${ext}`);
|
|
1171
|
-
if (fs.existsSync(fullPath)) return fullPath;
|
|
1037
|
+
if (fs$1.existsSync(fullPath)) return fullPath;
|
|
1172
1038
|
}
|
|
1173
1039
|
throw new Error(`No config file found in ${root}`);
|
|
1174
1040
|
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Load an Orval config file
|
|
1043
|
+
* @param configFilePath - Path to the config file (absolute or relative).
|
|
1044
|
+
* @returns The resolved Orval `Config` object.
|
|
1045
|
+
* @throws If the module does not provide a default export or the default export resolves to `undefined`.
|
|
1046
|
+
*
|
|
1047
|
+
* @example
|
|
1048
|
+
* // load a config object
|
|
1049
|
+
* const cfg = await loadConfigFile('./orval.config.ts');
|
|
1050
|
+
*/
|
|
1175
1051
|
async function loadConfigFile(configFilePath) {
|
|
1176
|
-
const
|
|
1177
|
-
if (
|
|
1178
|
-
return await
|
|
1052
|
+
const configExternal = await createJiti(process.cwd(), { interopDefault: true }).import(configFilePath, { default: true });
|
|
1053
|
+
if (configExternal === void 0) throw new Error(`${configFilePath} doesn't have a default export`);
|
|
1054
|
+
return await (isFunction(configExternal) ? configExternal() : configExternal);
|
|
1179
1055
|
}
|
|
1180
|
-
const generateConfig = async (configFile, options) => {
|
|
1181
|
-
const configFilePath = findConfigFile(configFile);
|
|
1182
|
-
let configExternal;
|
|
1183
|
-
try {
|
|
1184
|
-
configExternal = await loadConfigFile(configFilePath);
|
|
1185
|
-
} catch (error) {
|
|
1186
|
-
const errorMsg = error instanceof Error ? error.message : "unknown error";
|
|
1187
|
-
throw new Error(`failed to load from ${configFilePath} => ${errorMsg}`);
|
|
1188
|
-
}
|
|
1189
|
-
const workspace = path.dirname(configFilePath);
|
|
1190
|
-
const config = await (isFunction(configExternal) ? configExternal() : configExternal);
|
|
1191
|
-
const normalizedConfig = await asyncReduce(Object.entries(config), async (acc, [key, value]) => {
|
|
1192
|
-
acc[key] = await normalizeOptions(value, workspace, options);
|
|
1193
|
-
return acc;
|
|
1194
|
-
}, {});
|
|
1195
|
-
const fileToWatch = Object.entries(normalizedConfig).filter(([project]) => options?.projectName === void 0 || project === options.projectName).map(([, options$1]) => options$1?.input.target).filter((target) => isString(target));
|
|
1196
|
-
await (options?.watch && fileToWatch.length > 0 ? startWatcher(options.watch, () => generateSpecs(normalizedConfig, workspace, options.projectName), fileToWatch) : generateSpecs(normalizedConfig, workspace, options?.projectName));
|
|
1197
|
-
};
|
|
1198
1056
|
|
|
1199
1057
|
//#endregion
|
|
1200
|
-
export {
|
|
1201
|
-
//# sourceMappingURL=
|
|
1058
|
+
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 };
|
|
1059
|
+
//# sourceMappingURL=config-CJTbXPiX.mjs.map
|