@typeship-ax/cli 0.23.1 → 0.24.0
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/AGENTS.md +2 -2
- package/README.md +2 -2
- package/api.md +2 -2
- package/dist/arguments.d.ts +9 -2
- package/dist/arguments.d.ts.map +1 -1
- package/dist/arguments.js +17 -6
- package/dist/cli-agent.d.ts +42 -1
- package/dist/cli-agent.d.ts.map +1 -1
- package/dist/cli-agent.js +187 -18
- package/dist/cli.js +341 -76
- package/dist/fields.d.ts +8 -1
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +91 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/ops.d.ts +5 -0
- package/dist/ops.d.ts.map +1 -1
- package/dist/ops.js +66 -6
- package/dist/resources/deliveries.d.ts +1 -1
- package/dist/resources/deliveries.d.ts.map +1 -1
- package/dist/resources/deliveries.js +1 -1
- package/dist/resources/drafts.d.ts +1 -1
- package/dist/resources/drafts.d.ts.map +1 -1
- package/dist/resources/drafts.js +1 -1
- package/dist/resources/generations.d.ts +2 -2
- package/dist/resources/generations.d.ts.map +1 -1
- package/dist/resources/generations.js +2 -2
- package/dist/resources/releases.d.ts +1 -1
- package/dist/resources/releases.d.ts.map +1 -1
- package/dist/resources/releases.js +1 -1
- package/dist/resources/spec-revisions.d.ts +1 -1
- package/dist/resources/spec-revisions.d.ts.map +1 -1
- package/dist/resources/spec-revisions.js +1 -1
- package/dist/resources/targets.d.ts +1 -1
- package/dist/resources/targets.d.ts.map +1 -1
- package/dist/resources/targets.js +1 -1
- package/dist/table.d.ts +28 -0
- package/dist/table.d.ts.map +1 -0
- package/dist/table.js +167 -0
- package/dist/type-docs.d.ts +61 -0
- package/dist/type-docs.d.ts.map +1 -0
- package/dist/type-docs.js +174 -0
- package/package.json +1 -1
- package/src/arguments.ts +19 -7
- package/src/cli-agent.ts +196 -17
- package/src/cli.ts +330 -76
- package/src/fields.ts +81 -5
- package/src/index.ts +3 -3
- package/src/ops.ts +69 -6
- package/src/resources/deliveries.ts +2 -2
- package/src/resources/drafts.ts +2 -2
- package/src/resources/generations.ts +4 -4
- package/src/resources/releases.ts +2 -2
- package/src/resources/spec-revisions.ts +2 -2
- package/src/resources/targets.ts +2 -2
- package/src/table.ts +167 -0
- package/src/type-docs.ts +205 -0
package/src/fields.ts
CHANGED
|
@@ -42,24 +42,34 @@ export interface UnmatchedField {
|
|
|
42
42
|
* at least one item has it; reaching null or an empty array counts as a
|
|
43
43
|
* match, because the path may be right and the values merely empty. An
|
|
44
44
|
* empty result matches everything.
|
|
45
|
+
*
|
|
46
|
+
* `schema` is the JSON Schema of `value` (the operation's declared
|
|
47
|
+
* response, or its item schema for a list). A key the schema declares may
|
|
48
|
+
* be absent from every item, as optional fields are: the path matches, and
|
|
49
|
+
* projects to nothing. What the schema cannot vouch for (no schema, an
|
|
50
|
+
* object without properties, a key it does not list) still has to be in
|
|
51
|
+
* the data.
|
|
45
52
|
*/
|
|
46
|
-
export function unmatchedFields(value: unknown, paths: string[][]): UnmatchedField[] {
|
|
53
|
+
export function unmatchedFields(value: unknown, paths: string[][], schema?: unknown): UnmatchedField[] {
|
|
47
54
|
const out: UnmatchedField[] = [];
|
|
48
55
|
for (const path of paths) {
|
|
49
56
|
const miss = { depth: -1, keys: new Set<string>(), segment: null as string | null };
|
|
50
|
-
if (!pathMatches(value, path, 0, miss)) {
|
|
57
|
+
if (!pathMatches(value, path, 0, miss, schema)) {
|
|
51
58
|
out.push({ path: path.join("."), available: [...miss.keys].slice(0, 40), missing: miss.segment });
|
|
52
59
|
}
|
|
53
60
|
}
|
|
54
61
|
return out;
|
|
55
62
|
}
|
|
56
63
|
|
|
57
|
-
|
|
64
|
+
type Miss = { depth: number; keys: Set<string>; segment: string | null };
|
|
65
|
+
|
|
66
|
+
function pathMatches(value: unknown, path: string[], index: number, miss: Miss, schema: unknown): boolean {
|
|
58
67
|
if (value === null || value === undefined) return true;
|
|
59
68
|
if (Array.isArray(value)) {
|
|
60
69
|
if (value.length === 0) return true;
|
|
70
|
+
const items = arrayItems(schema);
|
|
61
71
|
let any = false;
|
|
62
|
-
for (const item of value) if (pathMatches(item, path, index, miss)) any = true;
|
|
72
|
+
for (const item of value) if (pathMatches(item, path, index, miss, items)) any = true;
|
|
63
73
|
return any;
|
|
64
74
|
}
|
|
65
75
|
if (index === path.length) return true;
|
|
@@ -70,11 +80,77 @@ function pathMatches(value: unknown, path: string[], index: number, miss: { dept
|
|
|
70
80
|
const key = path[index]!;
|
|
71
81
|
const record = value as Record<string, unknown>;
|
|
72
82
|
if (!Object.hasOwn(record, key)) {
|
|
83
|
+
const declared = declaredProperty(schema, key);
|
|
84
|
+
if (declared !== undefined) return declaredPath(declared, path, index + 1, miss);
|
|
73
85
|
if (miss.depth < index) { miss.depth = index; miss.keys = new Set(); miss.segment = key; }
|
|
74
86
|
if (miss.depth === index) for (const k of Object.keys(record)) miss.keys.add(k);
|
|
75
87
|
return false;
|
|
76
88
|
}
|
|
77
|
-
return pathMatches(record[key], path, index + 1, miss);
|
|
89
|
+
return pathMatches(record[key], path, index + 1, miss, declaredProperty(schema, key));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** The rest of a path below a declared key no item has: nothing in the data
|
|
93
|
+
* can contradict it, so it matches unless the schema lists that level's
|
|
94
|
+
* keys and the next segment is not one of them. */
|
|
95
|
+
function declaredPath(schema: unknown, path: string[], index: number, miss: Miss): boolean {
|
|
96
|
+
if (index === path.length) return true;
|
|
97
|
+
const key = path[index]!;
|
|
98
|
+
const declared = declaredProperty(schema, key);
|
|
99
|
+
if (declared !== undefined) return declaredPath(declared, path, index + 1, miss);
|
|
100
|
+
const listed = listedProperties(schema);
|
|
101
|
+
if (listed === null) return true;
|
|
102
|
+
if (miss.depth < index) { miss.depth = index; miss.keys = new Set(); miss.segment = key; }
|
|
103
|
+
if (miss.depth === index) for (const k of listed) miss.keys.add(k);
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** A schema with its allOf, anyOf and oneOf branches flattened, arrays
|
|
108
|
+
* seen through to their items. */
|
|
109
|
+
function variants(schema: unknown, out: Record<string, unknown>[] = []): Record<string, unknown>[] {
|
|
110
|
+
if (schema === null || typeof schema !== "object" || Array.isArray(schema)) return out;
|
|
111
|
+
const node = schema as Record<string, unknown>;
|
|
112
|
+
out.push(node);
|
|
113
|
+
for (const key of ["allOf", "anyOf", "oneOf"]) {
|
|
114
|
+
const branches = node[key];
|
|
115
|
+
if (Array.isArray(branches)) for (const branch of branches) variants(branch, out);
|
|
116
|
+
}
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function arrayItems(schema: unknown): unknown {
|
|
121
|
+
const items = variants(schema).map((node) => node.items).filter((item) => item !== undefined && item !== null);
|
|
122
|
+
return items.length === 0 ? undefined : items.length === 1 ? items[0] : { anyOf: items };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** The schema of `key` when some branch declares it, else undefined. */
|
|
126
|
+
function declaredProperty(schema: unknown, key: string): unknown {
|
|
127
|
+
const found = variants(schema).flatMap((node) => {
|
|
128
|
+
const properties = node.properties as Record<string, unknown> | undefined;
|
|
129
|
+
return properties && typeof properties === "object" && Object.hasOwn(properties, key) ? [properties[key] ?? {}] : [];
|
|
130
|
+
});
|
|
131
|
+
return found.length === 0 ? undefined : found.length === 1 ? found[0] : { anyOf: found };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Every key the schema declares, or null when it cannot say which keys
|
|
135
|
+
* exist: no schema, an object without properties, or one that admits more. */
|
|
136
|
+
function listedProperties(schema: unknown): string[] | null {
|
|
137
|
+
const nodes = variants(schema);
|
|
138
|
+
const keys: string[] = [];
|
|
139
|
+
let closed = false;
|
|
140
|
+
for (const node of nodes) {
|
|
141
|
+
const properties = node.properties as Record<string, unknown> | undefined;
|
|
142
|
+
if (properties && typeof properties === "object") {
|
|
143
|
+
closed = true;
|
|
144
|
+
keys.push(...Object.keys(properties));
|
|
145
|
+
}
|
|
146
|
+
if (node.additionalProperties !== undefined && node.additionalProperties !== false) return null;
|
|
147
|
+
if (node.patternProperties !== undefined) return null;
|
|
148
|
+
// Tool schemas keep the first eight variants of a union; more may exist.
|
|
149
|
+
if (Array.isArray(node.anyOf) && node.anyOf.length >= 8) return null;
|
|
150
|
+
}
|
|
151
|
+
// A branch that is an object without listed properties is open.
|
|
152
|
+
if (nodes.some((node) => node.properties === undefined && (node.type === "object" || (Array.isArray(node.type) && node.type.includes("object"))))) return null;
|
|
153
|
+
return closed ? [...new Set(keys)] : null;
|
|
78
154
|
}
|
|
79
155
|
|
|
80
156
|
/** The error message: the call went through, and for each unmatched path,
|
package/src/index.ts
CHANGED
|
@@ -25,8 +25,8 @@ import { OrganizationResource } from "./resources/organization.js";
|
|
|
25
25
|
import { ApiKeysResource } from "./resources/api-keys.js";
|
|
26
26
|
|
|
27
27
|
/** This package's version, also sent as the `User-Agent`. */
|
|
28
|
-
export const VERSION = "0.
|
|
29
|
-
const USER_AGENT = "@typeship-ax/cli/0.
|
|
28
|
+
export const VERSION = "0.24.0";
|
|
29
|
+
const USER_AGENT = "@typeship-ax/cli/0.24.0";
|
|
30
30
|
|
|
31
31
|
export interface ClientOptions {
|
|
32
32
|
/** Override the server URL. Default: `https://typeship.dev/api/v1` */
|
|
@@ -87,7 +87,7 @@ export interface ClientOptions {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
|
-
* Typeship — v0.
|
|
90
|
+
* Typeship — v0.24.0
|
|
91
91
|
*
|
|
92
92
|
* Resolve an OpenAPI or GraphQL Spec, diagnose it, and keep every
|
|
93
93
|
* selected CLI, MCP, and SDK Target current.
|