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

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) ?? [];
@@ -3303,7 +3168,7 @@ function typeNodeContainsReference(type, targetName) {
3303
3168
  }
3304
3169
  }
3305
3170
  function shouldEmitResolvedObjectProperty(property, declaration) {
3306
- if (property.name.startsWith("__@")) {
3171
+ if (property.name.startsWith("__")) {
3307
3172
  return false;
3308
3173
  }
3309
3174
  if (declaration !== void 0 && "name" in declaration && declaration.name !== void 0) {
@@ -4974,6 +4839,144 @@ function assignVendorPrefixedExtensionKeywords(schema, extensionSchema, vendorPr
4974
4839
  }
4975
4840
  }
4976
4841
 
4842
+ // src/extensions/registry.ts
4843
+ var import_internals5 = require("@formspec/core/internals");
4844
+ var import_internal3 = require("@formspec/analysis/internal");
4845
+ var BUILTIN_METADATA_TAGS = /* @__PURE__ */ new Set(["apiName", "displayName"]);
4846
+ function buildConstraintTagSources(extensions) {
4847
+ return extensions.map((extension) => ({
4848
+ extensionId: extension.extensionId,
4849
+ ...extension.constraintTags !== void 0 ? {
4850
+ constraintTags: extension.constraintTags.map((tag) => ({
4851
+ tagName: (0, import_internal3.normalizeFormSpecTagName)(tag.tagName)
4852
+ }))
4853
+ } : {}
4854
+ }));
4855
+ }
4856
+ function createExtensionRegistry(extensions) {
4857
+ const reservedTagSources = buildConstraintTagSources(extensions);
4858
+ const typeMap = /* @__PURE__ */ new Map();
4859
+ const typeNameMap = /* @__PURE__ */ new Map();
4860
+ const constraintMap = /* @__PURE__ */ new Map();
4861
+ const constraintTagMap = /* @__PURE__ */ new Map();
4862
+ const builtinBroadeningMap = /* @__PURE__ */ new Map();
4863
+ const annotationMap = /* @__PURE__ */ new Map();
4864
+ const metadataSlotMap = /* @__PURE__ */ new Map();
4865
+ const metadataTagMap = /* @__PURE__ */ new Map();
4866
+ for (const ext of extensions) {
4867
+ if (ext.types !== void 0) {
4868
+ for (const type of ext.types) {
4869
+ const qualifiedId = `${ext.extensionId}/${type.typeName}`;
4870
+ if (typeMap.has(qualifiedId)) {
4871
+ throw new Error(`Duplicate custom type ID: "${qualifiedId}"`);
4872
+ }
4873
+ typeMap.set(qualifiedId, type);
4874
+ for (const sourceTypeName of type.tsTypeNames ?? [type.typeName]) {
4875
+ if (typeNameMap.has(sourceTypeName)) {
4876
+ throw new Error(`Duplicate custom type source name: "${sourceTypeName}"`);
4877
+ }
4878
+ typeNameMap.set(sourceTypeName, {
4879
+ extensionId: ext.extensionId,
4880
+ registration: type
4881
+ });
4882
+ }
4883
+ if (type.builtinConstraintBroadenings !== void 0) {
4884
+ for (const broadening of type.builtinConstraintBroadenings) {
4885
+ const key = `${qualifiedId}:${broadening.tagName}`;
4886
+ if (builtinBroadeningMap.has(key)) {
4887
+ throw new Error(`Duplicate built-in constraint broadening: "${key}"`);
4888
+ }
4889
+ builtinBroadeningMap.set(key, {
4890
+ extensionId: ext.extensionId,
4891
+ registration: broadening
4892
+ });
4893
+ }
4894
+ }
4895
+ }
4896
+ }
4897
+ if (ext.constraints !== void 0) {
4898
+ for (const constraint of ext.constraints) {
4899
+ const qualifiedId = `${ext.extensionId}/${constraint.constraintName}`;
4900
+ if (constraintMap.has(qualifiedId)) {
4901
+ throw new Error(`Duplicate custom constraint ID: "${qualifiedId}"`);
4902
+ }
4903
+ constraintMap.set(qualifiedId, constraint);
4904
+ }
4905
+ }
4906
+ if (ext.constraintTags !== void 0) {
4907
+ for (const tag of ext.constraintTags) {
4908
+ const canonicalTagName = (0, import_internal3.normalizeFormSpecTagName)(tag.tagName);
4909
+ if (constraintTagMap.has(canonicalTagName)) {
4910
+ throw new Error(`Duplicate custom constraint tag: "@${canonicalTagName}"`);
4911
+ }
4912
+ constraintTagMap.set(canonicalTagName, {
4913
+ extensionId: ext.extensionId,
4914
+ registration: tag
4915
+ });
4916
+ }
4917
+ }
4918
+ if (ext.annotations !== void 0) {
4919
+ for (const annotation of ext.annotations) {
4920
+ const qualifiedId = `${ext.extensionId}/${annotation.annotationName}`;
4921
+ if (annotationMap.has(qualifiedId)) {
4922
+ throw new Error(`Duplicate custom annotation ID: "${qualifiedId}"`);
4923
+ }
4924
+ annotationMap.set(qualifiedId, annotation);
4925
+ }
4926
+ }
4927
+ if (ext.metadataSlots !== void 0) {
4928
+ for (const slot of ext.metadataSlots) {
4929
+ if (metadataSlotMap.has(slot.slotId)) {
4930
+ throw new Error(`Duplicate metadata slot ID: "${slot.slotId}"`);
4931
+ }
4932
+ metadataSlotMap.set(slot.slotId, true);
4933
+ const canonicalTagName = (0, import_internal3.normalizeFormSpecTagName)(slot.tagName);
4934
+ if (slot.allowBare === false && (slot.qualifiers?.length ?? 0) === 0) {
4935
+ throw new Error(
4936
+ `Metadata tag "@${canonicalTagName}" must allow bare usage or declare at least one qualifier.`
4937
+ );
4938
+ }
4939
+ if (metadataTagMap.has(canonicalTagName)) {
4940
+ throw new Error(`Duplicate metadata tag: "@${canonicalTagName}"`);
4941
+ }
4942
+ if (BUILTIN_METADATA_TAGS.has(canonicalTagName)) {
4943
+ throw new Error(
4944
+ `Metadata tag "@${canonicalTagName}" conflicts with built-in metadata tags.`
4945
+ );
4946
+ }
4947
+ if (constraintTagMap.has(canonicalTagName)) {
4948
+ throw new Error(
4949
+ `Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${canonicalTagName}".`
4950
+ );
4951
+ }
4952
+ if (Object.hasOwn(import_internals5.BUILTIN_CONSTRAINT_DEFINITIONS, (0, import_internals5.normalizeConstraintTagName)(canonicalTagName))) {
4953
+ throw new Error(
4954
+ `Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${(0, import_internals5.normalizeConstraintTagName)(canonicalTagName)}".`
4955
+ );
4956
+ }
4957
+ const existingTag = (0, import_internal3.getTagDefinition)(canonicalTagName, reservedTagSources);
4958
+ if (existingTag !== null) {
4959
+ throw BUILTIN_METADATA_TAGS.has(existingTag.canonicalName) ? new Error(
4960
+ `Metadata tag "@${canonicalTagName}" conflicts with built-in metadata tags.`
4961
+ ) : new Error(
4962
+ `Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${existingTag.canonicalName}".`
4963
+ );
4964
+ }
4965
+ metadataTagMap.set(canonicalTagName, true);
4966
+ }
4967
+ }
4968
+ }
4969
+ return {
4970
+ extensions,
4971
+ findType: (typeId) => typeMap.get(typeId),
4972
+ findTypeByName: (typeName) => typeNameMap.get(typeName),
4973
+ findConstraint: (constraintId) => constraintMap.get(constraintId),
4974
+ findConstraintTag: (tagName) => constraintTagMap.get((0, import_internal3.normalizeFormSpecTagName)(tagName)),
4975
+ findBuiltinConstraintBroadening: (typeId, tagName) => builtinBroadeningMap.get(`${typeId}:${tagName}`),
4976
+ findAnnotation: (annotationId) => annotationMap.get(annotationId)
4977
+ };
4978
+ }
4979
+
4977
4980
  // src/ui-schema/schema.ts
4978
4981
  var import_zod = require("zod");
4979
4982
  var jsonPointerSchema = import_zod.z.string();
@@ -5229,9 +5232,9 @@ function collectFieldNameMap(elements) {
5229
5232
  }
5230
5233
 
5231
5234
  // src/validate/constraint-validator.ts
5232
- var import_internal3 = require("@formspec/analysis/internal");
5235
+ var import_internal4 = require("@formspec/analysis/internal");
5233
5236
  function validateFieldNode(ctx, field) {
5234
- const analysis = (0, import_internal3.analyzeConstraintTargets)(
5237
+ const analysis = (0, import_internal4.analyzeConstraintTargets)(
5235
5238
  field.name,
5236
5239
  field.type,
5237
5240
  field.constraints,
@@ -5249,7 +5252,7 @@ function validateFieldNode(ctx, field) {
5249
5252
  }
5250
5253
  function validateObjectProperty(ctx, parentName, property) {
5251
5254
  const qualifiedName = `${parentName}.${property.name}`;
5252
- const analysis = (0, import_internal3.analyzeConstraintTargets)(
5255
+ const analysis = (0, import_internal4.analyzeConstraintTargets)(
5253
5256
  qualifiedName,
5254
5257
  property.type,
5255
5258
  property.constraints,
@@ -5360,144 +5363,6 @@ function formatLocation(location) {
5360
5363
  return `${location.file}:${String(location.line)}:${String(location.column)}`;
5361
5364
  }
5362
5365
 
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
5366
  // src/generators/method-schema.ts
5502
5367
  var import_internals6 = require("@formspec/core/internals");
5503
5368
  function typeToJsonSchema(type, checker, options) {