schemair 0.1.0 → 0.3.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/README.md +542 -32
- package/dist/authoring/index.cjs +13 -350
- package/dist/authoring/index.d.cts +2 -90
- package/dist/authoring/index.d.ts +2 -90
- package/dist/authoring/index.js +2 -304
- package/dist/authoring-Dnrg5TXm.cjs +389 -0
- package/dist/authoring-DyJNYs5o.js +362 -0
- package/dist/chunk-bFfwrPtJ.js +18 -0
- package/dist/compatibility/index.cjs +43 -0
- package/dist/compatibility/index.d.cts +2 -0
- package/dist/compatibility/index.d.ts +2 -0
- package/dist/compatibility/index.js +42 -0
- package/dist/definition/index.cjs +10 -2
- package/dist/definition/index.d.cts +3 -21
- package/dist/definition/index.d.ts +3 -21
- package/dist/definition/index.js +2 -2
- package/dist/definition-BH_LzXGc.js +1115 -0
- package/dist/definition-BLLBpLKv.cjs +1187 -0
- package/dist/index-1sDuqu05.d.ts +373 -0
- package/dist/index-BFSMT_2d.d.ts +53 -0
- package/dist/index-BGz7L_Fq.d.cts +73 -0
- package/dist/index-BTtdqi_M.d.ts +418 -0
- package/dist/index-BfbClf6R.d.cts +20 -0
- package/dist/index-CK7Is7vy.d.cts +420 -0
- package/dist/index-CUGhtuwA.d.cts +53 -0
- package/dist/index-CV8EZQy8.d.ts +92 -0
- package/dist/index-CzNxjqVg.d.cts +47 -0
- package/dist/index-DGHMUZ5m.d.cts +92 -0
- package/dist/{index-eK2Xgrwp.d.ts → index-DxvfPmw6.d.ts} +13 -9
- package/dist/index-T6nFhvGQ.d.ts +20 -0
- package/dist/{index-TACcK_mi.d.cts → index-ba_52Yu9.d.cts} +13 -9
- package/dist/index-hrcM9oJe.d.ts +47 -0
- package/dist/index-i7Au-FQ6.d.cts +373 -0
- package/dist/index-mu1znI1F.d.ts +73 -0
- package/dist/index.cjs +70 -58
- package/dist/index.d.cts +9 -7
- package/dist/index.d.ts +9 -7
- package/dist/index.js +10 -6
- package/dist/integrations/json-schema/index.cjs +328 -0
- package/dist/integrations/json-schema/index.d.cts +53 -0
- package/dist/integrations/json-schema/index.d.ts +53 -0
- package/dist/integrations/json-schema/index.js +324 -0
- package/dist/integrations/standard-schema/index.cjs +32 -0
- package/dist/integrations/standard-schema/index.d.cts +22 -0
- package/dist/integrations/standard-schema/index.d.ts +22 -0
- package/dist/integrations/standard-schema/index.js +32 -0
- package/dist/payload/index.cjs +45 -82
- package/dist/payload/index.d.cts +2 -56
- package/dist/payload/index.d.ts +2 -56
- package/dist/payload/index.js +45 -81
- package/dist/relations/index.cjs +3 -4
- package/dist/relations/index.d.cts +2 -2
- package/dist/relations/index.d.ts +2 -2
- package/dist/relations/index.js +2 -2
- package/dist/{relations-CMz_0nf4.cjs → relations-NUVJkAG8.cjs} +143 -211
- package/dist/{relations-By0bK3UK.js → relations-QtnCRW9x.js} +140 -202
- package/dist/resolve/index.cjs +308 -0
- package/dist/resolve/index.d.cts +2 -0
- package/dist/resolve/index.d.ts +2 -0
- package/dist/resolve/index.js +305 -0
- package/dist/schema-ref-key-BHVFVfj1.cjs +26 -0
- package/dist/schema-ref-key-DR__tPr-.js +14 -0
- package/dist/spec/index.cjs +9 -0
- package/dist/spec/index.d.cts +2 -2
- package/dist/spec/index.d.ts +2 -2
- package/dist/spec/index.js +3 -1
- package/dist/standard/index.cjs +810 -0
- package/dist/standard/index.d.cts +3 -0
- package/dist/standard/index.d.ts +3 -0
- package/dist/standard/index.js +777 -0
- package/dist/standard-BGMgbbEQ.js +471 -0
- package/dist/standard-etPFZDJI.cjs +513 -0
- package/dist/type-interpreter/index.cjs +3 -7
- package/dist/type-interpreter/index.d.cts +2 -99
- package/dist/type-interpreter/index.d.ts +2 -99
- package/dist/type-interpreter/index.js +2 -2
- package/dist/{type-interpreter-Ck0VDhzn.js → type-interpreter-BA8gcLUU.js} +58 -560
- package/dist/{type-interpreter-DAIBUqKf.cjs → type-interpreter-D8xETgq1.cjs} +63 -589
- package/package.json +60 -5
- package/dist/definition-BXj3T94L.js +0 -467
- package/dist/definition-DSZZTz4e.cjs +0 -473
- package/dist/index-CEzHfht2.d.ts +0 -269
- package/dist/index-rzkFjgrt.d.cts +0 -269
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { a as expressionShapeIssue, f as validateSchemaNodeDefinition, i as expressionKinds, n as validateSchemaTypeTermDefinition, r as expressionFields } from "./definition-BH_LzXGc.js";
|
|
2
|
+
import { n as schemaRefKey, t as indexSchemaRefs } from "./schema-ref-key-DR__tPr-.js";
|
|
3
|
+
import { r as checkSchemaRelation } from "./relations-QtnCRW9x.js";
|
|
3
4
|
|
|
4
5
|
//#region src/type-interpreter/materializer.ts
|
|
5
6
|
function isRecord(value) {
|
|
@@ -861,6 +862,18 @@ function compareTerms(source, target, context) {
|
|
|
861
862
|
message: "source does not provide a required field"
|
|
862
863
|
}]
|
|
863
864
|
};
|
|
865
|
+
if (!sourceField && source.additionalFields !== void 0) {
|
|
866
|
+
if (source.additionalFields === true) return {
|
|
867
|
+
status: "unknown",
|
|
868
|
+
issues: [{
|
|
869
|
+
code: "relation.unknown.additionalField",
|
|
870
|
+
path: ["fields", field.key],
|
|
871
|
+
message: "unconstrained source residual values do not prove compatibility with the target field"
|
|
872
|
+
}]
|
|
873
|
+
};
|
|
874
|
+
const residual = compareTerms(source.additionalFields, field.value, context);
|
|
875
|
+
if (residual.status !== "assignable") return residual;
|
|
876
|
+
}
|
|
864
877
|
if (sourceField) {
|
|
865
878
|
if (field.required === true && sourceField.required !== true) return {
|
|
866
879
|
status: "incompatible",
|
|
@@ -935,125 +948,11 @@ function unknownTermRelation() {
|
|
|
935
948
|
}]
|
|
936
949
|
};
|
|
937
950
|
}
|
|
938
|
-
|
|
939
|
-
if (
|
|
940
|
-
status: "assignable",
|
|
941
|
-
issues: []
|
|
942
|
-
};
|
|
943
|
-
if (source.kind === "absent") return target.kind === "absent" || target.kind === "maybeAbsent" ? {
|
|
944
|
-
status: "assignable",
|
|
945
|
-
issues: []
|
|
946
|
-
} : incompatiblePresence("absent");
|
|
947
|
-
if (target.kind === "never" || target.kind === "absent") return incompatiblePresence(target.kind);
|
|
948
|
-
if (source.kind === "maybeAbsent" && target.kind !== "maybeAbsent") return incompatiblePresence("maybeAbsent");
|
|
949
|
-
if (target.kind === "unknown") return {
|
|
950
|
-
status: "assignable",
|
|
951
|
-
issues: []
|
|
952
|
-
};
|
|
953
|
-
if (source.kind === "unknown") return unknownTermRelation();
|
|
954
|
-
if (source.kind === "opaqueHostType" && target.kind === "opaqueHostType") {
|
|
955
|
-
if (samePath(source.hostPath, target.hostPath)) return {
|
|
956
|
-
status: "assignable",
|
|
957
|
-
issues: []
|
|
958
|
-
};
|
|
959
|
-
if (!context.hostTypeRelation) return {
|
|
960
|
-
status: "incompatible",
|
|
961
|
-
issues: [{
|
|
962
|
-
code: "relation.incompatible.opaqueHostType",
|
|
963
|
-
path: [],
|
|
964
|
-
message: "different opaque host types require an explicit relation provider"
|
|
965
|
-
}]
|
|
966
|
-
};
|
|
967
|
-
return hostDecision(await context.hostTypeRelation(source.hostPath, target.hostPath), "opaque host type relation provider rejected the relation");
|
|
968
|
-
}
|
|
969
|
-
if (source.kind === "arrayOf" && target.kind === "arrayOf") {
|
|
970
|
-
if (!sameData(source.constraints, target.constraints)) return unknownMetadata();
|
|
971
|
-
return compareTermsAsync(source.element, target.element, context);
|
|
972
|
-
}
|
|
973
|
-
if (source.kind === "maybeAbsent" || target.kind === "maybeAbsent") {
|
|
974
|
-
if (source.kind !== "maybeAbsent") {
|
|
975
|
-
if (target.kind === "maybeAbsent") return compareTermsAsync(source, target.value, context);
|
|
976
|
-
return unreachableRelation();
|
|
977
|
-
}
|
|
978
|
-
if (target.kind !== "maybeAbsent") return incompatiblePresence("maybeAbsent");
|
|
979
|
-
return compareTermsAsync(source.value, target.value, context);
|
|
980
|
-
}
|
|
981
|
-
if (source.kind === "array" && target.kind === "array") return checkSchemaRelationAsync(source, target, context.relation);
|
|
982
|
-
if (source.kind === "record" && target.kind === "record") return checkSchemaRelationAsync(source, target, context.relation);
|
|
983
|
-
if (source.kind === "tupleOf" && target.kind === "tupleOf") {
|
|
984
|
-
if (source.elements.length !== target.elements.length) return {
|
|
985
|
-
status: "incompatible",
|
|
986
|
-
issues: [{
|
|
987
|
-
code: "relation.incompatible.tuple.length",
|
|
988
|
-
path: [],
|
|
989
|
-
message: "tuple lengths are different"
|
|
990
|
-
}]
|
|
991
|
-
};
|
|
992
|
-
for (let index = 0; index < source.elements.length; index += 1) {
|
|
993
|
-
const result$1 = await compareTermsAsync(source.elements[index], target.elements[index], context);
|
|
994
|
-
if (result$1.status !== "assignable") return result$1;
|
|
995
|
-
}
|
|
996
|
-
return {
|
|
997
|
-
status: "assignable",
|
|
998
|
-
issues: []
|
|
999
|
-
};
|
|
1000
|
-
}
|
|
1001
|
-
if (source.kind === "tuple" && target.kind === "tuple") return checkSchemaRelationAsync(source, target, context.relation);
|
|
1002
|
-
if (source.kind === "recordOf" && target.kind === "recordOf") {
|
|
1003
|
-
if (!sameData(source.constraints, target.constraints) || !sameData(source.additionalFields, target.additionalFields)) return unknownMetadata();
|
|
1004
|
-
const sourceFields = new Map(source.fields.map((field) => [field.key, field]));
|
|
1005
|
-
for (const field of target.fields) {
|
|
1006
|
-
const sourceField = sourceFields.get(field.key);
|
|
1007
|
-
if (!sourceField && field.required === true) return {
|
|
1008
|
-
status: "incompatible",
|
|
1009
|
-
issues: [{
|
|
1010
|
-
code: "relation.incompatible.required",
|
|
1011
|
-
path: ["fields", field.key],
|
|
1012
|
-
message: "source does not provide a required field"
|
|
1013
|
-
}]
|
|
1014
|
-
};
|
|
1015
|
-
if (sourceField) {
|
|
1016
|
-
if (field.required === true && sourceField.required !== true) return {
|
|
1017
|
-
status: "incompatible",
|
|
1018
|
-
issues: [{
|
|
1019
|
-
code: "relation.incompatible.required",
|
|
1020
|
-
path: ["fields", field.key],
|
|
1021
|
-
message: "source field may be absent"
|
|
1022
|
-
}]
|
|
1023
|
-
};
|
|
1024
|
-
const result$1 = await compareTermsAsync(sourceField.value, field.value, context);
|
|
1025
|
-
if (result$1.status !== "assignable") return result$1;
|
|
1026
|
-
}
|
|
1027
|
-
}
|
|
1028
|
-
for (const field of source.fields) if (!target.fields.some((candidate) => candidate.key === field.key)) {
|
|
1029
|
-
if (target.additionalFields === void 0) return {
|
|
1030
|
-
status: "incompatible",
|
|
1031
|
-
issues: [{
|
|
1032
|
-
code: "relation.incompatible.additionalField",
|
|
1033
|
-
path: ["fields", field.key],
|
|
1034
|
-
message: "target record does not allow this source field"
|
|
1035
|
-
}]
|
|
1036
|
-
};
|
|
1037
|
-
if (target.additionalFields !== true) {
|
|
1038
|
-
const relation = await compareTermsAsync(field.value, target.additionalFields, context);
|
|
1039
|
-
if (relation.status !== "assignable") return relation;
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
return {
|
|
1043
|
-
status: "assignable",
|
|
1044
|
-
issues: []
|
|
1045
|
-
};
|
|
1046
|
-
}
|
|
1047
|
-
const sourceSchema = validateSchemaNodeDefinition(source);
|
|
1048
|
-
const targetSchema = validateSchemaNodeDefinition(target);
|
|
1049
|
-
if (sourceSchema.ok && targetSchema.ok) return checkSchemaRelationAsync(sourceSchema.node, targetSchema.node, context.relation);
|
|
951
|
+
function relationWithInterpreterRefs(relation, interpreter) {
|
|
952
|
+
if (interpreter?.refs === void 0) return relation ?? {};
|
|
1050
953
|
return {
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
code: "relation.unknown.term",
|
|
1054
|
-
path: [],
|
|
1055
|
-
message: "async relation requires normalized term comparison"
|
|
1056
|
-
}]
|
|
954
|
+
...relation ?? {},
|
|
955
|
+
refs: [...relation?.refs ?? [], ...interpreter.refs]
|
|
1057
956
|
};
|
|
1058
957
|
}
|
|
1059
958
|
function diagnostics(result$1, status) {
|
|
@@ -1077,211 +976,12 @@ function compareEvaluated(source, target, relation = {}, hostTypeRelation) {
|
|
|
1077
976
|
} : { relation });
|
|
1078
977
|
}
|
|
1079
978
|
function checkTypeTermRelation(source, target, context = {}) {
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
async function checkTypeTermRelationAsync(source, target, context = {}) {
|
|
1083
|
-
const [sourceResult, targetResult] = await Promise.all([evaluateExpressionAsync(source, context.interpreter), evaluateExpressionAsync(target, context.interpreter)]);
|
|
1084
|
-
if (sourceResult.status !== "evaluated" || targetResult.status !== "evaluated") return compareEvaluated(sourceResult, targetResult);
|
|
1085
|
-
return compareTermsAsync(sourceResult.term, targetResult.term, context);
|
|
979
|
+
const relation = relationWithInterpreterRefs(context.relation, context.interpreter);
|
|
980
|
+
return compareEvaluated(evaluateExpression(source, context.interpreter), evaluateExpression(target, context.interpreter), relation, context.hostTypeRelation);
|
|
1086
981
|
}
|
|
1087
982
|
|
|
1088
983
|
//#endregion
|
|
1089
984
|
//#region src/type-interpreter/interpreter.ts
|
|
1090
|
-
const expressionKinds = new Set([
|
|
1091
|
-
"typeVar",
|
|
1092
|
-
"opaqueHostType",
|
|
1093
|
-
"absent",
|
|
1094
|
-
"never",
|
|
1095
|
-
"unknown",
|
|
1096
|
-
"maybeAbsent",
|
|
1097
|
-
"arrayOf",
|
|
1098
|
-
"tupleOf",
|
|
1099
|
-
"recordOf",
|
|
1100
|
-
"elementOf",
|
|
1101
|
-
"valueOf",
|
|
1102
|
-
"elementAt",
|
|
1103
|
-
"fieldOf",
|
|
1104
|
-
"keyOf",
|
|
1105
|
-
"fieldsOf",
|
|
1106
|
-
"pickFields",
|
|
1107
|
-
"omitFields",
|
|
1108
|
-
"partialFields",
|
|
1109
|
-
"requiredFields",
|
|
1110
|
-
"mergeRecords",
|
|
1111
|
-
"nullableOf",
|
|
1112
|
-
"taggedUnionOf",
|
|
1113
|
-
"intersect",
|
|
1114
|
-
"refine",
|
|
1115
|
-
"excludeVariants",
|
|
1116
|
-
"extractVariants"
|
|
1117
|
-
]);
|
|
1118
|
-
const expressionFields = {
|
|
1119
|
-
typeVar: {
|
|
1120
|
-
required: ["name"],
|
|
1121
|
-
allowed: [
|
|
1122
|
-
"kind",
|
|
1123
|
-
"name",
|
|
1124
|
-
"extends"
|
|
1125
|
-
]
|
|
1126
|
-
},
|
|
1127
|
-
opaqueHostType: {
|
|
1128
|
-
required: ["hostPath"],
|
|
1129
|
-
allowed: ["kind", "hostPath"]
|
|
1130
|
-
},
|
|
1131
|
-
absent: {
|
|
1132
|
-
required: [],
|
|
1133
|
-
allowed: ["kind"]
|
|
1134
|
-
},
|
|
1135
|
-
never: {
|
|
1136
|
-
required: [],
|
|
1137
|
-
allowed: ["kind"]
|
|
1138
|
-
},
|
|
1139
|
-
unknown: {
|
|
1140
|
-
required: [],
|
|
1141
|
-
allowed: ["kind"]
|
|
1142
|
-
},
|
|
1143
|
-
maybeAbsent: {
|
|
1144
|
-
required: ["value"],
|
|
1145
|
-
allowed: ["kind", "value"]
|
|
1146
|
-
},
|
|
1147
|
-
arrayOf: {
|
|
1148
|
-
required: ["element"],
|
|
1149
|
-
allowed: [
|
|
1150
|
-
"kind",
|
|
1151
|
-
"element",
|
|
1152
|
-
"constraints"
|
|
1153
|
-
]
|
|
1154
|
-
},
|
|
1155
|
-
tupleOf: {
|
|
1156
|
-
required: ["elements"],
|
|
1157
|
-
allowed: ["kind", "elements"]
|
|
1158
|
-
},
|
|
1159
|
-
recordOf: {
|
|
1160
|
-
required: ["fields"],
|
|
1161
|
-
allowed: [
|
|
1162
|
-
"kind",
|
|
1163
|
-
"fields",
|
|
1164
|
-
"additionalFields",
|
|
1165
|
-
"constraints"
|
|
1166
|
-
]
|
|
1167
|
-
},
|
|
1168
|
-
nullableOf: {
|
|
1169
|
-
required: ["value"],
|
|
1170
|
-
allowed: ["kind", "value"]
|
|
1171
|
-
},
|
|
1172
|
-
taggedUnionOf: {
|
|
1173
|
-
required: ["discriminator", "variants"],
|
|
1174
|
-
allowed: [
|
|
1175
|
-
"kind",
|
|
1176
|
-
"discriminator",
|
|
1177
|
-
"variants"
|
|
1178
|
-
]
|
|
1179
|
-
},
|
|
1180
|
-
elementOf: {
|
|
1181
|
-
required: ["source"],
|
|
1182
|
-
allowed: ["kind", "source"]
|
|
1183
|
-
},
|
|
1184
|
-
valueOf: {
|
|
1185
|
-
required: ["source"],
|
|
1186
|
-
allowed: ["kind", "source"]
|
|
1187
|
-
},
|
|
1188
|
-
elementAt: {
|
|
1189
|
-
required: ["source", "index"],
|
|
1190
|
-
allowed: [
|
|
1191
|
-
"kind",
|
|
1192
|
-
"source",
|
|
1193
|
-
"index"
|
|
1194
|
-
]
|
|
1195
|
-
},
|
|
1196
|
-
fieldOf: {
|
|
1197
|
-
required: ["source", "key"],
|
|
1198
|
-
allowed: [
|
|
1199
|
-
"kind",
|
|
1200
|
-
"source",
|
|
1201
|
-
"key"
|
|
1202
|
-
]
|
|
1203
|
-
},
|
|
1204
|
-
keyOf: {
|
|
1205
|
-
required: ["source"],
|
|
1206
|
-
allowed: ["kind", "source"]
|
|
1207
|
-
},
|
|
1208
|
-
fieldsOf: {
|
|
1209
|
-
required: ["source", "fields"],
|
|
1210
|
-
allowed: [
|
|
1211
|
-
"kind",
|
|
1212
|
-
"source",
|
|
1213
|
-
"fields"
|
|
1214
|
-
]
|
|
1215
|
-
},
|
|
1216
|
-
pickFields: {
|
|
1217
|
-
required: ["source", "fields"],
|
|
1218
|
-
allowed: [
|
|
1219
|
-
"kind",
|
|
1220
|
-
"source",
|
|
1221
|
-
"fields"
|
|
1222
|
-
]
|
|
1223
|
-
},
|
|
1224
|
-
omitFields: {
|
|
1225
|
-
required: ["source", "fields"],
|
|
1226
|
-
allowed: [
|
|
1227
|
-
"kind",
|
|
1228
|
-
"source",
|
|
1229
|
-
"fields"
|
|
1230
|
-
]
|
|
1231
|
-
},
|
|
1232
|
-
partialFields: {
|
|
1233
|
-
required: ["source", "fields"],
|
|
1234
|
-
allowed: [
|
|
1235
|
-
"kind",
|
|
1236
|
-
"source",
|
|
1237
|
-
"fields"
|
|
1238
|
-
]
|
|
1239
|
-
},
|
|
1240
|
-
requiredFields: {
|
|
1241
|
-
required: ["source", "fields"],
|
|
1242
|
-
allowed: [
|
|
1243
|
-
"kind",
|
|
1244
|
-
"source",
|
|
1245
|
-
"fields"
|
|
1246
|
-
]
|
|
1247
|
-
},
|
|
1248
|
-
mergeRecords: {
|
|
1249
|
-
required: ["sources", "conflict"],
|
|
1250
|
-
allowed: [
|
|
1251
|
-
"kind",
|
|
1252
|
-
"sources",
|
|
1253
|
-
"conflict"
|
|
1254
|
-
]
|
|
1255
|
-
},
|
|
1256
|
-
intersect: {
|
|
1257
|
-
required: ["sources"],
|
|
1258
|
-
allowed: ["kind", "sources"]
|
|
1259
|
-
},
|
|
1260
|
-
refine: {
|
|
1261
|
-
required: ["source", "fields"],
|
|
1262
|
-
allowed: [
|
|
1263
|
-
"kind",
|
|
1264
|
-
"source",
|
|
1265
|
-
"fields"
|
|
1266
|
-
]
|
|
1267
|
-
},
|
|
1268
|
-
excludeVariants: {
|
|
1269
|
-
required: ["source", "variants"],
|
|
1270
|
-
allowed: [
|
|
1271
|
-
"kind",
|
|
1272
|
-
"source",
|
|
1273
|
-
"variants"
|
|
1274
|
-
]
|
|
1275
|
-
},
|
|
1276
|
-
extractVariants: {
|
|
1277
|
-
required: ["source", "variants"],
|
|
1278
|
-
allowed: [
|
|
1279
|
-
"kind",
|
|
1280
|
-
"source",
|
|
1281
|
-
"variants"
|
|
1282
|
-
]
|
|
1283
|
-
}
|
|
1284
|
-
};
|
|
1285
985
|
function isObject(value) {
|
|
1286
986
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1287
987
|
}
|
|
@@ -1341,99 +1041,19 @@ function childTerms(expression) {
|
|
|
1341
1041
|
});
|
|
1342
1042
|
return children;
|
|
1343
1043
|
}
|
|
1344
|
-
function hasOnlyKeys(value, keys) {
|
|
1345
|
-
return Object.keys(value).every((key) => keys.includes(key));
|
|
1346
|
-
}
|
|
1347
|
-
function isSelector(value) {
|
|
1348
|
-
if (!isObject(value)) return false;
|
|
1349
|
-
if (value.kind === "all") return hasOnlyKeys(value, ["kind"]);
|
|
1350
|
-
return value.kind === "keys" && hasOnlyKeys(value, [
|
|
1351
|
-
"kind",
|
|
1352
|
-
"keys",
|
|
1353
|
-
"onMissing"
|
|
1354
|
-
]) && Array.isArray(value.keys) && value.keys.every((key) => typeof key === "string") && new Set(value.keys).size === value.keys.length && (value.onMissing === "error" || value.onMissing === "ignore");
|
|
1355
|
-
}
|
|
1356
|
-
function expressionShapeIssue(expression) {
|
|
1357
|
-
const kind = expression.kind;
|
|
1358
|
-
if (kind === "typeVar" && (typeof expression.name !== "string" || !expression.name.trim())) return "typeVar name must be non-blank";
|
|
1359
|
-
if (kind === "opaqueHostType" && (!Array.isArray(expression.hostPath) || expression.hostPath.length === 0 || expression.hostPath.some((part) => typeof part !== "string" || !part.trim()))) return "hostPath must be a non-empty path";
|
|
1360
|
-
if (kind === "tupleOf" && (!Array.isArray(expression.elements) || !isDense(expression.elements))) return "elements must be a dense array";
|
|
1361
|
-
if (kind === "recordOf") {
|
|
1362
|
-
if (!Array.isArray(expression.fields) || !isDense(expression.fields)) return "fields must be a dense array";
|
|
1363
|
-
const keys = /* @__PURE__ */ new Set();
|
|
1364
|
-
for (const field of expression.fields) {
|
|
1365
|
-
if (!isObject(field) || !hasOnlyKeys(field, [
|
|
1366
|
-
"key",
|
|
1367
|
-
"value",
|
|
1368
|
-
"required",
|
|
1369
|
-
"description"
|
|
1370
|
-
]) || typeof field.key !== "string" || keys.has(field.key)) return "record fields must have unique keys and a valid shape";
|
|
1371
|
-
if (field.required !== void 0 && typeof field.required !== "boolean") return "record field required must be a boolean";
|
|
1372
|
-
if (field.description !== void 0 && typeof field.description !== "string") return "record field description must be a string";
|
|
1373
|
-
keys.add(field.key);
|
|
1374
|
-
}
|
|
1375
|
-
if (expression.additionalFields !== void 0 && expression.additionalFields !== true && !isObject(expression.additionalFields)) return "additionalFields must be a type term or true";
|
|
1376
|
-
if (expression.constraints !== void 0 && (!Array.isArray(expression.constraints) || !isDense(expression.constraints))) return "constraints must be a dense array";
|
|
1377
|
-
}
|
|
1378
|
-
if (kind === "arrayOf" && expression.constraints !== void 0 && (!Array.isArray(expression.constraints) || !isDense(expression.constraints))) return "constraints must be a dense array";
|
|
1379
|
-
if (kind === "taggedUnionOf") {
|
|
1380
|
-
if (typeof expression.discriminator !== "string" || !expression.discriminator.trim() || !Array.isArray(expression.variants) || !isDense(expression.variants) || expression.variants.length < 2) return "taggedUnionOf requires a discriminator and at least two dense variants";
|
|
1381
|
-
const keys = /* @__PURE__ */ new Set();
|
|
1382
|
-
for (const variant of expression.variants) {
|
|
1383
|
-
if (!isObject(variant) || !hasOnlyKeys(variant, [
|
|
1384
|
-
"key",
|
|
1385
|
-
"value",
|
|
1386
|
-
"description"
|
|
1387
|
-
]) || typeof variant.key !== "string" || !variant.key.trim() || keys.has(variant.key)) return "taggedUnionOf variants must have unique non-blank keys and a valid shape";
|
|
1388
|
-
if (variant.description !== void 0 && typeof variant.description !== "string") return "variant description must be a string";
|
|
1389
|
-
keys.add(variant.key);
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
if ([
|
|
1393
|
-
"fieldsOf",
|
|
1394
|
-
"pickFields",
|
|
1395
|
-
"omitFields",
|
|
1396
|
-
"partialFields",
|
|
1397
|
-
"requiredFields"
|
|
1398
|
-
].includes(String(kind)) && !isSelector(expression.fields)) return "fields must be a valid field selector";
|
|
1399
|
-
if ((kind === "excludeVariants" || kind === "extractVariants") && !isSelector(expression.variants)) return "variants must be a valid variant selector";
|
|
1400
|
-
if (kind === "elementAt" && (!Number.isSafeInteger(expression.index) || expression.index < 0)) return "index must be a non-negative safe integer";
|
|
1401
|
-
if (kind === "fieldOf" && typeof expression.key !== "string") return "key must be a string";
|
|
1402
|
-
if (kind === "mergeRecords" && (!Array.isArray(expression.sources) || !isDense(expression.sources) || expression.sources.length < 2 || ![
|
|
1403
|
-
"leftWins",
|
|
1404
|
-
"rightWins",
|
|
1405
|
-
"error"
|
|
1406
|
-
].includes(String(expression.conflict)))) return "mergeRecords requires at least two dense sources and a valid conflict policy";
|
|
1407
|
-
if (kind === "intersect" && (!Array.isArray(expression.sources) || !isDense(expression.sources) || expression.sources.length < 2)) return "intersect requires at least two dense sources";
|
|
1408
|
-
if (kind === "refine") {
|
|
1409
|
-
if (!Array.isArray(expression.fields) || !isDense(expression.fields) || expression.fields.length === 0) return "refine requires non-empty dense field actions";
|
|
1410
|
-
const keys = /* @__PURE__ */ new Set();
|
|
1411
|
-
for (const action of expression.fields) {
|
|
1412
|
-
if (!isObject(action) || !hasOnlyKeys(action, [
|
|
1413
|
-
"key",
|
|
1414
|
-
"require",
|
|
1415
|
-
"intersectWith",
|
|
1416
|
-
"addConstraints"
|
|
1417
|
-
]) || typeof action.key !== "string" || keys.has(action.key)) return "refine actions must have unique keys and a valid shape";
|
|
1418
|
-
if (action.require !== void 0 && action.require !== true) return "refine require must be true when specified";
|
|
1419
|
-
if (action.addConstraints !== void 0 && (!Array.isArray(action.addConstraints) || !isDense(action.addConstraints))) return "addConstraints must be a dense array";
|
|
1420
|
-
keys.add(action.key);
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
}
|
|
1424
|
-
function isDense(value) {
|
|
1425
|
-
for (let index = 0; index < value.length; index += 1) if (!Object.prototype.hasOwnProperty.call(value, index)) return false;
|
|
1426
|
-
return true;
|
|
1427
|
-
}
|
|
1428
1044
|
function replaceChild(expression, path, value) {
|
|
1429
1045
|
const [key, indexText, subkey] = path.split(".");
|
|
1430
1046
|
if (indexText === void 0) {
|
|
1431
1047
|
expression[key] = value;
|
|
1432
1048
|
return;
|
|
1433
1049
|
}
|
|
1434
|
-
const items = expression[key];
|
|
1050
|
+
const items = [...expression[key]];
|
|
1051
|
+
expression[key] = items;
|
|
1435
1052
|
const index = Number(indexText);
|
|
1436
|
-
if (subkey) items[index]
|
|
1053
|
+
if (subkey) items[index] = {
|
|
1054
|
+
...items[index],
|
|
1055
|
+
[subkey]: value
|
|
1056
|
+
};
|
|
1437
1057
|
else items[index] = value;
|
|
1438
1058
|
}
|
|
1439
1059
|
function projectNormalized(expression) {
|
|
@@ -1542,33 +1162,32 @@ function operandKindIssue(expression) {
|
|
|
1542
1162
|
function normalize(term, state, depth = 0) {
|
|
1543
1163
|
state.steps += 1;
|
|
1544
1164
|
if (state.steps > (state.context.maxSteps ?? 2e3) || depth > (state.context.maxDepth ?? 64)) return failure("incomplete", "budget", "type interpretation work budget exceeded");
|
|
1165
|
+
const definition = validateSchemaTypeTermDefinition(term);
|
|
1166
|
+
if (!definition.ok) {
|
|
1167
|
+
const status = definition.issues.every((issue$1) => issue$1.code === "expression.cycle" || issue$1.code === "expression.budget") ? "incomplete" : "rejected";
|
|
1168
|
+
return {
|
|
1169
|
+
status,
|
|
1170
|
+
issues: definition.issues.map((issue$1) => ({
|
|
1171
|
+
...issue$1,
|
|
1172
|
+
code: `interpreter.${status}.${issue$1.code}`
|
|
1173
|
+
}))
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1545
1176
|
if (!isObject(term)) return failure("rejected", "term.object", "type term must be an object");
|
|
1546
1177
|
if (schemaTerm(term)) {
|
|
1547
1178
|
if (term.kind !== "ref") return result(term);
|
|
1548
|
-
|
|
1549
|
-
const
|
|
1550
|
-
if (
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
}
|
|
1559
|
-
if (!resolved) {
|
|
1560
|
-
state.refs.delete(key);
|
|
1561
|
-
return failure("incomplete", "ref.unresolved", "refPath resolver returned no schema");
|
|
1562
|
-
}
|
|
1563
|
-
if (typeof resolved === "object" && "status" in resolved && resolved.status !== "resolved") {
|
|
1564
|
-
state.refs.delete(key);
|
|
1565
|
-
return failure("incomplete", `ref.${resolved.status}`, resolved.message ?? "refPath resolver could not determine this path");
|
|
1566
|
-
}
|
|
1567
|
-
try {
|
|
1568
|
-
return normalize(typeof resolved === "object" && "status" in resolved ? resolved.schema : resolved, state, depth + 1);
|
|
1569
|
-
} finally {
|
|
1570
|
-
state.refs.delete(key);
|
|
1179
|
+
const key = schemaRefKey(term.refPath);
|
|
1180
|
+
const materialized = state.refIndex.get(key);
|
|
1181
|
+
if (materialized !== void 0) {
|
|
1182
|
+
if (state.refs.has(key)) return failure("incomplete", "cycle.ref", "refPath resolution encountered a recursive reference");
|
|
1183
|
+
state.refs.add(key);
|
|
1184
|
+
try {
|
|
1185
|
+
return normalize(materialized, state, depth + 1);
|
|
1186
|
+
} finally {
|
|
1187
|
+
state.refs.delete(key);
|
|
1188
|
+
}
|
|
1571
1189
|
}
|
|
1190
|
+
return failure("incomplete", state.context.refs === void 0 ? "ref.environment" : "ref.unresolved", state.context.refs === void 0 ? "refPath requires a preloaded refs environment" : "refPath is not present in the preloaded refs environment");
|
|
1572
1191
|
}
|
|
1573
1192
|
const kind = term.kind;
|
|
1574
1193
|
if (typeof kind !== "string" || !expressionKinds.has(kind)) return failure("rejected", "expression.kind", "term is neither a valid SchemaNode nor a supported expression");
|
|
@@ -1605,7 +1224,7 @@ function normalize(term, state, depth = 0) {
|
|
|
1605
1224
|
if (evaluated.status === "evaluated" && upper !== void 0) {
|
|
1606
1225
|
const upperResult = result(upper);
|
|
1607
1226
|
if (evaluated.unresolvedTypeVars?.length || upperResult.status === "evaluated" && upperResult.unresolvedTypeVars?.length) return failure("incomplete", "typeVar.bound", "type variable upper bound could not be established");
|
|
1608
|
-
const relation = checkTypeTermRelation(evaluated.term, upper);
|
|
1227
|
+
const relation = checkTypeTermRelation(evaluated.term, upper, { interpreter: state.context });
|
|
1609
1228
|
if (relation.status !== "assignable") return failure(relation.status === "incompatible" || relation.status === "rejected" ? "rejected" : "incomplete", "typeVar.bound", `binding for '${term.name}' does not satisfy its upper bound: ${relation.issues[0]?.message ?? relation.status}`);
|
|
1610
1229
|
}
|
|
1611
1230
|
return evaluated;
|
|
@@ -1671,97 +1290,14 @@ function normalize(term, state, depth = 0) {
|
|
|
1671
1290
|
function evaluateExpression(term, context = {}) {
|
|
1672
1291
|
return normalize(term, {
|
|
1673
1292
|
context,
|
|
1293
|
+
refIndex: indexSchemaRefs(context.refs),
|
|
1674
1294
|
active: /* @__PURE__ */ new Set(),
|
|
1675
1295
|
variables: /* @__PURE__ */ new Set(),
|
|
1676
1296
|
refs: /* @__PURE__ */ new Set(),
|
|
1677
1297
|
steps: 0
|
|
1678
1298
|
});
|
|
1679
1299
|
}
|
|
1680
|
-
|
|
1681
|
-
const activeRefs = /* @__PURE__ */ new Set();
|
|
1682
|
-
const activeVars = /* @__PURE__ */ new Set();
|
|
1683
|
-
const activeObjects = /* @__PURE__ */ new Set();
|
|
1684
|
-
let steps = 0;
|
|
1685
|
-
const resolveTree = async (value, depth = 0) => {
|
|
1686
|
-
steps += 1;
|
|
1687
|
-
if (steps > (context.maxSteps ?? 2e3) || depth > (context.maxDepth ?? 64)) return { failure: failure("incomplete", "budget", "type interpretation work budget exceeded") };
|
|
1688
|
-
if (!isObject(value)) return { value };
|
|
1689
|
-
if (activeObjects.has(value)) return { failure: failure("incomplete", "cycle.expression", "expression cycle could not be determined") };
|
|
1690
|
-
activeObjects.add(value);
|
|
1691
|
-
try {
|
|
1692
|
-
const definition = validateSchemaNodeDefinition(value);
|
|
1693
|
-
if (definition.ok && definition.node.kind === "ref") {
|
|
1694
|
-
if (!context.resolveRef) return { failure: failure("incomplete", "ref.resolver", "refPath requires an explicit resolver") };
|
|
1695
|
-
const key = definition.node.refPath.join("\0");
|
|
1696
|
-
if (activeRefs.has(key)) return { failure: failure("incomplete", "cycle.ref", "refPath resolution cycle could not be determined") };
|
|
1697
|
-
activeRefs.add(key);
|
|
1698
|
-
try {
|
|
1699
|
-
let resolution;
|
|
1700
|
-
try {
|
|
1701
|
-
resolution = await context.resolveRef(definition.node.refPath);
|
|
1702
|
-
} catch (error) {
|
|
1703
|
-
return { failure: failure("incomplete", "ref.error", `refPath resolver failed: ${error instanceof Error ? error.message : String(error)}`) };
|
|
1704
|
-
}
|
|
1705
|
-
if (!resolution) return { failure: failure("incomplete", "ref.unresolved", "refPath resolver returned no schema") };
|
|
1706
|
-
if (typeof resolution === "object" && "status" in resolution && resolution.status !== "resolved") return { failure: failure("incomplete", `ref.${resolution.status}`, resolution.message ?? "refPath resolver could not determine this path") };
|
|
1707
|
-
return await resolveTree(typeof resolution === "object" && "status" in resolution ? resolution.schema : resolution, depth + 1);
|
|
1708
|
-
} finally {
|
|
1709
|
-
activeRefs.delete(key);
|
|
1710
|
-
}
|
|
1711
|
-
}
|
|
1712
|
-
if (value.kind === "typeVar") {
|
|
1713
|
-
if (typeof value.name !== "string" || !value.name.trim()) return { value };
|
|
1714
|
-
const bound = context.typeVars?.[value.name];
|
|
1715
|
-
if (bound === void 0) {
|
|
1716
|
-
if (value.extends === void 0) return { value };
|
|
1717
|
-
const upper = await resolveTree(value.extends, depth + 1);
|
|
1718
|
-
return upper.failure ? upper : { value: {
|
|
1719
|
-
...value,
|
|
1720
|
-
extends: upper.value
|
|
1721
|
-
} };
|
|
1722
|
-
}
|
|
1723
|
-
if (activeVars.has(value.name)) return { failure: failure("incomplete", "cycle.typeVar", "typeVar resolution cycle could not be determined") };
|
|
1724
|
-
activeVars.add(value.name);
|
|
1725
|
-
try {
|
|
1726
|
-
const resolved$1 = await resolveTree(bound, depth + 1);
|
|
1727
|
-
if (resolved$1.failure || value.extends === void 0) return resolved$1;
|
|
1728
|
-
const upper = await resolveTree(value.extends, depth + 1);
|
|
1729
|
-
if (upper.failure) return upper;
|
|
1730
|
-
const source = evaluateExpression(resolved$1.value);
|
|
1731
|
-
const target = evaluateExpression(upper.value);
|
|
1732
|
-
if (source.status !== "evaluated" || target.status !== "evaluated" || source.unresolvedTypeVars?.length || target.unresolvedTypeVars?.length) return { failure: failure("incomplete", "typeVar.bound", "type variable upper bound could not be established") };
|
|
1733
|
-
const relation = checkTypeTermRelation(source.term, target.term);
|
|
1734
|
-
if (relation.status !== "assignable") return { failure: failure(relation.status === "incompatible" || relation.status === "rejected" ? "rejected" : "incomplete", "typeVar.bound", `binding for '${value.name}' does not satisfy its upper bound: ${relation.issues[0]?.message ?? relation.status}`) };
|
|
1735
|
-
return resolved$1;
|
|
1736
|
-
} finally {
|
|
1737
|
-
activeVars.delete(value.name);
|
|
1738
|
-
}
|
|
1739
|
-
}
|
|
1740
|
-
const kind = value.kind;
|
|
1741
|
-
if (typeof kind !== "string" || !expressionKinds.has(kind)) return { value };
|
|
1742
|
-
const shape = expressionFields[kind];
|
|
1743
|
-
if (Object.keys(value).some((key) => !shape.allowed.includes(key)) || shape.required.some((key) => !(key in value))) return { value };
|
|
1744
|
-
if (expressionShapeIssue(value)) return { value };
|
|
1745
|
-
const copy = { ...value };
|
|
1746
|
-
for (const [path, child] of childTerms(value)) {
|
|
1747
|
-
const resolved$1 = await resolveTree(child, depth + 1);
|
|
1748
|
-
if (resolved$1.failure) return resolved$1;
|
|
1749
|
-
replaceChild(copy, path, resolved$1.value);
|
|
1750
|
-
}
|
|
1751
|
-
return { value: copy };
|
|
1752
|
-
} finally {
|
|
1753
|
-
activeObjects.delete(value);
|
|
1754
|
-
}
|
|
1755
|
-
};
|
|
1756
|
-
const resolved = await resolveTree(term);
|
|
1757
|
-
if (resolved.failure) return resolved.failure;
|
|
1758
|
-
return evaluateExpression(resolved.value, {
|
|
1759
|
-
maxDepth: Number.MAX_SAFE_INTEGER,
|
|
1760
|
-
maxSteps: Number.MAX_SAFE_INTEGER
|
|
1761
|
-
});
|
|
1762
|
-
}
|
|
1763
|
-
const evaluateSchemaValueTypeTerm = evaluateExpression;
|
|
1764
|
-
const evaluateSchemaValueTypeTermAsync = evaluateExpressionAsync;
|
|
1300
|
+
const evaluateSchemaTypeTerm = evaluateExpression;
|
|
1765
1301
|
|
|
1766
1302
|
//#endregion
|
|
1767
1303
|
//#region src/type-interpreter/type-variable-solver.ts
|
|
@@ -1820,6 +1356,11 @@ function initial(input, context) {
|
|
|
1820
1356
|
code: "solver.rejected.variable.prebound",
|
|
1821
1357
|
message: "a variable declared for solving is already bound in the interpreter context"
|
|
1822
1358
|
}]);
|
|
1359
|
+
for (const [index, constraint] of input.constraints.entries()) if (!validateSchemaTypeTermDefinition(constraint.source).ok || !validateSchemaTypeTermDefinition(constraint.target).ok) return makeResult("rejected", {}, names, [{
|
|
1360
|
+
code: "solver.rejected.input",
|
|
1361
|
+
constraint: index,
|
|
1362
|
+
message: "constraint terms must be well formed"
|
|
1363
|
+
}]);
|
|
1823
1364
|
}
|
|
1824
1365
|
function interpreterContext(context, bindings) {
|
|
1825
1366
|
return {
|
|
@@ -1887,49 +1428,6 @@ function solveTypeVariables(input, context = {}) {
|
|
|
1887
1428
|
}
|
|
1888
1429
|
return makeResult("solved", bindings, input.variables, []);
|
|
1889
1430
|
}
|
|
1890
|
-
async function solveTypeVariablesAsync(input, context = {}) {
|
|
1891
|
-
const invalid = initial(input, context);
|
|
1892
|
-
if (invalid) return invalid;
|
|
1893
|
-
const bindings = Object.create(null);
|
|
1894
|
-
const names = new Set(input.variables);
|
|
1895
|
-
for (let pass = 0; pass <= input.variables.length; pass += 1) {
|
|
1896
|
-
let changed = false;
|
|
1897
|
-
for (const [index, constraint] of input.constraints.entries()) {
|
|
1898
|
-
const actual = await evaluateExpressionAsync(constraint.source, interpreterContext(context.interpreter, bindings));
|
|
1899
|
-
if (actual.status === "evaluated" && actual.unresolvedTypeVars?.length) continue;
|
|
1900
|
-
if (actual.status !== "evaluated") return makeResult(actual.status === "incomplete" ? "unknown" : actual.status, bindings, input.variables, [issue(actual.status, index, actual.issues[0]?.message ?? "source could not be evaluated")]);
|
|
1901
|
-
const found = [];
|
|
1902
|
-
if (candidates(actual.term, constraint.target, found)) return makeResult("incompatible", bindings, input.variables, [issue("incompatible.shape", index, "source and target container shapes differ")]);
|
|
1903
|
-
for (const candidate of found) {
|
|
1904
|
-
if (context.interpreter?.typeVars?.[candidate.name] !== void 0 && !names.has(candidate.name)) continue;
|
|
1905
|
-
if (!names.has(candidate.name)) return makeResult("rejected", bindings, input.variables, [issue("rejected.variable.undeclared", index, "target uses an undeclared type variable", candidate.name)]);
|
|
1906
|
-
const previous = bindings[candidate.name];
|
|
1907
|
-
if (!previous) {
|
|
1908
|
-
bindings[candidate.name] = candidate.term;
|
|
1909
|
-
changed = true;
|
|
1910
|
-
continue;
|
|
1911
|
-
}
|
|
1912
|
-
if ((await checkTypeTermRelationAsync(candidate.term, previous, relationContext(context, bindings))).status === "assignable") continue;
|
|
1913
|
-
if ((await checkTypeTermRelationAsync(previous, candidate.term, relationContext(context, bindings))).status === "assignable") {
|
|
1914
|
-
bindings[candidate.name] = candidate.term;
|
|
1915
|
-
changed = true;
|
|
1916
|
-
continue;
|
|
1917
|
-
}
|
|
1918
|
-
return makeResult("unknown", bindings, input.variables, [issue("unknown.variable.join", index, "no supported unique common supertype for variable candidates", candidate.name)]);
|
|
1919
|
-
}
|
|
1920
|
-
}
|
|
1921
|
-
if (!changed) break;
|
|
1922
|
-
}
|
|
1923
|
-
if (input.variables.some((name) => !Object.hasOwn(bindings, name))) return makeResult("unknown", bindings, input.variables, [{
|
|
1924
|
-
code: "solver.unknown.variable.unresolved",
|
|
1925
|
-
message: "one or more declared type variables could not be inferred"
|
|
1926
|
-
}]);
|
|
1927
|
-
for (const [index, constraint] of input.constraints.entries()) {
|
|
1928
|
-
const relation = await checkTypeTermRelationAsync(constraint.source, constraint.target, relationContext(context, bindings));
|
|
1929
|
-
if (relation.status !== "assignable") return makeResult(relation.status, bindings, input.variables, [issue(relation.status, index, relation.issues[0]?.message ?? "type relation could not be established")]);
|
|
1930
|
-
}
|
|
1931
|
-
return makeResult("solved", bindings, input.variables, []);
|
|
1932
|
-
}
|
|
1933
1431
|
|
|
1934
1432
|
//#endregion
|
|
1935
|
-
export {
|
|
1433
|
+
export { checkTypeTermRelation as i, evaluateExpression as n, evaluateSchemaTypeTerm as r, solveTypeVariables as t };
|