Skip to content

Commit d7ce3b0

Browse files
committed
fix: 🐛 expand "or" types for discriminator computation
1 parent 6b21e68 commit d7ce3b0

File tree

3 files changed

+121
-18
lines changed

3 files changed

+121
-18
lines changed

src/metaschema/__tests__/__snapshots__/metaschema.spec.ts.snap

Lines changed: 102 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,7 @@ exports[`can import metaschema 1`] = `
899899
│ "/kind"
900900
│ ]
901901
│ ],
902-
5,
902+
13,
903903
│ [
904904
│ "?",
905905
│ [
@@ -910,7 +910,7 @@ exports[`can import metaschema 1`] = `
910910
│ "/kind"
911911
│ ]
912912
│ ],
913-
4,
913+
12,
914914
│ [
915915
│ "?",
916916
│ [
@@ -921,7 +921,7 @@ exports[`can import metaschema 1`] = `
921921
│ "/kind"
922922
│ ]
923923
│ ],
924-
3,
924+
11,
925925
│ [
926926
│ "?",
927927
│ [
@@ -932,7 +932,7 @@ exports[`can import metaschema 1`] = `
932932
│ "/kind"
933933
│ ]
934934
│ ],
935-
2,
935+
10,
936936
│ [
937937
│ "?",
938938
│ [
@@ -943,8 +943,104 @@ exports[`can import metaschema 1`] = `
943943
│ "/kind"
944944
│ ]
945945
│ ],
946-
│ 1,
947-
│ 0
946+
│ 9,
947+
│ [
948+
│ "?",
949+
│ [
950+
│ "==",
951+
│ "map",
952+
│ [
953+
│ "$",
954+
│ "/kind"
955+
│ ]
956+
│ ],
957+
│ 8,
958+
│ [
959+
│ "?",
960+
│ [
961+
│ "==",
962+
│ "key",
963+
│ [
964+
│ "$",
965+
│ "/kind"
966+
│ ]
967+
│ ],
968+
│ 7,
969+
│ [
970+
│ "?",
971+
│ [
972+
│ "==",
973+
│ "obj",
974+
│ [
975+
│ "$",
976+
│ "/kind"
977+
│ ]
978+
│ ],
979+
│ 6,
980+
│ [
981+
│ "?",
982+
│ [
983+
│ "==",
984+
│ "con",
985+
│ [
986+
│ "$",
987+
│ "/kind"
988+
│ ]
989+
│ ],
990+
│ 5,
991+
│ [
992+
│ "?",
993+
│ [
994+
│ "==",
995+
│ "arr",
996+
│ [
997+
│ "$",
998+
│ "/kind"
999+
│ ]
1000+
│ ],
1001+
│ 4,
1002+
│ [
1003+
│ "?",
1004+
│ [
1005+
│ "==",
1006+
│ "bin",
1007+
│ [
1008+
│ "$",
1009+
│ "/kind"
1010+
│ ]
1011+
│ ],
1012+
│ 3,
1013+
│ [
1014+
│ "?",
1015+
│ [
1016+
│ "==",
1017+
│ "str",
1018+
│ [
1019+
│ "$",
1020+
│ "/kind"
1021+
│ ]
1022+
│ ],
1023+
│ 2,
1024+
│ [
1025+
│ "?",
1026+
│ [
1027+
│ "==",
1028+
│ "num",
1029+
│ [
1030+
│ "$",
1031+
│ "/kind"
1032+
│ ]
1033+
│ ],
1034+
│ 1,
1035+
│ 0
1036+
│ ]
1037+
│ ]
1038+
│ ]
1039+
│ ]
1040+
│ ]
1041+
│ ]
1042+
│ ]
1043+
│ ]
9481044
│ ]
9491045
│ ]
9501046
│ ]

src/schema/Walker.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ export class Walker {
1515
public walk (type: Schema): void {
1616
const onType = this.opts.onType ?? ((type: Schema) => {});
1717
switch (type.kind) {
18+
case 'key': {
19+
onType(type);
20+
this.walk(type.value as Schema);
21+
break;
22+
}
1823
case 'any':
1924
case 'con':
2025
case 'bool':
@@ -58,11 +63,6 @@ export class Walker {
5863
this.walk(type.res as Schema);
5964
break;
6065
}
61-
case 'key': {
62-
onType(type);
63-
this.walk(type.value as Schema);
64-
break;
65-
}
6666
case 'module': {
6767
onType(type);
6868
for (const alias of type.keys) this.walk(alias.value as Schema);

src/type/discriminator.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {ArrType, BoolType, ConType, NumType, type ObjKeyType, ObjType, StrType} from './classes';
22
import type {Expr} from '@jsonjoy.com/json-expression';
3-
import type {RefType, Type} from './types';
3+
import type {OrType, RefType, Type} from './types';
44

55
/**
66
* Discriminator class for automatically identifying distinguishing patterns in
@@ -75,14 +75,21 @@ export class Discriminator {
7575
}
7676

7777
public static createExpression(types: Type[]): Expr {
78-
const length = types.length;
7978
const specifiers = new Set<string>();
79+
const length = types.length;
80+
const expanded: Type[] = [];
81+
const expand = (type: Type): Type[] => {
82+
if (type.kind() === 'ref') type = (type as RefType).resolve();
83+
if (type.kind() === 'or')
84+
return (type as OrType).types.flatMap((t: Type) => expand(t));
85+
return [type];
86+
};
87+
for (let i = 0; i < length; i++) expanded.push(...expand(types[i]));
88+
const expandedLength = expanded.length;
8089
const discriminators: Discriminator[] = [];
81-
// TODO: expand all "or" types...
82-
for (let i = 1; i < length; i++) {
83-
const type = types[i];
84-
const resolved = type.kind() === 'ref' ? (type as RefType).resolve() : type;
85-
const d = Discriminator.find(resolved);
90+
for (let i = 1; i < expandedLength; i++) {
91+
const type = expanded[i];
92+
const d = Discriminator.find(type);
8693
const specifier = d.toSpecifier();
8794
if (specifiers.has(specifier)) throw new Error('Duplicate discriminator: ' + specifier);
8895
specifiers.add(specifier);

0 commit comments

Comments
 (0)