@formspec/build 0.1.0-alpha.42 → 0.1.0-alpha.44

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.
@@ -857,48 +857,8 @@ var ts2 = __toESM(require("typescript"), 1);
857
857
  // src/analyzer/tsdoc-parser.ts
858
858
  var ts = __toESM(require("typescript"), 1);
859
859
  var import_internal = require("@formspec/analysis/internal");
860
- var import_tsdoc = require("@microsoft/tsdoc");
861
860
  var import_internals3 = require("@formspec/core/internals");
862
861
  var import_internals4 = require("@formspec/core/internals");
863
- var TAGS_REQUIRING_RAW_TEXT = /* @__PURE__ */ new Set(["pattern", "enumOptions", "defaultValue"]);
864
- function createFormSpecTSDocConfig(extensionTagNames = []) {
865
- const config = new import_tsdoc.TSDocConfiguration();
866
- for (const tagName of Object.keys(import_internals3.BUILTIN_CONSTRAINT_DEFINITIONS)) {
867
- config.addTagDefinition(
868
- new import_tsdoc.TSDocTagDefinition({
869
- tagName: "@" + tagName,
870
- syntaxKind: import_tsdoc.TSDocTagSyntaxKind.BlockTag,
871
- allowMultiple: true
872
- })
873
- );
874
- }
875
- for (const tagName of ["apiName", "displayName", "format", "placeholder"]) {
876
- config.addTagDefinition(
877
- new import_tsdoc.TSDocTagDefinition({
878
- tagName: "@" + tagName,
879
- syntaxKind: import_tsdoc.TSDocTagSyntaxKind.BlockTag,
880
- allowMultiple: true
881
- })
882
- );
883
- }
884
- for (const tagName of extensionTagNames) {
885
- config.addTagDefinition(
886
- new import_tsdoc.TSDocTagDefinition({
887
- tagName: "@" + tagName,
888
- syntaxKind: import_tsdoc.TSDocTagSyntaxKind.BlockTag,
889
- allowMultiple: true
890
- })
891
- );
892
- }
893
- return config;
894
- }
895
- function sharedCommentSyntaxOptions(options, offset) {
896
- const extensions = options?.extensionRegistry?.extensions;
897
- return {
898
- ...offset !== void 0 ? { offset } : {},
899
- ...extensions !== void 0 ? { extensions } : {}
900
- };
901
- }
902
862
  function sharedTagValueOptions(options) {
903
863
  return {
904
864
  ...options?.extensionRegistry !== void 0 ? { registry: options.extensionRegistry } : {},
@@ -998,6 +958,30 @@ function pushUniqueCompilerDiagnostics(target, additions) {
998
958
  target.push(diagnostic);
999
959
  }
1000
960
  }
961
+ function processConstraintTag(tagName, text, parsedTag, provenance, node, sourceFile, supportingDeclarations, options, constraints, diagnostics) {
962
+ const compilerDiagnostics = buildCompilerBackedConstraintDiagnostics(
963
+ node,
964
+ sourceFile,
965
+ tagName,
966
+ parsedTag,
967
+ provenance,
968
+ supportingDeclarations,
969
+ options
970
+ );
971
+ if (compilerDiagnostics.length > 0) {
972
+ pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
973
+ return;
974
+ }
975
+ const constraintNode = (0, import_internal.parseConstraintTagValue)(
976
+ tagName,
977
+ text,
978
+ provenance,
979
+ sharedTagValueOptions(options)
980
+ );
981
+ if (constraintNode) {
982
+ constraints.push(constraintNode);
983
+ }
984
+ }
1001
985
  function renderSyntheticArgumentExpression(valueKind, argumentText) {
1002
986
  const trimmed = argumentText.trim();
1003
987
  if (trimmed === "") {
@@ -1283,10 +1267,9 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
1283
1267
  )
1284
1268
  ];
1285
1269
  }
1286
- var parserCache = /* @__PURE__ */ new Map();
1287
1270
  var parseResultCache = /* @__PURE__ */ new Map();
1288
- function getParser(options) {
1289
- const extensionTagNames = [
1271
+ function getExtensionTagNames(options) {
1272
+ return [
1290
1273
  ...options?.extensionRegistry?.extensions.flatMap(
1291
1274
  (extension) => (extension.constraintTags ?? []).map((tag) => (0, import_internal.normalizeFormSpecTagName)(tag.tagName))
1292
1275
  ) ?? [],
@@ -1294,14 +1277,6 @@ function getParser(options) {
1294
1277
  (extension) => (extension.metadataSlots ?? []).map((slot) => (0, import_internal.normalizeFormSpecTagName)(slot.tagName))
1295
1278
  ) ?? []
1296
1279
  ].sort();
1297
- const cacheKey = extensionTagNames.join("|");
1298
- const existing = parserCache.get(cacheKey);
1299
- if (existing) {
1300
- return existing;
1301
- }
1302
- const parser = new import_tsdoc.TSDocParser(createFormSpecTSDocConfig(extensionTagNames));
1303
- parserCache.set(cacheKey, parser);
1304
- return parser;
1305
1280
  }
1306
1281
  function getExtensionRegistryCacheKey(registry) {
1307
1282
  if (registry === void 0) {
@@ -1352,13 +1327,13 @@ function parseTSDocTags(node, file = "", options) {
1352
1327
  let placeholder;
1353
1328
  let displayNameProvenance;
1354
1329
  let placeholderProvenance;
1355
- const rawTextTags = [];
1356
1330
  const sourceFile = node.getSourceFile();
1357
1331
  const sourceText = sourceFile.getFullText();
1358
1332
  const extensionTypeNames = getExtensionTypeNames(options?.extensionRegistry);
1359
1333
  const supportingDeclarations = buildSupportingDeclarations(sourceFile, extensionTypeNames);
1360
1334
  const commentRanges = ts.getLeadingCommentRanges(sourceText, node.getFullStart());
1361
1335
  const rawTextFallbacks = collectRawTextFallbacks(node, file);
1336
+ const extensionTagNames = getExtensionTagNames(options);
1362
1337
  if (commentRanges) {
1363
1338
  for (const range of commentRanges) {
1364
1339
  if (range.kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
@@ -1368,38 +1343,18 @@ function parseTSDocTags(node, file = "", options) {
1368
1343
  if (!commentText.startsWith("/**")) {
1369
1344
  continue;
1370
1345
  }
1371
- const parser = getParser(options);
1372
- const parserContext = parser.parseRange(
1373
- import_tsdoc.TextRange.fromStringRange(sourceText, range.pos, range.end)
1374
- );
1375
- const docComment = parserContext.docComment;
1376
- const parsedComment = (0, import_internal.parseCommentBlock)(
1377
- commentText,
1378
- sharedCommentSyntaxOptions(options, range.pos)
1379
- );
1380
- let parsedTagCursor = 0;
1381
- const nextParsedTag = (normalizedTagName) => {
1382
- while (parsedTagCursor < parsedComment.tags.length) {
1383
- const candidate = parsedComment.tags[parsedTagCursor];
1384
- parsedTagCursor += 1;
1385
- if (candidate?.normalizedTagName === normalizedTagName) {
1386
- return candidate;
1387
- }
1388
- }
1389
- return null;
1390
- };
1391
- for (const parsedTag of parsedComment.tags) {
1392
- if (TAGS_REQUIRING_RAW_TEXT.has(parsedTag.normalizedTagName)) {
1393
- rawTextTags.push({ tag: parsedTag, commentText, commentOffset: range.pos });
1394
- }
1395
- }
1396
- for (const block of docComment.customBlocks) {
1397
- const tagName = (0, import_internals3.normalizeConstraintTagName)(block.blockTag.tagName.substring(1));
1398
- const parsedTag = nextParsedTag(tagName);
1346
+ const extensions = options?.extensionRegistry?.extensions;
1347
+ const unified = (0, import_internal.parseUnifiedComment)(commentText, {
1348
+ offset: range.pos,
1349
+ extensionTagNames,
1350
+ ...extensions !== void 0 ? { extensions } : {}
1351
+ });
1352
+ for (const tag of unified.tags) {
1353
+ const tagName = tag.normalizedTagName;
1399
1354
  if (tagName === "displayName" || tagName === "format" || tagName === "placeholder") {
1400
- const text2 = getBestBlockPayloadText(parsedTag, commentText, range.pos, block);
1355
+ const text2 = tag.resolvedPayloadText;
1401
1356
  if (text2 === "") continue;
1402
- const provenance2 = parsedTag !== null ? provenanceForParsedTag(parsedTag, sourceFile, file) : provenanceForComment(range, sourceFile, file, tagName);
1357
+ const provenance2 = provenanceForParsedTag(tag, sourceFile, file);
1403
1358
  switch (tagName) {
1404
1359
  case "displayName":
1405
1360
  if (!isMemberTargetDisplayName(text2) && displayName === void 0) {
@@ -1424,64 +1379,69 @@ function parseTSDocTags(node, file = "", options) {
1424
1379
  }
1425
1380
  continue;
1426
1381
  }
1427
- if (TAGS_REQUIRING_RAW_TEXT.has(tagName)) continue;
1428
- const text = getBestBlockPayloadText(parsedTag, commentText, range.pos, block);
1429
- const expectedType = (0, import_internals3.isBuiltinConstraintName)(tagName) ? import_internals3.BUILTIN_CONSTRAINT_DEFINITIONS[tagName] : void 0;
1430
- if (text === "" && expectedType !== "boolean") continue;
1431
- const provenance = parsedTag !== null ? provenanceForParsedTag(parsedTag, sourceFile, file) : provenanceForComment(range, sourceFile, file, tagName);
1432
- const compilerDiagnostics = buildCompilerBackedConstraintDiagnostics(
1433
- node,
1434
- sourceFile,
1435
- tagName,
1436
- parsedTag,
1437
- provenance,
1438
- supportingDeclarations,
1439
- options
1440
- );
1441
- if (compilerDiagnostics.length > 0) {
1442
- pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
1382
+ if (import_internal.TAGS_REQUIRING_RAW_TEXT.has(tagName)) {
1383
+ const fallback = rawTextFallbacks.get(tagName)?.shift();
1384
+ const text2 = (0, import_internal.choosePreferredPayloadText)(tag.resolvedPayloadText, fallback?.text ?? "");
1385
+ if (text2 === "") continue;
1386
+ const provenance2 = provenanceForParsedTag(tag, sourceFile, file);
1387
+ if (tagName === "defaultValue") {
1388
+ annotations.push((0, import_internal.parseDefaultValueTagValue)(text2, provenance2));
1389
+ continue;
1390
+ }
1391
+ processConstraintTag(
1392
+ tagName,
1393
+ text2,
1394
+ tag,
1395
+ provenance2,
1396
+ node,
1397
+ sourceFile,
1398
+ supportingDeclarations,
1399
+ options,
1400
+ constraints,
1401
+ diagnostics
1402
+ );
1443
1403
  continue;
1444
1404
  }
1445
- const constraintNode = (0, import_internal.parseConstraintTagValue)(
1405
+ const text = tag.resolvedPayloadText;
1406
+ const expectedType = (0, import_internals3.isBuiltinConstraintName)(tagName) ? import_internals3.BUILTIN_CONSTRAINT_DEFINITIONS[tagName] : void 0;
1407
+ if (text === "" && expectedType !== "boolean") continue;
1408
+ const provenance = provenanceForParsedTag(tag, sourceFile, file);
1409
+ processConstraintTag(
1446
1410
  tagName,
1447
1411
  text,
1412
+ tag,
1448
1413
  provenance,
1449
- sharedTagValueOptions(options)
1414
+ node,
1415
+ sourceFile,
1416
+ supportingDeclarations,
1417
+ options,
1418
+ constraints,
1419
+ diagnostics
1450
1420
  );
1451
- if (constraintNode) {
1452
- constraints.push(constraintNode);
1453
- }
1454
1421
  }
1455
- if (docComment.deprecatedBlock !== void 0) {
1456
- const message = extractBlockText(docComment.deprecatedBlock).trim();
1422
+ if (unified.isDeprecated) {
1457
1423
  annotations.push({
1458
1424
  kind: "annotation",
1459
1425
  annotationKind: "deprecated",
1460
- ...message !== "" && { message },
1426
+ ...unified.deprecationMessage !== "" && { message: unified.deprecationMessage },
1461
1427
  provenance: provenanceForComment(range, sourceFile, file, "deprecated")
1462
1428
  });
1463
1429
  }
1464
- {
1465
- const summary = extractPlainText(docComment.summarySection).trim();
1466
- if (summary !== "") {
1467
- annotations.push({
1468
- kind: "annotation",
1469
- annotationKind: "description",
1470
- value: summary,
1471
- provenance: provenanceForComment(range, sourceFile, file, "summary")
1472
- });
1473
- }
1430
+ if (unified.summaryText !== "") {
1431
+ annotations.push({
1432
+ kind: "annotation",
1433
+ annotationKind: "description",
1434
+ value: unified.summaryText,
1435
+ provenance: provenanceForComment(range, sourceFile, file, "summary")
1436
+ });
1474
1437
  }
1475
- if (docComment.remarksBlock !== void 0) {
1476
- const remarksText = extractBlockText(docComment.remarksBlock).trim();
1477
- if (remarksText !== "") {
1478
- annotations.push({
1479
- kind: "annotation",
1480
- annotationKind: "remarks",
1481
- value: remarksText,
1482
- provenance: provenanceForComment(range, sourceFile, file, "remarks")
1483
- });
1484
- }
1438
+ if (unified.remarksText !== "") {
1439
+ annotations.push({
1440
+ kind: "annotation",
1441
+ annotationKind: "remarks",
1442
+ value: unified.remarksText,
1443
+ provenance: provenanceForComment(range, sourceFile, file, "remarks")
1444
+ });
1485
1445
  }
1486
1446
  }
1487
1447
  }
@@ -1501,77 +1461,27 @@ function parseTSDocTags(node, file = "", options) {
1501
1461
  provenance: placeholderProvenance
1502
1462
  });
1503
1463
  }
1504
- if (rawTextTags.length > 0) {
1505
- for (const rawTextTag of rawTextTags) {
1506
- const fallbackQueue = rawTextFallbacks.get(rawTextTag.tag.normalizedTagName);
1507
- const fallback = fallbackQueue?.shift();
1508
- const text = choosePreferredPayloadText(
1509
- getSharedPayloadText(rawTextTag.tag, rawTextTag.commentText, rawTextTag.commentOffset),
1510
- fallback?.text ?? ""
1511
- );
1512
- if (text === "") continue;
1513
- const provenance = provenanceForParsedTag(rawTextTag.tag, sourceFile, file);
1514
- if (rawTextTag.tag.normalizedTagName === "defaultValue") {
1515
- const defaultValueNode = (0, import_internal.parseDefaultValueTagValue)(text, provenance);
1516
- annotations.push(defaultValueNode);
1517
- continue;
1518
- }
1519
- const compilerDiagnostics = buildCompilerBackedConstraintDiagnostics(
1520
- node,
1521
- sourceFile,
1522
- rawTextTag.tag.normalizedTagName,
1523
- rawTextTag.tag,
1524
- provenance,
1525
- supportingDeclarations,
1526
- options
1527
- );
1528
- if (compilerDiagnostics.length > 0) {
1529
- pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
1530
- continue;
1531
- }
1532
- const constraintNode = (0, import_internal.parseConstraintTagValue)(
1533
- rawTextTag.tag.normalizedTagName,
1534
- text,
1535
- provenance,
1536
- sharedTagValueOptions(options)
1537
- );
1538
- if (constraintNode) {
1539
- constraints.push(constraintNode);
1540
- }
1541
- }
1542
- }
1543
1464
  for (const [tagName, fallbacks] of rawTextFallbacks) {
1544
1465
  for (const fallback of fallbacks) {
1545
1466
  const text = fallback.text.trim();
1546
1467
  if (text === "") continue;
1547
1468
  const provenance = fallback.provenance;
1548
1469
  if (tagName === "defaultValue") {
1549
- const defaultValueNode = (0, import_internal.parseDefaultValueTagValue)(text, provenance);
1550
- annotations.push(defaultValueNode);
1470
+ annotations.push((0, import_internal.parseDefaultValueTagValue)(text, provenance));
1551
1471
  continue;
1552
1472
  }
1553
- const compilerDiagnostics = buildCompilerBackedConstraintDiagnostics(
1554
- node,
1555
- sourceFile,
1473
+ processConstraintTag(
1556
1474
  tagName,
1475
+ text,
1557
1476
  null,
1558
1477
  provenance,
1478
+ node,
1479
+ sourceFile,
1559
1480
  supportingDeclarations,
1560
- options
1561
- );
1562
- if (compilerDiagnostics.length > 0) {
1563
- pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
1564
- continue;
1565
- }
1566
- const constraintNode = (0, import_internal.parseConstraintTagValue)(
1567
- tagName,
1568
- text,
1569
- provenance,
1570
- sharedTagValueOptions(options)
1481
+ options,
1482
+ constraints,
1483
+ diagnostics
1571
1484
  );
1572
- if (constraintNode) {
1573
- constraints.push(constraintNode);
1574
- }
1575
1485
  }
1576
1486
  }
1577
1487
  const result = { constraints, annotations, diagnostics };
@@ -1589,8 +1499,8 @@ function extractDisplayNameMetadata(node) {
1589
1499
  if (range.kind !== ts.SyntaxKind.MultiLineCommentTrivia) continue;
1590
1500
  const commentText = sourceText.substring(range.pos, range.end);
1591
1501
  if (!commentText.startsWith("/**")) continue;
1592
- const parsed = (0, import_internal.parseCommentBlock)(commentText);
1593
- for (const tag of parsed.tags) {
1502
+ const unified = (0, import_internal.parseUnifiedComment)(commentText);
1503
+ for (const tag of unified.tags) {
1594
1504
  if (tag.normalizedTagName !== "displayName") {
1595
1505
  continue;
1596
1506
  }
@@ -1609,56 +1519,11 @@ function extractDisplayNameMetadata(node) {
1609
1519
  memberDisplayNames
1610
1520
  };
1611
1521
  }
1612
- function extractBlockText(block) {
1613
- return extractPlainText(block.content);
1614
- }
1615
- function extractPlainText(node) {
1616
- let result = "";
1617
- if (node instanceof import_tsdoc.DocExcerpt) {
1618
- return node.content.toString();
1619
- }
1620
- if (node instanceof import_tsdoc.DocPlainText) {
1621
- return node.text;
1622
- }
1623
- if (node instanceof import_tsdoc.DocSoftBreak) {
1624
- return " ";
1625
- }
1626
- if (typeof node.getChildNodes === "function") {
1627
- for (const child of node.getChildNodes()) {
1628
- result += extractPlainText(child);
1629
- }
1630
- }
1631
- return result;
1632
- }
1633
- function choosePreferredPayloadText(primary, fallback) {
1634
- const preferred = primary.trim();
1635
- const alternate = fallback.trim();
1636
- if (preferred === "") return alternate;
1637
- if (alternate === "") return preferred;
1638
- if (alternate.includes("\n")) return alternate;
1639
- if (alternate.length > preferred.length && alternate.startsWith(preferred)) {
1640
- return alternate;
1641
- }
1642
- return preferred;
1643
- }
1644
- function getSharedPayloadText(tag, commentText, commentOffset) {
1645
- if (tag.payloadSpan === null) {
1646
- return "";
1647
- }
1648
- return (0, import_internal.sliceCommentSpan)(commentText, tag.payloadSpan, {
1649
- offset: commentOffset
1650
- }).trim();
1651
- }
1652
- function getBestBlockPayloadText(tag, commentText, commentOffset, block) {
1653
- const sharedText = tag === null ? "" : getSharedPayloadText(tag, commentText, commentOffset);
1654
- const blockText = extractBlockText(block).replace(/\s+/g, " ").trim();
1655
- return choosePreferredPayloadText(sharedText, blockText);
1656
- }
1657
1522
  function collectRawTextFallbacks(node, file) {
1658
1523
  const fallbacks = /* @__PURE__ */ new Map();
1659
1524
  for (const tag of ts.getJSDocTags(node)) {
1660
1525
  const tagName = (0, import_internals3.normalizeConstraintTagName)(tag.tagName.text);
1661
- if (!TAGS_REQUIRING_RAW_TEXT.has(tagName)) continue;
1526
+ if (!import_internal.TAGS_REQUIRING_RAW_TEXT.has(tagName)) continue;
1662
1527
  const commentText = getTagCommentText(tag)?.trim() ?? "";
1663
1528
  if (commentText === "") continue;
1664
1529
  const entries = fallbacks.get(tagName) ?? [];
@@ -1767,6 +1632,31 @@ function isObjectType(type) {
1767
1632
  function isIntersectionType(type) {
1768
1633
  return !!(type.flags & ts3.TypeFlags.Intersection);
1769
1634
  }
1635
+ function isIntegerBrandedType(type) {
1636
+ if (!type.isIntersection()) {
1637
+ return false;
1638
+ }
1639
+ const hasNumberBase = type.types.some(
1640
+ (member) => !!(member.flags & ts3.TypeFlags.Number)
1641
+ );
1642
+ if (!hasNumberBase) {
1643
+ return false;
1644
+ }
1645
+ return type.getProperties().some((prop) => {
1646
+ const declaration = prop.valueDeclaration ?? prop.declarations?.[0];
1647
+ if (declaration === void 0) {
1648
+ return false;
1649
+ }
1650
+ if (!ts3.isPropertySignature(declaration) && !ts3.isPropertyDeclaration(declaration)) {
1651
+ return false;
1652
+ }
1653
+ const name = declaration.name;
1654
+ if (!ts3.isComputedPropertyName(name)) {
1655
+ return false;
1656
+ }
1657
+ return ts3.isIdentifier(name.expression) && name.expression.text === "__integerBrand";
1658
+ });
1659
+ }
1770
1660
  function isResolvableObjectLikeAliasTypeNode(typeNode) {
1771
1661
  if (ts3.isParenthesizedTypeNode(typeNode)) {
1772
1662
  return isResolvableObjectLikeAliasTypeNode(typeNode.type);
@@ -2892,6 +2782,9 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
2892
2782
  if (primitiveAlias) {
2893
2783
  return primitiveAlias;
2894
2784
  }
2785
+ if (isIntegerBrandedType(type)) {
2786
+ return { kind: "primitive", primitiveKind: "integer" };
2787
+ }
2895
2788
  if (type.flags & ts3.TypeFlags.String) {
2896
2789
  return { kind: "primitive", primitiveKind: "string" };
2897
2790
  }
@@ -2994,7 +2887,7 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
2994
2887
  return { kind: "primitive", primitiveKind: "string" };
2995
2888
  }
2996
2889
  function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
2997
- if (!(type.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null))) {
2890
+ if (!(type.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null)) && !isIntegerBrandedType(type)) {
2998
2891
  return null;
2999
2892
  }
3000
2893
  const aliasDecl = type.aliasSymbol?.declarations?.find(ts3.isTypeAliasDeclaration) ?? getReferencedTypeAliasDeclaration(sourceNode, checker);
@@ -3080,6 +2973,9 @@ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiti
3080
2973
  visitedAliases
3081
2974
  );
3082
2975
  }
2976
+ if (isIntegerBrandedType(type)) {
2977
+ return { kind: "primitive", primitiveKind: "integer" };
2978
+ }
3083
2979
  if (type.flags & ts3.TypeFlags.String) {
3084
2980
  return { kind: "primitive", primitiveKind: "string" };
3085
2981
  }
@@ -3303,7 +3199,7 @@ function typeNodeContainsReference(type, targetName) {
3303
3199
  }
3304
3200
  }
3305
3201
  function shouldEmitResolvedObjectProperty(property, declaration) {
3306
- if (property.name.startsWith("__@")) {
3202
+ if (property.name.startsWith("__")) {
3307
3203
  return false;
3308
3204
  }
3309
3205
  if (declaration !== void 0 && "name" in declaration && declaration.name !== void 0) {
@@ -4859,7 +4755,7 @@ function generateCustomType(type, ctx) {
4859
4755
  }
4860
4756
  return registration.toJsonSchema(type.payload, ctx.vendorPrefix);
4861
4757
  }
4862
- var JSON_SCHEMA_STRUCTURAL_KEYWORDS = /* @__PURE__ */ new Set([
4758
+ var VOCABULARY_MODE_BLOCKED_KEYWORDS = /* @__PURE__ */ new Set([
4863
4759
  "$schema",
4864
4760
  "$ref",
4865
4761
  "$defs",
@@ -4930,7 +4826,7 @@ function applyCustomConstraint(schema, constraint, ctx) {
4930
4826
  if (registration.emitsVocabularyKeywords) {
4931
4827
  const target = schema;
4932
4828
  for (const [key, value] of Object.entries(extensionSchema)) {
4933
- if (JSON_SCHEMA_STRUCTURAL_KEYWORDS.has(key)) {
4829
+ if (VOCABULARY_MODE_BLOCKED_KEYWORDS.has(key)) {
4934
4830
  throw new Error(
4935
4831
  `Custom constraint "${constraint.constraintId}" with emitsVocabularyKeywords must not overwrite standard JSON Schema keyword "${key}"`
4936
4832
  );
@@ -4974,6 +4870,144 @@ function assignVendorPrefixedExtensionKeywords(schema, extensionSchema, vendorPr
4974
4870
  }
4975
4871
  }
4976
4872
 
4873
+ // src/extensions/registry.ts
4874
+ var import_internals5 = require("@formspec/core/internals");
4875
+ var import_internal3 = require("@formspec/analysis/internal");
4876
+ var BUILTIN_METADATA_TAGS = /* @__PURE__ */ new Set(["apiName", "displayName"]);
4877
+ function buildConstraintTagSources(extensions) {
4878
+ return extensions.map((extension) => ({
4879
+ extensionId: extension.extensionId,
4880
+ ...extension.constraintTags !== void 0 ? {
4881
+ constraintTags: extension.constraintTags.map((tag) => ({
4882
+ tagName: (0, import_internal3.normalizeFormSpecTagName)(tag.tagName)
4883
+ }))
4884
+ } : {}
4885
+ }));
4886
+ }
4887
+ function createExtensionRegistry(extensions) {
4888
+ const reservedTagSources = buildConstraintTagSources(extensions);
4889
+ const typeMap = /* @__PURE__ */ new Map();
4890
+ const typeNameMap = /* @__PURE__ */ new Map();
4891
+ const constraintMap = /* @__PURE__ */ new Map();
4892
+ const constraintTagMap = /* @__PURE__ */ new Map();
4893
+ const builtinBroadeningMap = /* @__PURE__ */ new Map();
4894
+ const annotationMap = /* @__PURE__ */ new Map();
4895
+ const metadataSlotMap = /* @__PURE__ */ new Map();
4896
+ const metadataTagMap = /* @__PURE__ */ new Map();
4897
+ for (const ext of extensions) {
4898
+ if (ext.types !== void 0) {
4899
+ for (const type of ext.types) {
4900
+ const qualifiedId = `${ext.extensionId}/${type.typeName}`;
4901
+ if (typeMap.has(qualifiedId)) {
4902
+ throw new Error(`Duplicate custom type ID: "${qualifiedId}"`);
4903
+ }
4904
+ typeMap.set(qualifiedId, type);
4905
+ for (const sourceTypeName of type.tsTypeNames ?? [type.typeName]) {
4906
+ if (typeNameMap.has(sourceTypeName)) {
4907
+ throw new Error(`Duplicate custom type source name: "${sourceTypeName}"`);
4908
+ }
4909
+ typeNameMap.set(sourceTypeName, {
4910
+ extensionId: ext.extensionId,
4911
+ registration: type
4912
+ });
4913
+ }
4914
+ if (type.builtinConstraintBroadenings !== void 0) {
4915
+ for (const broadening of type.builtinConstraintBroadenings) {
4916
+ const key = `${qualifiedId}:${broadening.tagName}`;
4917
+ if (builtinBroadeningMap.has(key)) {
4918
+ throw new Error(`Duplicate built-in constraint broadening: "${key}"`);
4919
+ }
4920
+ builtinBroadeningMap.set(key, {
4921
+ extensionId: ext.extensionId,
4922
+ registration: broadening
4923
+ });
4924
+ }
4925
+ }
4926
+ }
4927
+ }
4928
+ if (ext.constraints !== void 0) {
4929
+ for (const constraint of ext.constraints) {
4930
+ const qualifiedId = `${ext.extensionId}/${constraint.constraintName}`;
4931
+ if (constraintMap.has(qualifiedId)) {
4932
+ throw new Error(`Duplicate custom constraint ID: "${qualifiedId}"`);
4933
+ }
4934
+ constraintMap.set(qualifiedId, constraint);
4935
+ }
4936
+ }
4937
+ if (ext.constraintTags !== void 0) {
4938
+ for (const tag of ext.constraintTags) {
4939
+ const canonicalTagName = (0, import_internal3.normalizeFormSpecTagName)(tag.tagName);
4940
+ if (constraintTagMap.has(canonicalTagName)) {
4941
+ throw new Error(`Duplicate custom constraint tag: "@${canonicalTagName}"`);
4942
+ }
4943
+ constraintTagMap.set(canonicalTagName, {
4944
+ extensionId: ext.extensionId,
4945
+ registration: tag
4946
+ });
4947
+ }
4948
+ }
4949
+ if (ext.annotations !== void 0) {
4950
+ for (const annotation of ext.annotations) {
4951
+ const qualifiedId = `${ext.extensionId}/${annotation.annotationName}`;
4952
+ if (annotationMap.has(qualifiedId)) {
4953
+ throw new Error(`Duplicate custom annotation ID: "${qualifiedId}"`);
4954
+ }
4955
+ annotationMap.set(qualifiedId, annotation);
4956
+ }
4957
+ }
4958
+ if (ext.metadataSlots !== void 0) {
4959
+ for (const slot of ext.metadataSlots) {
4960
+ if (metadataSlotMap.has(slot.slotId)) {
4961
+ throw new Error(`Duplicate metadata slot ID: "${slot.slotId}"`);
4962
+ }
4963
+ metadataSlotMap.set(slot.slotId, true);
4964
+ const canonicalTagName = (0, import_internal3.normalizeFormSpecTagName)(slot.tagName);
4965
+ if (slot.allowBare === false && (slot.qualifiers?.length ?? 0) === 0) {
4966
+ throw new Error(
4967
+ `Metadata tag "@${canonicalTagName}" must allow bare usage or declare at least one qualifier.`
4968
+ );
4969
+ }
4970
+ if (metadataTagMap.has(canonicalTagName)) {
4971
+ throw new Error(`Duplicate metadata tag: "@${canonicalTagName}"`);
4972
+ }
4973
+ if (BUILTIN_METADATA_TAGS.has(canonicalTagName)) {
4974
+ throw new Error(
4975
+ `Metadata tag "@${canonicalTagName}" conflicts with built-in metadata tags.`
4976
+ );
4977
+ }
4978
+ if (constraintTagMap.has(canonicalTagName)) {
4979
+ throw new Error(
4980
+ `Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${canonicalTagName}".`
4981
+ );
4982
+ }
4983
+ if (Object.hasOwn(import_internals5.BUILTIN_CONSTRAINT_DEFINITIONS, (0, import_internals5.normalizeConstraintTagName)(canonicalTagName))) {
4984
+ throw new Error(
4985
+ `Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${(0, import_internals5.normalizeConstraintTagName)(canonicalTagName)}".`
4986
+ );
4987
+ }
4988
+ const existingTag = (0, import_internal3.getTagDefinition)(canonicalTagName, reservedTagSources);
4989
+ if (existingTag !== null) {
4990
+ throw BUILTIN_METADATA_TAGS.has(existingTag.canonicalName) ? new Error(
4991
+ `Metadata tag "@${canonicalTagName}" conflicts with built-in metadata tags.`
4992
+ ) : new Error(
4993
+ `Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${existingTag.canonicalName}".`
4994
+ );
4995
+ }
4996
+ metadataTagMap.set(canonicalTagName, true);
4997
+ }
4998
+ }
4999
+ }
5000
+ return {
5001
+ extensions,
5002
+ findType: (typeId) => typeMap.get(typeId),
5003
+ findTypeByName: (typeName) => typeNameMap.get(typeName),
5004
+ findConstraint: (constraintId) => constraintMap.get(constraintId),
5005
+ findConstraintTag: (tagName) => constraintTagMap.get((0, import_internal3.normalizeFormSpecTagName)(tagName)),
5006
+ findBuiltinConstraintBroadening: (typeId, tagName) => builtinBroadeningMap.get(`${typeId}:${tagName}`),
5007
+ findAnnotation: (annotationId) => annotationMap.get(annotationId)
5008
+ };
5009
+ }
5010
+
4977
5011
  // src/ui-schema/schema.ts
4978
5012
  var import_zod = require("zod");
4979
5013
  var jsonPointerSchema = import_zod.z.string();
@@ -5229,9 +5263,9 @@ function collectFieldNameMap(elements) {
5229
5263
  }
5230
5264
 
5231
5265
  // src/validate/constraint-validator.ts
5232
- var import_internal3 = require("@formspec/analysis/internal");
5266
+ var import_internal4 = require("@formspec/analysis/internal");
5233
5267
  function validateFieldNode(ctx, field) {
5234
- const analysis = (0, import_internal3.analyzeConstraintTargets)(
5268
+ const analysis = (0, import_internal4.analyzeConstraintTargets)(
5235
5269
  field.name,
5236
5270
  field.type,
5237
5271
  field.constraints,
@@ -5249,7 +5283,7 @@ function validateFieldNode(ctx, field) {
5249
5283
  }
5250
5284
  function validateObjectProperty(ctx, parentName, property) {
5251
5285
  const qualifiedName = `${parentName}.${property.name}`;
5252
- const analysis = (0, import_internal3.analyzeConstraintTargets)(
5286
+ const analysis = (0, import_internal4.analyzeConstraintTargets)(
5253
5287
  qualifiedName,
5254
5288
  property.type,
5255
5289
  property.constraints,
@@ -5360,144 +5394,6 @@ function formatLocation(location) {
5360
5394
  return `${location.file}:${String(location.line)}:${String(location.column)}`;
5361
5395
  }
5362
5396
 
5363
- // src/extensions/registry.ts
5364
- var import_internals5 = require("@formspec/core/internals");
5365
- var import_internal4 = require("@formspec/analysis/internal");
5366
- var BUILTIN_METADATA_TAGS = /* @__PURE__ */ new Set(["apiName", "displayName"]);
5367
- function buildConstraintTagSources(extensions) {
5368
- return extensions.map((extension) => ({
5369
- extensionId: extension.extensionId,
5370
- ...extension.constraintTags !== void 0 ? {
5371
- constraintTags: extension.constraintTags.map((tag) => ({
5372
- tagName: (0, import_internal4.normalizeFormSpecTagName)(tag.tagName)
5373
- }))
5374
- } : {}
5375
- }));
5376
- }
5377
- function createExtensionRegistry(extensions) {
5378
- const reservedTagSources = buildConstraintTagSources(extensions);
5379
- const typeMap = /* @__PURE__ */ new Map();
5380
- const typeNameMap = /* @__PURE__ */ new Map();
5381
- const constraintMap = /* @__PURE__ */ new Map();
5382
- const constraintTagMap = /* @__PURE__ */ new Map();
5383
- const builtinBroadeningMap = /* @__PURE__ */ new Map();
5384
- const annotationMap = /* @__PURE__ */ new Map();
5385
- const metadataSlotMap = /* @__PURE__ */ new Map();
5386
- const metadataTagMap = /* @__PURE__ */ new Map();
5387
- for (const ext of extensions) {
5388
- if (ext.types !== void 0) {
5389
- for (const type of ext.types) {
5390
- const qualifiedId = `${ext.extensionId}/${type.typeName}`;
5391
- if (typeMap.has(qualifiedId)) {
5392
- throw new Error(`Duplicate custom type ID: "${qualifiedId}"`);
5393
- }
5394
- typeMap.set(qualifiedId, type);
5395
- for (const sourceTypeName of type.tsTypeNames ?? [type.typeName]) {
5396
- if (typeNameMap.has(sourceTypeName)) {
5397
- throw new Error(`Duplicate custom type source name: "${sourceTypeName}"`);
5398
- }
5399
- typeNameMap.set(sourceTypeName, {
5400
- extensionId: ext.extensionId,
5401
- registration: type
5402
- });
5403
- }
5404
- if (type.builtinConstraintBroadenings !== void 0) {
5405
- for (const broadening of type.builtinConstraintBroadenings) {
5406
- const key = `${qualifiedId}:${broadening.tagName}`;
5407
- if (builtinBroadeningMap.has(key)) {
5408
- throw new Error(`Duplicate built-in constraint broadening: "${key}"`);
5409
- }
5410
- builtinBroadeningMap.set(key, {
5411
- extensionId: ext.extensionId,
5412
- registration: broadening
5413
- });
5414
- }
5415
- }
5416
- }
5417
- }
5418
- if (ext.constraints !== void 0) {
5419
- for (const constraint of ext.constraints) {
5420
- const qualifiedId = `${ext.extensionId}/${constraint.constraintName}`;
5421
- if (constraintMap.has(qualifiedId)) {
5422
- throw new Error(`Duplicate custom constraint ID: "${qualifiedId}"`);
5423
- }
5424
- constraintMap.set(qualifiedId, constraint);
5425
- }
5426
- }
5427
- if (ext.constraintTags !== void 0) {
5428
- for (const tag of ext.constraintTags) {
5429
- const canonicalTagName = (0, import_internal4.normalizeFormSpecTagName)(tag.tagName);
5430
- if (constraintTagMap.has(canonicalTagName)) {
5431
- throw new Error(`Duplicate custom constraint tag: "@${canonicalTagName}"`);
5432
- }
5433
- constraintTagMap.set(canonicalTagName, {
5434
- extensionId: ext.extensionId,
5435
- registration: tag
5436
- });
5437
- }
5438
- }
5439
- if (ext.annotations !== void 0) {
5440
- for (const annotation of ext.annotations) {
5441
- const qualifiedId = `${ext.extensionId}/${annotation.annotationName}`;
5442
- if (annotationMap.has(qualifiedId)) {
5443
- throw new Error(`Duplicate custom annotation ID: "${qualifiedId}"`);
5444
- }
5445
- annotationMap.set(qualifiedId, annotation);
5446
- }
5447
- }
5448
- if (ext.metadataSlots !== void 0) {
5449
- for (const slot of ext.metadataSlots) {
5450
- if (metadataSlotMap.has(slot.slotId)) {
5451
- throw new Error(`Duplicate metadata slot ID: "${slot.slotId}"`);
5452
- }
5453
- metadataSlotMap.set(slot.slotId, true);
5454
- const canonicalTagName = (0, import_internal4.normalizeFormSpecTagName)(slot.tagName);
5455
- if (slot.allowBare === false && (slot.qualifiers?.length ?? 0) === 0) {
5456
- throw new Error(
5457
- `Metadata tag "@${canonicalTagName}" must allow bare usage or declare at least one qualifier.`
5458
- );
5459
- }
5460
- if (metadataTagMap.has(canonicalTagName)) {
5461
- throw new Error(`Duplicate metadata tag: "@${canonicalTagName}"`);
5462
- }
5463
- if (BUILTIN_METADATA_TAGS.has(canonicalTagName)) {
5464
- throw new Error(
5465
- `Metadata tag "@${canonicalTagName}" conflicts with built-in metadata tags.`
5466
- );
5467
- }
5468
- if (constraintTagMap.has(canonicalTagName)) {
5469
- throw new Error(
5470
- `Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${canonicalTagName}".`
5471
- );
5472
- }
5473
- if (Object.hasOwn(import_internals5.BUILTIN_CONSTRAINT_DEFINITIONS, (0, import_internals5.normalizeConstraintTagName)(canonicalTagName))) {
5474
- throw new Error(
5475
- `Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${(0, import_internals5.normalizeConstraintTagName)(canonicalTagName)}".`
5476
- );
5477
- }
5478
- const existingTag = (0, import_internal4.getTagDefinition)(canonicalTagName, reservedTagSources);
5479
- if (existingTag !== null) {
5480
- throw BUILTIN_METADATA_TAGS.has(existingTag.canonicalName) ? new Error(
5481
- `Metadata tag "@${canonicalTagName}" conflicts with built-in metadata tags.`
5482
- ) : new Error(
5483
- `Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${existingTag.canonicalName}".`
5484
- );
5485
- }
5486
- metadataTagMap.set(canonicalTagName, true);
5487
- }
5488
- }
5489
- }
5490
- return {
5491
- extensions,
5492
- findType: (typeId) => typeMap.get(typeId),
5493
- findTypeByName: (typeName) => typeNameMap.get(typeName),
5494
- findConstraint: (constraintId) => constraintMap.get(constraintId),
5495
- findConstraintTag: (tagName) => constraintTagMap.get((0, import_internal4.normalizeFormSpecTagName)(tagName)),
5496
- findBuiltinConstraintBroadening: (typeId, tagName) => builtinBroadeningMap.get(`${typeId}:${tagName}`),
5497
- findAnnotation: (annotationId) => annotationMap.get(annotationId)
5498
- };
5499
- }
5500
-
5501
5397
  // src/generators/method-schema.ts
5502
5398
  var import_internals6 = require("@formspec/core/internals");
5503
5399
  function typeToJsonSchema(type, checker, options) {