carrick 0.3.70 → 0.3.72
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 +10 -2
- package/bin/carrick.mjs +4 -1
- package/dist/contract.d.ts +3 -0
- package/dist/contract.js.map +1 -1
- package/dist/init/doctor.d.ts +3 -1
- package/dist/init/doctor.js +33 -6
- package/dist/init/doctor.js.map +1 -1
- package/dist/init/install-id.d.ts +32 -0
- package/dist/init/install-id.js +118 -0
- package/dist/init/install-id.js.map +1 -0
- package/dist/init/mcp.d.ts +59 -5
- package/dist/init/mcp.js +133 -27
- package/dist/init/mcp.js.map +1 -1
- package/dist/init/remove.d.ts +4 -0
- package/dist/init/remove.js +26 -5
- package/dist/init/remove.js.map +1 -1
- package/dist/init/run.d.ts +8 -0
- package/dist/init/run.js +20 -2
- package/dist/init/run.js.map +1 -1
- package/dist/native.d.ts +25 -5
- package/dist/native.js +41 -10
- package/dist/native.js.map +1 -1
- package/dist/render.js +7 -2
- package/dist/render.js.map +1 -1
- package/package.json +6 -6
- package/sidecar/dist/src/capture/api.d.ts +5 -1
- package/sidecar/dist/src/type-inferrer.d.ts +119 -19
- package/sidecar/dist/src/type-inferrer.js +413 -54
- package/sidecar/dist/src/type-structural-expander.d.ts +32 -3
- package/sidecar/dist/src/type-structural-expander.js +67 -16
|
@@ -36,17 +36,54 @@ import { canonicalizeUnionsInText } from './type-text-canonicalizer.js';
|
|
|
36
36
|
* cycle set somehow misses.
|
|
37
37
|
*/
|
|
38
38
|
export const MAX_EXPANSION_DEPTH = 12;
|
|
39
|
+
/** True when some override sits strictly below `position`. */
|
|
40
|
+
function hasOverrideBelow({ overrides, position }) {
|
|
41
|
+
for (const key of overrides.types.keys()) {
|
|
42
|
+
if (position === ''
|
|
43
|
+
? key !== ''
|
|
44
|
+
: key.startsWith(`${position}.`) || key.startsWith(`${position}<`)) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
function childCursor(cursor, segment) {
|
|
51
|
+
if (!cursor)
|
|
52
|
+
return undefined;
|
|
53
|
+
const position = segment.startsWith('<')
|
|
54
|
+
? `${cursor.position}${segment}`
|
|
55
|
+
: cursor.position === ''
|
|
56
|
+
? segment
|
|
57
|
+
: `${cursor.position}.${segment}`;
|
|
58
|
+
return { overrides: cursor.overrides, position };
|
|
59
|
+
}
|
|
39
60
|
/**
|
|
40
61
|
* Recursively render a `Type` as fully-inlined structural text.
|
|
41
62
|
*
|
|
42
63
|
* Named object/interface types are expanded to their member structure;
|
|
43
64
|
* primitives, literals, library types (`Date`, `Promise`, tuples, …) and
|
|
44
65
|
* functions stay by name. The `seen` set (object type ids on the current
|
|
45
|
-
* branch) breaks reference cycles; `depth` is a hard backstop.
|
|
66
|
+
* branch) breaks reference cycles; `depth` is a hard backstop. `overrides`
|
|
67
|
+
* substitutes a type at named member positions (`MemberOverrides`); without
|
|
68
|
+
* it the print is unchanged.
|
|
46
69
|
*/
|
|
47
|
-
export function expandTypeStructural(type, seen = new Set(), depth = 0) {
|
|
70
|
+
export function expandTypeStructural(type, seen = new Set(), depth = 0, overrides) {
|
|
71
|
+
return expandAt(type, seen, depth, overrides ? { overrides, position: '' } : undefined);
|
|
72
|
+
}
|
|
73
|
+
function expandAt(type, seen, depth, at) {
|
|
48
74
|
if (depth > MAX_EXPANSION_DEPTH)
|
|
49
75
|
return backstopText(type);
|
|
76
|
+
let cursor = at;
|
|
77
|
+
if (cursor) {
|
|
78
|
+
const replacement = cursor.overrides.types.get(cursor.position);
|
|
79
|
+
if (replacement) {
|
|
80
|
+
cursor.overrides.applied.add(cursor.position);
|
|
81
|
+
return expandAt(replacement, seen, depth, undefined);
|
|
82
|
+
}
|
|
83
|
+
// Nothing to substitute below here: print exactly as without overrides.
|
|
84
|
+
if (!hasOverrideBelow(cursor))
|
|
85
|
+
cursor = undefined;
|
|
86
|
+
}
|
|
50
87
|
// Primitives & literals: nothing to inline.
|
|
51
88
|
if (type.isString() ||
|
|
52
89
|
type.isNumber() ||
|
|
@@ -65,10 +102,10 @@ export function expandTypeStructural(type, seen = new Set(), depth = 0) {
|
|
|
65
102
|
}
|
|
66
103
|
// Unions / intersections: expand each member, in canonical order.
|
|
67
104
|
if (type.isUnion()) {
|
|
68
|
-
return canonicalMembers(type.getUnionTypes(), seen, depth).join(' | ');
|
|
105
|
+
return canonicalMembers(type.getUnionTypes(), seen, depth, cursor).join(' | ');
|
|
69
106
|
}
|
|
70
107
|
if (type.isIntersection()) {
|
|
71
|
-
return canonicalMembers(type.getIntersectionTypes(), seen, depth).join(' & ');
|
|
108
|
+
return canonicalMembers(type.getIntersectionTypes(), seen, depth, cursor).join(' & ');
|
|
72
109
|
}
|
|
73
110
|
// Tuples are array-like but must keep their `[a, b]` shape, not be walked
|
|
74
111
|
// as objects (which explodes into `Array.prototype`). Handle before arrays.
|
|
@@ -79,7 +116,7 @@ export function expandTypeStructural(type, seen = new Set(), depth = 0) {
|
|
|
79
116
|
const element = type.getArrayElementType();
|
|
80
117
|
if (!element)
|
|
81
118
|
return namedText(type);
|
|
82
|
-
const inner =
|
|
119
|
+
const inner = expandAt(element, seen, depth + 1, childCursor(cursor, '<0>'));
|
|
83
120
|
// Parenthesise a union/intersection element so `(A | B)[]` doesn't misparse
|
|
84
121
|
// as `A | B[]`. Decide from the TYPE, not the string: a single object
|
|
85
122
|
// literal like `{ a: A | B }` is NOT a union and must not be parenthesised,
|
|
@@ -87,8 +124,10 @@ export function expandTypeStructural(type, seen = new Set(), depth = 0) {
|
|
|
87
124
|
const needsParens = element.isUnion() || element.isIntersection();
|
|
88
125
|
return needsParens ? `(${inner})[]` : `${inner}[]`;
|
|
89
126
|
}
|
|
90
|
-
// Library / built-in types (Date, Promise, RegExp, …): keep by name
|
|
91
|
-
|
|
127
|
+
// Library / built-in types (Date, Promise, RegExp, …): keep by name, unless
|
|
128
|
+
// a member below has to be substituted — a schema library declares its
|
|
129
|
+
// inferred object types itself, and they are only walkable, not by-name.
|
|
130
|
+
if (!cursor && isLibraryType(type)) {
|
|
92
131
|
return namedText(type);
|
|
93
132
|
}
|
|
94
133
|
// Callable/constructable object types (functions): keep by name; their
|
|
@@ -105,7 +144,7 @@ export function expandTypeStructural(type, seen = new Set(), depth = 0) {
|
|
|
105
144
|
const props = type.getProperties();
|
|
106
145
|
if (props.length === 0)
|
|
107
146
|
return namedText(type);
|
|
108
|
-
const parts = props.map((prop) => expandProperty(prop, nextSeen, depth));
|
|
147
|
+
const parts = props.map((prop) => expandProperty(prop, nextSeen, depth, cursor));
|
|
109
148
|
return `{ ${parts.join('; ')}; }`;
|
|
110
149
|
}
|
|
111
150
|
return namedText(type);
|
|
@@ -164,8 +203,8 @@ function backstopText(type) {
|
|
|
164
203
|
* Ties can only happen between two members that render identically, in which
|
|
165
204
|
* case the joined output is the same whichever way round they go.
|
|
166
205
|
*/
|
|
167
|
-
function canonicalMembers(members, seen, depth) {
|
|
168
|
-
return orderMembers(members, (member) =>
|
|
206
|
+
function canonicalMembers(members, seen, depth, cursor) {
|
|
207
|
+
return orderMembers(members, (member) => expandAt(member, seen, depth + 1, cursor));
|
|
169
208
|
}
|
|
170
209
|
/**
|
|
171
210
|
* The canonical order itself, over whatever text `render` gives each member.
|
|
@@ -186,16 +225,28 @@ function orderMembers(members, render) {
|
|
|
186
225
|
return rendered.map((entry) => entry.text);
|
|
187
226
|
}
|
|
188
227
|
/** Render a single property as `name[?]: <expanded>`. */
|
|
189
|
-
function expandProperty(prop, seen, depth) {
|
|
228
|
+
function expandProperty(prop, seen, depth, at) {
|
|
190
229
|
const optional = (prop.getFlags() & ts.SymbolFlags.Optional) !== 0;
|
|
191
230
|
const propDecl = prop.getDeclarations()[0];
|
|
192
231
|
// Render the key from the declaration's name node so quoted/computed keys
|
|
193
232
|
// ('x-y', "x y", [Symbol.iterator]) survive as valid TS text rather than
|
|
194
233
|
// being unquoted into invalid output; fall back to the bare symbol name.
|
|
195
234
|
const name = renderPropertyName(prop, propDecl);
|
|
196
|
-
let propType =
|
|
197
|
-
? prop.getTypeAtLocation(
|
|
198
|
-
:
|
|
235
|
+
let propType = at
|
|
236
|
+
? prop.getTypeAtLocation(at.overrides.at)
|
|
237
|
+
: propDecl
|
|
238
|
+
? prop.getTypeAtLocation(propDecl)
|
|
239
|
+
: prop.getDeclaredType();
|
|
240
|
+
// A substituted member takes the override's TYPE but keeps this key's
|
|
241
|
+
// optionality, and is looked up before the `undefined` strip below so an
|
|
242
|
+
// override that carries `| undefined` strips like any other optional key.
|
|
243
|
+
let cursor = childCursor(at, prop.getName());
|
|
244
|
+
const replacement = cursor && cursor.overrides.types.get(cursor.position);
|
|
245
|
+
if (cursor && replacement) {
|
|
246
|
+
cursor.overrides.applied.add(cursor.position);
|
|
247
|
+
propType = replacement;
|
|
248
|
+
cursor = undefined;
|
|
249
|
+
}
|
|
199
250
|
// An optional property's type includes `undefined`; the structural label
|
|
200
251
|
// drops it (`note?: string`, not `note?: string | undefined`).
|
|
201
252
|
if (optional && propType.isUnion()) {
|
|
@@ -206,11 +257,11 @@ function expandProperty(prop, seen, depth) {
|
|
|
206
257
|
propType = nonUndefined[0];
|
|
207
258
|
}
|
|
208
259
|
else if (nonUndefined.length > 1) {
|
|
209
|
-
const inner = canonicalMembers(nonUndefined, seen, depth).join(' | ');
|
|
260
|
+
const inner = canonicalMembers(nonUndefined, seen, depth, cursor).join(' | ');
|
|
210
261
|
return `${name}?: ${inner}`;
|
|
211
262
|
}
|
|
212
263
|
}
|
|
213
|
-
const inner =
|
|
264
|
+
const inner = expandAt(propType, seen, depth + 1, cursor);
|
|
214
265
|
return `${name}${optional ? '?' : ''}: ${inner}`;
|
|
215
266
|
}
|
|
216
267
|
/**
|