typebox 1.1.18 → 1.1.20
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/build/value/clean/from-union.mjs +2 -1
- package/build/value/codec/from-intersect.mjs +42 -12
- package/build/value/codec/from-object.mjs +1 -1
- package/build/value/codec/from-union.mjs +4 -6
- package/build/value/convert/from-object.mjs +1 -1
- package/build/value/index.d.mts +1 -0
- package/build/value/index.mjs +4 -0
- package/build/value/repair/from-union.mjs +3 -50
- package/build/value/shared/index.d.mts +2 -0
- package/build/value/shared/index.mjs +2 -0
- package/build/value/shared/union-priority-sort.d.mts +3 -0
- package/build/value/shared/union-priority-sort.mjs +36 -0
- package/build/value/shared/union-score-select.d.mts +3 -0
- package/build/value/shared/union-score-select.mjs +51 -0
- package/package.json +30 -30
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
import { Check } from '../check/index.mjs';
|
|
3
3
|
import { Clone } from '../clone/index.mjs';
|
|
4
4
|
import { FromType } from './from-type.mjs';
|
|
5
|
+
import { UnionPrioritySort } from '../shared/union-priority-sort.mjs';
|
|
5
6
|
export function FromUnion(context, type, value) {
|
|
6
|
-
for (const schema of type.anyOf) {
|
|
7
|
+
for (const schema of UnionPrioritySort(type.anyOf)) {
|
|
7
8
|
const clean = FromType(context, schema, Clone(value));
|
|
8
9
|
if (Check(context, schema, clean))
|
|
9
10
|
return clean;
|
|
@@ -2,27 +2,57 @@
|
|
|
2
2
|
import { Guard } from '../../guard/index.mjs';
|
|
3
3
|
import { FromType } from './from-type.mjs';
|
|
4
4
|
import { Callback } from './callback.mjs';
|
|
5
|
+
import { Clone } from '../clone/index.mjs';
|
|
6
|
+
import { Clean } from '../clean/index.mjs';
|
|
7
|
+
// ------------------------------------------------------------------
|
|
8
|
+
// MergeInteriors
|
|
9
|
+
//
|
|
10
|
+
// Merges all interior operand results into a single object. Each
|
|
11
|
+
// subsequent operand's properties override those of prior operands.
|
|
12
|
+
//
|
|
13
|
+
// ------------------------------------------------------------------
|
|
14
|
+
function MergeInteriors(interiors) {
|
|
15
|
+
return interiors.reduce((results, interior) => ({ ...results, ...interior }), {});
|
|
16
|
+
}
|
|
17
|
+
// ------------------------------------------------------------------
|
|
18
|
+
// NonMatchingInterior
|
|
19
|
+
//
|
|
20
|
+
// Used when Intersect operands do not all produce Objects. Returns
|
|
21
|
+
// the first interior result that differs from the original value,
|
|
22
|
+
// indicating a Codec has transformed the data. If no operand
|
|
23
|
+
// produced a change, defaults to the first interior result.
|
|
24
|
+
//
|
|
25
|
+
// ------------------------------------------------------------------
|
|
26
|
+
function NonMatchingInterior(value, interiors) {
|
|
27
|
+
for (const interior of interiors)
|
|
28
|
+
if (!Guard.IsDeepEqual(value, interior))
|
|
29
|
+
return interior;
|
|
30
|
+
return value; // value-unchanged
|
|
31
|
+
}
|
|
5
32
|
// ------------------------------------------------------------------
|
|
6
33
|
// Decode
|
|
7
34
|
// ------------------------------------------------------------------
|
|
8
35
|
function Decode(direction, context, type, value) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
36
|
+
if (Guard.IsEqual(type.allOf.length, 0))
|
|
37
|
+
return Callback(direction, context, type, value);
|
|
38
|
+
const interiors = type.allOf.map((schema) => FromType(direction, context, schema, Clean(schema, Clone(value))));
|
|
39
|
+
const structural = interiors.every((result) => Guard.IsObject(result));
|
|
40
|
+
const exterior = structural ? MergeInteriors(interiors) : NonMatchingInterior(value, interiors);
|
|
41
|
+
return Callback(direction, context, type, exterior);
|
|
13
42
|
}
|
|
14
43
|
// ------------------------------------------------------------------
|
|
15
44
|
// Encode
|
|
16
45
|
// ------------------------------------------------------------------
|
|
17
46
|
function Encode(direction, context, type, value) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
47
|
+
if (Guard.IsEqual(type.allOf.length, 0))
|
|
48
|
+
return Callback(direction, context, type, value);
|
|
49
|
+
const exterior = Callback(direction, context, type, value);
|
|
50
|
+
const interiors = type.allOf.map((schema) => FromType(direction, context, schema, Clean(schema, Clone(exterior))));
|
|
51
|
+
const structural = interiors.every((result) => Guard.IsObject(result));
|
|
52
|
+
if (structural)
|
|
53
|
+
return MergeInteriors(interiors);
|
|
54
|
+
return NonMatchingInterior(exterior, interiors);
|
|
23
55
|
}
|
|
24
56
|
export function FromIntersect(direction, context, type, value) {
|
|
25
|
-
return Guard.IsEqual(direction, 'Decode')
|
|
26
|
-
? Decode(direction, context, type, value)
|
|
27
|
-
: Encode(direction, context, type, value);
|
|
57
|
+
return Guard.IsEqual(direction, 'Decode') ? Decode(direction, context, type, value) : Encode(direction, context, type, value);
|
|
28
58
|
}
|
|
@@ -3,7 +3,7 @@ import { Unreachable } from '../../system/unreachable/index.mjs';
|
|
|
3
3
|
import { Guard } from '../../guard/index.mjs';
|
|
4
4
|
import { FromType } from './from-type.mjs';
|
|
5
5
|
import { Callback } from './callback.mjs';
|
|
6
|
-
import { IsOptionalUndefined } from '../shared/
|
|
6
|
+
import { IsOptionalUndefined } from '../shared/optional-undefined.mjs';
|
|
7
7
|
// ------------------------------------------------------------------
|
|
8
8
|
// Decode
|
|
9
9
|
// ------------------------------------------------------------------
|
|
@@ -1,30 +1,28 @@
|
|
|
1
1
|
// deno-fmt-ignore-file
|
|
2
|
-
import { Unreachable } from '../../system/unreachable/index.mjs';
|
|
3
2
|
import { Guard } from '../../guard/index.mjs';
|
|
4
3
|
import { Callback } from './callback.mjs';
|
|
5
4
|
import { FromType } from './from-type.mjs';
|
|
6
5
|
import { Clone } from '../clone/index.mjs';
|
|
7
6
|
import { Check } from '../check/index.mjs';
|
|
7
|
+
import { UnionPrioritySort } from '../shared/union-priority-sort.mjs';
|
|
8
8
|
// ------------------------------------------------------------------
|
|
9
9
|
// Decode
|
|
10
10
|
// ------------------------------------------------------------------
|
|
11
|
-
// deno-coverage-ignore-start - unreachable | checked
|
|
12
11
|
function Decode(direction, context, type, value) {
|
|
13
|
-
for (const schema of type.anyOf) {
|
|
12
|
+
for (const schema of UnionPrioritySort(type.anyOf, 1)) {
|
|
14
13
|
if (!Check(context, schema, value))
|
|
15
14
|
continue;
|
|
16
15
|
const variant = FromType(direction, context, schema, value);
|
|
17
16
|
return Callback(direction, context, type, variant);
|
|
18
17
|
}
|
|
19
|
-
return
|
|
18
|
+
return value;
|
|
20
19
|
}
|
|
21
|
-
// deno-coverage-ignore-stop
|
|
22
20
|
// ------------------------------------------------------------------
|
|
23
21
|
// Encode
|
|
24
22
|
// ------------------------------------------------------------------
|
|
25
23
|
function Encode(direction, context, type, value) {
|
|
26
24
|
let exterior = Callback(direction, context, type, value);
|
|
27
|
-
for (const schema of type.anyOf) {
|
|
25
|
+
for (const schema of UnionPrioritySort(type.anyOf, -1)) {
|
|
28
26
|
const variant = FromType(direction, context, schema, Clone(exterior));
|
|
29
27
|
if (!Check(context, schema, variant))
|
|
30
28
|
continue;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Guard } from '../../guard/index.mjs';
|
|
3
3
|
import { FromType } from './from-type.mjs';
|
|
4
4
|
import { FromAdditionalProperties } from './from-additional.mjs';
|
|
5
|
-
import { IsOptionalUndefined } from '../shared/
|
|
5
|
+
import { IsOptionalUndefined } from '../shared/optional-undefined.mjs';
|
|
6
6
|
// ------------------------------------------------------------------
|
|
7
7
|
// FromProperties
|
|
8
8
|
// ------------------------------------------------------------------
|
package/build/value/index.d.mts
CHANGED
|
@@ -15,6 +15,7 @@ export * from './delta/index.mjs';
|
|
|
15
15
|
export * from './pipeline/index.mjs';
|
|
16
16
|
export * from './pointer/index.mjs';
|
|
17
17
|
export * from './repair/index.mjs';
|
|
18
|
+
export * from './shared/index.mjs';
|
|
18
19
|
import * as Value from './value.mjs';
|
|
19
20
|
export * as Value from './value.mjs';
|
|
20
21
|
export default Value;
|
package/build/value/index.mjs
CHANGED
|
@@ -19,6 +19,10 @@ export * from './pipeline/index.mjs';
|
|
|
19
19
|
export * from './pointer/index.mjs';
|
|
20
20
|
export * from './repair/index.mjs';
|
|
21
21
|
// ------------------------------------------------------------------
|
|
22
|
+
// Shared
|
|
23
|
+
// ------------------------------------------------------------------
|
|
24
|
+
export * from './shared/index.mjs';
|
|
25
|
+
// ------------------------------------------------------------------
|
|
22
26
|
// Default
|
|
23
27
|
// ------------------------------------------------------------------
|
|
24
28
|
import * as Value from './value.mjs';
|
|
@@ -1,65 +1,18 @@
|
|
|
1
1
|
// deno-fmt-ignore-file
|
|
2
2
|
import { IsDefault } from '../../schema/types/index.mjs';
|
|
3
|
-
import { Union
|
|
3
|
+
import { Union } from '../../type/index.mjs';
|
|
4
4
|
import { Flatten } from '../../type/engine/evaluate/index.mjs';
|
|
5
|
-
import { Guard } from '../../guard/index.mjs';
|
|
6
5
|
import { Check } from '../check/index.mjs';
|
|
7
6
|
import { Clone } from '../clone/index.mjs';
|
|
8
7
|
import { Create } from '../create/index.mjs';
|
|
9
|
-
import { RepairError } from './error.mjs';
|
|
10
8
|
import { FromType } from './from-type.mjs';
|
|
11
|
-
|
|
12
|
-
// Deref
|
|
13
|
-
// ------------------------------------------------------------------
|
|
14
|
-
function Deref(context, type, value) {
|
|
15
|
-
return IsRef(type)
|
|
16
|
-
? Guard.HasPropertyKey(context, type.$ref)
|
|
17
|
-
? Deref(context, context[type.$ref], value)
|
|
18
|
-
: (() => { throw new RepairError(context, type, value, 'Unable to Deref target on Union repair'); })()
|
|
19
|
-
: type;
|
|
20
|
-
}
|
|
21
|
-
// ------------------------------------------------------------------
|
|
22
|
-
// The following will score a schema against a value. For objects,
|
|
23
|
-
// the score is the tally of points awarded for each property of
|
|
24
|
-
// the value. Property points are (1.0 / propertyCount) to prevent
|
|
25
|
-
// large property counts biasing results. Properties that match
|
|
26
|
-
// literal values are maximally awarded as literals are typically
|
|
27
|
-
// used as union discriminator fields.
|
|
28
|
-
// ------------------------------------------------------------------
|
|
29
|
-
function ScoreVariant(context, type, value) {
|
|
30
|
-
// scoring is only possible for object types.
|
|
31
|
-
if (!(IsObject(type) && Guard.IsObject(value)))
|
|
32
|
-
return 0;
|
|
33
|
-
const keys = Guard.Keys(value);
|
|
34
|
-
const entries = Guard.Entries(type.properties);
|
|
35
|
-
return entries.reduce((result, [key, schema]) => {
|
|
36
|
-
const literal = IsLiteral(schema) && Guard.IsEqual(schema.const, value[key]) ? 100 : 0;
|
|
37
|
-
const checks = Check(context, schema, value[key]) ? 10 : 0;
|
|
38
|
-
const exists = keys.includes(key) ? 1 : 0;
|
|
39
|
-
return result + (literal + checks + exists);
|
|
40
|
-
}, 0);
|
|
41
|
-
}
|
|
42
|
-
// ------------------------------------------------------------------
|
|
43
|
-
// SelectVariant
|
|
44
|
-
// ------------------------------------------------------------------
|
|
45
|
-
function SelectVariant(context, type, value) {
|
|
46
|
-
const schemas = type.anyOf.map((schema) => Deref(context, schema, value));
|
|
47
|
-
let [select, best] = [schemas[0], 0];
|
|
48
|
-
for (const schema of schemas) {
|
|
49
|
-
const score = ScoreVariant(context, schema, value);
|
|
50
|
-
if (score > best) {
|
|
51
|
-
select = schema;
|
|
52
|
-
best = score;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return select;
|
|
56
|
-
}
|
|
9
|
+
import { UnionScoreSelect } from '../shared/union-score-select.mjs';
|
|
57
10
|
// ------------------------------------------------------------------
|
|
58
11
|
// RepairUnion
|
|
59
12
|
// ------------------------------------------------------------------
|
|
60
13
|
function RepairUnion(context, type, value) {
|
|
61
14
|
const union = Union(Flatten(type.anyOf));
|
|
62
|
-
const schema =
|
|
15
|
+
const schema = UnionScoreSelect(context, union, value);
|
|
63
16
|
return FromType(context, schema, value);
|
|
64
17
|
}
|
|
65
18
|
export function FromUnion(context, type, value) {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// deno-fmt-ignore-file
|
|
2
|
+
import { Guard } from '../../guard/index.mjs';
|
|
3
|
+
import { Compare } from '../../type/index.mjs';
|
|
4
|
+
// ------------------------------------------------------------------
|
|
5
|
+
// DeterministicCompare
|
|
6
|
+
//
|
|
7
|
+
// Provides a deterministic tie-break for schemas. This is used when
|
|
8
|
+
// schemas are structurally disjoint or mutually inclusive. While
|
|
9
|
+
// JSON serialization incurs a performance overhead, it serves as a
|
|
10
|
+
// reliable mechanism to ensure stable ordering and preserves the
|
|
11
|
+
// alphabetical alignment of named constants.
|
|
12
|
+
//
|
|
13
|
+
// ------------------------------------------------------------------
|
|
14
|
+
function DeterministicCompare(left, right) {
|
|
15
|
+
return JSON.stringify(left).localeCompare(JSON.stringify(right));
|
|
16
|
+
}
|
|
17
|
+
// ------------------------------------------------------------------
|
|
18
|
+
// UnionPrioritySort
|
|
19
|
+
//
|
|
20
|
+
// Performs a deterministic sort on Union members. By default, this
|
|
21
|
+
// function ensures that narrow (more specific) types precede broader
|
|
22
|
+
// types in the resulting array. The order can be reversed by setting
|
|
23
|
+
// the order property to -1 which will reverse unions from broader
|
|
24
|
+
// to more narrow.
|
|
25
|
+
//
|
|
26
|
+
// ------------------------------------------------------------------
|
|
27
|
+
/** Deterministically sorts schemas by structural relationship (narrow to broad) */
|
|
28
|
+
export function UnionPrioritySort(types, order = 1) {
|
|
29
|
+
return types.sort((left, right) => {
|
|
30
|
+
const result = Compare(left, right);
|
|
31
|
+
return (Guard.IsEqual(result, 'disjoint') ? DeterministicCompare(left, right) :
|
|
32
|
+
Guard.IsEqual(result, 'right-inside') ? 1 :
|
|
33
|
+
Guard.IsEqual(result, 'left-inside') ? -1 :
|
|
34
|
+
DeterministicCompare(left, right)) * order;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// deno-fmt-ignore-file
|
|
2
|
+
import { IsLiteral, IsObject, IsRef } from '../../type/index.mjs';
|
|
3
|
+
import { Guard } from '../../guard/index.mjs';
|
|
4
|
+
import { Check } from '../check/index.mjs';
|
|
5
|
+
// ------------------------------------------------------------------
|
|
6
|
+
// Deref
|
|
7
|
+
// ------------------------------------------------------------------
|
|
8
|
+
function Deref(context, type, value) {
|
|
9
|
+
return IsRef(type)
|
|
10
|
+
? Guard.HasPropertyKey(context, type.$ref)
|
|
11
|
+
? Deref(context, context[type.$ref], value)
|
|
12
|
+
: (() => { throw new Error('Unable to Deref target'); })()
|
|
13
|
+
: type;
|
|
14
|
+
}
|
|
15
|
+
// ------------------------------------------------------------------
|
|
16
|
+
// The following will score a schema against a value. For objects,
|
|
17
|
+
// the score is the tally of points awarded for each property of
|
|
18
|
+
// the value. Property points are (1.0 / propertyCount) to prevent
|
|
19
|
+
// large property counts biasing results. Properties that match
|
|
20
|
+
// literal values are maximally awarded as literals are typically
|
|
21
|
+
// used as union discriminator fields.
|
|
22
|
+
// ------------------------------------------------------------------
|
|
23
|
+
function ScoreVariant(context, type, value) {
|
|
24
|
+
// scoring is only possible for object types.
|
|
25
|
+
if (!(IsObject(type) && Guard.IsObject(value)))
|
|
26
|
+
return 0;
|
|
27
|
+
const keys = Guard.Keys(value);
|
|
28
|
+
const entries = Guard.Entries(type.properties);
|
|
29
|
+
return entries.reduce((result, [key, schema]) => {
|
|
30
|
+
const literal = IsLiteral(schema) && Guard.IsEqual(schema.const, value[key]) ? 100 : 0;
|
|
31
|
+
const checks = Check(context, schema, value[key]) ? 10 : 0;
|
|
32
|
+
const exists = keys.includes(key) ? 1 : 0;
|
|
33
|
+
return result + (literal + checks + exists);
|
|
34
|
+
}, 0);
|
|
35
|
+
}
|
|
36
|
+
// ------------------------------------------------------------------
|
|
37
|
+
// UnionScoreSelect
|
|
38
|
+
// ------------------------------------------------------------------
|
|
39
|
+
/** Scores Union variants and returns the best match for the given value */
|
|
40
|
+
export function UnionScoreSelect(context, type, value) {
|
|
41
|
+
const schemas = type.anyOf.map((schema) => Deref(context, schema, value));
|
|
42
|
+
let [select, best] = [schemas[0], 0];
|
|
43
|
+
for (const schema of schemas) {
|
|
44
|
+
const score = ScoreVariant(context, schema, value);
|
|
45
|
+
if (score > best) {
|
|
46
|
+
select = schema;
|
|
47
|
+
best = score;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return select;
|
|
51
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typebox",
|
|
3
3
|
"description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.20",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
7
7
|
"jsonschema"
|
|
@@ -16,29 +16,21 @@
|
|
|
16
16
|
"types": "./build/index.d.mts",
|
|
17
17
|
"module": "./build/index.mjs",
|
|
18
18
|
"exports": {
|
|
19
|
-
"./
|
|
20
|
-
"import": "./build/
|
|
21
|
-
"default": "./build/
|
|
22
|
-
},
|
|
23
|
-
"./compile": {
|
|
24
|
-
"import": "./build/compile/index.mjs",
|
|
25
|
-
"default": "./build/compile/index.mjs"
|
|
26
|
-
},
|
|
27
|
-
"./value": {
|
|
28
|
-
"import": "./build/value/index.mjs",
|
|
29
|
-
"default": "./build/value/index.mjs"
|
|
19
|
+
"./guard": {
|
|
20
|
+
"import": "./build/guard/index.mjs",
|
|
21
|
+
"default": "./build/guard/index.mjs"
|
|
30
22
|
},
|
|
31
23
|
"./error": {
|
|
32
24
|
"import": "./build/error/index.mjs",
|
|
33
25
|
"default": "./build/error/index.mjs"
|
|
34
26
|
},
|
|
35
|
-
"./
|
|
36
|
-
"import": "./build/
|
|
37
|
-
"default": "./build/
|
|
27
|
+
"./compile": {
|
|
28
|
+
"import": "./build/compile/index.mjs",
|
|
29
|
+
"default": "./build/compile/index.mjs"
|
|
38
30
|
},
|
|
39
|
-
"./
|
|
40
|
-
"import": "./build/
|
|
41
|
-
"default": "./build/
|
|
31
|
+
"./system": {
|
|
32
|
+
"import": "./build/system/index.mjs",
|
|
33
|
+
"default": "./build/system/index.mjs"
|
|
42
34
|
},
|
|
43
35
|
"./format": {
|
|
44
36
|
"import": "./build/format/index.mjs",
|
|
@@ -48,6 +40,14 @@
|
|
|
48
40
|
"import": "./build/type/index.mjs",
|
|
49
41
|
"default": "./build/type/index.mjs"
|
|
50
42
|
},
|
|
43
|
+
"./schema": {
|
|
44
|
+
"import": "./build/schema/index.mjs",
|
|
45
|
+
"default": "./build/schema/index.mjs"
|
|
46
|
+
},
|
|
47
|
+
"./value": {
|
|
48
|
+
"import": "./build/value/index.mjs",
|
|
49
|
+
"default": "./build/value/index.mjs"
|
|
50
|
+
},
|
|
51
51
|
".": {
|
|
52
52
|
"import": "./build/index.mjs",
|
|
53
53
|
"default": "./build/index.mjs"
|
|
@@ -55,23 +55,17 @@
|
|
|
55
55
|
},
|
|
56
56
|
"typesVersions": {
|
|
57
57
|
"*": {
|
|
58
|
-
"
|
|
59
|
-
"./build/
|
|
60
|
-
],
|
|
61
|
-
"compile": [
|
|
62
|
-
"./build/compile/index.d.mts"
|
|
63
|
-
],
|
|
64
|
-
"value": [
|
|
65
|
-
"./build/value/index.d.mts"
|
|
58
|
+
"guard": [
|
|
59
|
+
"./build/guard/index.d.mts"
|
|
66
60
|
],
|
|
67
61
|
"error": [
|
|
68
62
|
"./build/error/index.d.mts"
|
|
69
63
|
],
|
|
70
|
-
"
|
|
71
|
-
"./build/
|
|
64
|
+
"compile": [
|
|
65
|
+
"./build/compile/index.d.mts"
|
|
72
66
|
],
|
|
73
|
-
"
|
|
74
|
-
"./build/
|
|
67
|
+
"system": [
|
|
68
|
+
"./build/system/index.d.mts"
|
|
75
69
|
],
|
|
76
70
|
"format": [
|
|
77
71
|
"./build/format/index.d.mts"
|
|
@@ -79,6 +73,12 @@
|
|
|
79
73
|
"type": [
|
|
80
74
|
"./build/type/index.d.mts"
|
|
81
75
|
],
|
|
76
|
+
"schema": [
|
|
77
|
+
"./build/schema/index.d.mts"
|
|
78
|
+
],
|
|
79
|
+
"value": [
|
|
80
|
+
"./build/value/index.d.mts"
|
|
81
|
+
],
|
|
82
82
|
".": [
|
|
83
83
|
"./build/index.d.mts"
|
|
84
84
|
]
|