@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/cli.js CHANGED
@@ -1219,10 +1219,11 @@ function generatePrimitiveType(type) {
1219
1219
  function generateEnumType(type, ctx) {
1220
1220
  if (ctx.enumSerialization === "oneOf") {
1221
1221
  return {
1222
- oneOf: type.members.map((m) => ({
1223
- const: m.value,
1224
- title: m.displayName ?? String(m.value)
1225
- }))
1222
+ oneOf: type.members.map((m) => {
1223
+ const stringValue = String(m.value);
1224
+ const title = m.displayName !== void 0 && m.displayName !== stringValue ? m.displayName : void 0;
1225
+ return title !== void 0 ? { const: m.value, title } : { const: m.value };
1226
+ })
1226
1227
  };
1227
1228
  }
1228
1229
  const schema = { enum: type.members.map((m) => m.value) };
@@ -2042,7 +2043,8 @@ import {
2042
2043
  } from "@formspec/core/internals";
2043
2044
  import {
2044
2045
  getTagDefinition,
2045
- normalizeFormSpecTagName
2046
+ normalizeFormSpecTagName,
2047
+ getSyntheticLogger
2046
2048
  } from "@formspec/analysis/internal";
2047
2049
  function buildConstraintTagSources(extensions) {
2048
2050
  return extensions.map((extension) => ({
@@ -2055,6 +2057,11 @@ function buildConstraintTagSources(extensions) {
2055
2057
  }));
2056
2058
  }
2057
2059
  function createExtensionRegistry(extensions) {
2060
+ const registryLog = getSyntheticLogger();
2061
+ registryLog.debug("createExtensionRegistry: constructing", {
2062
+ extensionCount: extensions.length,
2063
+ extensionIds: extensions.map((e) => e.extensionId)
2064
+ });
2058
2065
  const reservedTagSources = buildConstraintTagSources(extensions);
2059
2066
  let symbolMap = /* @__PURE__ */ new Map();
2060
2067
  const typeMap = /* @__PURE__ */ new Map();
@@ -2186,6 +2193,14 @@ function createExtensionRegistry(extensions) {
2186
2193
  }
2187
2194
  }
2188
2195
  }
2196
+ registryLog.debug("createExtensionRegistry: complete", {
2197
+ typeCount: typeMap.size,
2198
+ constraintCount: constraintMap.size,
2199
+ constraintTagCount: constraintTagMap.size,
2200
+ broadeningCount: builtinBroadeningMap.size,
2201
+ annotationCount: annotationMap.size,
2202
+ metadataSlotCount: metadataSlotMap.size
2203
+ });
2189
2204
  return {
2190
2205
  extensions,
2191
2206
  findType: (typeId) => typeMap.get(typeId),
@@ -2449,6 +2464,16 @@ import {
2449
2464
  isBuiltinConstraintName
2450
2465
  } from "@formspec/core/internals";
2451
2466
  import "@formspec/core/internals";
2467
+ import { noopLogger as noopLogger4 } from "@formspec/core";
2468
+ import {
2469
+ getBuildLogger,
2470
+ getBroadeningLogger,
2471
+ getSyntheticLogger as getSyntheticLogger2,
2472
+ describeTypeKind,
2473
+ elapsedMicros,
2474
+ nowMicros,
2475
+ logTagApplication
2476
+ } from "@formspec/analysis/internal";
2452
2477
  function sharedTagValueOptions(options) {
2453
2478
  return {
2454
2479
  ...options?.extensionRegistry !== void 0 ? { registry: options.extensionRegistry } : {},
@@ -2852,56 +2877,82 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2852
2877
  if (definition === null) {
2853
2878
  return [];
2854
2879
  }
2880
+ const nonNullPlacement = placement;
2881
+ const log2 = getBuildLogger();
2882
+ const broadeningLog = getBroadeningLogger();
2883
+ const syntheticLog = getSyntheticLogger2();
2884
+ const logsEnabled = log2 !== noopLogger4 || broadeningLog !== noopLogger4;
2885
+ const syntheticTraceEnabled = syntheticLog !== noopLogger4;
2886
+ const logStart = logsEnabled ? nowMicros() : 0;
2887
+ const subjectTypeKind = logsEnabled ? describeTypeKind(subjectType, checker) : "";
2888
+ function emit(outcome, result2) {
2889
+ if (!logsEnabled) {
2890
+ return result2;
2891
+ }
2892
+ const entry = {
2893
+ consumer: "build",
2894
+ tag: tagName,
2895
+ placement: nonNullPlacement,
2896
+ subjectTypeKind,
2897
+ roleOutcome: outcome,
2898
+ elapsedMicros: elapsedMicros(logStart)
2899
+ };
2900
+ logTagApplication(log2, entry);
2901
+ if (outcome === "bypass" || outcome === "D1" || outcome === "D2") {
2902
+ logTagApplication(broadeningLog, entry);
2903
+ }
2904
+ return result2;
2905
+ }
2855
2906
  if (!definition.placements.includes(placement)) {
2856
- return [
2907
+ return emit("A-reject", [
2857
2908
  makeDiagnostic(
2858
2909
  "INVALID_TAG_PLACEMENT",
2859
2910
  `Tag "@${tagName}" is not allowed on ${placementLabel(placement)}.`,
2860
2911
  provenance
2861
2912
  )
2862
- ];
2913
+ ]);
2863
2914
  }
2864
2915
  const target = parsedTag?.target ?? null;
2865
2916
  let evaluatedType = subjectType;
2866
2917
  let targetLabel = node.getText(sourceFile);
2867
2918
  if (target !== null) {
2868
2919
  if (target.kind !== "path") {
2869
- return [
2920
+ return emit("B-reject", [
2870
2921
  makeDiagnostic(
2871
2922
  "UNSUPPORTED_TARGETING_SYNTAX",
2872
2923
  `Tag "@${tagName}" does not support ${target.kind} targeting syntax.`,
2873
2924
  provenance
2874
2925
  )
2875
- ];
2926
+ ]);
2876
2927
  }
2877
2928
  if (!target.valid || target.path === null) {
2878
- return [
2929
+ return emit("B-reject", [
2879
2930
  makeDiagnostic(
2880
2931
  "UNSUPPORTED_TARGETING_SYNTAX",
2881
2932
  `Tag "@${tagName}" has invalid path targeting syntax.`,
2882
2933
  provenance
2883
2934
  )
2884
- ];
2935
+ ]);
2885
2936
  }
2886
2937
  const resolution = resolvePathTargetType(subjectType, checker, target.path.segments);
2887
2938
  if (resolution.kind === "missing-property") {
2888
- return [
2939
+ return emit("B-reject", [
2889
2940
  makeDiagnostic(
2890
2941
  "UNKNOWN_PATH_TARGET",
2891
2942
  `Target "${target.rawText}": path-targeted constraint "${tagName}" references unknown path segment "${resolution.segment}"`,
2892
2943
  provenance
2893
2944
  )
2894
- ];
2945
+ ]);
2895
2946
  }
2896
2947
  if (resolution.kind === "unresolvable") {
2897
2948
  const actualType = checker.typeToString(resolution.type, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
2898
- return [
2949
+ return emit("B-reject", [
2899
2950
  makeDiagnostic(
2900
2951
  "TYPE_MISMATCH",
2901
2952
  `Target "${target.rawText}": path-targeted constraint "${tagName}" is invalid because type "${actualType}" cannot be traversed`,
2902
2953
  provenance
2903
2954
  )
2904
- ];
2955
+ ]);
2905
2956
  }
2906
2957
  evaluatedType = resolution.type;
2907
2958
  targetLabel = target.rawText;
@@ -2930,13 +2981,13 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2930
2981
  tagName,
2931
2982
  parsedTag?.argumentText
2932
2983
  ) : null;
2933
- return [
2984
+ return emit("B-reject", [
2934
2985
  makeDiagnostic(
2935
2986
  "TYPE_MISMATCH",
2936
2987
  hint === null ? baseMessage : `${baseMessage}. ${hint}`,
2937
2988
  provenance
2938
2989
  )
2939
- ];
2990
+ ]);
2940
2991
  }
2941
2992
  }
2942
2993
  const argumentExpression = renderSyntheticArgumentExpression(
@@ -2944,14 +2995,23 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2944
2995
  parsedTag?.argumentText ?? ""
2945
2996
  );
2946
2997
  if (definition.requiresArgument && argumentExpression === null) {
2947
- return [];
2998
+ return emit("A-pass", []);
2948
2999
  }
2949
3000
  if (hasBroadening) {
2950
- return [];
3001
+ return emit("bypass", []);
2951
3002
  }
2952
3003
  const subjectTypeText = checker.typeToString(subjectType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
2953
3004
  const hostType = options?.hostType ?? subjectType;
2954
3005
  const hostTypeText = checker.typeToString(hostType, node, SYNTHETIC_TYPE_FORMAT_FLAGS);
3006
+ if (syntheticTraceEnabled) {
3007
+ syntheticLog.trace("invoking synthetic checker", {
3008
+ consumer: "build",
3009
+ tag: tagName,
3010
+ placement,
3011
+ subjectTypeKind,
3012
+ subjectTypeText
3013
+ });
3014
+ }
2955
3015
  const result = checkSyntheticTagApplication({
2956
3016
  tagName,
2957
3017
  placement,
@@ -2978,26 +3038,26 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
2978
3038
  } : {}
2979
3039
  });
2980
3040
  if (result.diagnostics.length === 0) {
2981
- return [];
3041
+ return emit("C-pass", []);
2982
3042
  }
2983
3043
  const setupDiagnostic = result.diagnostics.find((diagnostic) => diagnostic.kind !== "typescript");
2984
3044
  if (setupDiagnostic !== void 0) {
2985
- return [
3045
+ return emit("C-reject", [
2986
3046
  makeDiagnostic(
2987
3047
  setupDiagnostic.kind === "unsupported-custom-type-override" ? "UNSUPPORTED_CUSTOM_TYPE_OVERRIDE" : "SYNTHETIC_SETUP_FAILURE",
2988
3048
  setupDiagnostic.message,
2989
3049
  provenance
2990
3050
  )
2991
- ];
3051
+ ]);
2992
3052
  }
2993
3053
  const expectedLabel = definition.valueKind === null ? "compatible argument" : capabilityLabel(definition.valueKind);
2994
- return [
3054
+ return emit("C-reject", [
2995
3055
  makeDiagnostic(
2996
3056
  "TYPE_MISMATCH",
2997
3057
  `Tag "@${tagName}" received an invalid argument for ${expectedLabel}.`,
2998
3058
  provenance
2999
3059
  )
3000
- ];
3060
+ ]);
3001
3061
  }
3002
3062
  function getExtensionTagNames(options) {
3003
3063
  return [
@@ -4175,6 +4235,22 @@ function extractReferenceTypeArguments(type, checker, file, typeRegistry, visiti
4175
4235
  }
4176
4236
  return referenceTypeNode.typeArguments.map((argumentNode) => {
4177
4237
  const argumentType = checker.getTypeFromTypeNode(argumentNode);
4238
+ const baseSymbol = argumentType.aliasSymbol ?? argumentType.getSymbol();
4239
+ const argumentSymbol = baseSymbol !== void 0 && baseSymbol.flags & ts6.SymbolFlags.Alias ? checker.getAliasedSymbol(baseSymbol) : baseSymbol;
4240
+ const argumentDecl = argumentSymbol?.declarations?.[0];
4241
+ if (argumentDecl !== void 0 && argumentDecl.getSourceFile().fileName !== file) {
4242
+ const argumentName = argumentSymbol?.getName() ?? baseSymbol?.getName();
4243
+ if (argumentName !== void 0) {
4244
+ return {
4245
+ tsType: argumentType,
4246
+ typeNode: {
4247
+ kind: "reference",
4248
+ name: argumentName,
4249
+ typeArguments: []
4250
+ }
4251
+ };
4252
+ }
4253
+ }
4178
4254
  return {
4179
4255
  tsType: argumentType,
4180
4256
  typeNode: resolveTypeNode(
@@ -4441,22 +4517,10 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
4441
4517
  sourceNode
4442
4518
  );
4443
4519
  if (customTypeLookup !== null) {
4444
- const typeId = customTypeIdFromLookup(customTypeLookup);
4445
- let payload = null;
4446
- if (customTypeLookup.registration.extractPayload !== void 0) {
4447
- try {
4448
- payload = customTypeLookup.registration.extractPayload(type, checker) ?? null;
4449
- } catch (cause) {
4450
- throw new Error(
4451
- `extractPayload for custom type "${customTypeLookup.registration.typeName}" in extension "${customTypeLookup.extensionId}" threw`,
4452
- { cause }
4453
- );
4454
- }
4455
- }
4456
4520
  return {
4457
4521
  kind: "custom",
4458
- typeId,
4459
- payload
4522
+ typeId: customTypeIdFromLookup(customTypeLookup),
4523
+ payload: null
4460
4524
  };
4461
4525
  }
4462
4526
  const primitiveAlias = tryResolveNamedPrimitiveAlias(
@@ -4640,6 +4704,21 @@ function getReferencedTypeAliasDeclaration(sourceNode, checker) {
4640
4704
  }
4641
4705
  return getTypeAliasDeclarationFromTypeReference(typeNode, checker);
4642
4706
  }
4707
+ function resolveNamedTypeWithSourceRecovery(type, sourceNode, checker) {
4708
+ const typeName = getNamedTypeName(type);
4709
+ const namedDecl = getNamedTypeDeclaration(type);
4710
+ if (typeName !== null && namedDecl !== void 0) {
4711
+ return { typeName, namedDecl };
4712
+ }
4713
+ if (sourceNode === void 0) {
4714
+ return null;
4715
+ }
4716
+ const refAliasDecl = getReferencedTypeAliasDeclaration(sourceNode, checker);
4717
+ if (refAliasDecl === void 0) {
4718
+ return null;
4719
+ }
4720
+ return { typeName: refAliasDecl.name.text, namedDecl: refAliasDecl };
4721
+ }
4643
4722
  function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
4644
4723
  if (!ts6.isTypeReferenceNode(typeNode)) {
4645
4724
  return false;
@@ -4698,8 +4777,23 @@ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiti
4698
4777
  );
4699
4778
  }
4700
4779
  function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
4701
- const typeName = getNamedTypeName(type);
4702
- const namedDecl = getNamedTypeDeclaration(type);
4780
+ const recovered = resolveNamedTypeWithSourceRecovery(type, sourceNode, checker);
4781
+ let typeName = null;
4782
+ let namedDecl;
4783
+ if (recovered !== null) {
4784
+ const recoveredAliasDecl = ts6.isTypeAliasDeclaration(recovered.namedDecl) ? recovered.namedDecl : void 0;
4785
+ if (recoveredAliasDecl !== void 0) {
4786
+ const aliasUnderlyingType = checker.getTypeFromTypeNode(recoveredAliasDecl.type);
4787
+ const isNonGeneric = recoveredAliasDecl.typeParameters === void 0 || recoveredAliasDecl.typeParameters.length === 0;
4788
+ if (isNonGeneric && (aliasUnderlyingType.isUnion() || isObjectType(aliasUnderlyingType))) {
4789
+ typeName = recovered.typeName;
4790
+ namedDecl = recovered.namedDecl;
4791
+ }
4792
+ } else {
4793
+ typeName = recovered.typeName;
4794
+ namedDecl = recovered.namedDecl;
4795
+ }
4796
+ }
4703
4797
  if (typeName && typeName in typeRegistry) {
4704
4798
  return { kind: "reference", name: typeName, typeArguments: [] };
4705
4799
  }
@@ -4731,6 +4825,10 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
4731
4825
  if (!typeName) {
4732
4826
  return result;
4733
4827
  }
4828
+ const existing = typeRegistry[typeName];
4829
+ if (existing !== void 0 && existing.type !== RESOLVING_TYPE_PLACEHOLDER) {
4830
+ return { kind: "reference", name: typeName, typeArguments: [] };
4831
+ }
4734
4832
  const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
4735
4833
  const metadata = namedDecl !== void 0 ? resolveNodeMetadata(
4736
4834
  metadataPolicy,
@@ -6995,11 +7093,11 @@ __export(index_exports, {
6995
7093
  uiSchemaSchema: () => uiSchema,
6996
7094
  writeSchemas: () => writeSchemas
6997
7095
  });
6998
- import { noopLogger as noopLogger4 } from "@formspec/core";
7096
+ import { noopLogger as noopLogger5 } from "@formspec/core";
6999
7097
  import * as fs from "fs";
7000
7098
  import * as path3 from "path";
7001
7099
  function buildFormSchemas(form, options) {
7002
- const logger = options?.logger ?? noopLogger4;
7100
+ const logger = options?.logger ?? noopLogger5;
7003
7101
  logger.debug("buildFormSchemas: starting schema generation");
7004
7102
  return {
7005
7103
  jsonSchema: generateJsonSchema(form, options),
@@ -7016,7 +7114,7 @@ function writeSchemas(form, options) {
7016
7114
  metadata,
7017
7115
  logger: rawLogger
7018
7116
  } = options;
7019
- const logger = (rawLogger ?? noopLogger4).child({ stage: "write" });
7117
+ const logger = (rawLogger ?? noopLogger5).child({ stage: "write" });
7020
7118
  const buildOptions = vendorPrefix === void 0 && enumSerialization === void 0 && metadata === void 0 ? { logger: rawLogger } : {
7021
7119
  ...vendorPrefix !== void 0 && { vendorPrefix },
7022
7120
  ...enumSerialization !== void 0 && { enumSerialization },