@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/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 +190 -5
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +190 -5
- 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 +190 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +190 -5
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +196 -3
- package/dist/internals.cjs.map +1 -1
- package/dist/internals.js +196 -3
- package/dist/internals.js.map +1 -1
- package/package.json +3 -3
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(
|
|
@@ -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(
|
|
@@ -3738,6 +3797,95 @@ function findInterfaceByName(sourceFile, interfaceName) {
|
|
|
3738
3797
|
function findTypeAliasByName(sourceFile, aliasName) {
|
|
3739
3798
|
return findNodeByName(sourceFile, aliasName, ts4.isTypeAliasDeclaration, (n) => n.name.text);
|
|
3740
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
|
+
}
|
|
3741
3889
|
function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry, metadataPolicy, discriminatorOptions) {
|
|
3742
3890
|
const analysisFilePath = path.resolve(filePath);
|
|
3743
3891
|
const classDecl = findClassByName(ctx.sourceFile, typeName);
|
|
@@ -3775,6 +3923,51 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
|
|
|
3775
3923
|
if (result.ok) {
|
|
3776
3924
|
return result.analysis;
|
|
3777
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
|
+
}
|
|
3778
3971
|
throw new Error(result.error);
|
|
3779
3972
|
}
|
|
3780
3973
|
throw new Error(
|