@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.cjs
CHANGED
|
@@ -921,6 +921,16 @@ function buildSupportingDeclarations(sourceFile, extensionTypeNames) {
|
|
|
921
921
|
return true;
|
|
922
922
|
}).map((statement) => statement.getText(sourceFile));
|
|
923
923
|
}
|
|
924
|
+
function pushUniqueCompilerDiagnostics(target, additions) {
|
|
925
|
+
for (const diagnostic of additions) {
|
|
926
|
+
if ((diagnostic.code === "UNSUPPORTED_CUSTOM_TYPE_OVERRIDE" || diagnostic.code === "SYNTHETIC_SETUP_FAILURE") && target.some(
|
|
927
|
+
(existing) => existing.code === diagnostic.code && existing.message === diagnostic.message
|
|
928
|
+
)) {
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
target.push(diagnostic);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
924
934
|
function renderSyntheticArgumentExpression(valueKind, argumentText) {
|
|
925
935
|
const trimmed = argumentText.trim();
|
|
926
936
|
if (trimmed === "") {
|
|
@@ -1187,6 +1197,16 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
|
|
|
1187
1197
|
if (result.diagnostics.length === 0) {
|
|
1188
1198
|
return [];
|
|
1189
1199
|
}
|
|
1200
|
+
const setupDiagnostic = result.diagnostics.find((diagnostic) => diagnostic.kind !== "typescript");
|
|
1201
|
+
if (setupDiagnostic !== void 0) {
|
|
1202
|
+
return [
|
|
1203
|
+
makeDiagnostic(
|
|
1204
|
+
setupDiagnostic.kind === "unsupported-custom-type-override" ? "UNSUPPORTED_CUSTOM_TYPE_OVERRIDE" : "SYNTHETIC_SETUP_FAILURE",
|
|
1205
|
+
setupDiagnostic.message,
|
|
1206
|
+
provenance
|
|
1207
|
+
)
|
|
1208
|
+
];
|
|
1209
|
+
}
|
|
1190
1210
|
const expectedLabel = definition.valueKind === null ? "compatible argument" : capabilityLabel(definition.valueKind);
|
|
1191
1211
|
return [
|
|
1192
1212
|
makeDiagnostic(
|
|
@@ -1352,7 +1372,7 @@ function parseTSDocTags(node, file = "", options) {
|
|
|
1352
1372
|
options
|
|
1353
1373
|
);
|
|
1354
1374
|
if (compilerDiagnostics.length > 0) {
|
|
1355
|
-
diagnostics
|
|
1375
|
+
pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
|
|
1356
1376
|
continue;
|
|
1357
1377
|
}
|
|
1358
1378
|
const constraintNode = (0, import_internal.parseConstraintTagValue)(
|
|
@@ -1439,7 +1459,7 @@ function parseTSDocTags(node, file = "", options) {
|
|
|
1439
1459
|
options
|
|
1440
1460
|
);
|
|
1441
1461
|
if (compilerDiagnostics.length > 0) {
|
|
1442
|
-
diagnostics
|
|
1462
|
+
pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
|
|
1443
1463
|
continue;
|
|
1444
1464
|
}
|
|
1445
1465
|
const constraintNode = (0, import_internal.parseConstraintTagValue)(
|
|
@@ -1473,7 +1493,7 @@ function parseTSDocTags(node, file = "", options) {
|
|
|
1473
1493
|
options
|
|
1474
1494
|
);
|
|
1475
1495
|
if (compilerDiagnostics.length > 0) {
|
|
1476
|
-
diagnostics
|
|
1496
|
+
pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
|
|
1477
1497
|
continue;
|
|
1478
1498
|
}
|
|
1479
1499
|
const constraintNode = (0, import_internal.parseConstraintTagValue)(
|
|
@@ -1680,6 +1700,21 @@ function isObjectType(type) {
|
|
|
1680
1700
|
function isIntersectionType(type) {
|
|
1681
1701
|
return !!(type.flags & ts3.TypeFlags.Intersection);
|
|
1682
1702
|
}
|
|
1703
|
+
function isResolvableObjectLikeAliasTypeNode(typeNode) {
|
|
1704
|
+
if (ts3.isParenthesizedTypeNode(typeNode)) {
|
|
1705
|
+
return isResolvableObjectLikeAliasTypeNode(typeNode.type);
|
|
1706
|
+
}
|
|
1707
|
+
if (ts3.isTypeLiteralNode(typeNode) || ts3.isTypeReferenceNode(typeNode)) {
|
|
1708
|
+
return true;
|
|
1709
|
+
}
|
|
1710
|
+
return ts3.isIntersectionTypeNode(typeNode) && typeNode.types.length > 0 && typeNode.types.every((member) => isResolvableObjectLikeAliasTypeNode(member));
|
|
1711
|
+
}
|
|
1712
|
+
function isSemanticallyPlainObjectLikeType(type, checker) {
|
|
1713
|
+
if (isIntersectionType(type)) {
|
|
1714
|
+
return type.types.length > 0 && type.types.every((member) => isSemanticallyPlainObjectLikeType(member, checker));
|
|
1715
|
+
}
|
|
1716
|
+
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);
|
|
1717
|
+
}
|
|
1683
1718
|
function isTypeReference(type) {
|
|
1684
1719
|
return !!(type.flags & ts3.TypeFlags.Object) && !!(type.objectFlags & ts3.ObjectFlags.Reference);
|
|
1685
1720
|
}
|
|
@@ -1743,6 +1778,35 @@ function resolveNodeMetadata(metadataPolicy, declarationKind, logicalName, node,
|
|
|
1743
1778
|
}
|
|
1744
1779
|
return resolvedMetadata;
|
|
1745
1780
|
}
|
|
1781
|
+
function analyzeDeclarationRootInfo(declaration, checker, file = "", extensionRegistry, metadataPolicy) {
|
|
1782
|
+
const normalizedMetadataPolicy = createAnalyzerMetadataPolicy(metadataPolicy);
|
|
1783
|
+
const declarationType = checker.getTypeAtLocation(declaration);
|
|
1784
|
+
const logicalName = ts3.isClassDeclaration(declaration) ? declaration.name?.text ?? "AnonymousClass" : declaration.name.text;
|
|
1785
|
+
const docResult = extractJSDocParseResult(
|
|
1786
|
+
declaration,
|
|
1787
|
+
file,
|
|
1788
|
+
makeParseOptions(extensionRegistry, void 0, checker, declarationType, declarationType)
|
|
1789
|
+
);
|
|
1790
|
+
const metadata = resolveNodeMetadata(
|
|
1791
|
+
normalizedMetadataPolicy,
|
|
1792
|
+
"type",
|
|
1793
|
+
logicalName,
|
|
1794
|
+
declaration,
|
|
1795
|
+
checker,
|
|
1796
|
+
extensionRegistry,
|
|
1797
|
+
{
|
|
1798
|
+
checker,
|
|
1799
|
+
declaration,
|
|
1800
|
+
subjectType: declarationType,
|
|
1801
|
+
hostType: declarationType
|
|
1802
|
+
}
|
|
1803
|
+
);
|
|
1804
|
+
return {
|
|
1805
|
+
...metadata !== void 0 && { metadata },
|
|
1806
|
+
annotations: docResult.annotations,
|
|
1807
|
+
diagnostics: docResult.diagnostics
|
|
1808
|
+
};
|
|
1809
|
+
}
|
|
1746
1810
|
function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry, metadataPolicy, discriminatorOptions) {
|
|
1747
1811
|
const normalizedMetadataPolicy = createAnalyzerMetadataPolicy(
|
|
1748
1812
|
metadataPolicy,
|
|
@@ -1908,6 +1972,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
|
|
|
1908
1972
|
const kindDesc = ts3.SyntaxKind[typeAlias.type.kind] ?? "unknown";
|
|
1909
1973
|
return {
|
|
1910
1974
|
ok: false,
|
|
1975
|
+
kind: "not-object-like",
|
|
1911
1976
|
error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object-like type alias (found ${kindDesc})`
|
|
1912
1977
|
};
|
|
1913
1978
|
}
|
|
@@ -1922,6 +1987,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
|
|
|
1922
1987
|
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
1923
1988
|
return {
|
|
1924
1989
|
ok: false,
|
|
1990
|
+
kind: "duplicate-properties",
|
|
1925
1991
|
error: `Type alias "${name}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
|
|
1926
1992
|
};
|
|
1927
1993
|
}
|
|
@@ -2618,10 +2684,10 @@ function findDuplicateObjectLikeTypeAliasPropertyNames(members) {
|
|
|
2618
2684
|
return [...duplicates].sort();
|
|
2619
2685
|
}
|
|
2620
2686
|
function getAnalyzableObjectLikePropertyName(name) {
|
|
2621
|
-
if (
|
|
2622
|
-
return
|
|
2687
|
+
if (ts3.isIdentifier(name) || ts3.isStringLiteral(name) || ts3.isNumericLiteral(name)) {
|
|
2688
|
+
return name.text;
|
|
2623
2689
|
}
|
|
2624
|
-
return
|
|
2690
|
+
return null;
|
|
2625
2691
|
}
|
|
2626
2692
|
function applyEnumMemberDisplayNames(type, annotations) {
|
|
2627
2693
|
if (!annotations.some(
|
|
@@ -2831,6 +2897,19 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
2831
2897
|
diagnostics
|
|
2832
2898
|
);
|
|
2833
2899
|
}
|
|
2900
|
+
if (resolvedSourceTypeNode !== void 0 && isResolvableObjectLikeAliasTypeNode(resolvedSourceTypeNode) && isSemanticallyPlainObjectLikeType(type, checker)) {
|
|
2901
|
+
return resolveObjectType(
|
|
2902
|
+
type,
|
|
2903
|
+
checker,
|
|
2904
|
+
file,
|
|
2905
|
+
typeRegistry,
|
|
2906
|
+
visiting,
|
|
2907
|
+
sourceNode,
|
|
2908
|
+
metadataPolicy,
|
|
2909
|
+
extensionRegistry,
|
|
2910
|
+
diagnostics
|
|
2911
|
+
);
|
|
2912
|
+
}
|
|
2834
2913
|
}
|
|
2835
2914
|
if (isObjectType(type)) {
|
|
2836
2915
|
return resolveObjectType(
|
|
@@ -3738,6 +3817,95 @@ function findInterfaceByName(sourceFile, interfaceName) {
|
|
|
3738
3817
|
function findTypeAliasByName(sourceFile, aliasName) {
|
|
3739
3818
|
return findNodeByName(sourceFile, aliasName, ts4.isTypeAliasDeclaration, (n) => n.name.text);
|
|
3740
3819
|
}
|
|
3820
|
+
function getResolvedObjectRootType(rootType, typeRegistry) {
|
|
3821
|
+
if (rootType.kind === "object") {
|
|
3822
|
+
return rootType;
|
|
3823
|
+
}
|
|
3824
|
+
if (rootType.kind !== "reference") {
|
|
3825
|
+
return null;
|
|
3826
|
+
}
|
|
3827
|
+
const definition = typeRegistry[rootType.name];
|
|
3828
|
+
return definition?.type.kind === "object" ? definition.type : null;
|
|
3829
|
+
}
|
|
3830
|
+
function createResolvedObjectAliasAnalysis(name, rootType, typeRegistry, rootInfo, diagnostics) {
|
|
3831
|
+
const resolvedRootType = getResolvedObjectRootType(rootType, typeRegistry);
|
|
3832
|
+
if (resolvedRootType === null) {
|
|
3833
|
+
return null;
|
|
3834
|
+
}
|
|
3835
|
+
const fields = resolvedRootType.properties.map((property) => ({
|
|
3836
|
+
kind: "field",
|
|
3837
|
+
name: property.name,
|
|
3838
|
+
...property.metadata !== void 0 && { metadata: property.metadata },
|
|
3839
|
+
type: property.type,
|
|
3840
|
+
required: !property.optional,
|
|
3841
|
+
constraints: property.constraints,
|
|
3842
|
+
annotations: property.annotations,
|
|
3843
|
+
provenance: property.provenance
|
|
3844
|
+
}));
|
|
3845
|
+
return {
|
|
3846
|
+
name,
|
|
3847
|
+
...rootInfo.metadata !== void 0 && { metadata: rootInfo.metadata },
|
|
3848
|
+
fields,
|
|
3849
|
+
fieldLayouts: fields.map(() => ({})),
|
|
3850
|
+
typeRegistry,
|
|
3851
|
+
...rootInfo.annotations.length > 0 && { annotations: [...rootInfo.annotations] },
|
|
3852
|
+
...diagnostics.length > 0 && { diagnostics: [...diagnostics] },
|
|
3853
|
+
instanceMethods: [],
|
|
3854
|
+
staticMethods: []
|
|
3855
|
+
};
|
|
3856
|
+
}
|
|
3857
|
+
function containsTypeReferenceInObjectLikeAlias(typeNode) {
|
|
3858
|
+
if (ts4.isParenthesizedTypeNode(typeNode)) {
|
|
3859
|
+
return containsTypeReferenceInObjectLikeAlias(typeNode.type);
|
|
3860
|
+
}
|
|
3861
|
+
if (ts4.isTypeReferenceNode(typeNode)) {
|
|
3862
|
+
return true;
|
|
3863
|
+
}
|
|
3864
|
+
return ts4.isIntersectionTypeNode(typeNode) && typeNode.types.some((member) => containsTypeReferenceInObjectLikeAlias(member));
|
|
3865
|
+
}
|
|
3866
|
+
function collectFallbackAliasMemberPropertyNames(typeNode, checker) {
|
|
3867
|
+
if (ts4.isParenthesizedTypeNode(typeNode)) {
|
|
3868
|
+
return collectFallbackAliasMemberPropertyNames(typeNode.type, checker);
|
|
3869
|
+
}
|
|
3870
|
+
if (ts4.isTypeLiteralNode(typeNode)) {
|
|
3871
|
+
const propertyNames = [];
|
|
3872
|
+
for (const member of typeNode.members) {
|
|
3873
|
+
if (!ts4.isPropertySignature(member)) {
|
|
3874
|
+
continue;
|
|
3875
|
+
}
|
|
3876
|
+
const propertyName = getAnalyzableObjectLikePropertyName(member.name);
|
|
3877
|
+
if (propertyName !== null) {
|
|
3878
|
+
propertyNames.push(propertyName);
|
|
3879
|
+
}
|
|
3880
|
+
}
|
|
3881
|
+
return propertyNames;
|
|
3882
|
+
}
|
|
3883
|
+
if (ts4.isTypeReferenceNode(typeNode)) {
|
|
3884
|
+
return checker.getTypeFromTypeNode(typeNode).getProperties().map((property) => property.getName());
|
|
3885
|
+
}
|
|
3886
|
+
return null;
|
|
3887
|
+
}
|
|
3888
|
+
function findFallbackAliasDuplicatePropertyNames(typeNode, checker) {
|
|
3889
|
+
if (!ts4.isIntersectionTypeNode(typeNode)) {
|
|
3890
|
+
return [];
|
|
3891
|
+
}
|
|
3892
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3893
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
3894
|
+
for (const member of typeNode.types) {
|
|
3895
|
+
const propertyNames = collectFallbackAliasMemberPropertyNames(member, checker);
|
|
3896
|
+
if (propertyNames === null) {
|
|
3897
|
+
continue;
|
|
3898
|
+
}
|
|
3899
|
+
for (const propertyName of propertyNames) {
|
|
3900
|
+
if (seen.has(propertyName)) {
|
|
3901
|
+
duplicates.add(propertyName);
|
|
3902
|
+
} else {
|
|
3903
|
+
seen.add(propertyName);
|
|
3904
|
+
}
|
|
3905
|
+
}
|
|
3906
|
+
}
|
|
3907
|
+
return [...duplicates].sort();
|
|
3908
|
+
}
|
|
3741
3909
|
function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry, metadataPolicy, discriminatorOptions) {
|
|
3742
3910
|
const analysisFilePath = path.resolve(filePath);
|
|
3743
3911
|
const classDecl = findClassByName(ctx.sourceFile, typeName);
|
|
@@ -3775,6 +3943,51 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
|
|
|
3775
3943
|
if (result.ok) {
|
|
3776
3944
|
return result.analysis;
|
|
3777
3945
|
}
|
|
3946
|
+
const fallbackEligible = result.kind === "not-object-like" && isResolvableObjectLikeAliasTypeNode(typeAlias.type) && containsTypeReferenceInObjectLikeAlias(typeAlias.type);
|
|
3947
|
+
if (!fallbackEligible) {
|
|
3948
|
+
throw new Error(result.error);
|
|
3949
|
+
}
|
|
3950
|
+
const duplicatePropertyNames = findFallbackAliasDuplicatePropertyNames(
|
|
3951
|
+
typeAlias.type,
|
|
3952
|
+
ctx.checker
|
|
3953
|
+
);
|
|
3954
|
+
if (duplicatePropertyNames.length > 0) {
|
|
3955
|
+
const sourceFile = typeAlias.getSourceFile();
|
|
3956
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
3957
|
+
throw new Error(
|
|
3958
|
+
`Type alias "${typeAlias.name.text}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
|
|
3959
|
+
);
|
|
3960
|
+
}
|
|
3961
|
+
const rootInfo = analyzeDeclarationRootInfo(
|
|
3962
|
+
typeAlias,
|
|
3963
|
+
ctx.checker,
|
|
3964
|
+
analysisFilePath,
|
|
3965
|
+
extensionRegistry,
|
|
3966
|
+
metadataPolicy
|
|
3967
|
+
);
|
|
3968
|
+
const diagnostics = [...rootInfo.diagnostics];
|
|
3969
|
+
const typeRegistry = {};
|
|
3970
|
+
const rootType = resolveTypeNode(
|
|
3971
|
+
ctx.checker.getTypeAtLocation(typeAlias),
|
|
3972
|
+
ctx.checker,
|
|
3973
|
+
analysisFilePath,
|
|
3974
|
+
typeRegistry,
|
|
3975
|
+
/* @__PURE__ */ new Set(),
|
|
3976
|
+
typeAlias,
|
|
3977
|
+
createAnalyzerMetadataPolicy(metadataPolicy, discriminatorOptions),
|
|
3978
|
+
extensionRegistry,
|
|
3979
|
+
diagnostics
|
|
3980
|
+
);
|
|
3981
|
+
const fallbackAnalysis = createResolvedObjectAliasAnalysis(
|
|
3982
|
+
typeAlias.name.text,
|
|
3983
|
+
rootType,
|
|
3984
|
+
typeRegistry,
|
|
3985
|
+
rootInfo,
|
|
3986
|
+
diagnostics
|
|
3987
|
+
);
|
|
3988
|
+
if (fallbackAnalysis !== null) {
|
|
3989
|
+
return fallbackAnalysis;
|
|
3990
|
+
}
|
|
3778
3991
|
throw new Error(result.error);
|
|
3779
3992
|
}
|
|
3780
3993
|
throw new Error(
|