@highstate/cli 0.4.2
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/index-gNMEequI.js +272 -0
- package/dist/main-CfRuzXF8.js +552 -0
- package/dist/main.js +16072 -0
- package/package.json +31 -0
@@ -0,0 +1,272 @@
|
|
1
|
+
const simpleKeyRegExp = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
2
|
+
function getPrintable(value) {
|
3
|
+
if (value === null)
|
4
|
+
return `null`;
|
5
|
+
if (value === undefined)
|
6
|
+
return `undefined`;
|
7
|
+
if (value === ``)
|
8
|
+
return `an empty string`;
|
9
|
+
if (typeof value === 'symbol')
|
10
|
+
return `<${value.toString()}>`;
|
11
|
+
if (Array.isArray(value))
|
12
|
+
return `an array`;
|
13
|
+
return JSON.stringify(value);
|
14
|
+
}
|
15
|
+
function computeKey(state, key) {
|
16
|
+
var _a, _b, _c;
|
17
|
+
if (typeof key === `number`) {
|
18
|
+
return `${(_a = state === null || state === undefined ? undefined : state.p) !== null && _a !== undefined ? _a : `.`}[${key}]`;
|
19
|
+
}
|
20
|
+
else if (simpleKeyRegExp.test(key)) {
|
21
|
+
return `${(_b = state === null || state === undefined ? undefined : state.p) !== null && _b !== undefined ? _b : ``}.${key}`;
|
22
|
+
}
|
23
|
+
else {
|
24
|
+
return `${(_c = state === null || state === undefined ? undefined : state.p) !== null && _c !== undefined ? _c : `.`}[${JSON.stringify(key)}]`;
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
function pushError({ errors, p } = {}, message) {
|
29
|
+
errors === null || errors === undefined ? undefined : errors.push(`${p !== null && p !== undefined ? p : `.`}: ${message}`);
|
30
|
+
return false;
|
31
|
+
}
|
32
|
+
function makeCoercionFn(target, key) {
|
33
|
+
return (v) => {
|
34
|
+
const previous = target[key];
|
35
|
+
target[key] = v;
|
36
|
+
return makeCoercionFn(target, key).bind(null, previous);
|
37
|
+
};
|
38
|
+
}
|
39
|
+
|
40
|
+
/**
|
41
|
+
* Create a validator that always returns true and never refines the type.
|
42
|
+
*/
|
43
|
+
function isUnknown() {
|
44
|
+
return makeValidator({
|
45
|
+
test: (value, state) => {
|
46
|
+
return true;
|
47
|
+
},
|
48
|
+
});
|
49
|
+
}
|
50
|
+
/**
|
51
|
+
* Create a validator that only returns true when the tested value is a string.
|
52
|
+
* Refines the type to `string`.
|
53
|
+
*/
|
54
|
+
function isString() {
|
55
|
+
return makeValidator({
|
56
|
+
test: (value, state) => {
|
57
|
+
if (typeof value !== `string`)
|
58
|
+
return pushError(state, `Expected a string (got ${getPrintable(value)})`);
|
59
|
+
return true;
|
60
|
+
},
|
61
|
+
});
|
62
|
+
}
|
63
|
+
/**
|
64
|
+
* Create a validator that only returns true when the tested value is an
|
65
|
+
* array whose all values match the provided subspec. Refines the type to
|
66
|
+
* `Array<T>`, with `T` being the subspec inferred type.
|
67
|
+
*
|
68
|
+
* Supports coercion if the `delimiter` option is set, in which case strings
|
69
|
+
* will be split accordingly.
|
70
|
+
*/
|
71
|
+
function isArray(spec, { delimiter } = {}) {
|
72
|
+
return makeValidator({
|
73
|
+
test: (value, state) => {
|
74
|
+
var _a;
|
75
|
+
const originalValue = value;
|
76
|
+
if (typeof value === `string` && typeof delimiter !== `undefined`) {
|
77
|
+
if (typeof (state === null || state === undefined ? undefined : state.coercions) !== `undefined`) {
|
78
|
+
if (typeof (state === null || state === undefined ? undefined : state.coercion) === `undefined`)
|
79
|
+
return pushError(state, `Unbound coercion result`);
|
80
|
+
value = value.split(delimiter);
|
81
|
+
}
|
82
|
+
}
|
83
|
+
if (!Array.isArray(value))
|
84
|
+
return pushError(state, `Expected an array (got ${getPrintable(value)})`);
|
85
|
+
let valid = true;
|
86
|
+
for (let t = 0, T = value.length; t < T; ++t) {
|
87
|
+
valid = spec(value[t], Object.assign(Object.assign({}, state), { p: computeKey(state, t), coercion: makeCoercionFn(value, t) })) && valid;
|
88
|
+
if (!valid && (state === null || state === undefined ? undefined : state.errors) == null) {
|
89
|
+
break;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
if (value !== originalValue)
|
93
|
+
state.coercions.push([(_a = state.p) !== null && _a !== undefined ? _a : `.`, state.coercion.bind(null, value)]);
|
94
|
+
return valid;
|
95
|
+
},
|
96
|
+
});
|
97
|
+
}
|
98
|
+
/**
|
99
|
+
* Create a validator that only returns true when the tested value is a
|
100
|
+
* tuple whose each value matches the corresponding subspec. Refines the type
|
101
|
+
* into a tuple whose each item has the type inferred by the corresponding
|
102
|
+
* tuple.
|
103
|
+
*
|
104
|
+
* Supports coercion if the `delimiter` option is set, in which case strings
|
105
|
+
* will be split accordingly.
|
106
|
+
*/
|
107
|
+
function isTuple(spec, { delimiter } = {}) {
|
108
|
+
const lengthValidator = hasExactLength(spec.length);
|
109
|
+
return makeValidator({
|
110
|
+
test: (value, state) => {
|
111
|
+
var _a;
|
112
|
+
if (typeof value === `string` && typeof delimiter !== `undefined`) {
|
113
|
+
if (typeof (state === null || state === undefined ? undefined : state.coercions) !== `undefined`) {
|
114
|
+
if (typeof (state === null || state === undefined ? undefined : state.coercion) === `undefined`)
|
115
|
+
return pushError(state, `Unbound coercion result`);
|
116
|
+
value = value.split(delimiter);
|
117
|
+
state.coercions.push([(_a = state.p) !== null && _a !== undefined ? _a : `.`, state.coercion.bind(null, value)]);
|
118
|
+
}
|
119
|
+
}
|
120
|
+
if (!Array.isArray(value))
|
121
|
+
return pushError(state, `Expected a tuple (got ${getPrintable(value)})`);
|
122
|
+
let valid = lengthValidator(value, Object.assign({}, state));
|
123
|
+
for (let t = 0, T = value.length; t < T && t < spec.length; ++t) {
|
124
|
+
valid = spec[t](value[t], Object.assign(Object.assign({}, state), { p: computeKey(state, t), coercion: makeCoercionFn(value, t) })) && valid;
|
125
|
+
if (!valid && (state === null || state === undefined ? undefined : state.errors) == null) {
|
126
|
+
break;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
return valid;
|
130
|
+
},
|
131
|
+
});
|
132
|
+
}
|
133
|
+
/**
|
134
|
+
* Create a validator that only returns true when the tested value is an
|
135
|
+
* object with any amount of properties that must all match the provided
|
136
|
+
* subspec. Refines the type to `Record<string, T>`, with `T` being the
|
137
|
+
* subspec inferred type.
|
138
|
+
*
|
139
|
+
* Keys can be optionally validated as well by using the `keys` optional
|
140
|
+
* subspec parameter.
|
141
|
+
*/
|
142
|
+
function isRecord(spec, { keys: keySpec = null, } = {}) {
|
143
|
+
const isArrayValidator = isArray(isTuple([keySpec !== null && keySpec !== undefined ? keySpec : isString(), spec]));
|
144
|
+
return makeValidator({
|
145
|
+
test: (value, state) => {
|
146
|
+
var _a;
|
147
|
+
if (Array.isArray(value)) {
|
148
|
+
if (typeof (state === null || state === undefined ? undefined : state.coercions) !== `undefined`) {
|
149
|
+
if (typeof (state === null || state === undefined ? undefined : state.coercion) === `undefined`)
|
150
|
+
return pushError(state, `Unbound coercion result`);
|
151
|
+
if (!isArrayValidator(value, Object.assign(Object.assign({}, state), { coercion: undefined })))
|
152
|
+
return false;
|
153
|
+
value = Object.fromEntries(value);
|
154
|
+
state.coercions.push([(_a = state.p) !== null && _a !== undefined ? _a : `.`, state.coercion.bind(null, value)]);
|
155
|
+
return true;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
if (typeof value !== `object` || value === null)
|
159
|
+
return pushError(state, `Expected an object (got ${getPrintable(value)})`);
|
160
|
+
const keys = Object.keys(value);
|
161
|
+
let valid = true;
|
162
|
+
for (let t = 0, T = keys.length; t < T && (valid || (state === null || state === undefined ? undefined : state.errors) != null); ++t) {
|
163
|
+
const key = keys[t];
|
164
|
+
const sub = value[key];
|
165
|
+
if (key === `__proto__` || key === `constructor`) {
|
166
|
+
valid = pushError(Object.assign(Object.assign({}, state), { p: computeKey(state, key) }), `Unsafe property name`);
|
167
|
+
continue;
|
168
|
+
}
|
169
|
+
if (keySpec !== null && !keySpec(key, state)) {
|
170
|
+
valid = false;
|
171
|
+
continue;
|
172
|
+
}
|
173
|
+
if (!spec(sub, Object.assign(Object.assign({}, state), { p: computeKey(state, key), coercion: makeCoercionFn(value, key) }))) {
|
174
|
+
valid = false;
|
175
|
+
continue;
|
176
|
+
}
|
177
|
+
}
|
178
|
+
return valid;
|
179
|
+
},
|
180
|
+
});
|
181
|
+
}
|
182
|
+
/**
|
183
|
+
* @deprecated Replace `isDict` by `isRecord`
|
184
|
+
*/
|
185
|
+
function isDict(spec, opts = {}) {
|
186
|
+
return isRecord(spec, opts);
|
187
|
+
}
|
188
|
+
|
189
|
+
function makeTrait(value) {
|
190
|
+
return () => {
|
191
|
+
return value;
|
192
|
+
};
|
193
|
+
}
|
194
|
+
function makeValidator({ test }) {
|
195
|
+
return makeTrait(test)();
|
196
|
+
}
|
197
|
+
/**
|
198
|
+
* Create a validator that checks that the tested array or string has exactly
|
199
|
+
* the specified length.
|
200
|
+
*/
|
201
|
+
function hasExactLength(length) {
|
202
|
+
return makeValidator({
|
203
|
+
test: (value, state) => {
|
204
|
+
if (!(value.length === length))
|
205
|
+
return pushError(state, `Expected to have a length of exactly ${length} elements (got ${value.length})`);
|
206
|
+
return true;
|
207
|
+
},
|
208
|
+
});
|
209
|
+
}
|
210
|
+
|
211
|
+
function cascade(spec, ...followups) {
|
212
|
+
const resolvedFollowups = Array.isArray(followups[0])
|
213
|
+
? followups[0]
|
214
|
+
: followups;
|
215
|
+
return makeValidator({
|
216
|
+
test: (value, state) => {
|
217
|
+
var _a, _b;
|
218
|
+
const context = { value: value };
|
219
|
+
const subCoercion = typeof (state === null || state === undefined ? undefined : state.coercions) !== `undefined`
|
220
|
+
? makeCoercionFn(context, `value`) : undefined;
|
221
|
+
const subCoercions = typeof (state === null || state === undefined ? undefined : state.coercions) !== `undefined`
|
222
|
+
? [] : undefined;
|
223
|
+
if (!spec(value, Object.assign(Object.assign({}, state), { coercion: subCoercion, coercions: subCoercions })))
|
224
|
+
return false;
|
225
|
+
const reverts = [];
|
226
|
+
if (typeof subCoercions !== `undefined`)
|
227
|
+
for (const [, coercion] of subCoercions)
|
228
|
+
reverts.push(coercion());
|
229
|
+
try {
|
230
|
+
if (typeof (state === null || state === void 0 ? void 0 : state.coercions) !== `undefined`) {
|
231
|
+
if (context.value !== value) {
|
232
|
+
if (typeof (state === null || state === void 0 ? void 0 : state.coercion) === `undefined`)
|
233
|
+
return pushError(state, `Unbound coercion result`);
|
234
|
+
state.coercions.push([(_a = state.p) !== null && _a !== void 0 ? _a : `.`, state.coercion.bind(null, context.value)]);
|
235
|
+
}
|
236
|
+
(_b = state === null || state === void 0 ? void 0 : state.coercions) === null || _b === void 0 ? void 0 : _b.push(...subCoercions);
|
237
|
+
}
|
238
|
+
return resolvedFollowups.every(spec => {
|
239
|
+
return spec(context.value, state);
|
240
|
+
});
|
241
|
+
}
|
242
|
+
finally {
|
243
|
+
for (const revert of reverts) {
|
244
|
+
revert();
|
245
|
+
}
|
246
|
+
}
|
247
|
+
},
|
248
|
+
});
|
249
|
+
}
|
250
|
+
function applyCascade(spec, ...followups) {
|
251
|
+
const resolvedFollowups = Array.isArray(followups[0])
|
252
|
+
? followups[0]
|
253
|
+
: followups;
|
254
|
+
return cascade(spec, resolvedFollowups);
|
255
|
+
}
|
256
|
+
var KeyRelationship;
|
257
|
+
(function (KeyRelationship) {
|
258
|
+
KeyRelationship["Forbids"] = "Forbids";
|
259
|
+
KeyRelationship["Requires"] = "Requires";
|
260
|
+
})(KeyRelationship || (KeyRelationship = {}));
|
261
|
+
({
|
262
|
+
[KeyRelationship.Forbids]: {
|
263
|
+
expect: false,
|
264
|
+
message: `forbids using`,
|
265
|
+
},
|
266
|
+
[KeyRelationship.Requires]: {
|
267
|
+
expect: true,
|
268
|
+
message: `requires using`,
|
269
|
+
},
|
270
|
+
});
|
271
|
+
|
272
|
+
export { KeyRelationship, applyCascade, cascade, hasExactLength, isArray, isDict, isRecord, isString, isTuple, isUnknown, makeTrait, makeValidator };
|