@oh-my-pi/omptype 18.0.11 → 18.1.0
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/js/compile.js +12 -10
- package/dist/js/interp.js +1 -0
- package/dist/js/keywords.js +3 -3
- package/dist/js/type.js +12 -19
- package/package.json +5 -5
- package/src/compile.ts +12 -10
- package/src/infer.ts +52 -37
- package/src/interp.ts +1 -0
- package/src/keywords.ts +3 -3
- package/src/type.ts +17 -26
package/dist/js/compile.js
CHANGED
|
@@ -907,11 +907,12 @@ export function compile(ir) {
|
|
|
907
907
|
// array), and each re-entry must reuse this build instead of starting a
|
|
908
908
|
// fresh one forever. The wrapper resolves to the built validator by call
|
|
909
909
|
// time; the interpreter is a safety net that never triggers post-build.
|
|
910
|
-
|
|
911
|
-
compiledCache.set(root, value => (built === undefined ? walk(root, value) : built(value)));
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
910
|
+
const built = {};
|
|
911
|
+
compiledCache.set(root, value => (built.value === undefined ? walk(root, value) : built.value(value)));
|
|
912
|
+
const compiled = new Builder().build(root);
|
|
913
|
+
built.value = compiled;
|
|
914
|
+
compiledCache.set(root, compiled);
|
|
915
|
+
return compiled;
|
|
915
916
|
}
|
|
916
917
|
return validator;
|
|
917
918
|
}
|
|
@@ -920,11 +921,12 @@ export function compileAllows(ir) {
|
|
|
920
921
|
const root = resolvedRoot(ir);
|
|
921
922
|
const validator = allowsCache.get(root);
|
|
922
923
|
if (validator === undefined) {
|
|
923
|
-
|
|
924
|
-
allowsCache.set(root, ((value) => built === undefined ? !(walk(root, value) instanceof OmpErrors) : built(value)));
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
924
|
+
const built = {};
|
|
925
|
+
allowsCache.set(root, ((value) => built.value === undefined ? !(walk(root, value) instanceof OmpErrors) : built.value(value)));
|
|
926
|
+
const compiled = new Builder().buildAllows(root);
|
|
927
|
+
built.value = compiled;
|
|
928
|
+
allowsCache.set(root, compiled);
|
|
929
|
+
return compiled;
|
|
928
930
|
}
|
|
929
931
|
return validator;
|
|
930
932
|
}
|
package/dist/js/interp.js
CHANGED
|
@@ -328,6 +328,7 @@ function visitNode(ir, v, path) {
|
|
|
328
328
|
if (ir.max !== undefined && v.length > ir.max)
|
|
329
329
|
return fail(path, `at most length ${ir.max}`, v.length);
|
|
330
330
|
const morph = hasMorph(ir.el);
|
|
331
|
+
// oxlint-disable-next-line unicorn/no-new-array -- length preallocation
|
|
331
332
|
const out = morph ? new Array(v.length) : v;
|
|
332
333
|
let errors;
|
|
333
334
|
for (let index = 0; index < v.length; index++) {
|
package/dist/js/keywords.js
CHANGED
|
@@ -98,8 +98,8 @@ function finiteNumber(expected = "a number") {
|
|
|
98
98
|
};
|
|
99
99
|
}
|
|
100
100
|
function jsonObject() {
|
|
101
|
-
|
|
102
|
-
const resolveValue = () => value;
|
|
101
|
+
const value = {};
|
|
102
|
+
const resolveValue = () => value.current;
|
|
103
103
|
const object = {
|
|
104
104
|
k: "object",
|
|
105
105
|
props: [],
|
|
@@ -111,7 +111,7 @@ function jsonObject() {
|
|
|
111
111
|
el: { k: "alias", name: "$jsonValue", resolve: resolveValue },
|
|
112
112
|
desc: "an object",
|
|
113
113
|
};
|
|
114
|
-
value = {
|
|
114
|
+
value.current = {
|
|
115
115
|
k: "union",
|
|
116
116
|
members: [
|
|
117
117
|
object,
|
package/dist/js/type.js
CHANGED
|
@@ -2071,14 +2071,14 @@ function parseGenericArgument(definition, outer) {
|
|
|
2071
2071
|
throw error;
|
|
2072
2072
|
}
|
|
2073
2073
|
}
|
|
2074
|
-
|
|
2074
|
+
const root = {};
|
|
2075
2075
|
const self = {
|
|
2076
2076
|
k: "alias",
|
|
2077
2077
|
name: "this",
|
|
2078
2078
|
resolve: () => {
|
|
2079
|
-
if (root === undefined || root === self)
|
|
2079
|
+
if (root.current === undefined || root.current === self)
|
|
2080
2080
|
throw new OmpTypeError('"this" cannot be used as a root definition');
|
|
2081
|
-
return root;
|
|
2081
|
+
return root.current;
|
|
2082
2082
|
},
|
|
2083
2083
|
};
|
|
2084
2084
|
const resolve = ((name) => (name === "this" ? self : outer?.(name)));
|
|
@@ -2091,10 +2091,10 @@ function parseGenericArgument(definition, outer) {
|
|
|
2091
2091
|
// strings inside the definition may still share the string cache.
|
|
2092
2092
|
markThisOnlyResolver(resolve);
|
|
2093
2093
|
}
|
|
2094
|
-
root = parseDef(definition, resolve);
|
|
2095
|
-
if (root === self)
|
|
2094
|
+
root.current = parseDef(definition, resolve);
|
|
2095
|
+
if (root.current === self)
|
|
2096
2096
|
throw new OmpTypeError('"this" cannot be used as a root definition');
|
|
2097
|
-
return root;
|
|
2097
|
+
return root.current;
|
|
2098
2098
|
}
|
|
2099
2099
|
function genericBodyIR(parameters, definition, arguments_, outer) {
|
|
2100
2100
|
const resolve = genericResolver(parameters, arguments_, outer);
|
|
@@ -2139,17 +2139,15 @@ function createRuntimeGeneric(parameters, definition, outer, validateBody = true
|
|
|
2139
2139
|
return generic;
|
|
2140
2140
|
}
|
|
2141
2141
|
export function type(first) {
|
|
2142
|
-
// biome-ignore lint/complexity/noArguments: Avoid allocating a rest array for the dominant single-definition call.
|
|
2143
2142
|
const count = arguments.length;
|
|
2144
2143
|
if (count === 2 && typeof first === "string" && first.trimStart().startsWith("<")) {
|
|
2145
|
-
// biome-ignore lint/complexity/noArguments: The generic path reads its second positional argument without a rest array.
|
|
2146
2144
|
return createRuntimeGeneric(parseGenericParameters(first), arguments[1]);
|
|
2147
2145
|
}
|
|
2148
2146
|
let definition = first;
|
|
2149
2147
|
if (count !== 1) {
|
|
2148
|
+
// oxlint-disable-next-line unicorn/no-new-array -- length preallocation
|
|
2150
2149
|
const expression = new Array(count);
|
|
2151
2150
|
for (let index = 0; index < count; index++) {
|
|
2152
|
-
// biome-ignore lint/complexity/noArguments: Only multi-part expressions pay to materialize an argument array.
|
|
2153
2151
|
expression[index] = arguments[index];
|
|
2154
2152
|
}
|
|
2155
2153
|
definition = expression;
|
|
@@ -2452,7 +2450,6 @@ function makeFn(resolve) {
|
|
|
2452
2450
|
return Object.assign(parser, { raw: parser });
|
|
2453
2451
|
}
|
|
2454
2452
|
/** Fix a schema's externally declared static type without changing its runtime validation. */
|
|
2455
|
-
// biome-ignore lint/complexity/noBannedTypes: empty default options object
|
|
2456
2453
|
export function declare() {
|
|
2457
2454
|
return {
|
|
2458
2455
|
type: definition => type(definition),
|
|
@@ -2710,7 +2707,6 @@ function naryStatics(resolve) {
|
|
|
2710
2707
|
RegExp: keywordSchema("RegExp"),
|
|
2711
2708
|
File: keywordSchema("File"),
|
|
2712
2709
|
Error: keywordSchema("Error"),
|
|
2713
|
-
// biome-ignore lint/complexity/noBannedTypes: built-in Function keyword
|
|
2714
2710
|
Function: keywordSchema("Function"),
|
|
2715
2711
|
Array: {
|
|
2716
2712
|
liftFrom(definition) {
|
|
@@ -2761,7 +2757,6 @@ function naryStatics(resolve) {
|
|
|
2761
2757
|
unknown: { any: keywordSchema("unknown.any") },
|
|
2762
2758
|
};
|
|
2763
2759
|
/** Date instance validator. */
|
|
2764
|
-
// biome-ignore lint/suspicious/noShadowRestrictedNames: ArkType exposes this exact keyword.
|
|
2765
2760
|
type.Date = makeType({ k: "instance", ctor: globalThis.Date, expected: "a Date" }, [], {});
|
|
2766
2761
|
/** Validate instances of `ctor`. */
|
|
2767
2762
|
function instanceOf(ctor) {
|
|
@@ -2795,7 +2790,6 @@ function naryStatics(resolve) {
|
|
|
2795
2790
|
}
|
|
2796
2791
|
type.enumeration = enumeration;
|
|
2797
2792
|
/** Enumerate an enum-like object's forward values, excluding numeric reverse mappings. */
|
|
2798
|
-
// biome-ignore lint/suspicious/noShadowRestrictedNames: Object.prototype.valueOf method name API
|
|
2799
2793
|
function valueOf(values) {
|
|
2800
2794
|
const members = [];
|
|
2801
2795
|
for (const key in values) {
|
|
@@ -2817,7 +2811,6 @@ function naryStatics(resolve) {
|
|
|
2817
2811
|
/** Build a function whose arguments and optional declared return are validated. */
|
|
2818
2812
|
type.fn = makeFn();
|
|
2819
2813
|
/** Fix an externally declared static type while retaining runtime validation. */
|
|
2820
|
-
// biome-ignore lint/complexity/noBannedTypes: empty default options object
|
|
2821
2814
|
type.declare = () => ({
|
|
2822
2815
|
type: definition => type(definition),
|
|
2823
2816
|
});
|
|
@@ -2932,7 +2925,7 @@ function buildScope(aliases, options) {
|
|
|
2932
2925
|
}
|
|
2933
2926
|
const references = new Map();
|
|
2934
2927
|
const targets = new Map();
|
|
2935
|
-
|
|
2928
|
+
const scopeValue = {};
|
|
2936
2929
|
const materialize = (entry) => {
|
|
2937
2930
|
if (entry.materialized)
|
|
2938
2931
|
return entry.definition;
|
|
@@ -3023,7 +3016,7 @@ function buildScope(aliases, options) {
|
|
|
3023
3016
|
return target;
|
|
3024
3017
|
};
|
|
3025
3018
|
const bind = (schema) => {
|
|
3026
|
-
Reflect.set(schema, "$", scopeValue);
|
|
3019
|
+
Reflect.set(schema, "$", scopeValue.current);
|
|
3027
3020
|
Reflect.set(schema, "resolver", resolve);
|
|
3028
3021
|
return schema;
|
|
3029
3022
|
};
|
|
@@ -3046,7 +3039,7 @@ function buildScope(aliases, options) {
|
|
|
3046
3039
|
const schemaFor = (name) => bind(makeType(withScopeConfig(targetFor(name)), EMPTY_STEPS, scopeMeta));
|
|
3047
3040
|
const bindModule = (names) => {
|
|
3048
3041
|
const module = {};
|
|
3049
|
-
Object.defineProperty(module, MODULE_SCOPE, { value: scopeValue });
|
|
3042
|
+
Object.defineProperty(module, MODULE_SCOPE, { value: scopeValue.current });
|
|
3050
3043
|
for (const name of names) {
|
|
3051
3044
|
const entry = entries.get(name);
|
|
3052
3045
|
if (entry === undefined)
|
|
@@ -3060,7 +3053,7 @@ function buildScope(aliases, options) {
|
|
|
3060
3053
|
}
|
|
3061
3054
|
return module;
|
|
3062
3055
|
};
|
|
3063
|
-
scopeValue = {
|
|
3056
|
+
scopeValue.current = {
|
|
3064
3057
|
type: scoped,
|
|
3065
3058
|
match: scopedMatch,
|
|
3066
3059
|
define(definition) {
|
|
@@ -3113,7 +3106,7 @@ function buildScope(aliases, options) {
|
|
|
3113
3106
|
return json;
|
|
3114
3107
|
},
|
|
3115
3108
|
};
|
|
3116
|
-
return scopeValue;
|
|
3109
|
+
return scopeValue.current;
|
|
3117
3110
|
}
|
|
3118
3111
|
/** `hasMorph` re-export for diagnostics/tooling. */
|
|
3119
3112
|
export { hasMorph };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/omptype",
|
|
4
|
-
"version": "18.0
|
|
4
|
+
"version": "18.1.0",
|
|
5
5
|
"description": "ArkType-compatible runtime schema validation with lazy JIT compilation",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Stencil Labs, Inc.",
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"main": "./dist/js/index.js",
|
|
24
24
|
"types": "./dist/types/index.d.ts",
|
|
25
25
|
"scripts": {
|
|
26
|
-
"check": "
|
|
26
|
+
"check": "oxlint . && oxfmt --check --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts' && bun run check:types",
|
|
27
27
|
"check:types": "tsgo -p tsconfig.json --noEmit",
|
|
28
|
-
"lint": "
|
|
29
|
-
"fix": "
|
|
30
|
-
"fmt": "
|
|
28
|
+
"lint": "oxlint .",
|
|
29
|
+
"fix": "oxlint --fix --fix-suggestions . && bun run fmt",
|
|
30
|
+
"fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'",
|
|
31
31
|
"test": "bun test --parallel",
|
|
32
32
|
"bench": "bun bench/bench.ts"
|
|
33
33
|
},
|
package/src/compile.ts
CHANGED
|
@@ -1108,11 +1108,12 @@ export function compile(ir: IR): (value: unknown) => unknown {
|
|
|
1108
1108
|
// array), and each re-entry must reuse this build instead of starting a
|
|
1109
1109
|
// fresh one forever. The wrapper resolves to the built validator by call
|
|
1110
1110
|
// time; the interpreter is a safety net that never triggers post-build.
|
|
1111
|
-
|
|
1112
|
-
compiledCache.set(root, value => (built === undefined ? walk(root, value) : built(value)));
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1111
|
+
const built: { value?: (value: unknown) => unknown } = {};
|
|
1112
|
+
compiledCache.set(root, value => (built.value === undefined ? walk(root, value) : built.value(value)));
|
|
1113
|
+
const compiled = new Builder().build(root);
|
|
1114
|
+
built.value = compiled;
|
|
1115
|
+
compiledCache.set(root, compiled);
|
|
1116
|
+
return compiled;
|
|
1116
1117
|
}
|
|
1117
1118
|
return validator;
|
|
1118
1119
|
}
|
|
@@ -1122,14 +1123,15 @@ export function compileAllows(ir: IR): (value: unknown) => value is unknown {
|
|
|
1122
1123
|
const root = resolvedRoot(ir);
|
|
1123
1124
|
const validator = allowsCache.get(root);
|
|
1124
1125
|
if (validator === undefined) {
|
|
1125
|
-
|
|
1126
|
+
const built: { value?: (value: unknown) => value is unknown } = {};
|
|
1126
1127
|
allowsCache.set(root, ((value: unknown) =>
|
|
1127
|
-
built === undefined ? !(walk(root, value) instanceof OmpErrors) : built(value)) as (
|
|
1128
|
+
built.value === undefined ? !(walk(root, value) instanceof OmpErrors) : built.value(value)) as (
|
|
1128
1129
|
value: unknown,
|
|
1129
1130
|
) => value is unknown);
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1131
|
+
const compiled = new Builder().buildAllows(root);
|
|
1132
|
+
built.value = compiled;
|
|
1133
|
+
allowsCache.set(root, compiled);
|
|
1134
|
+
return compiled;
|
|
1133
1135
|
}
|
|
1134
1136
|
return validator;
|
|
1135
1137
|
}
|
package/src/infer.ts
CHANGED
|
@@ -37,7 +37,6 @@ interface PrimitiveMap {
|
|
|
37
37
|
Key: PropertyKey;
|
|
38
38
|
Date: Date;
|
|
39
39
|
Array: unknown[];
|
|
40
|
-
// biome-ignore lint/complexity/noBannedTypes: built-in Function keyword
|
|
41
40
|
Function: Function;
|
|
42
41
|
RegExp: RegExp;
|
|
43
42
|
File: File;
|
|
@@ -214,35 +213,43 @@ type UnwrapProperty<def> = def extends readonly [infer value, "?" | "=", ...unkn
|
|
|
214
213
|
type Simplify<t> = { [key in keyof t]: t[key] };
|
|
215
214
|
|
|
216
215
|
type OutputRequired<def extends object> = {
|
|
217
|
-
-readonly [
|
|
218
|
-
|
|
219
|
-
?
|
|
220
|
-
|
|
221
|
-
|
|
216
|
+
-readonly [
|
|
217
|
+
key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
|
|
218
|
+
? HasDefault<def[key]> extends true
|
|
219
|
+
? PropName<key>
|
|
220
|
+
: never
|
|
221
|
+
: PropName<key>
|
|
222
|
+
]-?: InferDef<UnwrapProperty<def[key]>>;
|
|
222
223
|
};
|
|
223
224
|
|
|
224
225
|
type OutputOptional<def extends object> = {
|
|
225
|
-
-readonly [
|
|
226
|
-
|
|
227
|
-
?
|
|
228
|
-
|
|
229
|
-
|
|
226
|
+
-readonly [
|
|
227
|
+
key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
|
|
228
|
+
? HasDefault<def[key]> extends true
|
|
229
|
+
? never
|
|
230
|
+
: PropName<key>
|
|
231
|
+
: never
|
|
232
|
+
]?: InferDef<UnwrapProperty<def[key]>>;
|
|
230
233
|
};
|
|
231
234
|
|
|
232
235
|
type InputRequired<def extends object> = {
|
|
233
|
-
-readonly [
|
|
234
|
-
|
|
235
|
-
: HasDefault<def[key]> extends true
|
|
236
|
+
-readonly [
|
|
237
|
+
key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
|
|
236
238
|
? never
|
|
237
|
-
:
|
|
239
|
+
: HasDefault<def[key]> extends true
|
|
240
|
+
? never
|
|
241
|
+
: PropName<key>
|
|
242
|
+
]-?: InferDefIn<UnwrapProperty<def[key]>>;
|
|
238
243
|
};
|
|
239
244
|
|
|
240
245
|
type InputOptional<def extends object> = {
|
|
241
|
-
-readonly [
|
|
242
|
-
|
|
243
|
-
: HasDefault<def[key]> extends true
|
|
246
|
+
-readonly [
|
|
247
|
+
key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
|
|
244
248
|
? PropName<key>
|
|
245
|
-
:
|
|
249
|
+
: HasDefault<def[key]> extends true
|
|
250
|
+
? PropName<key>
|
|
251
|
+
: never
|
|
252
|
+
]?: InferDefIn<UnwrapProperty<def[key]>>;
|
|
246
253
|
};
|
|
247
254
|
|
|
248
255
|
/**
|
|
@@ -302,35 +309,43 @@ type InferLiteralDefIn<def> = def extends { readonly inferIn: infer input }
|
|
|
302
309
|
: unknown;
|
|
303
310
|
|
|
304
311
|
type LiteralRequired<def extends object> = {
|
|
305
|
-
-readonly [
|
|
306
|
-
|
|
307
|
-
?
|
|
308
|
-
|
|
309
|
-
|
|
312
|
+
-readonly [
|
|
313
|
+
key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
|
|
314
|
+
? HasDefault<def[key]> extends true
|
|
315
|
+
? PropName<key>
|
|
316
|
+
: never
|
|
317
|
+
: PropName<key>
|
|
318
|
+
]-?: InferLiteralDef<UnwrapProperty<def[key]>>;
|
|
310
319
|
};
|
|
311
320
|
|
|
312
321
|
type LiteralOptional<def extends object> = {
|
|
313
|
-
-readonly [
|
|
314
|
-
|
|
315
|
-
?
|
|
316
|
-
|
|
317
|
-
|
|
322
|
+
-readonly [
|
|
323
|
+
key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
|
|
324
|
+
? HasDefault<def[key]> extends true
|
|
325
|
+
? never
|
|
326
|
+
: PropName<key>
|
|
327
|
+
: never
|
|
328
|
+
]?: InferLiteralDef<UnwrapProperty<def[key]>>;
|
|
318
329
|
};
|
|
319
330
|
|
|
320
331
|
type LiteralRequiredIn<def extends object> = {
|
|
321
|
-
-readonly [
|
|
322
|
-
|
|
323
|
-
: HasDefault<def[key]> extends true
|
|
332
|
+
-readonly [
|
|
333
|
+
key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
|
|
324
334
|
? never
|
|
325
|
-
:
|
|
335
|
+
: HasDefault<def[key]> extends true
|
|
336
|
+
? never
|
|
337
|
+
: PropName<key>
|
|
338
|
+
]-?: InferLiteralDefIn<UnwrapProperty<def[key]>>;
|
|
326
339
|
};
|
|
327
340
|
|
|
328
341
|
type LiteralOptionalIn<def extends object> = {
|
|
329
|
-
-readonly [
|
|
330
|
-
|
|
331
|
-
: HasDefault<def[key]> extends true
|
|
342
|
+
-readonly [
|
|
343
|
+
key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
|
|
332
344
|
? PropName<key>
|
|
333
|
-
:
|
|
345
|
+
: HasDefault<def[key]> extends true
|
|
346
|
+
? PropName<key>
|
|
347
|
+
: never
|
|
348
|
+
]?: InferLiteralDefIn<UnwrapProperty<def[key]>>;
|
|
334
349
|
};
|
|
335
350
|
|
|
336
351
|
/** Object-literal inference that unwraps embedded schema values one level deep. */
|
package/src/interp.ts
CHANGED
|
@@ -293,6 +293,7 @@ function visitNode(ir: IR, v: unknown, path: PropertyKey[]): unknown {
|
|
|
293
293
|
if (ir.min !== undefined && v.length < ir.min) return fail(path, `at least length ${ir.min}`, v.length);
|
|
294
294
|
if (ir.max !== undefined && v.length > ir.max) return fail(path, `at most length ${ir.max}`, v.length);
|
|
295
295
|
const morph = hasMorph(ir.el);
|
|
296
|
+
// oxlint-disable-next-line unicorn/no-new-array -- length preallocation
|
|
296
297
|
const out = morph ? new Array<unknown>(v.length) : v;
|
|
297
298
|
let errors: OmpErrors | undefined;
|
|
298
299
|
for (let index = 0; index < v.length; index++) {
|
package/src/keywords.ts
CHANGED
|
@@ -116,8 +116,8 @@ function finiteNumber(expected = "a number"): IR {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
function jsonObject(): IR {
|
|
119
|
-
|
|
120
|
-
const resolveValue = (): IR => value;
|
|
119
|
+
const value: { current?: IR } = {};
|
|
120
|
+
const resolveValue = (): IR => value.current as IR;
|
|
121
121
|
const object: IR = {
|
|
122
122
|
k: "object",
|
|
123
123
|
props: [],
|
|
@@ -129,7 +129,7 @@ function jsonObject(): IR {
|
|
|
129
129
|
el: { k: "alias", name: "$jsonValue", resolve: resolveValue },
|
|
130
130
|
desc: "an object",
|
|
131
131
|
};
|
|
132
|
-
value = {
|
|
132
|
+
value.current = {
|
|
133
133
|
k: "union",
|
|
134
134
|
members: [
|
|
135
135
|
object,
|
package/src/type.ts
CHANGED
|
@@ -199,7 +199,6 @@ type NaryAndOutput<definitions extends readonly unknown[]> = definitions extends
|
|
|
199
199
|
type NaryAndInput<definitions extends readonly unknown[]> = definitions extends readonly []
|
|
200
200
|
? unknown
|
|
201
201
|
: SimplifyNary<UnionToIntersection<InferDefIn<definitions[number]>>>;
|
|
202
|
-
// biome-ignore lint/complexity/noBannedTypes: generic accumulator default
|
|
203
202
|
type ReduceNaryMergeOutput<definitions extends readonly unknown[], result = {}> = definitions extends readonly [
|
|
204
203
|
infer head,
|
|
205
204
|
...infer tail,
|
|
@@ -207,9 +206,7 @@ type ReduceNaryMergeOutput<definitions extends readonly unknown[], result = {}>
|
|
|
207
206
|
? ReduceNaryMergeOutput<tail, SimplifyNary<MergeTypes<result, InferDef<head>>>>
|
|
208
207
|
: definitions extends readonly []
|
|
209
208
|
? result
|
|
210
|
-
:
|
|
211
|
-
{};
|
|
212
|
-
// biome-ignore lint/complexity/noBannedTypes: generic accumulator default
|
|
209
|
+
: {};
|
|
213
210
|
type ReduceNaryMergeInput<definitions extends readonly unknown[], result = {}> = definitions extends readonly [
|
|
214
211
|
infer head,
|
|
215
212
|
...infer tail,
|
|
@@ -217,8 +214,7 @@ type ReduceNaryMergeInput<definitions extends readonly unknown[], result = {}> =
|
|
|
217
214
|
? ReduceNaryMergeInput<tail, SimplifyNary<MergeTypes<result, InferDefIn<head>>>>
|
|
218
215
|
: definitions extends readonly []
|
|
219
216
|
? result
|
|
220
|
-
:
|
|
221
|
-
{};
|
|
217
|
+
: {};
|
|
222
218
|
type NaryMergeOutput<definitions extends readonly unknown[]> = definitions extends readonly []
|
|
223
219
|
? object
|
|
224
220
|
: ReduceNaryMergeOutput<definitions>;
|
|
@@ -560,7 +556,8 @@ const EMPTY_META: TypeMeta = {};
|
|
|
560
556
|
const ARK_COMPAT_SCOPE = Object.freeze({ internal: Object.freeze({ name: "ark" as const }) });
|
|
561
557
|
|
|
562
558
|
interface InternalType
|
|
563
|
-
extends
|
|
559
|
+
extends
|
|
560
|
+
Type<unknown, unknown>,
|
|
564
561
|
FluentMethods<unknown, unknown>,
|
|
565
562
|
ObjectMethods<Record<PropertyKey, unknown>, unknown> {
|
|
566
563
|
(data: unknown): unknown;
|
|
@@ -2575,13 +2572,14 @@ function parseGenericArgument(definition: unknown, outer?: AliasResolver): IR {
|
|
|
2575
2572
|
if (!(error instanceof OmpTypeError) || !error.message.includes('unknown keyword "this"')) throw error;
|
|
2576
2573
|
}
|
|
2577
2574
|
}
|
|
2578
|
-
|
|
2575
|
+
const root: { current?: IR } = {};
|
|
2579
2576
|
const self: IR = {
|
|
2580
2577
|
k: "alias",
|
|
2581
2578
|
name: "this",
|
|
2582
2579
|
resolve: () => {
|
|
2583
|
-
if (root === undefined || root === self)
|
|
2584
|
-
|
|
2580
|
+
if (root.current === undefined || root.current === self)
|
|
2581
|
+
throw new OmpTypeError('"this" cannot be used as a root definition');
|
|
2582
|
+
return root.current;
|
|
2585
2583
|
},
|
|
2586
2584
|
};
|
|
2587
2585
|
const resolve = ((name: string) => (name === "this" ? self : outer?.(name))) as AliasResolver;
|
|
@@ -2593,9 +2591,9 @@ function parseGenericArgument(definition: unknown, outer?: AliasResolver): IR {
|
|
|
2593
2591
|
// strings inside the definition may still share the string cache.
|
|
2594
2592
|
markThisOnlyResolver(resolve);
|
|
2595
2593
|
}
|
|
2596
|
-
root = parseDef(definition, resolve);
|
|
2597
|
-
if (root === self) throw new OmpTypeError('"this" cannot be used as a root definition');
|
|
2598
|
-
return root;
|
|
2594
|
+
root.current = parseDef(definition, resolve);
|
|
2595
|
+
if (root.current === self) throw new OmpTypeError('"this" cannot be used as a root definition');
|
|
2596
|
+
return root.current;
|
|
2599
2597
|
}
|
|
2600
2598
|
|
|
2601
2599
|
function genericBodyIR(
|
|
@@ -2681,17 +2679,15 @@ export function type<const expression extends readonly unknown[]>(
|
|
|
2681
2679
|
...definition: expression
|
|
2682
2680
|
): FluentType<InferDef<expression>, InferDefIn<expression>>;
|
|
2683
2681
|
export function type(first?: unknown): FluentType<unknown> | Generic {
|
|
2684
|
-
// biome-ignore lint/complexity/noArguments: Avoid allocating a rest array for the dominant single-definition call.
|
|
2685
2682
|
const count = arguments.length;
|
|
2686
2683
|
if (count === 2 && typeof first === "string" && first.trimStart().startsWith("<")) {
|
|
2687
|
-
// biome-ignore lint/complexity/noArguments: The generic path reads its second positional argument without a rest array.
|
|
2688
2684
|
return createRuntimeGeneric(parseGenericParameters(first), arguments[1]);
|
|
2689
2685
|
}
|
|
2690
2686
|
let definition: unknown = first;
|
|
2691
2687
|
if (count !== 1) {
|
|
2688
|
+
// oxlint-disable-next-line unicorn/no-new-array -- length preallocation
|
|
2692
2689
|
const expression: unknown[] = new Array(count);
|
|
2693
2690
|
for (let index = 0; index < count; index++) {
|
|
2694
|
-
// biome-ignore lint/complexity/noArguments: Only multi-part expressions pay to materialize an argument array.
|
|
2695
2691
|
expression[index] = arguments[index];
|
|
2696
2692
|
}
|
|
2697
2693
|
definition = expression;
|
|
@@ -3160,7 +3156,6 @@ export interface DeclaredParser<declared> {
|
|
|
3160
3156
|
}
|
|
3161
3157
|
|
|
3162
3158
|
/** Fix a schema's externally declared static type without changing its runtime validation. */
|
|
3163
|
-
// biome-ignore lint/complexity/noBannedTypes: empty default options object
|
|
3164
3159
|
export function declare<declared, _options = {}>(): DeclaredParser<declared> {
|
|
3165
3160
|
return {
|
|
3166
3161
|
type: definition => type(definition) as unknown as FluentType<declared, InferDefIn<typeof definition>>,
|
|
@@ -3463,7 +3458,6 @@ export namespace type {
|
|
|
3463
3458
|
RegExp: keywordSchema<RegExp>("RegExp"),
|
|
3464
3459
|
File: keywordSchema<File>("File"),
|
|
3465
3460
|
Error: keywordSchema<Error>("Error"),
|
|
3466
|
-
// biome-ignore lint/complexity/noBannedTypes: built-in Function keyword
|
|
3467
3461
|
Function: keywordSchema<Function>("Function"),
|
|
3468
3462
|
Array: {
|
|
3469
3463
|
liftFrom<const definition>(
|
|
@@ -3567,7 +3561,6 @@ export namespace type {
|
|
|
3567
3561
|
unknown: { any: keywordSchema<unknown>("unknown.any") },
|
|
3568
3562
|
};
|
|
3569
3563
|
/** Date instance validator. */
|
|
3570
|
-
// biome-ignore lint/suspicious/noShadowRestrictedNames: ArkType exposes this exact keyword.
|
|
3571
3564
|
export const Date = makeType<globalThis.Date>({ k: "instance", ctor: globalThis.Date, expected: "a Date" }, [], {});
|
|
3572
3565
|
|
|
3573
3566
|
/** Validate instances of `ctor`. */
|
|
@@ -3604,7 +3597,6 @@ export namespace type {
|
|
|
3604
3597
|
}
|
|
3605
3598
|
|
|
3606
3599
|
/** Enumerate an enum-like object's forward values, excluding numeric reverse mappings. */
|
|
3607
|
-
// biome-ignore lint/suspicious/noShadowRestrictedNames: Object.prototype.valueOf method name API
|
|
3608
3600
|
export function valueOf<const values extends Record<PropertyKey, unknown>>(
|
|
3609
3601
|
values: values,
|
|
3610
3602
|
): FluentType<values[keyof values]> {
|
|
@@ -3629,7 +3621,6 @@ export namespace type {
|
|
|
3629
3621
|
export const fn: FnParser = makeFn();
|
|
3630
3622
|
|
|
3631
3623
|
/** Fix an externally declared static type while retaining runtime validation. */
|
|
3632
|
-
// biome-ignore lint/complexity/noBannedTypes: empty default options object
|
|
3633
3624
|
export const declare = <declared, _options = {}>(): DeclaredParser<declared> =>
|
|
3634
3625
|
({
|
|
3635
3626
|
type: definition => type(definition) as unknown as FluentType<declared, InferDefIn<typeof definition>>,
|
|
@@ -3802,7 +3793,7 @@ function buildScope(aliases: Record<string, unknown>, options?: ScopeOptions): T
|
|
|
3802
3793
|
|
|
3803
3794
|
const references = new Map<string, IR>();
|
|
3804
3795
|
const targets = new Map<string, IR>();
|
|
3805
|
-
|
|
3796
|
+
const scopeValue: { current?: TypeScope } = {};
|
|
3806
3797
|
|
|
3807
3798
|
const materialize = (entry: ScopeAlias): unknown => {
|
|
3808
3799
|
if (entry.materialized) return entry.definition;
|
|
@@ -3889,7 +3880,7 @@ function buildScope(aliases: Record<string, unknown>, options?: ScopeOptions): T
|
|
|
3889
3880
|
};
|
|
3890
3881
|
|
|
3891
3882
|
const bind = (schema: InternalType): InternalType => {
|
|
3892
|
-
Reflect.set(schema, "$", scopeValue);
|
|
3883
|
+
Reflect.set(schema, "$", scopeValue.current);
|
|
3893
3884
|
Reflect.set(schema, "resolver", resolve);
|
|
3894
3885
|
return schema;
|
|
3895
3886
|
};
|
|
@@ -3915,7 +3906,7 @@ function buildScope(aliases: Record<string, unknown>, options?: ScopeOptions): T
|
|
|
3915
3906
|
|
|
3916
3907
|
const bindModule = (names: readonly string[]): RuntimeModule => {
|
|
3917
3908
|
const module = {} as RuntimeModule;
|
|
3918
|
-
Object.defineProperty(module, MODULE_SCOPE, { value: scopeValue });
|
|
3909
|
+
Object.defineProperty(module, MODULE_SCOPE, { value: scopeValue.current });
|
|
3919
3910
|
for (const name of names) {
|
|
3920
3911
|
const entry = entries.get(name);
|
|
3921
3912
|
if (entry === undefined) continue;
|
|
@@ -3929,7 +3920,7 @@ function buildScope(aliases: Record<string, unknown>, options?: ScopeOptions): T
|
|
|
3929
3920
|
return module;
|
|
3930
3921
|
};
|
|
3931
3922
|
|
|
3932
|
-
scopeValue = {
|
|
3923
|
+
scopeValue.current = {
|
|
3933
3924
|
type: scoped,
|
|
3934
3925
|
match: scopedMatch,
|
|
3935
3926
|
define<const definition>(definition: definition): definition {
|
|
@@ -3979,7 +3970,7 @@ function buildScope(aliases: Record<string, unknown>, options?: ScopeOptions): T
|
|
|
3979
3970
|
return json;
|
|
3980
3971
|
},
|
|
3981
3972
|
};
|
|
3982
|
-
return scopeValue;
|
|
3973
|
+
return scopeValue.current;
|
|
3983
3974
|
}
|
|
3984
3975
|
|
|
3985
3976
|
/** A schema whose output type is not statically known (`type.raw` results). */
|