@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.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(
|
|
@@ -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(
|