@mirascript/typed 0.1.64 → 0.1.70
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 +38 -27
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/json.d.ts +5 -2
- package/dist/json.d.ts.map +1 -1
- package/dist/json.js +129 -48
- package/dist/json.js.map +1 -1
- package/dist/parser.d.ts +29 -1
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +13 -0
- package/dist/parser.js.map +1 -1
- package/dist/simplifier.d.ts +48 -0
- package/dist/simplifier.d.ts.map +1 -0
- package/dist/simplifier.js +332 -0
- package/dist/simplifier.js.map +1 -0
- package/dist/stringify.d.ts +7 -0
- package/dist/stringify.d.ts.map +1 -0
- package/dist/stringify.js +186 -0
- package/dist/stringify.js.map +1 -0
- package/dist/type.js +601 -289
- package/dist/type.js.map +1 -1
- package/package.json +7 -6
- package/src/index.ts +2 -0
- package/src/json.ts +142 -59
- package/src/parser.ts +49 -1
- package/src/simplifier.ts +404 -0
- package/src/stringify.ts +191 -0
- package/src/type.peggy +49 -2
package/dist/type.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/type.peggy"],"names":["$top_level_initializer","Start","UnionType","PostfixType","PrimaryType","TypeParamList","TypeArgList","FunctionType","NamedFunction","FunctionBody","FunctionParamList","FunctionParam","RecordType","FieldList","Field","FieldName","HexDigit","EscapeSequence","String","DoubleQuotePart","SingleQuotePart","BacktickPart","DoubleQuoteChar","SingleQuoteChar","BacktickChar","Identifier","_","$initializer"],"mappings":";;;;;AAAEA;AACFA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA
|
|
1
|
+
{"version":3,"sources":["../src/type.peggy"],"names":["$top_level_initializer","Start","UnionType","IntersectionType","PostfixType","PrimaryType","ReflectionType","TupleType","TupleElementList","TupleElement","TypeParamList","TypeArgList","FunctionType","NamedFunction","FunctionBody","FunctionParamList","FunctionParam","RecordType","FieldList","Field","FieldName","HexDigit","EscapeSequence","String","DoubleQuotePart","SingleQuotePart","BacktickPart","DoubleQuoteChar","SingleQuoteChar","BacktickChar","Identifier","_","$initializer"],"mappings":";;;;;AAAEA;AACFA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBA2DoD;AACpD;AACI,G;sBAG2C;AAC/C;AACI,G;iCAOmC;AACvC;AACA;AACA;AACA;AACI,G;kCAUuD;AAC3D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACI,G;wBACY;AAChB;AACA;AACI,G;yBAUsC;AAC1C;AACI,G;6BAOwC;AAC5C;AACI,G;iCAM0B;AAC9B;AACI,G;yBAkB0B,gBAAc,G;+BAGI;AAChD;AACA;AACA;AACI,G;6CAG0G;AAC9G;AACA;AACA;AACA;AACI,G;4BAGkD;AACtD;AACA;AACA;AACA;AACI,G;qCAGiD;AACrD;AACA;AACA;AACA;AACA;AACI,G;6BACoC;AACxC;AACI,G;4BAO+B,gCAA8B,G;kCAMnB;AAC9C;AACA;AACA;AACA;AACA;AACI,G;0BACW,oBAAkB,G;0BAIhB;AACjB;AACA;AACI,G;0BAU6B;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACE,G;yBAAoC;AACtC;AACA;AACA;AACA;AACE,G;yBAAiC;AACnC;AACA;AACA;AACA;AACA;AACA;AACE,G;2BAGkC,yBAAuB,G;2BACvB,yBAAuB,G;2BAC1B,yBAAuB,G;2BAI5B,mCAAiC,G;2BAIjC,mCAAiC,G;2BAIpC,mCAAiC,G;;;;;;;;;;;;;;;;;;;;;;;;;;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","file":"type.js"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mirascript/typed",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.70",
|
|
4
4
|
"author": "CloudPSS",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Parse MiraScript type definitions and generate TypeScript types / JSON schemas.",
|
|
@@ -23,15 +23,16 @@
|
|
|
23
23
|
"./package.json": "./package.json"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@types/node": "^26.
|
|
26
|
+
"@types/node": "^26.1.1",
|
|
27
27
|
"ava": "^8.0.1",
|
|
28
28
|
"c8": "^11.0.0",
|
|
29
|
-
"js-yaml": "^5.2.
|
|
30
|
-
"peggy": "^5.1.0"
|
|
29
|
+
"js-yaml": "^5.2.1",
|
|
30
|
+
"peggy": "^5.1.0",
|
|
31
|
+
"@mirascript/mirascript": "~0.1.70"
|
|
31
32
|
},
|
|
32
33
|
"dependencies": {
|
|
33
|
-
"
|
|
34
|
-
"@mirascript/constants": "~0.1.
|
|
34
|
+
"json-schema-typed": "^8.0.2",
|
|
35
|
+
"@mirascript/constants": "~0.1.70"
|
|
35
36
|
},
|
|
36
37
|
"scripts": {
|
|
37
38
|
"build": "peggy src/type.peggy --multi-output ./dist --dts --format es --source-map && tsc",
|
package/src/index.ts
CHANGED
package/src/json.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type JSONSchema, $schema } from 'json-schema-typed';
|
|
2
2
|
import { REG_NUMBER } from '@mirascript/constants';
|
|
3
|
+
import { simplify } from './simplifier.js';
|
|
3
4
|
import type { KnownType, LiteralType, NamedType, TemplateType, Type } from './parser.js';
|
|
4
5
|
|
|
6
|
+
export type { JSONSchema } from 'json-schema-typed';
|
|
7
|
+
|
|
5
8
|
/** Converts a KnownType or NamedType into JSON Schema */
|
|
6
|
-
function string(type: KnownType | NamedType):
|
|
9
|
+
function string(type: KnownType | NamedType): JSONSchema {
|
|
7
10
|
switch (type) {
|
|
8
11
|
case 'string':
|
|
9
12
|
return { type: 'string' };
|
|
@@ -14,19 +17,19 @@ function string(type: KnownType | NamedType): JSONSchema7 {
|
|
|
14
17
|
case 'nil':
|
|
15
18
|
return { type: 'null' };
|
|
16
19
|
case 'array':
|
|
17
|
-
return { type: 'array' };
|
|
20
|
+
return { type: 'array', items: true };
|
|
18
21
|
case 'record':
|
|
19
22
|
return { type: 'object' };
|
|
20
23
|
case 'extern':
|
|
21
|
-
return
|
|
24
|
+
return true;
|
|
22
25
|
case 'any':
|
|
23
|
-
return
|
|
26
|
+
return true;
|
|
24
27
|
case 'unknown':
|
|
25
|
-
return
|
|
28
|
+
return true;
|
|
26
29
|
case 'never':
|
|
27
|
-
return
|
|
30
|
+
return false;
|
|
28
31
|
default:
|
|
29
|
-
return
|
|
32
|
+
return true;
|
|
30
33
|
}
|
|
31
34
|
}
|
|
32
35
|
|
|
@@ -83,6 +86,9 @@ function templatePartPattern(part: Type, grouping: boolean): string {
|
|
|
83
86
|
result = `(${result})?`;
|
|
84
87
|
}
|
|
85
88
|
}
|
|
89
|
+
} else if (part.kind === 'intersection') {
|
|
90
|
+
// Regex intersection is not representable in general; keep behavior conservative.
|
|
91
|
+
result = RE_ANY;
|
|
86
92
|
} else {
|
|
87
93
|
result = RE_ANY;
|
|
88
94
|
}
|
|
@@ -104,27 +110,21 @@ function templatePattern(type: TemplateType): string {
|
|
|
104
110
|
}
|
|
105
111
|
|
|
106
112
|
/** Converts a LiteralType into JSON Schema */
|
|
107
|
-
function literal(type: LiteralType):
|
|
108
|
-
|
|
109
|
-
return { type: 'boolean', const: type.value };
|
|
110
|
-
}
|
|
111
|
-
return { type: 'string', const: type.value };
|
|
113
|
+
function literal(type: LiteralType): JSONSchema {
|
|
114
|
+
return { const: type.value };
|
|
112
115
|
}
|
|
113
116
|
|
|
114
117
|
/** Converts a union of LiteralTypes into a single JSON Schema enum */
|
|
115
|
-
function literalEnum(types: LiteralType[]):
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (valueTypes.size === 1) {
|
|
120
|
-
schema.type = valueTypes.values().next().value!;
|
|
121
|
-
}
|
|
118
|
+
function literalEnum(types: LiteralType[]): JSONSchema {
|
|
119
|
+
const schema: JSONSchema = {
|
|
120
|
+
enum: types.map((t) => t.value),
|
|
121
|
+
};
|
|
122
122
|
return schema;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
/** Type guard for LiteralType */
|
|
126
126
|
function isLiteralType(type: Type): type is LiteralType {
|
|
127
|
-
return typeof type
|
|
127
|
+
return typeof type == 'object' && type.kind === 'literal';
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
/** Options for toJSONSchema */
|
|
@@ -134,49 +134,67 @@ export interface ToJSONSchemaOptions {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
/** Converts a Type object into JSON Schema */
|
|
137
|
-
|
|
138
|
-
const loose = options
|
|
139
|
-
|
|
137
|
+
function toJSONSchemaImpl(type: Type, options: Required<ToJSONSchemaOptions>): JSONSchema {
|
|
138
|
+
const { loose } = options;
|
|
139
|
+
const simplified = simplify(type);
|
|
140
|
+
if (typeof simplified == 'symbol') {
|
|
140
141
|
return {};
|
|
141
142
|
}
|
|
142
|
-
if (typeof
|
|
143
|
-
return string(
|
|
143
|
+
if (typeof simplified == 'string') {
|
|
144
|
+
return string(simplified);
|
|
144
145
|
}
|
|
145
|
-
if (
|
|
146
|
+
if (simplified.kind === 'array') {
|
|
146
147
|
return {
|
|
147
148
|
type: 'array',
|
|
148
|
-
items:
|
|
149
|
+
items: toJSONSchemaImpl(simplified.element, options),
|
|
149
150
|
};
|
|
150
151
|
}
|
|
151
|
-
if (
|
|
152
|
-
const anyOf = [];
|
|
153
|
-
const literals = [];
|
|
154
|
-
for (const t of
|
|
152
|
+
if (simplified.kind === 'union') {
|
|
153
|
+
const anyOf: JSONSchema[] = [];
|
|
154
|
+
const literals: LiteralType[] = [];
|
|
155
|
+
for (const t of simplified.types) {
|
|
155
156
|
if (isLiteralType(t)) {
|
|
156
157
|
literals.push(t);
|
|
157
|
-
|
|
158
|
-
anyOf.push(toJSONSchema(t, options));
|
|
158
|
+
continue;
|
|
159
159
|
}
|
|
160
|
+
const child = toJSONSchemaImpl(t, options);
|
|
161
|
+
if (child === true) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
if (child === false) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
anyOf.push(child);
|
|
160
168
|
}
|
|
161
169
|
if (literals.length > 0) {
|
|
162
170
|
anyOf.push(literalEnum(literals));
|
|
163
171
|
}
|
|
172
|
+
if (anyOf.length === 0) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
164
175
|
if (anyOf.length === 1) {
|
|
165
176
|
return anyOf[0]!;
|
|
166
177
|
}
|
|
167
178
|
return { anyOf };
|
|
168
179
|
}
|
|
169
|
-
if (
|
|
170
|
-
|
|
171
|
-
|
|
180
|
+
if (simplified.kind === 'intersection') {
|
|
181
|
+
const allOf = simplified.types.map((t) => toJSONSchemaImpl(t, options));
|
|
182
|
+
if (allOf.length === 1) {
|
|
183
|
+
return allOf[0]!;
|
|
184
|
+
}
|
|
185
|
+
return { allOf };
|
|
186
|
+
}
|
|
187
|
+
if (simplified.kind === 'record') {
|
|
188
|
+
if ('fields' in simplified) {
|
|
189
|
+
const properties: Record<string, JSONSchema> = {};
|
|
172
190
|
const required: string[] = [];
|
|
173
|
-
for (const field of
|
|
174
|
-
properties[field.name] =
|
|
191
|
+
for (const field of simplified.fields) {
|
|
192
|
+
properties[field.name] = toJSONSchemaImpl(field.type, options);
|
|
175
193
|
if (!field.optional && !loose) {
|
|
176
194
|
required.push(field.name);
|
|
177
195
|
}
|
|
178
196
|
}
|
|
179
|
-
const schema:
|
|
197
|
+
const schema: JSONSchema = {
|
|
180
198
|
type: 'object',
|
|
181
199
|
properties,
|
|
182
200
|
additionalProperties: loose,
|
|
@@ -187,54 +205,119 @@ export function toJSONSchema(type: Type, options?: ToJSONSchemaOptions): JSONSch
|
|
|
187
205
|
return schema;
|
|
188
206
|
}
|
|
189
207
|
|
|
190
|
-
const valueSchema =
|
|
191
|
-
if (
|
|
208
|
+
const valueSchema = toJSONSchemaImpl(simplified.value, options);
|
|
209
|
+
if (simplified.key == null) {
|
|
192
210
|
return {
|
|
193
211
|
type: 'object',
|
|
194
212
|
additionalProperties: valueSchema,
|
|
195
213
|
};
|
|
196
214
|
}
|
|
197
|
-
if (typeof
|
|
198
|
-
if (isLiteralType(
|
|
199
|
-
const schema:
|
|
215
|
+
if (typeof simplified.key == 'object') {
|
|
216
|
+
if (isLiteralType(simplified.key)) {
|
|
217
|
+
const schema: JSONSchema = {
|
|
200
218
|
type: 'object',
|
|
201
|
-
properties: { [String(
|
|
219
|
+
properties: { [String(simplified.key.value)]: valueSchema },
|
|
202
220
|
additionalProperties: loose,
|
|
203
221
|
};
|
|
204
222
|
return schema;
|
|
205
|
-
} else if (
|
|
206
|
-
const schema:
|
|
223
|
+
} else if (simplified.key.kind === 'union' && simplified.key.types.every(isLiteralType)) {
|
|
224
|
+
const schema: JSONSchema = {
|
|
207
225
|
type: 'object',
|
|
208
|
-
properties: Object.fromEntries(
|
|
226
|
+
properties: Object.fromEntries(simplified.key.types.map((t) => [String(t.value), valueSchema])),
|
|
209
227
|
additionalProperties: loose,
|
|
210
228
|
};
|
|
211
229
|
return schema;
|
|
212
230
|
}
|
|
213
231
|
}
|
|
214
|
-
const pattern = templatePartPattern(
|
|
232
|
+
const pattern = templatePartPattern(simplified.key, false);
|
|
215
233
|
if (pattern === RE_ANY) {
|
|
216
234
|
return {
|
|
217
235
|
type: 'object',
|
|
218
236
|
additionalProperties: valueSchema,
|
|
219
237
|
};
|
|
220
238
|
}
|
|
221
|
-
const schema:
|
|
239
|
+
const schema: JSONSchema = {
|
|
222
240
|
type: 'object',
|
|
223
241
|
patternProperties: { [`^${pattern}$`]: valueSchema },
|
|
224
242
|
additionalProperties: loose,
|
|
225
243
|
};
|
|
226
244
|
return schema;
|
|
227
245
|
}
|
|
228
|
-
if (
|
|
229
|
-
return literal(
|
|
246
|
+
if (simplified.kind === 'literal') {
|
|
247
|
+
return literal(simplified);
|
|
230
248
|
}
|
|
231
|
-
if (
|
|
232
|
-
return
|
|
249
|
+
if (simplified.kind === 'function') {
|
|
250
|
+
return false;
|
|
233
251
|
}
|
|
234
|
-
if (
|
|
235
|
-
return { type: 'string', pattern: templatePattern(
|
|
252
|
+
if (simplified.kind === 'template') {
|
|
253
|
+
return { type: 'string', pattern: templatePattern(simplified) };
|
|
254
|
+
}
|
|
255
|
+
if (simplified.kind === 'tuple') {
|
|
256
|
+
// Collect element schemas, unwrapping array from rest elements (..T[] → T).
|
|
257
|
+
// Non-array rest (e.g. ..string) is treated as any ({}).
|
|
258
|
+
const elementSchemas = simplified.elements.map((e) => {
|
|
259
|
+
const t = e.type;
|
|
260
|
+
if (!e.spread) return toJSONSchemaImpl(t, options);
|
|
261
|
+
if (typeof t == 'object' && t.kind === 'array') {
|
|
262
|
+
return toJSONSchemaImpl(t.element, options);
|
|
263
|
+
}
|
|
264
|
+
return true;
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
const prefixItems = [];
|
|
268
|
+
let i = 0;
|
|
269
|
+
for (; i < elementSchemas.length; i++) {
|
|
270
|
+
const el = simplified.elements[i]!;
|
|
271
|
+
if (el.spread) break;
|
|
272
|
+
prefixItems.push(elementSchemas[i]!);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const items = [];
|
|
276
|
+
let hasAny = false;
|
|
277
|
+
for (; i < elementSchemas.length; i++) {
|
|
278
|
+
const schema = elementSchemas[i]!;
|
|
279
|
+
items.push(schema);
|
|
280
|
+
if (schema === true) {
|
|
281
|
+
hasAny = true;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const schema: JSONSchema = { type: 'array' };
|
|
286
|
+
if (prefixItems.length > 0) {
|
|
287
|
+
schema.prefixItems = prefixItems;
|
|
288
|
+
}
|
|
289
|
+
if (hasAny) {
|
|
290
|
+
schema.items = true;
|
|
291
|
+
} else if (items.length > 1) {
|
|
292
|
+
schema.items = { anyOf: items };
|
|
293
|
+
} else if (items.length === 1) {
|
|
294
|
+
schema.items = items[0]!;
|
|
295
|
+
} else {
|
|
296
|
+
schema.items = loose;
|
|
297
|
+
}
|
|
298
|
+
return schema;
|
|
299
|
+
}
|
|
300
|
+
if (simplified.kind === 'reflection') {
|
|
301
|
+
return true;
|
|
236
302
|
}
|
|
237
303
|
/* c8 ignore next 3 */
|
|
238
|
-
|
|
239
|
-
return
|
|
304
|
+
simplified satisfies never;
|
|
305
|
+
return true;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/** Converts a Type object into JSON Schema */
|
|
309
|
+
export function toJSONSchema(
|
|
310
|
+
type: Type,
|
|
311
|
+
options?: ToJSONSchemaOptions,
|
|
312
|
+
): JSONSchema.Interface & { $schema: typeof $schema } {
|
|
313
|
+
let schema = toJSONSchemaImpl(type, { loose: options?.loose ?? false });
|
|
314
|
+
if (schema === true) {
|
|
315
|
+
schema = {};
|
|
316
|
+
} else if (schema === false) {
|
|
317
|
+
schema = { not: true };
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
...schema,
|
|
321
|
+
$schema,
|
|
322
|
+
};
|
|
240
323
|
}
|
package/src/parser.ts
CHANGED
|
@@ -9,8 +9,11 @@ export type Type =
|
|
|
9
9
|
| TemplateType
|
|
10
10
|
| ArrayType
|
|
11
11
|
| UnionType
|
|
12
|
+
| IntersectionType
|
|
12
13
|
| RecordType
|
|
13
|
-
| FunctionType
|
|
14
|
+
| FunctionType
|
|
15
|
+
| TupleType
|
|
16
|
+
| ReflectionType;
|
|
14
17
|
|
|
15
18
|
/** Generic type parameter reference in MiraScript */
|
|
16
19
|
export type GenericType = symbol;
|
|
@@ -46,6 +49,14 @@ export interface UnionType {
|
|
|
46
49
|
types: Type[];
|
|
47
50
|
}
|
|
48
51
|
|
|
52
|
+
/** Intersection type in MiraScript */
|
|
53
|
+
export interface IntersectionType {
|
|
54
|
+
/** Tag */
|
|
55
|
+
kind: 'intersection';
|
|
56
|
+
/** Types in the intersection */
|
|
57
|
+
types: Type[];
|
|
58
|
+
}
|
|
59
|
+
|
|
49
60
|
/** Array type in MiraScript */
|
|
50
61
|
export interface ArrayType {
|
|
51
62
|
/** Tag */
|
|
@@ -105,6 +116,30 @@ export interface FunctionParameter {
|
|
|
105
116
|
spread?: boolean;
|
|
106
117
|
}
|
|
107
118
|
|
|
119
|
+
/** Tuple type in MiraScript */
|
|
120
|
+
export interface TupleType {
|
|
121
|
+
/** Tag */
|
|
122
|
+
kind: 'tuple';
|
|
123
|
+
/** Elements in the tuple */
|
|
124
|
+
elements: TupleElement[];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Tuple element in MiraScript */
|
|
128
|
+
export interface TupleElement {
|
|
129
|
+
/** Element type */
|
|
130
|
+
type: Type;
|
|
131
|
+
/** Whether the element is a rest element */
|
|
132
|
+
spread?: boolean;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Reflection type in MiraScript */
|
|
136
|
+
export interface ReflectionType {
|
|
137
|
+
/** Tag */
|
|
138
|
+
kind: 'reflection';
|
|
139
|
+
/** The name of the variable being reflected */
|
|
140
|
+
name: string;
|
|
141
|
+
}
|
|
142
|
+
|
|
108
143
|
/**
|
|
109
144
|
* Replaces generic type parameter names in the AST with unique symbols,
|
|
110
145
|
* scoped per function declaration.
|
|
@@ -136,6 +171,10 @@ function resolveGenerics(type: Type, scope = new Map<string, GenericType>()): Ty
|
|
|
136
171
|
type.types = type.types.map((t) => resolveGenerics(t, scope));
|
|
137
172
|
return type;
|
|
138
173
|
}
|
|
174
|
+
if (type.kind === 'intersection') {
|
|
175
|
+
type.types = type.types.map((t) => resolveGenerics(t, scope));
|
|
176
|
+
return type;
|
|
177
|
+
}
|
|
139
178
|
if (type.kind === 'record') {
|
|
140
179
|
if ('fields' in type) {
|
|
141
180
|
for (const field of type.fields) {
|
|
@@ -154,6 +193,15 @@ function resolveGenerics(type: Type, scope = new Map<string, GenericType>()): Ty
|
|
|
154
193
|
type.parts = type.parts.map((part) => resolveGenerics(part, scope));
|
|
155
194
|
return type;
|
|
156
195
|
}
|
|
196
|
+
if (type.kind === 'tuple') {
|
|
197
|
+
for (const element of type.elements) {
|
|
198
|
+
element.type = resolveGenerics(element.type, scope);
|
|
199
|
+
}
|
|
200
|
+
return type;
|
|
201
|
+
}
|
|
202
|
+
if (type.kind === 'reflection') {
|
|
203
|
+
return type;
|
|
204
|
+
}
|
|
157
205
|
/* c8 ignore next 3 */
|
|
158
206
|
(type) satisfies never;
|
|
159
207
|
return type;
|