@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/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":"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","file":"type.js"}
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.64",
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.0.1",
26
+ "@types/node": "^26.1.1",
27
27
  "ava": "^8.0.1",
28
28
  "c8": "^11.0.0",
29
- "js-yaml": "^5.2.0",
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
- "@types/json-schema": "^7.0.15",
34
- "@mirascript/constants": "~0.1.64"
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
@@ -1,2 +1,4 @@
1
1
  export * from './parser.js';
2
+ export * from './simplifier.js';
2
3
  export * from './json.js';
4
+ export * from './stringify.js';
package/src/json.ts CHANGED
@@ -1,9 +1,12 @@
1
- import type { JSONSchema7 } from 'json-schema';
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): JSONSchema7 {
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): JSONSchema7 {
108
- if (typeof type.value === 'boolean') {
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[]): JSONSchema7 {
116
- const values = types.map((t) => t.value);
117
- const valueTypes = new Set(values.map((v) => (typeof v === 'boolean' ? 'boolean' : 'string')));
118
- const schema: JSONSchema7 = { enum: values };
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 === 'object' && type.kind === 'literal';
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
- export function toJSONSchema(type: Type, options?: ToJSONSchemaOptions): JSONSchema7 {
138
- const loose = options?.loose ?? false;
139
- if (typeof type === 'symbol') {
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 type === 'string') {
143
- return string(type);
143
+ if (typeof simplified == 'string') {
144
+ return string(simplified);
144
145
  }
145
- if (type.kind === 'array') {
146
+ if (simplified.kind === 'array') {
146
147
  return {
147
148
  type: 'array',
148
- items: toJSONSchema(type.element, options),
149
+ items: toJSONSchemaImpl(simplified.element, options),
149
150
  };
150
151
  }
151
- if (type.kind === 'union') {
152
- const anyOf = [];
153
- const literals = [];
154
- for (const t of type.types) {
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
- } else {
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 (type.kind === 'record') {
170
- if ('fields' in type) {
171
- const properties: Record<string, JSONSchema7> = {};
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 type.fields) {
174
- properties[field.name] = toJSONSchema(field.type, options);
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: JSONSchema7 = {
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 = toJSONSchema(type.value, options);
191
- if (type.key == null) {
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 type.key == 'object') {
198
- if (isLiteralType(type.key)) {
199
- const schema: JSONSchema7 = {
215
+ if (typeof simplified.key == 'object') {
216
+ if (isLiteralType(simplified.key)) {
217
+ const schema: JSONSchema = {
200
218
  type: 'object',
201
- properties: { [String(type.key.value)]: valueSchema },
219
+ properties: { [String(simplified.key.value)]: valueSchema },
202
220
  additionalProperties: loose,
203
221
  };
204
222
  return schema;
205
- } else if (type.key.kind === 'union' && type.key.types.every(isLiteralType)) {
206
- const schema: JSONSchema7 = {
223
+ } else if (simplified.key.kind === 'union' && simplified.key.types.every(isLiteralType)) {
224
+ const schema: JSONSchema = {
207
225
  type: 'object',
208
- properties: Object.fromEntries(type.key.types.map((t) => [String(t.value), valueSchema])),
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(type.key, false);
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: JSONSchema7 = {
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 (type.kind === 'literal') {
229
- return literal(type);
246
+ if (simplified.kind === 'literal') {
247
+ return literal(simplified);
230
248
  }
231
- if (type.kind === 'function') {
232
- return {};
249
+ if (simplified.kind === 'function') {
250
+ return false;
233
251
  }
234
- if (type.kind === 'template') {
235
- return { type: 'string', pattern: templatePattern(type) };
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
- (type) satisfies never;
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;