orval 8.0.0-rc.1 → 8.0.0-rc.2
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 +81 -0
- package/dist/bin/orval.mjs.map +1 -0
- package/dist/{generate-6oT76j_W.js → config-BH1mpZT1.mjs} +121 -114
- package/dist/config-BH1mpZT1.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 +25 -24
- 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
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { c as name, i as startWatcher, l as version, n as loadConfigFile, o as normalizeOptions, r as generateSpec, s as description, t as findConfigFile } from "../config-BH1mpZT1.mjs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { Option, program } from "@commander-js/extra-typings";
|
|
5
|
+
import { ErrorWithTag, OutputClient, OutputMode, isString, log, logError, startMessage } from "@orval/core";
|
|
6
|
+
|
|
7
|
+
//#region src/bin/orval.ts
|
|
8
|
+
const orvalMessage = startMessage({
|
|
9
|
+
name,
|
|
10
|
+
version,
|
|
11
|
+
description
|
|
12
|
+
});
|
|
13
|
+
const cli = program.name("orval").description(orvalMessage).version(version);
|
|
14
|
+
cli.addOption(new Option("-o, --output <path>", "output file destination").conflicts(["config", "project"])).addOption(new Option("-i, --input <path>", "input file (yaml or json openapi specs)").conflicts(["config", "project"])).addOption(new Option("-c, --config <path>", "override flags by a config file").conflicts(["input", "output"])).addOption(new Option("-p, --project <name>", "focus a project of the config").conflicts(["input", "output"])).addOption(new Option("-m, --mode <name>", "default mode that will be used").choices(Object.values(OutputMode))).option("-w, --watch [paths...]", "Watch mode, if path is not specified, it watches the input target").addOption(new Option("--client <name>", "default client that will be used").choices(Object.values(OutputClient))).option("--mock", "activate the mock").option("--clean [paths...]", "Clean output directory").option("--prettier", "Prettier generated files").option("--biome", "biome generated files").option("--tsconfig <path>", "path to your tsconfig file").action(async (options) => {
|
|
15
|
+
log(orvalMessage);
|
|
16
|
+
if (isString(options.input) && isString(options.output)) {
|
|
17
|
+
const normalizedOptions = await normalizeOptions({
|
|
18
|
+
input: options.input,
|
|
19
|
+
output: {
|
|
20
|
+
target: options.output,
|
|
21
|
+
clean: options.clean,
|
|
22
|
+
prettier: options.prettier,
|
|
23
|
+
biome: options.biome,
|
|
24
|
+
mock: options.mock,
|
|
25
|
+
client: options.client,
|
|
26
|
+
mode: options.mode,
|
|
27
|
+
tsconfig: options.tsconfig
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
if (options.watch) await startWatcher(options.watch, async () => {
|
|
31
|
+
try {
|
|
32
|
+
await generateSpec(process.cwd(), normalizedOptions);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
logError(error);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
}, normalizedOptions.input.target);
|
|
38
|
+
else try {
|
|
39
|
+
await generateSpec(process.cwd(), normalizedOptions);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (error instanceof ErrorWithTag) logError(error.cause, error.tag);
|
|
42
|
+
else logError(error);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
const configFilePath = findConfigFile(options.config);
|
|
47
|
+
const workspace = path.dirname(configFilePath);
|
|
48
|
+
const configFile = await loadConfigFile(configFilePath);
|
|
49
|
+
if (isString(options.project) && !Object.hasOwn(configFile, options.project)) {
|
|
50
|
+
logError("Project not found in config", options.project);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
const configs = Object.entries(configFile).filter(([projectName]) => !isString(options.project) || projectName === options.project);
|
|
54
|
+
let hasErrors = false;
|
|
55
|
+
for (const [projectName, config] of configs) {
|
|
56
|
+
const normalizedOptions = await normalizeOptions(config, workspace, options);
|
|
57
|
+
if (options.watch === void 0) try {
|
|
58
|
+
await generateSpec(workspace, normalizedOptions, projectName);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
hasErrors = true;
|
|
61
|
+
logError(error, projectName);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const fileToWatch = isString(normalizedOptions.input.target) ? normalizedOptions.input.target : void 0;
|
|
65
|
+
await startWatcher(options.watch, async () => {
|
|
66
|
+
try {
|
|
67
|
+
await generateSpec(workspace, normalizedOptions, projectName);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
logError(error, projectName);
|
|
70
|
+
}
|
|
71
|
+
}, fileToWatch);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (hasErrors) logError("One or more project failed, see above for details");
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
await cli.parseAsync(process.argv);
|
|
78
|
+
|
|
79
|
+
//#endregion
|
|
80
|
+
export { };
|
|
81
|
+
//# sourceMappingURL=orval.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orval.mjs","names":["pkg.name","pkg.version","pkg.description"],"sources":["../../src/bin/orval.ts"],"sourcesContent":["#!/usr/bin/env node\nimport path from 'node:path';\n\nimport { Option, program } from '@commander-js/extra-typings';\nimport {\n ErrorWithTag,\n isString,\n log,\n logError,\n OutputClient,\n OutputMode,\n startMessage,\n} from '@orval/core';\n\nimport pkg from '../../package.json';\nimport { generateSpec } from '../generate-spec';\nimport { findConfigFile, loadConfigFile } from '../utils/config';\nimport { normalizeOptions } from '../utils/options';\nimport { startWatcher } from '../utils/watcher';\n\nconst orvalMessage = startMessage({\n name: pkg.name,\n version: pkg.version,\n description: pkg.description,\n});\nconst cli = program\n .name('orval')\n .description(orvalMessage)\n .version(pkg.version);\n\ncli\n .addOption(\n new Option('-o, --output <path>', 'output file destination').conflicts([\n 'config',\n 'project',\n ]),\n )\n .addOption(\n new Option(\n '-i, --input <path>',\n 'input file (yaml or json openapi specs)',\n ).conflicts(['config', 'project']),\n )\n .addOption(\n new Option(\n '-c, --config <path>',\n 'override flags by a config file',\n ).conflicts(['input', 'output']),\n )\n .addOption(\n new Option(\n '-p, --project <name>',\n 'focus a project of the config',\n ).conflicts(['input', 'output']),\n )\n .addOption(\n new Option('-m, --mode <name>', 'default mode that will be used').choices(\n Object.values(OutputMode),\n ),\n )\n .option(\n '-w, --watch [paths...]',\n 'Watch mode, if path is not specified, it watches the input target',\n )\n .addOption(\n new Option('--client <name>', 'default client that will be used').choices(\n Object.values(OutputClient),\n ),\n )\n .option('--mock', 'activate the mock')\n .option('--clean [paths...]', 'Clean output directory')\n .option('--prettier', 'Prettier generated files')\n .option('--biome', 'biome generated files')\n .option('--tsconfig <path>', 'path to your tsconfig file')\n .action(async (options) => {\n log(orvalMessage);\n\n if (isString(options.input) && isString(options.output)) {\n const normalizedOptions = await normalizeOptions({\n input: options.input,\n output: {\n target: options.output,\n clean: options.clean,\n prettier: options.prettier,\n biome: options.biome,\n mock: options.mock,\n client: options.client,\n mode: options.mode,\n tsconfig: options.tsconfig,\n },\n });\n\n if (options.watch) {\n await startWatcher(\n options.watch,\n async () => {\n try {\n await generateSpec(process.cwd(), normalizedOptions);\n } catch (error) {\n logError(error);\n process.exit(1);\n }\n },\n normalizedOptions.input.target as string,\n );\n } else {\n try {\n await generateSpec(process.cwd(), normalizedOptions);\n } catch (error) {\n if (error instanceof ErrorWithTag) {\n logError(error.cause, error.tag);\n } else {\n logError(error);\n }\n process.exit(1);\n }\n }\n } else {\n const configFilePath = findConfigFile(options.config);\n const workspace = path.dirname(configFilePath);\n const configFile = await loadConfigFile(configFilePath);\n\n if (\n isString(options.project) &&\n !Object.hasOwn(configFile, options.project)\n ) {\n logError('Project not found in config', options.project);\n process.exit(1);\n }\n\n const configs = Object.entries(configFile).filter(\n ([projectName]) =>\n // only filter by project if specified\n !isString(options.project) || projectName === options.project,\n );\n\n let hasErrors = false;\n for (const [projectName, config] of configs) {\n const normalizedOptions = await normalizeOptions(\n config,\n workspace,\n options,\n );\n\n if (options.watch === undefined) {\n try {\n await generateSpec(workspace, normalizedOptions, projectName);\n } catch (error) {\n hasErrors = true;\n logError(error, projectName);\n }\n } else {\n const fileToWatch = isString(normalizedOptions.input.target)\n ? normalizedOptions.input.target\n : undefined;\n\n await startWatcher(\n options.watch,\n async () => {\n try {\n await generateSpec(workspace, normalizedOptions, projectName);\n } catch (error) {\n logError(error, projectName);\n }\n },\n fileToWatch,\n );\n }\n }\n\n if (hasErrors)\n logError('One or more project failed, see above for details');\n }\n });\n\nawait cli.parseAsync(process.argv);\n"],"mappings":"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"}
|
|
@@ -1,11 +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 { createJiti } from "jiti";
|
|
2
|
+
import { 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";
|
|
6
3
|
import SwaggerParser from "@apidevtools/swagger-parser";
|
|
7
4
|
import chalk from "chalk";
|
|
8
|
-
import fs
|
|
5
|
+
import fs from "fs-extra";
|
|
9
6
|
import yaml from "js-yaml";
|
|
10
7
|
import * as mock from "@orval/mock";
|
|
11
8
|
import { DEFAULT_MOCK_OPTIONS, generateMockImports } from "@orval/mock";
|
|
@@ -17,14 +14,22 @@ import mcp from "@orval/mcp";
|
|
|
17
14
|
import query from "@orval/query";
|
|
18
15
|
import swr from "@orval/swr";
|
|
19
16
|
import zod from "@orval/zod";
|
|
17
|
+
import { ExecaError, execa } from "execa";
|
|
18
|
+
import { unique } from "remeda";
|
|
19
|
+
import { parseArgsStringToArgv } from "string-argv";
|
|
20
20
|
import https from "node:https";
|
|
21
21
|
import enquirer from "enquirer";
|
|
22
22
|
import { findUp } from "find-up";
|
|
23
23
|
import { parse } from "tsconfck";
|
|
24
|
-
import
|
|
25
|
-
import {
|
|
26
|
-
|
|
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.2";
|
|
27
31
|
|
|
32
|
+
//#endregion
|
|
28
33
|
//#region src/client.ts
|
|
29
34
|
const DEFAULT_CLIENT = OutputClient.AXIOS;
|
|
30
35
|
const getGeneratorClient = (outputClient, output) => {
|
|
@@ -347,7 +352,7 @@ const getAllSchemas = (spec, specKey) => {
|
|
|
347
352
|
|
|
348
353
|
//#endregion
|
|
349
354
|
//#region src/import-specs.ts
|
|
350
|
-
const resolveSpecs = async (path$1, { validate
|
|
355
|
+
const resolveSpecs = async (path$1, { validate, ...options }, _isUrl, isOnlySchema) => {
|
|
351
356
|
try {
|
|
352
357
|
if (validate) try {
|
|
353
358
|
await SwaggerParser.validate(path$1, options);
|
|
@@ -359,7 +364,7 @@ const resolveSpecs = async (path$1, { validate,...options }, _isUrl, isOnlySchem
|
|
|
359
364
|
if (_isUrl) return data;
|
|
360
365
|
return Object.fromEntries(Object.entries(data).sort().map(([key, value]) => [isUrl(key) ? key : upath.resolve(key), value]));
|
|
361
366
|
} catch {
|
|
362
|
-
const file = await fs
|
|
367
|
+
const file = await fs.readFile(path$1, "utf8");
|
|
363
368
|
return { [path$1]: yaml.load(file) };
|
|
364
369
|
}
|
|
365
370
|
};
|
|
@@ -383,10 +388,26 @@ const importSpecs = async (workspace, options) => {
|
|
|
383
388
|
};
|
|
384
389
|
|
|
385
390
|
//#endregion
|
|
386
|
-
//#region
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
391
|
+
//#region src/utils/execute-hook.ts
|
|
392
|
+
const executeHook = async (name$1, commands = [], args = []) => {
|
|
393
|
+
log(chalk.white(`Running ${name$1} hook...`));
|
|
394
|
+
for (const command of commands) try {
|
|
395
|
+
if (isString(command)) await executeCommand(command, args);
|
|
396
|
+
else if (isFunction(command)) await command(args);
|
|
397
|
+
else if (isObject(command)) await executeObjectCommand(command, args);
|
|
398
|
+
} catch (error) {
|
|
399
|
+
logError(error, `Failed to run ${name$1} hook`);
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
async function executeCommand(command, args) {
|
|
403
|
+
const [cmd, ..._args] = [...parseArgsStringToArgv(command), ...args];
|
|
404
|
+
await execa(cmd, _args);
|
|
405
|
+
}
|
|
406
|
+
async function executeObjectCommand(command, args) {
|
|
407
|
+
if (command.injectGeneratedDirsAndFiles === false) args = [];
|
|
408
|
+
if (isString(command.command)) await executeCommand(command.command, args);
|
|
409
|
+
else if (isFunction(command.command)) await command.command();
|
|
410
|
+
}
|
|
390
411
|
|
|
391
412
|
//#endregion
|
|
392
413
|
//#region src/utils/request.ts
|
|
@@ -439,7 +460,7 @@ const getGithubSpecReq = ({ accessToken, repo, owner, branch, path: path$1 }) =>
|
|
|
439
460
|
let githubToken = null;
|
|
440
461
|
const getGithubAcessToken = async (githubTokenPath) => {
|
|
441
462
|
if (githubToken) return githubToken;
|
|
442
|
-
if (await fs
|
|
463
|
+
if (await fs.pathExists(githubTokenPath)) return fs.readFile(githubTokenPath, "utf8");
|
|
443
464
|
else {
|
|
444
465
|
const answers = await enquirer.prompt([{
|
|
445
466
|
type: "input",
|
|
@@ -451,7 +472,7 @@ const getGithubAcessToken = async (githubTokenPath) => {
|
|
|
451
472
|
message: "Would you like to store your token for the next time? (stored in your node_modules)"
|
|
452
473
|
}]);
|
|
453
474
|
githubToken = answers.githubToken;
|
|
454
|
-
if (answers.saveToken) await fs
|
|
475
|
+
if (answers.saveToken) await fs.outputFile(githubTokenPath, answers.githubToken);
|
|
455
476
|
return answers.githubToken;
|
|
456
477
|
}
|
|
457
478
|
};
|
|
@@ -475,7 +496,7 @@ const getGithubOpenApi = async (url) => {
|
|
|
475
496
|
type: "confirm",
|
|
476
497
|
name: "removeToken",
|
|
477
498
|
message: "Your token doesn't have the correct permissions, should we remove it?"
|
|
478
|
-
}])).removeToken) await fs
|
|
499
|
+
}])).removeToken) await fs.unlink(githubTokenPath);
|
|
479
500
|
}
|
|
480
501
|
}
|
|
481
502
|
return body.data?.repository?.object.text;
|
|
@@ -486,7 +507,7 @@ const getGithubOpenApi = async (url) => {
|
|
|
486
507
|
type: "confirm",
|
|
487
508
|
name: "removeToken",
|
|
488
509
|
message: "Your token doesn't have the correct permissions, should we remove it?"
|
|
489
|
-
}])).removeToken) await fs
|
|
510
|
+
}])).removeToken) await fs.unlink(githubTokenPath);
|
|
490
511
|
}
|
|
491
512
|
throw new Error(error.body.message || `Oups... 🍻. ${error}`);
|
|
492
513
|
}
|
|
@@ -518,7 +539,7 @@ const loadPackageJson = async (packageJson, workspace = process.cwd()) => {
|
|
|
518
539
|
return;
|
|
519
540
|
}
|
|
520
541
|
const normalizedPath = normalizePath(packageJson, workspace);
|
|
521
|
-
if (fs
|
|
542
|
+
if (fs.existsSync(normalizedPath)) {
|
|
522
543
|
const pkg = await dynamicImport(normalizedPath);
|
|
523
544
|
if (isPackageJson(pkg)) return await maybeReplaceCatalog(pkg, workspace);
|
|
524
545
|
else throw new Error(`Invalid package.json file: ${normalizedPath}`);
|
|
@@ -536,7 +557,7 @@ const maybeReplaceCatalog = async (pkg, workspace) => {
|
|
|
536
557
|
log(`⚠️ ${chalk.yellow("package.json contains pnpm catalog: in dependencies, but no pnpm-workspace.yaml was found.")}`);
|
|
537
558
|
return pkg;
|
|
538
559
|
}
|
|
539
|
-
const file = await fs
|
|
560
|
+
const file = await fs.readFile(filePath, "utf8");
|
|
540
561
|
const pnpmWorkspaceFile = yaml.load(file);
|
|
541
562
|
performSubstitution(pkg.dependencies, pnpmWorkspaceFile);
|
|
542
563
|
performSubstitution(pkg.devDependencies, pnpmWorkspaceFile);
|
|
@@ -582,7 +603,7 @@ const loadTsconfig = async (tsconfig, workspace = process.cwd()) => {
|
|
|
582
603
|
}
|
|
583
604
|
if (isString(tsconfig)) {
|
|
584
605
|
const normalizedPath = normalizePath(tsconfig, workspace);
|
|
585
|
-
if (fs
|
|
606
|
+
if (fs.existsSync(normalizedPath)) {
|
|
586
607
|
const config = await parse(normalizedPath);
|
|
587
608
|
return config.referenced?.find(({ tsconfigFile }) => tsconfigFile === normalizedPath)?.tsconfig || config.tsconfig;
|
|
588
609
|
}
|
|
@@ -813,7 +834,7 @@ const normalizePath = (path$1, workspace) => {
|
|
|
813
834
|
return upath.resolve(workspace, path$1);
|
|
814
835
|
};
|
|
815
836
|
const normalizeOperationsAndTags = (operationsOrTags, workspace, global) => {
|
|
816
|
-
return Object.fromEntries(Object.entries(operationsOrTags).map(([key, { transformer, mutator, formData, formUrlEncoded, paramsSerializer, query: query$1, zod: zod$1
|
|
837
|
+
return Object.fromEntries(Object.entries(operationsOrTags).map(([key, { transformer, mutator, formData, formUrlEncoded, paramsSerializer, query: query$1, zod: zod$1, ...rest }]) => {
|
|
817
838
|
return [key, {
|
|
818
839
|
...rest,
|
|
819
840
|
...query$1 ? { query: normalizeQueryOptions(query$1, workspace, global.query) } : {},
|
|
@@ -943,45 +964,37 @@ const getDefaultFilesHeader = ({ title, description: description$1, version: ver
|
|
|
943
964
|
|
|
944
965
|
//#endregion
|
|
945
966
|
//#region src/utils/watcher.ts
|
|
946
|
-
|
|
967
|
+
/**
|
|
968
|
+
* Start a file watcher and invoke an async callback on file changes.
|
|
969
|
+
*
|
|
970
|
+
* If `watchOptions` is falsy the watcher is not started. Supported shapes:
|
|
971
|
+
* - boolean: when true the `defaultTarget` is watched
|
|
972
|
+
* - string: a single path to watch
|
|
973
|
+
* - string[]: an array of paths to watch
|
|
974
|
+
*
|
|
975
|
+
* @param watchOptions - false to disable watching, or a path/paths to watch
|
|
976
|
+
* @param watchFn - async callback executed on change events
|
|
977
|
+
* @param defaultTarget - path(s) to watch when `watchOptions` is `true` (default: '.')
|
|
978
|
+
* @returns Resolves once the watcher has been started (or immediately if disabled)
|
|
979
|
+
*
|
|
980
|
+
* @example
|
|
981
|
+
* await startWatcher(true, async () => { await buildProject(); }, 'src');
|
|
982
|
+
*/
|
|
983
|
+
async function startWatcher(watchOptions, watchFn, defaultTarget = ".") {
|
|
947
984
|
if (!watchOptions) return;
|
|
948
985
|
const { watch } = await import("chokidar");
|
|
949
986
|
const ignored = ["**/{.git,node_modules}/**"];
|
|
950
|
-
const watchPaths = typeof watchOptions === "boolean" ? defaultTarget :
|
|
987
|
+
const watchPaths = typeof watchOptions === "boolean" ? defaultTarget : watchOptions;
|
|
951
988
|
log(`Watching for changes in ${Array.isArray(watchPaths) ? watchPaths.map((v) => "\"" + v + "\"").join(" | ") : "\"" + watchPaths + "\""}`);
|
|
952
989
|
watch(watchPaths, {
|
|
953
990
|
ignorePermissionErrors: true,
|
|
954
991
|
ignored
|
|
955
|
-
}).on("all",
|
|
992
|
+
}).on("all", (type, file) => {
|
|
956
993
|
log(`Change detected: ${type} ${file}`);
|
|
957
|
-
|
|
958
|
-
await watchFn();
|
|
959
|
-
} catch (error) {
|
|
994
|
+
watchFn().catch((error) => {
|
|
960
995
|
logError(error);
|
|
961
|
-
}
|
|
996
|
+
});
|
|
962
997
|
});
|
|
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
998
|
}
|
|
986
999
|
|
|
987
1000
|
//#endregion
|
|
@@ -1040,16 +1053,16 @@ const writeSpecs = async (builder, workspace, options, projectName) => {
|
|
|
1040
1053
|
if (output.schemas) imports.push(upath.relativeSafe(workspacePath, getFileInfo(output.schemas).dirname));
|
|
1041
1054
|
if (output.indexFiles) {
|
|
1042
1055
|
const indexFile = upath.join(workspacePath, "/index.ts");
|
|
1043
|
-
if (await fs
|
|
1044
|
-
const data = await fs
|
|
1056
|
+
if (await fs.pathExists(indexFile)) {
|
|
1057
|
+
const data = await fs.readFile(indexFile, "utf8");
|
|
1045
1058
|
const importsNotDeclared = imports.filter((imp) => !data.includes(imp));
|
|
1046
|
-
await fs
|
|
1047
|
-
} else await fs
|
|
1059
|
+
await fs.appendFile(indexFile, unique(importsNotDeclared).map((imp) => `export * from '${imp}';\n`).join(""));
|
|
1060
|
+
} else await fs.outputFile(indexFile, unique(imports).map((imp) => `export * from '${imp}';`).join("\n") + "\n");
|
|
1048
1061
|
implementationPaths = [indexFile, ...implementationPaths];
|
|
1049
1062
|
}
|
|
1050
1063
|
}
|
|
1051
1064
|
if (builder.extraFiles.length > 0) {
|
|
1052
|
-
await Promise.all(builder.extraFiles.map(async (file) => fs
|
|
1065
|
+
await Promise.all(builder.extraFiles.map(async (file) => fs.outputFile(file.path, file.content)));
|
|
1053
1066
|
implementationPaths = [...implementationPaths, ...builder.extraFiles.map((file) => file.path)];
|
|
1054
1067
|
}
|
|
1055
1068
|
const paths = [...output.schemas ? [getFileInfo(output.schemas).dirname] : [], ...implementationPaths];
|
|
@@ -1109,8 +1122,19 @@ const getWriteMode = (mode) => {
|
|
|
1109
1122
|
};
|
|
1110
1123
|
|
|
1111
1124
|
//#endregion
|
|
1112
|
-
//#region src/generate.ts
|
|
1113
|
-
|
|
1125
|
+
//#region src/generate-spec.ts
|
|
1126
|
+
/**
|
|
1127
|
+
* Generate client/spec files for a single Orval project.
|
|
1128
|
+
*
|
|
1129
|
+
* @param workspace - Absolute or relative workspace path used to resolve imports.
|
|
1130
|
+
* @param options - Normalized generation options for this project.
|
|
1131
|
+
* @param projectName - Optional project name used in logging output.
|
|
1132
|
+
* @returns A promise that resolves once generation (and optional cleaning) completes.
|
|
1133
|
+
*
|
|
1134
|
+
* @example
|
|
1135
|
+
* await generateSpec(process.cwd(), normalizedOptions, 'my-project');
|
|
1136
|
+
*/
|
|
1137
|
+
async function generateSpec(workspace, options, projectName) {
|
|
1114
1138
|
if (options.output.clean) {
|
|
1115
1139
|
const extraPatterns = Array.isArray(options.output.clean) ? options.output.clean : [];
|
|
1116
1140
|
if (options.output.target) await removeFilesAndEmptyFolders([
|
|
@@ -1123,44 +1147,35 @@ const generateSpec = async (workspace, options, projectName) => {
|
|
|
1123
1147
|
"!**/*.d.ts",
|
|
1124
1148
|
...extraPatterns
|
|
1125
1149
|
], getFileInfo(options.output.schemas).dirname);
|
|
1126
|
-
log(`${projectName
|
|
1150
|
+
log(`${projectName} Cleaning output folder`);
|
|
1127
1151
|
}
|
|
1128
1152
|
await writeSpecs(await importSpecs(workspace, options), workspace, options, projectName);
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
try {
|
|
1149
|
-
await generateSpec(workspace, options, projectName$1);
|
|
1150
|
-
} catch (error) {
|
|
1151
|
-
hasErrors = true;
|
|
1152
|
-
logError(error, projectName$1);
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
if (hasErrors) throw new Error("One or more project failed, see above for details");
|
|
1156
|
-
};
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
//#endregion
|
|
1156
|
+
//#region src/utils/config.ts
|
|
1157
|
+
/**
|
|
1158
|
+
* Resolve the Orval config file path.
|
|
1159
|
+
*
|
|
1160
|
+
* @param configFilePath - Optional path to the config file (absolute or relative).
|
|
1161
|
+
* @returns The absolute path to the resolved config file.
|
|
1162
|
+
* @throws If a provided path does not exist or if no config file is found.
|
|
1163
|
+
*
|
|
1164
|
+
* @example
|
|
1165
|
+
* // explicit path
|
|
1166
|
+
* const p = findConfigFile('./orval.config.ts');
|
|
1167
|
+
*
|
|
1168
|
+
* @example
|
|
1169
|
+
* // automatic discovery (searches process.cwd())
|
|
1170
|
+
* const p = findConfigFile();
|
|
1171
|
+
*/
|
|
1157
1172
|
function findConfigFile(configFilePath) {
|
|
1158
1173
|
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`);
|
|
1174
|
+
const absolutePath = path.isAbsolute(configFilePath) ? configFilePath : path.resolve(process.cwd(), configFilePath);
|
|
1175
|
+
if (!fs$1.existsSync(absolutePath)) throw new Error(`Config file ${configFilePath} does not exist`);
|
|
1161
1176
|
return absolutePath;
|
|
1162
1177
|
}
|
|
1163
|
-
const root = process
|
|
1178
|
+
const root = process.cwd();
|
|
1164
1179
|
for (const ext of [
|
|
1165
1180
|
".ts",
|
|
1166
1181
|
".js",
|
|
@@ -1168,34 +1183,26 @@ function findConfigFile(configFilePath) {
|
|
|
1168
1183
|
".mts"
|
|
1169
1184
|
]) {
|
|
1170
1185
|
const fullPath = path.resolve(root, `orval.config${ext}`);
|
|
1171
|
-
if (fs.existsSync(fullPath)) return fullPath;
|
|
1186
|
+
if (fs$1.existsSync(fullPath)) return fullPath;
|
|
1172
1187
|
}
|
|
1173
1188
|
throw new Error(`No config file found in ${root}`);
|
|
1174
1189
|
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Load an Orval config file
|
|
1192
|
+
* @param configFilePath - Path to the config file (absolute or relative).
|
|
1193
|
+
* @returns The resolved Orval `Config` object.
|
|
1194
|
+
* @throws If the module does not provide a default export or the default export resolves to `undefined`.
|
|
1195
|
+
*
|
|
1196
|
+
* @example
|
|
1197
|
+
* // load a config object
|
|
1198
|
+
* const cfg = await loadConfigFile('./orval.config.ts');
|
|
1199
|
+
*/
|
|
1175
1200
|
async function loadConfigFile(configFilePath) {
|
|
1176
|
-
const
|
|
1177
|
-
if (
|
|
1178
|
-
return await
|
|
1201
|
+
const configExternal = await createJiti(process.cwd(), { interopDefault: true }).import(configFilePath, { default: true });
|
|
1202
|
+
if (configExternal === void 0) throw new Error(`${configFilePath} doesn't have a default export`);
|
|
1203
|
+
return await (isFunction(configExternal) ? configExternal() : configExternal);
|
|
1179
1204
|
}
|
|
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
1205
|
|
|
1199
1206
|
//#endregion
|
|
1200
|
-
export {
|
|
1201
|
-
//# sourceMappingURL=
|
|
1207
|
+
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-BH1mpZT1.mjs.map
|