swagger-typescript-api 13.0.0-experimental-1 → 13.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/LICENSE +21 -21
- package/README.md +26 -12
- package/cli/constants.js +3 -3
- package/cli/execute.js +52 -31
- package/cli/index.d.ts +1 -2
- package/cli/index.js +18 -17
- package/cli/operations/display-help.js +51 -29
- package/cli/parse-args.js +3 -3
- package/cli/process-option.js +28 -20
- package/index.d.ts +113 -8
- package/index.js +164 -135
- package/package.json +36 -30
- package/src/code-formatter.js +28 -13
- package/src/code-gen-process.js +367 -259
- package/src/commands/generate-templates/configuration.js +2 -2
- package/src/commands/generate-templates/index.js +1 -2
- package/src/commands/generate-templates/templates-gen-process.js +62 -35
- package/src/component-type-name-resolver.js +44 -0
- package/src/configuration.js +172 -96
- package/src/constants.js +28 -22
- package/src/index.js +3 -4
- package/src/schema-components-map.js +43 -25
- package/src/schema-parser/base-schema-parsers/array.js +43 -0
- package/src/schema-parser/base-schema-parsers/complex.js +51 -0
- package/src/schema-parser/base-schema-parsers/discriminator.js +304 -0
- package/src/schema-parser/base-schema-parsers/enum.js +158 -0
- package/src/schema-parser/base-schema-parsers/object.js +105 -0
- package/src/schema-parser/base-schema-parsers/primitive.js +63 -0
- package/src/schema-parser/complex-schema-parsers/all-of.js +26 -0
- package/src/schema-parser/complex-schema-parsers/any-of.js +27 -0
- package/src/schema-parser/complex-schema-parsers/not.js +9 -0
- package/src/schema-parser/complex-schema-parsers/one-of.js +27 -0
- package/src/schema-parser/mono-schema-parser.js +48 -0
- package/src/schema-parser/schema-formatters.js +69 -60
- package/src/schema-parser/schema-parser-fabric.js +131 -0
- package/src/schema-parser/schema-parser.js +234 -425
- package/src/schema-parser/schema-utils.js +165 -67
- package/src/schema-parser/util/enum-key-resolver.js +26 -0
- package/src/schema-routes/schema-routes.js +1222 -0
- package/src/schema-routes/util/specific-arg-name-resolver.js +26 -0
- package/src/schema-walker.js +93 -0
- package/src/swagger-schema-resolver.js +61 -28
- package/src/templates-worker.js +240 -0
- package/src/translators/javascript.js +83 -0
- package/src/translators/translator.js +35 -0
- package/src/type-name-formatter.js +43 -22
- package/src/util/file-system.js +30 -14
- package/src/util/id.js +2 -2
- package/src/util/internal-case.js +1 -1
- package/src/util/logger.js +46 -20
- package/src/util/name-resolver.js +52 -60
- package/src/util/object-assign.js +7 -3
- package/src/util/pascal-case.js +1 -1
- package/src/util/request.js +5 -5
- package/src/util/sort-by-property.js +17 -0
- package/templates/README.md +17 -17
- package/templates/base/README.md +7 -7
- package/templates/base/data-contract-jsdoc.ejs +37 -37
- package/templates/base/data-contracts.ejs +40 -27
- package/templates/base/enum-data-contract.ejs +12 -12
- package/templates/base/http-client.ejs +3 -3
- package/templates/base/http-clients/axios-http-client.ejs +139 -138
- package/templates/base/http-clients/fetch-http-client.ejs +224 -224
- package/templates/base/interface-data-contract.ejs +10 -10
- package/templates/base/object-field-jsdoc.ejs +28 -28
- package/templates/base/route-docs.ejs +30 -30
- package/templates/base/route-name.ejs +42 -42
- package/templates/base/route-type.ejs +22 -21
- package/templates/base/type-data-contract.ejs +15 -15
- package/templates/default/README.md +6 -6
- package/templates/default/api.ejs +69 -68
- package/templates/default/procedure-call.ejs +100 -100
- package/templates/default/route-types.ejs +32 -32
- package/templates/modular/README.md +6 -6
- package/templates/modular/api.ejs +28 -28
- package/templates/modular/procedure-call.ejs +100 -100
- package/templates/modular/route-types.ejs +18 -18
- package/src/schema-parser/schema-processor.js +0 -79
- package/src/schema-parser/schema-routes.js +0 -950
- package/src/templates.js +0 -182
- package/src/translators/JavaScript.js +0 -60
package/LICENSE
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2019-present acacode
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
-
a copy of this software and associated documentation files (the
|
|
7
|
-
'Software'), to deal in the Software without restriction, including
|
|
8
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
-
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
-
the following conditions:
|
|
12
|
-
|
|
13
|
-
The above copyright notice and this permission notice shall be
|
|
14
|
-
included in all copies or substantial portions of the Software.
|
|
15
|
-
|
|
16
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
20
|
-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019-present acacode
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
'Software'), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
22
22
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/swagger-typescript-api)
|
|
4
4
|
[](https://github.com/acacode/swagger-typescript-api/actions/workflows/main.yml) <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
|
5
|
-
[](#contributors)
|
|
6
6
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
|
7
7
|
|
|
8
8
|
<img src="https://raw.githubusercontent.com/acacode/swagger-typescript-api/master/assets/swagger-typescript-api-logo.png" align="left"
|
|
@@ -21,9 +21,15 @@ Any questions you can ask [**here**](https://github.com/acacode/swagger-typescri
|
|
|
21
21
|
|
|
22
22
|

|
|
23
23
|
|
|
24
|
-
👀 This project is looking for a code maintainer 👀
|
|
25
24
|
P.S. If you are creating the PR, please check your changes with using command `npm run prepare`
|
|
26
|
-
P.S. If you want to contribute please use
|
|
25
|
+
P.S. If you want to contribute please use the `next` branch. All PRs that has target `master` will be declined!
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
Thanks to [Jetbrains](https://www.jetbrains.com/?from=swaggertypescriptapi) for providing a free license for their excellent Webstorm IDE.
|
|
29
|
+
<a href="https://www.jetbrains.com/?from=swaggertypescriptapi">
|
|
30
|
+
<img src="https://upload.wikimedia.org/wikipedia/commons/1/1a/JetBrains_Logo_2016.svg" alt="Jetbrains">
|
|
31
|
+
</a>
|
|
32
|
+
|
|
27
33
|
|
|
28
34
|
## 👀 Examples
|
|
29
35
|
|
|
@@ -75,6 +81,8 @@ Options:
|
|
|
75
81
|
--debug additional information about processes inside this tool (default: false)
|
|
76
82
|
--another-array-type generate array types as Array<Type> (by default Type[]) (default: false)
|
|
77
83
|
--sort-types sort fields and types (default: false)
|
|
84
|
+
--sort-routes sort routes in alphabetical order (default: false)
|
|
85
|
+
--custom-config <string> custom config: primitiveTypeConstructs, hooks, ... (default: "")
|
|
78
86
|
--extract-enums extract all enums from inline interface\type content to typescript enum construction (default: false)
|
|
79
87
|
-h, --help display help for command
|
|
80
88
|
|
|
@@ -100,7 +108,7 @@ const { generateApi, generateTemplates } = require('swagger-typescript-api');
|
|
|
100
108
|
const path = require("path");
|
|
101
109
|
const fs = require("fs");
|
|
102
110
|
|
|
103
|
-
/* NOTE: all fields are optional expect one of `
|
|
111
|
+
/* NOTE: all fields are optional expect one of `input`, `url`, `spec` */
|
|
104
112
|
generateApi({
|
|
105
113
|
name: "MySuperbApi.ts",
|
|
106
114
|
// set to `false` to prevent the tool from writing to disk
|
|
@@ -124,6 +132,7 @@ generateApi({
|
|
|
124
132
|
toJS: false,
|
|
125
133
|
extractRequestParams: false,
|
|
126
134
|
extractRequestBody: false,
|
|
135
|
+
extractEnums: false,
|
|
127
136
|
unwrapResponseData: false,
|
|
128
137
|
prettier: { // By default prettier config is load from your project
|
|
129
138
|
printWidth: 120,
|
|
@@ -142,6 +151,8 @@ generateApi({
|
|
|
142
151
|
enumKeyPrefix: '',
|
|
143
152
|
enumKeySuffix: '',
|
|
144
153
|
addReadonly: false,
|
|
154
|
+
sortTypes: false,
|
|
155
|
+
sortRouters: false,
|
|
145
156
|
extractingOptions: {
|
|
146
157
|
requestBodySuffix: ["Payload", "Body", "Input"],
|
|
147
158
|
requestParamsSuffix: ["Params"],
|
|
@@ -399,15 +410,16 @@ generateApi({
|
|
|
399
410
|
### `primitiveTypeConstructs`
|
|
400
411
|
|
|
401
412
|
It is type mapper or translator swagger schema objects. `primitiveTypeConstructs` translates `type`/`format` schema fields to typescript structs.
|
|
402
|
-
This option has type
|
|
403
|
-
|
|
413
|
+
This option has type
|
|
404
414
|
```ts
|
|
405
415
|
type PrimitiveTypeStructValue =
|
|
406
|
-
|
|
407
|
-
|
|
416
|
+
| string
|
|
417
|
+
| ((schema: Record<string, any>, parser: import("./src/schema-parser/schema-parser").SchemaParser) => string);
|
|
408
418
|
|
|
409
|
-
type PrimitiveTypeStruct = Record<
|
|
410
|
-
|
|
419
|
+
type PrimitiveTypeStruct = Record<
|
|
420
|
+
"integer" | "number" | "boolean" | "object" | "file" | "string" | "array",
|
|
421
|
+
string | ({ $default: PrimitiveTypeStructValue } & Record<string, PrimitiveTypeStructValue>)
|
|
422
|
+
>
|
|
411
423
|
|
|
412
424
|
declare const primitiveTypeConstructs: (struct: PrimitiveTypeStruct) => Partial<PrimitiveTypeStruct>
|
|
413
425
|
|
|
@@ -442,8 +454,8 @@ generateApi({
|
|
|
442
454
|
"relative-json-pointer": () => "string",
|
|
443
455
|
regex: () => "string",
|
|
444
456
|
},
|
|
445
|
-
array:
|
|
446
|
-
const content =
|
|
457
|
+
array: (schema, parser) => {
|
|
458
|
+
const content = parser.getInlineParseContent(schema.items);
|
|
447
459
|
return parser.safeAddNullToType(schema, `(${content})[]`);
|
|
448
460
|
},
|
|
449
461
|
})
|
|
@@ -528,6 +540,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|
|
528
540
|
<td align="center"><a href="https://github.com/ApacheEx"><img src="https://avatars.githubusercontent.com/u/1918108?v=4?s=100" width="100px;" alt="Oleg Kuzava"/><br /><sub><b>Oleg Kuzava</b></sub></a><br /><a href="https://github.com/acacode/swagger-typescript-api/commits?author=ApacheEx" title="Code">💻</a> <a href="https://github.com/acacode/swagger-typescript-api/issues?q=author%3AApacheEx" title="Bug reports">🐛</a></td>
|
|
529
541
|
<td align="center"><a href="http://nikz.se"><img src="https://avatars.githubusercontent.com/u/7352072?v=4?s=100" width="100px;" alt="Niklas Frank"/><br /><sub><b>Niklas Frank</b></sub></a><br /><a href="https://github.com/acacode/swagger-typescript-api/commits?author=nksfrank" title="Code">💻</a> <a href="https://github.com/acacode/swagger-typescript-api/issues?q=author%3Anksfrank" title="Bug reports">🐛</a></td>
|
|
530
542
|
<td align="center"><a href="https://quentinbrunet.com"><img src="https://avatars.githubusercontent.com/u/20137632?v=4?s=100" width="100px;" alt="Quentin Brunet"/><br /><sub><b>Quentin Brunet</b></sub></a><br /><a href="https://github.com/acacode/swagger-typescript-api/commits?author=qboot" title="Code">💻</a></td>
|
|
543
|
+
<td align="center"><a href="https://github.com/Soarc"><img src="https://avatars.githubusercontent.com/u/3385495?v=4?s=100" width="100px;" alt="Gor Rustamyan"/><br /><sub><b>Gor Rustamyan</b></sub></a><br /><a href="https://github.com/acacode/swagger-typescript-api/commits?author=Soarc" title="Code">💻</a> <a href="https://github.com/acacode/swagger-typescript-api/issues?q=author%3ASoarc" title="Bug reports">🐛</a></td>
|
|
544
|
+
<td align="center"><a href="https://github.com/JochenDiekenbrock"><img src="https://avatars.githubusercontent.com/u/1625222?v=4?s=100" width="100px;" alt="Jochen Diekenbrock"/><br /><sub><b>Jochen Diekenbrock</b></sub></a><br /><a href="https://github.com/acacode/swagger-typescript-api/commits?author=JochenDiekenbrock" title="Code">💻</a> <a href="https://github.com/acacode/swagger-typescript-api/issues?q=author%3AJochenDiekenbrock" title="Bug reports">🐛</a></td>
|
|
531
545
|
</tr>
|
|
532
546
|
</tbody>
|
|
533
547
|
</table>
|
package/cli/constants.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const root_command = Symbol(
|
|
2
|
-
const skip_command = Symbol(
|
|
1
|
+
const root_command = Symbol('root');
|
|
2
|
+
const skip_command = Symbol('skip');
|
|
3
3
|
|
|
4
|
-
const reservedOptions = [
|
|
4
|
+
const reservedOptions = ['version', 'help'];
|
|
5
5
|
|
|
6
6
|
module.exports = {
|
|
7
7
|
root_command,
|
package/cli/execute.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
const _ = require(
|
|
2
|
-
const { root_command, skip_command } = require(
|
|
3
|
-
const { parseArgs } = require(
|
|
4
|
-
const didYouMean = require(
|
|
1
|
+
const _ = require('lodash');
|
|
2
|
+
const { root_command, skip_command } = require('./constants');
|
|
3
|
+
const { parseArgs } = require('./parse-args');
|
|
4
|
+
const didYouMean = require('didyoumean');
|
|
5
5
|
|
|
6
6
|
didYouMean.threshold = 0.5;
|
|
7
7
|
|
|
8
|
+
// eslint-disable-next-line no-unused-vars
|
|
8
9
|
const execute = (params, commands, instance) => {
|
|
9
10
|
const args = parseArgs(params.args, params.from);
|
|
10
11
|
|
|
@@ -17,7 +18,9 @@ const execute = (params, commands, instance) => {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
if (!usageOptions.length && command.name === root_command) {
|
|
20
|
-
usageOptions.push(
|
|
21
|
+
usageOptions.push(
|
|
22
|
+
command.options.find((option) => option.flags.name === 'help'),
|
|
23
|
+
);
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
const operationOptions = usageOptions.filter((option) => option.operation);
|
|
@@ -29,20 +32,23 @@ const execute = (params, commands, instance) => {
|
|
|
29
32
|
});
|
|
30
33
|
return;
|
|
31
34
|
} else {
|
|
32
|
-
let error =
|
|
35
|
+
let error = '';
|
|
33
36
|
|
|
34
|
-
const processUserOptionData = (
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return acc
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
37
|
+
const processUserOptionData = (userOption, option) => {
|
|
38
|
+
if (userOption) {
|
|
39
|
+
const data = userOption.$data;
|
|
40
|
+
if (!data.length && !option.flags.value) {
|
|
41
|
+
return !option.flags.isNoFlag;
|
|
42
|
+
}
|
|
43
|
+
if (option.flags.value) {
|
|
44
|
+
if (option.flags.value.variadic) {
|
|
45
|
+
return data.reduce((acc, d) => {
|
|
46
|
+
acc.push(...d.split(',').map(option.flags.value.formatter));
|
|
47
|
+
return acc;
|
|
48
|
+
}, []);
|
|
49
|
+
} else {
|
|
50
|
+
return option.flags.value.formatter(data[0] || option.default);
|
|
51
|
+
}
|
|
46
52
|
}
|
|
47
53
|
}
|
|
48
54
|
|
|
@@ -52,17 +58,21 @@ const execute = (params, commands, instance) => {
|
|
|
52
58
|
const parsedOptionsObject = command.options.reduce((acc, option) => {
|
|
53
59
|
if (error) return acc;
|
|
54
60
|
|
|
55
|
-
const userOption = usageOptions.find(
|
|
61
|
+
const userOption = usageOptions.find(
|
|
62
|
+
(o) => o.flags.name === option.flags.name,
|
|
63
|
+
);
|
|
56
64
|
|
|
57
65
|
if (!userOption && option.required) {
|
|
58
66
|
error = `required option '${option.flags.raw}' not specified`;
|
|
59
67
|
return acc;
|
|
60
68
|
}
|
|
61
69
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
acc[option.flags.name] =
|
|
70
|
+
const flagValue = processUserOptionData(userOption, option);
|
|
71
|
+
if (!option.operation) {
|
|
72
|
+
const internal = option.internal || {};
|
|
73
|
+
acc[internal.name || option.flags.name] = internal.formatter
|
|
74
|
+
? internal.formatter(flagValue)
|
|
75
|
+
: flagValue;
|
|
66
76
|
}
|
|
67
77
|
|
|
68
78
|
return acc;
|
|
@@ -84,7 +94,7 @@ const processArgs = (commands, args) => {
|
|
|
84
94
|
let command = null;
|
|
85
95
|
let usageOptions = [];
|
|
86
96
|
let walkingOption = null;
|
|
87
|
-
let error =
|
|
97
|
+
let error = '';
|
|
88
98
|
|
|
89
99
|
let allFlagKeys = [];
|
|
90
100
|
|
|
@@ -94,33 +104,44 @@ const processArgs = (commands, args) => {
|
|
|
94
104
|
if (i === 0) {
|
|
95
105
|
command = commands[arg];
|
|
96
106
|
|
|
97
|
-
if (!command && !arg.startsWith(
|
|
107
|
+
if (!command && !arg.startsWith('-')) {
|
|
98
108
|
const tip = didYouMean(arg, _.keys(commands));
|
|
99
|
-
error = `unknown command ${arg}${
|
|
109
|
+
error = `unknown command ${arg}${
|
|
110
|
+
tip ? `\n(Did you mean ${tip} ?)` : ''
|
|
111
|
+
}`;
|
|
100
112
|
} else if (!command) {
|
|
101
113
|
command = commands[root_command];
|
|
102
114
|
}
|
|
103
115
|
|
|
104
116
|
if (command) {
|
|
105
|
-
allFlagKeys = command.options.reduce(
|
|
117
|
+
allFlagKeys = command.options.reduce(
|
|
118
|
+
(acc, option) => [...acc, ...option.flags.keys],
|
|
119
|
+
[],
|
|
120
|
+
);
|
|
106
121
|
}
|
|
107
122
|
}
|
|
108
123
|
|
|
109
124
|
if (error) return;
|
|
110
125
|
|
|
111
|
-
if (arg.startsWith(
|
|
112
|
-
const option = command.options.find((option) =>
|
|
126
|
+
if (arg.startsWith('-')) {
|
|
127
|
+
const option = command.options.find((option) =>
|
|
128
|
+
option.flags.keys.includes(arg),
|
|
129
|
+
);
|
|
113
130
|
|
|
114
131
|
if (!option) {
|
|
115
132
|
const tip = didYouMean(arg, allFlagKeys);
|
|
116
|
-
error = `unknown option ${arg}${
|
|
133
|
+
error = `unknown option ${arg}${
|
|
134
|
+
tip ? `\n(Did you mean ${tip} ?)` : ''
|
|
135
|
+
}`;
|
|
117
136
|
}
|
|
118
137
|
|
|
119
138
|
if (option) {
|
|
120
139
|
if (walkingOption && walkingOption.flags.name === option.flags.name) {
|
|
121
140
|
return;
|
|
122
141
|
}
|
|
123
|
-
const existedOption = usageOptions.find(
|
|
142
|
+
const existedOption = usageOptions.find(
|
|
143
|
+
(o) => o.flags.name === option.flags.name,
|
|
144
|
+
);
|
|
124
145
|
if (existedOption) {
|
|
125
146
|
walkingOption = existedOption;
|
|
126
147
|
} else {
|
package/cli/index.d.ts
CHANGED
package/cli/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const _ = require(
|
|
2
|
-
const { reservedOptions, root_command } = require(
|
|
3
|
-
const { processOption } = require(
|
|
4
|
-
const { execute } = require(
|
|
5
|
-
const { displayHelp } = require(
|
|
6
|
-
const { displayVersion } = require(
|
|
1
|
+
const _ = require('lodash');
|
|
2
|
+
const { reservedOptions, root_command } = require('./constants');
|
|
3
|
+
const { processOption } = require('./process-option');
|
|
4
|
+
const { execute } = require('./execute');
|
|
5
|
+
const { displayHelp } = require('./operations/display-help');
|
|
6
|
+
const { displayVersion } = require('./operations/display-version');
|
|
7
7
|
|
|
8
8
|
const cli = (input) => {
|
|
9
9
|
const commands = {};
|
|
@@ -11,15 +11,15 @@ const cli = (input) => {
|
|
|
11
11
|
const addCommand = (command, { addVersion = false, addHelp = true } = {}) => {
|
|
12
12
|
commands[command.name] = {
|
|
13
13
|
name: command.name,
|
|
14
|
-
description: `${command.description ||
|
|
14
|
+
description: `${command.description || ''}`,
|
|
15
15
|
options: _.compact(_.map(command.options, processOption)),
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
if (addVersion) {
|
|
19
19
|
commands[command.name].options.unshift(
|
|
20
20
|
processOption({
|
|
21
|
-
flags:
|
|
22
|
-
description:
|
|
21
|
+
flags: '-v, --version',
|
|
22
|
+
description: 'output the current version',
|
|
23
23
|
operation: () => displayVersion(instance),
|
|
24
24
|
}),
|
|
25
25
|
);
|
|
@@ -28,9 +28,10 @@ const cli = (input) => {
|
|
|
28
28
|
if (addHelp) {
|
|
29
29
|
commands[command.name].options.push(
|
|
30
30
|
processOption({
|
|
31
|
-
flags:
|
|
32
|
-
description:
|
|
33
|
-
operation: () =>
|
|
31
|
+
flags: '-h, --help',
|
|
32
|
+
description: 'display help for command',
|
|
33
|
+
operation: () =>
|
|
34
|
+
displayHelp(commands, instance, commands[command.name]),
|
|
34
35
|
}),
|
|
35
36
|
);
|
|
36
37
|
}
|
|
@@ -62,7 +63,7 @@ const cli = (input) => {
|
|
|
62
63
|
if (!processed) return;
|
|
63
64
|
|
|
64
65
|
if (reservedOptions.includes(processed.name)) {
|
|
65
|
-
console.warn(
|
|
66
|
+
console.warn('reserved option', processed.name);
|
|
66
67
|
return;
|
|
67
68
|
}
|
|
68
69
|
|
|
@@ -71,16 +72,16 @@ const cli = (input) => {
|
|
|
71
72
|
|
|
72
73
|
commands[root_command].options.unshift(
|
|
73
74
|
processOption({
|
|
74
|
-
flags:
|
|
75
|
-
description:
|
|
75
|
+
flags: '-v, --version',
|
|
76
|
+
description: 'output the current version',
|
|
76
77
|
operation: () => displayVersion(instance),
|
|
77
78
|
}),
|
|
78
79
|
);
|
|
79
80
|
|
|
80
81
|
commands[root_command].options.push(
|
|
81
82
|
processOption({
|
|
82
|
-
flags:
|
|
83
|
-
description:
|
|
83
|
+
flags: '-h, --help',
|
|
84
|
+
description: 'display help for command',
|
|
84
85
|
operation: () => displayHelp(commands, instance, commands[root_command]),
|
|
85
86
|
}),
|
|
86
87
|
);
|
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
const _ = require(
|
|
2
|
-
const { root_command } = require(
|
|
1
|
+
const _ = require('lodash');
|
|
2
|
+
const { root_command } = require('../constants');
|
|
3
3
|
|
|
4
4
|
const generateOptionsOutput = (options) =>
|
|
5
5
|
options.reduce(
|
|
6
6
|
(acc, option) => {
|
|
7
|
-
const flags = `${option.flags.keys.join(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
const flags = `${option.flags.keys.join(', ')}${
|
|
8
|
+
option.flags.value?.raw ? ` ${option.flags.value?.raw}` : ''
|
|
9
|
+
}`;
|
|
10
|
+
const description = `${option.description || ''}${
|
|
11
|
+
option.default === undefined ||
|
|
12
|
+
(option.flags.isNoFlag && option.default === true)
|
|
13
|
+
? ''
|
|
14
|
+
: ` (default: ${
|
|
15
|
+
typeof option.default === 'string'
|
|
16
|
+
? `"${option.default}"`
|
|
17
|
+
: option.default
|
|
18
|
+
})`
|
|
12
19
|
}`;
|
|
13
20
|
|
|
14
21
|
if (flags.length > acc.maxLength) {
|
|
@@ -30,10 +37,10 @@ const generateOptionsOutput = (options) =>
|
|
|
30
37
|
const generateOptionsTextOutput = (options, maxLength, spaces) =>
|
|
31
38
|
options
|
|
32
39
|
.map((option) => {
|
|
33
|
-
const spacesText = Array(spaces).fill(
|
|
34
|
-
const leftStr = `${spacesText}${option.flags.padEnd(maxLength,
|
|
35
|
-
const leftStrFiller = Array(leftStr.length).fill(
|
|
36
|
-
const descriptionLines = option.description.split(
|
|
40
|
+
const spacesText = Array(spaces).fill(' ').join('');
|
|
41
|
+
const leftStr = `${spacesText}${option.flags.padEnd(maxLength, ' ')} `;
|
|
42
|
+
const leftStrFiller = Array(leftStr.length).fill(' ').join('');
|
|
43
|
+
const descriptionLines = option.description.split('\n');
|
|
37
44
|
|
|
38
45
|
return (
|
|
39
46
|
leftStr +
|
|
@@ -45,13 +52,15 @@ const generateOptionsTextOutput = (options, maxLength, spaces) =>
|
|
|
45
52
|
|
|
46
53
|
return `\n${leftStrFiller}${line}`;
|
|
47
54
|
})
|
|
48
|
-
.join(
|
|
55
|
+
.join('')
|
|
49
56
|
);
|
|
50
57
|
})
|
|
51
|
-
.join(
|
|
58
|
+
.join('\n');
|
|
52
59
|
|
|
53
60
|
const displayAllHelp = (commands, instance) => {
|
|
54
|
-
const { options, maxLength: maxOptionLength } = generateOptionsOutput(
|
|
61
|
+
const { options, maxLength: maxOptionLength } = generateOptionsOutput(
|
|
62
|
+
commands[root_command].options,
|
|
63
|
+
);
|
|
55
64
|
|
|
56
65
|
const { commands: commandLabels, maxLength: maxCommandLength } = _.filter(
|
|
57
66
|
commands,
|
|
@@ -59,7 +68,7 @@ const displayAllHelp = (commands, instance) => {
|
|
|
59
68
|
).reduce(
|
|
60
69
|
(acc, command) => {
|
|
61
70
|
const options = generateOptionsOutput(command.options);
|
|
62
|
-
const name = `${command.name}${options.length ?
|
|
71
|
+
const name = `${command.name}${options.length ? ' [options]' : ''}`;
|
|
63
72
|
const description = command.description;
|
|
64
73
|
|
|
65
74
|
const maxLength = Math.max(name.length, options.maxLength);
|
|
@@ -84,10 +93,17 @@ const displayAllHelp = (commands, instance) => {
|
|
|
84
93
|
|
|
85
94
|
const commandsOutput = commandLabels
|
|
86
95
|
.map((commandLabel) => {
|
|
87
|
-
const leftStr = ` ${commandLabel.name.padEnd(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
const leftStr = ` ${commandLabel.name.padEnd(
|
|
97
|
+
maxCommandLength,
|
|
98
|
+
' ',
|
|
99
|
+
)} `;
|
|
100
|
+
const leftStrFiller = Array(leftStr.length).fill(' ').join('');
|
|
101
|
+
const descriptionLines = commandLabel.description.split('\n');
|
|
102
|
+
const optionsTextOutput = generateOptionsTextOutput(
|
|
103
|
+
commandLabel.options.options,
|
|
104
|
+
maxCommandLength,
|
|
105
|
+
4,
|
|
106
|
+
);
|
|
91
107
|
|
|
92
108
|
return (
|
|
93
109
|
leftStr +
|
|
@@ -99,11 +115,11 @@ const displayAllHelp = (commands, instance) => {
|
|
|
99
115
|
|
|
100
116
|
return `\n${leftStrFiller}${line}`;
|
|
101
117
|
})
|
|
102
|
-
.join(
|
|
103
|
-
(optionsTextOutput.length ? `\n${optionsTextOutput}` :
|
|
118
|
+
.join('') +
|
|
119
|
+
(optionsTextOutput.length ? `\n${optionsTextOutput}` : '')
|
|
104
120
|
);
|
|
105
121
|
})
|
|
106
|
-
.join(
|
|
122
|
+
.join('\n');
|
|
107
123
|
|
|
108
124
|
const outputTest = [
|
|
109
125
|
optionsOutput &&
|
|
@@ -114,11 +130,13 @@ ${optionsOutput}`,
|
|
|
114
130
|
${commandsOutput}`,
|
|
115
131
|
]
|
|
116
132
|
.filter(Boolean)
|
|
117
|
-
.join(
|
|
133
|
+
.join('\n\n');
|
|
118
134
|
|
|
119
|
-
console.log(`Usage: ${[instance.input.name, instance.input.alias]
|
|
120
|
-
|
|
121
|
-
|
|
135
|
+
console.log(`Usage: ${[instance.input.name, instance.input.alias]
|
|
136
|
+
.filter(Boolean)
|
|
137
|
+
.join('|')}${optionsOutput ? ' [options]' : ''}${
|
|
138
|
+
commandsOutput ? ' [command]' : ''
|
|
139
|
+
}
|
|
122
140
|
${
|
|
123
141
|
instance.input.description &&
|
|
124
142
|
`
|
|
@@ -131,7 +149,9 @@ ${outputTest}`);
|
|
|
131
149
|
const displayHelp = (commands, instance, command) => {
|
|
132
150
|
if (command.name === root_command) return displayAllHelp(commands, instance);
|
|
133
151
|
|
|
134
|
-
const { options, maxLength: maxOptionLength } = generateOptionsOutput(
|
|
152
|
+
const { options, maxLength: maxOptionLength } = generateOptionsOutput(
|
|
153
|
+
command.options,
|
|
154
|
+
);
|
|
135
155
|
const optionsOutput = generateOptionsTextOutput(options, maxOptionLength, 2);
|
|
136
156
|
|
|
137
157
|
const outputTest = [
|
|
@@ -140,9 +160,11 @@ const displayHelp = (commands, instance, command) => {
|
|
|
140
160
|
${optionsOutput}`,
|
|
141
161
|
]
|
|
142
162
|
.filter(Boolean)
|
|
143
|
-
.join(
|
|
163
|
+
.join('\n\n');
|
|
144
164
|
|
|
145
|
-
console.log(`Usage: ${instance.input.name} ${command.name}${
|
|
165
|
+
console.log(`Usage: ${instance.input.name} ${command.name}${
|
|
166
|
+
optionsOutput ? ' [options]' : ''
|
|
167
|
+
}
|
|
146
168
|
${
|
|
147
169
|
command.description &&
|
|
148
170
|
`
|
package/cli/parse-args.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
const parseArgs = (args, type) => {
|
|
2
2
|
if (args == null || !Array.isArray(args)) {
|
|
3
|
-
throw
|
|
3
|
+
throw 'args should be array';
|
|
4
4
|
}
|
|
5
5
|
const argsCopy = args.slice();
|
|
6
6
|
|
|
7
7
|
switch (type) {
|
|
8
|
-
case
|
|
8
|
+
case 'electron': {
|
|
9
9
|
if (process.defaultApp) {
|
|
10
10
|
return argsCopy.slice(2);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
return argsCopy.slice(1);
|
|
14
14
|
}
|
|
15
|
-
case
|
|
15
|
+
case 'user': {
|
|
16
16
|
return argsCopy;
|
|
17
17
|
}
|
|
18
18
|
default: {
|
package/cli/process-option.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const _ = require(
|
|
1
|
+
const _ = require('lodash');
|
|
2
2
|
|
|
3
3
|
const optionFormatters = {
|
|
4
4
|
number: (str) => +str,
|
|
@@ -13,29 +13,36 @@ const processFlags = (flags) => {
|
|
|
13
13
|
let name = null;
|
|
14
14
|
const keys = [];
|
|
15
15
|
let value = null;
|
|
16
|
-
const isNoFlag = flags.includes(
|
|
16
|
+
const isNoFlag = flags.includes('--no-');
|
|
17
17
|
|
|
18
|
-
_.compact(_.split(flags,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
18
|
+
_.compact(_.split(flags, ' ').map((str) => str.replace(/,/g, ''))).forEach(
|
|
19
|
+
(str) => {
|
|
20
|
+
if (str.startsWith('-')) {
|
|
21
|
+
keys.push(str);
|
|
22
|
+
} else if (value === null) {
|
|
23
|
+
if (str.startsWith('{') || str.startsWith('[') || str.startsWith('<')) {
|
|
24
|
+
const rawValue = str.replace(/[{[<>}\].]/g, '');
|
|
25
|
+
const variadic = str.includes('...');
|
|
26
|
+
value = {
|
|
27
|
+
raw: str,
|
|
28
|
+
variadic,
|
|
29
|
+
name: rawValue,
|
|
30
|
+
formatter: optionFormatters[rawValue] || optionFormatters.string,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
31
33
|
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
+
},
|
|
35
|
+
);
|
|
34
36
|
|
|
35
37
|
const longestKey = keys.slice().sort((a, b) => b.length - a.length)[0];
|
|
36
38
|
|
|
37
39
|
if (!_.isEmpty(longestKey)) {
|
|
38
|
-
name = _.camelCase(
|
|
40
|
+
name = _.camelCase(
|
|
41
|
+
(isNoFlag ? longestKey.replace('--no-', '') : longestKey).replace(
|
|
42
|
+
/(--?)/,
|
|
43
|
+
'',
|
|
44
|
+
),
|
|
45
|
+
);
|
|
39
46
|
}
|
|
40
47
|
|
|
41
48
|
return {
|
|
@@ -51,16 +58,17 @@ const processOption = (option) => {
|
|
|
51
58
|
const processedFlags = processFlags(option.flags);
|
|
52
59
|
|
|
53
60
|
if (!processedFlags.name) {
|
|
54
|
-
console.warn(
|
|
61
|
+
console.warn('invalid option', option);
|
|
55
62
|
return null;
|
|
56
63
|
}
|
|
57
64
|
|
|
58
65
|
return {
|
|
59
66
|
required: !!option.required,
|
|
60
|
-
description: `${option.description ||
|
|
67
|
+
description: `${option.description || ''}`,
|
|
61
68
|
default: option.default,
|
|
62
69
|
flags: processedFlags,
|
|
63
70
|
operation: option.operation,
|
|
71
|
+
internal: option.internal,
|
|
64
72
|
};
|
|
65
73
|
};
|
|
66
74
|
|