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.
Files changed (83) hide show
  1. package/README.md +542 -32
  2. package/dist/authoring/index.cjs +13 -350
  3. package/dist/authoring/index.d.cts +2 -90
  4. package/dist/authoring/index.d.ts +2 -90
  5. package/dist/authoring/index.js +2 -304
  6. package/dist/authoring-Dnrg5TXm.cjs +389 -0
  7. package/dist/authoring-DyJNYs5o.js +362 -0
  8. package/dist/chunk-bFfwrPtJ.js +18 -0
  9. package/dist/compatibility/index.cjs +43 -0
  10. package/dist/compatibility/index.d.cts +2 -0
  11. package/dist/compatibility/index.d.ts +2 -0
  12. package/dist/compatibility/index.js +42 -0
  13. package/dist/definition/index.cjs +10 -2
  14. package/dist/definition/index.d.cts +3 -21
  15. package/dist/definition/index.d.ts +3 -21
  16. package/dist/definition/index.js +2 -2
  17. package/dist/definition-BH_LzXGc.js +1115 -0
  18. package/dist/definition-BLLBpLKv.cjs +1187 -0
  19. package/dist/index-1sDuqu05.d.ts +373 -0
  20. package/dist/index-BFSMT_2d.d.ts +53 -0
  21. package/dist/index-BGz7L_Fq.d.cts +73 -0
  22. package/dist/index-BTtdqi_M.d.ts +418 -0
  23. package/dist/index-BfbClf6R.d.cts +20 -0
  24. package/dist/index-CK7Is7vy.d.cts +420 -0
  25. package/dist/index-CUGhtuwA.d.cts +53 -0
  26. package/dist/index-CV8EZQy8.d.ts +92 -0
  27. package/dist/index-CzNxjqVg.d.cts +47 -0
  28. package/dist/index-DGHMUZ5m.d.cts +92 -0
  29. package/dist/{index-eK2Xgrwp.d.ts → index-DxvfPmw6.d.ts} +13 -9
  30. package/dist/index-T6nFhvGQ.d.ts +20 -0
  31. package/dist/{index-TACcK_mi.d.cts → index-ba_52Yu9.d.cts} +13 -9
  32. package/dist/index-hrcM9oJe.d.ts +47 -0
  33. package/dist/index-i7Au-FQ6.d.cts +373 -0
  34. package/dist/index-mu1znI1F.d.ts +73 -0
  35. package/dist/index.cjs +70 -58
  36. package/dist/index.d.cts +9 -7
  37. package/dist/index.d.ts +9 -7
  38. package/dist/index.js +10 -6
  39. package/dist/integrations/json-schema/index.cjs +328 -0
  40. package/dist/integrations/json-schema/index.d.cts +53 -0
  41. package/dist/integrations/json-schema/index.d.ts +53 -0
  42. package/dist/integrations/json-schema/index.js +324 -0
  43. package/dist/integrations/standard-schema/index.cjs +32 -0
  44. package/dist/integrations/standard-schema/index.d.cts +22 -0
  45. package/dist/integrations/standard-schema/index.d.ts +22 -0
  46. package/dist/integrations/standard-schema/index.js +32 -0
  47. package/dist/payload/index.cjs +45 -82
  48. package/dist/payload/index.d.cts +2 -56
  49. package/dist/payload/index.d.ts +2 -56
  50. package/dist/payload/index.js +45 -81
  51. package/dist/relations/index.cjs +3 -4
  52. package/dist/relations/index.d.cts +2 -2
  53. package/dist/relations/index.d.ts +2 -2
  54. package/dist/relations/index.js +2 -2
  55. package/dist/{relations-CMz_0nf4.cjs → relations-NUVJkAG8.cjs} +143 -211
  56. package/dist/{relations-By0bK3UK.js → relations-QtnCRW9x.js} +140 -202
  57. package/dist/resolve/index.cjs +308 -0
  58. package/dist/resolve/index.d.cts +2 -0
  59. package/dist/resolve/index.d.ts +2 -0
  60. package/dist/resolve/index.js +305 -0
  61. package/dist/schema-ref-key-BHVFVfj1.cjs +26 -0
  62. package/dist/schema-ref-key-DR__tPr-.js +14 -0
  63. package/dist/spec/index.cjs +9 -0
  64. package/dist/spec/index.d.cts +2 -2
  65. package/dist/spec/index.d.ts +2 -2
  66. package/dist/spec/index.js +3 -1
  67. package/dist/standard/index.cjs +810 -0
  68. package/dist/standard/index.d.cts +3 -0
  69. package/dist/standard/index.d.ts +3 -0
  70. package/dist/standard/index.js +777 -0
  71. package/dist/standard-BGMgbbEQ.js +471 -0
  72. package/dist/standard-etPFZDJI.cjs +513 -0
  73. package/dist/type-interpreter/index.cjs +3 -7
  74. package/dist/type-interpreter/index.d.cts +2 -99
  75. package/dist/type-interpreter/index.d.ts +2 -99
  76. package/dist/type-interpreter/index.js +2 -2
  77. package/dist/{type-interpreter-Ck0VDhzn.js → type-interpreter-BA8gcLUU.js} +58 -560
  78. package/dist/{type-interpreter-DAIBUqKf.cjs → type-interpreter-D8xETgq1.cjs} +63 -589
  79. package/package.json +60 -5
  80. package/dist/definition-BXj3T94L.js +0 -467
  81. package/dist/definition-DSZZTz4e.cjs +0 -473
  82. package/dist/index-CEzHfht2.d.ts +0 -269
  83. package/dist/index-rzkFjgrt.d.cts +0 -269
@@ -1,5 +1,6 @@
1
- import { t as validateSchemaNodeDefinition } from "./definition-BXj3T94L.js";
2
- import { i as checkSchemaRelationAsync, r as checkSchemaRelation } from "./relations-By0bK3UK.js";
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
- async function compareTermsAsync(source, target, context) {
939
- if (source.kind === "never") return {
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
- status: "unknown",
1052
- issues: [{
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
- return compareEvaluated(evaluateExpression(source, context.interpreter), evaluateExpression(target, context.interpreter), context.relation, context.hostTypeRelation);
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][subkey] = value;
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
- if (!state.context.resolveRef) return failure("incomplete", "ref.resolver", "refPath requires an explicit resolver");
1549
- const key = term.refPath.join("\0");
1550
- if (state.refs.has(key)) return failure("incomplete", "cycle.ref", "refPath resolution cycle could not be determined");
1551
- state.refs.add(key);
1552
- let resolved;
1553
- try {
1554
- resolved = state.context.resolveRef(term.refPath);
1555
- } catch (error) {
1556
- state.refs.delete(key);
1557
- return failure("incomplete", "ref.error", `refPath resolver failed: ${error instanceof Error ? error.message : String(error)}`);
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
- async function evaluateExpressionAsync(term, context = {}) {
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 { evaluateSchemaValueTypeTerm as a, checkTypeTermRelationAsync as c, evaluateExpressionAsync as i, solveTypeVariablesAsync as n, evaluateSchemaValueTypeTermAsync as o, evaluateExpression as r, checkTypeTermRelation as s, solveTypeVariables as t };
1433
+ export { checkTypeTermRelation as i, evaluateExpression as n, evaluateSchemaTypeTerm as r, solveTypeVariables as t };