@devbie/apits 0.0.0-stage → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -2
- package/bin/apits +4 -0
- package/dist/cjs/core/cli.d.ts +29 -0
- package/dist/cjs/core/cli.js +396 -0
- package/dist/cjs/core/generator.js +301 -0
- package/dist/cjs/core/writeRequestClient.js +93 -0
- package/dist/cjs/index.js +25 -0
- package/dist/cjs/types.js +90 -0
- package/dist/cjs/utils/console.js +79 -0
- package/dist/cjs/utils/getOutputPath.js +43 -0
- package/dist/cjs/utils/helpers.js +166 -0
- package/dist/cjs/utils/openApiToInterfaces.js +229 -0
- package/dist/cjs/utils/spinner.js +69 -0
- package/dist/cjs/utils/utils.d.ts +56 -0
- package/dist/cjs/utils/utils.js +355 -0
- package/dist/cjs/utils/vtilsLite.js +123 -0
- package/dist/esm/core/cli.d.mts +29 -0
- package/dist/esm/core/cli.mjs +713 -0
- package/dist/esm/core/generator.mjs +463 -0
- package/dist/esm/core/writeRequestClient.mjs +54 -0
- package/dist/esm/index.mjs +2 -0
- package/dist/esm/types.mjs +94 -0
- package/dist/esm/utils/console.mjs +65 -0
- package/dist/esm/utils/getOutputPath.mjs +12 -0
- package/dist/esm/utils/helpers.mjs +226 -0
- package/dist/esm/utils/openApiToInterfaces.mjs +326 -0
- package/dist/esm/utils/spinner.mjs +58 -0
- package/dist/esm/utils/utils.d.mts +56 -0
- package/dist/esm/utils/utils.mjs +545 -0
- package/dist/esm/utils/vtilsLite.mjs +142 -0
- package/package.json +68 -4
package/README.md
CHANGED
|
@@ -1,3 +1,90 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @devbie/apits
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Based on the OpenAPI specification, generate request and response type declarations and request method bodies for APIs
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
`npm install @devbie/apits`
|
|
8
|
+
|
|
9
|
+
## Quick start (no config file needed)
|
|
10
|
+
|
|
11
|
+
Pass an OpenAPI document URL or a local JSON / YAML file:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
apits gen http://localhost:3041/api-json
|
|
15
|
+
apits gen ./openapi.yaml -o src/api
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The `gen` word is optional:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
apits ./openapi.json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Each run generates two files in the output directory:
|
|
25
|
+
|
|
26
|
+
- `<name>.ts` — type declarations and request functions for every API
|
|
27
|
+
- `request.ts` — the default axios client (skipped with `--no-client`)
|
|
28
|
+
|
|
29
|
+
The file name is derived from the input when `-n/--name` is omitted:
|
|
30
|
+
`http://localhost:3041/api-json` → `localhost.ts`, `./user.openapi.yaml` →
|
|
31
|
+
`userOpenapi.ts`.
|
|
32
|
+
|
|
33
|
+
### CLI options
|
|
34
|
+
|
|
35
|
+
| Option | Description | Default |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| `input` (positional) | OpenAPI document URL or local `.json` / `.json5` / `.yaml` / `.yml` file | — |
|
|
38
|
+
| `-o, --output <path>` | Output directory | `src/api` |
|
|
39
|
+
| `-n, --name <name>` | Base name of the generated `<name>.ts`; when using a config file, filters sources by name | derived from the input host / file name |
|
|
40
|
+
| `--base-url <url>` | Runtime `baseURL` (supports the `[code]:` prefix) | — |
|
|
41
|
+
| `--no-client` | Do not scaffold the default `request.ts` axios client | client is generated |
|
|
42
|
+
| `-w, --watch` | Watch a local document and regenerate on change | off |
|
|
43
|
+
|
|
44
|
+
## Optional configuration file
|
|
45
|
+
|
|
46
|
+
Create a config only when you need multiple sources, JSON/JSON5 config, or
|
|
47
|
+
function-based customization:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
apits init
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`apits init ./openapi.json` prefills the document address.
|
|
54
|
+
|
|
55
|
+
The config file is auto-discovered from any of:
|
|
56
|
+
`apits.config.local.ts`, `apits.config.ts`, `apits.config.local.json`,
|
|
57
|
+
`apits.config.json`, or the `apits` field in `package.json`.
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
// apits.config.ts
|
|
61
|
+
import { defineConfig } from '@devbie/apits'
|
|
62
|
+
|
|
63
|
+
export default defineConfig([
|
|
64
|
+
{
|
|
65
|
+
input: 'http://localhost:3041/api-json',
|
|
66
|
+
output: 'src/api/user',
|
|
67
|
+
name: 'user', // optional, derived from `input` when omitted
|
|
68
|
+
baseURL: '[code]:process.env.BASE_API_URL',
|
|
69
|
+
clientImportTemplate: () => "import request from './request'",
|
|
70
|
+
client: true
|
|
71
|
+
}
|
|
72
|
+
])
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
CLI flags take precedence over config-file values. With a config file,
|
|
76
|
+
`-n/--name` selects which source(s) to run.
|
|
77
|
+
|
|
78
|
+
## Generate from a config file
|
|
79
|
+
|
|
80
|
+
Once a config file exists, generate all sources with:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
apits gen
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Or generate a single source by name:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
apits gen -n user
|
|
90
|
+
```
|
package/bin/apits
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import yargs from "yargs";
|
|
2
|
+
/** Flags accepted by the `gen` command. */
|
|
3
|
+
interface GenFlags {
|
|
4
|
+
/** OpenAPI document URL or local file path. */
|
|
5
|
+
input?: string;
|
|
6
|
+
/** Output directory. */
|
|
7
|
+
output?: string;
|
|
8
|
+
/** File base name (CLI mode) or name filter (config-file mode). */
|
|
9
|
+
name?: string;
|
|
10
|
+
/** Runtime baseURL (string; `[code]:` prefix supported). */
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
/** Whether to scaffold the default request.ts client. */
|
|
13
|
+
client?: boolean;
|
|
14
|
+
/** Watch local input files and regenerate on change. */
|
|
15
|
+
watch?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Scaffold an optional apits.config.ts template. */
|
|
18
|
+
export declare function genConfig(prefill?: {
|
|
19
|
+
input?: string;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
export declare function start(flags?: GenFlags): Promise<void>;
|
|
22
|
+
export default class CLI {
|
|
23
|
+
run(args: string[]): {
|
|
24
|
+
[x: string]: any;
|
|
25
|
+
};
|
|
26
|
+
private genBuilder;
|
|
27
|
+
init(): yargs.Argv<any>;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// src/core/cli.ts
|
|
30
|
+
var cli_exports = {};
|
|
31
|
+
__export(cli_exports, {
|
|
32
|
+
default: () => CLI,
|
|
33
|
+
genConfig: () => genConfig,
|
|
34
|
+
start: () => start
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(cli_exports);
|
|
37
|
+
var import_api = require("tsx/cjs/api");
|
|
38
|
+
var import_fs_extra = __toESM(require("fs-extra"));
|
|
39
|
+
var import_path = __toESM(require("path"));
|
|
40
|
+
var import_prompts = __toESM(require("prompts"));
|
|
41
|
+
var import_yargs = __toESM(require("yargs"));
|
|
42
|
+
var import_vtilsLite = require("../utils/vtilsLite.js");
|
|
43
|
+
var import_generator = require("./generator.js");
|
|
44
|
+
var import_chalk = __toESM(require("chalk"));
|
|
45
|
+
var conso = __toESM(require("../utils/console.js"));
|
|
46
|
+
var import_utils = require("../utils/utils.js");
|
|
47
|
+
var import_spinner = require("../utils/spinner.js");
|
|
48
|
+
var import_helpers = require("../utils/helpers.js");
|
|
49
|
+
(0, import_api.register)();
|
|
50
|
+
var CONFIG_FILE_CANDIDATES = [
|
|
51
|
+
"apits.config.local.ts",
|
|
52
|
+
"apits.config.ts",
|
|
53
|
+
"apits.config.local.json",
|
|
54
|
+
"apits.config.json"
|
|
55
|
+
];
|
|
56
|
+
var NoInputError = class extends Error {
|
|
57
|
+
};
|
|
58
|
+
function isHttpInput(input) {
|
|
59
|
+
return /^https?:\/\//i.test(input);
|
|
60
|
+
}
|
|
61
|
+
function normalizeConfig(raw) {
|
|
62
|
+
return (0, import_helpers.defineConfig)(Array.isArray(raw) ? raw : [raw]);
|
|
63
|
+
}
|
|
64
|
+
async function discoverConfigFile(cwd = process.cwd()) {
|
|
65
|
+
for (const fileName of CONFIG_FILE_CANDIDATES) {
|
|
66
|
+
const filePath = import_path.default.join(cwd, fileName);
|
|
67
|
+
if (await import_fs_extra.default.pathExists(filePath)) {
|
|
68
|
+
return { filePath, kind: fileName.endsWith(".json") ? "json" : "ts" };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const packageJsonPath = import_path.default.join(cwd, "package.json");
|
|
72
|
+
if (await import_fs_extra.default.pathExists(packageJsonPath)) {
|
|
73
|
+
try {
|
|
74
|
+
const pkg = JSON.parse(await import_fs_extra.default.readFile(packageJsonPath, "utf-8"));
|
|
75
|
+
if (pkg.apits) {
|
|
76
|
+
return { filePath: packageJsonPath, kind: "package" };
|
|
77
|
+
}
|
|
78
|
+
} catch {
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return void 0;
|
|
82
|
+
}
|
|
83
|
+
function loadConfigFile(discovered) {
|
|
84
|
+
const { filePath, kind } = discovered;
|
|
85
|
+
if (kind === "ts") {
|
|
86
|
+
const mod = require(filePath);
|
|
87
|
+
return normalizeConfig(mod.default ?? mod);
|
|
88
|
+
}
|
|
89
|
+
if (kind === "json") {
|
|
90
|
+
return normalizeConfig(JSON.parse(import_fs_extra.default.readFileSync(filePath, "utf-8")));
|
|
91
|
+
}
|
|
92
|
+
const pkg = JSON.parse(import_fs_extra.default.readFileSync(filePath, "utf-8"));
|
|
93
|
+
return normalizeConfig(pkg.apits);
|
|
94
|
+
}
|
|
95
|
+
function buildCliConfig(flags) {
|
|
96
|
+
const config = {
|
|
97
|
+
input: flags.input,
|
|
98
|
+
output: flags.output || "src/api"
|
|
99
|
+
};
|
|
100
|
+
if (flags.name) {
|
|
101
|
+
config.name = flags.name;
|
|
102
|
+
}
|
|
103
|
+
if (flags.baseUrl !== void 0) {
|
|
104
|
+
config.baseURL = flags.baseUrl;
|
|
105
|
+
}
|
|
106
|
+
config.client = flags.client ?? true;
|
|
107
|
+
return (0, import_helpers.defineConfig)(config)[0];
|
|
108
|
+
}
|
|
109
|
+
function assignUniqueNames(configs) {
|
|
110
|
+
const counts = /* @__PURE__ */ new Map();
|
|
111
|
+
configs.forEach((item) => {
|
|
112
|
+
const base = item.name || import_generator.Generator.deriveName(item.input);
|
|
113
|
+
const seen = counts.get(base) ?? 0;
|
|
114
|
+
counts.set(base, seen + 1);
|
|
115
|
+
if (!item.name) {
|
|
116
|
+
item.name = seen === 0 ? base : `${base}_${seen + 1}`;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
async function resolveConfigs(flags) {
|
|
121
|
+
if (flags.input) {
|
|
122
|
+
const configs = [buildCliConfig(flags)];
|
|
123
|
+
assignUniqueNames(configs);
|
|
124
|
+
return { configs, source: "cli" };
|
|
125
|
+
}
|
|
126
|
+
const discovered = await discoverConfigFile();
|
|
127
|
+
if (discovered) {
|
|
128
|
+
let configs = loadConfigFile(discovered);
|
|
129
|
+
if (flags.name) {
|
|
130
|
+
configs = configs.filter((item) => item.name === flags.name);
|
|
131
|
+
if (configs.length === 0) {
|
|
132
|
+
throw new Error(`No config found with name: ${flags.name}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
configs = configs.map((item) => ({
|
|
136
|
+
...item,
|
|
137
|
+
...flags.output ? { output: flags.output } : {},
|
|
138
|
+
...flags.baseUrl !== void 0 ? { baseURL: flags.baseUrl } : {},
|
|
139
|
+
...flags.client !== void 0 ? { client: flags.client } : {}
|
|
140
|
+
}));
|
|
141
|
+
assignUniqueNames(configs);
|
|
142
|
+
return { configs, source: "file", configFile: discovered.filePath };
|
|
143
|
+
}
|
|
144
|
+
throw new NoInputError();
|
|
145
|
+
}
|
|
146
|
+
function printNoInputHint() {
|
|
147
|
+
conso.error(
|
|
148
|
+
[
|
|
149
|
+
"No OpenAPI input found. Use one of:",
|
|
150
|
+
"",
|
|
151
|
+
" 1. Pass document URL or path directly (no config file needed):",
|
|
152
|
+
" apits gen http://localhost:3041/api-json -o src/api",
|
|
153
|
+
" apits gen ./openapi.yaml",
|
|
154
|
+
"",
|
|
155
|
+
" 2. Generate a config file (multi-source / function-based customization):",
|
|
156
|
+
" apits init"
|
|
157
|
+
].join("\n")
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
async function genConfig(prefill) {
|
|
161
|
+
const cwd = process.cwd();
|
|
162
|
+
const configTSFile = import_path.default.join(cwd, "apits.config.ts");
|
|
163
|
+
if (await import_fs_extra.default.pathExists(configTSFile)) {
|
|
164
|
+
conso.tips(`Config file already exists: ${configTSFile}`);
|
|
165
|
+
const answers = await (0, import_prompts.default)({
|
|
166
|
+
message: "Overwrite existing config file?",
|
|
167
|
+
name: "override",
|
|
168
|
+
type: "confirm"
|
|
169
|
+
});
|
|
170
|
+
if (!answers.override)
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const configAnswers = await (0, import_prompts.default)([
|
|
174
|
+
{
|
|
175
|
+
message: "API document URL or local JSON/YAML file path",
|
|
176
|
+
name: "input",
|
|
177
|
+
type: "text",
|
|
178
|
+
initial: (prefill == null ? void 0 : prefill.input) || ""
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
message: "Generated file name (optional, derived from input if blank)",
|
|
182
|
+
name: "name",
|
|
183
|
+
type: "text",
|
|
184
|
+
initial: ""
|
|
185
|
+
}
|
|
186
|
+
]);
|
|
187
|
+
if (!configAnswers || !configAnswers.input) {
|
|
188
|
+
return conso.tips("Cancelled, config file not written");
|
|
189
|
+
}
|
|
190
|
+
const nameLine = (configAnswers == null ? void 0 : configAnswers.name) ? ` name: '${configAnswers.name}',
|
|
191
|
+
` : "";
|
|
192
|
+
await import_fs_extra.default.outputFile(
|
|
193
|
+
configTSFile,
|
|
194
|
+
await (0, import_utils.formatContent)(import_vtilsLite.dedent`
|
|
195
|
+
import { defineConfig } from '@devbie/apits'
|
|
196
|
+
|
|
197
|
+
export default defineConfig([{
|
|
198
|
+
input: '${(configAnswers == null ? void 0 : configAnswers.input) || ""}',
|
|
199
|
+
output: 'src/api',
|
|
200
|
+
${nameLine} baseURL: '[code]:process.env.BASE_API_URL',
|
|
201
|
+
clientImportTemplate: () => "${`import request from './request'`}",
|
|
202
|
+
// Keep the scaffolded request.ts because the import above points at it.
|
|
203
|
+
client: true,
|
|
204
|
+
}])
|
|
205
|
+
`)
|
|
206
|
+
);
|
|
207
|
+
conso.success("Config file written");
|
|
208
|
+
}
|
|
209
|
+
async function startGenerate(config, index = 0) {
|
|
210
|
+
const { output: outputDir } = config;
|
|
211
|
+
const label = import_chalk.default.green(`${config.input} elapsed`);
|
|
212
|
+
console.time(label);
|
|
213
|
+
import_spinner.spinnerInstance.start();
|
|
214
|
+
const generator = new import_generator.Generator(config);
|
|
215
|
+
const output = await generator.generate();
|
|
216
|
+
await generator.write(output);
|
|
217
|
+
import_spinner.spinnerInstance.clear();
|
|
218
|
+
conso.log(import_chalk.default.yellowBright(`
|
|
219
|
+
${index + 1}.-------------------------`));
|
|
220
|
+
conso.success(`Code generated, output: ${outputDir}`);
|
|
221
|
+
console.timeEnd(label);
|
|
222
|
+
conso.log(import_chalk.default.yellowBright("---------------------------\n"));
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
async function runAll(configs) {
|
|
226
|
+
await (0, import_helpers.asyncFnArrayOrderRun)(
|
|
227
|
+
configs.map((configItem, index) => {
|
|
228
|
+
return async () => {
|
|
229
|
+
await startGenerate(configItem, index);
|
|
230
|
+
};
|
|
231
|
+
})
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
function watchConfigs(configs) {
|
|
235
|
+
const localConfigs = configs.filter((item) => !isHttpInput(item.input));
|
|
236
|
+
if (localConfigs.length === 0) {
|
|
237
|
+
conso.tips("--watch only supports local files; remote URLs are ignored");
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const timers = /* @__PURE__ */ new Map();
|
|
241
|
+
localConfigs.forEach((configItem) => {
|
|
242
|
+
const filePath = import_path.default.resolve(configItem.input);
|
|
243
|
+
import_fs_extra.default.watch(filePath, async (eventType) => {
|
|
244
|
+
if (eventType === "rename") {
|
|
245
|
+
try {
|
|
246
|
+
import_fs_extra.default.watch(filePath, async (ev) => {
|
|
247
|
+
scheduleRebuild(filePath, ev);
|
|
248
|
+
});
|
|
249
|
+
} catch {
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
scheduleRebuild(filePath, eventType);
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
function scheduleRebuild(filePath, eventType) {
|
|
256
|
+
if (eventType !== "change" && eventType !== "rename")
|
|
257
|
+
return;
|
|
258
|
+
const oldTimer = timers.get(filePath);
|
|
259
|
+
if (oldTimer)
|
|
260
|
+
clearTimeout(oldTimer);
|
|
261
|
+
timers.set(
|
|
262
|
+
filePath,
|
|
263
|
+
setTimeout(async () => {
|
|
264
|
+
const configItem = localConfigs.find((c) => import_path.default.resolve(c.input) === filePath);
|
|
265
|
+
if (!configItem)
|
|
266
|
+
return;
|
|
267
|
+
const idx = localConfigs.indexOf(configItem);
|
|
268
|
+
conso.tips(`Detected change, regenerating: ${filePath}`);
|
|
269
|
+
try {
|
|
270
|
+
await startGenerate(configItem, idx);
|
|
271
|
+
} catch (err) {
|
|
272
|
+
conso.error(`Regeneration failed: ${err.message || err}`);
|
|
273
|
+
}
|
|
274
|
+
}, 200)
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
conso.tips(`Watching ${localConfigs.length} local document(s), Ctrl+C to exit`);
|
|
278
|
+
}
|
|
279
|
+
async function start(flags = {}) {
|
|
280
|
+
const timeLabel = import_chalk.default.green("Total elapsed");
|
|
281
|
+
console.time(timeLabel);
|
|
282
|
+
let resolved;
|
|
283
|
+
try {
|
|
284
|
+
resolved = await resolveConfigs(flags);
|
|
285
|
+
} catch (err) {
|
|
286
|
+
if (err instanceof NoInputError) {
|
|
287
|
+
printNoInputHint();
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
import_spinner.spinnerInstance.stop();
|
|
291
|
+
conso.error(`Config resolution failed: ${err.message || err}`);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
conso.tips(
|
|
295
|
+
resolved.source === "cli" ? `Using CLI input: ${flags.input}` : `Found config file: ${resolved.configFile}`
|
|
296
|
+
);
|
|
297
|
+
try {
|
|
298
|
+
import_spinner.spinnerInstance.start("Generating code...\n");
|
|
299
|
+
await runAll(resolved.configs);
|
|
300
|
+
import_spinner.spinnerInstance.stop();
|
|
301
|
+
} catch (err) {
|
|
302
|
+
import_spinner.spinnerInstance.stop();
|
|
303
|
+
conso.error("Execution failed:");
|
|
304
|
+
conso.error(`Error: ${err.message || err}`);
|
|
305
|
+
if (err.stack) {
|
|
306
|
+
conso.error(`Stack: ${err.stack}`);
|
|
307
|
+
}
|
|
308
|
+
if (err.cause) {
|
|
309
|
+
conso.error(`Cause: ${err.cause}`);
|
|
310
|
+
}
|
|
311
|
+
return conso.error("Code generation failed, see error details above");
|
|
312
|
+
}
|
|
313
|
+
console.timeEnd(timeLabel);
|
|
314
|
+
if (flags.watch) {
|
|
315
|
+
watchConfigs(resolved.configs);
|
|
316
|
+
}
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
function toFlags(argv) {
|
|
320
|
+
return {
|
|
321
|
+
input: typeof argv.input === "string" && argv.input ? argv.input : void 0,
|
|
322
|
+
output: typeof argv.output === "string" ? argv.output : void 0,
|
|
323
|
+
name: typeof argv.name === "string" ? argv.name : void 0,
|
|
324
|
+
baseUrl: typeof argv.baseUrl === "string" ? argv.baseUrl : void 0,
|
|
325
|
+
client: typeof argv.client === "boolean" ? argv.client : void 0,
|
|
326
|
+
watch: Boolean(argv.watch)
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
var CLI = class {
|
|
330
|
+
run(args) {
|
|
331
|
+
const cli = this.init();
|
|
332
|
+
if (args.length === 0) {
|
|
333
|
+
cli.showHelp();
|
|
334
|
+
}
|
|
335
|
+
return cli.parse(args);
|
|
336
|
+
}
|
|
337
|
+
genBuilder(y) {
|
|
338
|
+
return y.positional("input", {
|
|
339
|
+
type: "string",
|
|
340
|
+
describe: "OpenAPI document URL or local JSON/YAML file path"
|
|
341
|
+
}).option("output", {
|
|
342
|
+
alias: "o",
|
|
343
|
+
type: "string",
|
|
344
|
+
describe: "Output directory (default: src/api)"
|
|
345
|
+
}).option("name", {
|
|
346
|
+
alias: "n",
|
|
347
|
+
type: "string",
|
|
348
|
+
describe: "Generated file name; filters by name in config-file mode"
|
|
349
|
+
}).option("base-url", {
|
|
350
|
+
type: "string",
|
|
351
|
+
describe: "Runtime baseURL (supports [code]: prefix for code emission)"
|
|
352
|
+
}).option("client", {
|
|
353
|
+
type: "boolean",
|
|
354
|
+
describe: "Generate default request.ts (use --no-client to disable, --client to force-enable)"
|
|
355
|
+
}).option("watch", {
|
|
356
|
+
alias: "w",
|
|
357
|
+
type: "boolean",
|
|
358
|
+
default: false,
|
|
359
|
+
describe: "Watch local document for changes and auto-regenerate"
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
init() {
|
|
363
|
+
return import_yargs.default.scriptName("apits").usage("Usage: $0 [gen] [input] [options]").command(
|
|
364
|
+
"init [input]",
|
|
365
|
+
"Scaffold an optional apits.config.ts file",
|
|
366
|
+
(y) => {
|
|
367
|
+
y.positional("input", {
|
|
368
|
+
type: "string",
|
|
369
|
+
describe: "Prefilled document URL or local file path"
|
|
370
|
+
});
|
|
371
|
+
},
|
|
372
|
+
async (argv) => {
|
|
373
|
+
await genConfig({ input: typeof argv.input === "string" ? argv.input : void 0 });
|
|
374
|
+
}
|
|
375
|
+
).command(
|
|
376
|
+
"gen [input]",
|
|
377
|
+
"Generate TypeScript types and request functions from an OpenAPI document",
|
|
378
|
+
(y) => this.genBuilder(y),
|
|
379
|
+
(argv) => {
|
|
380
|
+
start(toFlags(argv));
|
|
381
|
+
}
|
|
382
|
+
).command(
|
|
383
|
+
"$0 [input]",
|
|
384
|
+
false,
|
|
385
|
+
(y) => this.genBuilder(y),
|
|
386
|
+
(argv) => {
|
|
387
|
+
start(toFlags(argv));
|
|
388
|
+
}
|
|
389
|
+
).help();
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
393
|
+
0 && (module.exports = {
|
|
394
|
+
genConfig,
|
|
395
|
+
start
|
|
396
|
+
});
|