@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/README.md +1 -1
- package/dist/analyzer/class-analyzer.d.ts +4 -0
- package/dist/analyzer/class-analyzer.d.ts.map +1 -1
- package/dist/analyzer/program.d.ts.map +1 -1
- package/dist/build-alpha.d.ts +2 -0
- package/dist/build-beta.d.ts +2 -0
- package/dist/build-internal.d.ts +2 -0
- package/dist/build.d.ts +2 -0
- package/dist/cli.cjs +207 -12
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +207 -12
- package/dist/cli.js.map +1 -1
- package/dist/generators/discovered-schema.d.ts +2 -0
- package/dist/generators/discovered-schema.d.ts.map +1 -1
- package/dist/index.cjs +207 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +207 -12
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +213 -10
- package/dist/internals.cjs.map +1 -1
- package/dist/internals.js +213 -10
- package/dist/internals.js.map +1 -1
- package/package.json +2 -2
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 (
|
|
2598
|
-
return
|
|
2643
|
+
if (ts3.isIdentifier(name) || ts3.isStringLiteral(name) || ts3.isNumericLiteral(name)) {
|
|
2644
|
+
return name.text;
|
|
2599
2645
|
}
|
|
2600
|
-
return
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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(
|