specli 0.0.5 → 0.0.8
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/bin/specli.js +19 -0
- package/cli.ts +13 -4
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +2331 -0
- package/dist/cli.js.map +53 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2032 -0
- package/dist/index.js.map +48 -0
- package/dist/src/ai/tools.d.ts +139 -0
- package/dist/src/ai/tools.d.ts.map +1 -0
- package/dist/src/ai/tools.js +1656 -0
- package/dist/src/ai/tools.js.map +45 -0
- package/dist/src/cli/auth-requirements.d.ts +10 -0
- package/dist/src/cli/auth-requirements.d.ts.map +1 -0
- package/dist/src/cli/auth-requirements.js +66 -0
- package/dist/src/cli/auth-requirements.js.map +10 -0
- package/dist/src/cli/auth-schemes.d.ts +22 -0
- package/dist/src/cli/auth-schemes.d.ts.map +1 -0
- package/dist/src/cli/auth-schemes.js +116 -0
- package/dist/src/cli/auth-schemes.js.map +11 -0
- package/dist/src/cli/capabilities.d.ts +32 -0
- package/dist/src/cli/capabilities.d.ts.map +1 -0
- package/dist/src/cli/capabilities.js +45 -0
- package/dist/src/cli/capabilities.js.map +10 -0
- package/dist/src/cli/command-id.d.ts +8 -0
- package/dist/src/cli/command-id.d.ts.map +1 -0
- package/dist/src/cli/command-id.js +18 -0
- package/dist/src/cli/command-id.js.map +11 -0
- package/dist/src/cli/command-index.d.ts +6 -0
- package/dist/src/cli/command-index.d.ts.map +1 -0
- package/dist/src/cli/command-index.js +15 -0
- package/dist/src/cli/command-index.js.map +10 -0
- package/dist/src/cli/command-model.d.ts +40 -0
- package/dist/src/cli/command-model.d.ts.map +1 -0
- package/dist/src/cli/command-model.js +274 -0
- package/dist/src/cli/command-model.js.map +18 -0
- package/dist/src/cli/compile.d.ts +15 -0
- package/dist/src/cli/compile.d.ts.map +1 -0
- package/dist/src/cli/compile.js +146 -0
- package/dist/src/cli/compile.js.map +11 -0
- package/dist/src/cli/crypto.d.ts +2 -0
- package/dist/src/cli/crypto.d.ts.map +1 -0
- package/dist/src/cli/crypto.js +15 -0
- package/dist/src/cli/crypto.js.map +10 -0
- package/dist/src/cli/derive-name.d.ts +9 -0
- package/dist/src/cli/derive-name.d.ts.map +1 -0
- package/dist/src/cli/derive-name.js +70 -0
- package/dist/src/cli/derive-name.js.map +10 -0
- package/dist/src/cli/exec.d.ts +14 -0
- package/dist/src/cli/exec.d.ts.map +1 -0
- package/dist/src/cli/exec.js +2077 -0
- package/dist/src/cli/exec.js.map +49 -0
- package/dist/src/cli/main.d.ts +10 -0
- package/dist/src/cli/main.d.ts.map +1 -0
- package/dist/src/cli/main.js +2032 -0
- package/dist/src/cli/main.js.map +48 -0
- package/dist/src/cli/naming.d.ts +12 -0
- package/dist/src/cli/naming.d.ts.map +1 -0
- package/dist/src/cli/naming.js +216 -0
- package/dist/src/cli/naming.js.map +12 -0
- package/dist/src/cli/operations.d.ts +3 -0
- package/dist/src/cli/operations.d.ts.map +1 -0
- package/dist/src/cli/operations.js +103 -0
- package/dist/src/cli/operations.js.map +10 -0
- package/dist/src/cli/params.d.ts +19 -0
- package/dist/src/cli/params.d.ts.map +1 -0
- package/dist/src/cli/params.js +79 -0
- package/dist/src/cli/params.js.map +12 -0
- package/dist/src/cli/pluralize.d.ts +2 -0
- package/dist/src/cli/pluralize.d.ts.map +1 -0
- package/dist/src/cli/pluralize.js +43 -0
- package/dist/src/cli/pluralize.js.map +10 -0
- package/dist/src/cli/positional.d.ts +19 -0
- package/dist/src/cli/positional.d.ts.map +1 -0
- package/dist/src/cli/positional.js +39 -0
- package/dist/src/cli/positional.js.map +10 -0
- package/dist/src/cli/request-body.d.ts +20 -0
- package/dist/src/cli/request-body.d.ts.map +1 -0
- package/dist/src/cli/request-body.js +82 -0
- package/dist/src/cli/request-body.js.map +12 -0
- package/dist/src/cli/runtime/argv.d.ts +3 -0
- package/dist/src/cli/runtime/argv.d.ts.map +1 -0
- package/dist/src/cli/runtime/argv.js +22 -0
- package/dist/src/cli/runtime/argv.js.map +10 -0
- package/dist/src/cli/runtime/auth/resolve.d.ts +9 -0
- package/dist/src/cli/runtime/auth/resolve.d.ts.map +1 -0
- package/dist/src/cli/runtime/auth/resolve.js +38 -0
- package/dist/src/cli/runtime/auth/resolve.js.map +10 -0
- package/dist/src/cli/runtime/body-flags.d.ts +41 -0
- package/dist/src/cli/runtime/body-flags.d.ts.map +1 -0
- package/dist/src/cli/runtime/body-flags.js +86 -0
- package/dist/src/cli/runtime/body-flags.js.map +10 -0
- package/dist/src/cli/runtime/body.d.ts +15 -0
- package/dist/src/cli/runtime/body.d.ts.map +1 -0
- package/dist/src/cli/runtime/body.js +40 -0
- package/dist/src/cli/runtime/body.js.map +11 -0
- package/dist/src/cli/runtime/collect.d.ts +2 -0
- package/dist/src/cli/runtime/collect.d.ts.map +1 -0
- package/dist/src/cli/runtime/collect.js +9 -0
- package/dist/src/cli/runtime/collect.js.map +10 -0
- package/dist/src/cli/runtime/compat.d.ts +35 -0
- package/dist/src/cli/runtime/compat.d.ts.map +1 -0
- package/dist/src/cli/runtime/compat.js +62 -0
- package/dist/src/cli/runtime/compat.js.map +10 -0
- package/dist/src/cli/runtime/context.d.ts +16 -0
- package/dist/src/cli/runtime/context.d.ts.map +1 -0
- package/dist/src/cli/runtime/context.js +936 -0
- package/dist/src/cli/runtime/context.js.map +32 -0
- package/dist/src/cli/runtime/execute.d.ts +33 -0
- package/dist/src/cli/runtime/execute.d.ts.map +1 -0
- package/dist/src/cli/runtime/execute.js +670 -0
- package/dist/src/cli/runtime/execute.js.map +22 -0
- package/dist/src/cli/runtime/generated.d.ts +14 -0
- package/dist/src/cli/runtime/generated.d.ts.map +1 -0
- package/dist/src/cli/runtime/generated.js +869 -0
- package/dist/src/cli/runtime/generated.js.map +23 -0
- package/dist/src/cli/runtime/headers.d.ts +9 -0
- package/dist/src/cli/runtime/headers.d.ts.map +1 -0
- package/dist/src/cli/runtime/headers.js +36 -0
- package/dist/src/cli/runtime/headers.js.map +10 -0
- package/dist/src/cli/runtime/index.d.ts +4 -0
- package/dist/src/cli/runtime/index.d.ts.map +1 -0
- package/dist/src/cli/runtime/index.js +1808 -0
- package/dist/src/cli/runtime/index.js.map +46 -0
- package/dist/src/cli/runtime/profile/secrets.d.ts +25 -0
- package/dist/src/cli/runtime/profile/secrets.d.ts.map +1 -0
- package/dist/src/cli/runtime/profile/secrets.js +51 -0
- package/dist/src/cli/runtime/profile/secrets.js.map +11 -0
- package/dist/src/cli/runtime/profile/store.d.ts +15 -0
- package/dist/src/cli/runtime/profile/store.d.ts.map +1 -0
- package/dist/src/cli/runtime/profile/store.js +102 -0
- package/dist/src/cli/runtime/profile/store.js.map +11 -0
- package/dist/src/cli/runtime/request.d.ts +36 -0
- package/dist/src/cli/runtime/request.d.ts.map +1 -0
- package/dist/src/cli/runtime/request.js +571 -0
- package/dist/src/cli/runtime/request.js.map +21 -0
- package/dist/src/cli/runtime/server-url.d.ts +8 -0
- package/dist/src/cli/runtime/server-url.d.ts.map +1 -0
- package/dist/src/cli/runtime/server-url.js +55 -0
- package/dist/src/cli/runtime/server-url.js.map +11 -0
- package/dist/src/cli/runtime/template.d.ts +5 -0
- package/dist/src/cli/runtime/template.d.ts.map +1 -0
- package/dist/src/cli/runtime/template.js +29 -0
- package/dist/src/cli/runtime/template.js.map +10 -0
- package/dist/src/cli/runtime/validate/ajv.d.ts +3 -0
- package/dist/src/cli/runtime/validate/ajv.d.ts.map +1 -0
- package/dist/src/cli/runtime/validate/ajv.js +17 -0
- package/dist/src/cli/runtime/validate/ajv.js.map +10 -0
- package/dist/src/cli/runtime/validate/coerce.d.ts +4 -0
- package/dist/src/cli/runtime/validate/coerce.d.ts.map +1 -0
- package/dist/src/cli/runtime/validate/coerce.js +60 -0
- package/dist/src/cli/runtime/validate/coerce.js.map +10 -0
- package/dist/src/cli/runtime/validate/error.d.ts +3 -0
- package/dist/src/cli/runtime/validate/error.d.ts.map +1 -0
- package/dist/src/cli/runtime/validate/error.js +21 -0
- package/dist/src/cli/runtime/validate/error.js.map +10 -0
- package/dist/src/cli/runtime/validate/index.d.ts +5 -0
- package/dist/src/cli/runtime/validate/index.d.ts.map +1 -0
- package/dist/src/cli/runtime/validate/index.js +122 -0
- package/dist/src/cli/runtime/validate/index.js.map +13 -0
- package/dist/src/cli/runtime/validate/schema.d.ts +9 -0
- package/dist/src/cli/runtime/validate/schema.d.ts.map +1 -0
- package/dist/src/cli/runtime/validate/schema.js +36 -0
- package/dist/src/cli/runtime/validate/schema.js.map +10 -0
- package/dist/src/cli/schema-shape.d.ts +5 -0
- package/dist/src/cli/schema-shape.d.ts.map +1 -0
- package/dist/src/cli/schema-shape.js +41 -0
- package/dist/src/cli/schema-shape.js.map +10 -0
- package/dist/src/cli/schema.d.ts +30 -0
- package/dist/src/cli/schema.d.ts.map +1 -0
- package/dist/src/cli/schema.js +38 -0
- package/dist/src/cli/schema.js.map +10 -0
- package/dist/src/cli/server.d.ts +16 -0
- package/dist/src/cli/server.d.ts.map +1 -0
- package/dist/src/cli/server.js +64 -0
- package/dist/src/cli/server.js.map +11 -0
- package/dist/src/cli/spec-id.d.ts +3 -0
- package/dist/src/cli/spec-id.d.ts.map +1 -0
- package/dist/src/cli/spec-id.js +21 -0
- package/dist/src/cli/spec-id.js.map +11 -0
- package/dist/src/cli/spec-loader.d.ts +7 -0
- package/dist/src/cli/spec-loader.d.ts.map +1 -0
- package/dist/src/cli/spec-loader.js +110 -0
- package/dist/src/cli/spec-loader.js.map +15 -0
- package/dist/src/cli/stable-json.d.ts +4 -0
- package/dist/src/cli/stable-json.d.ts.map +1 -0
- package/dist/src/cli/stable-json.js +35 -0
- package/dist/src/cli/stable-json.js.map +10 -0
- package/dist/src/cli/strings.d.ts +3 -0
- package/dist/src/cli/strings.d.ts.map +1 -0
- package/dist/src/cli/strings.js +16 -0
- package/dist/src/cli/strings.js.map +10 -0
- package/dist/src/cli/types.d.ts +53 -0
- package/dist/src/cli/types.d.ts.map +1 -0
- package/dist/src/cli/types.js +9 -0
- package/dist/src/cli/types.js.map +10 -0
- package/package.json +32 -4
- package/src/ai/tools.ts +211 -0
- package/src/cli/main.ts +3 -2
- package/src/cli/runtime/body.ts +3 -3
- package/src/cli/runtime/compat.ts +89 -0
- package/src/cli/runtime/execute.ts +98 -39
- package/src/cli/runtime/generated.ts +111 -4
- package/src/cli/runtime/profile/secrets.ts +42 -1
- package/src/cli/runtime/profile/store.ts +15 -13
- package/src/cli/runtime/request.ts +12 -4
- package/src/cli/spec-loader.ts +2 -2
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
// src/cli/pluralize.ts
|
|
2
|
+
var IRREGULAR = {
|
|
3
|
+
person: "people",
|
|
4
|
+
man: "men",
|
|
5
|
+
woman: "women",
|
|
6
|
+
child: "children",
|
|
7
|
+
tooth: "teeth",
|
|
8
|
+
foot: "feet",
|
|
9
|
+
mouse: "mice",
|
|
10
|
+
goose: "geese"
|
|
11
|
+
};
|
|
12
|
+
var UNCOUNTABLE = new Set([
|
|
13
|
+
"metadata",
|
|
14
|
+
"information",
|
|
15
|
+
"equipment",
|
|
16
|
+
"money",
|
|
17
|
+
"series",
|
|
18
|
+
"species"
|
|
19
|
+
]);
|
|
20
|
+
function pluralize(word) {
|
|
21
|
+
const w = word.trim();
|
|
22
|
+
if (!w)
|
|
23
|
+
return w;
|
|
24
|
+
const lower = w.toLowerCase();
|
|
25
|
+
if (UNCOUNTABLE.has(lower))
|
|
26
|
+
return lower;
|
|
27
|
+
if (IRREGULAR[lower])
|
|
28
|
+
return IRREGULAR[lower];
|
|
29
|
+
if (lower.endsWith("s"))
|
|
30
|
+
return lower;
|
|
31
|
+
if (/[bcdfghjklmnpqrstvwxyz]y$/.test(lower)) {
|
|
32
|
+
return lower.replace(/y$/, "ies");
|
|
33
|
+
}
|
|
34
|
+
if (/(ch|sh|x|z)$/.test(lower)) {
|
|
35
|
+
return `${lower}es`;
|
|
36
|
+
}
|
|
37
|
+
return `${lower}s`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// src/cli/strings.ts
|
|
41
|
+
function kebabCase(input) {
|
|
42
|
+
const trimmed = input.trim();
|
|
43
|
+
if (!trimmed)
|
|
44
|
+
return "";
|
|
45
|
+
return trimmed.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[\s_.:/]+/g, "-").replace(/[^a-zA-Z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").toLowerCase();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/cli/naming.ts
|
|
49
|
+
var GENERIC_TAGS = new Set(["default", "defaults", "api"]);
|
|
50
|
+
function getPathSegments(path) {
|
|
51
|
+
return path.split("/").map((s) => s.trim()).filter(Boolean);
|
|
52
|
+
}
|
|
53
|
+
function getPathArgs(path) {
|
|
54
|
+
const args = [];
|
|
55
|
+
const re = /\{([^}]+)\}/g;
|
|
56
|
+
while (true) {
|
|
57
|
+
const match = re.exec(path);
|
|
58
|
+
if (!match)
|
|
59
|
+
break;
|
|
60
|
+
args.push(match[1]);
|
|
61
|
+
}
|
|
62
|
+
return args;
|
|
63
|
+
}
|
|
64
|
+
function pickResourceFromTags(tags) {
|
|
65
|
+
if (!tags.length)
|
|
66
|
+
return;
|
|
67
|
+
const first = tags[0]?.trim();
|
|
68
|
+
if (!first)
|
|
69
|
+
return;
|
|
70
|
+
if (GENERIC_TAGS.has(first.toLowerCase()))
|
|
71
|
+
return;
|
|
72
|
+
return first;
|
|
73
|
+
}
|
|
74
|
+
function splitOperationId(operationId) {
|
|
75
|
+
const trimmed = operationId.trim();
|
|
76
|
+
if (!trimmed)
|
|
77
|
+
return {};
|
|
78
|
+
if (trimmed.includes(".")) {
|
|
79
|
+
const [prefix, ...rest] = trimmed.split(".");
|
|
80
|
+
return { prefix, suffix: rest.join(".") };
|
|
81
|
+
}
|
|
82
|
+
if (trimmed.includes("__")) {
|
|
83
|
+
const [prefix, ...rest] = trimmed.split("__");
|
|
84
|
+
return { prefix, suffix: rest.join("__") };
|
|
85
|
+
}
|
|
86
|
+
if (trimmed.includes("_")) {
|
|
87
|
+
const [prefix, ...rest] = trimmed.split("_");
|
|
88
|
+
return { prefix, suffix: rest.join("_") };
|
|
89
|
+
}
|
|
90
|
+
return { suffix: trimmed };
|
|
91
|
+
}
|
|
92
|
+
function inferStyle(op) {
|
|
93
|
+
if (op.path.includes("."))
|
|
94
|
+
return "rpc";
|
|
95
|
+
if (op.operationId?.includes(".") && op.method === "POST")
|
|
96
|
+
return "rpc";
|
|
97
|
+
return "rest";
|
|
98
|
+
}
|
|
99
|
+
function inferResource(op) {
|
|
100
|
+
const tag = pickResourceFromTags(op.tags);
|
|
101
|
+
if (tag)
|
|
102
|
+
return pluralize(kebabCase(tag));
|
|
103
|
+
if (op.operationId) {
|
|
104
|
+
const { prefix } = splitOperationId(op.operationId);
|
|
105
|
+
if (prefix) {
|
|
106
|
+
const fromId = kebabCase(prefix);
|
|
107
|
+
if (fromId === "ping")
|
|
108
|
+
return "ping";
|
|
109
|
+
return pluralize(fromId);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const segments = getPathSegments(op.path);
|
|
113
|
+
let first = segments[0] ?? "api";
|
|
114
|
+
first = first.includes(".") ? first.split(".")[0] : first;
|
|
115
|
+
if (first.toLowerCase() === "ping")
|
|
116
|
+
return "ping";
|
|
117
|
+
const cleaned = first.replace(/^\{.+\}$/, "");
|
|
118
|
+
return pluralize(kebabCase(cleaned || "api"));
|
|
119
|
+
}
|
|
120
|
+
function canonicalizeAction(action) {
|
|
121
|
+
const a = kebabCase(action);
|
|
122
|
+
if (a === "retrieve" || a === "read")
|
|
123
|
+
return "get";
|
|
124
|
+
if (a === "list" || a === "search")
|
|
125
|
+
return "list";
|
|
126
|
+
if (a === "create")
|
|
127
|
+
return "create";
|
|
128
|
+
if (a === "update" || a === "patch")
|
|
129
|
+
return "update";
|
|
130
|
+
if (a === "delete" || a === "remove")
|
|
131
|
+
return "delete";
|
|
132
|
+
return a;
|
|
133
|
+
}
|
|
134
|
+
function inferRestAction(op) {
|
|
135
|
+
if (op.operationId) {
|
|
136
|
+
const { suffix } = splitOperationId(op.operationId);
|
|
137
|
+
if (suffix) {
|
|
138
|
+
const fromId = canonicalizeAction(suffix);
|
|
139
|
+
if (fromId === "get" || fromId === "list" || fromId === "create" || fromId === "update" || fromId === "delete") {
|
|
140
|
+
return fromId;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const method = op.method.toUpperCase();
|
|
145
|
+
const args = getPathArgs(op.path);
|
|
146
|
+
const hasId = args.length > 0;
|
|
147
|
+
if (method === "GET" && !hasId)
|
|
148
|
+
return "list";
|
|
149
|
+
if (method === "POST" && !hasId)
|
|
150
|
+
return "create";
|
|
151
|
+
if (method === "GET" && hasId)
|
|
152
|
+
return "get";
|
|
153
|
+
if ((method === "PUT" || method === "PATCH") && hasId)
|
|
154
|
+
return "update";
|
|
155
|
+
if (method === "DELETE" && hasId)
|
|
156
|
+
return "delete";
|
|
157
|
+
return kebabCase(method);
|
|
158
|
+
}
|
|
159
|
+
function inferRpcAction(op) {
|
|
160
|
+
if (op.operationId) {
|
|
161
|
+
const { suffix } = splitOperationId(op.operationId);
|
|
162
|
+
if (suffix)
|
|
163
|
+
return canonicalizeAction(suffix);
|
|
164
|
+
}
|
|
165
|
+
const segments = getPathSegments(op.path);
|
|
166
|
+
const last = segments[segments.length - 1] ?? "";
|
|
167
|
+
if (last.includes(".")) {
|
|
168
|
+
const part = last.split(".").pop() ?? last;
|
|
169
|
+
return canonicalizeAction(part);
|
|
170
|
+
}
|
|
171
|
+
return kebabCase(op.method);
|
|
172
|
+
}
|
|
173
|
+
function planOperation(op) {
|
|
174
|
+
const style = inferStyle(op);
|
|
175
|
+
const resource = inferResource(op);
|
|
176
|
+
const action = style === "rpc" ? inferRpcAction(op) : inferRestAction(op);
|
|
177
|
+
return {
|
|
178
|
+
...op,
|
|
179
|
+
key: op.key,
|
|
180
|
+
style,
|
|
181
|
+
resource,
|
|
182
|
+
action,
|
|
183
|
+
canonicalAction: action,
|
|
184
|
+
pathArgs: getPathArgs(op.path).map((a) => kebabCase(a))
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function planOperations(ops) {
|
|
188
|
+
const planned = ops.map(planOperation);
|
|
189
|
+
const counts = new Map;
|
|
190
|
+
for (const op of planned) {
|
|
191
|
+
const key = `${op.resource}:${op.action}`;
|
|
192
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
193
|
+
}
|
|
194
|
+
const seen = new Map;
|
|
195
|
+
return planned.map((op) => {
|
|
196
|
+
const key = `${op.resource}:${op.action}`;
|
|
197
|
+
const total = counts.get(key) ?? 0;
|
|
198
|
+
if (total <= 1)
|
|
199
|
+
return op;
|
|
200
|
+
const idx = (seen.get(key) ?? 0) + 1;
|
|
201
|
+
seen.set(key, idx);
|
|
202
|
+
const suffix = op.operationId ? kebabCase(op.operationId) : kebabCase(`${op.method}-${op.path}`);
|
|
203
|
+
const disambiguatedAction = `${op.action}-${suffix}-${idx}`;
|
|
204
|
+
return {
|
|
205
|
+
...op,
|
|
206
|
+
action: disambiguatedAction,
|
|
207
|
+
aliasOf: `${op.resource} ${op.canonicalAction}`
|
|
208
|
+
};
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
export {
|
|
212
|
+
planOperations,
|
|
213
|
+
planOperation
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
//# debugId=99ADFCE0CE9D3B1464756E2164756E21
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/cli/pluralize.ts", "../../../src/cli/strings.ts", "../../../src/cli/naming.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"const IRREGULAR: Record<string, string> = {\n\tperson: \"people\",\n\tman: \"men\",\n\twoman: \"women\",\n\tchild: \"children\",\n\ttooth: \"teeth\",\n\tfoot: \"feet\",\n\tmouse: \"mice\",\n\tgoose: \"geese\",\n};\n\nconst UNCOUNTABLE = new Set([\n\t\"metadata\",\n\t\"information\",\n\t\"equipment\",\n\t\"money\",\n\t\"series\",\n\t\"species\",\n]);\n\nexport function pluralize(word: string): string {\n\tconst w = word.trim();\n\tif (!w) return w;\n\n\tconst lower = w.toLowerCase();\n\tif (UNCOUNTABLE.has(lower)) return lower;\n\tif (IRREGULAR[lower]) return IRREGULAR[lower];\n\n\t// already plural-ish\n\tif (lower.endsWith(\"s\")) return lower;\n\n\tif (/[bcdfghjklmnpqrstvwxyz]y$/.test(lower)) {\n\t\treturn lower.replace(/y$/, \"ies\");\n\t}\n\n\tif (/(ch|sh|x|z)$/.test(lower)) {\n\t\treturn `${lower}es`;\n\t}\n\n\treturn `${lower}s`;\n}\n",
|
|
6
|
+
"export function kebabCase(input: string): string {\n\tconst trimmed = input.trim();\n\tif (!trimmed) return \"\";\n\n\t// Convert spaces/underscores/dots to dashes, split camelCase.\n\treturn trimmed\n\t\t.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n\t\t.replace(/[\\s_.:/]+/g, \"-\")\n\t\t.replace(/[^a-zA-Z0-9-]/g, \"-\")\n\t\t.replace(/-+/g, \"-\")\n\t\t.replace(/^-|-$/g, \"\")\n\t\t.toLowerCase();\n}\n\nexport function titleCase(input: string): string {\n\treturn input\n\t\t.split(/\\s+/g)\n\t\t.filter(Boolean)\n\t\t.map((w) => w[0]?.toUpperCase() + w.slice(1))\n\t\t.join(\" \");\n}\n",
|
|
7
|
+
"import { pluralize } from \"./pluralize.ts\";\nimport { kebabCase } from \"./strings.ts\";\nimport type { NormalizedOperation } from \"./types.ts\";\n\nexport type PlannedOperation = NormalizedOperation & {\n\tresource: string;\n\taction: string;\n\tpathArgs: string[];\n\tstyle: \"rest\" | \"rpc\";\n\tcanonicalAction: string;\n\taliasOf?: string;\n};\n\nconst GENERIC_TAGS = new Set([\"default\", \"defaults\", \"api\"]);\n\nfunction getPathSegments(path: string): string[] {\n\treturn path\n\t\t.split(\"/\")\n\t\t.map((s) => s.trim())\n\t\t.filter(Boolean);\n}\n\nfunction getPathArgs(path: string): string[] {\n\tconst args: string[] = [];\n\tconst re = /\\{([^}]+)\\}/g;\n\n\twhile (true) {\n\t\tconst match = re.exec(path);\n\t\tif (!match) break;\n\t\t// biome-ignore lint/style/noNonNullAssertion: unknown\n\t\targs.push(match[1]!);\n\t}\n\n\treturn args;\n}\n\nfunction pickResourceFromTags(tags: string[]): string | undefined {\n\tif (!tags.length) return undefined;\n\tconst first = tags[0]?.trim();\n\tif (!first) return undefined;\n\tif (GENERIC_TAGS.has(first.toLowerCase())) return undefined;\n\treturn first;\n}\n\nfunction splitOperationId(operationId: string): {\n\tprefix?: string;\n\tsuffix?: string;\n} {\n\tconst trimmed = operationId.trim();\n\tif (!trimmed) return {};\n\n\t// Prefer dot-notation when present: Contacts.List\n\tif (trimmed.includes(\".\")) {\n\t\tconst [prefix, ...rest] = trimmed.split(\".\");\n\t\treturn { prefix, suffix: rest.join(\".\") };\n\t}\n\n\t// Try separators: Contacts_List, Contacts__List\n\tif (trimmed.includes(\"__\")) {\n\t\tconst [prefix, ...rest] = trimmed.split(\"__\");\n\t\treturn { prefix, suffix: rest.join(\"__\") };\n\t}\n\n\tif (trimmed.includes(\"_\")) {\n\t\tconst [prefix, ...rest] = trimmed.split(\"_\");\n\t\treturn { prefix, suffix: rest.join(\"_\") };\n\t}\n\n\treturn { suffix: trimmed };\n}\n\nfunction inferStyle(op: NormalizedOperation): \"rest\" | \"rpc\" {\n\t// Path-based RPC convention (common in gRPC-ish HTTP gateways)\n\t// - POST /Contacts.List\n\t// - POST /Contacts/Service.List\n\tif (op.path.includes(\".\")) return \"rpc\";\n\n\t// operationId dot-notation alone is not enough to call it RPC; many REST APIs\n\t// have dotted ids. We treat dotted operationId as a weak signal.\n\tif (op.operationId?.includes(\".\") && op.method === \"POST\") return \"rpc\";\n\n\treturn \"rest\";\n}\n\nfunction inferResource(op: NormalizedOperation): string {\n\tconst tag = pickResourceFromTags(op.tags);\n\tif (tag) return pluralize(kebabCase(tag));\n\n\tif (op.operationId) {\n\t\tconst { prefix } = splitOperationId(op.operationId);\n\t\tif (prefix) {\n\t\t\tconst fromId = kebabCase(prefix);\n\t\t\tif (fromId === \"ping\") return \"ping\";\n\t\t\treturn pluralize(fromId);\n\t\t}\n\t}\n\n\tconst segments = getPathSegments(op.path);\n\tlet first = segments[0] ?? \"api\";\n\n\t// If first segment is rpc-ish, like Contacts.List, split it.\n\t// biome-ignore lint/style/noNonNullAssertion: split always returns at least one element\n\tfirst = first.includes(\".\") ? first.split(\".\")[0]! : first;\n\n\t// Singletons like /ping generally shouldn't become `pings`.\n\tif (first.toLowerCase() === \"ping\") return \"ping\";\n\n\t// Strip path params if they appear in first segment (rare)\n\tconst cleaned = first.replace(/^\\{.+\\}$/, \"\");\n\treturn pluralize(kebabCase(cleaned || \"api\"));\n}\n\nfunction canonicalizeAction(action: string): string {\n\tconst a = kebabCase(action);\n\n\t// Common RPC verbs -> REST canonical verbs\n\tif (a === \"retrieve\" || a === \"read\") return \"get\";\n\tif (a === \"list\" || a === \"search\") return \"list\";\n\tif (a === \"create\") return \"create\";\n\tif (a === \"update\" || a === \"patch\") return \"update\";\n\tif (a === \"delete\" || a === \"remove\") return \"delete\";\n\n\treturn a;\n}\n\nfunction inferRestAction(op: NormalizedOperation): string {\n\t// If operationId is present and looks intentional, prefer it.\n\t// This helps with singleton endpoints like GET /ping (Ping.Get) vs collections.\n\tif (op.operationId) {\n\t\tconst { suffix } = splitOperationId(op.operationId);\n\t\tif (suffix) {\n\t\t\tconst fromId = canonicalizeAction(suffix);\n\t\t\tif (\n\t\t\t\tfromId === \"get\" ||\n\t\t\t\tfromId === \"list\" ||\n\t\t\t\tfromId === \"create\" ||\n\t\t\t\tfromId === \"update\" ||\n\t\t\t\tfromId === \"delete\"\n\t\t\t) {\n\t\t\t\treturn fromId;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst method = op.method.toUpperCase();\n\tconst args = getPathArgs(op.path);\n\tconst hasId = args.length > 0;\n\n\tif (method === \"GET\" && !hasId) return \"list\";\n\tif (method === \"POST\" && !hasId) return \"create\";\n\n\tif (method === \"GET\" && hasId) return \"get\";\n\tif ((method === \"PUT\" || method === \"PATCH\") && hasId) return \"update\";\n\tif (method === \"DELETE\" && hasId) return \"delete\";\n\n\treturn kebabCase(method);\n}\n\nfunction inferRpcAction(op: NormalizedOperation): string {\n\t// Prefer operationId suffix: Contacts.List -> list\n\tif (op.operationId) {\n\t\tconst { suffix } = splitOperationId(op.operationId);\n\t\tif (suffix) return canonicalizeAction(suffix);\n\t}\n\n\t// Else take last segment and split by '.'\n\tconst segments = getPathSegments(op.path);\n\tconst last = segments[segments.length - 1] ?? \"\";\n\tif (last.includes(\".\")) {\n\t\tconst part = last.split(\".\").pop() ?? last;\n\t\treturn canonicalizeAction(part);\n\t}\n\n\treturn kebabCase(op.method);\n}\n\nexport function planOperation(op: NormalizedOperation): PlannedOperation {\n\tconst style = inferStyle(op);\n\tconst resource = inferResource(op);\n\tconst action = style === \"rpc\" ? inferRpcAction(op) : inferRestAction(op);\n\n\treturn {\n\t\t...op,\n\t\tkey: op.key,\n\t\tstyle,\n\t\tresource,\n\t\taction,\n\t\tcanonicalAction: action,\n\t\tpathArgs: getPathArgs(op.path).map((a) => kebabCase(a)),\n\t};\n}\n\nexport function planOperations(ops: NormalizedOperation[]): PlannedOperation[] {\n\tconst planned = ops.map(planOperation);\n\n\t// Stable collision handling: if resource+action repeats, add a suffix.\n\tconst counts = new Map<string, number>();\n\tfor (const op of planned) {\n\t\tconst key = `${op.resource}:${op.action}`;\n\t\tcounts.set(key, (counts.get(key) ?? 0) + 1);\n\t}\n\n\tconst seen = new Map<string, number>();\n\treturn planned.map((op) => {\n\t\tconst key = `${op.resource}:${op.action}`;\n\t\tconst total = counts.get(key) ?? 0;\n\t\tif (total <= 1) return op;\n\n\t\tconst idx = (seen.get(key) ?? 0) + 1;\n\t\tseen.set(key, idx);\n\n\t\tconst suffix = op.operationId\n\t\t\t? kebabCase(op.operationId)\n\t\t\t: kebabCase(`${op.method}-${op.path}`);\n\n\t\tconst disambiguatedAction = `${op.action}-${suffix}-${idx}`;\n\n\t\treturn {\n\t\t\t...op,\n\t\t\taction: disambiguatedAction,\n\t\t\taliasOf: `${op.resource} ${op.canonicalAction}`,\n\t\t};\n\t});\n}\n"
|
|
8
|
+
],
|
|
9
|
+
"mappings": "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",
|
|
10
|
+
"debugId": "99ADFCE0CE9D3B1464756E2164756E21",
|
|
11
|
+
"names": []
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../../../src/cli/operations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,mBAAmB,EAGnB,UAAU,EACV,MAAM,YAAY,CAAC;AA6GpB,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,mBAAmB,EAAE,CAqCtE"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// src/cli/operations.ts
|
|
2
|
+
function operationKey(method, path) {
|
|
3
|
+
return `${method.toUpperCase()} ${path}`;
|
|
4
|
+
}
|
|
5
|
+
var HTTP_METHODS = [
|
|
6
|
+
"get",
|
|
7
|
+
"post",
|
|
8
|
+
"put",
|
|
9
|
+
"patch",
|
|
10
|
+
"delete",
|
|
11
|
+
"options",
|
|
12
|
+
"head",
|
|
13
|
+
"trace"
|
|
14
|
+
];
|
|
15
|
+
function normalizeParam(p) {
|
|
16
|
+
if (!p || typeof p !== "object")
|
|
17
|
+
return;
|
|
18
|
+
const loc = p.in;
|
|
19
|
+
const name = p.name;
|
|
20
|
+
if (loc !== "path" && loc !== "query" && loc !== "header" && loc !== "cookie") {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (!name)
|
|
24
|
+
return;
|
|
25
|
+
return {
|
|
26
|
+
in: loc,
|
|
27
|
+
name,
|
|
28
|
+
required: Boolean(p.required || loc === "path"),
|
|
29
|
+
description: p.description,
|
|
30
|
+
schema: p.schema
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function mergeParameters(pathParams, opParams) {
|
|
34
|
+
const merged = new Map;
|
|
35
|
+
for (const p of pathParams ?? []) {
|
|
36
|
+
const normalized = normalizeParam(p);
|
|
37
|
+
if (!normalized)
|
|
38
|
+
continue;
|
|
39
|
+
merged.set(`${normalized.in}:${normalized.name}`, normalized);
|
|
40
|
+
}
|
|
41
|
+
for (const p of opParams ?? []) {
|
|
42
|
+
const normalized = normalizeParam(p);
|
|
43
|
+
if (!normalized)
|
|
44
|
+
continue;
|
|
45
|
+
merged.set(`${normalized.in}:${normalized.name}`, normalized);
|
|
46
|
+
}
|
|
47
|
+
return [...merged.values()];
|
|
48
|
+
}
|
|
49
|
+
function normalizeRequestBody(rb) {
|
|
50
|
+
if (!rb)
|
|
51
|
+
return;
|
|
52
|
+
const content = rb.content ?? {};
|
|
53
|
+
const contentTypes = Object.keys(content);
|
|
54
|
+
const schemasByContentType = {};
|
|
55
|
+
for (const contentType of contentTypes) {
|
|
56
|
+
schemasByContentType[contentType] = content[contentType]?.schema;
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
required: Boolean(rb.required),
|
|
60
|
+
contentTypes,
|
|
61
|
+
schemasByContentType
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function indexOperations(doc) {
|
|
65
|
+
const out = [];
|
|
66
|
+
const paths = doc.paths ?? {};
|
|
67
|
+
for (const [path, rawPathItem] of Object.entries(paths)) {
|
|
68
|
+
if (!rawPathItem || typeof rawPathItem !== "object")
|
|
69
|
+
continue;
|
|
70
|
+
const pathItem = rawPathItem;
|
|
71
|
+
for (const method of HTTP_METHODS) {
|
|
72
|
+
const op = pathItem[method];
|
|
73
|
+
if (!op)
|
|
74
|
+
continue;
|
|
75
|
+
const parameters = mergeParameters(pathItem.parameters, op.parameters);
|
|
76
|
+
const normalizedMethod = method.toUpperCase();
|
|
77
|
+
out.push({
|
|
78
|
+
key: operationKey(normalizedMethod, path),
|
|
79
|
+
method: normalizedMethod,
|
|
80
|
+
path,
|
|
81
|
+
operationId: op.operationId,
|
|
82
|
+
tags: op.tags ?? [],
|
|
83
|
+
summary: op.summary,
|
|
84
|
+
description: op.description,
|
|
85
|
+
deprecated: op.deprecated,
|
|
86
|
+
security: op.security ?? doc.security,
|
|
87
|
+
parameters,
|
|
88
|
+
requestBody: normalizeRequestBody(op.requestBody)
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
out.sort((a, b) => {
|
|
93
|
+
if (a.path !== b.path)
|
|
94
|
+
return a.path.localeCompare(b.path);
|
|
95
|
+
return a.method.localeCompare(b.method);
|
|
96
|
+
});
|
|
97
|
+
return out;
|
|
98
|
+
}
|
|
99
|
+
export {
|
|
100
|
+
indexOperations
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
//# debugId=C74131EC8AF45C3D64756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/cli/operations.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type {\n\tNormalizedOperation,\n\tNormalizedParameter,\n\tNormalizedRequestBody,\n\tOpenApiDoc,\n} from \"./types.ts\";\n\nfunction operationKey(method: string, path: string): string {\n\treturn `${method.toUpperCase()} ${path}`;\n}\n\nconst HTTP_METHODS = [\n\t\"get\",\n\t\"post\",\n\t\"put\",\n\t\"patch\",\n\t\"delete\",\n\t\"options\",\n\t\"head\",\n\t\"trace\",\n] as const;\n\ntype RawParameter = {\n\tin?: string;\n\tname?: string;\n\trequired?: boolean;\n\tdescription?: string;\n\tschema?: unknown;\n};\n\ntype RawRequestBody = {\n\trequired?: boolean;\n\tcontent?: Record<string, { schema?: unknown } | undefined>;\n};\n\ntype RawOperation = {\n\toperationId?: string;\n\ttags?: string[];\n\tsummary?: string;\n\tdescription?: string;\n\tdeprecated?: boolean;\n\tsecurity?: OpenApiDoc[\"security\"];\n\tparameters?: RawParameter[];\n\trequestBody?: RawRequestBody;\n};\n\ntype RawPathItem = {\n\tparameters?: RawParameter[];\n} & Partial<Record<(typeof HTTP_METHODS)[number], RawOperation>>;\n\nfunction normalizeParam(p: RawParameter): NormalizedParameter | undefined {\n\tif (!p || typeof p !== \"object\") return undefined;\n\tconst loc = p.in;\n\tconst name = p.name;\n\tif (\n\t\tloc !== \"path\" &&\n\t\tloc !== \"query\" &&\n\t\tloc !== \"header\" &&\n\t\tloc !== \"cookie\"\n\t) {\n\t\treturn undefined;\n\t}\n\tif (!name) return undefined;\n\n\treturn {\n\t\tin: loc,\n\t\tname,\n\t\trequired: Boolean(p.required || loc === \"path\"),\n\t\tdescription: p.description,\n\t\tschema: p.schema,\n\t};\n}\n\nfunction mergeParameters(\n\tpathParams: RawParameter[] | undefined,\n\topParams: RawParameter[] | undefined,\n): NormalizedParameter[] {\n\tconst merged = new Map<string, NormalizedParameter>();\n\n\tfor (const p of pathParams ?? []) {\n\t\tconst normalized = normalizeParam(p);\n\t\tif (!normalized) continue;\n\t\tmerged.set(`${normalized.in}:${normalized.name}`, normalized);\n\t}\n\n\tfor (const p of opParams ?? []) {\n\t\tconst normalized = normalizeParam(p);\n\t\tif (!normalized) continue;\n\t\tmerged.set(`${normalized.in}:${normalized.name}`, normalized);\n\t}\n\n\treturn [...merged.values()];\n}\n\nfunction normalizeRequestBody(\n\trb: RawRequestBody | undefined,\n): NormalizedRequestBody | undefined {\n\tif (!rb) return undefined;\n\n\tconst content = rb.content ?? {};\n\tconst contentTypes = Object.keys(content);\n\tconst schemasByContentType: Record<string, unknown | undefined> = {};\n\n\tfor (const contentType of contentTypes) {\n\t\tschemasByContentType[contentType] = content[contentType]?.schema;\n\t}\n\n\treturn {\n\t\trequired: Boolean(rb.required),\n\t\tcontentTypes,\n\t\tschemasByContentType,\n\t};\n}\n\nexport function indexOperations(doc: OpenApiDoc): NormalizedOperation[] {\n\tconst out: NormalizedOperation[] = [];\n\tconst paths = doc.paths ?? {};\n\n\tfor (const [path, rawPathItem] of Object.entries(paths)) {\n\t\tif (!rawPathItem || typeof rawPathItem !== \"object\") continue;\n\n\t\tconst pathItem = rawPathItem as RawPathItem;\n\n\t\tfor (const method of HTTP_METHODS) {\n\t\t\tconst op = pathItem[method];\n\t\t\tif (!op) continue;\n\n\t\t\tconst parameters = mergeParameters(pathItem.parameters, op.parameters);\n\t\t\tconst normalizedMethod = method.toUpperCase();\n\t\t\tout.push({\n\t\t\t\tkey: operationKey(normalizedMethod, path),\n\t\t\t\tmethod: normalizedMethod,\n\t\t\t\tpath,\n\t\t\t\toperationId: op.operationId,\n\t\t\t\ttags: op.tags ?? [],\n\t\t\t\tsummary: op.summary,\n\t\t\t\tdescription: op.description,\n\t\t\t\tdeprecated: op.deprecated,\n\t\t\t\tsecurity: (op.security ?? doc.security) as OpenApiDoc[\"security\"],\n\t\t\t\tparameters,\n\t\t\t\trequestBody: normalizeRequestBody(op.requestBody),\n\t\t\t});\n\t\t}\n\t}\n\n\tout.sort((a, b) => {\n\t\tif (a.path !== b.path) return a.path.localeCompare(b.path);\n\t\treturn a.method.localeCompare(b.method);\n\t});\n\n\treturn out;\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "C74131EC8AF45C3D64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { NormalizedOperation, NormalizedParameter } from "./types.js";
|
|
2
|
+
export type ParamType = import("./schema-shape.js").ParamType;
|
|
3
|
+
export type ParamSpec = {
|
|
4
|
+
kind: "positional" | "flag";
|
|
5
|
+
in: NormalizedParameter["in"];
|
|
6
|
+
name: string;
|
|
7
|
+
flag: string;
|
|
8
|
+
required: boolean;
|
|
9
|
+
description?: string;
|
|
10
|
+
type: ParamType;
|
|
11
|
+
format?: string;
|
|
12
|
+
enum?: string[];
|
|
13
|
+
itemType?: ParamType;
|
|
14
|
+
itemFormat?: string;
|
|
15
|
+
itemEnum?: string[];
|
|
16
|
+
schema?: import("./types.js").JsonSchema;
|
|
17
|
+
};
|
|
18
|
+
export declare function deriveParamSpecs(op: NormalizedOperation): ParamSpec[];
|
|
19
|
+
//# sourceMappingURL=params.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"params.d.ts","sourceRoot":"","sources":["../../../src/cli/params.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE3E,MAAM,MAAM,SAAS,GAAG,OAAO,mBAAmB,EAAE,SAAS,CAAC;AAE9D,MAAM,MAAM,SAAS,GAAG;IACvB,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC;IAC5B,EAAE,EAAE,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAGhB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAGpB,MAAM,CAAC,EAAE,OAAO,YAAY,EAAE,UAAU,CAAC;CACzC,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,mBAAmB,GAAG,SAAS,EAAE,CAwCrE"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// src/cli/schema-shape.ts
|
|
2
|
+
function getSchemaType(schema) {
|
|
3
|
+
if (!schema || typeof schema !== "object")
|
|
4
|
+
return "unknown";
|
|
5
|
+
const t = schema.type;
|
|
6
|
+
if (t === "string")
|
|
7
|
+
return "string";
|
|
8
|
+
if (t === "number")
|
|
9
|
+
return "number";
|
|
10
|
+
if (t === "integer")
|
|
11
|
+
return "integer";
|
|
12
|
+
if (t === "boolean")
|
|
13
|
+
return "boolean";
|
|
14
|
+
if (t === "array")
|
|
15
|
+
return "array";
|
|
16
|
+
if (t === "object")
|
|
17
|
+
return "object";
|
|
18
|
+
return "unknown";
|
|
19
|
+
}
|
|
20
|
+
function getSchemaFormat(schema) {
|
|
21
|
+
if (!schema || typeof schema !== "object")
|
|
22
|
+
return;
|
|
23
|
+
const f = schema.format;
|
|
24
|
+
return typeof f === "string" ? f : undefined;
|
|
25
|
+
}
|
|
26
|
+
function getSchemaEnumStrings(schema) {
|
|
27
|
+
if (!schema || typeof schema !== "object")
|
|
28
|
+
return;
|
|
29
|
+
const e = schema.enum;
|
|
30
|
+
if (!Array.isArray(e))
|
|
31
|
+
return;
|
|
32
|
+
const values = e.filter((v) => typeof v === "string");
|
|
33
|
+
return values.length ? values : undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/cli/strings.ts
|
|
37
|
+
function kebabCase(input) {
|
|
38
|
+
const trimmed = input.trim();
|
|
39
|
+
if (!trimmed)
|
|
40
|
+
return "";
|
|
41
|
+
return trimmed.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[\s_.:/]+/g, "-").replace(/[^a-zA-Z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").toLowerCase();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/cli/params.ts
|
|
45
|
+
function deriveParamSpecs(op) {
|
|
46
|
+
const out = [];
|
|
47
|
+
for (const p of op.parameters) {
|
|
48
|
+
const flag = `--${kebabCase(p.name)}`;
|
|
49
|
+
const type = getSchemaType(p.schema);
|
|
50
|
+
const schemaObj = p.schema && typeof p.schema === "object" ? p.schema : undefined;
|
|
51
|
+
const itemsSchema = schemaObj && type === "array" && typeof schemaObj.items === "object" ? schemaObj.items : undefined;
|
|
52
|
+
out.push({
|
|
53
|
+
kind: p.in === "path" ? "positional" : "flag",
|
|
54
|
+
in: p.in,
|
|
55
|
+
name: p.name,
|
|
56
|
+
flag,
|
|
57
|
+
required: p.required,
|
|
58
|
+
description: p.description,
|
|
59
|
+
type,
|
|
60
|
+
format: getSchemaFormat(p.schema),
|
|
61
|
+
enum: getSchemaEnumStrings(p.schema),
|
|
62
|
+
itemType: type === "array" ? getSchemaType(itemsSchema) : undefined,
|
|
63
|
+
itemFormat: type === "array" ? getSchemaFormat(itemsSchema) : undefined,
|
|
64
|
+
itemEnum: type === "array" ? getSchemaEnumStrings(itemsSchema) : undefined,
|
|
65
|
+
schema: schemaObj
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
out.sort((a, b) => {
|
|
69
|
+
if (a.in !== b.in)
|
|
70
|
+
return a.in.localeCompare(b.in);
|
|
71
|
+
return a.name.localeCompare(b.name);
|
|
72
|
+
});
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
export {
|
|
76
|
+
deriveParamSpecs
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
//# debugId=1318B970EA1D049964756E2164756E21
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/cli/schema-shape.ts", "../../../src/cli/strings.ts", "../../../src/cli/params.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"export type ParamType =\n\t| \"string\"\n\t| \"number\"\n\t| \"integer\"\n\t| \"boolean\"\n\t| \"array\"\n\t| \"object\"\n\t| \"unknown\";\n\nexport function getSchemaType(schema: unknown): ParamType {\n\tif (!schema || typeof schema !== \"object\") return \"unknown\";\n\tconst t = (schema as { type?: unknown }).type;\n\tif (t === \"string\") return \"string\";\n\tif (t === \"number\") return \"number\";\n\tif (t === \"integer\") return \"integer\";\n\tif (t === \"boolean\") return \"boolean\";\n\tif (t === \"array\") return \"array\";\n\tif (t === \"object\") return \"object\";\n\treturn \"unknown\";\n}\n\nexport function getSchemaFormat(schema: unknown): string | undefined {\n\tif (!schema || typeof schema !== \"object\") return undefined;\n\tconst f = (schema as { format?: unknown }).format;\n\treturn typeof f === \"string\" ? f : undefined;\n}\n\nexport function getSchemaEnumStrings(schema: unknown): string[] | undefined {\n\tif (!schema || typeof schema !== \"object\") return undefined;\n\tconst e = (schema as { enum?: unknown }).enum;\n\tif (!Array.isArray(e)) return undefined;\n\n\t// We only surface string enums for now (enough for flag docs + completion).\n\tconst values = e.filter((v) => typeof v === \"string\") as string[];\n\treturn values.length ? values : undefined;\n}\n",
|
|
6
|
+
"export function kebabCase(input: string): string {\n\tconst trimmed = input.trim();\n\tif (!trimmed) return \"\";\n\n\t// Convert spaces/underscores/dots to dashes, split camelCase.\n\treturn trimmed\n\t\t.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n\t\t.replace(/[\\s_.:/]+/g, \"-\")\n\t\t.replace(/[^a-zA-Z0-9-]/g, \"-\")\n\t\t.replace(/-+/g, \"-\")\n\t\t.replace(/^-|-$/g, \"\")\n\t\t.toLowerCase();\n}\n\nexport function titleCase(input: string): string {\n\treturn input\n\t\t.split(/\\s+/g)\n\t\t.filter(Boolean)\n\t\t.map((w) => w[0]?.toUpperCase() + w.slice(1))\n\t\t.join(\" \");\n}\n",
|
|
7
|
+
"import {\n\tgetSchemaEnumStrings,\n\tgetSchemaFormat,\n\tgetSchemaType,\n} from \"./schema-shape.ts\";\nimport { kebabCase } from \"./strings.ts\";\nimport type { NormalizedOperation, NormalizedParameter } from \"./types.ts\";\n\nexport type ParamType = import(\"./schema-shape.ts\").ParamType;\n\nexport type ParamSpec = {\n\tkind: \"positional\" | \"flag\";\n\tin: NormalizedParameter[\"in\"];\n\tname: string;\n\tflag: string;\n\trequired: boolean;\n\tdescription?: string;\n\ttype: ParamType;\n\tformat?: string;\n\tenum?: string[];\n\n\t// Arrays\n\titemType?: ParamType;\n\titemFormat?: string;\n\titemEnum?: string[];\n\n\t// Original schema for Ajv validation and future advanced flag expansion.\n\tschema?: import(\"./types.ts\").JsonSchema;\n};\n\nexport function deriveParamSpecs(op: NormalizedOperation): ParamSpec[] {\n\tconst out: ParamSpec[] = [];\n\n\tfor (const p of op.parameters) {\n\t\tconst flag = `--${kebabCase(p.name)}`;\n\t\tconst type = getSchemaType(p.schema);\n\t\tconst schemaObj =\n\t\t\tp.schema && typeof p.schema === \"object\"\n\t\t\t\t? (p.schema as import(\"./types.ts\").JsonSchema)\n\t\t\t\t: undefined;\n\n\t\tconst itemsSchema =\n\t\t\tschemaObj && type === \"array\" && typeof schemaObj.items === \"object\"\n\t\t\t\t? (schemaObj.items as unknown)\n\t\t\t\t: undefined;\n\n\t\tout.push({\n\t\t\tkind: p.in === \"path\" ? \"positional\" : \"flag\",\n\t\t\tin: p.in,\n\t\t\tname: p.name,\n\t\t\tflag,\n\t\t\trequired: p.required,\n\t\t\tdescription: p.description,\n\t\t\ttype,\n\t\t\tformat: getSchemaFormat(p.schema),\n\t\t\tenum: getSchemaEnumStrings(p.schema),\n\t\t\titemType: type === \"array\" ? getSchemaType(itemsSchema) : undefined,\n\t\t\titemFormat: type === \"array\" ? getSchemaFormat(itemsSchema) : undefined,\n\t\t\titemEnum:\n\t\t\t\ttype === \"array\" ? getSchemaEnumStrings(itemsSchema) : undefined,\n\t\t\tschema: schemaObj,\n\t\t});\n\t}\n\n\tout.sort((a, b) => {\n\t\tif (a.in !== b.in) return a.in.localeCompare(b.in);\n\t\treturn a.name.localeCompare(b.name);\n\t});\n\n\treturn out;\n}\n"
|
|
8
|
+
],
|
|
9
|
+
"mappings": ";AASO,SAAS,aAAa,CAAC,QAA4B;AAAA,EACzD,IAAI,CAAC,UAAU,OAAO,WAAW;AAAA,IAAU,OAAO;AAAA,EAClD,MAAM,IAAK,OAA8B;AAAA,EACzC,IAAI,MAAM;AAAA,IAAU,OAAO;AAAA,EAC3B,IAAI,MAAM;AAAA,IAAU,OAAO;AAAA,EAC3B,IAAI,MAAM;AAAA,IAAW,OAAO;AAAA,EAC5B,IAAI,MAAM;AAAA,IAAW,OAAO;AAAA,EAC5B,IAAI,MAAM;AAAA,IAAS,OAAO;AAAA,EAC1B,IAAI,MAAM;AAAA,IAAU,OAAO;AAAA,EAC3B,OAAO;AAAA;AAGD,SAAS,eAAe,CAAC,QAAqC;AAAA,EACpE,IAAI,CAAC,UAAU,OAAO,WAAW;AAAA,IAAU;AAAA,EAC3C,MAAM,IAAK,OAAgC;AAAA,EAC3C,OAAO,OAAO,MAAM,WAAW,IAAI;AAAA;AAG7B,SAAS,oBAAoB,CAAC,QAAuC;AAAA,EAC3E,IAAI,CAAC,UAAU,OAAO,WAAW;AAAA,IAAU;AAAA,EAC3C,MAAM,IAAK,OAA8B;AAAA,EACzC,IAAI,CAAC,MAAM,QAAQ,CAAC;AAAA,IAAG;AAAA,EAGvB,MAAM,SAAS,EAAE,OAAO,CAAC,MAAM,OAAO,MAAM,QAAQ;AAAA,EACpD,OAAO,OAAO,SAAS,SAAS;AAAA;;;AClC1B,SAAS,SAAS,CAAC,OAAuB;AAAA,EAChD,MAAM,UAAU,MAAM,KAAK;AAAA,EAC3B,IAAI,CAAC;AAAA,IAAS,OAAO;AAAA,EAGrB,OAAO,QACL,QAAQ,sBAAsB,OAAO,EACrC,QAAQ,cAAc,GAAG,EACzB,QAAQ,kBAAkB,GAAG,EAC7B,QAAQ,OAAO,GAAG,EAClB,QAAQ,UAAU,EAAE,EACpB,YAAY;AAAA;;;ACmBR,SAAS,gBAAgB,CAAC,IAAsC;AAAA,EACtE,MAAM,MAAmB,CAAC;AAAA,EAE1B,WAAW,KAAK,GAAG,YAAY;AAAA,IAC9B,MAAM,OAAO,KAAK,UAAU,EAAE,IAAI;AAAA,IAClC,MAAM,OAAO,cAAc,EAAE,MAAM;AAAA,IACnC,MAAM,YACL,EAAE,UAAU,OAAO,EAAE,WAAW,WAC5B,EAAE,SACH;AAAA,IAEJ,MAAM,cACL,aAAa,SAAS,WAAW,OAAO,UAAU,UAAU,WACxD,UAAU,QACX;AAAA,IAEJ,IAAI,KAAK;AAAA,MACR,MAAM,EAAE,OAAO,SAAS,eAAe;AAAA,MACvC,IAAI,EAAE;AAAA,MACN,MAAM,EAAE;AAAA,MACR;AAAA,MACA,UAAU,EAAE;AAAA,MACZ,aAAa,EAAE;AAAA,MACf;AAAA,MACA,QAAQ,gBAAgB,EAAE,MAAM;AAAA,MAChC,MAAM,qBAAqB,EAAE,MAAM;AAAA,MACnC,UAAU,SAAS,UAAU,cAAc,WAAW,IAAI;AAAA,MAC1D,YAAY,SAAS,UAAU,gBAAgB,WAAW,IAAI;AAAA,MAC9D,UACC,SAAS,UAAU,qBAAqB,WAAW,IAAI;AAAA,MACxD,QAAQ;AAAA,IACT,CAAC;AAAA,EACF;AAAA,EAEA,IAAI,KAAK,CAAC,GAAG,MAAM;AAAA,IAClB,IAAI,EAAE,OAAO,EAAE;AAAA,MAAI,OAAO,EAAE,GAAG,cAAc,EAAE,EAAE;AAAA,IACjD,OAAO,EAAE,KAAK,cAAc,EAAE,IAAI;AAAA,GAClC;AAAA,EAED,OAAO;AAAA;",
|
|
10
|
+
"debugId": "1318B970EA1D049964756E2164756E21",
|
|
11
|
+
"names": []
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pluralize.d.ts","sourceRoot":"","sources":["../../../src/cli/pluralize.ts"],"names":[],"mappings":"AAoBA,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAoB9C"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// src/cli/pluralize.ts
|
|
2
|
+
var IRREGULAR = {
|
|
3
|
+
person: "people",
|
|
4
|
+
man: "men",
|
|
5
|
+
woman: "women",
|
|
6
|
+
child: "children",
|
|
7
|
+
tooth: "teeth",
|
|
8
|
+
foot: "feet",
|
|
9
|
+
mouse: "mice",
|
|
10
|
+
goose: "geese"
|
|
11
|
+
};
|
|
12
|
+
var UNCOUNTABLE = new Set([
|
|
13
|
+
"metadata",
|
|
14
|
+
"information",
|
|
15
|
+
"equipment",
|
|
16
|
+
"money",
|
|
17
|
+
"series",
|
|
18
|
+
"species"
|
|
19
|
+
]);
|
|
20
|
+
function pluralize(word) {
|
|
21
|
+
const w = word.trim();
|
|
22
|
+
if (!w)
|
|
23
|
+
return w;
|
|
24
|
+
const lower = w.toLowerCase();
|
|
25
|
+
if (UNCOUNTABLE.has(lower))
|
|
26
|
+
return lower;
|
|
27
|
+
if (IRREGULAR[lower])
|
|
28
|
+
return IRREGULAR[lower];
|
|
29
|
+
if (lower.endsWith("s"))
|
|
30
|
+
return lower;
|
|
31
|
+
if (/[bcdfghjklmnpqrstvwxyz]y$/.test(lower)) {
|
|
32
|
+
return lower.replace(/y$/, "ies");
|
|
33
|
+
}
|
|
34
|
+
if (/(ch|sh|x|z)$/.test(lower)) {
|
|
35
|
+
return `${lower}es`;
|
|
36
|
+
}
|
|
37
|
+
return `${lower}s`;
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
pluralize
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
//# debugId=DB29AA914B97043364756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/cli/pluralize.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"const IRREGULAR: Record<string, string> = {\n\tperson: \"people\",\n\tman: \"men\",\n\twoman: \"women\",\n\tchild: \"children\",\n\ttooth: \"teeth\",\n\tfoot: \"feet\",\n\tmouse: \"mice\",\n\tgoose: \"geese\",\n};\n\nconst UNCOUNTABLE = new Set([\n\t\"metadata\",\n\t\"information\",\n\t\"equipment\",\n\t\"money\",\n\t\"series\",\n\t\"species\",\n]);\n\nexport function pluralize(word: string): string {\n\tconst w = word.trim();\n\tif (!w) return w;\n\n\tconst lower = w.toLowerCase();\n\tif (UNCOUNTABLE.has(lower)) return lower;\n\tif (IRREGULAR[lower]) return IRREGULAR[lower];\n\n\t// already plural-ish\n\tif (lower.endsWith(\"s\")) return lower;\n\n\tif (/[bcdfghjklmnpqrstvwxyz]y$/.test(lower)) {\n\t\treturn lower.replace(/y$/, \"ies\");\n\t}\n\n\tif (/(ch|sh|x|z)$/.test(lower)) {\n\t\treturn `${lower}es`;\n\t}\n\n\treturn `${lower}s`;\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";AAAA,IAAM,YAAoC;AAAA,EACzC,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AACR;AAEA,IAAM,cAAc,IAAI,IAAI;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAEM,SAAS,SAAS,CAAC,MAAsB;AAAA,EAC/C,MAAM,IAAI,KAAK,KAAK;AAAA,EACpB,IAAI,CAAC;AAAA,IAAG,OAAO;AAAA,EAEf,MAAM,QAAQ,EAAE,YAAY;AAAA,EAC5B,IAAI,YAAY,IAAI,KAAK;AAAA,IAAG,OAAO;AAAA,EACnC,IAAI,UAAU;AAAA,IAAQ,OAAO,UAAU;AAAA,EAGvC,IAAI,MAAM,SAAS,GAAG;AAAA,IAAG,OAAO;AAAA,EAEhC,IAAI,4BAA4B,KAAK,KAAK,GAAG;AAAA,IAC5C,OAAO,MAAM,QAAQ,MAAM,KAAK;AAAA,EACjC;AAAA,EAEA,IAAI,eAAe,KAAK,KAAK,GAAG;AAAA,IAC/B,OAAO,GAAG;AAAA,EACX;AAAA,EAEA,OAAO,GAAG;AAAA;",
|
|
8
|
+
"debugId": "DB29AA914B97043364756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ParamSpec } from "./params.js";
|
|
2
|
+
export type ActionShapeForCli = {
|
|
3
|
+
pathArgs: string[];
|
|
4
|
+
params: ParamSpec[];
|
|
5
|
+
};
|
|
6
|
+
export type PositionalArg = {
|
|
7
|
+
name: string;
|
|
8
|
+
required: boolean;
|
|
9
|
+
description?: string;
|
|
10
|
+
type: import("./schema-shape.js").ParamType;
|
|
11
|
+
format?: string;
|
|
12
|
+
enum?: string[];
|
|
13
|
+
};
|
|
14
|
+
export type FlagsIndex = {
|
|
15
|
+
flags: Array<Pick<import("./params.js").ParamSpec, "in" | "name" | "flag" | "required" | "description" | "type" | "format" | "enum" | "itemType" | "itemFormat" | "itemEnum">>;
|
|
16
|
+
};
|
|
17
|
+
export declare function derivePositionals(action: ActionShapeForCli): PositionalArg[];
|
|
18
|
+
export declare function deriveFlags(action: ActionShapeForCli): FlagsIndex;
|
|
19
|
+
//# sourceMappingURL=positional.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"positional.d.ts","sourceRoot":"","sources":["../../../src/cli/positional.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,MAAM,iBAAiB,GAAG;IAC/B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,SAAS,EAAE,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,OAAO,mBAAmB,EAAE,SAAS,CAAC;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACxB,KAAK,EAAE,KAAK,CACX,IAAI,CACH,OAAO,aAAa,EAAE,SAAS,EAC7B,IAAI,GACJ,MAAM,GACN,MAAM,GACN,UAAU,GACV,aAAa,GACb,MAAM,GACN,QAAQ,GACR,MAAM,GACN,UAAU,GACV,YAAY,GACZ,UAAU,CACZ,CACD,CAAC;CACF,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,aAAa,EAAE,CAmB5E;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,UAAU,CAkBjE"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// src/cli/positional.ts
|
|
2
|
+
function derivePositionals(action) {
|
|
3
|
+
const byName = new Map;
|
|
4
|
+
for (const name of action.pathArgs) {
|
|
5
|
+
const p = action.params.find((x) => x.in === "path" && x.name === name);
|
|
6
|
+
byName.set(name, {
|
|
7
|
+
name,
|
|
8
|
+
required: true,
|
|
9
|
+
description: p?.description,
|
|
10
|
+
type: p?.type ?? "unknown",
|
|
11
|
+
format: p?.format,
|
|
12
|
+
enum: p?.enum
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
return [...byName.values()];
|
|
16
|
+
}
|
|
17
|
+
function deriveFlags(action) {
|
|
18
|
+
return {
|
|
19
|
+
flags: action.params.filter((p) => p.kind === "flag").map((p) => ({
|
|
20
|
+
in: p.in,
|
|
21
|
+
name: p.name,
|
|
22
|
+
flag: p.flag,
|
|
23
|
+
required: p.required,
|
|
24
|
+
description: p.description,
|
|
25
|
+
type: p.type,
|
|
26
|
+
format: p.format,
|
|
27
|
+
enum: p.enum,
|
|
28
|
+
itemType: p.itemType,
|
|
29
|
+
itemFormat: p.itemFormat,
|
|
30
|
+
itemEnum: p.itemEnum
|
|
31
|
+
}))
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
derivePositionals,
|
|
36
|
+
deriveFlags
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
//# debugId=16EFAB2F171B486164756E2164756E21
|