@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.cjs
CHANGED
|
@@ -1680,6 +1680,21 @@ function isObjectType(type) {
|
|
|
1680
1680
|
function isIntersectionType(type) {
|
|
1681
1681
|
return !!(type.flags & ts3.TypeFlags.Intersection);
|
|
1682
1682
|
}
|
|
1683
|
+
function isResolvableObjectLikeAliasTypeNode(typeNode) {
|
|
1684
|
+
if (ts3.isParenthesizedTypeNode(typeNode)) {
|
|
1685
|
+
return isResolvableObjectLikeAliasTypeNode(typeNode.type);
|
|
1686
|
+
}
|
|
1687
|
+
if (ts3.isTypeLiteralNode(typeNode) || ts3.isTypeReferenceNode(typeNode)) {
|
|
1688
|
+
return true;
|
|
1689
|
+
}
|
|
1690
|
+
return ts3.isIntersectionTypeNode(typeNode) && typeNode.types.length > 0 && typeNode.types.every((member) => isResolvableObjectLikeAliasTypeNode(member));
|
|
1691
|
+
}
|
|
1692
|
+
function isSemanticallyPlainObjectLikeType(type, checker) {
|
|
1693
|
+
if (isIntersectionType(type)) {
|
|
1694
|
+
return type.types.length > 0 && type.types.every((member) => isSemanticallyPlainObjectLikeType(member, checker));
|
|
1695
|
+
}
|
|
1696
|
+
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);
|
|
1697
|
+
}
|
|
1683
1698
|
function isTypeReference(type) {
|
|
1684
1699
|
return !!(type.flags & ts3.TypeFlags.Object) && !!(type.objectFlags & ts3.ObjectFlags.Reference);
|
|
1685
1700
|
}
|
|
@@ -1743,6 +1758,35 @@ function resolveNodeMetadata(metadataPolicy, declarationKind, logicalName, node,
|
|
|
1743
1758
|
}
|
|
1744
1759
|
return resolvedMetadata;
|
|
1745
1760
|
}
|
|
1761
|
+
function analyzeDeclarationRootInfo(declaration, checker, file = "", extensionRegistry, metadataPolicy) {
|
|
1762
|
+
const normalizedMetadataPolicy = createAnalyzerMetadataPolicy(metadataPolicy);
|
|
1763
|
+
const declarationType = checker.getTypeAtLocation(declaration);
|
|
1764
|
+
const logicalName = ts3.isClassDeclaration(declaration) ? declaration.name?.text ?? "AnonymousClass" : declaration.name.text;
|
|
1765
|
+
const docResult = extractJSDocParseResult(
|
|
1766
|
+
declaration,
|
|
1767
|
+
file,
|
|
1768
|
+
makeParseOptions(extensionRegistry, void 0, checker, declarationType, declarationType)
|
|
1769
|
+
);
|
|
1770
|
+
const metadata = resolveNodeMetadata(
|
|
1771
|
+
normalizedMetadataPolicy,
|
|
1772
|
+
"type",
|
|
1773
|
+
logicalName,
|
|
1774
|
+
declaration,
|
|
1775
|
+
checker,
|
|
1776
|
+
extensionRegistry,
|
|
1777
|
+
{
|
|
1778
|
+
checker,
|
|
1779
|
+
declaration,
|
|
1780
|
+
subjectType: declarationType,
|
|
1781
|
+
hostType: declarationType
|
|
1782
|
+
}
|
|
1783
|
+
);
|
|
1784
|
+
return {
|
|
1785
|
+
...metadata !== void 0 && { metadata },
|
|
1786
|
+
annotations: docResult.annotations,
|
|
1787
|
+
diagnostics: docResult.diagnostics
|
|
1788
|
+
};
|
|
1789
|
+
}
|
|
1746
1790
|
function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry, metadataPolicy, discriminatorOptions) {
|
|
1747
1791
|
const normalizedMetadataPolicy = createAnalyzerMetadataPolicy(
|
|
1748
1792
|
metadataPolicy,
|
|
@@ -1908,6 +1952,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
|
|
|
1908
1952
|
const kindDesc = ts3.SyntaxKind[typeAlias.type.kind] ?? "unknown";
|
|
1909
1953
|
return {
|
|
1910
1954
|
ok: false,
|
|
1955
|
+
kind: "not-object-like",
|
|
1911
1956
|
error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object-like type alias (found ${kindDesc})`
|
|
1912
1957
|
};
|
|
1913
1958
|
}
|
|
@@ -1922,6 +1967,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
|
|
|
1922
1967
|
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
1923
1968
|
return {
|
|
1924
1969
|
ok: false,
|
|
1970
|
+
kind: "duplicate-properties",
|
|
1925
1971
|
error: `Type alias "${name}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
|
|
1926
1972
|
};
|
|
1927
1973
|
}
|
|
@@ -2618,10 +2664,10 @@ function findDuplicateObjectLikeTypeAliasPropertyNames(members) {
|
|
|
2618
2664
|
return [...duplicates].sort();
|
|
2619
2665
|
}
|
|
2620
2666
|
function getAnalyzableObjectLikePropertyName(name) {
|
|
2621
|
-
if (
|
|
2622
|
-
return
|
|
2667
|
+
if (ts3.isIdentifier(name) || ts3.isStringLiteral(name) || ts3.isNumericLiteral(name)) {
|
|
2668
|
+
return name.text;
|
|
2623
2669
|
}
|
|
2624
|
-
return
|
|
2670
|
+
return null;
|
|
2625
2671
|
}
|
|
2626
2672
|
function applyEnumMemberDisplayNames(type, annotations) {
|
|
2627
2673
|
if (!annotations.some(
|
|
@@ -2712,7 +2758,7 @@ function resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, ch
|
|
|
2712
2758
|
};
|
|
2713
2759
|
}
|
|
2714
2760
|
if (ts3.isTypeReferenceNode(typeNode) && ts3.isIdentifier(typeNode.typeName)) {
|
|
2715
|
-
const aliasDecl =
|
|
2761
|
+
const aliasDecl = getTypeAliasDeclarationFromTypeReference(typeNode, checker);
|
|
2716
2762
|
if (aliasDecl !== void 0) {
|
|
2717
2763
|
return resolveRegisteredCustomTypeFromTypeNode(aliasDecl.type, extensionRegistry, checker);
|
|
2718
2764
|
}
|
|
@@ -2831,6 +2877,19 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
2831
2877
|
diagnostics
|
|
2832
2878
|
);
|
|
2833
2879
|
}
|
|
2880
|
+
if (resolvedSourceTypeNode !== void 0 && isResolvableObjectLikeAliasTypeNode(resolvedSourceTypeNode) && isSemanticallyPlainObjectLikeType(type, checker)) {
|
|
2881
|
+
return resolveObjectType(
|
|
2882
|
+
type,
|
|
2883
|
+
checker,
|
|
2884
|
+
file,
|
|
2885
|
+
typeRegistry,
|
|
2886
|
+
visiting,
|
|
2887
|
+
sourceNode,
|
|
2888
|
+
metadataPolicy,
|
|
2889
|
+
extensionRegistry,
|
|
2890
|
+
diagnostics
|
|
2891
|
+
);
|
|
2892
|
+
}
|
|
2834
2893
|
}
|
|
2835
2894
|
if (isObjectType(type)) {
|
|
2836
2895
|
return resolveObjectType(
|
|
@@ -2905,13 +2964,13 @@ function getReferencedTypeAliasDeclaration(sourceNode, checker) {
|
|
|
2905
2964
|
if (!typeNode || !ts3.isTypeReferenceNode(typeNode)) {
|
|
2906
2965
|
return void 0;
|
|
2907
2966
|
}
|
|
2908
|
-
return
|
|
2967
|
+
return getTypeAliasDeclarationFromTypeReference(typeNode, checker);
|
|
2909
2968
|
}
|
|
2910
2969
|
function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
|
|
2911
2970
|
if (!ts3.isTypeReferenceNode(typeNode)) {
|
|
2912
2971
|
return false;
|
|
2913
2972
|
}
|
|
2914
|
-
const aliasDecl =
|
|
2973
|
+
const aliasDecl = getTypeAliasDeclarationFromTypeReference(typeNode, checker);
|
|
2915
2974
|
if (!aliasDecl) {
|
|
2916
2975
|
return false;
|
|
2917
2976
|
}
|
|
@@ -3480,8 +3539,7 @@ function resolveAliasedTypeNode(typeNode, checker, visited = /* @__PURE__ */ new
|
|
|
3480
3539
|
if (!ts3.isTypeReferenceNode(typeNode) || !ts3.isIdentifier(typeNode.typeName)) {
|
|
3481
3540
|
return typeNode;
|
|
3482
3541
|
}
|
|
3483
|
-
const
|
|
3484
|
-
const aliasDecl = symbol?.declarations?.find(ts3.isTypeAliasDeclaration);
|
|
3542
|
+
const aliasDecl = getTypeAliasDeclarationFromTypeReference(typeNode, checker);
|
|
3485
3543
|
if (aliasDecl === void 0 || visited.has(aliasDecl)) {
|
|
3486
3544
|
return typeNode;
|
|
3487
3545
|
}
|
|
@@ -3531,8 +3589,7 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
|
|
|
3531
3589
|
);
|
|
3532
3590
|
}
|
|
3533
3591
|
const symbol = checker.getSymbolAtLocation(typeNode.typeName);
|
|
3534
|
-
|
|
3535
|
-
const aliasDecl = symbol.declarations.find(ts3.isTypeAliasDeclaration);
|
|
3592
|
+
const aliasDecl = getAliasedTypeAliasDeclaration(symbol, checker);
|
|
3536
3593
|
if (!aliasDecl) return [];
|
|
3537
3594
|
if (ts3.isTypeLiteralNode(aliasDecl.type)) return [];
|
|
3538
3595
|
const aliasFieldType = resolveTypeNode(
|
|
@@ -3555,6 +3612,18 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
|
|
|
3555
3612
|
);
|
|
3556
3613
|
return constraints;
|
|
3557
3614
|
}
|
|
3615
|
+
function getAliasedSymbol(symbol, checker) {
|
|
3616
|
+
if (symbol === void 0) {
|
|
3617
|
+
return void 0;
|
|
3618
|
+
}
|
|
3619
|
+
return symbol.flags & ts3.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
3620
|
+
}
|
|
3621
|
+
function getAliasedTypeAliasDeclaration(symbol, checker) {
|
|
3622
|
+
return getAliasedSymbol(symbol, checker)?.declarations?.find(ts3.isTypeAliasDeclaration);
|
|
3623
|
+
}
|
|
3624
|
+
function getTypeAliasDeclarationFromTypeReference(typeNode, checker) {
|
|
3625
|
+
return getAliasedTypeAliasDeclaration(checker.getSymbolAtLocation(typeNode.typeName), checker);
|
|
3626
|
+
}
|
|
3558
3627
|
function provenanceForNode(node, file) {
|
|
3559
3628
|
const sourceFile = node.getSourceFile();
|
|
3560
3629
|
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
@@ -3728,6 +3797,95 @@ function findInterfaceByName(sourceFile, interfaceName) {
|
|
|
3728
3797
|
function findTypeAliasByName(sourceFile, aliasName) {
|
|
3729
3798
|
return findNodeByName(sourceFile, aliasName, ts4.isTypeAliasDeclaration, (n) => n.name.text);
|
|
3730
3799
|
}
|
|
3800
|
+
function getResolvedObjectRootType(rootType, typeRegistry) {
|
|
3801
|
+
if (rootType.kind === "object") {
|
|
3802
|
+
return rootType;
|
|
3803
|
+
}
|
|
3804
|
+
if (rootType.kind !== "reference") {
|
|
3805
|
+
return null;
|
|
3806
|
+
}
|
|
3807
|
+
const definition = typeRegistry[rootType.name];
|
|
3808
|
+
return definition?.type.kind === "object" ? definition.type : null;
|
|
3809
|
+
}
|
|
3810
|
+
function createResolvedObjectAliasAnalysis(name, rootType, typeRegistry, rootInfo, diagnostics) {
|
|
3811
|
+
const resolvedRootType = getResolvedObjectRootType(rootType, typeRegistry);
|
|
3812
|
+
if (resolvedRootType === null) {
|
|
3813
|
+
return null;
|
|
3814
|
+
}
|
|
3815
|
+
const fields = resolvedRootType.properties.map((property) => ({
|
|
3816
|
+
kind: "field",
|
|
3817
|
+
name: property.name,
|
|
3818
|
+
...property.metadata !== void 0 && { metadata: property.metadata },
|
|
3819
|
+
type: property.type,
|
|
3820
|
+
required: !property.optional,
|
|
3821
|
+
constraints: property.constraints,
|
|
3822
|
+
annotations: property.annotations,
|
|
3823
|
+
provenance: property.provenance
|
|
3824
|
+
}));
|
|
3825
|
+
return {
|
|
3826
|
+
name,
|
|
3827
|
+
...rootInfo.metadata !== void 0 && { metadata: rootInfo.metadata },
|
|
3828
|
+
fields,
|
|
3829
|
+
fieldLayouts: fields.map(() => ({})),
|
|
3830
|
+
typeRegistry,
|
|
3831
|
+
...rootInfo.annotations.length > 0 && { annotations: [...rootInfo.annotations] },
|
|
3832
|
+
...diagnostics.length > 0 && { diagnostics: [...diagnostics] },
|
|
3833
|
+
instanceMethods: [],
|
|
3834
|
+
staticMethods: []
|
|
3835
|
+
};
|
|
3836
|
+
}
|
|
3837
|
+
function containsTypeReferenceInObjectLikeAlias(typeNode) {
|
|
3838
|
+
if (ts4.isParenthesizedTypeNode(typeNode)) {
|
|
3839
|
+
return containsTypeReferenceInObjectLikeAlias(typeNode.type);
|
|
3840
|
+
}
|
|
3841
|
+
if (ts4.isTypeReferenceNode(typeNode)) {
|
|
3842
|
+
return true;
|
|
3843
|
+
}
|
|
3844
|
+
return ts4.isIntersectionTypeNode(typeNode) && typeNode.types.some((member) => containsTypeReferenceInObjectLikeAlias(member));
|
|
3845
|
+
}
|
|
3846
|
+
function collectFallbackAliasMemberPropertyNames(typeNode, checker) {
|
|
3847
|
+
if (ts4.isParenthesizedTypeNode(typeNode)) {
|
|
3848
|
+
return collectFallbackAliasMemberPropertyNames(typeNode.type, checker);
|
|
3849
|
+
}
|
|
3850
|
+
if (ts4.isTypeLiteralNode(typeNode)) {
|
|
3851
|
+
const propertyNames = [];
|
|
3852
|
+
for (const member of typeNode.members) {
|
|
3853
|
+
if (!ts4.isPropertySignature(member)) {
|
|
3854
|
+
continue;
|
|
3855
|
+
}
|
|
3856
|
+
const propertyName = getAnalyzableObjectLikePropertyName(member.name);
|
|
3857
|
+
if (propertyName !== null) {
|
|
3858
|
+
propertyNames.push(propertyName);
|
|
3859
|
+
}
|
|
3860
|
+
}
|
|
3861
|
+
return propertyNames;
|
|
3862
|
+
}
|
|
3863
|
+
if (ts4.isTypeReferenceNode(typeNode)) {
|
|
3864
|
+
return checker.getTypeFromTypeNode(typeNode).getProperties().map((property) => property.getName());
|
|
3865
|
+
}
|
|
3866
|
+
return null;
|
|
3867
|
+
}
|
|
3868
|
+
function findFallbackAliasDuplicatePropertyNames(typeNode, checker) {
|
|
3869
|
+
if (!ts4.isIntersectionTypeNode(typeNode)) {
|
|
3870
|
+
return [];
|
|
3871
|
+
}
|
|
3872
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3873
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
3874
|
+
for (const member of typeNode.types) {
|
|
3875
|
+
const propertyNames = collectFallbackAliasMemberPropertyNames(member, checker);
|
|
3876
|
+
if (propertyNames === null) {
|
|
3877
|
+
continue;
|
|
3878
|
+
}
|
|
3879
|
+
for (const propertyName of propertyNames) {
|
|
3880
|
+
if (seen.has(propertyName)) {
|
|
3881
|
+
duplicates.add(propertyName);
|
|
3882
|
+
} else {
|
|
3883
|
+
seen.add(propertyName);
|
|
3884
|
+
}
|
|
3885
|
+
}
|
|
3886
|
+
}
|
|
3887
|
+
return [...duplicates].sort();
|
|
3888
|
+
}
|
|
3731
3889
|
function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry, metadataPolicy, discriminatorOptions) {
|
|
3732
3890
|
const analysisFilePath = path.resolve(filePath);
|
|
3733
3891
|
const classDecl = findClassByName(ctx.sourceFile, typeName);
|
|
@@ -3765,6 +3923,51 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
|
|
|
3765
3923
|
if (result.ok) {
|
|
3766
3924
|
return result.analysis;
|
|
3767
3925
|
}
|
|
3926
|
+
const fallbackEligible = result.kind === "not-object-like" && isResolvableObjectLikeAliasTypeNode(typeAlias.type) && containsTypeReferenceInObjectLikeAlias(typeAlias.type);
|
|
3927
|
+
if (!fallbackEligible) {
|
|
3928
|
+
throw new Error(result.error);
|
|
3929
|
+
}
|
|
3930
|
+
const duplicatePropertyNames = findFallbackAliasDuplicatePropertyNames(
|
|
3931
|
+
typeAlias.type,
|
|
3932
|
+
ctx.checker
|
|
3933
|
+
);
|
|
3934
|
+
if (duplicatePropertyNames.length > 0) {
|
|
3935
|
+
const sourceFile = typeAlias.getSourceFile();
|
|
3936
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
3937
|
+
throw new Error(
|
|
3938
|
+
`Type alias "${typeAlias.name.text}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
|
|
3939
|
+
);
|
|
3940
|
+
}
|
|
3941
|
+
const rootInfo = analyzeDeclarationRootInfo(
|
|
3942
|
+
typeAlias,
|
|
3943
|
+
ctx.checker,
|
|
3944
|
+
analysisFilePath,
|
|
3945
|
+
extensionRegistry,
|
|
3946
|
+
metadataPolicy
|
|
3947
|
+
);
|
|
3948
|
+
const diagnostics = [...rootInfo.diagnostics];
|
|
3949
|
+
const typeRegistry = {};
|
|
3950
|
+
const rootType = resolveTypeNode(
|
|
3951
|
+
ctx.checker.getTypeAtLocation(typeAlias),
|
|
3952
|
+
ctx.checker,
|
|
3953
|
+
analysisFilePath,
|
|
3954
|
+
typeRegistry,
|
|
3955
|
+
/* @__PURE__ */ new Set(),
|
|
3956
|
+
typeAlias,
|
|
3957
|
+
createAnalyzerMetadataPolicy(metadataPolicy, discriminatorOptions),
|
|
3958
|
+
extensionRegistry,
|
|
3959
|
+
diagnostics
|
|
3960
|
+
);
|
|
3961
|
+
const fallbackAnalysis = createResolvedObjectAliasAnalysis(
|
|
3962
|
+
typeAlias.name.text,
|
|
3963
|
+
rootType,
|
|
3964
|
+
typeRegistry,
|
|
3965
|
+
rootInfo,
|
|
3966
|
+
diagnostics
|
|
3967
|
+
);
|
|
3968
|
+
if (fallbackAnalysis !== null) {
|
|
3969
|
+
return fallbackAnalysis;
|
|
3970
|
+
}
|
|
3768
3971
|
throw new Error(result.error);
|
|
3769
3972
|
}
|
|
3770
3973
|
throw new Error(
|