@formspec/build 0.1.0-alpha.36 → 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(
@@ -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(
@@ -3714,6 +3773,95 @@ function findInterfaceByName(sourceFile, interfaceName) {
3714
3773
  function findTypeAliasByName(sourceFile, aliasName) {
3715
3774
  return findNodeByName(sourceFile, aliasName, ts4.isTypeAliasDeclaration, (n) => n.name.text);
3716
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
+ }
3717
3865
  function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry, metadataPolicy, discriminatorOptions) {
3718
3866
  const analysisFilePath = path.resolve(filePath);
3719
3867
  const classDecl = findClassByName(ctx.sourceFile, typeName);
@@ -3751,6 +3899,51 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
3751
3899
  if (result.ok) {
3752
3900
  return result.analysis;
3753
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
+ }
3754
3947
  throw new Error(result.error);
3755
3948
  }
3756
3949
  throw new Error(