@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/cli.js
CHANGED
|
@@ -2237,6 +2237,16 @@ function buildSupportingDeclarations(sourceFile, extensionTypeNames) {
|
|
|
2237
2237
|
return true;
|
|
2238
2238
|
}).map((statement) => statement.getText(sourceFile));
|
|
2239
2239
|
}
|
|
2240
|
+
function pushUniqueCompilerDiagnostics(target, additions) {
|
|
2241
|
+
for (const diagnostic of additions) {
|
|
2242
|
+
if ((diagnostic.code === "UNSUPPORTED_CUSTOM_TYPE_OVERRIDE" || diagnostic.code === "SYNTHETIC_SETUP_FAILURE") && target.some(
|
|
2243
|
+
(existing) => existing.code === diagnostic.code && existing.message === diagnostic.message
|
|
2244
|
+
)) {
|
|
2245
|
+
continue;
|
|
2246
|
+
}
|
|
2247
|
+
target.push(diagnostic);
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2240
2250
|
function renderSyntheticArgumentExpression(valueKind, argumentText) {
|
|
2241
2251
|
const trimmed = argumentText.trim();
|
|
2242
2252
|
if (trimmed === "") {
|
|
@@ -2503,6 +2513,16 @@ function buildCompilerBackedConstraintDiagnostics(node, sourceFile, tagName, par
|
|
|
2503
2513
|
if (result.diagnostics.length === 0) {
|
|
2504
2514
|
return [];
|
|
2505
2515
|
}
|
|
2516
|
+
const setupDiagnostic = result.diagnostics.find((diagnostic) => diagnostic.kind !== "typescript");
|
|
2517
|
+
if (setupDiagnostic !== void 0) {
|
|
2518
|
+
return [
|
|
2519
|
+
makeDiagnostic(
|
|
2520
|
+
setupDiagnostic.kind === "unsupported-custom-type-override" ? "UNSUPPORTED_CUSTOM_TYPE_OVERRIDE" : "SYNTHETIC_SETUP_FAILURE",
|
|
2521
|
+
setupDiagnostic.message,
|
|
2522
|
+
provenance
|
|
2523
|
+
)
|
|
2524
|
+
];
|
|
2525
|
+
}
|
|
2506
2526
|
const expectedLabel = definition.valueKind === null ? "compatible argument" : capabilityLabel(definition.valueKind);
|
|
2507
2527
|
return [
|
|
2508
2528
|
makeDiagnostic(
|
|
@@ -2666,7 +2686,7 @@ function parseTSDocTags(node, file = "", options) {
|
|
|
2666
2686
|
options
|
|
2667
2687
|
);
|
|
2668
2688
|
if (compilerDiagnostics.length > 0) {
|
|
2669
|
-
diagnostics
|
|
2689
|
+
pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
|
|
2670
2690
|
continue;
|
|
2671
2691
|
}
|
|
2672
2692
|
const constraintNode = parseConstraintTagValue(
|
|
@@ -2753,7 +2773,7 @@ function parseTSDocTags(node, file = "", options) {
|
|
|
2753
2773
|
options
|
|
2754
2774
|
);
|
|
2755
2775
|
if (compilerDiagnostics.length > 0) {
|
|
2756
|
-
diagnostics
|
|
2776
|
+
pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
|
|
2757
2777
|
continue;
|
|
2758
2778
|
}
|
|
2759
2779
|
const constraintNode = parseConstraintTagValue(
|
|
@@ -2787,7 +2807,7 @@ function parseTSDocTags(node, file = "", options) {
|
|
|
2787
2807
|
options
|
|
2788
2808
|
);
|
|
2789
2809
|
if (compilerDiagnostics.length > 0) {
|
|
2790
|
-
diagnostics
|
|
2810
|
+
pushUniqueCompilerDiagnostics(diagnostics, compilerDiagnostics);
|
|
2791
2811
|
continue;
|
|
2792
2812
|
}
|
|
2793
2813
|
const constraintNode = parseConstraintTagValue(
|
|
@@ -3016,6 +3036,21 @@ function isObjectType(type) {
|
|
|
3016
3036
|
function isIntersectionType(type) {
|
|
3017
3037
|
return !!(type.flags & ts3.TypeFlags.Intersection);
|
|
3018
3038
|
}
|
|
3039
|
+
function isResolvableObjectLikeAliasTypeNode(typeNode) {
|
|
3040
|
+
if (ts3.isParenthesizedTypeNode(typeNode)) {
|
|
3041
|
+
return isResolvableObjectLikeAliasTypeNode(typeNode.type);
|
|
3042
|
+
}
|
|
3043
|
+
if (ts3.isTypeLiteralNode(typeNode) || ts3.isTypeReferenceNode(typeNode)) {
|
|
3044
|
+
return true;
|
|
3045
|
+
}
|
|
3046
|
+
return ts3.isIntersectionTypeNode(typeNode) && typeNode.types.length > 0 && typeNode.types.every((member) => isResolvableObjectLikeAliasTypeNode(member));
|
|
3047
|
+
}
|
|
3048
|
+
function isSemanticallyPlainObjectLikeType(type, checker) {
|
|
3049
|
+
if (isIntersectionType(type)) {
|
|
3050
|
+
return type.types.length > 0 && type.types.every((member) => isSemanticallyPlainObjectLikeType(member, checker));
|
|
3051
|
+
}
|
|
3052
|
+
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);
|
|
3053
|
+
}
|
|
3019
3054
|
function isTypeReference(type) {
|
|
3020
3055
|
return !!(type.flags & ts3.TypeFlags.Object) && !!(type.objectFlags & ts3.ObjectFlags.Reference);
|
|
3021
3056
|
}
|
|
@@ -3268,6 +3303,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
|
|
|
3268
3303
|
const kindDesc = ts3.SyntaxKind[typeAlias.type.kind] ?? "unknown";
|
|
3269
3304
|
return {
|
|
3270
3305
|
ok: false,
|
|
3306
|
+
kind: "not-object-like",
|
|
3271
3307
|
error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object-like type alias (found ${kindDesc})`
|
|
3272
3308
|
};
|
|
3273
3309
|
}
|
|
@@ -3282,6 +3318,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
|
|
|
3282
3318
|
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
3283
3319
|
return {
|
|
3284
3320
|
ok: false,
|
|
3321
|
+
kind: "duplicate-properties",
|
|
3285
3322
|
error: `Type alias "${name}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
|
|
3286
3323
|
};
|
|
3287
3324
|
}
|
|
@@ -3978,10 +4015,10 @@ function findDuplicateObjectLikeTypeAliasPropertyNames(members) {
|
|
|
3978
4015
|
return [...duplicates].sort();
|
|
3979
4016
|
}
|
|
3980
4017
|
function getAnalyzableObjectLikePropertyName(name) {
|
|
3981
|
-
if (
|
|
3982
|
-
return
|
|
4018
|
+
if (ts3.isIdentifier(name) || ts3.isStringLiteral(name) || ts3.isNumericLiteral(name)) {
|
|
4019
|
+
return name.text;
|
|
3983
4020
|
}
|
|
3984
|
-
return
|
|
4021
|
+
return null;
|
|
3985
4022
|
}
|
|
3986
4023
|
function applyEnumMemberDisplayNames(type, annotations) {
|
|
3987
4024
|
if (!annotations.some(
|
|
@@ -4191,6 +4228,19 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
4191
4228
|
diagnostics
|
|
4192
4229
|
);
|
|
4193
4230
|
}
|
|
4231
|
+
if (resolvedSourceTypeNode !== void 0 && isResolvableObjectLikeAliasTypeNode(resolvedSourceTypeNode) && isSemanticallyPlainObjectLikeType(type, checker)) {
|
|
4232
|
+
return resolveObjectType(
|
|
4233
|
+
type,
|
|
4234
|
+
checker,
|
|
4235
|
+
file,
|
|
4236
|
+
typeRegistry,
|
|
4237
|
+
visiting,
|
|
4238
|
+
sourceNode,
|
|
4239
|
+
metadataPolicy,
|
|
4240
|
+
extensionRegistry,
|
|
4241
|
+
diagnostics
|
|
4242
|
+
);
|
|
4243
|
+
}
|
|
4194
4244
|
}
|
|
4195
4245
|
if (isObjectType(type)) {
|
|
4196
4246
|
return resolveObjectType(
|
|
@@ -5114,6 +5164,95 @@ function findInterfaceByName(sourceFile, interfaceName) {
|
|
|
5114
5164
|
function findTypeAliasByName(sourceFile, aliasName) {
|
|
5115
5165
|
return findNodeByName(sourceFile, aliasName, ts4.isTypeAliasDeclaration, (n) => n.name.text);
|
|
5116
5166
|
}
|
|
5167
|
+
function getResolvedObjectRootType(rootType, typeRegistry) {
|
|
5168
|
+
if (rootType.kind === "object") {
|
|
5169
|
+
return rootType;
|
|
5170
|
+
}
|
|
5171
|
+
if (rootType.kind !== "reference") {
|
|
5172
|
+
return null;
|
|
5173
|
+
}
|
|
5174
|
+
const definition = typeRegistry[rootType.name];
|
|
5175
|
+
return definition?.type.kind === "object" ? definition.type : null;
|
|
5176
|
+
}
|
|
5177
|
+
function createResolvedObjectAliasAnalysis(name, rootType, typeRegistry, rootInfo, diagnostics) {
|
|
5178
|
+
const resolvedRootType = getResolvedObjectRootType(rootType, typeRegistry);
|
|
5179
|
+
if (resolvedRootType === null) {
|
|
5180
|
+
return null;
|
|
5181
|
+
}
|
|
5182
|
+
const fields = resolvedRootType.properties.map((property) => ({
|
|
5183
|
+
kind: "field",
|
|
5184
|
+
name: property.name,
|
|
5185
|
+
...property.metadata !== void 0 && { metadata: property.metadata },
|
|
5186
|
+
type: property.type,
|
|
5187
|
+
required: !property.optional,
|
|
5188
|
+
constraints: property.constraints,
|
|
5189
|
+
annotations: property.annotations,
|
|
5190
|
+
provenance: property.provenance
|
|
5191
|
+
}));
|
|
5192
|
+
return {
|
|
5193
|
+
name,
|
|
5194
|
+
...rootInfo.metadata !== void 0 && { metadata: rootInfo.metadata },
|
|
5195
|
+
fields,
|
|
5196
|
+
fieldLayouts: fields.map(() => ({})),
|
|
5197
|
+
typeRegistry,
|
|
5198
|
+
...rootInfo.annotations.length > 0 && { annotations: [...rootInfo.annotations] },
|
|
5199
|
+
...diagnostics.length > 0 && { diagnostics: [...diagnostics] },
|
|
5200
|
+
instanceMethods: [],
|
|
5201
|
+
staticMethods: []
|
|
5202
|
+
};
|
|
5203
|
+
}
|
|
5204
|
+
function containsTypeReferenceInObjectLikeAlias(typeNode) {
|
|
5205
|
+
if (ts4.isParenthesizedTypeNode(typeNode)) {
|
|
5206
|
+
return containsTypeReferenceInObjectLikeAlias(typeNode.type);
|
|
5207
|
+
}
|
|
5208
|
+
if (ts4.isTypeReferenceNode(typeNode)) {
|
|
5209
|
+
return true;
|
|
5210
|
+
}
|
|
5211
|
+
return ts4.isIntersectionTypeNode(typeNode) && typeNode.types.some((member) => containsTypeReferenceInObjectLikeAlias(member));
|
|
5212
|
+
}
|
|
5213
|
+
function collectFallbackAliasMemberPropertyNames(typeNode, checker) {
|
|
5214
|
+
if (ts4.isParenthesizedTypeNode(typeNode)) {
|
|
5215
|
+
return collectFallbackAliasMemberPropertyNames(typeNode.type, checker);
|
|
5216
|
+
}
|
|
5217
|
+
if (ts4.isTypeLiteralNode(typeNode)) {
|
|
5218
|
+
const propertyNames = [];
|
|
5219
|
+
for (const member of typeNode.members) {
|
|
5220
|
+
if (!ts4.isPropertySignature(member)) {
|
|
5221
|
+
continue;
|
|
5222
|
+
}
|
|
5223
|
+
const propertyName = getAnalyzableObjectLikePropertyName(member.name);
|
|
5224
|
+
if (propertyName !== null) {
|
|
5225
|
+
propertyNames.push(propertyName);
|
|
5226
|
+
}
|
|
5227
|
+
}
|
|
5228
|
+
return propertyNames;
|
|
5229
|
+
}
|
|
5230
|
+
if (ts4.isTypeReferenceNode(typeNode)) {
|
|
5231
|
+
return checker.getTypeFromTypeNode(typeNode).getProperties().map((property) => property.getName());
|
|
5232
|
+
}
|
|
5233
|
+
return null;
|
|
5234
|
+
}
|
|
5235
|
+
function findFallbackAliasDuplicatePropertyNames(typeNode, checker) {
|
|
5236
|
+
if (!ts4.isIntersectionTypeNode(typeNode)) {
|
|
5237
|
+
return [];
|
|
5238
|
+
}
|
|
5239
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5240
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
5241
|
+
for (const member of typeNode.types) {
|
|
5242
|
+
const propertyNames = collectFallbackAliasMemberPropertyNames(member, checker);
|
|
5243
|
+
if (propertyNames === null) {
|
|
5244
|
+
continue;
|
|
5245
|
+
}
|
|
5246
|
+
for (const propertyName of propertyNames) {
|
|
5247
|
+
if (seen.has(propertyName)) {
|
|
5248
|
+
duplicates.add(propertyName);
|
|
5249
|
+
} else {
|
|
5250
|
+
seen.add(propertyName);
|
|
5251
|
+
}
|
|
5252
|
+
}
|
|
5253
|
+
}
|
|
5254
|
+
return [...duplicates].sort();
|
|
5255
|
+
}
|
|
5117
5256
|
function analyzeNamedTypeToIR(filePath, typeName, extensionRegistry, metadataPolicy, discriminatorOptions) {
|
|
5118
5257
|
const ctx = createProgramContext(filePath);
|
|
5119
5258
|
return analyzeNamedTypeToIRFromProgramContext(
|
|
@@ -5162,6 +5301,51 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
|
|
|
5162
5301
|
if (result.ok) {
|
|
5163
5302
|
return result.analysis;
|
|
5164
5303
|
}
|
|
5304
|
+
const fallbackEligible = result.kind === "not-object-like" && isResolvableObjectLikeAliasTypeNode(typeAlias.type) && containsTypeReferenceInObjectLikeAlias(typeAlias.type);
|
|
5305
|
+
if (!fallbackEligible) {
|
|
5306
|
+
throw new Error(result.error);
|
|
5307
|
+
}
|
|
5308
|
+
const duplicatePropertyNames = findFallbackAliasDuplicatePropertyNames(
|
|
5309
|
+
typeAlias.type,
|
|
5310
|
+
ctx.checker
|
|
5311
|
+
);
|
|
5312
|
+
if (duplicatePropertyNames.length > 0) {
|
|
5313
|
+
const sourceFile = typeAlias.getSourceFile();
|
|
5314
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
5315
|
+
throw new Error(
|
|
5316
|
+
`Type alias "${typeAlias.name.text}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
|
|
5317
|
+
);
|
|
5318
|
+
}
|
|
5319
|
+
const rootInfo = analyzeDeclarationRootInfo(
|
|
5320
|
+
typeAlias,
|
|
5321
|
+
ctx.checker,
|
|
5322
|
+
analysisFilePath,
|
|
5323
|
+
extensionRegistry,
|
|
5324
|
+
metadataPolicy
|
|
5325
|
+
);
|
|
5326
|
+
const diagnostics = [...rootInfo.diagnostics];
|
|
5327
|
+
const typeRegistry = {};
|
|
5328
|
+
const rootType = resolveTypeNode(
|
|
5329
|
+
ctx.checker.getTypeAtLocation(typeAlias),
|
|
5330
|
+
ctx.checker,
|
|
5331
|
+
analysisFilePath,
|
|
5332
|
+
typeRegistry,
|
|
5333
|
+
/* @__PURE__ */ new Set(),
|
|
5334
|
+
typeAlias,
|
|
5335
|
+
createAnalyzerMetadataPolicy(metadataPolicy, discriminatorOptions),
|
|
5336
|
+
extensionRegistry,
|
|
5337
|
+
diagnostics
|
|
5338
|
+
);
|
|
5339
|
+
const fallbackAnalysis = createResolvedObjectAliasAnalysis(
|
|
5340
|
+
typeAlias.name.text,
|
|
5341
|
+
rootType,
|
|
5342
|
+
typeRegistry,
|
|
5343
|
+
rootInfo,
|
|
5344
|
+
diagnostics
|
|
5345
|
+
);
|
|
5346
|
+
if (fallbackAnalysis !== null) {
|
|
5347
|
+
return fallbackAnalysis;
|
|
5348
|
+
}
|
|
5165
5349
|
throw new Error(result.error);
|
|
5166
5350
|
}
|
|
5167
5351
|
throw new Error(
|
|
@@ -5704,15 +5888,36 @@ function generateSchemasFromParameter(options) {
|
|
|
5704
5888
|
}
|
|
5705
5889
|
function generateSchemasFromReturnType(options) {
|
|
5706
5890
|
const signature = options.context.checker.getSignatureFromDeclaration(options.declaration);
|
|
5707
|
-
const
|
|
5891
|
+
const returnType = signature !== void 0 ? options.context.checker.getReturnTypeOfSignature(signature) : options.context.checker.getTypeAtLocation(options.declaration);
|
|
5892
|
+
const type = unwrapPromiseType(options.context.checker, returnType);
|
|
5893
|
+
const sourceNode = type !== returnType ? unwrapPromiseTypeNode(options.declaration.type) ?? options.declaration.type ?? options.declaration : options.declaration.type ?? options.declaration;
|
|
5708
5894
|
const fallbackName = options.declaration.name !== void 0 && ts7.isIdentifier(options.declaration.name) ? `${options.declaration.name.text}ReturnType` : "ReturnType";
|
|
5709
5895
|
return generateSchemasFromResolvedType({
|
|
5710
5896
|
...options,
|
|
5711
5897
|
type,
|
|
5712
|
-
sourceNode
|
|
5898
|
+
sourceNode,
|
|
5713
5899
|
name: fallbackName
|
|
5714
5900
|
});
|
|
5715
5901
|
}
|
|
5902
|
+
function unwrapPromiseType(checker, type) {
|
|
5903
|
+
if (!("getAwaitedType" in checker) || typeof checker.getAwaitedType !== "function") {
|
|
5904
|
+
return type;
|
|
5905
|
+
}
|
|
5906
|
+
return checker.getAwaitedType(type) ?? type;
|
|
5907
|
+
}
|
|
5908
|
+
function unwrapPromiseTypeNode(typeNode) {
|
|
5909
|
+
if (typeNode === void 0) {
|
|
5910
|
+
return void 0;
|
|
5911
|
+
}
|
|
5912
|
+
if (ts7.isParenthesizedTypeNode(typeNode)) {
|
|
5913
|
+
const unwrapped = unwrapPromiseTypeNode(typeNode.type);
|
|
5914
|
+
return unwrapped ?? typeNode;
|
|
5915
|
+
}
|
|
5916
|
+
return isPromiseTypeReferenceNode(typeNode) ? typeNode.typeArguments[0] : typeNode;
|
|
5917
|
+
}
|
|
5918
|
+
function isPromiseTypeReferenceNode(typeNode) {
|
|
5919
|
+
return ts7.isTypeReferenceNode(typeNode) && ts7.isIdentifier(typeNode.typeName) && typeNode.typeName.text === "Promise" && typeNode.typeArguments !== void 0 && typeNode.typeArguments.length > 0;
|
|
5920
|
+
}
|
|
5716
5921
|
var init_discovered_schema = __esm({
|
|
5717
5922
|
"src/generators/discovered-schema.ts"() {
|
|
5718
5923
|
"use strict";
|