@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.
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/extensions/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EACV,mBAAmB,EACnB,sBAAsB,EACtB,4BAA4B,EAC5B,4BAA4B,EAC5B,yBAAyB,EACzB,uCAAuC,EACxC,MAAM,gBAAgB,CAAC;AAexB;;;;;;;;GAQG;AACH,MAAM,WAAW,yBAAyB;IACxC,oEAAoE;IACpE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAC;CAC/C;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAEpD;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,sBAAsB,GAAG,SAAS,CAAC;IAC7D;;;;;OAKG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,yBAAyB,GAAG,SAAS,CAAC;IACxE;;;;;;;;;OASG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,yBAAyB,GAAG,SAAS,CAAC;IAEtE;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,GAAG,yBAAyB,GAAG,SAAS,CAAC;IAE3E;;;;;OAKG;IACH,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,4BAA4B,GAAG,SAAS,CAAC;IAC/E;;OAEG;IACH,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAC7B;QACE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,YAAY,EAAE,yBAAyB,CAAC;KAClD,GACD,SAAS,CAAC;IACd;;OAEG;IACH,+BAA+B,CAC7B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GAEb;QACE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,YAAY,EAAE,uCAAuC,CAAC;KAChE,GACD,SAAS,CAAC;IAEd;;;;;OAKG;IACH,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,4BAA4B,GAAG,SAAS,CAAC;CAChF;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IACjE;;;;;;;;OAQG;IACH,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,yBAAyB,CAAC,GAAG,IAAI,CAAC;CACpE;AAuBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,SAAS,mBAAmB,EAAE,GACzC,wBAAwB,CAuK1B"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/extensions/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EACV,mBAAmB,EACnB,sBAAsB,EACtB,4BAA4B,EAC5B,4BAA4B,EAC5B,yBAAyB,EACzB,uCAAuC,EACxC,MAAM,gBAAgB,CAAC;AAgBxB;;;;;;;;GAQG;AACH,MAAM,WAAW,yBAAyB;IACxC,oEAAoE;IACpE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAC;CAC/C;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAEpD;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,sBAAsB,GAAG,SAAS,CAAC;IAC7D;;;;;OAKG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,yBAAyB,GAAG,SAAS,CAAC;IACxE;;;;;;;;;OASG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,yBAAyB,GAAG,SAAS,CAAC;IAEtE;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,GAAG,yBAAyB,GAAG,SAAS,CAAC;IAE3E;;;;;OAKG;IACH,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,4BAA4B,GAAG,SAAS,CAAC;IAC/E;;OAEG;IACH,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAC7B;QACE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,YAAY,EAAE,yBAAyB,CAAC;KAClD,GACD,SAAS,CAAC;IACd;;OAEG;IACH,+BAA+B,CAC7B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GAEb;QACE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,YAAY,EAAE,uCAAuC,CAAC;KAChE,GACD,SAAS,CAAC;IAEd;;;;;OAKG;IACH,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,4BAA4B,GAAG,SAAS,CAAC;CAChF;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IACjE;;;;;;;;OAQG;IACH,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,yBAAyB,CAAC,GAAG,IAAI,CAAC;CACpE;AAuBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,SAAS,mBAAmB,EAAE,GACzC,wBAAwB,CAwL1B"}
package/dist/index.cjs CHANGED
@@ -56,7 +56,7 @@ __export(index_exports, {
56
56
  writeSchemas: () => writeSchemas
57
57
  });
58
58
  module.exports = __toCommonJS(index_exports);
59
- var import_core3 = require("@formspec/core");
59
+ var import_core4 = require("@formspec/core");
60
60
 
61
61
  // src/json-schema/generator.ts
62
62
  var import_core = require("@formspec/core");
@@ -1224,10 +1224,11 @@ function generatePrimitiveType(type) {
1224
1224
  function generateEnumType(type, ctx) {
1225
1225
  if (ctx.enumSerialization === "oneOf") {
1226
1226
  return {
1227
- oneOf: type.members.map((m) => ({
1228
- const: m.value,
1229
- title: m.displayName ?? String(m.value)
1230
- }))
1227
+ oneOf: type.members.map((m) => {
1228
+ const stringValue = String(m.value);
1229
+ const title = m.displayName !== void 0 && m.displayName !== stringValue ? m.displayName : void 0;
1230
+ return title !== void 0 ? { const: m.value, title } : { const: m.value };
1231
+ })
1231
1232
  };
1232
1233
  }
1233
1234
  const schema = { enum: type.members.map((m) => m.value) };
@@ -2024,6 +2025,11 @@ function buildConstraintTagSources(extensions) {
2024
2025
  }));
2025
2026
  }
2026
2027
  function createExtensionRegistry(extensions) {
2028
+ const registryLog = (0, import_internal.getSyntheticLogger)();
2029
+ registryLog.debug("createExtensionRegistry: constructing", {
2030
+ extensionCount: extensions.length,
2031
+ extensionIds: extensions.map((e) => e.extensionId)
2032
+ });
2027
2033
  const reservedTagSources = buildConstraintTagSources(extensions);
2028
2034
  let symbolMap = /* @__PURE__ */ new Map();
2029
2035
  const typeMap = /* @__PURE__ */ new Map();
@@ -2155,6 +2161,14 @@ function createExtensionRegistry(extensions) {
2155
2161
  }
2156
2162
  }
2157
2163
  }
2164
+ registryLog.debug("createExtensionRegistry: complete", {
2165
+ typeCount: typeMap.size,
2166
+ constraintCount: constraintMap.size,
2167
+ constraintTagCount: constraintTagMap.size,
2168
+ broadeningCount: builtinBroadeningMap.size,
2169
+ annotationCount: annotationMap.size,
2170
+ metadataSlotCount: metadataSlotMap.size
2171
+ });
2158
2172
  return {
2159
2173
  extensions,
2160
2174
  findType: (typeId) => typeMap.get(typeId),
@@ -2242,7 +2256,7 @@ var path = __toESM(require("path"), 1);
2242
2256
 
2243
2257
  // src/analyzer/class-analyzer.ts
2244
2258
  var ts6 = __toESM(require("typescript"), 1);
2245
- var import_internal4 = require("@formspec/analysis/internal");
2259
+ var import_internal5 = require("@formspec/analysis/internal");
2246
2260
 
2247
2261
  // src/analyzer/jsdoc-constraints.ts
2248
2262
  var ts5 = __toESM(require("typescript"), 1);
@@ -2252,6 +2266,7 @@ var ts4 = __toESM(require("typescript"), 1);
2252
2266
  var import_internal3 = require("@formspec/analysis/internal");
2253
2267
  var import_internals4 = require("@formspec/core/internals");
2254
2268
  var import_internals5 = require("@formspec/core/internals");
2269
+ var import_core3 = require("@formspec/core");
2255
2270
 
2256
2271
  // src/extensions/resolve-custom-type.ts
2257
2272
  var ts2 = __toESM(require("typescript"), 1);
@@ -2379,6 +2394,7 @@ function isIntegerBrandedType(type) {
2379
2394
  }
2380
2395
 
2381
2396
  // src/analyzer/tsdoc-parser.ts
2397
+ var import_internal4 = require("@formspec/analysis/internal");
2382
2398
  function sharedTagValueOptions(options) {
2383
2399
  return {
2384
2400
  ...options?.extensionRegistry !== void 0 ? { registry: options.extensionRegistry } : {},
@@ -2785,56 +2801,82 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2785
2801
  if (definition === null) {
2786
2802
  return [];
2787
2803
  }
2804
+ const nonNullPlacement = placement;
2805
+ const log = (0, import_internal4.getBuildLogger)();
2806
+ const broadeningLog = (0, import_internal4.getBroadeningLogger)();
2807
+ const syntheticLog = (0, import_internal4.getSyntheticLogger)();
2808
+ const logsEnabled = log !== import_core3.noopLogger || broadeningLog !== import_core3.noopLogger;
2809
+ const syntheticTraceEnabled = syntheticLog !== import_core3.noopLogger;
2810
+ const logStart = logsEnabled ? (0, import_internal4.nowMicros)() : 0;
2811
+ const subjectTypeKind = logsEnabled ? (0, import_internal4.describeTypeKind)(subjectType, checker) : "";
2812
+ function emit(outcome, result2) {
2813
+ if (!logsEnabled) {
2814
+ return result2;
2815
+ }
2816
+ const entry = {
2817
+ consumer: "build",
2818
+ tag: tagName,
2819
+ placement: nonNullPlacement,
2820
+ subjectTypeKind,
2821
+ roleOutcome: outcome,
2822
+ elapsedMicros: (0, import_internal4.elapsedMicros)(logStart)
2823
+ };
2824
+ (0, import_internal4.logTagApplication)(log, entry);
2825
+ if (outcome === "bypass" || outcome === "D1" || outcome === "D2") {
2826
+ (0, import_internal4.logTagApplication)(broadeningLog, entry);
2827
+ }
2828
+ return result2;
2829
+ }
2788
2830
  if (!definition.placements.includes(placement)) {
2789
- return [
2831
+ return emit("A-reject", [
2790
2832
  makeDiagnostic(
2791
2833
  "INVALID_TAG_PLACEMENT",
2792
2834
  `Tag "@${tagName}" is not allowed on ${placementLabel(placement)}.`,
2793
2835
  provenance
2794
2836
  )
2795
- ];
2837
+ ]);
2796
2838
  }
2797
2839
  const target = parsedTag?.target ?? null;
2798
2840
  let evaluatedType = subjectType;
2799
2841
  let targetLabel = node.getText(sourceFile);
2800
2842
  if (target !== null) {
2801
2843
  if (target.kind !== "path") {
2802
- return [
2844
+ return emit("B-reject", [
2803
2845
  makeDiagnostic(
2804
2846
  "UNSUPPORTED_TARGETING_SYNTAX",
2805
2847
  `Tag "@${tagName}" does not support ${target.kind} targeting syntax.`,
2806
2848
  provenance
2807
2849
  )
2808
- ];
2850
+ ]);
2809
2851
  }
2810
2852
  if (!target.valid || target.path === null) {
2811
- return [
2853
+ return emit("B-reject", [
2812
2854
  makeDiagnostic(
2813
2855
  "UNSUPPORTED_TARGETING_SYNTAX",
2814
2856
  `Tag "@${tagName}" has invalid path targeting syntax.`,
2815
2857
  provenance
2816
2858
  )
2817
- ];
2859
+ ]);
2818
2860
  }
2819
2861
  const resolution = (0, import_internal3.resolvePathTargetType)(subjectType, checker, target.path.segments);
2820
2862
  if (resolution.kind === "missing-property") {
2821
- return [
2863
+ return emit("B-reject", [
2822
2864
  makeDiagnostic(
2823
2865
  "UNKNOWN_PATH_TARGET",
2824
2866
  `Target "${target.rawText}": path-targeted constraint "${tagName}" references unknown path segment "${resolution.segment}"`,
2825
2867
  provenance
2826
2868
  )
2827
- ];
2869
+ ]);
2828
2870
  }
2829
2871
  if (resolution.kind === "unresolvable") {
2830
2872
  const actualType = checker.typeToString(resolution.type, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
2831
- return [
2873
+ return emit("B-reject", [
2832
2874
  makeDiagnostic(
2833
2875
  "TYPE_MISMATCH",
2834
2876
  `Target "${target.rawText}": path-targeted constraint "${tagName}" is invalid because type "${actualType}" cannot be traversed`,
2835
2877
  provenance
2836
2878
  )
2837
- ];
2879
+ ]);
2838
2880
  }
2839
2881
  evaluatedType = resolution.type;
2840
2882
  targetLabel = target.rawText;
@@ -2863,13 +2905,13 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2863
2905
  tagName,
2864
2906
  parsedTag?.argumentText
2865
2907
  ) : null;
2866
- return [
2908
+ return emit("B-reject", [
2867
2909
  makeDiagnostic(
2868
2910
  "TYPE_MISMATCH",
2869
2911
  hint === null ? baseMessage : `${baseMessage}. ${hint}`,
2870
2912
  provenance
2871
2913
  )
2872
- ];
2914
+ ]);
2873
2915
  }
2874
2916
  }
2875
2917
  const argumentExpression = renderSyntheticArgumentExpression(
@@ -2877,14 +2919,23 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2877
2919
  parsedTag?.argumentText ?? ""
2878
2920
  );
2879
2921
  if (definition.requiresArgument && argumentExpression === null) {
2880
- return [];
2922
+ return emit("A-pass", []);
2881
2923
  }
2882
2924
  if (hasBroadening) {
2883
- return [];
2925
+ return emit("bypass", []);
2884
2926
  }
2885
2927
  const subjectTypeText = checker.typeToString(subjectType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
2886
2928
  const hostType = options?.hostType ?? subjectType;
2887
2929
  const hostTypeText = checker.typeToString(hostType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
2930
+ if (syntheticTraceEnabled) {
2931
+ syntheticLog.trace("invoking synthetic checker", {
2932
+ consumer: "build",
2933
+ tag: tagName,
2934
+ placement,
2935
+ subjectTypeKind,
2936
+ subjectTypeText
2937
+ });
2938
+ }
2888
2939
  const result = (0, import_internal3.checkSyntheticTagApplication)({
2889
2940
  tagName,
2890
2941
  placement,
@@ -2911,26 +2962,26 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2911
2962
  } : {}
2912
2963
  });
2913
2964
  if (result.diagnostics.length === 0) {
2914
- return [];
2965
+ return emit("C-pass", []);
2915
2966
  }
2916
2967
  const setupDiagnostic = result.diagnostics.find((diagnostic) => diagnostic.kind !== "typescript");
2917
2968
  if (setupDiagnostic !== void 0) {
2918
- return [
2969
+ return emit("C-reject", [
2919
2970
  makeDiagnostic(
2920
2971
  setupDiagnostic.kind === "unsupported-custom-type-override" ? "UNSUPPORTED_CUSTOM_TYPE_OVERRIDE" : "SYNTHETIC_SETUP_FAILURE",
2921
2972
  setupDiagnostic.message,
2922
2973
  provenance
2923
2974
  )
2924
- ];
2975
+ ]);
2925
2976
  }
2926
2977
  const expectedLabel = definition.valueKind === null ? "compatible argument" : capabilityLabel(definition.valueKind);
2927
- return [
2978
+ return emit("C-reject", [
2928
2979
  makeDiagnostic(
2929
2980
  "TYPE_MISMATCH",
2930
2981
  `Tag "@${tagName}" received an invalid argument for ${expectedLabel}.`,
2931
2982
  provenance
2932
2983
  )
2933
- ];
2984
+ ]);
2934
2985
  }
2935
2986
  var parseResultCache = /* @__PURE__ */ new Map();
2936
2987
  function getExtensionTagNames(options) {
@@ -3340,7 +3391,7 @@ function createAnalyzerMetadataPolicy(input, discriminator) {
3340
3391
  };
3341
3392
  }
3342
3393
  function resolveNodeMetadata(metadataPolicy, declarationKind, logicalName, node, checker, extensionRegistry, buildContext) {
3343
- const analysis = (0, import_internal4.analyzeMetadataForNodeWithChecker)({
3394
+ const analysis = (0, import_internal5.analyzeMetadataForNodeWithChecker)({
3344
3395
  checker,
3345
3396
  node,
3346
3397
  logicalName,
@@ -3681,7 +3732,7 @@ function getLeadingParsedTags(node) {
3681
3732
  if (!commentText.startsWith("/**")) {
3682
3733
  continue;
3683
3734
  }
3684
- parsedTags.push(...(0, import_internal4.parseCommentBlock)(commentText, { offset: range.pos }).tags);
3735
+ parsedTags.push(...(0, import_internal5.parseCommentBlock)(commentText, { offset: range.pos }).tags);
3685
3736
  }
3686
3737
  return parsedTags;
3687
3738
  }
@@ -4090,6 +4141,22 @@ function extractReferenceTypeArguments(type, checker, file, typeRegistry, visiti
4090
4141
  }
4091
4142
  return referenceTypeNode.typeArguments.map((argumentNode) => {
4092
4143
  const argumentType = checker.getTypeFromTypeNode(argumentNode);
4144
+ const baseSymbol = argumentType.aliasSymbol ?? argumentType.getSymbol();
4145
+ const argumentSymbol = baseSymbol !== void 0 && baseSymbol.flags & ts6.SymbolFlags.Alias ? checker.getAliasedSymbol(baseSymbol) : baseSymbol;
4146
+ const argumentDecl = argumentSymbol?.declarations?.[0];
4147
+ if (argumentDecl !== void 0 && argumentDecl.getSourceFile().fileName !== file) {
4148
+ const argumentName = argumentSymbol?.getName() ?? baseSymbol?.getName();
4149
+ if (argumentName !== void 0) {
4150
+ return {
4151
+ tsType: argumentType,
4152
+ typeNode: {
4153
+ kind: "reference",
4154
+ name: argumentName,
4155
+ typeArguments: []
4156
+ }
4157
+ };
4158
+ }
4159
+ }
4093
4160
  return {
4094
4161
  tsType: argumentType,
4095
4162
  typeNode: resolveTypeNode(
@@ -4356,22 +4423,10 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
4356
4423
  sourceNode
4357
4424
  );
4358
4425
  if (customTypeLookup !== null) {
4359
- const typeId = customTypeIdFromLookup(customTypeLookup);
4360
- let payload = null;
4361
- if (customTypeLookup.registration.extractPayload !== void 0) {
4362
- try {
4363
- payload = customTypeLookup.registration.extractPayload(type, checker) ?? null;
4364
- } catch (cause) {
4365
- throw new Error(
4366
- `extractPayload for custom type "${customTypeLookup.registration.typeName}" in extension "${customTypeLookup.extensionId}" threw`,
4367
- { cause }
4368
- );
4369
- }
4370
- }
4371
4426
  return {
4372
4427
  kind: "custom",
4373
- typeId,
4374
- payload
4428
+ typeId: customTypeIdFromLookup(customTypeLookup),
4429
+ payload: null
4375
4430
  };
4376
4431
  }
4377
4432
  const primitiveAlias = tryResolveNamedPrimitiveAlias(
@@ -4555,6 +4610,21 @@ function getReferencedTypeAliasDeclaration(sourceNode, checker) {
4555
4610
  }
4556
4611
  return getTypeAliasDeclarationFromTypeReference(typeNode, checker);
4557
4612
  }
4613
+ function resolveNamedTypeWithSourceRecovery(type, sourceNode, checker) {
4614
+ const typeName = getNamedTypeName(type);
4615
+ const namedDecl = getNamedTypeDeclaration(type);
4616
+ if (typeName !== null && namedDecl !== void 0) {
4617
+ return { typeName, namedDecl };
4618
+ }
4619
+ if (sourceNode === void 0) {
4620
+ return null;
4621
+ }
4622
+ const refAliasDecl = getReferencedTypeAliasDeclaration(sourceNode, checker);
4623
+ if (refAliasDecl === void 0) {
4624
+ return null;
4625
+ }
4626
+ return { typeName: refAliasDecl.name.text, namedDecl: refAliasDecl };
4627
+ }
4558
4628
  function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
4559
4629
  if (!ts6.isTypeReferenceNode(typeNode)) {
4560
4630
  return false;
@@ -4613,8 +4683,23 @@ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiti
4613
4683
  );
4614
4684
  }
4615
4685
  function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
4616
- const typeName = getNamedTypeName(type);
4617
- const namedDecl = getNamedTypeDeclaration(type);
4686
+ const recovered = resolveNamedTypeWithSourceRecovery(type, sourceNode, checker);
4687
+ let typeName = null;
4688
+ let namedDecl;
4689
+ if (recovered !== null) {
4690
+ const recoveredAliasDecl = ts6.isTypeAliasDeclaration(recovered.namedDecl) ? recovered.namedDecl : void 0;
4691
+ if (recoveredAliasDecl !== void 0) {
4692
+ const aliasUnderlyingType = checker.getTypeFromTypeNode(recoveredAliasDecl.type);
4693
+ const isNonGeneric = recoveredAliasDecl.typeParameters === void 0 || recoveredAliasDecl.typeParameters.length === 0;
4694
+ if (isNonGeneric && (aliasUnderlyingType.isUnion() || isObjectType(aliasUnderlyingType))) {
4695
+ typeName = recovered.typeName;
4696
+ namedDecl = recovered.namedDecl;
4697
+ }
4698
+ } else {
4699
+ typeName = recovered.typeName;
4700
+ namedDecl = recovered.namedDecl;
4701
+ }
4702
+ }
4618
4703
  if (typeName && typeName in typeRegistry) {
4619
4704
  return { kind: "reference", name: typeName, typeArguments: [] };
4620
4705
  }
@@ -4646,6 +4731,10 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
4646
4731
  if (!typeName) {
4647
4732
  return result;
4648
4733
  }
4734
+ const existing = typeRegistry[typeName];
4735
+ if (existing !== void 0 && existing.type !== RESOLVING_TYPE_PLACEHOLDER) {
4736
+ return { kind: "reference", name: typeName, typeArguments: [] };
4737
+ }
4649
4738
  const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
4650
4739
  const metadata = namedDecl !== void 0 ? resolveNodeMetadata(
4651
4740
  metadataPolicy,
@@ -5769,9 +5858,9 @@ function findRegistrationByTypeName(registry, typeName) {
5769
5858
  }
5770
5859
 
5771
5860
  // src/validate/constraint-validator.ts
5772
- var import_internal5 = require("@formspec/analysis/internal");
5861
+ var import_internal6 = require("@formspec/analysis/internal");
5773
5862
  function validateFieldNode(ctx, field) {
5774
- const analysis = (0, import_internal5.analyzeConstraintTargets)(
5863
+ const analysis = (0, import_internal6.analyzeConstraintTargets)(
5775
5864
  field.name,
5776
5865
  field.type,
5777
5866
  field.constraints,
@@ -5789,7 +5878,7 @@ function validateFieldNode(ctx, field) {
5789
5878
  }
5790
5879
  function validateObjectProperty(ctx, parentName, property) {
5791
5880
  const qualifiedName = `${parentName}.${property.name}`;
5792
- const analysis = (0, import_internal5.analyzeConstraintTargets)(
5881
+ const analysis = (0, import_internal6.analyzeConstraintTargets)(
5793
5882
  qualifiedName,
5794
5883
  property.type,
5795
5884
  property.constraints,
@@ -6201,7 +6290,7 @@ function resolveModuleExportDeclaration(context, exportName = "default") {
6201
6290
 
6202
6291
  // src/generators/discovered-schema.ts
6203
6292
  var ts11 = __toESM(require("typescript"), 1);
6204
- var import_internal6 = require("@formspec/analysis/internal");
6293
+ var import_internal7 = require("@formspec/analysis/internal");
6205
6294
  var import_internals6 = require("@formspec/core/internals");
6206
6295
  function toDiscoveredTypeSchemas(result, resolvedMetadata) {
6207
6296
  return {
@@ -6558,7 +6647,7 @@ function generateSchemasFromReturnType(options) {
6558
6647
  }
6559
6648
  function resolveDeclarationMetadata(options) {
6560
6649
  const resolved = resolveStaticOptions(options);
6561
- const analysis = (0, import_internal6.analyzeMetadataForNodeWithChecker)({
6650
+ const analysis = (0, import_internal7.analyzeMetadataForNodeWithChecker)({
6562
6651
  checker: options.context.checker,
6563
6652
  node: options.declaration,
6564
6653
  metadata: resolved.metadata,
@@ -6801,7 +6890,7 @@ function annotationKey(annotation) {
6801
6890
 
6802
6891
  // src/index.ts
6803
6892
  function buildFormSchemas(form, options) {
6804
- const logger = options?.logger ?? import_core3.noopLogger;
6893
+ const logger = options?.logger ?? import_core4.noopLogger;
6805
6894
  logger.debug("buildFormSchemas: starting schema generation");
6806
6895
  return {
6807
6896
  jsonSchema: generateJsonSchema(form, options),
@@ -6818,7 +6907,7 @@ function writeSchemas(form, options) {
6818
6907
  metadata,
6819
6908
  logger: rawLogger
6820
6909
  } = options;
6821
- const logger = (rawLogger ?? import_core3.noopLogger).child({ stage: "write" });
6910
+ const logger = (rawLogger ?? import_core4.noopLogger).child({ stage: "write" });
6822
6911
  const buildOptions = vendorPrefix === void 0 && enumSerialization === void 0 && metadata === void 0 ? { logger: rawLogger } : {
6823
6912
  ...vendorPrefix !== void 0 && { vendorPrefix },
6824
6913
  ...enumSerialization !== void 0 && { enumSerialization },