specli 0.0.11 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +216 -325
- package/bin/cli.sh +27 -0
- package/dist/{src/ai → ai}/tools.d.ts +0 -1
- package/dist/ai/tools.js +161 -0
- package/dist/ai/tools.test.d.ts +1 -0
- package/dist/ai/tools.test.js +56 -0
- package/dist/{src/cli → cli}/auth-requirements.d.ts +0 -1
- package/dist/cli/auth-requirements.js +65 -0
- package/dist/cli/auth-requirements.test.d.ts +1 -0
- package/dist/cli/auth-requirements.test.js +16 -0
- package/dist/{src/cli → cli}/auth-schemes.d.ts +0 -1
- package/dist/cli/auth-schemes.js +112 -0
- package/dist/cli/auth-schemes.test.d.ts +1 -0
- package/dist/cli/auth-schemes.test.js +56 -0
- package/dist/{src/cli → cli}/capabilities.d.ts +0 -1
- package/dist/cli/capabilities.js +41 -0
- package/dist/cli/capabilities.test.d.ts +1 -0
- package/dist/cli/capabilities.test.js +84 -0
- package/dist/{src/cli → cli}/command-id.d.ts +0 -1
- package/dist/cli/command-id.js +8 -0
- package/dist/cli/command-id.test.d.ts +1 -0
- package/dist/cli/command-id.test.js +27 -0
- package/dist/{src/cli → cli}/command-index.d.ts +0 -1
- package/dist/cli/command-index.js +9 -0
- package/dist/{src/cli → cli}/command-model.d.ts +0 -1
- package/dist/cli/command-model.js +53 -0
- package/dist/cli/command-model.test.d.ts +1 -0
- package/dist/cli/command-model.test.js +40 -0
- package/dist/{src/cli → cli}/compile.d.ts +0 -1
- package/dist/cli/compile.js +79 -0
- package/dist/{src/cli → cli}/crypto.d.ts +0 -1
- package/dist/cli/crypto.js +9 -0
- package/dist/{src/cli → cli}/derive-name.d.ts +0 -1
- package/dist/cli/derive-name.js +96 -0
- package/dist/{src/cli → cli}/exec.d.ts +0 -1
- package/dist/cli/exec.js +50 -0
- package/dist/{src/cli → cli}/main.d.ts +0 -1
- package/dist/cli/main.js +177 -0
- package/dist/{src/cli → cli}/naming.d.ts +0 -1
- package/dist/cli/naming.js +191 -0
- package/dist/cli/naming.test.d.ts +1 -0
- package/dist/cli/naming.test.js +75 -0
- package/dist/{src/cli → cli}/operations.d.ts +0 -1
- package/dist/cli/operations.js +100 -0
- package/dist/cli/operations.test.d.ts +1 -0
- package/dist/cli/operations.test.js +51 -0
- package/dist/{src/cli → cli}/params.d.ts +0 -1
- package/dist/cli/params.js +36 -0
- package/dist/cli/params.test.d.ts +1 -0
- package/dist/cli/params.test.js +62 -0
- package/dist/{src/cli → cli}/pluralize.d.ts +0 -1
- package/dist/cli/pluralize.js +38 -0
- package/dist/{src/cli → cli}/positional.d.ts +0 -1
- package/dist/cli/positional.js +35 -0
- package/dist/cli/positional.test.d.ts +1 -0
- package/dist/cli/positional.test.js +60 -0
- package/dist/{src/cli → cli}/request-body.d.ts +0 -1
- package/dist/cli/request-body.js +44 -0
- package/dist/cli/request-body.test.d.ts +1 -0
- package/dist/cli/request-body.test.js +31 -0
- package/dist/{src/cli → cli}/runtime/argv.d.ts +0 -1
- package/dist/cli/runtime/argv.js +15 -0
- package/dist/{src/cli → cli}/runtime/auth/resolve.d.ts +0 -1
- package/dist/cli/runtime/auth/resolve.js +39 -0
- package/dist/{src/cli → cli}/runtime/body-flags.d.ts +0 -1
- package/dist/cli/runtime/body-flags.js +117 -0
- package/dist/cli/runtime/body-flags.test.d.ts +1 -0
- package/dist/cli/runtime/body-flags.test.js +192 -0
- package/dist/{src/cli → cli}/runtime/body.d.ts +0 -1
- package/dist/cli/runtime/body.js +16 -0
- package/dist/{src/cli → cli}/runtime/collect.d.ts +0 -1
- package/dist/cli/runtime/collect.js +3 -0
- package/dist/{src/cli → cli}/runtime/compat.d.ts +0 -1
- package/dist/cli/runtime/compat.js +78 -0
- package/dist/{src/cli → cli}/runtime/context.d.ts +0 -1
- package/dist/cli/runtime/context.js +44 -0
- package/dist/{src/cli → cli}/runtime/execute.d.ts +0 -1
- package/dist/cli/runtime/execute.js +106 -0
- package/dist/{src/cli → cli}/runtime/generated.d.ts +0 -1
- package/dist/cli/runtime/generated.js +168 -0
- package/dist/{src/cli → cli}/runtime/headers.d.ts +0 -1
- package/dist/cli/runtime/headers.js +30 -0
- package/dist/{src/cli → cli}/runtime/index.d.ts +0 -1
- package/dist/cli/runtime/index.js +3 -0
- package/dist/{src/cli → cli}/runtime/profile/secrets.d.ts +0 -1
- package/dist/cli/runtime/profile/secrets.js +53 -0
- package/dist/{src/cli → cli}/runtime/profile/store.d.ts +0 -1
- package/dist/cli/runtime/profile/store.js +63 -0
- package/dist/{src/cli → cli}/runtime/request.d.ts +0 -1
- package/dist/cli/runtime/request.js +283 -0
- package/dist/cli/runtime/request.test.d.ts +1 -0
- package/dist/cli/runtime/request.test.js +332 -0
- package/dist/{src/cli → cli}/runtime/server-url.d.ts +0 -1
- package/dist/cli/runtime/server-url.js +28 -0
- package/dist/{src/cli → cli}/runtime/template.d.ts +0 -1
- package/dist/cli/runtime/template.js +22 -0
- package/dist/cli/runtime/validate/ajv.d.ts +2 -0
- package/dist/cli/runtime/validate/ajv.js +11 -0
- package/dist/{src/cli → cli}/runtime/validate/coerce.d.ts +0 -1
- package/dist/cli/runtime/validate/coerce.js +63 -0
- package/dist/cli/runtime/validate/coerce.test.d.ts +1 -0
- package/dist/cli/runtime/validate/coerce.test.js +75 -0
- package/dist/{src/cli → cli}/runtime/validate/error.d.ts +0 -1
- package/dist/cli/runtime/validate/error.js +19 -0
- package/dist/{src/cli → cli}/runtime/validate/index.d.ts +0 -1
- package/dist/cli/runtime/validate/index.js +4 -0
- package/dist/{src/cli → cli}/runtime/validate/schema.d.ts +0 -1
- package/dist/cli/runtime/validate/schema.js +38 -0
- package/dist/{src/cli → cli}/schema-shape.d.ts +0 -1
- package/dist/cli/schema-shape.js +34 -0
- package/dist/{src/cli → cli}/schema.d.ts +0 -1
- package/dist/cli/schema.js +31 -0
- package/dist/{src/cli → cli}/server.d.ts +0 -1
- package/dist/cli/server.js +130 -0
- package/dist/cli/server.test.d.ts +1 -0
- package/dist/cli/server.test.js +49 -0
- package/dist/{src/cli → cli}/spec-id.d.ts +0 -1
- package/dist/cli/spec-id.js +8 -0
- package/dist/{src/cli → cli}/spec-loader.d.ts +0 -1
- package/dist/cli/spec-loader.js +40 -0
- package/dist/{src/cli → cli}/stable-json.d.ts +0 -1
- package/dist/cli/stable-json.js +29 -0
- package/dist/{src/cli → cli}/strings.d.ts +0 -1
- package/dist/cli/strings.js +20 -0
- package/dist/{src/cli → cli}/types.d.ts +0 -1
- package/dist/cli/types.js +3 -0
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +51 -2324
- package/dist/compiled.d.ts +2 -0
- package/{src/compiled.ts → dist/compiled.js} +8 -11
- package/dist/macros/env.d.ts +10 -0
- package/dist/macros/env.js +22 -0
- package/dist/macros/spec.d.ts +5 -0
- package/dist/macros/spec.js +16 -0
- package/package.json +17 -25
- package/bin/specli.js +0 -26
- package/cli.ts +0 -77
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -53
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -2032
- package/dist/index.js.map +0 -48
- package/dist/src/ai/tools.d.ts.map +0 -1
- package/dist/src/ai/tools.js +0 -1656
- package/dist/src/ai/tools.js.map +0 -45
- package/dist/src/cli/auth-requirements.d.ts.map +0 -1
- package/dist/src/cli/auth-requirements.js +0 -66
- package/dist/src/cli/auth-requirements.js.map +0 -10
- package/dist/src/cli/auth-schemes.d.ts.map +0 -1
- package/dist/src/cli/auth-schemes.js +0 -116
- package/dist/src/cli/auth-schemes.js.map +0 -11
- package/dist/src/cli/capabilities.d.ts.map +0 -1
- package/dist/src/cli/capabilities.js +0 -45
- package/dist/src/cli/capabilities.js.map +0 -10
- package/dist/src/cli/command-id.d.ts.map +0 -1
- package/dist/src/cli/command-id.js +0 -18
- package/dist/src/cli/command-id.js.map +0 -11
- package/dist/src/cli/command-index.d.ts.map +0 -1
- package/dist/src/cli/command-index.js +0 -15
- package/dist/src/cli/command-index.js.map +0 -10
- package/dist/src/cli/command-model.d.ts.map +0 -1
- package/dist/src/cli/command-model.js +0 -274
- package/dist/src/cli/command-model.js.map +0 -18
- package/dist/src/cli/compile.d.ts.map +0 -1
- package/dist/src/cli/compile.js +0 -146
- package/dist/src/cli/compile.js.map +0 -11
- package/dist/src/cli/crypto.d.ts.map +0 -1
- package/dist/src/cli/crypto.js +0 -15
- package/dist/src/cli/crypto.js.map +0 -10
- package/dist/src/cli/derive-name.d.ts.map +0 -1
- package/dist/src/cli/derive-name.js +0 -70
- package/dist/src/cli/derive-name.js.map +0 -10
- package/dist/src/cli/exec.d.ts.map +0 -1
- package/dist/src/cli/exec.js +0 -2077
- package/dist/src/cli/exec.js.map +0 -49
- package/dist/src/cli/main.d.ts.map +0 -1
- package/dist/src/cli/main.js +0 -2032
- package/dist/src/cli/main.js.map +0 -48
- package/dist/src/cli/naming.d.ts.map +0 -1
- package/dist/src/cli/naming.js +0 -216
- package/dist/src/cli/naming.js.map +0 -12
- package/dist/src/cli/operations.d.ts.map +0 -1
- package/dist/src/cli/operations.js +0 -103
- package/dist/src/cli/operations.js.map +0 -10
- package/dist/src/cli/params.d.ts.map +0 -1
- package/dist/src/cli/params.js +0 -79
- package/dist/src/cli/params.js.map +0 -12
- package/dist/src/cli/pluralize.d.ts.map +0 -1
- package/dist/src/cli/pluralize.js +0 -43
- package/dist/src/cli/pluralize.js.map +0 -10
- package/dist/src/cli/positional.d.ts.map +0 -1
- package/dist/src/cli/positional.js +0 -39
- package/dist/src/cli/positional.js.map +0 -10
- package/dist/src/cli/request-body.d.ts.map +0 -1
- package/dist/src/cli/request-body.js +0 -82
- package/dist/src/cli/request-body.js.map +0 -12
- package/dist/src/cli/runtime/argv.d.ts.map +0 -1
- package/dist/src/cli/runtime/argv.js +0 -22
- package/dist/src/cli/runtime/argv.js.map +0 -10
- package/dist/src/cli/runtime/auth/resolve.d.ts.map +0 -1
- package/dist/src/cli/runtime/auth/resolve.js +0 -38
- package/dist/src/cli/runtime/auth/resolve.js.map +0 -10
- package/dist/src/cli/runtime/body-flags.d.ts.map +0 -1
- package/dist/src/cli/runtime/body-flags.js +0 -86
- package/dist/src/cli/runtime/body-flags.js.map +0 -10
- package/dist/src/cli/runtime/body.d.ts.map +0 -1
- package/dist/src/cli/runtime/body.js +0 -40
- package/dist/src/cli/runtime/body.js.map +0 -11
- package/dist/src/cli/runtime/collect.d.ts.map +0 -1
- package/dist/src/cli/runtime/collect.js +0 -9
- package/dist/src/cli/runtime/collect.js.map +0 -10
- package/dist/src/cli/runtime/compat.d.ts.map +0 -1
- package/dist/src/cli/runtime/compat.js +0 -62
- package/dist/src/cli/runtime/compat.js.map +0 -10
- package/dist/src/cli/runtime/context.d.ts.map +0 -1
- package/dist/src/cli/runtime/context.js +0 -936
- package/dist/src/cli/runtime/context.js.map +0 -32
- package/dist/src/cli/runtime/execute.d.ts.map +0 -1
- package/dist/src/cli/runtime/execute.js +0 -670
- package/dist/src/cli/runtime/execute.js.map +0 -22
- package/dist/src/cli/runtime/generated.d.ts.map +0 -1
- package/dist/src/cli/runtime/generated.js +0 -869
- package/dist/src/cli/runtime/generated.js.map +0 -23
- package/dist/src/cli/runtime/headers.d.ts.map +0 -1
- package/dist/src/cli/runtime/headers.js +0 -36
- package/dist/src/cli/runtime/headers.js.map +0 -10
- package/dist/src/cli/runtime/index.d.ts.map +0 -1
- package/dist/src/cli/runtime/index.js +0 -1808
- package/dist/src/cli/runtime/index.js.map +0 -46
- package/dist/src/cli/runtime/profile/secrets.d.ts.map +0 -1
- package/dist/src/cli/runtime/profile/secrets.js +0 -51
- package/dist/src/cli/runtime/profile/secrets.js.map +0 -11
- package/dist/src/cli/runtime/profile/store.d.ts.map +0 -1
- package/dist/src/cli/runtime/profile/store.js +0 -102
- package/dist/src/cli/runtime/profile/store.js.map +0 -11
- package/dist/src/cli/runtime/request.d.ts.map +0 -1
- package/dist/src/cli/runtime/request.js +0 -571
- package/dist/src/cli/runtime/request.js.map +0 -21
- package/dist/src/cli/runtime/server-url.d.ts.map +0 -1
- package/dist/src/cli/runtime/server-url.js +0 -55
- package/dist/src/cli/runtime/server-url.js.map +0 -11
- package/dist/src/cli/runtime/template.d.ts.map +0 -1
- package/dist/src/cli/runtime/template.js +0 -29
- package/dist/src/cli/runtime/template.js.map +0 -10
- package/dist/src/cli/runtime/validate/ajv.d.ts +0 -3
- package/dist/src/cli/runtime/validate/ajv.d.ts.map +0 -1
- package/dist/src/cli/runtime/validate/ajv.js +0 -17
- package/dist/src/cli/runtime/validate/ajv.js.map +0 -10
- package/dist/src/cli/runtime/validate/coerce.d.ts.map +0 -1
- package/dist/src/cli/runtime/validate/coerce.js +0 -60
- package/dist/src/cli/runtime/validate/coerce.js.map +0 -10
- package/dist/src/cli/runtime/validate/error.d.ts.map +0 -1
- package/dist/src/cli/runtime/validate/error.js +0 -21
- package/dist/src/cli/runtime/validate/error.js.map +0 -10
- package/dist/src/cli/runtime/validate/index.d.ts.map +0 -1
- package/dist/src/cli/runtime/validate/index.js +0 -122
- package/dist/src/cli/runtime/validate/index.js.map +0 -13
- package/dist/src/cli/runtime/validate/schema.d.ts.map +0 -1
- package/dist/src/cli/runtime/validate/schema.js +0 -36
- package/dist/src/cli/runtime/validate/schema.js.map +0 -10
- package/dist/src/cli/schema-shape.d.ts.map +0 -1
- package/dist/src/cli/schema-shape.js +0 -41
- package/dist/src/cli/schema-shape.js.map +0 -10
- package/dist/src/cli/schema.d.ts.map +0 -1
- package/dist/src/cli/schema.js +0 -38
- package/dist/src/cli/schema.js.map +0 -10
- package/dist/src/cli/server.d.ts.map +0 -1
- package/dist/src/cli/server.js +0 -64
- package/dist/src/cli/server.js.map +0 -11
- package/dist/src/cli/spec-id.d.ts.map +0 -1
- package/dist/src/cli/spec-id.js +0 -21
- package/dist/src/cli/spec-id.js.map +0 -11
- package/dist/src/cli/spec-loader.d.ts.map +0 -1
- package/dist/src/cli/spec-loader.js +0 -110
- package/dist/src/cli/spec-loader.js.map +0 -15
- package/dist/src/cli/stable-json.d.ts.map +0 -1
- package/dist/src/cli/stable-json.js +0 -35
- package/dist/src/cli/stable-json.js.map +0 -10
- package/dist/src/cli/strings.d.ts.map +0 -1
- package/dist/src/cli/strings.js +0 -16
- package/dist/src/cli/strings.js.map +0 -10
- package/dist/src/cli/types.d.ts.map +0 -1
- package/dist/src/cli/types.js +0 -9
- package/dist/src/cli/types.js.map +0 -10
- package/index.ts +0 -1
- package/src/ai/tools.ts +0 -211
- package/src/cli/auth-requirements.ts +0 -91
- package/src/cli/auth-schemes.ts +0 -187
- package/src/cli/capabilities.ts +0 -88
- package/src/cli/command-id.ts +0 -16
- package/src/cli/command-index.ts +0 -19
- package/src/cli/command-model.ts +0 -128
- package/src/cli/compile.ts +0 -101
- package/src/cli/crypto.ts +0 -9
- package/src/cli/derive-name.ts +0 -101
- package/src/cli/exec.ts +0 -72
- package/src/cli/main.ts +0 -231
- package/src/cli/naming.ts +0 -224
- package/src/cli/operations.ts +0 -152
- package/src/cli/params.ts +0 -71
- package/src/cli/pluralize.ts +0 -41
- package/src/cli/positional.ts +0 -75
- package/src/cli/request-body.ts +0 -94
- package/src/cli/runtime/argv.ts +0 -14
- package/src/cli/runtime/auth/resolve.ts +0 -59
- package/src/cli/runtime/body-flags.ts +0 -176
- package/src/cli/runtime/body.ts +0 -24
- package/src/cli/runtime/collect.ts +0 -6
- package/src/cli/runtime/compat.ts +0 -89
- package/src/cli/runtime/context.ts +0 -62
- package/src/cli/runtime/execute.ts +0 -147
- package/src/cli/runtime/generated.ts +0 -242
- package/src/cli/runtime/headers.ts +0 -37
- package/src/cli/runtime/index.ts +0 -3
- package/src/cli/runtime/profile/secrets.ts +0 -83
- package/src/cli/runtime/profile/store.ts +0 -100
- package/src/cli/runtime/request.ts +0 -390
- package/src/cli/runtime/server-url.ts +0 -45
- package/src/cli/runtime/template.ts +0 -26
- package/src/cli/runtime/validate/ajv.ts +0 -13
- package/src/cli/runtime/validate/coerce.ts +0 -71
- package/src/cli/runtime/validate/error.ts +0 -29
- package/src/cli/runtime/validate/index.ts +0 -4
- package/src/cli/runtime/validate/schema.ts +0 -54
- package/src/cli/schema-shape.ts +0 -36
- package/src/cli/schema.ts +0 -76
- package/src/cli/server.ts +0 -88
- package/src/cli/spec-id.ts +0 -12
- package/src/cli/spec-loader.ts +0 -58
- package/src/cli/stable-json.ts +0 -35
- package/src/cli/strings.ts +0 -21
- package/src/cli/types.ts +0 -59
- package/src/macros/env.ts +0 -21
- package/src/macros/spec.ts +0 -17
|
@@ -1,390 +0,0 @@
|
|
|
1
|
-
import type { AuthScheme } from "../auth-schemes.ts";
|
|
2
|
-
import type { CommandAction } from "../command-model.ts";
|
|
3
|
-
|
|
4
|
-
import { resolveAuthScheme } from "./auth/resolve.ts";
|
|
5
|
-
import { getToken } from "./profile/secrets.ts";
|
|
6
|
-
import { getProfile, readProfiles } from "./profile/store.ts";
|
|
7
|
-
import { resolveServerUrl } from "./server-url.ts";
|
|
8
|
-
import { applyTemplate } from "./template.ts";
|
|
9
|
-
import {
|
|
10
|
-
createAjv,
|
|
11
|
-
deriveValidationSchemas,
|
|
12
|
-
formatAjvErrors,
|
|
13
|
-
} from "./validate/index.ts";
|
|
14
|
-
|
|
15
|
-
export type RuntimeGlobals = {
|
|
16
|
-
spec?: string;
|
|
17
|
-
server?: string;
|
|
18
|
-
serverVar?: string[];
|
|
19
|
-
|
|
20
|
-
curl?: boolean;
|
|
21
|
-
json?: boolean;
|
|
22
|
-
|
|
23
|
-
auth?: string;
|
|
24
|
-
bearerToken?: string;
|
|
25
|
-
oauthToken?: string;
|
|
26
|
-
username?: string;
|
|
27
|
-
password?: string;
|
|
28
|
-
apiKey?: string;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
function parseKeyValuePairs(
|
|
32
|
-
pairs: string[] | undefined,
|
|
33
|
-
): Record<string, string> {
|
|
34
|
-
const out: Record<string, string> = {};
|
|
35
|
-
for (const pair of pairs ?? []) {
|
|
36
|
-
const idx = pair.indexOf("=");
|
|
37
|
-
if (idx === -1)
|
|
38
|
-
throw new Error(`Invalid pair '${pair}', expected name=value`);
|
|
39
|
-
const name = pair.slice(0, idx).trim();
|
|
40
|
-
const value = pair.slice(idx + 1).trim();
|
|
41
|
-
if (!name) throw new Error(`Invalid pair '${pair}', missing name`);
|
|
42
|
-
out[name] = value;
|
|
43
|
-
}
|
|
44
|
-
return out;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function _parseTimeoutMs(value: string | undefined): number | undefined {
|
|
48
|
-
if (!value) return undefined;
|
|
49
|
-
const n = Number(value);
|
|
50
|
-
if (!Number.isFinite(n) || n <= 0)
|
|
51
|
-
throw new Error("--timeout must be a positive number");
|
|
52
|
-
return n;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function pickAuthSchemeKey(
|
|
56
|
-
action: CommandAction,
|
|
57
|
-
globals: RuntimeGlobals,
|
|
58
|
-
): string | undefined {
|
|
59
|
-
if (globals.auth) return globals.auth;
|
|
60
|
-
|
|
61
|
-
// If operation declares a single requirement set with a single scheme, default to it.
|
|
62
|
-
const req = action.auth.alternatives;
|
|
63
|
-
if (req.length === 1 && req[0]?.length === 1) {
|
|
64
|
-
return req[0][0]?.key;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return undefined;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function applyAuth(
|
|
71
|
-
headers: Headers,
|
|
72
|
-
url: URL,
|
|
73
|
-
action: CommandAction,
|
|
74
|
-
globals: RuntimeGlobals,
|
|
75
|
-
authSchemes: AuthScheme[],
|
|
76
|
-
): { headers: Headers; url: URL } {
|
|
77
|
-
const schemeKey = pickAuthSchemeKey(action, globals);
|
|
78
|
-
if (!schemeKey) return { headers, url };
|
|
79
|
-
|
|
80
|
-
const scheme = authSchemes.find((s) => s.key === schemeKey);
|
|
81
|
-
if (!scheme) {
|
|
82
|
-
throw new Error(
|
|
83
|
-
`Unknown auth scheme '${schemeKey}'. Available: ${authSchemes
|
|
84
|
-
.map((s) => s.key)
|
|
85
|
-
.join(", ")}`,
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (
|
|
90
|
-
scheme.kind === "http-bearer" ||
|
|
91
|
-
scheme.kind === "oauth2" ||
|
|
92
|
-
scheme.kind === "openIdConnect"
|
|
93
|
-
) {
|
|
94
|
-
const token = globals.bearerToken ?? globals.oauthToken;
|
|
95
|
-
if (!token)
|
|
96
|
-
throw new Error("Missing token. Provide --bearer-token <token>.");
|
|
97
|
-
headers.set("Authorization", `Bearer ${token}`);
|
|
98
|
-
return { headers, url };
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (scheme.kind === "http-basic") {
|
|
102
|
-
if (!globals.username) throw new Error("Missing --username for basic auth");
|
|
103
|
-
if (!globals.password) throw new Error("Missing --password for basic auth");
|
|
104
|
-
const raw = `${globals.username}:${globals.password}`;
|
|
105
|
-
const encoded = Buffer.from(raw, "utf8").toString("base64");
|
|
106
|
-
headers.set("Authorization", `Basic ${encoded}`);
|
|
107
|
-
return { headers, url };
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (scheme.kind === "api-key") {
|
|
111
|
-
if (!scheme.name)
|
|
112
|
-
throw new Error(`apiKey scheme '${scheme.key}' missing name`);
|
|
113
|
-
if (!scheme.in)
|
|
114
|
-
throw new Error(`apiKey scheme '${scheme.key}' missing location`);
|
|
115
|
-
if (!globals.apiKey) throw new Error("Missing --api-key for apiKey auth");
|
|
116
|
-
|
|
117
|
-
if (scheme.in === "header") {
|
|
118
|
-
headers.set(scheme.name, globals.apiKey);
|
|
119
|
-
}
|
|
120
|
-
if (scheme.in === "query") {
|
|
121
|
-
url.searchParams.set(scheme.name, globals.apiKey);
|
|
122
|
-
}
|
|
123
|
-
if (scheme.in === "cookie") {
|
|
124
|
-
const existing = headers.get("Cookie");
|
|
125
|
-
const part = `${scheme.name}=${globals.apiKey}`;
|
|
126
|
-
headers.set("Cookie", existing ? `${existing}; ${part}` : part);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return { headers, url };
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return { headers, url };
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export type EmbeddedDefaults = {
|
|
136
|
-
server?: string;
|
|
137
|
-
serverVars?: string[];
|
|
138
|
-
auth?: string;
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
export type BuildRequestInput = {
|
|
142
|
-
specId: string;
|
|
143
|
-
action: CommandAction;
|
|
144
|
-
positionalValues: string[];
|
|
145
|
-
flagValues: Record<string, unknown>;
|
|
146
|
-
globals: RuntimeGlobals;
|
|
147
|
-
servers: import("../server.ts").ServerInfo[];
|
|
148
|
-
authSchemes: AuthScheme[];
|
|
149
|
-
embeddedDefaults?: EmbeddedDefaults;
|
|
150
|
-
bodyFlagDefs?: import("./body-flags.ts").BodyFlagDef[];
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
export async function buildRequest(
|
|
154
|
-
input: BuildRequestInput,
|
|
155
|
-
): Promise<{ request: Request; curl: string }> {
|
|
156
|
-
// Always use the "default" profile for simplicity
|
|
157
|
-
const defaultProfileName = "default";
|
|
158
|
-
const profilesFile = await readProfiles();
|
|
159
|
-
const profile = getProfile(profilesFile, defaultProfileName);
|
|
160
|
-
const embedded = input.embeddedDefaults;
|
|
161
|
-
|
|
162
|
-
// Merge server vars: CLI flags override embedded defaults
|
|
163
|
-
const embeddedServerVars = parseKeyValuePairs(embedded?.serverVars);
|
|
164
|
-
const cliServerVars = parseKeyValuePairs(input.globals.serverVar);
|
|
165
|
-
const serverVars = { ...embeddedServerVars, ...cliServerVars };
|
|
166
|
-
|
|
167
|
-
// Priority: CLI flag > profile > embedded default
|
|
168
|
-
const serverUrl = resolveServerUrl({
|
|
169
|
-
serverOverride: input.globals.server ?? profile?.server ?? embedded?.server,
|
|
170
|
-
servers: input.servers,
|
|
171
|
-
serverVars,
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
// Path params: action.positionals order matches templated params order.
|
|
175
|
-
const pathVars: Record<string, string> = {};
|
|
176
|
-
for (let i = 0; i < input.action.positionals.length; i++) {
|
|
177
|
-
const pos = input.action.positionals[i];
|
|
178
|
-
const raw = input.action.pathArgs[i];
|
|
179
|
-
const value = input.positionalValues[i];
|
|
180
|
-
if (typeof raw === "string" && typeof value === "string") {
|
|
181
|
-
pathVars[raw] = value;
|
|
182
|
-
}
|
|
183
|
-
// Use cli name too as fallback
|
|
184
|
-
if (pos?.name && typeof value === "string") {
|
|
185
|
-
pathVars[pos.name] = value;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const path = applyTemplate(input.action.path, pathVars, { encode: true });
|
|
190
|
-
|
|
191
|
-
// Build the full URL by combining server URL and path.
|
|
192
|
-
// We need to handle the case where path starts with "/" carefully:
|
|
193
|
-
// URL constructor treats absolute paths as relative to origin, not base path.
|
|
194
|
-
const baseUrl = serverUrl.endsWith("/") ? serverUrl : `${serverUrl}/`;
|
|
195
|
-
const relativePath = path.startsWith("/") ? path.slice(1) : path;
|
|
196
|
-
const url = new URL(relativePath, baseUrl);
|
|
197
|
-
|
|
198
|
-
const headers = new Headers();
|
|
199
|
-
|
|
200
|
-
// Collect declared params for validation.
|
|
201
|
-
const queryValues: Record<string, unknown> = {};
|
|
202
|
-
const headerValues: Record<string, unknown> = {};
|
|
203
|
-
const cookieValues: Record<string, unknown> = {};
|
|
204
|
-
|
|
205
|
-
for (const p of input.action.params) {
|
|
206
|
-
if (p.kind !== "flag") continue;
|
|
207
|
-
const optValue = input.flagValues[optionKeyFromFlag(p.flag)];
|
|
208
|
-
if (typeof optValue === "undefined") continue;
|
|
209
|
-
|
|
210
|
-
if (p.in === "query") {
|
|
211
|
-
queryValues[p.name] = optValue;
|
|
212
|
-
}
|
|
213
|
-
if (p.in === "header") {
|
|
214
|
-
headerValues[p.name] = optValue;
|
|
215
|
-
}
|
|
216
|
-
if (p.in === "cookie") {
|
|
217
|
-
cookieValues[p.name] = optValue;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Validate params (query/header/cookie) using Ajv.
|
|
222
|
-
const schemas = deriveValidationSchemas(input.action);
|
|
223
|
-
const ajv = createAjv();
|
|
224
|
-
|
|
225
|
-
if (schemas.querySchema) {
|
|
226
|
-
const validate = ajv.compile(schemas.querySchema);
|
|
227
|
-
if (!validate(queryValues)) {
|
|
228
|
-
throw new Error(formatAjvErrors(validate.errors));
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
if (schemas.headerSchema) {
|
|
232
|
-
const validate = ajv.compile(schemas.headerSchema);
|
|
233
|
-
if (!validate(headerValues)) {
|
|
234
|
-
throw new Error(formatAjvErrors(validate.errors));
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
if (schemas.cookieSchema) {
|
|
238
|
-
const validate = ajv.compile(schemas.cookieSchema);
|
|
239
|
-
if (!validate(cookieValues)) {
|
|
240
|
-
throw new Error(formatAjvErrors(validate.errors));
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Apply params -> query/header/cookie
|
|
245
|
-
for (const [name, value] of Object.entries(queryValues)) {
|
|
246
|
-
if (Array.isArray(value)) {
|
|
247
|
-
for (const item of value) {
|
|
248
|
-
url.searchParams.append(name, String(item));
|
|
249
|
-
}
|
|
250
|
-
continue;
|
|
251
|
-
}
|
|
252
|
-
url.searchParams.set(name, String(value));
|
|
253
|
-
}
|
|
254
|
-
for (const [name, value] of Object.entries(headerValues)) {
|
|
255
|
-
headers.set(name, String(value));
|
|
256
|
-
}
|
|
257
|
-
for (const [name, value] of Object.entries(cookieValues)) {
|
|
258
|
-
const existing = headers.get("Cookie");
|
|
259
|
-
const part = `${name}=${String(value)}`;
|
|
260
|
-
headers.set("Cookie", existing ? `${existing}; ${part}` : part);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
let body: string | undefined;
|
|
264
|
-
if (input.action.requestBody) {
|
|
265
|
-
// Check if any body flags were provided using the flag definitions
|
|
266
|
-
const bodyFlagDefs = input.bodyFlagDefs ?? [];
|
|
267
|
-
const hasBodyFlags = bodyFlagDefs.some((def) => {
|
|
268
|
-
// Commander keeps dots in option names: --address.street -> "address.street"
|
|
269
|
-
const dotKey = def.path.join(".");
|
|
270
|
-
return input.flagValues[dotKey] !== undefined;
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
const contentType = input.action.requestBody.preferredContentType;
|
|
274
|
-
if (contentType) headers.set("Content-Type", contentType);
|
|
275
|
-
|
|
276
|
-
const schema = input.action.requestBodySchema;
|
|
277
|
-
|
|
278
|
-
// Check if there are any required fields in the body
|
|
279
|
-
const requiredFields = bodyFlagDefs.filter((d) => d.required);
|
|
280
|
-
|
|
281
|
-
if (!hasBodyFlags) {
|
|
282
|
-
if (requiredFields.length > 0) {
|
|
283
|
-
// Error: user must provide required fields
|
|
284
|
-
const flagList = requiredFields.map((d) => `--${d.path.join(".")}`);
|
|
285
|
-
throw new Error(`Required: ${flagList.join(", ")}`);
|
|
286
|
-
}
|
|
287
|
-
// No required fields - send empty body if body is required, otherwise skip
|
|
288
|
-
if (input.action.requestBody.required) {
|
|
289
|
-
body = "{}";
|
|
290
|
-
}
|
|
291
|
-
} else {
|
|
292
|
-
if (!contentType?.includes("json")) {
|
|
293
|
-
throw new Error(
|
|
294
|
-
"Body field flags are only supported for JSON request bodies.",
|
|
295
|
-
);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Check for missing required fields
|
|
299
|
-
const { findMissingRequired, parseDotNotationFlags } = await import(
|
|
300
|
-
"./body-flags.ts"
|
|
301
|
-
);
|
|
302
|
-
const missing = findMissingRequired(input.flagValues, bodyFlagDefs);
|
|
303
|
-
if (missing.length > 0) {
|
|
304
|
-
const missingFlags = missing.map((m) => `--${m}`).join(", ");
|
|
305
|
-
throw new Error(`Missing required fields: ${missingFlags}`);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// Build nested object from dot-notation flags
|
|
309
|
-
const built = parseDotNotationFlags(input.flagValues, bodyFlagDefs);
|
|
310
|
-
|
|
311
|
-
if (schema) {
|
|
312
|
-
const validate = ajv.compile(schema);
|
|
313
|
-
if (!validate(built)) {
|
|
314
|
-
throw new Error(formatAjvErrors(validate.errors));
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
body = JSON.stringify(built);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Check if user has a stored token (needed for auth scheme auto-selection)
|
|
323
|
-
const storedToken = profile?.name
|
|
324
|
-
? await getToken(input.specId, profile.name)
|
|
325
|
-
: null;
|
|
326
|
-
|
|
327
|
-
// Auth resolution priority: CLI flag > profile > embedded default
|
|
328
|
-
const resolvedAuthScheme = resolveAuthScheme(
|
|
329
|
-
input.authSchemes,
|
|
330
|
-
input.action.auth,
|
|
331
|
-
{
|
|
332
|
-
flagAuthScheme: input.globals.auth,
|
|
333
|
-
profileAuthScheme: profile?.authScheme,
|
|
334
|
-
embeddedAuthScheme: embedded?.auth,
|
|
335
|
-
hasStoredToken: Boolean(storedToken),
|
|
336
|
-
},
|
|
337
|
-
);
|
|
338
|
-
|
|
339
|
-
const tokenFromProfile = resolvedAuthScheme ? storedToken : null;
|
|
340
|
-
|
|
341
|
-
const globalsWithProfileAuth: RuntimeGlobals = {
|
|
342
|
-
...input.globals,
|
|
343
|
-
auth: resolvedAuthScheme,
|
|
344
|
-
bearerToken:
|
|
345
|
-
input.globals.bearerToken ??
|
|
346
|
-
input.globals.oauthToken ??
|
|
347
|
-
tokenFromProfile ??
|
|
348
|
-
undefined,
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
const final = applyAuth(
|
|
352
|
-
headers,
|
|
353
|
-
url,
|
|
354
|
-
input.action,
|
|
355
|
-
globalsWithProfileAuth,
|
|
356
|
-
input.authSchemes,
|
|
357
|
-
);
|
|
358
|
-
|
|
359
|
-
const req = new Request(final.url.toString(), {
|
|
360
|
-
method: input.action.method,
|
|
361
|
-
headers: final.headers,
|
|
362
|
-
body,
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
const curl = buildCurl(req, body);
|
|
366
|
-
return { request: req, curl };
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
function buildCurl(req: Request, body: string | undefined): string {
|
|
370
|
-
const parts: string[] = ["curl", "-sS", "-X", req.method];
|
|
371
|
-
for (const [k, v] of req.headers.entries()) {
|
|
372
|
-
parts.push("-H", shellQuote(`${k}: ${v}`));
|
|
373
|
-
}
|
|
374
|
-
if (typeof body === "string") {
|
|
375
|
-
parts.push("--data", shellQuote(body));
|
|
376
|
-
}
|
|
377
|
-
parts.push(shellQuote(req.url));
|
|
378
|
-
return parts.join(" ");
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
function shellQuote(value: string): string {
|
|
382
|
-
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
function optionKeyFromFlag(flag: string): string {
|
|
386
|
-
// Commander uses camelCase property names derived from long flag.
|
|
387
|
-
// Example: --x-request-id -> xRequestId
|
|
388
|
-
const name = flag.replace(/^--/, "");
|
|
389
|
-
return name.replace(/-([a-z])/g, (_, c) => String(c).toUpperCase());
|
|
390
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { ServerInfo } from "../server.ts";
|
|
2
|
-
|
|
3
|
-
import { applyTemplate, extractTemplateVars } from "./template.ts";
|
|
4
|
-
|
|
5
|
-
export type ResolveServerInput = {
|
|
6
|
-
serverOverride?: string;
|
|
7
|
-
servers: ServerInfo[];
|
|
8
|
-
serverVars: Record<string, string>;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export function resolveServerUrl(input: ResolveServerInput): string {
|
|
12
|
-
// Treat empty string as undefined (serverOverride can come from env vars or profiles)
|
|
13
|
-
const base = input.serverOverride || input.servers[0]?.url;
|
|
14
|
-
if (!base) {
|
|
15
|
-
throw new Error(
|
|
16
|
-
"No server URL found. Provide --server <url> or define servers in the OpenAPI spec.",
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const names = extractTemplateVars(base);
|
|
21
|
-
if (!names.length) return base;
|
|
22
|
-
|
|
23
|
-
const vars: Record<string, string> = {};
|
|
24
|
-
for (const name of names) {
|
|
25
|
-
const provided = input.serverVars[name];
|
|
26
|
-
if (typeof provided === "string") {
|
|
27
|
-
vars[name] = provided;
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// If spec has default for this var, use it.
|
|
32
|
-
const match = input.servers.find((s) => s.url === base);
|
|
33
|
-
const v = match?.variables.find((x) => x.name === name);
|
|
34
|
-
if (typeof v?.default === "string") {
|
|
35
|
-
vars[name] = v.default;
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
throw new Error(
|
|
40
|
-
`Missing server variable '${name}'. Provide --server-var ${name}=...`,
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return applyTemplate(base, vars);
|
|
45
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export function extractTemplateVars(template: string): string[] {
|
|
2
|
-
const out: string[] = [];
|
|
3
|
-
const re = /\{([^}]+)\}/g;
|
|
4
|
-
while (true) {
|
|
5
|
-
const match = re.exec(template);
|
|
6
|
-
if (!match) break;
|
|
7
|
-
out.push((match[1] ?? "").trim());
|
|
8
|
-
}
|
|
9
|
-
return out.filter(Boolean);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function applyTemplate(
|
|
13
|
-
template: string,
|
|
14
|
-
vars: Record<string, string>,
|
|
15
|
-
options?: { encode?: boolean },
|
|
16
|
-
): string {
|
|
17
|
-
const encode = options?.encode ?? false;
|
|
18
|
-
return template.replace(/\{([^}]+)\}/g, (_, rawName) => {
|
|
19
|
-
const name = String(rawName).trim();
|
|
20
|
-
const value = vars[name];
|
|
21
|
-
if (typeof value !== "string") {
|
|
22
|
-
throw new Error(`Missing template variable: ${name}`);
|
|
23
|
-
}
|
|
24
|
-
return encode ? encodeURIComponent(value) : value;
|
|
25
|
-
});
|
|
26
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { InvalidArgumentError } from "commander";
|
|
2
|
-
|
|
3
|
-
import type { ParamType } from "../../schema-shape.ts";
|
|
4
|
-
|
|
5
|
-
export function coerceValue(raw: string, type: ParamType): unknown {
|
|
6
|
-
if (type === "string" || type === "unknown") return raw;
|
|
7
|
-
|
|
8
|
-
if (type === "boolean") {
|
|
9
|
-
// Commander boolean options are handled without a value; keep for completeness.
|
|
10
|
-
if (raw === "true") return true;
|
|
11
|
-
if (raw === "false") return false;
|
|
12
|
-
throw new InvalidArgumentError(`Expected boolean, got '${raw}'`);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (type === "integer") {
|
|
16
|
-
const n = Number.parseInt(raw, 10);
|
|
17
|
-
if (!Number.isFinite(n))
|
|
18
|
-
throw new InvalidArgumentError(`Expected integer, got '${raw}'`);
|
|
19
|
-
return n;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (type === "number") {
|
|
23
|
-
const n = Number(raw);
|
|
24
|
-
if (!Number.isFinite(n))
|
|
25
|
-
throw new InvalidArgumentError(`Expected number, got '${raw}'`);
|
|
26
|
-
return n;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// For now, accept objects as JSON strings.
|
|
30
|
-
if (type === "object") {
|
|
31
|
-
try {
|
|
32
|
-
return JSON.parse(raw);
|
|
33
|
-
} catch {
|
|
34
|
-
throw new InvalidArgumentError(
|
|
35
|
-
`Expected JSON object, got '${raw}'. Use --data/--file for complex bodies.`,
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Arrays should usually be passed as repeatable flags or comma-separated,
|
|
41
|
-
// but allow JSON arrays too.
|
|
42
|
-
if (type === "array") {
|
|
43
|
-
return coerceArrayInput(raw, "string");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return raw;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function coerceArrayInput(raw: string, itemType: ParamType): unknown[] {
|
|
50
|
-
const trimmed = raw.trim();
|
|
51
|
-
if (!trimmed) return [];
|
|
52
|
-
|
|
53
|
-
if (trimmed.startsWith("[")) {
|
|
54
|
-
let parsed: unknown;
|
|
55
|
-
try {
|
|
56
|
-
parsed = JSON.parse(trimmed);
|
|
57
|
-
} catch {
|
|
58
|
-
throw new InvalidArgumentError(`Expected JSON array, got '${raw}'`);
|
|
59
|
-
}
|
|
60
|
-
if (!Array.isArray(parsed)) {
|
|
61
|
-
throw new InvalidArgumentError(`Expected JSON array, got '${raw}'`);
|
|
62
|
-
}
|
|
63
|
-
return parsed.map((v) => coerceValue(String(v), itemType));
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return trimmed
|
|
67
|
-
.split(",")
|
|
68
|
-
.map((s) => s.trim())
|
|
69
|
-
.filter(Boolean)
|
|
70
|
-
.map((s) => coerceValue(s, itemType));
|
|
71
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { ErrorObject } from "ajv";
|
|
2
|
-
|
|
3
|
-
export function formatAjvErrors(
|
|
4
|
-
errors: ErrorObject[] | null | undefined,
|
|
5
|
-
): string {
|
|
6
|
-
if (!errors?.length) return "Invalid input";
|
|
7
|
-
|
|
8
|
-
return errors
|
|
9
|
-
.map((e) => {
|
|
10
|
-
const path = e.instancePath || e.schemaPath || "";
|
|
11
|
-
|
|
12
|
-
if (
|
|
13
|
-
e.keyword === "required" &&
|
|
14
|
-
e.params &&
|
|
15
|
-
typeof e.params === "object" &&
|
|
16
|
-
"missingProperty" in e.params
|
|
17
|
-
) {
|
|
18
|
-
const missing = String(
|
|
19
|
-
(e.params as { missingProperty?: unknown }).missingProperty,
|
|
20
|
-
);
|
|
21
|
-
const where = e.instancePath || "/";
|
|
22
|
-
return `${where} missing required property '${missing}'`.trim();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const msg = e.message || "invalid";
|
|
26
|
-
return `${path} ${msg}`.trim();
|
|
27
|
-
})
|
|
28
|
-
.join("\n");
|
|
29
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import type { CommandAction } from "../../command-model.ts";
|
|
2
|
-
import type { JsonSchema } from "../../types.ts";
|
|
3
|
-
|
|
4
|
-
export type ValidationSchemas = {
|
|
5
|
-
querySchema?: JsonSchema;
|
|
6
|
-
headerSchema?: JsonSchema;
|
|
7
|
-
cookieSchema?: JsonSchema;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
type ObjectSchema = {
|
|
11
|
-
type: "object";
|
|
12
|
-
properties: Record<string, JsonSchema>;
|
|
13
|
-
required?: string[];
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export function deriveValidationSchemas(
|
|
17
|
-
action: CommandAction,
|
|
18
|
-
): ValidationSchemas {
|
|
19
|
-
// We validate only simple containers for now.
|
|
20
|
-
// Deep style/encoding differences for OpenAPI params are out of scope for v1.
|
|
21
|
-
const query: ObjectSchema = { type: "object", properties: {}, required: [] };
|
|
22
|
-
const header: ObjectSchema = { type: "object", properties: {}, required: [] };
|
|
23
|
-
const cookie: ObjectSchema = { type: "object", properties: {}, required: [] };
|
|
24
|
-
|
|
25
|
-
for (const p of action.params) {
|
|
26
|
-
if (p.kind !== "flag") continue;
|
|
27
|
-
const target =
|
|
28
|
-
p.in === "query"
|
|
29
|
-
? query
|
|
30
|
-
: p.in === "header"
|
|
31
|
-
? header
|
|
32
|
-
: p.in === "cookie"
|
|
33
|
-
? cookie
|
|
34
|
-
: undefined;
|
|
35
|
-
if (!target) continue;
|
|
36
|
-
|
|
37
|
-
const schema = p.schema ?? (p.type === "unknown" ? {} : { type: p.type });
|
|
38
|
-
target.properties[p.name] = schema;
|
|
39
|
-
if (p.required) {
|
|
40
|
-
if (!target.required) target.required = [];
|
|
41
|
-
target.required.push(p.name);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (!query.required?.length) delete query.required;
|
|
46
|
-
if (!header.required?.length) delete header.required;
|
|
47
|
-
if (!cookie.required?.length) delete cookie.required;
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
querySchema: Object.keys(query.properties).length ? query : undefined,
|
|
51
|
-
headerSchema: Object.keys(header.properties).length ? header : undefined,
|
|
52
|
-
cookieSchema: Object.keys(cookie.properties).length ? cookie : undefined,
|
|
53
|
-
};
|
|
54
|
-
}
|
package/src/cli/schema-shape.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
export type ParamType =
|
|
2
|
-
| "string"
|
|
3
|
-
| "number"
|
|
4
|
-
| "integer"
|
|
5
|
-
| "boolean"
|
|
6
|
-
| "array"
|
|
7
|
-
| "object"
|
|
8
|
-
| "unknown";
|
|
9
|
-
|
|
10
|
-
export function getSchemaType(schema: unknown): ParamType {
|
|
11
|
-
if (!schema || typeof schema !== "object") return "unknown";
|
|
12
|
-
const t = (schema as { type?: unknown }).type;
|
|
13
|
-
if (t === "string") return "string";
|
|
14
|
-
if (t === "number") return "number";
|
|
15
|
-
if (t === "integer") return "integer";
|
|
16
|
-
if (t === "boolean") return "boolean";
|
|
17
|
-
if (t === "array") return "array";
|
|
18
|
-
if (t === "object") return "object";
|
|
19
|
-
return "unknown";
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function getSchemaFormat(schema: unknown): string | undefined {
|
|
23
|
-
if (!schema || typeof schema !== "object") return undefined;
|
|
24
|
-
const f = (schema as { format?: unknown }).format;
|
|
25
|
-
return typeof f === "string" ? f : undefined;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function getSchemaEnumStrings(schema: unknown): string[] | undefined {
|
|
29
|
-
if (!schema || typeof schema !== "object") return undefined;
|
|
30
|
-
const e = (schema as { enum?: unknown }).enum;
|
|
31
|
-
if (!Array.isArray(e)) return undefined;
|
|
32
|
-
|
|
33
|
-
// We only surface string enums for now (enough for flag docs + completion).
|
|
34
|
-
const values = e.filter((v) => typeof v === "string") as string[];
|
|
35
|
-
return values.length ? values : undefined;
|
|
36
|
-
}
|