swagger-typescript-api 11.0.0--alpha-1 → 11.0.0--alpha-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.
@@ -0,0 +1,10 @@
1
+ const root_command = Symbol("root");
2
+ const skip_command = Symbol("skip");
3
+
4
+ const reservedOptions = ["version", "help"];
5
+
6
+ module.exports = {
7
+ root_command,
8
+ skip_command,
9
+ reservedOptions,
10
+ };
package/cli/execute.js ADDED
@@ -0,0 +1,136 @@
1
+ const _ = require("lodash");
2
+ const { root_command, skip_command } = require("./constants");
3
+ const { parseArgs } = require("./parse-args");
4
+ const didyoumean = require("didyoumean");
5
+
6
+ const execute = (params, commands, instance) => {
7
+ const args = parseArgs(params.args, params.from);
8
+
9
+ return new Promise((resolve, reject) => {
10
+ const { command, usageOptions, error } = processArgs(commands, args);
11
+
12
+ if (error) {
13
+ reject(new Error(error));
14
+ }
15
+
16
+ if (!usageOptions.length && command.name === root_command) {
17
+ usageOptions.push(command.options.find((option) => option.flags.name === "help"));
18
+ }
19
+
20
+ const operationOptions = usageOptions.filter((option) => option.operation);
21
+ if (operationOptions.length) {
22
+ operationOptions[0].operation();
23
+ resolve({
24
+ command: skip_command,
25
+ options: {},
26
+ });
27
+ return;
28
+ } else {
29
+ let error = "";
30
+
31
+ const processUserOptionData = (data, option) => {
32
+ if (!data.length && !option.flags.value) {
33
+ return !option.flags.isNoFlag;
34
+ }
35
+ if (option.flags.value) {
36
+ if (option.flags.value.variadic) {
37
+ return data.reduce((acc, d) => {
38
+ acc.push(...d.split(",").map(option.flags.value.formatter));
39
+ return acc;
40
+ }, []);
41
+ } else {
42
+ return option.flags.value.formatter(data[0] || option.default);
43
+ }
44
+ }
45
+
46
+ return option.default;
47
+ };
48
+
49
+ const parsedOptionsObject = command.options.reduce((acc, option) => {
50
+ if (error) return acc;
51
+
52
+ const userOption = usageOptions.find((o) => o.flags.name === option.flags.name);
53
+
54
+ if (!userOption && option.required) {
55
+ error = `required option '${option.flags.raw}' not specified`;
56
+ return acc;
57
+ }
58
+
59
+ if (userOption) {
60
+ acc[option.flags.name] = processUserOptionData(userOption.$data, option);
61
+ } else {
62
+ acc[option.flags.name] = option.default;
63
+ }
64
+
65
+ return acc;
66
+ }, {});
67
+
68
+ if (error) {
69
+ reject(new Error(error));
70
+ } else {
71
+ resolve({
72
+ command: command.name === root_command ? null : command.name,
73
+ options: parsedOptionsObject,
74
+ });
75
+ }
76
+ }
77
+ });
78
+ };
79
+
80
+ const processArgs = (commands, args) => {
81
+ let command = null;
82
+ let usageOptions = [];
83
+ let walkingOption = null;
84
+ let error = "";
85
+
86
+ let allFlagKeys = [];
87
+
88
+ _.forEach(args, (arg, i) => {
89
+ if (error) return;
90
+
91
+ if (i === 0) {
92
+ command = commands[arg] || commands[root_command];
93
+ allFlagKeys = command.options.reduce((acc, option) => [...acc, ...option.flags.keys], []);
94
+ }
95
+ if (arg.startsWith("-")) {
96
+ const option = command.options.find((option) => option.flags.keys.includes(arg));
97
+
98
+ if (!option) {
99
+ error = `unknown option ${arg}\n(Did you mean ${didyoumean(arg, allFlagKeys)} ?)`;
100
+ }
101
+
102
+ if (option) {
103
+ if (walkingOption && walkingOption.flags.name === option.flags.name) {
104
+ return;
105
+ }
106
+ const existedOption = usageOptions.find((o) => o.flags.name === option.flags.name);
107
+ if (existedOption) {
108
+ walkingOption = existedOption;
109
+ } else {
110
+ walkingOption = {
111
+ ...option,
112
+ $data: [],
113
+ };
114
+ usageOptions.push(walkingOption);
115
+ }
116
+ }
117
+
118
+ return;
119
+ }
120
+
121
+ if (walkingOption) {
122
+ walkingOption.$data.push(arg);
123
+ }
124
+ });
125
+ command = command || commands[root_command];
126
+
127
+ return {
128
+ command,
129
+ usageOptions,
130
+ error,
131
+ };
132
+ };
133
+
134
+ module.exports = {
135
+ execute,
136
+ };
package/cli/index.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ import { skip_command } from "./constants";
2
+
3
+ type CliStructOption = {
4
+ flags?: string;
5
+ description?: string;
6
+ default?: unknown;
7
+ };
8
+
9
+ type CliStruct = {
10
+ inherited?: string | null;
11
+ name?: string;
12
+ alias?: string;
13
+ version?: string;
14
+ description?: string;
15
+ options: CliStructOption[];
16
+ commands?: CliStruct[];
17
+ };
18
+
19
+ type ExecuteOptions = {
20
+ args: string[];
21
+ };
22
+
23
+ type ExecuteOutput = {
24
+ command: null | string;
25
+ options: Record<string, any>;
26
+ };
27
+
28
+ type CliInstance = {
29
+ addCommand: (struct: CliStruct) => CliInstance;
30
+ execute: (options: ExecuteOptions) => Promise<ExecuteOutput>;
31
+ };
32
+
33
+ type Cli = <S extends Omit<CliStruct, "inherited">>(struct: S) => CliInstance;
34
+
35
+ export declare const cli: Cli;
package/cli/index.js ADDED
@@ -0,0 +1,69 @@
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
+
8
+ const cli = (input) => {
9
+ const commands = {};
10
+
11
+ const addCommand = (command) => {
12
+ commands[command.name] = {
13
+ name: command.name,
14
+ description: `${command.description || ""}`,
15
+ options: _.compact(_.map(command.options, processOption)),
16
+ };
17
+
18
+ return instance;
19
+ };
20
+
21
+ const instance = {
22
+ commands,
23
+ input,
24
+ addCommand,
25
+ execute: (params) => execute(params, commands, instance),
26
+ };
27
+
28
+ addCommand({
29
+ name: root_command,
30
+ options: [],
31
+ });
32
+
33
+ _.forEach(input.options, (option) => {
34
+ const processed = processOption(option);
35
+
36
+ if (!processed) return;
37
+
38
+ if (reservedOptions.includes(processed.name)) {
39
+ console.warn("reserved option", processed.name);
40
+ return;
41
+ }
42
+
43
+ commands[root_command].options.push(processed);
44
+ });
45
+
46
+ commands[root_command].options.unshift(
47
+ processOption({
48
+ flags: "-v, --version",
49
+ description: "output the current version",
50
+ operation: () => displayVersion(instance),
51
+ }),
52
+ );
53
+
54
+ commands[root_command].options.push(
55
+ processOption({
56
+ flags: "-h, --help",
57
+ description: "display help for command",
58
+ operation: () => displayHelp(commands, instance),
59
+ }),
60
+ );
61
+
62
+ _.forEach(input.commands, addCommand);
63
+
64
+ return instance;
65
+ };
66
+
67
+ module.exports = {
68
+ cli,
69
+ };
@@ -0,0 +1,133 @@
1
+ const _ = require("lodash");
2
+ const { root_command } = require("../constants");
3
+
4
+ const displayHelp = (commands, instance) => {
5
+ const generateOptionsOutput = (options) =>
6
+ options.reduce(
7
+ (acc, option) => {
8
+ const flags = `${option.flags.keys.join(", ")}${option.flags.value?.raw ? ` ${option.flags.value?.raw}` : ""}`;
9
+ const description = `${option.description || ""}${
10
+ option.default === undefined || (option.flags.isNoFlag && option.default === true)
11
+ ? ""
12
+ : ` (default: ${typeof option.default === "string" ? `"${option.default}"` : option.default})`
13
+ }`;
14
+
15
+ if (flags.length > acc.maxLength) {
16
+ acc.maxLength = flags.length;
17
+ }
18
+
19
+ acc.options.push({
20
+ flags,
21
+ description,
22
+ });
23
+ return acc;
24
+ },
25
+ {
26
+ options: [],
27
+ maxLength: 0,
28
+ },
29
+ );
30
+
31
+ const { options, maxLength: maxOptionLength } = generateOptionsOutput(commands[root_command].options);
32
+
33
+ const { commands: commandLabels, maxLength: maxCommandLength } = _.filter(
34
+ commands,
35
+ (command) => command.name !== root_command,
36
+ ).reduce(
37
+ (acc, command) => {
38
+ const options = generateOptionsOutput(command.options);
39
+ const name = `${command.name}${options.length ? " [options]" : ""}`;
40
+ const description = command.description;
41
+
42
+ const maxLength = Math.max(name.length, options.maxLength);
43
+ if (maxLength > acc.maxLength) {
44
+ acc.maxLength = maxLength;
45
+ }
46
+
47
+ acc.commands.push({
48
+ description,
49
+ name,
50
+ options,
51
+ });
52
+ return acc;
53
+ },
54
+ {
55
+ commands: [],
56
+ maxLength: maxOptionLength,
57
+ },
58
+ );
59
+
60
+ const generateOptionsTextOutput = (options, maxLength, spaces) =>
61
+ options
62
+ .map((option) => {
63
+ const spacesText = Array(spaces).fill(" ").join("");
64
+ const leftStr = `${spacesText}${option.flags.padEnd(maxLength, " ")} `;
65
+ const leftStrFiller = Array(leftStr.length).fill(" ").join("");
66
+ const descriptionLines = option.description.split("\n");
67
+
68
+ return (
69
+ leftStr +
70
+ descriptionLines
71
+ .map((line, i) => {
72
+ if (i === 0) {
73
+ return line;
74
+ }
75
+
76
+ return `\n${leftStrFiller}${line}`;
77
+ })
78
+ .join("")
79
+ );
80
+ })
81
+ .join("\n");
82
+
83
+ const optionsOutput = generateOptionsTextOutput(options, maxOptionLength, 2);
84
+
85
+ const commandsOutput = commandLabels
86
+ .map((commandLabel) => {
87
+ const leftStr = ` ${commandLabel.name.padEnd(maxCommandLength, " ")} `;
88
+ const leftStrFiller = Array(leftStr.length).fill(" ").join("");
89
+ const descriptionLines = commandLabel.description.split("\n");
90
+ const optionsTextOutput = generateOptionsTextOutput(commandLabel.options.options, maxCommandLength, 4);
91
+
92
+ return (
93
+ leftStr +
94
+ descriptionLines
95
+ .map((line, i) => {
96
+ if (i === 0) {
97
+ return line;
98
+ }
99
+
100
+ return `\n${leftStrFiller}${line}`;
101
+ })
102
+ .join("") +
103
+ (optionsTextOutput.length ? `\n${optionsTextOutput}` : "")
104
+ );
105
+ })
106
+ .join("\n");
107
+
108
+ const outputTest = [
109
+ optionsOutput &&
110
+ `Options:
111
+ ${optionsOutput}`,
112
+ commandsOutput &&
113
+ `Commands:
114
+ ${commandsOutput}`,
115
+ ]
116
+ .filter(Boolean)
117
+ .join("\n\n");
118
+
119
+ console.log(`Usage: ${[instance.input.name, instance.input.alias].filter(Boolean).join("|")}${
120
+ optionsOutput ? " [options]" : ""
121
+ }${commandsOutput ? " [command]" : ""}
122
+ ${
123
+ instance.input.description &&
124
+ `
125
+ ${instance.input.description}`
126
+ }
127
+
128
+ ${outputTest}`);
129
+ };
130
+
131
+ module.exports = {
132
+ displayHelp,
133
+ };
@@ -0,0 +1,5 @@
1
+ const displayVersion = (instance) => {
2
+ console.log(instance.input.version);
3
+ };
4
+
5
+ module.exports = { displayVersion };
@@ -0,0 +1,26 @@
1
+ const parseArgs = (args, type) => {
2
+ if (args == null || !Array.isArray(args)) {
3
+ throw "args should be array";
4
+ }
5
+ const argsCopy = args.slice();
6
+
7
+ switch (type) {
8
+ case "electron": {
9
+ if (process.defaultApp) {
10
+ return argsCopy.slice(2);
11
+ }
12
+
13
+ return argsCopy.slice(1);
14
+ }
15
+ case "user": {
16
+ return argsCopy;
17
+ }
18
+ default: {
19
+ return argsCopy.slice(2);
20
+ }
21
+ }
22
+ };
23
+
24
+ module.exports = {
25
+ parseArgs,
26
+ };
@@ -0,0 +1,69 @@
1
+ const _ = require("lodash");
2
+
3
+ const optionFormatters = {
4
+ number: (str) => +str,
5
+ numeric: (str) => +str,
6
+ str: (str) => `${str}`,
7
+ string: (str) => `${str}`,
8
+ bool: (str) => !!str,
9
+ boolean: (str) => !!str,
10
+ };
11
+
12
+ const processFlags = (flags) => {
13
+ let name = null;
14
+ const keys = [];
15
+ let value = null;
16
+ const isNoFlag = flags.includes("--no-");
17
+
18
+ _.compact(_.split(flags, " ").map((str) => str.replace(/\,/g, ""))).forEach((str) => {
19
+ if (str.startsWith("-")) {
20
+ keys.push(str);
21
+ } else if (value === null) {
22
+ if (str.startsWith("{") || str.startsWith("[") || str.startsWith("<")) {
23
+ const rawValue = str.replace(/[\{\[\<\>\}\]\.]/g, "");
24
+ const variadic = str.includes("...");
25
+ value = {
26
+ raw: str,
27
+ variadic,
28
+ name: rawValue,
29
+ formatter: optionFormatters[rawValue] || optionFormatters.string,
30
+ };
31
+ }
32
+ }
33
+ });
34
+
35
+ const longestKey = keys.slice().sort((a, b) => b.length - a.length)[0];
36
+
37
+ if (!_.isEmpty(longestKey)) {
38
+ name = _.camelCase((isNoFlag ? longestKey.replace("--no-", "") : longestKey).replace(/(--?)/, ""));
39
+ }
40
+
41
+ return {
42
+ isNoFlag,
43
+ raw: flags,
44
+ name,
45
+ keys,
46
+ value,
47
+ };
48
+ };
49
+
50
+ const processOption = (option) => {
51
+ const processedFlags = processFlags(option.flags);
52
+
53
+ if (!processedFlags.name) {
54
+ console.warn("invalid option", option);
55
+ return null;
56
+ }
57
+
58
+ return {
59
+ required: !!option.required,
60
+ description: `${option.description || ""}`,
61
+ default: option.default,
62
+ flags: processedFlags,
63
+ operation: option.operation,
64
+ };
65
+ };
66
+
67
+ module.exports = {
68
+ processOption,
69
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swagger-typescript-api",
3
- "version": "11.0.0--alpha-1",
3
+ "version": "11.0.0--alpha-2",
4
4
  "description": "Generate typescript/javascript api from swagger schema",
5
5
  "scripts": {
6
6
  "cli:json": "node index.js -r -d -p ./swagger-test-cli.json -n swagger-test-cli.ts",
@@ -108,6 +108,7 @@
108
108
  "index.js",
109
109
  "index.d.ts",
110
110
  "templates",
111
+ "cli",
111
112
  "LICENSE"
112
113
  ],
113
114
  "bugs": {