@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.
@@ -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
@@ -0,0 +1,2 @@
1
+ export * from './parser.js';
2
+ export * from './json.js';
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]*