x-openapi-flow 1.3.4 → 1.3.6
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 +14 -3
- package/bin/x-openapi-flow.js +450 -19
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# x-openapi-flow
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|
|
|
5
5
|
CLI and extension contract for documenting and validating resource lifecycle workflows in OpenAPI using `x-openapi-flow`.
|
|
6
6
|
|
|
@@ -53,6 +53,10 @@ npx x-openapi-flow graph openapi.yaml
|
|
|
53
53
|
## CLI Commands
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
|
+
npx x-openapi-flow help [command]
|
|
57
|
+
npx x-openapi-flow --help
|
|
58
|
+
npx x-openapi-flow version
|
|
59
|
+
npx x-openapi-flow --version
|
|
56
60
|
npx x-openapi-flow validate <openapi-file> [--format pretty|json] [--profile core|relaxed|strict] [--strict-quality] [--config path]
|
|
57
61
|
npx x-openapi-flow init [--flows path] [--force] [--dry-run]
|
|
58
62
|
npx x-openapi-flow apply [openapi-file] [--flows path] [--out path]
|
|
@@ -66,8 +70,15 @@ npx x-openapi-flow generate-insomnia [openapi-file] [--output path]
|
|
|
66
70
|
npx x-openapi-flow generate-redoc [openapi-file] [--output path]
|
|
67
71
|
npx x-openapi-flow graph <openapi-file> [--format mermaid|json]
|
|
68
72
|
npx x-openapi-flow doctor [--config path]
|
|
73
|
+
npx x-openapi-flow completion [bash|zsh]
|
|
69
74
|
```
|
|
70
75
|
|
|
76
|
+
Helpful additions:
|
|
77
|
+
|
|
78
|
+
- Command-specific help: `x-openapi-flow <command> --help` (example: `x-openapi-flow validate --help`)
|
|
79
|
+
- Verbose troubleshooting: `x-openapi-flow <command> --verbose`
|
|
80
|
+
- Shell completion output: `x-openapi-flow completion bash` or `x-openapi-flow completion zsh`
|
|
81
|
+
|
|
71
82
|
## Output Adapters
|
|
72
83
|
|
|
73
84
|
`x-openapi-flow` now supports modular output adapters that reuse the same internal flow graph:
|
|
@@ -409,14 +420,14 @@ Field reference format:
|
|
|
409
420
|
- A ready HTML example is available at `../example/openapi-swagger-ui/examples/swagger-ui/index.html`.
|
|
410
421
|
- The plugin renders a global **Flow Overview** (Mermaid image) near the top of the docs, plus operation-level flow cards.
|
|
411
422
|
|
|
412
|
-

|
|
413
424
|
|
|
414
425
|
### Graph Output Example
|
|
415
426
|
|
|
416
427
|
`x-openapi-flow graph` includes transition guidance labels in Mermaid output when present (`next_operation_id`, `prerequisite_operation_ids`).
|
|
417
428
|
The `graph` command accepts both full OpenAPI source files and sidecar files (`{context}.x.(json|yaml)` and legacy `{context}-openapi-flow.(json|yaml)`).
|
|
418
429
|
|
|
419
|
-

|
|
420
431
|
|
|
421
432
|
## Repository and Documentation
|
|
422
433
|
|
package/bin/x-openapi-flow.js
CHANGED
|
@@ -20,9 +20,361 @@ const {
|
|
|
20
20
|
generateInsomniaWorkspace,
|
|
21
21
|
generateRedocPackage,
|
|
22
22
|
} = require("../adapters/flow-output-adapters");
|
|
23
|
+
const pkg = require("../package.json");
|
|
23
24
|
|
|
24
25
|
const DEFAULT_CONFIG_NAME = "x-openapi-flow.config.json";
|
|
25
26
|
const DEFAULT_FLOWS_FILE = "x-openapi-flow.flows.yaml";
|
|
27
|
+
const KNOWN_COMMANDS = [
|
|
28
|
+
"validate",
|
|
29
|
+
"init",
|
|
30
|
+
"apply",
|
|
31
|
+
"diff",
|
|
32
|
+
"lint",
|
|
33
|
+
"analyze",
|
|
34
|
+
"generate-sdk",
|
|
35
|
+
"export-doc-flows",
|
|
36
|
+
"generate-postman",
|
|
37
|
+
"generate-insomnia",
|
|
38
|
+
"generate-redoc",
|
|
39
|
+
"graph",
|
|
40
|
+
"doctor",
|
|
41
|
+
"completion",
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const COMMAND_SNIPPETS = {
|
|
45
|
+
validate: {
|
|
46
|
+
usage: "x-openapi-flow validate <openapi-file> [--format pretty|json] [--profile core|relaxed|strict] [--strict-quality] [--config path]",
|
|
47
|
+
examples: [
|
|
48
|
+
"x-openapi-flow validate examples/order-api.yaml",
|
|
49
|
+
"x-openapi-flow validate examples/order-api.yaml --profile relaxed",
|
|
50
|
+
"x-openapi-flow validate examples/order-api.yaml --strict-quality",
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
init: {
|
|
54
|
+
usage: "x-openapi-flow init [openapi-file] [--flows path] [--force] [--dry-run]",
|
|
55
|
+
examples: [
|
|
56
|
+
"x-openapi-flow init",
|
|
57
|
+
"x-openapi-flow init openapi.yaml --flows openapi.x.yaml",
|
|
58
|
+
"x-openapi-flow init openapi.yaml --force",
|
|
59
|
+
"x-openapi-flow init openapi.yaml --dry-run",
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
apply: {
|
|
63
|
+
usage: "x-openapi-flow apply [openapi-file] [--flows path] [--out path] [--in-place]",
|
|
64
|
+
examples: [
|
|
65
|
+
"x-openapi-flow apply openapi.yaml",
|
|
66
|
+
"x-openapi-flow apply openapi.yaml --in-place",
|
|
67
|
+
"x-openapi-flow apply openapi.yaml --out openapi.flow.yaml",
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
diff: {
|
|
71
|
+
usage: "x-openapi-flow diff [openapi-file] [--flows path] [--format pretty|json]",
|
|
72
|
+
examples: [
|
|
73
|
+
"x-openapi-flow diff openapi.yaml",
|
|
74
|
+
"x-openapi-flow diff openapi.yaml --format json",
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
lint: {
|
|
78
|
+
usage: "x-openapi-flow lint [openapi-file] [--format pretty|json] [--config path]",
|
|
79
|
+
examples: [
|
|
80
|
+
"x-openapi-flow lint openapi.yaml",
|
|
81
|
+
"x-openapi-flow lint openapi.yaml --format json",
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
analyze: {
|
|
85
|
+
usage: "x-openapi-flow analyze [openapi-file] [--format pretty|json] [--out path] [--merge] [--flows path]",
|
|
86
|
+
examples: [
|
|
87
|
+
"x-openapi-flow analyze openapi.yaml",
|
|
88
|
+
"x-openapi-flow analyze openapi.yaml --out openapi.x.yaml",
|
|
89
|
+
"x-openapi-flow analyze openapi.yaml --merge --flows openapi.x.yaml",
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
"generate-sdk": {
|
|
93
|
+
usage: "x-openapi-flow generate-sdk [openapi-file] --lang typescript [--output path]",
|
|
94
|
+
examples: [
|
|
95
|
+
"x-openapi-flow generate-sdk openapi.yaml --lang typescript --output ./sdk",
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
"export-doc-flows": {
|
|
99
|
+
usage: "x-openapi-flow export-doc-flows [openapi-file] [--output path] [--format markdown|json]",
|
|
100
|
+
examples: [
|
|
101
|
+
"x-openapi-flow export-doc-flows openapi.yaml --output ./docs/api-flows.md",
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
"generate-postman": {
|
|
105
|
+
usage: "x-openapi-flow generate-postman [openapi-file] [--output path] [--with-scripts]",
|
|
106
|
+
examples: [
|
|
107
|
+
"x-openapi-flow generate-postman openapi.yaml --output ./x-openapi-flow.postman_collection.json --with-scripts",
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
"generate-insomnia": {
|
|
111
|
+
usage: "x-openapi-flow generate-insomnia [openapi-file] [--output path]",
|
|
112
|
+
examples: [
|
|
113
|
+
"x-openapi-flow generate-insomnia openapi.yaml --output ./x-openapi-flow.insomnia.json",
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
"generate-redoc": {
|
|
117
|
+
usage: "x-openapi-flow generate-redoc [openapi-file] [--output path]",
|
|
118
|
+
examples: [
|
|
119
|
+
"x-openapi-flow generate-redoc openapi.yaml --output ./redoc-flow",
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
graph: {
|
|
123
|
+
usage: "x-openapi-flow graph <openapi-file> [--format mermaid|json]",
|
|
124
|
+
examples: [
|
|
125
|
+
"x-openapi-flow graph examples/order-api.yaml",
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
doctor: {
|
|
129
|
+
usage: "x-openapi-flow doctor [--config path]",
|
|
130
|
+
examples: [
|
|
131
|
+
"x-openapi-flow doctor",
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
completion: {
|
|
135
|
+
usage: "x-openapi-flow completion [bash|zsh]",
|
|
136
|
+
examples: [
|
|
137
|
+
"x-openapi-flow completion bash > ~/.x-openapi-flow-completion.bash",
|
|
138
|
+
"x-openapi-flow completion zsh > ~/.x-openapi-flow-completion.zsh",
|
|
139
|
+
],
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
function stripGlobalFlags(args) {
|
|
144
|
+
const cleaned = [];
|
|
145
|
+
let verbose = false;
|
|
146
|
+
|
|
147
|
+
for (const token of args) {
|
|
148
|
+
if (token === "--verbose") {
|
|
149
|
+
verbose = true;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
cleaned.push(token);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return { args: cleaned, verbose };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function printVerbose(parsed) {
|
|
159
|
+
if (!parsed || !parsed.verbose) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const printable = { ...parsed };
|
|
164
|
+
console.error("[verbose] Parsed CLI arguments:");
|
|
165
|
+
console.error(JSON.stringify(printable, null, 2));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function buildCompletionScript(shell) {
|
|
169
|
+
const commands = [...KNOWN_COMMANDS, "help", "version"].join(" ");
|
|
170
|
+
|
|
171
|
+
if (shell === "zsh") {
|
|
172
|
+
return `#compdef x-openapi-flow
|
|
173
|
+
_x_openapi_flow() {
|
|
174
|
+
local -a commands
|
|
175
|
+
commands=(${commands})
|
|
176
|
+
local -a global_opts
|
|
177
|
+
global_opts=(--help --version --verbose)
|
|
178
|
+
|
|
179
|
+
if (( CURRENT == 2 )); then
|
|
180
|
+
_describe 'command' commands
|
|
181
|
+
return
|
|
182
|
+
fi
|
|
183
|
+
|
|
184
|
+
case "$words[2]" in
|
|
185
|
+
validate)
|
|
186
|
+
_values 'options' --format --profile --strict-quality --config --help
|
|
187
|
+
;;
|
|
188
|
+
init)
|
|
189
|
+
_values 'options' --flows --force --dry-run --help
|
|
190
|
+
;;
|
|
191
|
+
apply)
|
|
192
|
+
_values 'options' --flows --out --in-place --help
|
|
193
|
+
;;
|
|
194
|
+
diff)
|
|
195
|
+
_values 'options' --flows --format --help
|
|
196
|
+
;;
|
|
197
|
+
lint)
|
|
198
|
+
_values 'options' --format --config --help
|
|
199
|
+
;;
|
|
200
|
+
analyze)
|
|
201
|
+
_values 'options' --format --out --merge --flows --help
|
|
202
|
+
;;
|
|
203
|
+
generate-sdk)
|
|
204
|
+
_values 'options' --lang --output --help
|
|
205
|
+
;;
|
|
206
|
+
export-doc-flows)
|
|
207
|
+
_values 'options' --output --format --help
|
|
208
|
+
;;
|
|
209
|
+
generate-postman)
|
|
210
|
+
_values 'options' --output --with-scripts --help
|
|
211
|
+
;;
|
|
212
|
+
generate-insomnia)
|
|
213
|
+
_values 'options' --output --help
|
|
214
|
+
;;
|
|
215
|
+
generate-redoc)
|
|
216
|
+
_values 'options' --output --help
|
|
217
|
+
;;
|
|
218
|
+
graph)
|
|
219
|
+
_values 'options' --format --help
|
|
220
|
+
;;
|
|
221
|
+
doctor)
|
|
222
|
+
_values 'options' --config --help
|
|
223
|
+
;;
|
|
224
|
+
completion)
|
|
225
|
+
_values 'shell' bash zsh
|
|
226
|
+
;;
|
|
227
|
+
*)
|
|
228
|
+
_values 'global options' $global_opts
|
|
229
|
+
;;
|
|
230
|
+
esac
|
|
231
|
+
}
|
|
232
|
+
compdef _x_openapi_flow x-openapi-flow
|
|
233
|
+
`;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return `_x_openapi_flow()
|
|
237
|
+
{
|
|
238
|
+
local cur prev opts
|
|
239
|
+
COMPREPLY=()
|
|
240
|
+
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
241
|
+
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
242
|
+
opts="${commands}"
|
|
243
|
+
|
|
244
|
+
if [[ \${COMP_CWORD} -eq 1 ]]; then
|
|
245
|
+
COMPREPLY=( $(compgen -W "${commands} --help --version --verbose" -- "\$cur") )
|
|
246
|
+
return 0
|
|
247
|
+
fi
|
|
248
|
+
|
|
249
|
+
case "\${COMP_WORDS[1]}" in
|
|
250
|
+
validate)
|
|
251
|
+
COMPREPLY=( $(compgen -W "--format --profile --strict-quality --config --help --verbose" -- "\$cur") )
|
|
252
|
+
;;
|
|
253
|
+
init)
|
|
254
|
+
COMPREPLY=( $(compgen -W "--flows --force --dry-run --help --verbose" -- "\$cur") )
|
|
255
|
+
;;
|
|
256
|
+
apply)
|
|
257
|
+
COMPREPLY=( $(compgen -W "--flows --out --in-place --help --verbose" -- "\$cur") )
|
|
258
|
+
;;
|
|
259
|
+
diff)
|
|
260
|
+
COMPREPLY=( $(compgen -W "--flows --format --help --verbose" -- "\$cur") )
|
|
261
|
+
;;
|
|
262
|
+
lint)
|
|
263
|
+
COMPREPLY=( $(compgen -W "--format --config --help --verbose" -- "\$cur") )
|
|
264
|
+
;;
|
|
265
|
+
analyze)
|
|
266
|
+
COMPREPLY=( $(compgen -W "--format --out --merge --flows --help --verbose" -- "\$cur") )
|
|
267
|
+
;;
|
|
268
|
+
generate-sdk)
|
|
269
|
+
COMPREPLY=( $(compgen -W "--lang --output --help --verbose" -- "\$cur") )
|
|
270
|
+
;;
|
|
271
|
+
export-doc-flows)
|
|
272
|
+
COMPREPLY=( $(compgen -W "--output --format --help --verbose" -- "\$cur") )
|
|
273
|
+
;;
|
|
274
|
+
generate-postman)
|
|
275
|
+
COMPREPLY=( $(compgen -W "--output --with-scripts --help --verbose" -- "\$cur") )
|
|
276
|
+
;;
|
|
277
|
+
generate-insomnia)
|
|
278
|
+
COMPREPLY=( $(compgen -W "--output --help --verbose" -- "\$cur") )
|
|
279
|
+
;;
|
|
280
|
+
generate-redoc)
|
|
281
|
+
COMPREPLY=( $(compgen -W "--output --help --verbose" -- "\$cur") )
|
|
282
|
+
;;
|
|
283
|
+
graph)
|
|
284
|
+
COMPREPLY=( $(compgen -W "--format --help --verbose" -- "\$cur") )
|
|
285
|
+
;;
|
|
286
|
+
doctor)
|
|
287
|
+
COMPREPLY=( $(compgen -W "--config --help --verbose" -- "\$cur") )
|
|
288
|
+
;;
|
|
289
|
+
completion)
|
|
290
|
+
COMPREPLY=( $(compgen -W "bash zsh --help --verbose" -- "\$cur") )
|
|
291
|
+
;;
|
|
292
|
+
*)
|
|
293
|
+
COMPREPLY=( $(compgen -W "--help --version --verbose" -- "\$cur") )
|
|
294
|
+
;;
|
|
295
|
+
esac
|
|
296
|
+
}
|
|
297
|
+
complete -F _x_openapi_flow x-openapi-flow
|
|
298
|
+
`;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function parseCompletionArgs(args) {
|
|
302
|
+
const positional = args.filter((token) => !token.startsWith("--"));
|
|
303
|
+
if (positional.length > 1) {
|
|
304
|
+
return { error: `Unexpected argument: ${positional[1]}` };
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const shell = positional[0] || "bash";
|
|
308
|
+
if (![
|
|
309
|
+
"bash",
|
|
310
|
+
"zsh",
|
|
311
|
+
].includes(shell)) {
|
|
312
|
+
return { error: `Invalid shell '${shell}'. Use 'bash' or 'zsh'.` };
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return { shell };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function suggestCommand(input) {
|
|
319
|
+
if (!input) return null;
|
|
320
|
+
const normalized = input.toLowerCase();
|
|
321
|
+
const prefix = KNOWN_COMMANDS.find((cmd) => cmd.startsWith(normalized));
|
|
322
|
+
if (prefix) {
|
|
323
|
+
return prefix;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const includes = KNOWN_COMMANDS.find((cmd) => cmd.includes(normalized));
|
|
327
|
+
if (includes) {
|
|
328
|
+
return includes;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function levenshtein(a, b) {
|
|
332
|
+
const rows = a.length + 1;
|
|
333
|
+
const cols = b.length + 1;
|
|
334
|
+
const matrix = Array.from({ length: rows }, () => Array(cols).fill(0));
|
|
335
|
+
|
|
336
|
+
for (let i = 0; i < rows; i += 1) {
|
|
337
|
+
matrix[i][0] = i;
|
|
338
|
+
}
|
|
339
|
+
for (let j = 0; j < cols; j += 1) {
|
|
340
|
+
matrix[0][j] = j;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
for (let i = 1; i < rows; i += 1) {
|
|
344
|
+
for (let j = 1; j < cols; j += 1) {
|
|
345
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
346
|
+
matrix[i][j] = Math.min(
|
|
347
|
+
matrix[i - 1][j] + 1,
|
|
348
|
+
matrix[i][j - 1] + 1,
|
|
349
|
+
matrix[i - 1][j - 1] + cost
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return matrix[a.length][b.length];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
let best = null;
|
|
358
|
+
let bestScore = Number.POSITIVE_INFINITY;
|
|
359
|
+
for (const candidate of KNOWN_COMMANDS) {
|
|
360
|
+
const score = levenshtein(normalized, candidate);
|
|
361
|
+
if (score < bestScore) {
|
|
362
|
+
bestScore = score;
|
|
363
|
+
best = candidate;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return bestScore <= 3 ? best : null;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function buildUnknownCommandError(command) {
|
|
371
|
+
const suggestion = suggestCommand(command);
|
|
372
|
+
if (!suggestion) {
|
|
373
|
+
return `Unknown command: ${command}`;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return `Unknown command: ${command}. Did you mean '${suggestion}'?`;
|
|
377
|
+
}
|
|
26
378
|
|
|
27
379
|
function resolveConfigPath(configPathArg) {
|
|
28
380
|
return configPathArg
|
|
@@ -49,10 +401,23 @@ function loadConfig(configPathArg) {
|
|
|
49
401
|
}
|
|
50
402
|
}
|
|
51
403
|
|
|
52
|
-
function printHelp() {
|
|
404
|
+
function printHelp(command) {
|
|
405
|
+
if (command && COMMAND_SNIPPETS[command]) {
|
|
406
|
+
const snippet = COMMAND_SNIPPETS[command];
|
|
407
|
+
const examples = snippet.examples.map((item) => ` ${item}`).join("\n");
|
|
408
|
+
console.log(`x-openapi-flow CLI\n\nCommand: ${command}\n\nUsage:\n ${snippet.usage}\n\nExamples:\n${examples}\n`);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
|
|
53
412
|
console.log(`x-openapi-flow CLI
|
|
54
413
|
|
|
414
|
+
Global options:
|
|
415
|
+
--help, -h Show help
|
|
416
|
+
--version, -v Show CLI version
|
|
417
|
+
--verbose Print parsed arguments for troubleshooting
|
|
418
|
+
|
|
55
419
|
Usage:
|
|
420
|
+
x-openapi-flow <command> [options]
|
|
56
421
|
x-openapi-flow validate <openapi-file> [--format pretty|json] [--profile core|relaxed|strict] [--strict-quality] [--config path]
|
|
57
422
|
x-openapi-flow init [openapi-file] [--flows path] [--force] [--dry-run]
|
|
58
423
|
x-openapi-flow apply [openapi-file] [--flows path] [--out path] [--in-place]
|
|
@@ -66,7 +431,11 @@ Usage:
|
|
|
66
431
|
x-openapi-flow generate-redoc [openapi-file] [--output path]
|
|
67
432
|
x-openapi-flow graph <openapi-file> [--format mermaid|json]
|
|
68
433
|
x-openapi-flow doctor [--config path]
|
|
434
|
+
x-openapi-flow completion [bash|zsh]
|
|
435
|
+
x-openapi-flow help [command]
|
|
436
|
+
x-openapi-flow version
|
|
69
437
|
x-openapi-flow --help
|
|
438
|
+
x-openapi-flow --version
|
|
70
439
|
|
|
71
440
|
Examples:
|
|
72
441
|
x-openapi-flow validate examples/order-api.yaml
|
|
@@ -94,6 +463,25 @@ Examples:
|
|
|
94
463
|
x-openapi-flow generate-redoc openapi.yaml --output ./redoc-flow
|
|
95
464
|
x-openapi-flow graph examples/order-api.yaml
|
|
96
465
|
x-openapi-flow doctor
|
|
466
|
+
|
|
467
|
+
Quick Start:
|
|
468
|
+
# 1) Initialize sidecar from your OpenAPI file
|
|
469
|
+
x-openapi-flow init
|
|
470
|
+
|
|
471
|
+
# 2) Apply sidecar into flow output
|
|
472
|
+
x-openapi-flow apply
|
|
473
|
+
|
|
474
|
+
# 3) Validate with strict profile
|
|
475
|
+
x-openapi-flow validate --profile strict
|
|
476
|
+
|
|
477
|
+
Autocomplete:
|
|
478
|
+
# Bash
|
|
479
|
+
x-openapi-flow completion bash > ~/.x-openapi-flow-completion.bash
|
|
480
|
+
echo 'source ~/.x-openapi-flow-completion.bash' >> ~/.bashrc
|
|
481
|
+
|
|
482
|
+
# Zsh
|
|
483
|
+
x-openapi-flow completion zsh > ~/.x-openapi-flow-completion.zsh
|
|
484
|
+
echo 'source ~/.x-openapi-flow-completion.zsh' >> ~/.zshrc
|
|
97
485
|
`);
|
|
98
486
|
}
|
|
99
487
|
|
|
@@ -828,84 +1216,113 @@ function parseGenerateRedocArgs(args) {
|
|
|
828
1216
|
}
|
|
829
1217
|
|
|
830
1218
|
function parseArgs(argv) {
|
|
831
|
-
const
|
|
1219
|
+
const stripped = stripGlobalFlags(argv.slice(2));
|
|
1220
|
+
const args = stripped.args;
|
|
832
1221
|
const command = args[0];
|
|
1222
|
+
const withVerbose = (payload) => ({ ...payload, verbose: stripped.verbose });
|
|
833
1223
|
|
|
834
1224
|
if (!command || command === "--help" || command === "-h") {
|
|
835
|
-
return { help: true };
|
|
1225
|
+
return withVerbose({ help: true });
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
if (command === "--version" || command === "-v" || command === "version") {
|
|
1229
|
+
return withVerbose({ version: true });
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
if (command === "help") {
|
|
1233
|
+
const helpTarget = args[1];
|
|
1234
|
+
if (!helpTarget) {
|
|
1235
|
+
return withVerbose({ help: true });
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
if (!KNOWN_COMMANDS.includes(helpTarget)) {
|
|
1239
|
+
return withVerbose({ error: buildUnknownCommandError(helpTarget) });
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
return withVerbose({ help: true, command: helpTarget });
|
|
836
1243
|
}
|
|
837
1244
|
|
|
838
1245
|
const commandArgs = args.slice(1);
|
|
839
1246
|
if (commandArgs.includes("--help") || commandArgs.includes("-h")) {
|
|
840
|
-
return { help: true, command };
|
|
1247
|
+
return withVerbose({ help: true, command });
|
|
841
1248
|
}
|
|
842
1249
|
|
|
843
1250
|
if (command === "validate") {
|
|
844
1251
|
const parsed = parseValidateArgs(commandArgs);
|
|
845
|
-
return parsed.error ? parsed : { command, ...parsed };
|
|
1252
|
+
return withVerbose(parsed.error ? parsed : { command, ...parsed });
|
|
846
1253
|
}
|
|
847
1254
|
|
|
848
1255
|
if (command === "init") {
|
|
849
1256
|
const parsed = parseInitArgs(commandArgs);
|
|
850
|
-
return parsed.error ? parsed : { command, ...parsed };
|
|
1257
|
+
return withVerbose(parsed.error ? parsed : { command, ...parsed });
|
|
851
1258
|
}
|
|
852
1259
|
|
|
853
1260
|
if (command === "graph") {
|
|
854
1261
|
const parsed = parseGraphArgs(commandArgs);
|
|
855
|
-
return parsed.error ? parsed : { command, ...parsed };
|
|
1262
|
+
return withVerbose(parsed.error ? parsed : { command, ...parsed });
|
|
856
1263
|
}
|
|
857
1264
|
|
|
858
1265
|
if (command === "analyze") {
|
|
859
1266
|
const parsed = parseAnalyzeArgs(commandArgs);
|
|
860
|
-
return parsed.error ? parsed : { command, ...parsed };
|
|
1267
|
+
return withVerbose(parsed.error ? parsed : { command, ...parsed });
|
|
861
1268
|
}
|
|
862
1269
|
|
|
863
1270
|
if (command === "apply") {
|
|
864
1271
|
const parsed = parseApplyArgs(commandArgs);
|
|
865
|
-
return parsed.error ? parsed : { command, ...parsed };
|
|
1272
|
+
return withVerbose(parsed.error ? parsed : { command, ...parsed });
|
|
866
1273
|
}
|
|
867
1274
|
|
|
868
1275
|
if (command === "diff") {
|
|
869
1276
|
const parsed = parseDiffArgs(commandArgs);
|
|
870
|
-
return parsed.error ? parsed : { command, ...parsed };
|
|
1277
|
+
return withVerbose(parsed.error ? parsed : { command, ...parsed });
|
|
871
1278
|
}
|
|
872
1279
|
|
|
873
1280
|
if (command === "lint") {
|
|
874
1281
|
const parsed = parseLintArgs(commandArgs);
|
|
875
|
-
return parsed.error ? parsed : { command, ...parsed };
|
|
1282
|
+
return withVerbose(parsed.error ? parsed : { command, ...parsed });
|
|
876
1283
|
}
|
|
877
1284
|
|
|
878
1285
|
if (command === "doctor") {
|
|
879
1286
|
const parsed = parseDoctorArgs(commandArgs);
|
|
880
|
-
return parsed.error ? parsed : { command, ...parsed };
|
|
1287
|
+
return withVerbose(parsed.error ? parsed : { command, ...parsed });
|
|
881
1288
|
}
|
|
882
1289
|
|
|
883
1290
|
if (command === "generate-sdk") {
|
|
884
1291
|
const parsed = parseGenerateSdkArgs(commandArgs);
|
|
885
|
-
return parsed.error ? parsed : { command, ...parsed };
|
|
1292
|
+
return withVerbose(parsed.error ? parsed : { command, ...parsed });
|
|
886
1293
|
}
|
|
887
1294
|
|
|
888
1295
|
if (command === "export-doc-flows") {
|
|
889
1296
|
const parsed = parseExportDocFlowsArgs(commandArgs);
|
|
890
|
-
return parsed.error ? parsed : { command, ...parsed };
|
|
1297
|
+
return withVerbose(parsed.error ? parsed : { command, ...parsed });
|
|
891
1298
|
}
|
|
892
1299
|
|
|
893
1300
|
if (command === "generate-postman") {
|
|
894
1301
|
const parsed = parseGeneratePostmanArgs(commandArgs);
|
|
895
|
-
return parsed.error ? parsed : { command, ...parsed };
|
|
1302
|
+
return withVerbose(parsed.error ? parsed : { command, ...parsed });
|
|
896
1303
|
}
|
|
897
1304
|
|
|
898
1305
|
if (command === "generate-insomnia") {
|
|
899
1306
|
const parsed = parseGenerateInsomniaArgs(commandArgs);
|
|
900
|
-
return parsed.error ? parsed : { command, ...parsed };
|
|
1307
|
+
return withVerbose(parsed.error ? parsed : { command, ...parsed });
|
|
901
1308
|
}
|
|
902
1309
|
|
|
903
1310
|
if (command === "generate-redoc") {
|
|
904
1311
|
const parsed = parseGenerateRedocArgs(commandArgs);
|
|
905
|
-
return parsed.error ? parsed : { command, ...parsed };
|
|
1312
|
+
return withVerbose(parsed.error ? parsed : { command, ...parsed });
|
|
906
1313
|
}
|
|
907
1314
|
|
|
908
|
-
|
|
1315
|
+
if (command === "completion") {
|
|
1316
|
+
const parsed = parseCompletionArgs(commandArgs);
|
|
1317
|
+
return withVerbose(parsed.error ? parsed : { command, ...parsed });
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
return withVerbose({ error: buildUnknownCommandError(command) });
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
function runCompletion(parsed) {
|
|
1324
|
+
console.log(buildCompletionScript(parsed.shell));
|
|
1325
|
+
return 0;
|
|
909
1326
|
}
|
|
910
1327
|
|
|
911
1328
|
function findOpenApiFile(startDirectory) {
|
|
@@ -2251,9 +2668,19 @@ function runGenerateRedoc(parsed) {
|
|
|
2251
2668
|
|
|
2252
2669
|
function main() {
|
|
2253
2670
|
const parsed = parseArgs(process.argv);
|
|
2671
|
+
printVerbose(parsed);
|
|
2672
|
+
|
|
2673
|
+
if (parsed.version) {
|
|
2674
|
+
console.log(pkg.version);
|
|
2675
|
+
process.exit(0);
|
|
2676
|
+
}
|
|
2254
2677
|
|
|
2255
2678
|
if (parsed.help) {
|
|
2256
|
-
|
|
2679
|
+
if (parsed.command && !KNOWN_COMMANDS.includes(parsed.command)) {
|
|
2680
|
+
console.error(`ERROR: ${buildUnknownCommandError(parsed.command)}`);
|
|
2681
|
+
process.exit(1);
|
|
2682
|
+
}
|
|
2683
|
+
printHelp(parsed.command);
|
|
2257
2684
|
process.exit(0);
|
|
2258
2685
|
}
|
|
2259
2686
|
|
|
@@ -2300,6 +2727,10 @@ function main() {
|
|
|
2300
2727
|
process.exit(runGenerateRedoc(parsed));
|
|
2301
2728
|
}
|
|
2302
2729
|
|
|
2730
|
+
if (parsed.command === "completion") {
|
|
2731
|
+
process.exit(runCompletion(parsed));
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2303
2734
|
if (parsed.command === "apply") {
|
|
2304
2735
|
process.exit(runApply(parsed));
|
|
2305
2736
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "x-openapi-flow",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.6",
|
|
4
4
|
"description": "OpenAPI extension for resource workflow and lifecycle management",
|
|
5
5
|
"main": "lib/validator.js",
|
|
6
6
|
"repository": {
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
"adapters",
|
|
18
18
|
"templates",
|
|
19
19
|
"schema",
|
|
20
|
-
"schema",
|
|
21
20
|
"examples",
|
|
22
21
|
"README.md",
|
|
23
22
|
"LICENSE"
|