@formspec/build 0.1.0-alpha.35 → 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 +207 -12
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +207 -12
- 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 +207 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +207 -12
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +213 -10
- package/dist/internals.cjs.map +1 -1
- package/dist/internals.js +213 -10
- package/dist/internals.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -3016,6 +3016,21 @@ function isObjectType(type) {
|
|
|
3016
3016
|
function isIntersectionType(type) {
|
|
3017
3017
|
return !!(type.flags & ts3.TypeFlags.Intersection);
|
|
3018
3018
|
}
|
|
3019
|
+
function isResolvableObjectLikeAliasTypeNode(typeNode) {
|
|
3020
|
+
if (ts3.isParenthesizedTypeNode(typeNode)) {
|
|
3021
|
+
return isResolvableObjectLikeAliasTypeNode(typeNode.type);
|
|
3022
|
+
}
|
|
3023
|
+
if (ts3.isTypeLiteralNode(typeNode) || ts3.isTypeReferenceNode(typeNode)) {
|
|
3024
|
+
return true;
|
|
3025
|
+
}
|
|
3026
|
+
return ts3.isIntersectionTypeNode(typeNode) && typeNode.types.length > 0 && typeNode.types.every((member) => isResolvableObjectLikeAliasTypeNode(member));
|
|
3027
|
+
}
|
|
3028
|
+
function isSemanticallyPlainObjectLikeType(type, checker) {
|
|
3029
|
+
if (isIntersectionType(type)) {
|
|
3030
|
+
return type.types.length > 0 && type.types.every((member) => isSemanticallyPlainObjectLikeType(member, checker));
|
|
3031
|
+
}
|
|
3032
|
+
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);
|
|
3033
|
+
}
|
|
3019
3034
|
function isTypeReference(type) {
|
|
3020
3035
|
return !!(type.flags & ts3.TypeFlags.Object) && !!(type.objectFlags & ts3.ObjectFlags.Reference);
|
|
3021
3036
|
}
|
|
@@ -3268,6 +3283,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
|
|
|
3268
3283
|
const kindDesc = ts3.SyntaxKind[typeAlias.type.kind] ?? "unknown";
|
|
3269
3284
|
return {
|
|
3270
3285
|
ok: false,
|
|
3286
|
+
kind: "not-object-like",
|
|
3271
3287
|
error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object-like type alias (found ${kindDesc})`
|
|
3272
3288
|
};
|
|
3273
3289
|
}
|
|
@@ -3282,6 +3298,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
|
|
|
3282
3298
|
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
3283
3299
|
return {
|
|
3284
3300
|
ok: false,
|
|
3301
|
+
kind: "duplicate-properties",
|
|
3285
3302
|
error: `Type alias "${name}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
|
|
3286
3303
|
};
|
|
3287
3304
|
}
|
|
@@ -3978,10 +3995,10 @@ function findDuplicateObjectLikeTypeAliasPropertyNames(members) {
|
|
|
3978
3995
|
return [...duplicates].sort();
|
|
3979
3996
|
}
|
|
3980
3997
|
function getAnalyzableObjectLikePropertyName(name) {
|
|
3981
|
-
if (
|
|
3982
|
-
return
|
|
3998
|
+
if (ts3.isIdentifier(name) || ts3.isStringLiteral(name) || ts3.isNumericLiteral(name)) {
|
|
3999
|
+
return name.text;
|
|
3983
4000
|
}
|
|
3984
|
-
return
|
|
4001
|
+
return null;
|
|
3985
4002
|
}
|
|
3986
4003
|
function applyEnumMemberDisplayNames(type, annotations) {
|
|
3987
4004
|
if (!annotations.some(
|
|
@@ -4072,7 +4089,7 @@ function resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, ch
|
|
|
4072
4089
|
};
|
|
4073
4090
|
}
|
|
4074
4091
|
if (ts3.isTypeReferenceNode(typeNode) && ts3.isIdentifier(typeNode.typeName)) {
|
|
4075
|
-
const aliasDecl =
|
|
4092
|
+
const aliasDecl = getTypeAliasDeclarationFromTypeReference(typeNode, checker);
|
|
4076
4093
|
if (aliasDecl !== void 0) {
|
|
4077
4094
|
return resolveRegisteredCustomTypeFromTypeNode(aliasDecl.type, extensionRegistry, checker);
|
|
4078
4095
|
}
|
|
@@ -4191,6 +4208,19 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
4191
4208
|
diagnostics
|
|
4192
4209
|
);
|
|
4193
4210
|
}
|
|
4211
|
+
if (resolvedSourceTypeNode !== void 0 && isResolvableObjectLikeAliasTypeNode(resolvedSourceTypeNode) && isSemanticallyPlainObjectLikeType(type, checker)) {
|
|
4212
|
+
return resolveObjectType(
|
|
4213
|
+
type,
|
|
4214
|
+
checker,
|
|
4215
|
+
file,
|
|
4216
|
+
typeRegistry,
|
|
4217
|
+
visiting,
|
|
4218
|
+
sourceNode,
|
|
4219
|
+
metadataPolicy,
|
|
4220
|
+
extensionRegistry,
|
|
4221
|
+
diagnostics
|
|
4222
|
+
);
|
|
4223
|
+
}
|
|
4194
4224
|
}
|
|
4195
4225
|
if (isObjectType(type)) {
|
|
4196
4226
|
return resolveObjectType(
|
|
@@ -4265,13 +4295,13 @@ function getReferencedTypeAliasDeclaration(sourceNode, checker) {
|
|
|
4265
4295
|
if (!typeNode || !ts3.isTypeReferenceNode(typeNode)) {
|
|
4266
4296
|
return void 0;
|
|
4267
4297
|
}
|
|
4268
|
-
return
|
|
4298
|
+
return getTypeAliasDeclarationFromTypeReference(typeNode, checker);
|
|
4269
4299
|
}
|
|
4270
4300
|
function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
|
|
4271
4301
|
if (!ts3.isTypeReferenceNode(typeNode)) {
|
|
4272
4302
|
return false;
|
|
4273
4303
|
}
|
|
4274
|
-
const aliasDecl =
|
|
4304
|
+
const aliasDecl = getTypeAliasDeclarationFromTypeReference(typeNode, checker);
|
|
4275
4305
|
if (!aliasDecl) {
|
|
4276
4306
|
return false;
|
|
4277
4307
|
}
|
|
@@ -4840,8 +4870,7 @@ function resolveAliasedTypeNode(typeNode, checker, visited = /* @__PURE__ */ new
|
|
|
4840
4870
|
if (!ts3.isTypeReferenceNode(typeNode) || !ts3.isIdentifier(typeNode.typeName)) {
|
|
4841
4871
|
return typeNode;
|
|
4842
4872
|
}
|
|
4843
|
-
const
|
|
4844
|
-
const aliasDecl = symbol?.declarations?.find(ts3.isTypeAliasDeclaration);
|
|
4873
|
+
const aliasDecl = getTypeAliasDeclarationFromTypeReference(typeNode, checker);
|
|
4845
4874
|
if (aliasDecl === void 0 || visited.has(aliasDecl)) {
|
|
4846
4875
|
return typeNode;
|
|
4847
4876
|
}
|
|
@@ -4890,8 +4919,7 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
|
|
|
4890
4919
|
);
|
|
4891
4920
|
}
|
|
4892
4921
|
const symbol = checker.getSymbolAtLocation(typeNode.typeName);
|
|
4893
|
-
|
|
4894
|
-
const aliasDecl = symbol.declarations.find(ts3.isTypeAliasDeclaration);
|
|
4922
|
+
const aliasDecl = getAliasedTypeAliasDeclaration(symbol, checker);
|
|
4895
4923
|
if (!aliasDecl) return [];
|
|
4896
4924
|
if (ts3.isTypeLiteralNode(aliasDecl.type)) return [];
|
|
4897
4925
|
const aliasFieldType = resolveTypeNode(
|
|
@@ -4914,6 +4942,18 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
|
|
|
4914
4942
|
);
|
|
4915
4943
|
return constraints;
|
|
4916
4944
|
}
|
|
4945
|
+
function getAliasedSymbol(symbol, checker) {
|
|
4946
|
+
if (symbol === void 0) {
|
|
4947
|
+
return void 0;
|
|
4948
|
+
}
|
|
4949
|
+
return symbol.flags & ts3.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
4950
|
+
}
|
|
4951
|
+
function getAliasedTypeAliasDeclaration(symbol, checker) {
|
|
4952
|
+
return getAliasedSymbol(symbol, checker)?.declarations?.find(ts3.isTypeAliasDeclaration);
|
|
4953
|
+
}
|
|
4954
|
+
function getTypeAliasDeclarationFromTypeReference(typeNode, checker) {
|
|
4955
|
+
return getAliasedTypeAliasDeclaration(checker.getSymbolAtLocation(typeNode.typeName), checker);
|
|
4956
|
+
}
|
|
4917
4957
|
function provenanceForNode(node, file) {
|
|
4918
4958
|
const sourceFile = node.getSourceFile();
|
|
4919
4959
|
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
@@ -5104,6 +5144,95 @@ function findInterfaceByName(sourceFile, interfaceName) {
|
|
|
5104
5144
|
function findTypeAliasByName(sourceFile, aliasName) {
|
|
5105
5145
|
return findNodeByName(sourceFile, aliasName, ts4.isTypeAliasDeclaration, (n) => n.name.text);
|
|
5106
5146
|
}
|
|
5147
|
+
function getResolvedObjectRootType(rootType, typeRegistry) {
|
|
5148
|
+
if (rootType.kind === "object") {
|
|
5149
|
+
return rootType;
|
|
5150
|
+
}
|
|
5151
|
+
if (rootType.kind !== "reference") {
|
|
5152
|
+
return null;
|
|
5153
|
+
}
|
|
5154
|
+
const definition = typeRegistry[rootType.name];
|
|
5155
|
+
return definition?.type.kind === "object" ? definition.type : null;
|
|
5156
|
+
}
|
|
5157
|
+
function createResolvedObjectAliasAnalysis(name, rootType, typeRegistry, rootInfo, diagnostics) {
|
|
5158
|
+
const resolvedRootType = getResolvedObjectRootType(rootType, typeRegistry);
|
|
5159
|
+
if (resolvedRootType === null) {
|
|
5160
|
+
return null;
|
|
5161
|
+
}
|
|
5162
|
+
const fields = resolvedRootType.properties.map((property) => ({
|
|
5163
|
+
kind: "field",
|
|
5164
|
+
name: property.name,
|
|
5165
|
+
...property.metadata !== void 0 && { metadata: property.metadata },
|
|
5166
|
+
type: property.type,
|
|
5167
|
+
required: !property.optional,
|
|
5168
|
+
constraints: property.constraints,
|
|
5169
|
+
annotations: property.annotations,
|
|
5170
|
+
provenance: property.provenance
|
|
5171
|
+
}));
|
|
5172
|
+
return {
|
|
5173
|
+
name,
|
|
5174
|
+
...rootInfo.metadata !== void 0 && { metadata: rootInfo.metadata },
|
|
5175
|
+
fields,
|
|
5176
|
+
fieldLayouts: fields.map(() => ({})),
|
|
5177
|
+
typeRegistry,
|
|
5178
|
+
...rootInfo.annotations.length > 0 && { annotations: [...rootInfo.annotations] },
|
|
5179
|
+
...diagnostics.length > 0 && { diagnostics: [...diagnostics] },
|
|
5180
|
+
instanceMethods: [],
|
|
5181
|
+
staticMethods: []
|
|
5182
|
+
};
|
|
5183
|
+
}
|
|
5184
|
+
function containsTypeReferenceInObjectLikeAlias(typeNode) {
|
|
5185
|
+
if (ts4.isParenthesizedTypeNode(typeNode)) {
|
|
5186
|
+
return containsTypeReferenceInObjectLikeAlias(typeNode.type);
|
|
5187
|
+
}
|
|
5188
|
+
if (ts4.isTypeReferenceNode(typeNode)) {
|
|
5189
|
+
return true;
|
|
5190
|
+
}
|
|
5191
|
+
return ts4.isIntersectionTypeNode(typeNode) && typeNode.types.some((member) => containsTypeReferenceInObjectLikeAlias(member));
|
|
5192
|
+
}
|
|
5193
|
+
function collectFallbackAliasMemberPropertyNames(typeNode, checker) {
|
|
5194
|
+
if (ts4.isParenthesizedTypeNode(typeNode)) {
|
|
5195
|
+
return collectFallbackAliasMemberPropertyNames(typeNode.type, checker);
|
|
5196
|
+
}
|
|
5197
|
+
if (ts4.isTypeLiteralNode(typeNode)) {
|
|
5198
|
+
const propertyNames = [];
|
|
5199
|
+
for (const member of typeNode.members) {
|
|
5200
|
+
if (!ts4.isPropertySignature(member)) {
|
|
5201
|
+
continue;
|
|
5202
|
+
}
|
|
5203
|
+
const propertyName = getAnalyzableObjectLikePropertyName(member.name);
|
|
5204
|
+
if (propertyName !== null) {
|
|
5205
|
+
propertyNames.push(propertyName);
|
|
5206
|
+
}
|
|
5207
|
+
}
|
|
5208
|
+
return propertyNames;
|
|
5209
|
+
}
|
|
5210
|
+
if (ts4.isTypeReferenceNode(typeNode)) {
|
|
5211
|
+
return checker.getTypeFromTypeNode(typeNode).getProperties().map((property) => property.getName());
|
|
5212
|
+
}
|
|
5213
|
+
return null;
|
|
5214
|
+
}
|
|
5215
|
+
function findFallbackAliasDuplicatePropertyNames(typeNode, checker) {
|
|
5216
|
+
if (!ts4.isIntersectionTypeNode(typeNode)) {
|
|
5217
|
+
return [];
|
|
5218
|
+
}
|
|
5219
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5220
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
5221
|
+
for (const member of typeNode.types) {
|
|
5222
|
+
const propertyNames = collectFallbackAliasMemberPropertyNames(member, checker);
|
|
5223
|
+
if (propertyNames === null) {
|
|
5224
|
+
continue;
|
|
5225
|
+
}
|
|
5226
|
+
for (const propertyName of propertyNames) {
|
|
5227
|
+
if (seen.has(propertyName)) {
|
|
5228
|
+
duplicates.add(propertyName);
|
|
5229
|
+
} else {
|
|
5230
|
+
seen.add(propertyName);
|
|
5231
|
+
}
|
|
5232
|
+
}
|
|
5233
|
+
}
|
|
5234
|
+
return [...duplicates].sort();
|
|
5235
|
+
}
|
|
5107
5236
|
function analyzeNamedTypeToIR(filePath, typeName, extensionRegistry, metadataPolicy, discriminatorOptions) {
|
|
5108
5237
|
const ctx = createProgramContext(filePath);
|
|
5109
5238
|
return analyzeNamedTypeToIRFromProgramContext(
|
|
@@ -5152,6 +5281,51 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
|
|
|
5152
5281
|
if (result.ok) {
|
|
5153
5282
|
return result.analysis;
|
|
5154
5283
|
}
|
|
5284
|
+
const fallbackEligible = result.kind === "not-object-like" && isResolvableObjectLikeAliasTypeNode(typeAlias.type) && containsTypeReferenceInObjectLikeAlias(typeAlias.type);
|
|
5285
|
+
if (!fallbackEligible) {
|
|
5286
|
+
throw new Error(result.error);
|
|
5287
|
+
}
|
|
5288
|
+
const duplicatePropertyNames = findFallbackAliasDuplicatePropertyNames(
|
|
5289
|
+
typeAlias.type,
|
|
5290
|
+
ctx.checker
|
|
5291
|
+
);
|
|
5292
|
+
if (duplicatePropertyNames.length > 0) {
|
|
5293
|
+
const sourceFile = typeAlias.getSourceFile();
|
|
5294
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
5295
|
+
throw new Error(
|
|
5296
|
+
`Type alias "${typeAlias.name.text}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
|
|
5297
|
+
);
|
|
5298
|
+
}
|
|
5299
|
+
const rootInfo = analyzeDeclarationRootInfo(
|
|
5300
|
+
typeAlias,
|
|
5301
|
+
ctx.checker,
|
|
5302
|
+
analysisFilePath,
|
|
5303
|
+
extensionRegistry,
|
|
5304
|
+
metadataPolicy
|
|
5305
|
+
);
|
|
5306
|
+
const diagnostics = [...rootInfo.diagnostics];
|
|
5307
|
+
const typeRegistry = {};
|
|
5308
|
+
const rootType = resolveTypeNode(
|
|
5309
|
+
ctx.checker.getTypeAtLocation(typeAlias),
|
|
5310
|
+
ctx.checker,
|
|
5311
|
+
analysisFilePath,
|
|
5312
|
+
typeRegistry,
|
|
5313
|
+
/* @__PURE__ */ new Set(),
|
|
5314
|
+
typeAlias,
|
|
5315
|
+
createAnalyzerMetadataPolicy(metadataPolicy, discriminatorOptions),
|
|
5316
|
+
extensionRegistry,
|
|
5317
|
+
diagnostics
|
|
5318
|
+
);
|
|
5319
|
+
const fallbackAnalysis = createResolvedObjectAliasAnalysis(
|
|
5320
|
+
typeAlias.name.text,
|
|
5321
|
+
rootType,
|
|
5322
|
+
typeRegistry,
|
|
5323
|
+
rootInfo,
|
|
5324
|
+
diagnostics
|
|
5325
|
+
);
|
|
5326
|
+
if (fallbackAnalysis !== null) {
|
|
5327
|
+
return fallbackAnalysis;
|
|
5328
|
+
}
|
|
5155
5329
|
throw new Error(result.error);
|
|
5156
5330
|
}
|
|
5157
5331
|
throw new Error(
|
|
@@ -5694,15 +5868,36 @@ function generateSchemasFromParameter(options) {
|
|
|
5694
5868
|
}
|
|
5695
5869
|
function generateSchemasFromReturnType(options) {
|
|
5696
5870
|
const signature = options.context.checker.getSignatureFromDeclaration(options.declaration);
|
|
5697
|
-
const
|
|
5871
|
+
const returnType = signature !== void 0 ? options.context.checker.getReturnTypeOfSignature(signature) : options.context.checker.getTypeAtLocation(options.declaration);
|
|
5872
|
+
const type = unwrapPromiseType(options.context.checker, returnType);
|
|
5873
|
+
const sourceNode = type !== returnType ? unwrapPromiseTypeNode(options.declaration.type) ?? options.declaration.type ?? options.declaration : options.declaration.type ?? options.declaration;
|
|
5698
5874
|
const fallbackName = options.declaration.name !== void 0 && ts7.isIdentifier(options.declaration.name) ? `${options.declaration.name.text}ReturnType` : "ReturnType";
|
|
5699
5875
|
return generateSchemasFromResolvedType({
|
|
5700
5876
|
...options,
|
|
5701
5877
|
type,
|
|
5702
|
-
sourceNode
|
|
5878
|
+
sourceNode,
|
|
5703
5879
|
name: fallbackName
|
|
5704
5880
|
});
|
|
5705
5881
|
}
|
|
5882
|
+
function unwrapPromiseType(checker, type) {
|
|
5883
|
+
if (!("getAwaitedType" in checker) || typeof checker.getAwaitedType !== "function") {
|
|
5884
|
+
return type;
|
|
5885
|
+
}
|
|
5886
|
+
return checker.getAwaitedType(type) ?? type;
|
|
5887
|
+
}
|
|
5888
|
+
function unwrapPromiseTypeNode(typeNode) {
|
|
5889
|
+
if (typeNode === void 0) {
|
|
5890
|
+
return void 0;
|
|
5891
|
+
}
|
|
5892
|
+
if (ts7.isParenthesizedTypeNode(typeNode)) {
|
|
5893
|
+
const unwrapped = unwrapPromiseTypeNode(typeNode.type);
|
|
5894
|
+
return unwrapped ?? typeNode;
|
|
5895
|
+
}
|
|
5896
|
+
return isPromiseTypeReferenceNode(typeNode) ? typeNode.typeArguments[0] : typeNode;
|
|
5897
|
+
}
|
|
5898
|
+
function isPromiseTypeReferenceNode(typeNode) {
|
|
5899
|
+
return ts7.isTypeReferenceNode(typeNode) && ts7.isIdentifier(typeNode.typeName) && typeNode.typeName.text === "Promise" && typeNode.typeArguments !== void 0 && typeNode.typeArguments.length > 0;
|
|
5900
|
+
}
|
|
5706
5901
|
var init_discovered_schema = __esm({
|
|
5707
5902
|
"src/generators/discovered-schema.ts"() {
|
|
5708
5903
|
"use strict";
|