@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.
package/dist/internals.js CHANGED
@@ -828,6 +828,7 @@ import {
828
828
  isBuiltinConstraintName
829
829
  } from "@formspec/core/internals";
830
830
  import "@formspec/core/internals";
831
+ import { noopLogger } from "@formspec/core";
831
832
 
832
833
  // src/extensions/resolve-custom-type.ts
833
834
  import * as ts2 from "typescript";
@@ -955,6 +956,15 @@ function isIntegerBrandedType(type) {
955
956
  }
956
957
 
957
958
  // src/analyzer/tsdoc-parser.ts
959
+ import {
960
+ getBuildLogger,
961
+ getBroadeningLogger,
962
+ getSyntheticLogger,
963
+ describeTypeKind,
964
+ elapsedMicros,
965
+ nowMicros,
966
+ logTagApplication
967
+ } from "@formspec/analysis/internal";
958
968
  function sharedTagValueOptions(options) {
959
969
  return {
960
970
  ...options?.extensionRegistry !== void 0 ? { registry: options.extensionRegistry } : {},
@@ -1361,56 +1371,82 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
1361
1371
  if (definition === null) {
1362
1372
  return [];
1363
1373
  }
1374
+ const nonNullPlacement = placement;
1375
+ const log = getBuildLogger();
1376
+ const broadeningLog = getBroadeningLogger();
1377
+ const syntheticLog = getSyntheticLogger();
1378
+ const logsEnabled = log !== noopLogger || broadeningLog !== noopLogger;
1379
+ const syntheticTraceEnabled = syntheticLog !== noopLogger;
1380
+ const logStart = logsEnabled ? nowMicros() : 0;
1381
+ const subjectTypeKind = logsEnabled ? describeTypeKind(subjectType, checker) : "";
1382
+ function emit(outcome, result2) {
1383
+ if (!logsEnabled) {
1384
+ return result2;
1385
+ }
1386
+ const entry = {
1387
+ consumer: "build",
1388
+ tag: tagName,
1389
+ placement: nonNullPlacement,
1390
+ subjectTypeKind,
1391
+ roleOutcome: outcome,
1392
+ elapsedMicros: elapsedMicros(logStart)
1393
+ };
1394
+ logTagApplication(log, entry);
1395
+ if (outcome === "bypass" || outcome === "D1" || outcome === "D2") {
1396
+ logTagApplication(broadeningLog, entry);
1397
+ }
1398
+ return result2;
1399
+ }
1364
1400
  if (!definition.placements.includes(placement)) {
1365
- return [
1401
+ return emit("A-reject", [
1366
1402
  makeDiagnostic(
1367
1403
  "INVALID_TAG_PLACEMENT",
1368
1404
  `Tag "@${tagName}" is not allowed on ${placementLabel(placement)}.`,
1369
1405
  provenance
1370
1406
  )
1371
- ];
1407
+ ]);
1372
1408
  }
1373
1409
  const target = parsedTag?.target ?? null;
1374
1410
  let evaluatedType = subjectType;
1375
1411
  let targetLabel = node.getText(sourceFile);
1376
1412
  if (target !== null) {
1377
1413
  if (target.kind !== "path") {
1378
- return [
1414
+ return emit("B-reject", [
1379
1415
  makeDiagnostic(
1380
1416
  "UNSUPPORTED_TARGETING_SYNTAX",
1381
1417
  `Tag "@${tagName}" does not support ${target.kind} targeting syntax.`,
1382
1418
  provenance
1383
1419
  )
1384
- ];
1420
+ ]);
1385
1421
  }
1386
1422
  if (!target.valid || target.path === null) {
1387
- return [
1423
+ return emit("B-reject", [
1388
1424
  makeDiagnostic(
1389
1425
  "UNSUPPORTED_TARGETING_SYNTAX",
1390
1426
  `Tag "@${tagName}" has invalid path targeting syntax.`,
1391
1427
  provenance
1392
1428
  )
1393
- ];
1429
+ ]);
1394
1430
  }
1395
1431
  const resolution = resolvePathTargetType(subjectType, checker, target.path.segments);
1396
1432
  if (resolution.kind === "missing-property") {
1397
- return [
1433
+ return emit("B-reject", [
1398
1434
  makeDiagnostic(
1399
1435
  "UNKNOWN_PATH_TARGET",
1400
1436
  `Target "${target.rawText}": path-targeted constraint "${tagName}" references unknown path segment "${resolution.segment}"`,
1401
1437
  provenance
1402
1438
  )
1403
- ];
1439
+ ]);
1404
1440
  }
1405
1441
  if (resolution.kind === "unresolvable") {
1406
1442
  const actualType = checker.typeToString(resolution.type, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
1407
- return [
1443
+ return emit("B-reject", [
1408
1444
  makeDiagnostic(
1409
1445
  "TYPE_MISMATCH",
1410
1446
  `Target "${target.rawText}": path-targeted constraint "${tagName}" is invalid because type "${actualType}" cannot be traversed`,
1411
1447
  provenance
1412
1448
  )
1413
- ];
1449
+ ]);
1414
1450
  }
1415
1451
  evaluatedType = resolution.type;
1416
1452
  targetLabel = target.rawText;
@@ -1439,13 +1475,13 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
1439
1475
  tagName,
1440
1476
  parsedTag?.argumentText
1441
1477
  ) : null;
1442
- return [
1478
+ return emit("B-reject", [
1443
1479
  makeDiagnostic(
1444
1480
  "TYPE_MISMATCH",
1445
1481
  hint === null ? baseMessage : `${baseMessage}. ${hint}`,
1446
1482
  provenance
1447
1483
  )
1448
- ];
1484
+ ]);
1449
1485
  }
1450
1486
  }
1451
1487
  const argumentExpression = renderSyntheticArgumentExpression(
@@ -1453,14 +1489,23 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
1453
1489
  parsedTag?.argumentText ?? ""
1454
1490
  );
1455
1491
  if (definition.requiresArgument && argumentExpression === null) {
1456
- return [];
1492
+ return emit("A-pass", []);
1457
1493
  }
1458
1494
  if (hasBroadening) {
1459
- return [];
1495
+ return emit("bypass", []);
1460
1496
  }
1461
1497
  const subjectTypeText = checker.typeToString(subjectType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
1462
1498
  const hostType = options?.hostType ?? subjectType;
1463
1499
  const hostTypeText = checker.typeToString(hostType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
1500
+ if (syntheticTraceEnabled) {
1501
+ syntheticLog.trace("invoking synthetic checker", {
1502
+ consumer: "build",
1503
+ tag: tagName,
1504
+ placement,
1505
+ subjectTypeKind,
1506
+ subjectTypeText
1507
+ });
1508
+ }
1464
1509
  const result = checkSyntheticTagApplication({
1465
1510
  tagName,
1466
1511
  placement,
@@ -1487,26 +1532,26 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
1487
1532
  } : {}
1488
1533
  });
1489
1534
  if (result.diagnostics.length === 0) {
1490
- return [];
1535
+ return emit("C-pass", []);
1491
1536
  }
1492
1537
  const setupDiagnostic = result.diagnostics.find((diagnostic) => diagnostic.kind !== "typescript");
1493
1538
  if (setupDiagnostic !== void 0) {
1494
- return [
1539
+ return emit("C-reject", [
1495
1540
  makeDiagnostic(
1496
1541
  setupDiagnostic.kind === "unsupported-custom-type-override" ? "UNSUPPORTED_CUSTOM_TYPE_OVERRIDE" : "SYNTHETIC_SETUP_FAILURE",
1497
1542
  setupDiagnostic.message,
1498
1543
  provenance
1499
1544
  )
1500
- ];
1545
+ ]);
1501
1546
  }
1502
1547
  const expectedLabel = definition.valueKind === null ? "compatible argument" : capabilityLabel(definition.valueKind);
1503
- return [
1548
+ return emit("C-reject", [
1504
1549
  makeDiagnostic(
1505
1550
  "TYPE_MISMATCH",
1506
1551
  `Tag "@${tagName}" received an invalid argument for ${expectedLabel}.`,
1507
1552
  provenance
1508
1553
  )
1509
- ];
1554
+ ]);
1510
1555
  }
1511
1556
  var parseResultCache = /* @__PURE__ */ new Map();
1512
1557
  function getExtensionTagNames(options) {
@@ -2666,6 +2711,22 @@ function extractReferenceTypeArguments(type, checker, file, typeRegistry, visiti
2666
2711
  }
2667
2712
  return referenceTypeNode.typeArguments.map((argumentNode) => {
2668
2713
  const argumentType = checker.getTypeFromTypeNode(argumentNode);
2714
+ const baseSymbol = argumentType.aliasSymbol ?? argumentType.getSymbol();
2715
+ const argumentSymbol = baseSymbol !== void 0 && baseSymbol.flags & ts6.SymbolFlags.Alias ? checker.getAliasedSymbol(baseSymbol) : baseSymbol;
2716
+ const argumentDecl = argumentSymbol?.declarations?.[0];
2717
+ if (argumentDecl !== void 0 && argumentDecl.getSourceFile().fileName !== file) {
2718
+ const argumentName = argumentSymbol?.getName() ?? baseSymbol?.getName();
2719
+ if (argumentName !== void 0) {
2720
+ return {
2721
+ tsType: argumentType,
2722
+ typeNode: {
2723
+ kind: "reference",
2724
+ name: argumentName,
2725
+ typeArguments: []
2726
+ }
2727
+ };
2728
+ }
2729
+ }
2669
2730
  return {
2670
2731
  tsType: argumentType,
2671
2732
  typeNode: resolveTypeNode(
@@ -2932,22 +2993,10 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
2932
2993
  sourceNode
2933
2994
  );
2934
2995
  if (customTypeLookup !== null) {
2935
- const typeId = customTypeIdFromLookup(customTypeLookup);
2936
- let payload = null;
2937
- if (customTypeLookup.registration.extractPayload !== void 0) {
2938
- try {
2939
- payload = customTypeLookup.registration.extractPayload(type, checker) ?? null;
2940
- } catch (cause) {
2941
- throw new Error(
2942
- `extractPayload for custom type "${customTypeLookup.registration.typeName}" in extension "${customTypeLookup.extensionId}" threw`,
2943
- { cause }
2944
- );
2945
- }
2946
- }
2947
2996
  return {
2948
2997
  kind: "custom",
2949
- typeId,
2950
- payload
2998
+ typeId: customTypeIdFromLookup(customTypeLookup),
2999
+ payload: null
2951
3000
  };
2952
3001
  }
2953
3002
  const primitiveAlias = tryResolveNamedPrimitiveAlias(
@@ -3131,6 +3180,21 @@ function getReferencedTypeAliasDeclaration(sourceNode, checker) {
3131
3180
  }
3132
3181
  return getTypeAliasDeclarationFromTypeReference(typeNode, checker);
3133
3182
  }
3183
+ function resolveNamedTypeWithSourceRecovery(type, sourceNode, checker) {
3184
+ const typeName = getNamedTypeName(type);
3185
+ const namedDecl = getNamedTypeDeclaration(type);
3186
+ if (typeName !== null && namedDecl !== void 0) {
3187
+ return { typeName, namedDecl };
3188
+ }
3189
+ if (sourceNode === void 0) {
3190
+ return null;
3191
+ }
3192
+ const refAliasDecl = getReferencedTypeAliasDeclaration(sourceNode, checker);
3193
+ if (refAliasDecl === void 0) {
3194
+ return null;
3195
+ }
3196
+ return { typeName: refAliasDecl.name.text, namedDecl: refAliasDecl };
3197
+ }
3134
3198
  function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
3135
3199
  if (!ts6.isTypeReferenceNode(typeNode)) {
3136
3200
  return false;
@@ -3189,8 +3253,23 @@ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiti
3189
3253
  );
3190
3254
  }
3191
3255
  function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
3192
- const typeName = getNamedTypeName(type);
3193
- const namedDecl = getNamedTypeDeclaration(type);
3256
+ const recovered = resolveNamedTypeWithSourceRecovery(type, sourceNode, checker);
3257
+ let typeName = null;
3258
+ let namedDecl;
3259
+ if (recovered !== null) {
3260
+ const recoveredAliasDecl = ts6.isTypeAliasDeclaration(recovered.namedDecl) ? recovered.namedDecl : void 0;
3261
+ if (recoveredAliasDecl !== void 0) {
3262
+ const aliasUnderlyingType = checker.getTypeFromTypeNode(recoveredAliasDecl.type);
3263
+ const isNonGeneric = recoveredAliasDecl.typeParameters === void 0 || recoveredAliasDecl.typeParameters.length === 0;
3264
+ if (isNonGeneric && (aliasUnderlyingType.isUnion() || isObjectType(aliasUnderlyingType))) {
3265
+ typeName = recovered.typeName;
3266
+ namedDecl = recovered.namedDecl;
3267
+ }
3268
+ } else {
3269
+ typeName = recovered.typeName;
3270
+ namedDecl = recovered.namedDecl;
3271
+ }
3272
+ }
3194
3273
  if (typeName && typeName in typeRegistry) {
3195
3274
  return { kind: "reference", name: typeName, typeArguments: [] };
3196
3275
  }
@@ -3222,6 +3301,10 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
3222
3301
  if (!typeName) {
3223
3302
  return result;
3224
3303
  }
3304
+ const existing = typeRegistry[typeName];
3305
+ if (existing !== void 0 && existing.type !== RESOLVING_TYPE_PLACEHOLDER) {
3306
+ return { kind: "reference", name: typeName, typeArguments: [] };
3307
+ }
3225
3308
  const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
3226
3309
  const metadata = namedDecl !== void 0 ? resolveNodeMetadata(
3227
3310
  metadataPolicy,
@@ -4553,10 +4636,11 @@ function generatePrimitiveType(type) {
4553
4636
  function generateEnumType(type, ctx) {
4554
4637
  if (ctx.enumSerialization === "oneOf") {
4555
4638
  return {
4556
- oneOf: type.members.map((m) => ({
4557
- const: m.value,
4558
- title: m.displayName ?? String(m.value)
4559
- }))
4639
+ oneOf: type.members.map((m) => {
4640
+ const stringValue = String(m.value);
4641
+ const title = m.displayName !== void 0 && m.displayName !== stringValue ? m.displayName : void 0;
4642
+ return title !== void 0 ? { const: m.value, title } : { const: m.value };
4643
+ })
4560
4644
  };
4561
4645
  }
4562
4646
  const schema = { enum: type.members.map((m) => m.value) };
@@ -5051,7 +5135,8 @@ import {
5051
5135
  } from "@formspec/core/internals";
5052
5136
  import {
5053
5137
  getTagDefinition as getTagDefinition2,
5054
- normalizeFormSpecTagName as normalizeFormSpecTagName2
5138
+ normalizeFormSpecTagName as normalizeFormSpecTagName2,
5139
+ getSyntheticLogger as getSyntheticLogger2
5055
5140
  } from "@formspec/analysis/internal";
5056
5141
  var BUILTIN_METADATA_TAGS = /* @__PURE__ */ new Set(["apiName", "displayName"]);
5057
5142
  function buildConstraintTagSources(extensions) {
@@ -5065,6 +5150,11 @@ function buildConstraintTagSources(extensions) {
5065
5150
  }));
5066
5151
  }
5067
5152
  function createExtensionRegistry(extensions) {
5153
+ const registryLog = getSyntheticLogger2();
5154
+ registryLog.debug("createExtensionRegistry: constructing", {
5155
+ extensionCount: extensions.length,
5156
+ extensionIds: extensions.map((e) => e.extensionId)
5157
+ });
5068
5158
  const reservedTagSources = buildConstraintTagSources(extensions);
5069
5159
  let symbolMap = /* @__PURE__ */ new Map();
5070
5160
  const typeMap = /* @__PURE__ */ new Map();
@@ -5196,6 +5286,14 @@ function createExtensionRegistry(extensions) {
5196
5286
  }
5197
5287
  }
5198
5288
  }
5289
+ registryLog.debug("createExtensionRegistry: complete", {
5290
+ typeCount: typeMap.size,
5291
+ constraintCount: constraintMap.size,
5292
+ constraintTagCount: constraintTagMap.size,
5293
+ broadeningCount: builtinBroadeningMap.size,
5294
+ annotationCount: annotationMap.size,
5295
+ metadataSlotCount: metadataSlotMap.size
5296
+ });
5199
5297
  return {
5200
5298
  extensions,
5201
5299
  findType: (typeId) => typeMap.get(typeId),