@formspec/build 0.1.0-alpha.54 → 0.1.0-alpha.55

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.
@@ -852,7 +852,7 @@ var path = __toESM(require("path"), 1);
852
852
 
853
853
  // src/analyzer/class-analyzer.ts
854
854
  var ts6 = __toESM(require("typescript"), 1);
855
- var import_internal3 = require("@formspec/analysis/internal");
855
+ var import_internal4 = require("@formspec/analysis/internal");
856
856
 
857
857
  // src/analyzer/jsdoc-constraints.ts
858
858
  var ts5 = __toESM(require("typescript"), 1);
@@ -862,6 +862,7 @@ var ts4 = __toESM(require("typescript"), 1);
862
862
  var import_internal2 = require("@formspec/analysis/internal");
863
863
  var import_internals3 = require("@formspec/core/internals");
864
864
  var import_internals4 = require("@formspec/core/internals");
865
+ var import_core = require("@formspec/core");
865
866
 
866
867
  // src/extensions/resolve-custom-type.ts
867
868
  var ts2 = __toESM(require("typescript"), 1);
@@ -989,6 +990,7 @@ function isIntegerBrandedType(type) {
989
990
  }
990
991
 
991
992
  // src/analyzer/tsdoc-parser.ts
993
+ var import_internal3 = require("@formspec/analysis/internal");
992
994
  function sharedTagValueOptions(options) {
993
995
  return {
994
996
  ...options?.extensionRegistry !== void 0 ? { registry: options.extensionRegistry } : {},
@@ -1395,56 +1397,82 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
1395
1397
  if (definition === null) {
1396
1398
  return [];
1397
1399
  }
1400
+ const nonNullPlacement = placement;
1401
+ const log = (0, import_internal3.getBuildLogger)();
1402
+ const broadeningLog = (0, import_internal3.getBroadeningLogger)();
1403
+ const syntheticLog = (0, import_internal3.getSyntheticLogger)();
1404
+ const logsEnabled = log !== import_core.noopLogger || broadeningLog !== import_core.noopLogger;
1405
+ const syntheticTraceEnabled = syntheticLog !== import_core.noopLogger;
1406
+ const logStart = logsEnabled ? (0, import_internal3.nowMicros)() : 0;
1407
+ const subjectTypeKind = logsEnabled ? (0, import_internal3.describeTypeKind)(subjectType, checker) : "";
1408
+ function emit(outcome, result2) {
1409
+ if (!logsEnabled) {
1410
+ return result2;
1411
+ }
1412
+ const entry = {
1413
+ consumer: "build",
1414
+ tag: tagName,
1415
+ placement: nonNullPlacement,
1416
+ subjectTypeKind,
1417
+ roleOutcome: outcome,
1418
+ elapsedMicros: (0, import_internal3.elapsedMicros)(logStart)
1419
+ };
1420
+ (0, import_internal3.logTagApplication)(log, entry);
1421
+ if (outcome === "bypass" || outcome === "D1" || outcome === "D2") {
1422
+ (0, import_internal3.logTagApplication)(broadeningLog, entry);
1423
+ }
1424
+ return result2;
1425
+ }
1398
1426
  if (!definition.placements.includes(placement)) {
1399
- return [
1427
+ return emit("A-reject", [
1400
1428
  makeDiagnostic(
1401
1429
  "INVALID_TAG_PLACEMENT",
1402
1430
  `Tag "@${tagName}" is not allowed on ${placementLabel(placement)}.`,
1403
1431
  provenance
1404
1432
  )
1405
- ];
1433
+ ]);
1406
1434
  }
1407
1435
  const target = parsedTag?.target ?? null;
1408
1436
  let evaluatedType = subjectType;
1409
1437
  let targetLabel = node.getText(sourceFile);
1410
1438
  if (target !== null) {
1411
1439
  if (target.kind !== "path") {
1412
- return [
1440
+ return emit("B-reject", [
1413
1441
  makeDiagnostic(
1414
1442
  "UNSUPPORTED_TARGETING_SYNTAX",
1415
1443
  `Tag "@${tagName}" does not support ${target.kind} targeting syntax.`,
1416
1444
  provenance
1417
1445
  )
1418
- ];
1446
+ ]);
1419
1447
  }
1420
1448
  if (!target.valid || target.path === null) {
1421
- return [
1449
+ return emit("B-reject", [
1422
1450
  makeDiagnostic(
1423
1451
  "UNSUPPORTED_TARGETING_SYNTAX",
1424
1452
  `Tag "@${tagName}" has invalid path targeting syntax.`,
1425
1453
  provenance
1426
1454
  )
1427
- ];
1455
+ ]);
1428
1456
  }
1429
1457
  const resolution = (0, import_internal2.resolvePathTargetType)(subjectType, checker, target.path.segments);
1430
1458
  if (resolution.kind === "missing-property") {
1431
- return [
1459
+ return emit("B-reject", [
1432
1460
  makeDiagnostic(
1433
1461
  "UNKNOWN_PATH_TARGET",
1434
1462
  `Target "${target.rawText}": path-targeted constraint "${tagName}" references unknown path segment "${resolution.segment}"`,
1435
1463
  provenance
1436
1464
  )
1437
- ];
1465
+ ]);
1438
1466
  }
1439
1467
  if (resolution.kind === "unresolvable") {
1440
1468
  const actualType = checker.typeToString(resolution.type, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
1441
- return [
1469
+ return emit("B-reject", [
1442
1470
  makeDiagnostic(
1443
1471
  "TYPE_MISMATCH",
1444
1472
  `Target "${target.rawText}": path-targeted constraint "${tagName}" is invalid because type "${actualType}" cannot be traversed`,
1445
1473
  provenance
1446
1474
  )
1447
- ];
1475
+ ]);
1448
1476
  }
1449
1477
  evaluatedType = resolution.type;
1450
1478
  targetLabel = target.rawText;
@@ -1473,13 +1501,13 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
1473
1501
  tagName,
1474
1502
  parsedTag?.argumentText
1475
1503
  ) : null;
1476
- return [
1504
+ return emit("B-reject", [
1477
1505
  makeDiagnostic(
1478
1506
  "TYPE_MISMATCH",
1479
1507
  hint === null ? baseMessage : `${baseMessage}. ${hint}`,
1480
1508
  provenance
1481
1509
  )
1482
- ];
1510
+ ]);
1483
1511
  }
1484
1512
  }
1485
1513
  const argumentExpression = renderSyntheticArgumentExpression(
@@ -1487,14 +1515,23 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
1487
1515
  parsedTag?.argumentText ?? ""
1488
1516
  );
1489
1517
  if (definition.requiresArgument && argumentExpression === null) {
1490
- return [];
1518
+ return emit("A-pass", []);
1491
1519
  }
1492
1520
  if (hasBroadening) {
1493
- return [];
1521
+ return emit("bypass", []);
1494
1522
  }
1495
1523
  const subjectTypeText = checker.typeToString(subjectType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
1496
1524
  const hostType = options?.hostType ?? subjectType;
1497
1525
  const hostTypeText = checker.typeToString(hostType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
1526
+ if (syntheticTraceEnabled) {
1527
+ syntheticLog.trace("invoking synthetic checker", {
1528
+ consumer: "build",
1529
+ tag: tagName,
1530
+ placement,
1531
+ subjectTypeKind,
1532
+ subjectTypeText
1533
+ });
1534
+ }
1498
1535
  const result = (0, import_internal2.checkSyntheticTagApplication)({
1499
1536
  tagName,
1500
1537
  placement,
@@ -1521,26 +1558,26 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
1521
1558
  } : {}
1522
1559
  });
1523
1560
  if (result.diagnostics.length === 0) {
1524
- return [];
1561
+ return emit("C-pass", []);
1525
1562
  }
1526
1563
  const setupDiagnostic = result.diagnostics.find((diagnostic) => diagnostic.kind !== "typescript");
1527
1564
  if (setupDiagnostic !== void 0) {
1528
- return [
1565
+ return emit("C-reject", [
1529
1566
  makeDiagnostic(
1530
1567
  setupDiagnostic.kind === "unsupported-custom-type-override" ? "UNSUPPORTED_CUSTOM_TYPE_OVERRIDE" : "SYNTHETIC_SETUP_FAILURE",
1531
1568
  setupDiagnostic.message,
1532
1569
  provenance
1533
1570
  )
1534
- ];
1571
+ ]);
1535
1572
  }
1536
1573
  const expectedLabel = definition.valueKind === null ? "compatible argument" : capabilityLabel(definition.valueKind);
1537
- return [
1574
+ return emit("C-reject", [
1538
1575
  makeDiagnostic(
1539
1576
  "TYPE_MISMATCH",
1540
1577
  `Tag "@${tagName}" received an invalid argument for ${expectedLabel}.`,
1541
1578
  provenance
1542
1579
  )
1543
- ];
1580
+ ]);
1544
1581
  }
1545
1582
  var parseResultCache = /* @__PURE__ */ new Map();
1546
1583
  function getExtensionTagNames(options) {
@@ -1950,7 +1987,7 @@ function createAnalyzerMetadataPolicy(input, discriminator) {
1950
1987
  };
1951
1988
  }
1952
1989
  function resolveNodeMetadata(metadataPolicy, declarationKind, logicalName, node, checker, extensionRegistry, buildContext) {
1953
- const analysis = (0, import_internal3.analyzeMetadataForNodeWithChecker)({
1990
+ const analysis = (0, import_internal4.analyzeMetadataForNodeWithChecker)({
1954
1991
  checker,
1955
1992
  node,
1956
1993
  logicalName,
@@ -2291,7 +2328,7 @@ function getLeadingParsedTags(node) {
2291
2328
  if (!commentText.startsWith("/**")) {
2292
2329
  continue;
2293
2330
  }
2294
- parsedTags.push(...(0, import_internal3.parseCommentBlock)(commentText, { offset: range.pos }).tags);
2331
+ parsedTags.push(...(0, import_internal4.parseCommentBlock)(commentText, { offset: range.pos }).tags);
2295
2332
  }
2296
2333
  return parsedTags;
2297
2334
  }
@@ -2700,6 +2737,22 @@ function extractReferenceTypeArguments(type, checker, file, typeRegistry, visiti
2700
2737
  }
2701
2738
  return referenceTypeNode.typeArguments.map((argumentNode) => {
2702
2739
  const argumentType = checker.getTypeFromTypeNode(argumentNode);
2740
+ const baseSymbol = argumentType.aliasSymbol ?? argumentType.getSymbol();
2741
+ const argumentSymbol = baseSymbol !== void 0 && baseSymbol.flags & ts6.SymbolFlags.Alias ? checker.getAliasedSymbol(baseSymbol) : baseSymbol;
2742
+ const argumentDecl = argumentSymbol?.declarations?.[0];
2743
+ if (argumentDecl !== void 0 && argumentDecl.getSourceFile().fileName !== file) {
2744
+ const argumentName = argumentSymbol?.getName() ?? baseSymbol?.getName();
2745
+ if (argumentName !== void 0) {
2746
+ return {
2747
+ tsType: argumentType,
2748
+ typeNode: {
2749
+ kind: "reference",
2750
+ name: argumentName,
2751
+ typeArguments: []
2752
+ }
2753
+ };
2754
+ }
2755
+ }
2703
2756
  return {
2704
2757
  tsType: argumentType,
2705
2758
  typeNode: resolveTypeNode(
@@ -2966,22 +3019,10 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
2966
3019
  sourceNode
2967
3020
  );
2968
3021
  if (customTypeLookup !== null) {
2969
- const typeId = customTypeIdFromLookup(customTypeLookup);
2970
- let payload = null;
2971
- if (customTypeLookup.registration.extractPayload !== void 0) {
2972
- try {
2973
- payload = customTypeLookup.registration.extractPayload(type, checker) ?? null;
2974
- } catch (cause) {
2975
- throw new Error(
2976
- `extractPayload for custom type "${customTypeLookup.registration.typeName}" in extension "${customTypeLookup.extensionId}" threw`,
2977
- { cause }
2978
- );
2979
- }
2980
- }
2981
3022
  return {
2982
3023
  kind: "custom",
2983
- typeId,
2984
- payload
3024
+ typeId: customTypeIdFromLookup(customTypeLookup),
3025
+ payload: null
2985
3026
  };
2986
3027
  }
2987
3028
  const primitiveAlias = tryResolveNamedPrimitiveAlias(
@@ -3165,6 +3206,21 @@ function getReferencedTypeAliasDeclaration(sourceNode, checker) {
3165
3206
  }
3166
3207
  return getTypeAliasDeclarationFromTypeReference(typeNode, checker);
3167
3208
  }
3209
+ function resolveNamedTypeWithSourceRecovery(type, sourceNode, checker) {
3210
+ const typeName = getNamedTypeName(type);
3211
+ const namedDecl = getNamedTypeDeclaration(type);
3212
+ if (typeName !== null && namedDecl !== void 0) {
3213
+ return { typeName, namedDecl };
3214
+ }
3215
+ if (sourceNode === void 0) {
3216
+ return null;
3217
+ }
3218
+ const refAliasDecl = getReferencedTypeAliasDeclaration(sourceNode, checker);
3219
+ if (refAliasDecl === void 0) {
3220
+ return null;
3221
+ }
3222
+ return { typeName: refAliasDecl.name.text, namedDecl: refAliasDecl };
3223
+ }
3168
3224
  function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
3169
3225
  if (!ts6.isTypeReferenceNode(typeNode)) {
3170
3226
  return false;
@@ -3223,8 +3279,23 @@ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiti
3223
3279
  );
3224
3280
  }
3225
3281
  function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
3226
- const typeName = getNamedTypeName(type);
3227
- const namedDecl = getNamedTypeDeclaration(type);
3282
+ const recovered = resolveNamedTypeWithSourceRecovery(type, sourceNode, checker);
3283
+ let typeName = null;
3284
+ let namedDecl;
3285
+ if (recovered !== null) {
3286
+ const recoveredAliasDecl = ts6.isTypeAliasDeclaration(recovered.namedDecl) ? recovered.namedDecl : void 0;
3287
+ if (recoveredAliasDecl !== void 0) {
3288
+ const aliasUnderlyingType = checker.getTypeFromTypeNode(recoveredAliasDecl.type);
3289
+ const isNonGeneric = recoveredAliasDecl.typeParameters === void 0 || recoveredAliasDecl.typeParameters.length === 0;
3290
+ if (isNonGeneric && (aliasUnderlyingType.isUnion() || isObjectType(aliasUnderlyingType))) {
3291
+ typeName = recovered.typeName;
3292
+ namedDecl = recovered.namedDecl;
3293
+ }
3294
+ } else {
3295
+ typeName = recovered.typeName;
3296
+ namedDecl = recovered.namedDecl;
3297
+ }
3298
+ }
3228
3299
  if (typeName && typeName in typeRegistry) {
3229
3300
  return { kind: "reference", name: typeName, typeArguments: [] };
3230
3301
  }
@@ -3256,6 +3327,10 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
3256
3327
  if (!typeName) {
3257
3328
  return result;
3258
3329
  }
3330
+ const existing = typeRegistry[typeName];
3331
+ if (existing !== void 0 && existing.type !== RESOLVING_TYPE_PLACEHOLDER) {
3332
+ return { kind: "reference", name: typeName, typeArguments: [] };
3333
+ }
3259
3334
  const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
3260
3335
  const metadata = namedDecl !== void 0 ? resolveNodeMetadata(
3261
3336
  metadataPolicy,
@@ -4587,10 +4662,11 @@ function generatePrimitiveType(type) {
4587
4662
  function generateEnumType(type, ctx) {
4588
4663
  if (ctx.enumSerialization === "oneOf") {
4589
4664
  return {
4590
- oneOf: type.members.map((m) => ({
4591
- const: m.value,
4592
- title: m.displayName ?? String(m.value)
4593
- }))
4665
+ oneOf: type.members.map((m) => {
4666
+ const stringValue = String(m.value);
4667
+ const title = m.displayName !== void 0 && m.displayName !== stringValue ? m.displayName : void 0;
4668
+ return title !== void 0 ? { const: m.value, title } : { const: m.value };
4669
+ })
4594
4670
  };
4595
4671
  }
4596
4672
  const schema = { enum: type.members.map((m) => m.value) };
@@ -5080,19 +5156,24 @@ function assignVendorPrefixedExtensionKeywords(schema, extensionSchema, vendorPr
5080
5156
 
5081
5157
  // src/extensions/registry.ts
5082
5158
  var import_internals5 = require("@formspec/core/internals");
5083
- var import_internal4 = require("@formspec/analysis/internal");
5159
+ var import_internal5 = require("@formspec/analysis/internal");
5084
5160
  var BUILTIN_METADATA_TAGS = /* @__PURE__ */ new Set(["apiName", "displayName"]);
5085
5161
  function buildConstraintTagSources(extensions) {
5086
5162
  return extensions.map((extension) => ({
5087
5163
  extensionId: extension.extensionId,
5088
5164
  ...extension.constraintTags !== void 0 ? {
5089
5165
  constraintTags: extension.constraintTags.map((tag) => ({
5090
- tagName: (0, import_internal4.normalizeFormSpecTagName)(tag.tagName)
5166
+ tagName: (0, import_internal5.normalizeFormSpecTagName)(tag.tagName)
5091
5167
  }))
5092
5168
  } : {}
5093
5169
  }));
5094
5170
  }
5095
5171
  function createExtensionRegistry(extensions) {
5172
+ const registryLog = (0, import_internal5.getSyntheticLogger)();
5173
+ registryLog.debug("createExtensionRegistry: constructing", {
5174
+ extensionCount: extensions.length,
5175
+ extensionIds: extensions.map((e) => e.extensionId)
5176
+ });
5096
5177
  const reservedTagSources = buildConstraintTagSources(extensions);
5097
5178
  let symbolMap = /* @__PURE__ */ new Map();
5098
5179
  const typeMap = /* @__PURE__ */ new Map();
@@ -5160,7 +5241,7 @@ function createExtensionRegistry(extensions) {
5160
5241
  }
5161
5242
  if (ext.constraintTags !== void 0) {
5162
5243
  for (const tag of ext.constraintTags) {
5163
- const canonicalTagName = (0, import_internal4.normalizeFormSpecTagName)(tag.tagName);
5244
+ const canonicalTagName = (0, import_internal5.normalizeFormSpecTagName)(tag.tagName);
5164
5245
  if (constraintTagMap.has(canonicalTagName)) {
5165
5246
  throw new Error(`Duplicate custom constraint tag: "@${canonicalTagName}"`);
5166
5247
  }
@@ -5185,7 +5266,7 @@ function createExtensionRegistry(extensions) {
5185
5266
  throw new Error(`Duplicate metadata slot ID: "${slot.slotId}"`);
5186
5267
  }
5187
5268
  metadataSlotMap.set(slot.slotId, true);
5188
- const canonicalTagName = (0, import_internal4.normalizeFormSpecTagName)(slot.tagName);
5269
+ const canonicalTagName = (0, import_internal5.normalizeFormSpecTagName)(slot.tagName);
5189
5270
  if (slot.allowBare === false && (slot.qualifiers?.length ?? 0) === 0) {
5190
5271
  throw new Error(
5191
5272
  `Metadata tag "@${canonicalTagName}" must allow bare usage or declare at least one qualifier.`
@@ -5212,7 +5293,7 @@ function createExtensionRegistry(extensions) {
5212
5293
  `Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${(0, import_internals5.normalizeConstraintTagName)(canonicalTagName)}".`
5213
5294
  );
5214
5295
  }
5215
- const existingTag = (0, import_internal4.getTagDefinition)(canonicalTagName, reservedTagSources);
5296
+ const existingTag = (0, import_internal5.getTagDefinition)(canonicalTagName, reservedTagSources);
5216
5297
  if (existingTag !== null) {
5217
5298
  throw BUILTIN_METADATA_TAGS.has(existingTag.canonicalName) ? new Error(
5218
5299
  `Metadata tag "@${canonicalTagName}" conflicts with built-in metadata tags.`
@@ -5224,6 +5305,14 @@ function createExtensionRegistry(extensions) {
5224
5305
  }
5225
5306
  }
5226
5307
  }
5308
+ registryLog.debug("createExtensionRegistry: complete", {
5309
+ typeCount: typeMap.size,
5310
+ constraintCount: constraintMap.size,
5311
+ constraintTagCount: constraintTagMap.size,
5312
+ broadeningCount: builtinBroadeningMap.size,
5313
+ annotationCount: annotationMap.size,
5314
+ metadataSlotCount: metadataSlotMap.size
5315
+ });
5227
5316
  return {
5228
5317
  extensions,
5229
5318
  findType: (typeId) => typeMap.get(typeId),
@@ -5234,7 +5323,7 @@ function createExtensionRegistry(extensions) {
5234
5323
  symbolMap = map;
5235
5324
  },
5236
5325
  findConstraint: (constraintId) => constraintMap.get(constraintId),
5237
- findConstraintTag: (tagName) => constraintTagMap.get((0, import_internal4.normalizeFormSpecTagName)(tagName)),
5326
+ findConstraintTag: (tagName) => constraintTagMap.get((0, import_internal5.normalizeFormSpecTagName)(tagName)),
5238
5327
  findBuiltinConstraintBroadening: (typeId, tagName) => builtinBroadeningMap.get(`${typeId}:${tagName}`),
5239
5328
  findAnnotation: (annotationId) => annotationMap.get(annotationId)
5240
5329
  };
@@ -5502,9 +5591,9 @@ function collectFieldNameMap(elements) {
5502
5591
  }
5503
5592
 
5504
5593
  // src/validate/constraint-validator.ts
5505
- var import_internal5 = require("@formspec/analysis/internal");
5594
+ var import_internal6 = require("@formspec/analysis/internal");
5506
5595
  function validateFieldNode(ctx, field) {
5507
- const analysis = (0, import_internal5.analyzeConstraintTargets)(
5596
+ const analysis = (0, import_internal6.analyzeConstraintTargets)(
5508
5597
  field.name,
5509
5598
  field.type,
5510
5599
  field.constraints,
@@ -5522,7 +5611,7 @@ function validateFieldNode(ctx, field) {
5522
5611
  }
5523
5612
  function validateObjectProperty(ctx, parentName, property) {
5524
5613
  const qualifiedName = `${parentName}.${property.name}`;
5525
- const analysis = (0, import_internal5.analyzeConstraintTargets)(
5614
+ const analysis = (0, import_internal6.analyzeConstraintTargets)(
5526
5615
  qualifiedName,
5527
5616
  property.type,
5528
5617
  property.constraints,