@mirascript/typed 0.1.62
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/LICENSE +21 -0
- package/README.md +47 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/json.d.ts +5 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +99 -0
- package/dist/json.js.map +1 -0
- package/dist/parser.d.ts +50 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +8 -0
- package/dist/parser.js.map +1 -0
- package/dist/type.d.ts +208 -0
- package/dist/type.js +1218 -0
- package/dist/type.js.map +1 -0
- package/package.json +39 -0
- package/src/index.ts +2 -0
- package/src/json.ts +105 -0
- package/src/parser.ts +71 -0
- package/src/type.peggy +128 -0
package/dist/type.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["..\\src\\type.peggy"],"names":["Start","Type","UnionType","PostfixType","PrimaryType","RecordType","FieldList","Field","FieldName","String","Identifier","_","$initializer"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAuBgB,aAAW,G;yBAOP;AACpB;AACI,G;gCAGuD;AAC3D;AACA;AACA;AACA;AACI,G;gCAC+C;AACnD;AACA;AACA;AACA;AACI,G;iCAQmC;AACvC;AACA;AACA;AACA;AACI,G;kCAOiD;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACI,G;wBACY;AAChB;AACI,G;sBACoB;AACxB;AACI,G;qBAQW,sBAAoB,G;2BACD,0BAAwB,G;4BAGZ;AAC9C;AACI,G;kCAG0C;AAC9C;AACA;AACA;AACA;AACA;AACI,G;uBACQ;AACZ;AACA;AACA;AACI,G;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAvFJA,cAAK;;;;;;;;;;;;;;;;;;WAOLC,aAAI;;;;;;;;;;;;;;WAKJC,kBAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAmBTC,oBAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAYXC,oBAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAuBXC,mBAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAIVC,kBAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAKTC,cAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAcLC,kBAAS;;;;;;;;;;;WAQTC,eAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAINC,mBAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAGVC,UAAC;;;;;;;;;;;;;;;;;;;;;;;;;AA9HAC;AACDA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA;AACAA","file":"type.js"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mirascript/typed",
|
|
3
|
+
"version": "0.1.62",
|
|
4
|
+
"author": "CloudPSS",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"description": "Parse MiraScript type definitions and generate TypeScript types / JSON schemas.",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"mirascript",
|
|
9
|
+
"json-schema",
|
|
10
|
+
"types"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://mira.cloudpss.net",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/CloudPSS/MiraScript.git",
|
|
16
|
+
"directory": "packages/typed"
|
|
17
|
+
},
|
|
18
|
+
"type": "module",
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": "./dist/index.js",
|
|
23
|
+
"./package.json": "./package.json"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^26.0.0",
|
|
27
|
+
"ava": "^8.0.1",
|
|
28
|
+
"js-yaml": "^5.1.0",
|
|
29
|
+
"peggy": "^5.1.0"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@types/json-schema": "^7.0.15"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "peggy src/type.peggy --multi-output ./dist --dts --format es --source-map && tsc",
|
|
36
|
+
"clean": "rimraf dist",
|
|
37
|
+
"test": "ava --no-worker-threads"
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/index.ts
ADDED
package/src/json.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { JSONSchema7 } from 'json-schema';
|
|
2
|
+
import type { KnownType, LiteralType, NamedType, Type } from './parser.js';
|
|
3
|
+
|
|
4
|
+
/** Converts a KnownType or NamedType into JSON Schema */
|
|
5
|
+
function string(type: KnownType | NamedType): JSONSchema7 {
|
|
6
|
+
switch (type) {
|
|
7
|
+
case 'string':
|
|
8
|
+
return { type: 'string' };
|
|
9
|
+
case 'number':
|
|
10
|
+
return { type: 'number' };
|
|
11
|
+
case 'boolean':
|
|
12
|
+
return { type: 'boolean' };
|
|
13
|
+
case 'nil':
|
|
14
|
+
return { type: 'null' };
|
|
15
|
+
case 'array':
|
|
16
|
+
return { type: 'array' };
|
|
17
|
+
case 'record':
|
|
18
|
+
return { type: 'object' };
|
|
19
|
+
case 'extern':
|
|
20
|
+
return {};
|
|
21
|
+
case 'any':
|
|
22
|
+
return {};
|
|
23
|
+
case 'unknown':
|
|
24
|
+
return {};
|
|
25
|
+
case 'never':
|
|
26
|
+
return {};
|
|
27
|
+
default:
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Converts a Type object into JSON Schema */
|
|
33
|
+
export function toJSONSchema(type: Type): JSONSchema7 {
|
|
34
|
+
if (typeof type === 'string') {
|
|
35
|
+
return string(type);
|
|
36
|
+
}
|
|
37
|
+
if (type.kind === 'array') {
|
|
38
|
+
return {
|
|
39
|
+
type: 'array',
|
|
40
|
+
items: toJSONSchema(type.element),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (type.kind === 'union') {
|
|
44
|
+
const literals = type.types.filter(isLiteralType);
|
|
45
|
+
if (literals.length === type.types.length) {
|
|
46
|
+
return literalEnum(literals);
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
anyOf: type.types.map(toJSONSchema),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (type.kind === 'record') {
|
|
53
|
+
if (type.value !== undefined) {
|
|
54
|
+
return {
|
|
55
|
+
type: 'object',
|
|
56
|
+
additionalProperties: toJSONSchema(type.value),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const properties: Record<string, JSONSchema7> = {};
|
|
60
|
+
const required: string[] = [];
|
|
61
|
+
for (const field of type.fields) {
|
|
62
|
+
properties[field.name] = toJSONSchema(field.type);
|
|
63
|
+
if (!field.optional) {
|
|
64
|
+
required.push(field.name);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const schema: JSONSchema7 = {
|
|
68
|
+
type: 'object',
|
|
69
|
+
properties,
|
|
70
|
+
};
|
|
71
|
+
if (required.length > 0) {
|
|
72
|
+
schema.required = required;
|
|
73
|
+
}
|
|
74
|
+
return schema;
|
|
75
|
+
}
|
|
76
|
+
if (type.kind === 'literal') {
|
|
77
|
+
return literal(type);
|
|
78
|
+
}
|
|
79
|
+
(type) satisfies never;
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Converts a LiteralType into JSON Schema */
|
|
84
|
+
function literal(type: LiteralType): JSONSchema7 {
|
|
85
|
+
if (typeof type.value === 'boolean') {
|
|
86
|
+
return { type: 'boolean', const: type.value };
|
|
87
|
+
}
|
|
88
|
+
return { type: 'string', const: type.value };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Converts a union of LiteralTypes into a single JSON Schema enum */
|
|
92
|
+
function literalEnum(types: LiteralType[]): JSONSchema7 {
|
|
93
|
+
const values = types.map((t) => t.value);
|
|
94
|
+
const valueTypes = new Set(values.map((v) => (typeof v === 'boolean' ? 'boolean' : 'string')));
|
|
95
|
+
const schema: JSONSchema7 = { enum: values };
|
|
96
|
+
if (valueTypes.size === 1) {
|
|
97
|
+
schema.type = valueTypes.values().next().value!;
|
|
98
|
+
}
|
|
99
|
+
return schema;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Type guard for LiteralType */
|
|
103
|
+
function isLiteralType(type: Type): type is LiteralType {
|
|
104
|
+
return typeof type === 'object' && type.kind === 'literal';
|
|
105
|
+
}
|
package/src/parser.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { parse as _parse } from '../dist/type.js';
|
|
2
|
+
|
|
3
|
+
/** MiraScript type */
|
|
4
|
+
export type Type = KnownType | NamedType | LiteralType | ArrayType | UnionType | RecordType;
|
|
5
|
+
|
|
6
|
+
/** Literal type in MiraScript */
|
|
7
|
+
export interface LiteralType {
|
|
8
|
+
/** Tag */
|
|
9
|
+
kind: 'literal';
|
|
10
|
+
/** Literal value */
|
|
11
|
+
value: string | boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Known type names in MiraScript */
|
|
15
|
+
export type KnownType =
|
|
16
|
+
| 'string'
|
|
17
|
+
| 'number'
|
|
18
|
+
| 'boolean'
|
|
19
|
+
| 'nil'
|
|
20
|
+
| 'array'
|
|
21
|
+
| 'record'
|
|
22
|
+
| 'extern'
|
|
23
|
+
| 'any'
|
|
24
|
+
| 'unknown'
|
|
25
|
+
| 'never';
|
|
26
|
+
|
|
27
|
+
/** Named type in MiraScript */
|
|
28
|
+
export type NamedType = string & Record<never, never>;
|
|
29
|
+
|
|
30
|
+
/** Union type in MiraScript */
|
|
31
|
+
export interface UnionType {
|
|
32
|
+
/** Tag */
|
|
33
|
+
kind: 'union';
|
|
34
|
+
/** Types in the union */
|
|
35
|
+
types: Type[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Array type in MiraScript */
|
|
39
|
+
export interface ArrayType {
|
|
40
|
+
/** Tag */
|
|
41
|
+
kind: 'array';
|
|
42
|
+
/** Element type */
|
|
43
|
+
element: Type;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Record type in MiraScript */
|
|
47
|
+
export interface RecordType {
|
|
48
|
+
/** Tag */
|
|
49
|
+
kind: 'record';
|
|
50
|
+
/** Fields in the record */
|
|
51
|
+
fields: RecordField[];
|
|
52
|
+
/** Value type for record<T> */
|
|
53
|
+
value?: Type;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Record field in MiraScript */
|
|
57
|
+
export interface RecordField {
|
|
58
|
+
/** Field name */
|
|
59
|
+
name: string;
|
|
60
|
+
/** Whether the field is optional */
|
|
61
|
+
optional?: boolean;
|
|
62
|
+
/** Field type */
|
|
63
|
+
type: Type;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Parses a type string into a Type object.
|
|
68
|
+
*/
|
|
69
|
+
export function parse(type: string): Type {
|
|
70
|
+
return _parse(type) as Type;
|
|
71
|
+
}
|
package/src/type.peggy
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
{
|
|
2
|
+
function named(name) {
|
|
3
|
+
return name;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function array(element) {
|
|
7
|
+
return { kind: "array", element };
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function union(types) {
|
|
11
|
+
if (types.length === 1) return types[0];
|
|
12
|
+
return { kind: "union", types };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function record(fields) {
|
|
16
|
+
for(let i = 0; i < fields.length; i++) {
|
|
17
|
+
fields[i].name ??= String(i);
|
|
18
|
+
}
|
|
19
|
+
return { kind: "record", fields };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
Start
|
|
24
|
+
= _ t:Type _ { return t; }
|
|
25
|
+
|
|
26
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
27
|
+
// Type (union)
|
|
28
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
29
|
+
|
|
30
|
+
Type
|
|
31
|
+
= head:UnionType {
|
|
32
|
+
return head;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
UnionType
|
|
36
|
+
= _ "|" _ first:PostfixType rest:(_ "|" _ PostfixType)* {
|
|
37
|
+
return union([
|
|
38
|
+
first,
|
|
39
|
+
...rest.map(x => x[3])
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
42
|
+
/ first:PostfixType rest:(_ "|" _ PostfixType)+ {
|
|
43
|
+
return union([
|
|
44
|
+
first,
|
|
45
|
+
...rest.map(x => x[3])
|
|
46
|
+
]);
|
|
47
|
+
}
|
|
48
|
+
/ PostfixType
|
|
49
|
+
|
|
50
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
51
|
+
// Array
|
|
52
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
53
|
+
|
|
54
|
+
PostfixType
|
|
55
|
+
= base:PrimaryType suffix:("[]" _)* {
|
|
56
|
+
let t = base;
|
|
57
|
+
for (const _ of suffix)
|
|
58
|
+
t = array(t);
|
|
59
|
+
return t;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
63
|
+
// Primary
|
|
64
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
65
|
+
|
|
66
|
+
PrimaryType
|
|
67
|
+
= name:Identifier generic:(_ "<" _ t:Type _ ">")? {
|
|
68
|
+
if (generic) {
|
|
69
|
+
const t = generic[3];
|
|
70
|
+
if (name === 'array') return array(t);
|
|
71
|
+
if (name === 'record') return { kind: "record", fields: [], value: t };
|
|
72
|
+
}
|
|
73
|
+
if (name === 'true') return { kind: "literal", value: true };
|
|
74
|
+
if (name === 'false') return { kind: "literal", value: false };
|
|
75
|
+
return named(name);
|
|
76
|
+
}
|
|
77
|
+
/ lit:String {
|
|
78
|
+
return { kind: "literal", value: lit };
|
|
79
|
+
}
|
|
80
|
+
/ "(" _ t:Type _ ")" {
|
|
81
|
+
return t;
|
|
82
|
+
}
|
|
83
|
+
/ RecordType
|
|
84
|
+
|
|
85
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
86
|
+
// Record
|
|
87
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
88
|
+
|
|
89
|
+
RecordType
|
|
90
|
+
= "(" _ ")" { return record([]); }
|
|
91
|
+
/ "(" _ fields:FieldList _ ")" { return record(fields); }
|
|
92
|
+
|
|
93
|
+
FieldList
|
|
94
|
+
= fields:Field|1.., _ "," _ | ( _ "," _ )? {
|
|
95
|
+
return fields;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
Field
|
|
99
|
+
= name:FieldName opt:("?"?) _ ":" _ t:Type {
|
|
100
|
+
return {
|
|
101
|
+
name,
|
|
102
|
+
optional: opt !== null,
|
|
103
|
+
type: t
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/ t:Type {
|
|
107
|
+
return {
|
|
108
|
+
type: t
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
FieldName
|
|
113
|
+
= Identifier
|
|
114
|
+
/ String
|
|
115
|
+
|
|
116
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
117
|
+
// Lexer
|
|
118
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
119
|
+
|
|
120
|
+
String
|
|
121
|
+
= '"' @$[^"]* '"'
|
|
122
|
+
/ "'" @$[^']* "'"
|
|
123
|
+
|
|
124
|
+
Identifier
|
|
125
|
+
= $([a-zA-Z_][a-zA-Z0-9_]*)
|
|
126
|
+
|
|
127
|
+
_
|
|
128
|
+
= [ \t\r\n]*
|