@formspec/build 0.1.0-alpha.36 → 0.1.0-alpha.38
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 +36 -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/analyzer/tsdoc-parser.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 +213 -8
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +213 -8
- 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 +213 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +213 -8
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +219 -6
- package/dist/internals.cjs.map +1 -1
- package/dist/internals.js +219 -6
- package/dist/internals.js.map +1 -1
- package/package.json +3 -3
package/dist/internals.js
CHANGED
|
@@ -897,6 +897,16 @@ function buildSupportingDeclarations(sourceFile, extensionTypeNames) {
|
|
|
897
897
|
return true;
|
|
898
898
|
}).map((statement) => statement.getText(sourceFile));
|
|
899
899
|
}
|
|
900
|
+
function pushUniqueCompilerDiagnostics(target, additions) {
|
|
901
|
+
for (const diagnostic of additions) {
|
|
902
|
+
if ((diagnostic.code === "UNSUPPORTED_CUSTOM_TYPE_OVERRIDE" || diagnostic.code === "SYNTHETIC_SETUP_FAILURE") && target.some(
|
|
903
|
+
(existing) => existing.code === diagnostic.code && existing.message === diagnostic.message
|
|
904
|
+
)) {
|
|
905
|
+
continue;
|
|
906
|
+
}
|
|
907
|
+
target.push(diagnostic);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
900
910
|
function renderSyntheticArgumentExpression(valueKind, argumentText) {
|
|
901
911
|
const trimmed = argumentText.trim();
|
|
902
912
|
if (trimmed === "") {
|
|
@@ -1163,6 +1173,16 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
|
|
|
1163
1173
|
if (result.diagnostics.length === 0) {
|
|
1164
1174
|
return [];
|
|
1165
1175
|
}
|
|
1176
|
+
const setupDiagnostic = result.diagnostics.find((diagnostic) => diagnostic.kind !== "typescript");
|
|
1177
|
+
if (setupDiagnostic !== void 0) {
|
|
1178
|
+
return [
|
|
1179
|
+
makeDiagnostic(
|
|
1180
|
+
setupDiagnostic.kind === "unsupported-custom-type-override" ? "UNSUPPORTED_CUSTOM_TYPE_OVERRIDE" : "SYNTHETIC_SETUP_FAILURE",
|
|
1181
|
+
setupDiagnostic.message,
|
|
1182
|
+
provenance
|
|
1183
|
+
)
|
|
1184
|
+
];
|
|
1185
|
+
}
|
|
1166
1186
|
const expectedLabel = definition.valueKind === null ? "compatible argument" : capabilityLabel(definition.valueKind);
|
|
1167
1187
|
return [
|
|
1168
1188
|
makeDiagnostic(
|
|
@@ -1328,7 +1348,7 @@ function parseTSDocTags(node, file = "", options) {
|
|
|
1328
1348
|
options
|
|
1329
1349
|
);
|
|
1330
1350
|
if (compilerDiagnostics.length > 0) {
|
|
1331
|
-
diagnostics
|
|
1351
|
+
pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
|
|
1332
1352
|
continue;
|
|
1333
1353
|
}
|
|
1334
1354
|
const constraintNode = parseConstraintTagValue(
|
|
@@ -1415,7 +1435,7 @@ function parseTSDocTags(node, file = "", options) {
|
|
|
1415
1435
|
options
|
|
1416
1436
|
);
|
|
1417
1437
|
if (compilerDiagnostics.length > 0) {
|
|
1418
|
-
diagnostics
|
|
1438
|
+
pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
|
|
1419
1439
|
continue;
|
|
1420
1440
|
}
|
|
1421
1441
|
const constraintNode = parseConstraintTagValue(
|
|
@@ -1449,7 +1469,7 @@ function parseTSDocTags(node, file = "", options) {
|
|
|
1449
1469
|
options
|
|
1450
1470
|
);
|
|
1451
1471
|
if (compilerDiagnostics.length > 0) {
|
|
1452
|
-
diagnostics
|
|
1472
|
+
pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
|
|
1453
1473
|
continue;
|
|
1454
1474
|
}
|
|
1455
1475
|
const constraintNode = parseConstraintTagValue(
|
|
@@ -1656,6 +1676,21 @@ function isObjectType(type) {
|
|
|
1656
1676
|
function isIntersectionType(type) {
|
|
1657
1677
|
return !!(type.flags & ts3.TypeFlags.Intersection);
|
|
1658
1678
|
}
|
|
1679
|
+
function isResolvableObjectLikeAliasTypeNode(typeNode) {
|
|
1680
|
+
if (ts3.isParenthesizedTypeNode(typeNode)) {
|
|
1681
|
+
return isResolvableObjectLikeAliasTypeNode(typeNode.type);
|
|
1682
|
+
}
|
|
1683
|
+
if (ts3.isTypeLiteralNode(typeNode) || ts3.isTypeReferenceNode(typeNode)) {
|
|
1684
|
+
return true;
|
|
1685
|
+
}
|
|
1686
|
+
return ts3.isIntersectionTypeNode(typeNode) && typeNode.types.length > 0 && typeNode.types.every((member) => isResolvableObjectLikeAliasTypeNode(member));
|
|
1687
|
+
}
|
|
1688
|
+
function isSemanticallyPlainObjectLikeType(type, checker) {
|
|
1689
|
+
if (isIntersectionType(type)) {
|
|
1690
|
+
return type.types.length > 0 && type.types.every((member) => isSemanticallyPlainObjectLikeType(member, checker));
|
|
1691
|
+
}
|
|
1692
|
+
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);
|
|
1693
|
+
}
|
|
1659
1694
|
function isTypeReference(type) {
|
|
1660
1695
|
return !!(type.flags & ts3.TypeFlags.Object) && !!(type.objectFlags & ts3.ObjectFlags.Reference);
|
|
1661
1696
|
}
|
|
@@ -1719,6 +1754,35 @@ function resolveNodeMetadata(metadataPolicy, declarationKind, logicalName, node,
|
|
|
1719
1754
|
}
|
|
1720
1755
|
return resolvedMetadata;
|
|
1721
1756
|
}
|
|
1757
|
+
function analyzeDeclarationRootInfo(declaration, checker, file = "", extensionRegistry, metadataPolicy) {
|
|
1758
|
+
const normalizedMetadataPolicy = createAnalyzerMetadataPolicy(metadataPolicy);
|
|
1759
|
+
const declarationType = checker.getTypeAtLocation(declaration);
|
|
1760
|
+
const logicalName = ts3.isClassDeclaration(declaration) ? declaration.name?.text ?? "AnonymousClass" : declaration.name.text;
|
|
1761
|
+
const docResult = extractJSDocParseResult(
|
|
1762
|
+
declaration,
|
|
1763
|
+
file,
|
|
1764
|
+
makeParseOptions(extensionRegistry, void 0, checker, declarationType, declarationType)
|
|
1765
|
+
);
|
|
1766
|
+
const metadata = resolveNodeMetadata(
|
|
1767
|
+
normalizedMetadataPolicy,
|
|
1768
|
+
"type",
|
|
1769
|
+
logicalName,
|
|
1770
|
+
declaration,
|
|
1771
|
+
checker,
|
|
1772
|
+
extensionRegistry,
|
|
1773
|
+
{
|
|
1774
|
+
checker,
|
|
1775
|
+
declaration,
|
|
1776
|
+
subjectType: declarationType,
|
|
1777
|
+
hostType: declarationType
|
|
1778
|
+
}
|
|
1779
|
+
);
|
|
1780
|
+
return {
|
|
1781
|
+
...metadata !== void 0 && { metadata },
|
|
1782
|
+
annotations: docResult.annotations,
|
|
1783
|
+
diagnostics: docResult.diagnostics
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1722
1786
|
function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry, metadataPolicy, discriminatorOptions) {
|
|
1723
1787
|
const normalizedMetadataPolicy = createAnalyzerMetadataPolicy(
|
|
1724
1788
|
metadataPolicy,
|
|
@@ -1884,6 +1948,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
|
|
|
1884
1948
|
const kindDesc = ts3.SyntaxKind[typeAlias.type.kind] ?? "unknown";
|
|
1885
1949
|
return {
|
|
1886
1950
|
ok: false,
|
|
1951
|
+
kind: "not-object-like",
|
|
1887
1952
|
error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object-like type alias (found ${kindDesc})`
|
|
1888
1953
|
};
|
|
1889
1954
|
}
|
|
@@ -1898,6 +1963,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
|
|
|
1898
1963
|
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
1899
1964
|
return {
|
|
1900
1965
|
ok: false,
|
|
1966
|
+
kind: "duplicate-properties",
|
|
1901
1967
|
error: `Type alias "${name}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
|
|
1902
1968
|
};
|
|
1903
1969
|
}
|
|
@@ -2594,10 +2660,10 @@ function findDuplicateObjectLikeTypeAliasPropertyNames(members) {
|
|
|
2594
2660
|
return [...duplicates].sort();
|
|
2595
2661
|
}
|
|
2596
2662
|
function getAnalyzableObjectLikePropertyName(name) {
|
|
2597
|
-
if (
|
|
2598
|
-
return
|
|
2663
|
+
if (ts3.isIdentifier(name) || ts3.isStringLiteral(name) || ts3.isNumericLiteral(name)) {
|
|
2664
|
+
return name.text;
|
|
2599
2665
|
}
|
|
2600
|
-
return
|
|
2666
|
+
return null;
|
|
2601
2667
|
}
|
|
2602
2668
|
function applyEnumMemberDisplayNames(type, annotations) {
|
|
2603
2669
|
if (!annotations.some(
|
|
@@ -2807,6 +2873,19 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
2807
2873
|
diagnostics
|
|
2808
2874
|
);
|
|
2809
2875
|
}
|
|
2876
|
+
if (resolvedSourceTypeNode !== void 0 && isResolvableObjectLikeAliasTypeNode(resolvedSourceTypeNode) && isSemanticallyPlainObjectLikeType(type, checker)) {
|
|
2877
|
+
return resolveObjectType(
|
|
2878
|
+
type,
|
|
2879
|
+
checker,
|
|
2880
|
+
file,
|
|
2881
|
+
typeRegistry,
|
|
2882
|
+
visiting,
|
|
2883
|
+
sourceNode,
|
|
2884
|
+
metadataPolicy,
|
|
2885
|
+
extensionRegistry,
|
|
2886
|
+
diagnostics
|
|
2887
|
+
);
|
|
2888
|
+
}
|
|
2810
2889
|
}
|
|
2811
2890
|
if (isObjectType(type)) {
|
|
2812
2891
|
return resolveObjectType(
|
|
@@ -3714,6 +3793,95 @@ function findInterfaceByName(sourceFile, interfaceName) {
|
|
|
3714
3793
|
function findTypeAliasByName(sourceFile, aliasName) {
|
|
3715
3794
|
return findNodeByName(sourceFile, aliasName, ts4.isTypeAliasDeclaration, (n) => n.name.text);
|
|
3716
3795
|
}
|
|
3796
|
+
function getResolvedObjectRootType(rootType, typeRegistry) {
|
|
3797
|
+
if (rootType.kind === "object") {
|
|
3798
|
+
return rootType;
|
|
3799
|
+
}
|
|
3800
|
+
if (rootType.kind !== "reference") {
|
|
3801
|
+
return null;
|
|
3802
|
+
}
|
|
3803
|
+
const definition = typeRegistry[rootType.name];
|
|
3804
|
+
return definition?.type.kind === "object" ? definition.type : null;
|
|
3805
|
+
}
|
|
3806
|
+
function createResolvedObjectAliasAnalysis(name, rootType, typeRegistry, rootInfo, diagnostics) {
|
|
3807
|
+
const resolvedRootType = getResolvedObjectRootType(rootType, typeRegistry);
|
|
3808
|
+
if (resolvedRootType === null) {
|
|
3809
|
+
return null;
|
|
3810
|
+
}
|
|
3811
|
+
const fields = resolvedRootType.properties.map((property) => ({
|
|
3812
|
+
kind: "field",
|
|
3813
|
+
name: property.name,
|
|
3814
|
+
...property.metadata !== void 0 && { metadata: property.metadata },
|
|
3815
|
+
type: property.type,
|
|
3816
|
+
required: !property.optional,
|
|
3817
|
+
constraints: property.constraints,
|
|
3818
|
+
annotations: property.annotations,
|
|
3819
|
+
provenance: property.provenance
|
|
3820
|
+
}));
|
|
3821
|
+
return {
|
|
3822
|
+
name,
|
|
3823
|
+
...rootInfo.metadata !== void 0 && { metadata: rootInfo.metadata },
|
|
3824
|
+
fields,
|
|
3825
|
+
fieldLayouts: fields.map(() => ({})),
|
|
3826
|
+
typeRegistry,
|
|
3827
|
+
...rootInfo.annotations.length > 0 && { annotations: [...rootInfo.annotations] },
|
|
3828
|
+
...diagnostics.length > 0 && { diagnostics: [...diagnostics] },
|
|
3829
|
+
instanceMethods: [],
|
|
3830
|
+
staticMethods: []
|
|
3831
|
+
};
|
|
3832
|
+
}
|
|
3833
|
+
function containsTypeReferenceInObjectLikeAlias(typeNode) {
|
|
3834
|
+
if (ts4.isParenthesizedTypeNode(typeNode)) {
|
|
3835
|
+
return containsTypeReferenceInObjectLikeAlias(typeNode.type);
|
|
3836
|
+
}
|
|
3837
|
+
if (ts4.isTypeReferenceNode(typeNode)) {
|
|
3838
|
+
return true;
|
|
3839
|
+
}
|
|
3840
|
+
return ts4.isIntersectionTypeNode(typeNode) && typeNode.types.some((member) => containsTypeReferenceInObjectLikeAlias(member));
|
|
3841
|
+
}
|
|
3842
|
+
function collectFallbackAliasMemberPropertyNames(typeNode, checker) {
|
|
3843
|
+
if (ts4.isParenthesizedTypeNode(typeNode)) {
|
|
3844
|
+
return collectFallbackAliasMemberPropertyNames(typeNode.type, checker);
|
|
3845
|
+
}
|
|
3846
|
+
if (ts4.isTypeLiteralNode(typeNode)) {
|
|
3847
|
+
const propertyNames = [];
|
|
3848
|
+
for (const member of typeNode.members) {
|
|
3849
|
+
if (!ts4.isPropertySignature(member)) {
|
|
3850
|
+
continue;
|
|
3851
|
+
}
|
|
3852
|
+
const propertyName = getAnalyzableObjectLikePropertyName(member.name);
|
|
3853
|
+
if (propertyName !== null) {
|
|
3854
|
+
propertyNames.push(propertyName);
|
|
3855
|
+
}
|
|
3856
|
+
}
|
|
3857
|
+
return propertyNames;
|
|
3858
|
+
}
|
|
3859
|
+
if (ts4.isTypeReferenceNode(typeNode)) {
|
|
3860
|
+
return checker.getTypeFromTypeNode(typeNode).getProperties().map((property) => property.getName());
|
|
3861
|
+
}
|
|
3862
|
+
return null;
|
|
3863
|
+
}
|
|
3864
|
+
function findFallbackAliasDuplicatePropertyNames(typeNode, checker) {
|
|
3865
|
+
if (!ts4.isIntersectionTypeNode(typeNode)) {
|
|
3866
|
+
return [];
|
|
3867
|
+
}
|
|
3868
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3869
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
3870
|
+
for (const member of typeNode.types) {
|
|
3871
|
+
const propertyNames = collectFallbackAliasMemberPropertyNames(member, checker);
|
|
3872
|
+
if (propertyNames === null) {
|
|
3873
|
+
continue;
|
|
3874
|
+
}
|
|
3875
|
+
for (const propertyName of propertyNames) {
|
|
3876
|
+
if (seen.has(propertyName)) {
|
|
3877
|
+
duplicates.add(propertyName);
|
|
3878
|
+
} else {
|
|
3879
|
+
seen.add(propertyName);
|
|
3880
|
+
}
|
|
3881
|
+
}
|
|
3882
|
+
}
|
|
3883
|
+
return [...duplicates].sort();
|
|
3884
|
+
}
|
|
3717
3885
|
function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry, metadataPolicy, discriminatorOptions) {
|
|
3718
3886
|
const analysisFilePath = path.resolve(filePath);
|
|
3719
3887
|
const classDecl = findClassByName(ctx.sourceFile, typeName);
|
|
@@ -3751,6 +3919,51 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
|
|
|
3751
3919
|
if (result.ok) {
|
|
3752
3920
|
return result.analysis;
|
|
3753
3921
|
}
|
|
3922
|
+
const fallbackEligible = result.kind === "not-object-like" && isResolvableObjectLikeAliasTypeNode(typeAlias.type) && containsTypeReferenceInObjectLikeAlias(typeAlias.type);
|
|
3923
|
+
if (!fallbackEligible) {
|
|
3924
|
+
throw new Error(result.error);
|
|
3925
|
+
}
|
|
3926
|
+
const duplicatePropertyNames = findFallbackAliasDuplicatePropertyNames(
|
|
3927
|
+
typeAlias.type,
|
|
3928
|
+
ctx.checker
|
|
3929
|
+
);
|
|
3930
|
+
if (duplicatePropertyNames.length > 0) {
|
|
3931
|
+
const sourceFile = typeAlias.getSourceFile();
|
|
3932
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
3933
|
+
throw new Error(
|
|
3934
|
+
`Type alias "${typeAlias.name.text}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
|
|
3935
|
+
);
|
|
3936
|
+
}
|
|
3937
|
+
const rootInfo = analyzeDeclarationRootInfo(
|
|
3938
|
+
typeAlias,
|
|
3939
|
+
ctx.checker,
|
|
3940
|
+
analysisFilePath,
|
|
3941
|
+
extensionRegistry,
|
|
3942
|
+
metadataPolicy
|
|
3943
|
+
);
|
|
3944
|
+
const diagnostics = [...rootInfo.diagnostics];
|
|
3945
|
+
const typeRegistry = {};
|
|
3946
|
+
const rootType = resolveTypeNode(
|
|
3947
|
+
ctx.checker.getTypeAtLocation(typeAlias),
|
|
3948
|
+
ctx.checker,
|
|
3949
|
+
analysisFilePath,
|
|
3950
|
+
typeRegistry,
|
|
3951
|
+
/* @__PURE__ */ new Set(),
|
|
3952
|
+
typeAlias,
|
|
3953
|
+
createAnalyzerMetadataPolicy(metadataPolicy, discriminatorOptions),
|
|
3954
|
+
extensionRegistry,
|
|
3955
|
+
diagnostics
|
|
3956
|
+
);
|
|
3957
|
+
const fallbackAnalysis = createResolvedObjectAliasAnalysis(
|
|
3958
|
+
typeAlias.name.text,
|
|
3959
|
+
rootType,
|
|
3960
|
+
typeRegistry,
|
|
3961
|
+
rootInfo,
|
|
3962
|
+
diagnostics
|
|
3963
|
+
);
|
|
3964
|
+
if (fallbackAnalysis !== null) {
|
|
3965
|
+
return fallbackAnalysis;
|
|
3966
|
+
}
|
|
3754
3967
|
throw new Error(result.error);
|
|
3755
3968
|
}
|
|
3756
3969
|
throw new Error(
|