-
Notifications
You must be signed in to change notification settings - Fork 220
/
Copy pathschema-gen.js
103 lines (98 loc) · 2.96 KB
/
schema-gen.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// @ts-check
// import { M } from '@agoric/vat-data';
// eslint-disable-next-line import/no-extraneous-dependencies
import { passStyleOf, getTag } from '@endo/pass-style';
// XXX how to use devDependencies from tests/tools??
// eslint-disable-next-line import/no-extraneous-dependencies
import { Type } from '@sinclair/typebox';
// import * as fsAmbient from 'fs/promises';
/**
* @file Generate JSON schema for editing config files
* based on endo patterns
*/
// why is kindOf not exported?!
// https://github.com/endojs/endo/blob/53973bddbf73f681640ed9b7dd7bafdc2f8a3126/packages/patterns/src/patterns/patternMatchers.js#L219
const kindOf = patt => {
const passStyle = passStyleOf(patt);
if (passStyle !== 'tagged') return passStyle;
return getTag(patt);
};
const { entries, fromEntries } = Object;
/**
* @param {Pattern} pattern
*/
export const toTypeBox = pattern => {
const todo = (...stuff) => {
console.error(...stuff);
throw Error(`not implemented`);
};
/**
* @param {Pattern} patt
* @returns {import('@sinclair/typebox').TSchema}
*/
const recur = patt => {
const pattKind = kindOf(patt);
switch (pattKind) {
case 'string':
return Type.Literal(patt);
case 'copyRecord': {
return Type.Object(
fromEntries(
entries(patt).map(([prop, valPat]) => [prop, recur(valPat)]),
),
);
}
case 'match:any': {
return Type.Any();
}
case 'match:string': {
const [limits] = patt.payload;
if (limits) todo(limits);
return Type.String();
}
case 'match:and': {
const patts = patt.payload;
return Type.Intersect(patts.map(recur));
}
case 'match:or': {
const patts = patt.payload;
return Type.Union(patts.map(recur));
}
case 'match:arrayOf': {
const [subPatt, limits] = patt.payload;
if (limits) todo(limits);
return Type.Array(recur(subPatt));
}
case 'match:recordOf': {
const [keyPatt, valuePatt] = patt.payload;
// XXX Type.Record requires Type.String()
return Type.Record(recur(keyPatt), recur(valuePatt));
}
case 'match:splitRecord': {
const [required, optional] = patt.payload;
const ty = recur(required);
return optional
? Type.Composite([ty, Type.Partial(recur(optional))])
: ty;
}
case 'match:kind': {
const valueKind = patt.payload;
switch (valueKind) {
case 'boolean':
return Type.Boolean();
case 'number':
return Type.Number();
case 'string':
return Type.String();
default:
console.error('@@@', pattKind, patt);
throw Error(`unrecognized value kind: ${pattKind}`);
}
}
default:
console.error('@@@', pattKind, patt);
throw Error(`unrecognized pattern kind: ${pattKind}`);
}
};
return recur(pattern);
};