@formspec/build 0.1.0-alpha.35 → 0.1.0-alpha.37

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
@@ -1656,6 +1656,21 @@ function isObjectType(type) {
1656
1656
  function isIntersectionType(type) {
1657
1657
  return !!(type.flags & ts3.TypeFlags.Intersection);
1658
1658
  }
1659
+ function isResolvableObjectLikeAliasTypeNode(typeNode) {
1660
+ if (ts3.isParenthesizedTypeNode(typeNode)) {
1661
+ return isResolvableObjectLikeAliasTypeNode(typeNode.type);
1662
+ }
1663
+ if (ts3.isTypeLiteralNode(typeNode) || ts3.isTypeReferenceNode(typeNode)) {
1664
+ return true;
1665
+ }
1666
+ return ts3.isIntersectionTypeNode(typeNode) && typeNode.types.length > 0 && typeNode.types.every((member) => isResolvableObjectLikeAliasTypeNode(member));
1667
+ }
1668
+ function isSemanticallyPlainObjectLikeType(type, checker) {
1669
+ if (isIntersectionType(type)) {
1670
+ return type.types.length > 0 && type.types.every((member) => isSemanticallyPlainObjectLikeType(member, checker));
1671
+ }
1672
+ return isObjectType(type) && checker.getSignaturesOfType(type, ts3.SignatureKind.Call).length === 0 && checker.getSignaturesOfType(type, ts3.SignatureKind.Construct).length === 0 && !checker.isArrayType(type) && !checker.isTupleType(type);
1673
+ }
1659
1674
  function isTypeReference(type) {
1660
1675
  return !!(type.flags & ts3.TypeFlags.Object) && !!(type.objectFlags & ts3.ObjectFlags.Reference);
1661
1676
  }
@@ -1719,6 +1734,35 @@ function resolveNodeMetadata(metadataPolicy, declarationKind, logicalName, node,
1719
1734
  }
1720
1735
  return resolvedMetadata;
1721
1736
  }
1737
+ function analyzeDeclarationRootInfo(declaration, checker, file = "", extensionRegistry, metadataPolicy) {
1738
+ const normalizedMetadataPolicy = createAnalyzerMetadataPolicy(metadataPolicy);
1739
+ const declarationType = checker.getTypeAtLocation(declaration);
1740
+ const logicalName = ts3.isClassDeclaration(declaration) ? declaration.name?.text ?? "AnonymousClass" : declaration.name.text;
1741
+ const docResult = extractJSDocParseResult(
1742
+ declaration,
1743
+ file,
1744
+ makeParseOptions(extensionRegistry, void 0, checker, declarationType, declarationType)
1745
+ );
1746
+ const metadata = resolveNodeMetadata(
1747
+ normalizedMetadataPolicy,
1748
+ "type",
1749
+ logicalName,
1750
+ declaration,
1751
+ checker,
1752
+ extensionRegistry,
1753
+ {
1754
+ checker,
1755
+ declaration,
1756
+ subjectType: declarationType,
1757
+ hostType: declarationType
1758
+ }
1759
+ );
1760
+ return {
1761
+ ...metadata !== void 0 && { metadata },
1762
+ annotations: docResult.annotations,
1763
+ diagnostics: docResult.diagnostics
1764
+ };
1765
+ }
1722
1766
  function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry, metadataPolicy, discriminatorOptions) {
1723
1767
  const normalizedMetadataPolicy = createAnalyzerMetadataPolicy(
1724
1768
  metadataPolicy,
@@ -1884,6 +1928,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
1884
1928
  const kindDesc = ts3.SyntaxKind[typeAlias.type.kind] ?? "unknown";
1885
1929
  return {
1886
1930
  ok: false,
1931
+ kind: "not-object-like",
1887
1932
  error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object-like type alias (found ${kindDesc})`
1888
1933
  };
1889
1934
  }
@@ -1898,6 +1943,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
1898
1943
  const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
1899
1944
  return {
1900
1945
  ok: false,
1946
+ kind: "duplicate-properties",
1901
1947
  error: `Type alias "${name}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
1902
1948
  };
1903
1949
  }
@@ -2594,10 +2640,10 @@ function findDuplicateObjectLikeTypeAliasPropertyNames(members) {
2594
2640
  return [...duplicates].sort();
2595
2641
  }
2596
2642
  function getAnalyzableObjectLikePropertyName(name) {
2597
- if (!ts3.isIdentifier(name)) {
2598
- return null;
2643
+ if (ts3.isIdentifier(name) || ts3.isStringLiteral(name) || ts3.isNumericLiteral(name)) {
2644
+ return name.text;
2599
2645
  }
2600
- return name.text;
2646
+ return null;
2601
2647
  }
2602
2648
  function applyEnumMemberDisplayNames(type, annotations) {
2603
2649
  if (!annotations.some(
@@ -2688,7 +2734,7 @@ function resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, ch
2688
2734
  };
2689
2735
  }
2690
2736
  if (ts3.isTypeReferenceNode(typeNode) && ts3.isIdentifier(typeNode.typeName)) {
2691
- const aliasDecl = checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts3.isTypeAliasDeclaration);
2737
+ const aliasDecl = getTypeAliasDeclarationFromTypeReference(typeNode, checker);
2692
2738
  if (aliasDecl !== void 0) {
2693
2739
  return resolveRegisteredCustomTypeFromTypeNode(aliasDecl.type, extensionRegistry, checker);
2694
2740
  }
@@ -2807,6 +2853,19 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
2807
2853
  diagnostics
2808
2854
  );
2809
2855
  }
2856
+ if (resolvedSourceTypeNode !== void 0 && isResolvableObjectLikeAliasTypeNode(resolvedSourceTypeNode) && isSemanticallyPlainObjectLikeType(type, checker)) {
2857
+ return resolveObjectType(
2858
+ type,
2859
+ checker,
2860
+ file,
2861
+ typeRegistry,
2862
+ visiting,
2863
+ sourceNode,
2864
+ metadataPolicy,
2865
+ extensionRegistry,
2866
+ diagnostics
2867
+ );
2868
+ }
2810
2869
  }
2811
2870
  if (isObjectType(type)) {
2812
2871
  return resolveObjectType(
@@ -2881,13 +2940,13 @@ function getReferencedTypeAliasDeclaration(sourceNode, checker) {
2881
2940
  if (!typeNode || !ts3.isTypeReferenceNode(typeNode)) {
2882
2941
  return void 0;
2883
2942
  }
2884
- return checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts3.isTypeAliasDeclaration);
2943
+ return getTypeAliasDeclarationFromTypeReference(typeNode, checker);
2885
2944
  }
2886
2945
  function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
2887
2946
  if (!ts3.isTypeReferenceNode(typeNode)) {
2888
2947
  return false;
2889
2948
  }
2890
- const aliasDecl = checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts3.isTypeAliasDeclaration);
2949
+ const aliasDecl = getTypeAliasDeclarationFromTypeReference(typeNode, checker);
2891
2950
  if (!aliasDecl) {
2892
2951
  return false;
2893
2952
  }
@@ -3456,8 +3515,7 @@ function resolveAliasedTypeNode(typeNode, checker, visited = /* @__PURE__ */ new
3456
3515
  if (!ts3.isTypeReferenceNode(typeNode) || !ts3.isIdentifier(typeNode.typeName)) {
3457
3516
  return typeNode;
3458
3517
  }
3459
- const symbol = checker.getSymbolAtLocation(typeNode.typeName);
3460
- const aliasDecl = symbol?.declarations?.find(ts3.isTypeAliasDeclaration);
3518
+ const aliasDecl = getTypeAliasDeclarationFromTypeReference(typeNode, checker);
3461
3519
  if (aliasDecl === void 0 || visited.has(aliasDecl)) {
3462
3520
  return typeNode;
3463
3521
  }
@@ -3507,8 +3565,7 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
3507
3565
  );
3508
3566
  }
3509
3567
  const symbol = checker.getSymbolAtLocation(typeNode.typeName);
3510
- if (!symbol?.declarations) return [];
3511
- const aliasDecl = symbol.declarations.find(ts3.isTypeAliasDeclaration);
3568
+ const aliasDecl = getAliasedTypeAliasDeclaration(symbol, checker);
3512
3569
  if (!aliasDecl) return [];
3513
3570
  if (ts3.isTypeLiteralNode(aliasDecl.type)) return [];
3514
3571
  const aliasFieldType = resolveTypeNode(
@@ -3531,6 +3588,18 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
3531
3588
  );
3532
3589
  return constraints;
3533
3590
  }
3591
+ function getAliasedSymbol(symbol, checker) {
3592
+ if (symbol === void 0) {
3593
+ return void 0;
3594
+ }
3595
+ return symbol.flags & ts3.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
3596
+ }
3597
+ function getAliasedTypeAliasDeclaration(symbol, checker) {
3598
+ return getAliasedSymbol(symbol, checker)?.declarations?.find(ts3.isTypeAliasDeclaration);
3599
+ }
3600
+ function getTypeAliasDeclarationFromTypeReference(typeNode, checker) {
3601
+ return getAliasedTypeAliasDeclaration(checker.getSymbolAtLocation(typeNode.typeName), checker);
3602
+ }
3534
3603
  function provenanceForNode(node, file) {
3535
3604
  const sourceFile = node.getSourceFile();
3536
3605
  const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
@@ -3704,6 +3773,95 @@ function findInterfaceByName(sourceFile, interfaceName) {
3704
3773
  function findTypeAliasByName(sourceFile, aliasName) {
3705
3774
  return findNodeByName(sourceFile, aliasName, ts4.isTypeAliasDeclaration, (n) => n.name.text);
3706
3775
  }
3776
+ function getResolvedObjectRootType(rootType, typeRegistry) {
3777
+ if (rootType.kind === "object") {
3778
+ return rootType;
3779
+ }
3780
+ if (rootType.kind !== "reference") {
3781
+ return null;
3782
+ }
3783
+ const definition = typeRegistry[rootType.name];
3784
+ return definition?.type.kind === "object" ? definition.type : null;
3785
+ }
3786
+ function createResolvedObjectAliasAnalysis(name, rootType, typeRegistry, rootInfo, diagnostics) {
3787
+ const resolvedRootType = getResolvedObjectRootType(rootType, typeRegistry);
3788
+ if (resolvedRootType === null) {
3789
+ return null;
3790
+ }
3791
+ const fields = resolvedRootType.properties.map((property) => ({
3792
+ kind: "field",
3793
+ name: property.name,
3794
+ ...property.metadata !== void 0 && { metadata: property.metadata },
3795
+ type: property.type,
3796
+ required: !property.optional,
3797
+ constraints: property.constraints,
3798
+ annotations: property.annotations,
3799
+ provenance: property.provenance
3800
+ }));
3801
+ return {
3802
+ name,
3803
+ ...rootInfo.metadata !== void 0 && { metadata: rootInfo.metadata },
3804
+ fields,
3805
+ fieldLayouts: fields.map(() => ({})),
3806
+ typeRegistry,
3807
+ ...rootInfo.annotations.length > 0 && { annotations: [...rootInfo.annotations] },
3808
+ ...diagnostics.length > 0 && { diagnostics: [...diagnostics] },
3809
+ instanceMethods: [],
3810
+ staticMethods: []
3811
+ };
3812
+ }
3813
+ function containsTypeReferenceInObjectLikeAlias(typeNode) {
3814
+ if (ts4.isParenthesizedTypeNode(typeNode)) {
3815
+ return containsTypeReferenceInObjectLikeAlias(typeNode.type);
3816
+ }
3817
+ if (ts4.isTypeReferenceNode(typeNode)) {
3818
+ return true;
3819
+ }
3820
+ return ts4.isIntersectionTypeNode(typeNode) && typeNode.types.some((member) => containsTypeReferenceInObjectLikeAlias(member));
3821
+ }
3822
+ function collectFallbackAliasMemberPropertyNames(typeNode, checker) {
3823
+ if (ts4.isParenthesizedTypeNode(typeNode)) {
3824
+ return collectFallbackAliasMemberPropertyNames(typeNode.type, checker);
3825
+ }
3826
+ if (ts4.isTypeLiteralNode(typeNode)) {
3827
+ const propertyNames = [];
3828
+ for (const member of typeNode.members) {
3829
+ if (!ts4.isPropertySignature(member)) {
3830
+ continue;
3831
+ }
3832
+ const propertyName = getAnalyzableObjectLikePropertyName(member.name);
3833
+ if (propertyName !== null) {
3834
+ propertyNames.push(propertyName);
3835
+ }
3836
+ }
3837
+ return propertyNames;
3838
+ }
3839
+ if (ts4.isTypeReferenceNode(typeNode)) {
3840
+ return checker.getTypeFromTypeNode(typeNode).getProperties().map((property) => property.getName());
3841
+ }
3842
+ return null;
3843
+ }
3844
+ function findFallbackAliasDuplicatePropertyNames(typeNode, checker) {
3845
+ if (!ts4.isIntersectionTypeNode(typeNode)) {
3846
+ return [];
3847
+ }
3848
+ const seen = /* @__PURE__ */ new Set();
3849
+ const duplicates = /* @__PURE__ */ new Set();
3850
+ for (const member of typeNode.types) {
3851
+ const propertyNames = collectFallbackAliasMemberPropertyNames(member, checker);
3852
+ if (propertyNames === null) {
3853
+ continue;
3854
+ }
3855
+ for (const propertyName of propertyNames) {
3856
+ if (seen.has(propertyName)) {
3857
+ duplicates.add(propertyName);
3858
+ } else {
3859
+ seen.add(propertyName);
3860
+ }
3861
+ }
3862
+ }
3863
+ return [...duplicates].sort();
3864
+ }
3707
3865
  function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry, metadataPolicy, discriminatorOptions) {
3708
3866
  const analysisFilePath = path.resolve(filePath);
3709
3867
  const classDecl = findClassByName(ctx.sourceFile, typeName);
@@ -3741,6 +3899,51 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
3741
3899
  if (result.ok) {
3742
3900
  return result.analysis;
3743
3901
  }
3902
+ const fallbackEligible = result.kind === "not-object-like" && isResolvableObjectLikeAliasTypeNode(typeAlias.type) && containsTypeReferenceInObjectLikeAlias(typeAlias.type);
3903
+ if (!fallbackEligible) {
3904
+ throw new Error(result.error);
3905
+ }
3906
+ const duplicatePropertyNames = findFallbackAliasDuplicatePropertyNames(
3907
+ typeAlias.type,
3908
+ ctx.checker
3909
+ );
3910
+ if (duplicatePropertyNames.length > 0) {
3911
+ const sourceFile = typeAlias.getSourceFile();
3912
+ const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
3913
+ throw new Error(
3914
+ `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
3915
+ );
3916
+ }
3917
+ const rootInfo = analyzeDeclarationRootInfo(
3918
+ typeAlias,
3919
+ ctx.checker,
3920
+ analysisFilePath,
3921
+ extensionRegistry,
3922
+ metadataPolicy
3923
+ );
3924
+ const diagnostics = [...rootInfo.diagnostics];
3925
+ const typeRegistry = {};
3926
+ const rootType = resolveTypeNode(
3927
+ ctx.checker.getTypeAtLocation(typeAlias),
3928
+ ctx.checker,
3929
+ analysisFilePath,
3930
+ typeRegistry,
3931
+ /* @__PURE__ */ new Set(),
3932
+ typeAlias,
3933
+ createAnalyzerMetadataPolicy(metadataPolicy, discriminatorOptions),
3934
+ extensionRegistry,
3935
+ diagnostics
3936
+ );
3937
+ const fallbackAnalysis = createResolvedObjectAliasAnalysis(
3938
+ typeAlias.name.text,
3939
+ rootType,
3940
+ typeRegistry,
3941
+ rootInfo,
3942
+ diagnostics
3943
+ );
3944
+ if (fallbackAnalysis !== null) {
3945
+ return fallbackAnalysis;
3946
+ }
3744
3947
  throw new Error(result.error);
3745
3948
  }
3746
3949
  throw new Error(