@formspec/build 0.1.0-alpha.15 → 0.1.0-alpha.16

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 (42) hide show
  1. package/dist/__tests__/fixtures/edge-cases.d.ts +11 -0
  2. package/dist/__tests__/fixtures/edge-cases.d.ts.map +1 -1
  3. package/dist/__tests__/fixtures/mixed-authoring-shipping-address.d.ts +30 -0
  4. package/dist/__tests__/fixtures/mixed-authoring-shipping-address.d.ts.map +1 -0
  5. package/dist/__tests__/mixed-authoring.test.d.ts +2 -0
  6. package/dist/__tests__/mixed-authoring.test.d.ts.map +1 -0
  7. package/dist/__tests__/parity/utils.d.ts +5 -3
  8. package/dist/__tests__/parity/utils.d.ts.map +1 -1
  9. package/dist/analyzer/class-analyzer.d.ts +4 -2
  10. package/dist/analyzer/class-analyzer.d.ts.map +1 -1
  11. package/dist/analyzer/tsdoc-parser.d.ts +20 -2
  12. package/dist/analyzer/tsdoc-parser.d.ts.map +1 -1
  13. package/dist/browser.cjs +172 -17
  14. package/dist/browser.cjs.map +1 -1
  15. package/dist/browser.d.ts.map +1 -1
  16. package/dist/browser.js +172 -17
  17. package/dist/browser.js.map +1 -1
  18. package/dist/build.d.ts +39 -1
  19. package/dist/canonicalize/tsdoc-canonicalizer.d.ts.map +1 -1
  20. package/dist/cli.cjs +634 -88
  21. package/dist/cli.cjs.map +1 -1
  22. package/dist/cli.js +634 -88
  23. package/dist/cli.js.map +1 -1
  24. package/dist/generators/mixed-authoring.d.ts +45 -0
  25. package/dist/generators/mixed-authoring.d.ts.map +1 -0
  26. package/dist/index.cjs +622 -87
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +621 -87
  31. package/dist/index.js.map +1 -1
  32. package/dist/internals.cjs +526 -91
  33. package/dist/internals.cjs.map +1 -1
  34. package/dist/internals.js +526 -91
  35. package/dist/internals.js.map +1 -1
  36. package/dist/json-schema/ir-generator.d.ts +3 -2
  37. package/dist/json-schema/ir-generator.d.ts.map +1 -1
  38. package/dist/ui-schema/ir-generator.d.ts.map +1 -1
  39. package/dist/validate/constraint-validator.d.ts.map +1 -1
  40. package/package.json +3 -3
  41. package/dist/__tests__/jsdoc-constraints.test.d.ts +0 -9
  42. package/dist/__tests__/jsdoc-constraints.test.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,KAAK,cAAc,EACpB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGrD,YAAY,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,YAAY,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AACrF,YAAY,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAE5E,YAAY,EACV,WAAW,EACX,cAAc,EACd,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,YAAY,EACV,QAAQ,EACR,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,IAAI,EACJ,UAAU,EACV,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,gBAAgB,EAChB,yBAAyB,EACzB,mBAAmB,EACnB,0BAA0B,EAC1B,UAAU,EACV,aAAa,EACb,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,QAAQ,IAAI,cAAc,GAC3B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAGlF,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAG5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAGjF,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,YAAY,EACV,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,oCAAoC,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,yCAAyC;IACzC,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,yBAAyB,CAAC;AAEhE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,SAAS,WAAW,EAAE,EAC/D,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EACjB,OAAO,CAAC,EAAE,uBAAuB,GAChC,WAAW,CAKb"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAsB,KAAK,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAEhG,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGrD,YAAY,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,YAAY,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AACrF,YAAY,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAE5E,YAAY,EACV,WAAW,EACX,cAAc,EACd,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,YAAY,EACV,QAAQ,EACR,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,IAAI,EACJ,UAAU,EACV,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,gBAAgB,EAChB,yBAAyB,EACzB,mBAAmB,EACnB,0BAA0B,EAC1B,UAAU,EACV,aAAa,EACb,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,QAAQ,IAAI,cAAc,GAC3B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAGlF,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAG5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAGjF,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,YAAY,EACV,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,oCAAoC,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,yCAAyC;IACzC,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,yBAAyB,CAAC;AAEhE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,SAAS,WAAW,EAAE,EAC/D,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EACjB,OAAO,CAAC,EAAE,uBAAuB,GAChC,WAAW,CAKb"}
package/dist/browser.js CHANGED
@@ -330,6 +330,9 @@ function generateJsonSchemaFromIR(ir, options) {
330
330
  const ctx = makeContext(options);
331
331
  for (const [name, typeDef] of Object.entries(ir.typeRegistry)) {
332
332
  ctx.defs[name] = generateTypeNode(typeDef.type, ctx);
333
+ if (typeDef.annotations && typeDef.annotations.length > 0) {
334
+ applyAnnotations(ctx.defs[name], typeDef.annotations, ctx);
335
+ }
333
336
  }
334
337
  const properties = {};
335
338
  const required = [];
@@ -341,6 +344,9 @@ function generateJsonSchemaFromIR(ir, options) {
341
344
  properties,
342
345
  ...uniqueRequired.length > 0 && { required: uniqueRequired }
343
346
  };
347
+ if (ir.annotations && ir.annotations.length > 0) {
348
+ applyAnnotations(result, ir.annotations, ctx);
349
+ }
344
350
  if (Object.keys(ctx.defs).length > 0) {
345
351
  result.$defs = ctx.defs;
346
352
  }
@@ -370,22 +376,51 @@ function collectFields(elements, properties, required, ctx) {
370
376
  }
371
377
  function generateFieldSchema(field, ctx) {
372
378
  const schema = generateTypeNode(field.type, ctx);
379
+ const itemStringSchema = schema.type === "array" && schema.items?.type === "string" ? schema.items : void 0;
373
380
  const directConstraints = [];
381
+ const itemConstraints = [];
374
382
  const pathConstraints = [];
375
383
  for (const c of field.constraints) {
376
384
  if (c.path) {
377
385
  pathConstraints.push(c);
386
+ } else if (itemStringSchema !== void 0 && isStringItemConstraint(c)) {
387
+ itemConstraints.push(c);
378
388
  } else {
379
389
  directConstraints.push(c);
380
390
  }
381
391
  }
382
392
  applyConstraints(schema, directConstraints, ctx);
383
- applyAnnotations(schema, field.annotations, ctx);
393
+ if (itemStringSchema !== void 0) {
394
+ applyConstraints(itemStringSchema, itemConstraints, ctx);
395
+ }
396
+ const rootAnnotations = [];
397
+ const itemAnnotations = [];
398
+ for (const annotation of field.annotations) {
399
+ if (itemStringSchema !== void 0 && annotation.annotationKind === "format") {
400
+ itemAnnotations.push(annotation);
401
+ } else {
402
+ rootAnnotations.push(annotation);
403
+ }
404
+ }
405
+ applyAnnotations(schema, rootAnnotations, ctx);
406
+ if (itemStringSchema !== void 0) {
407
+ applyAnnotations(itemStringSchema, itemAnnotations, ctx);
408
+ }
384
409
  if (pathConstraints.length === 0) {
385
410
  return schema;
386
411
  }
387
412
  return applyPathTargetedConstraints(schema, pathConstraints, ctx);
388
413
  }
414
+ function isStringItemConstraint(constraint) {
415
+ switch (constraint.constraintKind) {
416
+ case "minLength":
417
+ case "maxLength":
418
+ case "pattern":
419
+ return true;
420
+ default:
421
+ return false;
422
+ }
423
+ }
389
424
  function applyPathTargetedConstraints(schema, pathConstraints, ctx) {
390
425
  if (schema.type === "array" && schema.items) {
391
426
  schema.items = applyPathTargetedConstraints(schema.items, pathConstraints, ctx);
@@ -603,6 +638,9 @@ function applyConstraints(schema, constraints, ctx) {
603
638
  case "uniqueItems":
604
639
  schema.uniqueItems = constraint.value;
605
640
  break;
641
+ case "const":
642
+ schema.const = constraint.value;
643
+ break;
606
644
  case "allowedMembers":
607
645
  break;
608
646
  case "custom":
@@ -627,8 +665,14 @@ function applyAnnotations(schema, annotations, ctx) {
627
665
  case "defaultValue":
628
666
  schema.default = annotation.value;
629
667
  break;
668
+ case "format":
669
+ schema.format = annotation.value;
670
+ break;
630
671
  case "deprecated":
631
672
  schema.deprecated = true;
673
+ if (annotation.message !== void 0 && annotation.message !== "") {
674
+ schema["x-formspec-deprecation-description"] = annotation.message;
675
+ }
632
676
  break;
633
677
  case "placeholder":
634
678
  break;
@@ -816,25 +860,31 @@ function createShowRule(fieldName, value) {
816
860
  }
817
861
  };
818
862
  }
863
+ function flattenConditionSchema(scope, schema) {
864
+ if (schema.allOf === void 0) {
865
+ if (scope === "#") {
866
+ return [schema];
867
+ }
868
+ const fieldName = scope.replace("#/properties/", "");
869
+ return [
870
+ {
871
+ properties: {
872
+ [fieldName]: schema
873
+ }
874
+ }
875
+ ];
876
+ }
877
+ return schema.allOf.flatMap((member) => flattenConditionSchema(scope, member));
878
+ }
819
879
  function combineRules(parentRule, childRule) {
820
- const parentCondition = parentRule.condition;
821
- const childCondition = childRule.condition;
822
880
  return {
823
881
  effect: "SHOW",
824
882
  condition: {
825
883
  scope: "#",
826
884
  schema: {
827
885
  allOf: [
828
- {
829
- properties: {
830
- [parentCondition.scope.replace("#/properties/", "")]: parentCondition.schema
831
- }
832
- },
833
- {
834
- properties: {
835
- [childCondition.scope.replace("#/properties/", "")]: childCondition.schema
836
- }
837
- }
886
+ ...flattenConditionSchema(parentRule.condition.scope, parentRule.condition.schema),
887
+ ...flattenConditionSchema(childRule.condition.scope, childRule.condition.schema)
838
888
  ]
839
889
  }
840
890
  }
@@ -842,10 +892,14 @@ function combineRules(parentRule, childRule) {
842
892
  }
843
893
  function fieldNodeToControl(field, parentRule) {
844
894
  const displayNameAnnotation = field.annotations.find((a) => a.annotationKind === "displayName");
895
+ const placeholderAnnotation = field.annotations.find((a) => a.annotationKind === "placeholder");
845
896
  const control = {
846
897
  type: "Control",
847
898
  scope: fieldToScope(field.name),
848
899
  ...displayNameAnnotation !== void 0 && { label: displayNameAnnotation.value },
900
+ ...placeholderAnnotation !== void 0 && {
901
+ options: { placeholder: placeholderAnnotation.value }
902
+ },
849
903
  ...parentRule !== void 0 && { rule: parentRule }
850
904
  };
851
905
  return control;
@@ -1040,6 +1094,15 @@ function addUnknownExtension(ctx, message, primary) {
1040
1094
  relatedLocations: []
1041
1095
  });
1042
1096
  }
1097
+ function addUnknownPathTarget(ctx, message, primary) {
1098
+ ctx.diagnostics.push({
1099
+ code: "UNKNOWN_PATH_TARGET",
1100
+ message,
1101
+ severity: "error",
1102
+ primaryLocation: primary,
1103
+ relatedLocations: []
1104
+ });
1105
+ }
1043
1106
  function addConstraintBroadening(ctx, message, primary, related) {
1044
1107
  ctx.diagnostics.push({
1045
1108
  code: "CONSTRAINT_BROADENING",
@@ -1060,6 +1123,45 @@ function findAllowedMembers(constraints) {
1060
1123
  (c) => c.constraintKind === "allowedMembers"
1061
1124
  );
1062
1125
  }
1126
+ function findConstConstraints(constraints) {
1127
+ return constraints.filter(
1128
+ (c) => c.constraintKind === "const"
1129
+ );
1130
+ }
1131
+ function jsonValueEquals(left, right) {
1132
+ if (left === right) {
1133
+ return true;
1134
+ }
1135
+ if (Array.isArray(left) || Array.isArray(right)) {
1136
+ if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) {
1137
+ return false;
1138
+ }
1139
+ return left.every((item, index) => jsonValueEquals(item, right[index]));
1140
+ }
1141
+ if (isJsonObject(left) || isJsonObject(right)) {
1142
+ if (!isJsonObject(left) || !isJsonObject(right)) {
1143
+ return false;
1144
+ }
1145
+ const leftKeys = Object.keys(left).sort();
1146
+ const rightKeys = Object.keys(right).sort();
1147
+ if (leftKeys.length !== rightKeys.length) {
1148
+ return false;
1149
+ }
1150
+ return leftKeys.every((key, index) => {
1151
+ const rightKey = rightKeys[index];
1152
+ if (rightKey !== key) {
1153
+ return false;
1154
+ }
1155
+ const leftValue = left[key];
1156
+ const rightValue = right[rightKey];
1157
+ return leftValue !== void 0 && rightValue !== void 0 && jsonValueEquals(leftValue, rightValue);
1158
+ });
1159
+ }
1160
+ return false;
1161
+ }
1162
+ function isJsonObject(value) {
1163
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1164
+ }
1063
1165
  function isOrderedBoundConstraint(constraint) {
1064
1166
  return constraint.constraintKind === "minimum" || constraint.constraintKind === "exclusiveMinimum" || constraint.constraintKind === "minLength" || constraint.constraintKind === "minItems" || constraint.constraintKind === "maximum" || constraint.constraintKind === "exclusiveMaximum" || constraint.constraintKind === "maxLength" || constraint.constraintKind === "maxItems";
1065
1167
  }
@@ -1266,6 +1368,25 @@ function checkAllowedMembersContradiction(ctx, fieldName, constraints) {
1266
1368
  }
1267
1369
  }
1268
1370
  }
1371
+ function checkConstContradictions(ctx, fieldName, constraints) {
1372
+ const constConstraints = findConstConstraints(constraints);
1373
+ if (constConstraints.length < 2) return;
1374
+ const first = constConstraints[0];
1375
+ if (first === void 0) return;
1376
+ for (let i = 1; i < constConstraints.length; i++) {
1377
+ const current = constConstraints[i];
1378
+ if (current === void 0) continue;
1379
+ if (jsonValueEquals(first.value, current.value)) {
1380
+ continue;
1381
+ }
1382
+ addContradiction(
1383
+ ctx,
1384
+ `Field "${fieldName}": conflicting @const constraints require both ${JSON.stringify(first.value)} and ${JSON.stringify(current.value)}`,
1385
+ first.provenance,
1386
+ current.provenance
1387
+ );
1388
+ }
1389
+ }
1269
1390
  function typeLabel(type) {
1270
1391
  switch (type.kind) {
1271
1392
  case "primitive":
@@ -1338,6 +1459,8 @@ function checkConstraintOnType(ctx, fieldName, type, constraint) {
1338
1459
  const isString = effectiveType.kind === "primitive" && effectiveType.primitiveKind === "string";
1339
1460
  const isArray = effectiveType.kind === "array";
1340
1461
  const isEnum = effectiveType.kind === "enum";
1462
+ const arrayItemType = effectiveType.kind === "array" ? dereferenceType(ctx, effectiveType.items) : void 0;
1463
+ const isStringArray = arrayItemType?.kind === "primitive" && arrayItemType.primitiveKind === "string";
1341
1464
  const label = typeLabel(effectiveType);
1342
1465
  const ck = constraint.constraintKind;
1343
1466
  switch (ck) {
@@ -1358,10 +1481,10 @@ function checkConstraintOnType(ctx, fieldName, type, constraint) {
1358
1481
  case "minLength":
1359
1482
  case "maxLength":
1360
1483
  case "pattern": {
1361
- if (!isString) {
1484
+ if (!isString && !isStringArray) {
1362
1485
  addTypeMismatch(
1363
1486
  ctx,
1364
- `Field "${fieldName}": constraint "${ck}" is only valid on string fields, but field type is "${label}"`,
1487
+ `Field "${fieldName}": constraint "${ck}" is only valid on string fields or string array items, but field type is "${label}"`,
1365
1488
  constraint.provenance
1366
1489
  );
1367
1490
  }
@@ -1389,6 +1512,37 @@ function checkConstraintOnType(ctx, fieldName, type, constraint) {
1389
1512
  }
1390
1513
  break;
1391
1514
  }
1515
+ case "const": {
1516
+ const isPrimitiveConstType = effectiveType.kind === "primitive" && ["string", "number", "boolean", "null"].includes(effectiveType.primitiveKind) || effectiveType.kind === "enum";
1517
+ if (!isPrimitiveConstType) {
1518
+ addTypeMismatch(
1519
+ ctx,
1520
+ `Field "${fieldName}": constraint "const" is only valid on primitive or enum fields, but field type is "${label}"`,
1521
+ constraint.provenance
1522
+ );
1523
+ break;
1524
+ }
1525
+ if (effectiveType.kind === "primitive") {
1526
+ const valueType = constraint.value === null ? "null" : Array.isArray(constraint.value) ? "array" : typeof constraint.value;
1527
+ if (valueType !== effectiveType.primitiveKind) {
1528
+ addTypeMismatch(
1529
+ ctx,
1530
+ `Field "${fieldName}": @const value type "${valueType}" is incompatible with field type "${effectiveType.primitiveKind}"`,
1531
+ constraint.provenance
1532
+ );
1533
+ }
1534
+ break;
1535
+ }
1536
+ const memberValues = effectiveType.members.map((member) => member.value);
1537
+ if (!memberValues.some((member) => jsonValueEquals(member, constraint.value))) {
1538
+ addTypeMismatch(
1539
+ ctx,
1540
+ `Field "${fieldName}": @const value ${JSON.stringify(constraint.value)} is not one of the enum members`,
1541
+ constraint.provenance
1542
+ );
1543
+ }
1544
+ break;
1545
+ }
1392
1546
  case "custom": {
1393
1547
  checkCustomConstraint(ctx, fieldName, effectiveType, constraint);
1394
1548
  break;
@@ -1407,9 +1561,9 @@ function checkTypeApplicability(ctx, fieldName, type, constraints) {
1407
1561
  const resolution = resolvePathTargetType(ctx, type, constraint.path.segments);
1408
1562
  const targetFieldName = formatPathTargetFieldName(fieldName, constraint.path.segments);
1409
1563
  if (resolution.kind === "missing-property") {
1410
- addTypeMismatch(
1564
+ addUnknownPathTarget(
1411
1565
  ctx,
1412
- `Field "${fieldName}": path-targeted constraint "${constraint.constraintKind}" references unknown path segment "${resolution.segment}"`,
1566
+ `Field "${targetFieldName}": path-targeted constraint "${constraint.constraintKind}" references unknown path segment "${resolution.segment}"`,
1413
1567
  constraint.provenance
1414
1568
  );
1415
1569
  continue;
@@ -1469,6 +1623,7 @@ function validateConstraints(ctx, name, type, constraints) {
1469
1623
  checkNumericContradictions(ctx, name, constraints);
1470
1624
  checkLengthContradictions(ctx, name, constraints);
1471
1625
  checkAllowedMembersContradiction(ctx, name, constraints);
1626
+ checkConstContradictions(ctx, name, constraints);
1472
1627
  checkConstraintBroadening(ctx, name, constraints);
1473
1628
  checkTypeApplicability(ctx, name, type, constraints);
1474
1629
  }