@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/index.js
CHANGED
|
@@ -2906,6 +2906,21 @@ function isObjectType(type) {
|
|
|
2906
2906
|
function isIntersectionType(type) {
|
|
2907
2907
|
return !!(type.flags & ts3.TypeFlags.Intersection);
|
|
2908
2908
|
}
|
|
2909
|
+
function isResolvableObjectLikeAliasTypeNode(typeNode) {
|
|
2910
|
+
if (ts3.isParenthesizedTypeNode(typeNode)) {
|
|
2911
|
+
return isResolvableObjectLikeAliasTypeNode(typeNode.type);
|
|
2912
|
+
}
|
|
2913
|
+
if (ts3.isTypeLiteralNode(typeNode) || ts3.isTypeReferenceNode(typeNode)) {
|
|
2914
|
+
return true;
|
|
2915
|
+
}
|
|
2916
|
+
return ts3.isIntersectionTypeNode(typeNode) && typeNode.types.length > 0 && typeNode.types.every((member) => isResolvableObjectLikeAliasTypeNode(member));
|
|
2917
|
+
}
|
|
2918
|
+
function isSemanticallyPlainObjectLikeType(type, checker) {
|
|
2919
|
+
if (isIntersectionType(type)) {
|
|
2920
|
+
return type.types.length > 0 && type.types.every((member) => isSemanticallyPlainObjectLikeType(member, checker));
|
|
2921
|
+
}
|
|
2922
|
+
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);
|
|
2923
|
+
}
|
|
2909
2924
|
function isTypeReference(type) {
|
|
2910
2925
|
return !!(type.flags & ts3.TypeFlags.Object) && !!(type.objectFlags & ts3.ObjectFlags.Reference);
|
|
2911
2926
|
}
|
|
@@ -3163,6 +3178,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
|
|
|
3163
3178
|
const kindDesc = ts3.SyntaxKind[typeAlias.type.kind] ?? "unknown";
|
|
3164
3179
|
return {
|
|
3165
3180
|
ok: false,
|
|
3181
|
+
kind: "not-object-like",
|
|
3166
3182
|
error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object-like type alias (found ${kindDesc})`
|
|
3167
3183
|
};
|
|
3168
3184
|
}
|
|
@@ -3177,6 +3193,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry,
|
|
|
3177
3193
|
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
3178
3194
|
return {
|
|
3179
3195
|
ok: false,
|
|
3196
|
+
kind: "duplicate-properties",
|
|
3180
3197
|
error: `Type alias "${name}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
|
|
3181
3198
|
};
|
|
3182
3199
|
}
|
|
@@ -3873,10 +3890,10 @@ function findDuplicateObjectLikeTypeAliasPropertyNames(members) {
|
|
|
3873
3890
|
return [...duplicates].sort();
|
|
3874
3891
|
}
|
|
3875
3892
|
function getAnalyzableObjectLikePropertyName(name) {
|
|
3876
|
-
if (
|
|
3877
|
-
return
|
|
3893
|
+
if (ts3.isIdentifier(name) || ts3.isStringLiteral(name) || ts3.isNumericLiteral(name)) {
|
|
3894
|
+
return name.text;
|
|
3878
3895
|
}
|
|
3879
|
-
return
|
|
3896
|
+
return null;
|
|
3880
3897
|
}
|
|
3881
3898
|
function applyEnumMemberDisplayNames(type, annotations) {
|
|
3882
3899
|
if (!annotations.some(
|
|
@@ -3967,7 +3984,7 @@ function resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, ch
|
|
|
3967
3984
|
};
|
|
3968
3985
|
}
|
|
3969
3986
|
if (ts3.isTypeReferenceNode(typeNode) && ts3.isIdentifier(typeNode.typeName)) {
|
|
3970
|
-
const aliasDecl =
|
|
3987
|
+
const aliasDecl = getTypeAliasDeclarationFromTypeReference(typeNode, checker);
|
|
3971
3988
|
if (aliasDecl !== void 0) {
|
|
3972
3989
|
return resolveRegisteredCustomTypeFromTypeNode(aliasDecl.type, extensionRegistry, checker);
|
|
3973
3990
|
}
|
|
@@ -4086,6 +4103,19 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
4086
4103
|
diagnostics
|
|
4087
4104
|
);
|
|
4088
4105
|
}
|
|
4106
|
+
if (resolvedSourceTypeNode !== void 0 && isResolvableObjectLikeAliasTypeNode(resolvedSourceTypeNode) && isSemanticallyPlainObjectLikeType(type, checker)) {
|
|
4107
|
+
return resolveObjectType(
|
|
4108
|
+
type,
|
|
4109
|
+
checker,
|
|
4110
|
+
file,
|
|
4111
|
+
typeRegistry,
|
|
4112
|
+
visiting,
|
|
4113
|
+
sourceNode,
|
|
4114
|
+
metadataPolicy,
|
|
4115
|
+
extensionRegistry,
|
|
4116
|
+
diagnostics
|
|
4117
|
+
);
|
|
4118
|
+
}
|
|
4089
4119
|
}
|
|
4090
4120
|
if (isObjectType(type)) {
|
|
4091
4121
|
return resolveObjectType(
|
|
@@ -4160,13 +4190,13 @@ function getReferencedTypeAliasDeclaration(sourceNode, checker) {
|
|
|
4160
4190
|
if (!typeNode || !ts3.isTypeReferenceNode(typeNode)) {
|
|
4161
4191
|
return void 0;
|
|
4162
4192
|
}
|
|
4163
|
-
return
|
|
4193
|
+
return getTypeAliasDeclarationFromTypeReference(typeNode, checker);
|
|
4164
4194
|
}
|
|
4165
4195
|
function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
|
|
4166
4196
|
if (!ts3.isTypeReferenceNode(typeNode)) {
|
|
4167
4197
|
return false;
|
|
4168
4198
|
}
|
|
4169
|
-
const aliasDecl =
|
|
4199
|
+
const aliasDecl = getTypeAliasDeclarationFromTypeReference(typeNode, checker);
|
|
4170
4200
|
if (!aliasDecl) {
|
|
4171
4201
|
return false;
|
|
4172
4202
|
}
|
|
@@ -4735,8 +4765,7 @@ function resolveAliasedTypeNode(typeNode, checker, visited = /* @__PURE__ */ new
|
|
|
4735
4765
|
if (!ts3.isTypeReferenceNode(typeNode) || !ts3.isIdentifier(typeNode.typeName)) {
|
|
4736
4766
|
return typeNode;
|
|
4737
4767
|
}
|
|
4738
|
-
const
|
|
4739
|
-
const aliasDecl = symbol?.declarations?.find(ts3.isTypeAliasDeclaration);
|
|
4768
|
+
const aliasDecl = getTypeAliasDeclarationFromTypeReference(typeNode, checker);
|
|
4740
4769
|
if (aliasDecl === void 0 || visited.has(aliasDecl)) {
|
|
4741
4770
|
return typeNode;
|
|
4742
4771
|
}
|
|
@@ -4786,8 +4815,7 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
|
|
|
4786
4815
|
);
|
|
4787
4816
|
}
|
|
4788
4817
|
const symbol = checker.getSymbolAtLocation(typeNode.typeName);
|
|
4789
|
-
|
|
4790
|
-
const aliasDecl = symbol.declarations.find(ts3.isTypeAliasDeclaration);
|
|
4818
|
+
const aliasDecl = getAliasedTypeAliasDeclaration(symbol, checker);
|
|
4791
4819
|
if (!aliasDecl) return [];
|
|
4792
4820
|
if (ts3.isTypeLiteralNode(aliasDecl.type)) return [];
|
|
4793
4821
|
const aliasFieldType = resolveTypeNode(
|
|
@@ -4810,6 +4838,18 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
|
|
|
4810
4838
|
);
|
|
4811
4839
|
return constraints;
|
|
4812
4840
|
}
|
|
4841
|
+
function getAliasedSymbol(symbol, checker) {
|
|
4842
|
+
if (symbol === void 0) {
|
|
4843
|
+
return void 0;
|
|
4844
|
+
}
|
|
4845
|
+
return symbol.flags & ts3.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
4846
|
+
}
|
|
4847
|
+
function getAliasedTypeAliasDeclaration(symbol, checker) {
|
|
4848
|
+
return getAliasedSymbol(symbol, checker)?.declarations?.find(ts3.isTypeAliasDeclaration);
|
|
4849
|
+
}
|
|
4850
|
+
function getTypeAliasDeclarationFromTypeReference(typeNode, checker) {
|
|
4851
|
+
return getAliasedTypeAliasDeclaration(checker.getSymbolAtLocation(typeNode.typeName), checker);
|
|
4852
|
+
}
|
|
4813
4853
|
function provenanceForNode(node, file) {
|
|
4814
4854
|
const sourceFile = node.getSourceFile();
|
|
4815
4855
|
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
@@ -4983,6 +5023,95 @@ function findInterfaceByName(sourceFile, interfaceName) {
|
|
|
4983
5023
|
function findTypeAliasByName(sourceFile, aliasName) {
|
|
4984
5024
|
return findNodeByName(sourceFile, aliasName, ts4.isTypeAliasDeclaration, (n) => n.name.text);
|
|
4985
5025
|
}
|
|
5026
|
+
function getResolvedObjectRootType(rootType, typeRegistry) {
|
|
5027
|
+
if (rootType.kind === "object") {
|
|
5028
|
+
return rootType;
|
|
5029
|
+
}
|
|
5030
|
+
if (rootType.kind !== "reference") {
|
|
5031
|
+
return null;
|
|
5032
|
+
}
|
|
5033
|
+
const definition = typeRegistry[rootType.name];
|
|
5034
|
+
return definition?.type.kind === "object" ? definition.type : null;
|
|
5035
|
+
}
|
|
5036
|
+
function createResolvedObjectAliasAnalysis(name, rootType, typeRegistry, rootInfo, diagnostics) {
|
|
5037
|
+
const resolvedRootType = getResolvedObjectRootType(rootType, typeRegistry);
|
|
5038
|
+
if (resolvedRootType === null) {
|
|
5039
|
+
return null;
|
|
5040
|
+
}
|
|
5041
|
+
const fields = resolvedRootType.properties.map((property) => ({
|
|
5042
|
+
kind: "field",
|
|
5043
|
+
name: property.name,
|
|
5044
|
+
...property.metadata !== void 0 && { metadata: property.metadata },
|
|
5045
|
+
type: property.type,
|
|
5046
|
+
required: !property.optional,
|
|
5047
|
+
constraints: property.constraints,
|
|
5048
|
+
annotations: property.annotations,
|
|
5049
|
+
provenance: property.provenance
|
|
5050
|
+
}));
|
|
5051
|
+
return {
|
|
5052
|
+
name,
|
|
5053
|
+
...rootInfo.metadata !== void 0 && { metadata: rootInfo.metadata },
|
|
5054
|
+
fields,
|
|
5055
|
+
fieldLayouts: fields.map(() => ({})),
|
|
5056
|
+
typeRegistry,
|
|
5057
|
+
...rootInfo.annotations.length > 0 && { annotations: [...rootInfo.annotations] },
|
|
5058
|
+
...diagnostics.length > 0 && { diagnostics: [...diagnostics] },
|
|
5059
|
+
instanceMethods: [],
|
|
5060
|
+
staticMethods: []
|
|
5061
|
+
};
|
|
5062
|
+
}
|
|
5063
|
+
function containsTypeReferenceInObjectLikeAlias(typeNode) {
|
|
5064
|
+
if (ts4.isParenthesizedTypeNode(typeNode)) {
|
|
5065
|
+
return containsTypeReferenceInObjectLikeAlias(typeNode.type);
|
|
5066
|
+
}
|
|
5067
|
+
if (ts4.isTypeReferenceNode(typeNode)) {
|
|
5068
|
+
return true;
|
|
5069
|
+
}
|
|
5070
|
+
return ts4.isIntersectionTypeNode(typeNode) && typeNode.types.some((member) => containsTypeReferenceInObjectLikeAlias(member));
|
|
5071
|
+
}
|
|
5072
|
+
function collectFallbackAliasMemberPropertyNames(typeNode, checker) {
|
|
5073
|
+
if (ts4.isParenthesizedTypeNode(typeNode)) {
|
|
5074
|
+
return collectFallbackAliasMemberPropertyNames(typeNode.type, checker);
|
|
5075
|
+
}
|
|
5076
|
+
if (ts4.isTypeLiteralNode(typeNode)) {
|
|
5077
|
+
const propertyNames = [];
|
|
5078
|
+
for (const member of typeNode.members) {
|
|
5079
|
+
if (!ts4.isPropertySignature(member)) {
|
|
5080
|
+
continue;
|
|
5081
|
+
}
|
|
5082
|
+
const propertyName = getAnalyzableObjectLikePropertyName(member.name);
|
|
5083
|
+
if (propertyName !== null) {
|
|
5084
|
+
propertyNames.push(propertyName);
|
|
5085
|
+
}
|
|
5086
|
+
}
|
|
5087
|
+
return propertyNames;
|
|
5088
|
+
}
|
|
5089
|
+
if (ts4.isTypeReferenceNode(typeNode)) {
|
|
5090
|
+
return checker.getTypeFromTypeNode(typeNode).getProperties().map((property) => property.getName());
|
|
5091
|
+
}
|
|
5092
|
+
return null;
|
|
5093
|
+
}
|
|
5094
|
+
function findFallbackAliasDuplicatePropertyNames(typeNode, checker) {
|
|
5095
|
+
if (!ts4.isIntersectionTypeNode(typeNode)) {
|
|
5096
|
+
return [];
|
|
5097
|
+
}
|
|
5098
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5099
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
5100
|
+
for (const member of typeNode.types) {
|
|
5101
|
+
const propertyNames = collectFallbackAliasMemberPropertyNames(member, checker);
|
|
5102
|
+
if (propertyNames === null) {
|
|
5103
|
+
continue;
|
|
5104
|
+
}
|
|
5105
|
+
for (const propertyName of propertyNames) {
|
|
5106
|
+
if (seen.has(propertyName)) {
|
|
5107
|
+
duplicates.add(propertyName);
|
|
5108
|
+
} else {
|
|
5109
|
+
seen.add(propertyName);
|
|
5110
|
+
}
|
|
5111
|
+
}
|
|
5112
|
+
}
|
|
5113
|
+
return [...duplicates].sort();
|
|
5114
|
+
}
|
|
4986
5115
|
function analyzeNamedTypeToIR(filePath, typeName, extensionRegistry, metadataPolicy, discriminatorOptions) {
|
|
4987
5116
|
const ctx = createProgramContext(filePath);
|
|
4988
5117
|
return analyzeNamedTypeToIRFromProgramContext(
|
|
@@ -5031,6 +5160,51 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
|
|
|
5031
5160
|
if (result.ok) {
|
|
5032
5161
|
return result.analysis;
|
|
5033
5162
|
}
|
|
5163
|
+
const fallbackEligible = result.kind === "not-object-like" && isResolvableObjectLikeAliasTypeNode(typeAlias.type) && containsTypeReferenceInObjectLikeAlias(typeAlias.type);
|
|
5164
|
+
if (!fallbackEligible) {
|
|
5165
|
+
throw new Error(result.error);
|
|
5166
|
+
}
|
|
5167
|
+
const duplicatePropertyNames = findFallbackAliasDuplicatePropertyNames(
|
|
5168
|
+
typeAlias.type,
|
|
5169
|
+
ctx.checker
|
|
5170
|
+
);
|
|
5171
|
+
if (duplicatePropertyNames.length > 0) {
|
|
5172
|
+
const sourceFile = typeAlias.getSourceFile();
|
|
5173
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
5174
|
+
throw new Error(
|
|
5175
|
+
`Type alias "${typeAlias.name.text}" at line ${String(line + 1)} contains duplicate property names across object-like members: ${duplicatePropertyNames.join(", ")}`
|
|
5176
|
+
);
|
|
5177
|
+
}
|
|
5178
|
+
const rootInfo = analyzeDeclarationRootInfo(
|
|
5179
|
+
typeAlias,
|
|
5180
|
+
ctx.checker,
|
|
5181
|
+
analysisFilePath,
|
|
5182
|
+
extensionRegistry,
|
|
5183
|
+
metadataPolicy
|
|
5184
|
+
);
|
|
5185
|
+
const diagnostics = [...rootInfo.diagnostics];
|
|
5186
|
+
const typeRegistry = {};
|
|
5187
|
+
const rootType = resolveTypeNode(
|
|
5188
|
+
ctx.checker.getTypeAtLocation(typeAlias),
|
|
5189
|
+
ctx.checker,
|
|
5190
|
+
analysisFilePath,
|
|
5191
|
+
typeRegistry,
|
|
5192
|
+
/* @__PURE__ */ new Set(),
|
|
5193
|
+
typeAlias,
|
|
5194
|
+
createAnalyzerMetadataPolicy(metadataPolicy, discriminatorOptions),
|
|
5195
|
+
extensionRegistry,
|
|
5196
|
+
diagnostics
|
|
5197
|
+
);
|
|
5198
|
+
const fallbackAnalysis = createResolvedObjectAliasAnalysis(
|
|
5199
|
+
typeAlias.name.text,
|
|
5200
|
+
rootType,
|
|
5201
|
+
typeRegistry,
|
|
5202
|
+
rootInfo,
|
|
5203
|
+
diagnostics
|
|
5204
|
+
);
|
|
5205
|
+
if (fallbackAnalysis !== null) {
|
|
5206
|
+
return fallbackAnalysis;
|
|
5207
|
+
}
|
|
5034
5208
|
throw new Error(result.error);
|
|
5035
5209
|
}
|
|
5036
5210
|
throw new Error(
|
|
@@ -5536,15 +5710,36 @@ function generateSchemasFromParameter(options) {
|
|
|
5536
5710
|
}
|
|
5537
5711
|
function generateSchemasFromReturnType(options) {
|
|
5538
5712
|
const signature = options.context.checker.getSignatureFromDeclaration(options.declaration);
|
|
5539
|
-
const
|
|
5713
|
+
const returnType = signature !== void 0 ? options.context.checker.getReturnTypeOfSignature(signature) : options.context.checker.getTypeAtLocation(options.declaration);
|
|
5714
|
+
const type = unwrapPromiseType(options.context.checker, returnType);
|
|
5715
|
+
const sourceNode = type !== returnType ? unwrapPromiseTypeNode(options.declaration.type) ?? options.declaration.type ?? options.declaration : options.declaration.type ?? options.declaration;
|
|
5540
5716
|
const fallbackName = options.declaration.name !== void 0 && ts7.isIdentifier(options.declaration.name) ? `${options.declaration.name.text}ReturnType` : "ReturnType";
|
|
5541
5717
|
return generateSchemasFromResolvedType({
|
|
5542
5718
|
...options,
|
|
5543
5719
|
type,
|
|
5544
|
-
sourceNode
|
|
5720
|
+
sourceNode,
|
|
5545
5721
|
name: fallbackName
|
|
5546
5722
|
});
|
|
5547
5723
|
}
|
|
5724
|
+
function unwrapPromiseType(checker, type) {
|
|
5725
|
+
if (!("getAwaitedType" in checker) || typeof checker.getAwaitedType !== "function") {
|
|
5726
|
+
return type;
|
|
5727
|
+
}
|
|
5728
|
+
return checker.getAwaitedType(type) ?? type;
|
|
5729
|
+
}
|
|
5730
|
+
function unwrapPromiseTypeNode(typeNode) {
|
|
5731
|
+
if (typeNode === void 0) {
|
|
5732
|
+
return void 0;
|
|
5733
|
+
}
|
|
5734
|
+
if (ts7.isParenthesizedTypeNode(typeNode)) {
|
|
5735
|
+
const unwrapped = unwrapPromiseTypeNode(typeNode.type);
|
|
5736
|
+
return unwrapped ?? typeNode;
|
|
5737
|
+
}
|
|
5738
|
+
return isPromiseTypeReferenceNode(typeNode) ? typeNode.typeArguments[0] : typeNode;
|
|
5739
|
+
}
|
|
5740
|
+
function isPromiseTypeReferenceNode(typeNode) {
|
|
5741
|
+
return ts7.isTypeReferenceNode(typeNode) && ts7.isIdentifier(typeNode.typeName) && typeNode.typeName.text === "Promise" && typeNode.typeArguments !== void 0 && typeNode.typeArguments.length > 0;
|
|
5742
|
+
}
|
|
5548
5743
|
|
|
5549
5744
|
// src/generators/mixed-authoring.ts
|
|
5550
5745
|
function buildMixedAuthoringSchemas(options) {
|