@formspec/build 0.1.0-alpha.53 → 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/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- import { noopLogger as noopLogger3 } from "@formspec/core";
2
+ import { noopLogger as noopLogger4 } from "@formspec/core";
3
3
 
4
4
  // src/json-schema/generator.ts
5
5
  import { noopLogger } from "@formspec/core";
@@ -1167,10 +1167,11 @@ function generatePrimitiveType(type) {
1167
1167
  function generateEnumType(type, ctx) {
1168
1168
  if (ctx.enumSerialization === "oneOf") {
1169
1169
  return {
1170
- oneOf: type.members.map((m) => ({
1171
- const: m.value,
1172
- title: m.displayName ?? String(m.value)
1173
- }))
1170
+ oneOf: type.members.map((m) => {
1171
+ const stringValue = String(m.value);
1172
+ const title = m.displayName !== void 0 && m.displayName !== stringValue ? m.displayName : void 0;
1173
+ return title !== void 0 ? { const: m.value, title } : { const: m.value };
1174
+ })
1174
1175
  };
1175
1176
  }
1176
1177
  const schema = { enum: type.members.map((m) => m.value) };
@@ -1959,7 +1960,8 @@ import {
1959
1960
  } from "@formspec/core/internals";
1960
1961
  import {
1961
1962
  getTagDefinition,
1962
- normalizeFormSpecTagName
1963
+ normalizeFormSpecTagName,
1964
+ getSyntheticLogger
1963
1965
  } from "@formspec/analysis/internal";
1964
1966
  var BUILTIN_METADATA_TAGS = /* @__PURE__ */ new Set(["apiName", "displayName"]);
1965
1967
  function buildConstraintTagSources(extensions) {
@@ -1973,6 +1975,11 @@ function buildConstraintTagSources(extensions) {
1973
1975
  }));
1974
1976
  }
1975
1977
  function createExtensionRegistry(extensions) {
1978
+ const registryLog = getSyntheticLogger();
1979
+ registryLog.debug("createExtensionRegistry: constructing", {
1980
+ extensionCount: extensions.length,
1981
+ extensionIds: extensions.map((e) => e.extensionId)
1982
+ });
1976
1983
  const reservedTagSources = buildConstraintTagSources(extensions);
1977
1984
  let symbolMap = /* @__PURE__ */ new Map();
1978
1985
  const typeMap = /* @__PURE__ */ new Map();
@@ -2104,6 +2111,14 @@ function createExtensionRegistry(extensions) {
2104
2111
  }
2105
2112
  }
2106
2113
  }
2114
+ registryLog.debug("createExtensionRegistry: complete", {
2115
+ typeCount: typeMap.size,
2116
+ constraintCount: constraintMap.size,
2117
+ constraintTagCount: constraintTagMap.size,
2118
+ broadeningCount: builtinBroadeningMap.size,
2119
+ annotationCount: annotationMap.size,
2120
+ metadataSlotCount: metadataSlotMap.size
2121
+ });
2107
2122
  return {
2108
2123
  extensions,
2109
2124
  findType: (typeId) => typeMap.get(typeId),
@@ -2223,6 +2238,7 @@ import {
2223
2238
  isBuiltinConstraintName
2224
2239
  } from "@formspec/core/internals";
2225
2240
  import "@formspec/core/internals";
2241
+ import { noopLogger as noopLogger3 } from "@formspec/core";
2226
2242
 
2227
2243
  // src/extensions/resolve-custom-type.ts
2228
2244
  import * as ts2 from "typescript";
@@ -2350,6 +2366,15 @@ function isIntegerBrandedType(type) {
2350
2366
  }
2351
2367
 
2352
2368
  // src/analyzer/tsdoc-parser.ts
2369
+ import {
2370
+ getBuildLogger,
2371
+ getBroadeningLogger,
2372
+ getSyntheticLogger as getSyntheticLogger2,
2373
+ describeTypeKind,
2374
+ elapsedMicros,
2375
+ nowMicros,
2376
+ logTagApplication
2377
+ } from "@formspec/analysis/internal";
2353
2378
  function sharedTagValueOptions(options) {
2354
2379
  return {
2355
2380
  ...options?.extensionRegistry !== void 0 ? { registry: options.extensionRegistry } : {},
@@ -2756,56 +2781,82 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2756
2781
  if (definition === null) {
2757
2782
  return [];
2758
2783
  }
2784
+ const nonNullPlacement = placement;
2785
+ const log = getBuildLogger();
2786
+ const broadeningLog = getBroadeningLogger();
2787
+ const syntheticLog = getSyntheticLogger2();
2788
+ const logsEnabled = log !== noopLogger3 || broadeningLog !== noopLogger3;
2789
+ const syntheticTraceEnabled = syntheticLog !== noopLogger3;
2790
+ const logStart = logsEnabled ? nowMicros() : 0;
2791
+ const subjectTypeKind = logsEnabled ? describeTypeKind(subjectType, checker) : "";
2792
+ function emit(outcome, result2) {
2793
+ if (!logsEnabled) {
2794
+ return result2;
2795
+ }
2796
+ const entry = {
2797
+ consumer: "build",
2798
+ tag: tagName,
2799
+ placement: nonNullPlacement,
2800
+ subjectTypeKind,
2801
+ roleOutcome: outcome,
2802
+ elapsedMicros: elapsedMicros(logStart)
2803
+ };
2804
+ logTagApplication(log, entry);
2805
+ if (outcome === "bypass" || outcome === "D1" || outcome === "D2") {
2806
+ logTagApplication(broadeningLog, entry);
2807
+ }
2808
+ return result2;
2809
+ }
2759
2810
  if (!definition.placements.includes(placement)) {
2760
- return [
2811
+ return emit("A-reject", [
2761
2812
  makeDiagnostic(
2762
2813
  "INVALID_TAG_PLACEMENT",
2763
2814
  `Tag "@${tagName}" is not allowed on ${placementLabel(placement)}.`,
2764
2815
  provenance
2765
2816
  )
2766
- ];
2817
+ ]);
2767
2818
  }
2768
2819
  const target = parsedTag?.target ?? null;
2769
2820
  let evaluatedType = subjectType;
2770
2821
  let targetLabel = node.getText(sourceFile);
2771
2822
  if (target !== null) {
2772
2823
  if (target.kind !== "path") {
2773
- return [
2824
+ return emit("B-reject", [
2774
2825
  makeDiagnostic(
2775
2826
  "UNSUPPORTED_TARGETING_SYNTAX",
2776
2827
  `Tag "@${tagName}" does not support ${target.kind} targeting syntax.`,
2777
2828
  provenance
2778
2829
  )
2779
- ];
2830
+ ]);
2780
2831
  }
2781
2832
  if (!target.valid || target.path === null) {
2782
- return [
2833
+ return emit("B-reject", [
2783
2834
  makeDiagnostic(
2784
2835
  "UNSUPPORTED_TARGETING_SYNTAX",
2785
2836
  `Tag "@${tagName}" has invalid path targeting syntax.`,
2786
2837
  provenance
2787
2838
  )
2788
- ];
2839
+ ]);
2789
2840
  }
2790
2841
  const resolution = resolvePathTargetType(subjectType, checker, target.path.segments);
2791
2842
  if (resolution.kind === "missing-property") {
2792
- return [
2843
+ return emit("B-reject", [
2793
2844
  makeDiagnostic(
2794
2845
  "UNKNOWN_PATH_TARGET",
2795
2846
  `Target "${target.rawText}": path-targeted constraint "${tagName}" references unknown path segment "${resolution.segment}"`,
2796
2847
  provenance
2797
2848
  )
2798
- ];
2849
+ ]);
2799
2850
  }
2800
2851
  if (resolution.kind === "unresolvable") {
2801
2852
  const actualType = checker.typeToString(resolution.type, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
2802
- return [
2853
+ return emit("B-reject", [
2803
2854
  makeDiagnostic(
2804
2855
  "TYPE_MISMATCH",
2805
2856
  `Target "${target.rawText}": path-targeted constraint "${tagName}" is invalid because type "${actualType}" cannot be traversed`,
2806
2857
  provenance
2807
2858
  )
2808
- ];
2859
+ ]);
2809
2860
  }
2810
2861
  evaluatedType = resolution.type;
2811
2862
  targetLabel = target.rawText;
@@ -2834,13 +2885,13 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2834
2885
  tagName,
2835
2886
  parsedTag?.argumentText
2836
2887
  ) : null;
2837
- return [
2888
+ return emit("B-reject", [
2838
2889
  makeDiagnostic(
2839
2890
  "TYPE_MISMATCH",
2840
2891
  hint === null ? baseMessage : `${baseMessage}. ${hint}`,
2841
2892
  provenance
2842
2893
  )
2843
- ];
2894
+ ]);
2844
2895
  }
2845
2896
  }
2846
2897
  const argumentExpression = renderSyntheticArgumentExpression(
@@ -2848,14 +2899,23 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2848
2899
  parsedTag?.argumentText ?? ""
2849
2900
  );
2850
2901
  if (definition.requiresArgument && argumentExpression === null) {
2851
- return [];
2902
+ return emit("A-pass", []);
2852
2903
  }
2853
2904
  if (hasBroadening) {
2854
- return [];
2905
+ return emit("bypass", []);
2855
2906
  }
2856
2907
  const subjectTypeText = checker.typeToString(subjectType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
2857
2908
  const hostType = options?.hostType ?? subjectType;
2858
2909
  const hostTypeText = checker.typeToString(hostType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
2910
+ if (syntheticTraceEnabled) {
2911
+ syntheticLog.trace("invoking synthetic checker", {
2912
+ consumer: "build",
2913
+ tag: tagName,
2914
+ placement,
2915
+ subjectTypeKind,
2916
+ subjectTypeText
2917
+ });
2918
+ }
2859
2919
  const result = checkSyntheticTagApplication({
2860
2920
  tagName,
2861
2921
  placement,
@@ -2882,26 +2942,26 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2882
2942
  } : {}
2883
2943
  });
2884
2944
  if (result.diagnostics.length === 0) {
2885
- return [];
2945
+ return emit("C-pass", []);
2886
2946
  }
2887
2947
  const setupDiagnostic = result.diagnostics.find((diagnostic) => diagnostic.kind !== "typescript");
2888
2948
  if (setupDiagnostic !== void 0) {
2889
- return [
2949
+ return emit("C-reject", [
2890
2950
  makeDiagnostic(
2891
2951
  setupDiagnostic.kind === "unsupported-custom-type-override" ? "UNSUPPORTED_CUSTOM_TYPE_OVERRIDE" : "SYNTHETIC_SETUP_FAILURE",
2892
2952
  setupDiagnostic.message,
2893
2953
  provenance
2894
2954
  )
2895
- ];
2955
+ ]);
2896
2956
  }
2897
2957
  const expectedLabel = definition.valueKind === null ? "compatible argument" : capabilityLabel(definition.valueKind);
2898
- return [
2958
+ return emit("C-reject", [
2899
2959
  makeDiagnostic(
2900
2960
  "TYPE_MISMATCH",
2901
2961
  `Tag "@${tagName}" received an invalid argument for ${expectedLabel}.`,
2902
2962
  provenance
2903
2963
  )
2904
- ];
2964
+ ]);
2905
2965
  }
2906
2966
  var parseResultCache = /* @__PURE__ */ new Map();
2907
2967
  function getExtensionTagNames(options) {
@@ -4061,6 +4121,22 @@ function extractReferenceTypeArguments(type, checker, file, typeRegistry, visiti
4061
4121
  }
4062
4122
  return referenceTypeNode.typeArguments.map((argumentNode) => {
4063
4123
  const argumentType = checker.getTypeFromTypeNode(argumentNode);
4124
+ const baseSymbol = argumentType.aliasSymbol ?? argumentType.getSymbol();
4125
+ const argumentSymbol = baseSymbol !== void 0 && baseSymbol.flags & ts6.SymbolFlags.Alias ? checker.getAliasedSymbol(baseSymbol) : baseSymbol;
4126
+ const argumentDecl = argumentSymbol?.declarations?.[0];
4127
+ if (argumentDecl !== void 0 && argumentDecl.getSourceFile().fileName !== file) {
4128
+ const argumentName = argumentSymbol?.getName() ?? baseSymbol?.getName();
4129
+ if (argumentName !== void 0) {
4130
+ return {
4131
+ tsType: argumentType,
4132
+ typeNode: {
4133
+ kind: "reference",
4134
+ name: argumentName,
4135
+ typeArguments: []
4136
+ }
4137
+ };
4138
+ }
4139
+ }
4064
4140
  return {
4065
4141
  tsType: argumentType,
4066
4142
  typeNode: resolveTypeNode(
@@ -4514,6 +4590,21 @@ function getReferencedTypeAliasDeclaration(sourceNode, checker) {
4514
4590
  }
4515
4591
  return getTypeAliasDeclarationFromTypeReference(typeNode, checker);
4516
4592
  }
4593
+ function resolveNamedTypeWithSourceRecovery(type, sourceNode, checker) {
4594
+ const typeName = getNamedTypeName(type);
4595
+ const namedDecl = getNamedTypeDeclaration(type);
4596
+ if (typeName !== null && namedDecl !== void 0) {
4597
+ return { typeName, namedDecl };
4598
+ }
4599
+ if (sourceNode === void 0) {
4600
+ return null;
4601
+ }
4602
+ const refAliasDecl = getReferencedTypeAliasDeclaration(sourceNode, checker);
4603
+ if (refAliasDecl === void 0) {
4604
+ return null;
4605
+ }
4606
+ return { typeName: refAliasDecl.name.text, namedDecl: refAliasDecl };
4607
+ }
4517
4608
  function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
4518
4609
  if (!ts6.isTypeReferenceNode(typeNode)) {
4519
4610
  return false;
@@ -4572,8 +4663,23 @@ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiti
4572
4663
  );
4573
4664
  }
4574
4665
  function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
4575
- const typeName = getNamedTypeName(type);
4576
- const namedDecl = getNamedTypeDeclaration(type);
4666
+ const recovered = resolveNamedTypeWithSourceRecovery(type, sourceNode, checker);
4667
+ let typeName = null;
4668
+ let namedDecl;
4669
+ if (recovered !== null) {
4670
+ const recoveredAliasDecl = ts6.isTypeAliasDeclaration(recovered.namedDecl) ? recovered.namedDecl : void 0;
4671
+ if (recoveredAliasDecl !== void 0) {
4672
+ const aliasUnderlyingType = checker.getTypeFromTypeNode(recoveredAliasDecl.type);
4673
+ const isNonGeneric = recoveredAliasDecl.typeParameters === void 0 || recoveredAliasDecl.typeParameters.length === 0;
4674
+ if (isNonGeneric && (aliasUnderlyingType.isUnion() || isObjectType(aliasUnderlyingType))) {
4675
+ typeName = recovered.typeName;
4676
+ namedDecl = recovered.namedDecl;
4677
+ }
4678
+ } else {
4679
+ typeName = recovered.typeName;
4680
+ namedDecl = recovered.namedDecl;
4681
+ }
4682
+ }
4577
4683
  if (typeName && typeName in typeRegistry) {
4578
4684
  return { kind: "reference", name: typeName, typeArguments: [] };
4579
4685
  }
@@ -4605,6 +4711,10 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
4605
4711
  if (!typeName) {
4606
4712
  return result;
4607
4713
  }
4714
+ const existing = typeRegistry[typeName];
4715
+ if (existing !== void 0 && existing.type !== RESOLVING_TYPE_PLACEHOLDER) {
4716
+ return { kind: "reference", name: typeName, typeArguments: [] };
4717
+ }
4608
4718
  const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
4609
4719
  const metadata = namedDecl !== void 0 ? resolveNodeMetadata(
4610
4720
  metadataPolicy,
@@ -6760,7 +6870,7 @@ function annotationKey(annotation) {
6760
6870
 
6761
6871
  // src/index.ts
6762
6872
  function buildFormSchemas(form, options) {
6763
- const logger = options?.logger ?? noopLogger3;
6873
+ const logger = options?.logger ?? noopLogger4;
6764
6874
  logger.debug("buildFormSchemas: starting schema generation");
6765
6875
  return {
6766
6876
  jsonSchema: generateJsonSchema(form, options),
@@ -6777,7 +6887,7 @@ function writeSchemas(form, options) {
6777
6887
  metadata,
6778
6888
  logger: rawLogger
6779
6889
  } = options;
6780
- const logger = (rawLogger ?? noopLogger3).child({ stage: "write" });
6890
+ const logger = (rawLogger ?? noopLogger4).child({ stage: "write" });
6781
6891
  const buildOptions = vendorPrefix === void 0 && enumSerialization === void 0 && metadata === void 0 ? { logger: rawLogger } : {
6782
6892
  ...vendorPrefix !== void 0 && { vendorPrefix },
6783
6893
  ...enumSerialization !== void 0 && { enumSerialization },