@openpkg-ts/sdk 0.54.9 → 0.54.10
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/dist/index.d.ts +37 -4
- package/dist/index.js +445 -315
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1202,6 +1202,12 @@ import { assertSpec, getAvailableVersions, getValidationErrors, LATEST_VERSION,
|
|
|
1202
1202
|
import { SpecType as SpecType4 } from "@openpkg-ts/spec";
|
|
1203
1203
|
import ts2 from "typescript";
|
|
1204
1204
|
import ts from "typescript";
|
|
1205
|
+
interface ExpansionBudget {
|
|
1206
|
+
/** Export name, or `type <id>` for a registered type. */
|
|
1207
|
+
owner: string;
|
|
1208
|
+
ops: number;
|
|
1209
|
+
exceeded: boolean;
|
|
1210
|
+
}
|
|
1205
1211
|
interface SerializerContext {
|
|
1206
1212
|
typeChecker: ts.TypeChecker;
|
|
1207
1213
|
program: ts.Program;
|
|
@@ -1214,6 +1220,8 @@ interface SerializerContext {
|
|
|
1214
1220
|
visitedTypes: Set<ts.Type>;
|
|
1215
1221
|
/** Permanent "already processed" set for registerReferencedTypes */
|
|
1216
1222
|
registeredTypes: Set<ts.Type>;
|
|
1223
|
+
/** Generic union/intersection alias being built at its own declaration: decomposed once, referenced everywhere else. */
|
|
1224
|
+
aliasBody?: ts.Type;
|
|
1217
1225
|
/** Flag to indicate we're processing tuple elements - skip Array prototype methods */
|
|
1218
1226
|
inTupleElement?: boolean;
|
|
1219
1227
|
/** Include private/protected class members (default: false) */
|
|
@@ -1242,12 +1250,22 @@ interface SerializerContext {
|
|
|
1242
1250
|
idOwner: Map<string, string>;
|
|
1243
1251
|
/** Workspace package name → dir, used to package-scope colliding type ids. */
|
|
1244
1252
|
workspacePackages: ReadonlyMap<string, string>;
|
|
1245
|
-
/**
|
|
1253
|
+
/**
|
|
1254
|
+
* Schema-build steps of the or registered type being built. Each gets
|
|
1255
|
+
* its own budget, so what one spends never changes what another emits: the
|
|
1256
|
+
* same comes out the same in a full run and under `only`.
|
|
1257
|
+
*/
|
|
1258
|
+
budget: ExpansionBudget;
|
|
1259
|
+
/** Cap on one budget's steps; past this, that owner's deep parts emit x-ts-type text. */
|
|
1260
|
+
maxBudgetOps: number;
|
|
1261
|
+
/** Structural schema-build steps taken this extract, all budgets together. */
|
|
1246
1262
|
schemaOps: number;
|
|
1247
|
-
/**
|
|
1263
|
+
/** Safety ceiling on schemaOps against runaway expansion; past this, everything emits text. */
|
|
1248
1264
|
maxSchemaOps: number;
|
|
1249
|
-
/** True once
|
|
1265
|
+
/** True once any schema degraded to text (a budget ran out, or a type defers expansion). */
|
|
1250
1266
|
budgetExceeded: boolean;
|
|
1267
|
+
/** Owners whose budget ran out, in the order they did. */
|
|
1268
|
+
exhaustedBudgets: string[];
|
|
1251
1269
|
}
|
|
1252
1270
|
declare class TypeRegistry {
|
|
1253
1271
|
private types;
|
|
@@ -1905,6 +1923,16 @@ declare function typeNodeOfSignature(sig: ts16.Signature): ts16.TypeNode | undef
|
|
|
1905
1923
|
*/
|
|
1906
1924
|
declare function buildSchemaFromTypeNode(node: ts16.TypeNode, checker: ts16.TypeChecker, ctx?: SerializerContext): SpecSchema5;
|
|
1907
1925
|
/**
|
|
1926
|
+
* Schema arms for the bases of a class or interface the checker cannot see
|
|
1927
|
+
* into (`any`: an unresolved import, an alias over a missing global). Such a
|
|
1928
|
+
* base contributes members nobody can list, so the own shape must not read as
|
|
1929
|
+
* closed: callers emit `allOf: [own shape, ...arms]`, the form an alias
|
|
1930
|
+
* intersection with the same arm (`{...} & Config`) already takes.
|
|
1931
|
+
*/
|
|
1932
|
+
declare function openHeritageArms(declarations: readonly ts16.Declaration[], checker: ts16.TypeChecker, ctx?: SerializerContext): SpecSchema5[];
|
|
1933
|
+
/** `allOf` of a shape and the open heritage arms; the shape alone when there are none. */
|
|
1934
|
+
declare function withOpenHeritage(schema: SpecSchema5, arms: readonly SpecSchema5[]): SpecSchema5;
|
|
1935
|
+
/**
|
|
1908
1936
|
* Strip `undefined` from a union type when optionality is already expressed
|
|
1909
1937
|
* elsewhere (`required: false`, `flags.optional`). Used for both schema shape
|
|
1910
1938
|
* and x-ts-type text so neither re-encodes optionality as `| undefined`.
|
|
@@ -1981,6 +2009,11 @@ declare function ensureNonEmptySchema(schema: SpecSchema5, type: ts16.Type, chec
|
|
|
1981
2009
|
*/
|
|
1982
2010
|
declare function buildSchema(type: ts16.Type, checker: ts16.TypeChecker, ctx?: SerializerContext, typeNode?: ts16.TypeNode): SpecSchema5;
|
|
1983
2011
|
/**
|
|
2012
|
+
* Schema of a named type at its own declaration. A generic union/intersection
|
|
2013
|
+
* alias is decomposed here and nowhere else; every use of it is a `$ref`.
|
|
2014
|
+
*/
|
|
2015
|
+
declare function buildAliasBodySchema(type: ts16.Type, checker: ts16.TypeChecker, ctx: SerializerContext): SpecSchema5;
|
|
2016
|
+
/**
|
|
1984
2017
|
* Build schema for function types
|
|
1985
2018
|
*/
|
|
1986
2019
|
declare function buildFunctionSchema(callSignatures: readonly ts16.Signature[], checker: ts16.TypeChecker, ctx: SerializerContext | undefined): SpecSchema5;
|
|
@@ -2024,4 +2057,4 @@ declare function findDiscriminatorProperty(unionTypes: ts16.Type[], checker: ts1
|
|
|
2024
2057
|
import ts17 from "typescript";
|
|
2025
2058
|
declare function isExported(node: ts17.Node): boolean;
|
|
2026
2059
|
declare function getNodeName(node: ts17.Node): string | undefined;
|
|
2027
|
-
export { zodAdapter, writtenTypeText, withDescription2 as withDescription, withDeprecated, validateSpec, valibotAdapter, typeboxAdapter, typeNodeOfSignature, typeNodeDefersExpansion, toToolSchema, toSearchIndexJSON, toSearchIndex2 as toSearchIndex, toPagefindRecords2 as toPagefindRecords, toNavigation2 as toNavigation, toMarkdown2 as toMarkdown, toJsonSchema, toJSONString, toJSON2 as toJSON, toHTML2 as toHTML, toFumadocsMetaJSON, toDocusaurusSidebarJS, toAlgoliaRecords2 as toAlgoliaRecords, stripUndefinedFromType, stripTsExtensions, sortByName, shouldEmitAliasTypeText, serializeVariable, serializeTypeAlias, serializeInterface, serializeFunctionExport, serializeEnum, serializeClass, scrubImportQualifiers, schemasAreEqual, schemaIsAny, resolveTypeRef, resolveTarget, resolveExportTarget, resolveCompiledPath, resolveAliasSymbol, renderTypeText, registerReferencedTypes, registerAdapter, recommendSemverBump, query, pickEntry, parseGithubRepo, normalizeType, normalizeSchema, normalizeMembers, normalizeExport, mergeConfig, loadSpec, loadConfig, listExports, isTypeReference, isTypeOnlyExport, isSymbolDeprecated, isStandardJSONSchema, isSchemaType, isRemoteInput, isReadonlyPropertySymbol, isPureRefSchema, isProperty, isPrimitiveName, isPathLikeInput, isMethod, isExported, isEntryFilePath, isDeferredMappedOrConditional, isBuiltinSymbol, isBuiltinGeneric, isAnonymous, groupByVisibility, getValidationErrors, getTypeOrigin, getSourceLocation, getProperties, getParamDescription, getNonNullableType, getNodeName, getMethods, getMemberBadges, getJSDocComment, getExportKind, getExport2 as getExport, getAvailableVersions, toMarkdown2 as generateDocs, formatTypeParameters, formatSchema, formatReturnType, formatParameters, formatMappedType, formatConditionalType, formatBadges, findWorkspaceRoot, findDiscriminatorProperty, findAdapter, filterSpec, extractTypeParameters, extractStandardSchemasFromTs, extractStandardSchemasFromProject, extractStandardSchemas, extractSpec, extractSchemaType, extractParameters, extract, exportToMarkdown, exportToJsonSchema, ensureNonEmptySchema, diffSpec2 as diffSpecs, diffSpec, detectTsRuntime, deduplicateSchemas, decoratePropertySchema, declaredTypeNode, createProgram, createDocs, cloneRemote, categorizeBreakingChanges, catalogPackages, calculateNextVersion, bundleRefs, buildSignatureString, buildSchemaFromTypeNode, buildSchema, buildObjectSchema, buildFunctionSchema, assertSpec, asStandardSchema, arktypeAdapter, TypeRegistry, TypeReference2 as TypeReference, TsRuntime, ToolSchemaResult, ToolSchemaProvider, ToToolSchemaOptions, ToJsonSchemaOptions, StandardSchemaExtractionResult, StandardSchemaExtractionOutput, StandardJSONSchemaV1, StandardJSONSchemaTarget, StandardJSONSchemaOptions, SpecMappedType, SpecError, SpecDiff, SpecConditionalType, SkippedExportDetail, SimplifiedSpec, SimplifiedSignature, SimplifiedReturn, SimplifiedParameter, SimplifiedMember, SimplifiedExport, SimplifiedExample, SerializerContext, SemverRecommendation, SemverBump, SearchRecord, SearchOptions, SearchIndex, SchemaVersion, SchemaExtractionResult, SchemaAdapter, STRING_PROTOTYPE_METHODS, ResolveTargetResult, ResolveTargetOptions, ResolveOk, ResolveNeedsBuild, ResolveExplicit, ResolveEmpty, ResolveAmbiguous, QueryBuilder, ProjectExtractionOutput, ProjectExtractionInfo, ProgramResult, ProgramOptions, PagefindRecord, PackageRecord, PRIMITIVES, OpenpkgConfig, NormalizeOptions, NavOptions, NavItem, NavGroup, NavFormat, NUMBER_PROTOTYPE_METHODS, MemberChangeInfo, MarkdownOptions, LoadOptions, ListExportsResult, ListExportsOptions, LATEST_VERSION, JsonSchemaDocument, JSONSchema, JSONOptions, HTMLOptions, GroupBy, GetExportResult, GetExportOptions, GenericNav, FumadocsMetaItem, FumadocsMeta, FormatSchemaOptions, ForgottenExport, FilterResult, FilterCriteria, ExtractionWarningCode, ExtractionWarning, ExtractStandardSchemasOptions, ExtractResult, ExtractOptions, ExtractFromProjectOptions, ExternalsConfig, ExportVerification, ExportTracker, ExportMarkdownOptions, ExportItem, DocusaurusSidebarItem, DocusaurusSidebar, DocsInstance, Diagnostic, CloneFn, CategorizedBreaking, CacheManagerOptions, CacheManager, CONFIG_FILENAME, BundleResult, BundleOptions, BuiltinSchema, BreakingSeverity, BUILTIN_TYPE_SCHEMAS, AsStandardSchemaOptions, AlgoliaRecord, ARRAY_PROTOTYPE_METHODS };
|
|
2060
|
+
export { zodAdapter, writtenTypeText, withOpenHeritage, withDescription2 as withDescription, withDeprecated, validateSpec, valibotAdapter, typeboxAdapter, typeNodeOfSignature, typeNodeDefersExpansion, toToolSchema, toSearchIndexJSON, toSearchIndex2 as toSearchIndex, toPagefindRecords2 as toPagefindRecords, toNavigation2 as toNavigation, toMarkdown2 as toMarkdown, toJsonSchema, toJSONString, toJSON2 as toJSON, toHTML2 as toHTML, toFumadocsMetaJSON, toDocusaurusSidebarJS, toAlgoliaRecords2 as toAlgoliaRecords, stripUndefinedFromType, stripTsExtensions, sortByName, shouldEmitAliasTypeText, serializeVariable, serializeTypeAlias, serializeInterface, serializeFunctionExport, serializeEnum, serializeClass, scrubImportQualifiers, schemasAreEqual, schemaIsAny, resolveTypeRef, resolveTarget, resolveExportTarget, resolveCompiledPath, resolveAliasSymbol, renderTypeText, registerReferencedTypes, registerAdapter, recommendSemverBump, query, pickEntry, parseGithubRepo, openHeritageArms, normalizeType, normalizeSchema, normalizeMembers, normalizeExport, mergeConfig, loadSpec, loadConfig, listExports, isTypeReference, isTypeOnlyExport, isSymbolDeprecated, isStandardJSONSchema, isSchemaType, isRemoteInput, isReadonlyPropertySymbol, isPureRefSchema, isProperty, isPrimitiveName, isPathLikeInput, isMethod, isExported, isEntryFilePath, isDeferredMappedOrConditional, isBuiltinSymbol, isBuiltinGeneric, isAnonymous, groupByVisibility, getValidationErrors, getTypeOrigin, getSourceLocation, getProperties, getParamDescription, getNonNullableType, getNodeName, getMethods, getMemberBadges, getJSDocComment, getExportKind, getExport2 as getExport, getAvailableVersions, toMarkdown2 as generateDocs, formatTypeParameters, formatSchema, formatReturnType, formatParameters, formatMappedType, formatConditionalType, formatBadges, findWorkspaceRoot, findDiscriminatorProperty, findAdapter, filterSpec, extractTypeParameters, extractStandardSchemasFromTs, extractStandardSchemasFromProject, extractStandardSchemas, extractSpec, extractSchemaType, extractParameters, extract, exportToMarkdown, exportToJsonSchema, ensureNonEmptySchema, diffSpec2 as diffSpecs, diffSpec, detectTsRuntime, deduplicateSchemas, decoratePropertySchema, declaredTypeNode, createProgram, createDocs, cloneRemote, categorizeBreakingChanges, catalogPackages, calculateNextVersion, bundleRefs, buildSignatureString, buildSchemaFromTypeNode, buildSchema, buildObjectSchema, buildFunctionSchema, buildAliasBodySchema, assertSpec, asStandardSchema, arktypeAdapter, TypeRegistry, TypeReference2 as TypeReference, TsRuntime, ToolSchemaResult, ToolSchemaProvider, ToToolSchemaOptions, ToJsonSchemaOptions, StandardSchemaExtractionResult, StandardSchemaExtractionOutput, StandardJSONSchemaV1, StandardJSONSchemaTarget, StandardJSONSchemaOptions, SpecMappedType, SpecError, SpecDiff, SpecConditionalType, SkippedExportDetail, SimplifiedSpec, SimplifiedSignature, SimplifiedReturn, SimplifiedParameter, SimplifiedMember, SimplifiedExport, SimplifiedExample, SerializerContext, SemverRecommendation, SemverBump, SearchRecord, SearchOptions, SearchIndex, SchemaVersion, SchemaExtractionResult, SchemaAdapter, STRING_PROTOTYPE_METHODS, ResolveTargetResult, ResolveTargetOptions, ResolveOk, ResolveNeedsBuild, ResolveExplicit, ResolveEmpty, ResolveAmbiguous, QueryBuilder, ProjectExtractionOutput, ProjectExtractionInfo, ProgramResult, ProgramOptions, PagefindRecord, PackageRecord, PRIMITIVES, OpenpkgConfig, NormalizeOptions, NavOptions, NavItem, NavGroup, NavFormat, NUMBER_PROTOTYPE_METHODS, MemberChangeInfo, MarkdownOptions, LoadOptions, ListExportsResult, ListExportsOptions, LATEST_VERSION, JsonSchemaDocument, JSONSchema, JSONOptions, HTMLOptions, GroupBy, GetExportResult, GetExportOptions, GenericNav, FumadocsMetaItem, FumadocsMeta, FormatSchemaOptions, ForgottenExport, FilterResult, FilterCriteria, ExtractionWarningCode, ExtractionWarning, ExtractStandardSchemasOptions, ExtractResult, ExtractOptions, ExtractFromProjectOptions, ExternalsConfig, ExportVerification, ExportTracker, ExportMarkdownOptions, ExportItem, DocusaurusSidebarItem, DocusaurusSidebar, DocsInstance, Diagnostic, CloneFn, CategorizedBreaking, CacheManagerOptions, CacheManager, CONFIG_FILENAME, BundleResult, BundleOptions, BuiltinSchema, BreakingSeverity, BUILTIN_TYPE_SCHEMAS, AsStandardSchemaOptions, AlgoliaRecord, ARRAY_PROTOTYPE_METHODS };
|
package/dist/index.js
CHANGED
|
@@ -2263,6 +2263,21 @@ function getExportKind(declaration, type) {
|
|
|
2263
2263
|
return "function";
|
|
2264
2264
|
return "variable";
|
|
2265
2265
|
}
|
|
2266
|
+
function getExtendsExpressions(node) {
|
|
2267
|
+
return node.heritageClauses?.find((clause) => clause.token === ts2.SyntaxKind.ExtendsKeyword)?.types ?? [];
|
|
2268
|
+
}
|
|
2269
|
+
function getExtendsText(node, checker) {
|
|
2270
|
+
const names = getExtendsExpressions(node).map((expr) => {
|
|
2271
|
+
const name = checker.getTypeAtLocation(expr).getSymbol()?.getName();
|
|
2272
|
+
return name && !name.startsWith("__") ? name : expr.expression.getText();
|
|
2273
|
+
});
|
|
2274
|
+
return names.length > 0 ? names.join(" & ") : undefined;
|
|
2275
|
+
}
|
|
2276
|
+
function propertyNameText(name) {
|
|
2277
|
+
if (ts2.isComputedPropertyName(name))
|
|
2278
|
+
return name.getText();
|
|
2279
|
+
return name.text;
|
|
2280
|
+
}
|
|
2266
2281
|
|
|
2267
2282
|
// src/compiler/program.ts
|
|
2268
2283
|
import * as fs4 from "node:fs";
|
|
@@ -2603,8 +2618,39 @@ function createProgram(options) {
|
|
|
2603
2618
|
import ts10 from "typescript";
|
|
2604
2619
|
|
|
2605
2620
|
// src/types/parameters.ts
|
|
2621
|
+
import ts7 from "typescript";
|
|
2622
|
+
|
|
2623
|
+
// src/ast/registry.ts
|
|
2606
2624
|
import ts6 from "typescript";
|
|
2607
2625
|
|
|
2626
|
+
// src/serializers/expansion-budget.ts
|
|
2627
|
+
var MAX_BUDGET_OPS = 1e4;
|
|
2628
|
+
var MAX_SCHEMA_OPS = 200000;
|
|
2629
|
+
function withExpansionBudget(ctx, owner, fn) {
|
|
2630
|
+
const outer = {
|
|
2631
|
+
budget: ctx.budget,
|
|
2632
|
+
currentDepth: ctx.currentDepth,
|
|
2633
|
+
visitedTypes: ctx.visitedTypes,
|
|
2634
|
+
inTupleElement: ctx.inTupleElement,
|
|
2635
|
+
aliasBody: ctx.aliasBody
|
|
2636
|
+
};
|
|
2637
|
+
const budget = { owner, ops: 0, exceeded: false };
|
|
2638
|
+
Object.assign(ctx, {
|
|
2639
|
+
budget,
|
|
2640
|
+
currentDepth: 0,
|
|
2641
|
+
visitedTypes: new Set,
|
|
2642
|
+
inTupleElement: undefined,
|
|
2643
|
+
aliasBody: undefined
|
|
2644
|
+
});
|
|
2645
|
+
try {
|
|
2646
|
+
return fn();
|
|
2647
|
+
} finally {
|
|
2648
|
+
if (budget.exceeded)
|
|
2649
|
+
ctx.exhaustedBudgets.push(owner);
|
|
2650
|
+
Object.assign(ctx, outer);
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
|
|
2608
2654
|
// src/types/schema-builder.ts
|
|
2609
2655
|
import ts5 from "typescript";
|
|
2610
2656
|
|
|
@@ -2662,6 +2708,10 @@ function resolveFromModuleSpecifier(decl, symbol, checker, program) {
|
|
|
2662
2708
|
if (ts4.isExportSpecifier(decl)) {
|
|
2663
2709
|
const exportDecl = decl.parent?.parent;
|
|
2664
2710
|
if (exportDecl && ts4.isExportDeclaration(exportDecl)) {
|
|
2711
|
+
if (!exportDecl.moduleSpecifier) {
|
|
2712
|
+
const local = checker.getExportSpecifierLocalTargetSymbol(decl);
|
|
2713
|
+
return local && local !== symbol ? local : undefined;
|
|
2714
|
+
}
|
|
2665
2715
|
moduleSpecifier = exportDecl.moduleSpecifier;
|
|
2666
2716
|
importedName = (decl.propertyName ?? decl.name).text;
|
|
2667
2717
|
}
|
|
@@ -2834,7 +2884,8 @@ function resolvedSymbol(symbol, checker) {
|
|
|
2834
2884
|
return;
|
|
2835
2885
|
if (symbol.flags & ts5.SymbolFlags.Alias) {
|
|
2836
2886
|
try {
|
|
2837
|
-
|
|
2887
|
+
const target = checker.getAliasedSymbol(symbol);
|
|
2888
|
+
return checker.isUnknownSymbol(target) ? symbol : target;
|
|
2838
2889
|
} catch {
|
|
2839
2890
|
return symbol;
|
|
2840
2891
|
}
|
|
@@ -2869,10 +2920,11 @@ function buildSchemaFromTypeNode(node, checker, ctx) {
|
|
|
2869
2920
|
if (node.kind === ts5.SyntaxKind.UnknownKeyword) {
|
|
2870
2921
|
return { type: "unknown" };
|
|
2871
2922
|
}
|
|
2872
|
-
|
|
2873
|
-
|
|
2923
|
+
const nameNode = ts5.isTypeReferenceNode(node) ? node.typeName : ts5.isExpressionWithTypeArguments(node) && (ts5.isIdentifier(node.expression) || ts5.isPropertyAccessExpression(node.expression)) ? node.expression : undefined;
|
|
2924
|
+
if (nameNode) {
|
|
2925
|
+
const raw = checker.getSymbolAtLocation(ts5.isQualifiedName(nameNode) ? nameNode.right : ts5.isPropertyAccessExpression(nameNode) ? nameNode.name : nameNode);
|
|
2874
2926
|
const symbol = resolvedSymbol(raw, checker);
|
|
2875
|
-
const name = symbol?.getName() ??
|
|
2927
|
+
const name = symbol?.getName() ?? nameNode.getText();
|
|
2876
2928
|
const args = node.typeArguments?.map((arg) => {
|
|
2877
2929
|
if (typeNodeDefersExpansion(arg, checker, ctx?.program)) {
|
|
2878
2930
|
return buildSchemaFromTypeNode(arg, checker, ctx);
|
|
@@ -2888,6 +2940,9 @@ function buildSchemaFromTypeNode(node, checker, ctx) {
|
|
|
2888
2940
|
}
|
|
2889
2941
|
return { ...schema, typeArguments: args };
|
|
2890
2942
|
};
|
|
2943
|
+
if (symbol && symbol.flags & ts5.SymbolFlags.TypeParameter) {
|
|
2944
|
+
return { "x-ts-type": name };
|
|
2945
|
+
}
|
|
2891
2946
|
if (name && isBuiltinGeneric(name) && (!symbol || isBuiltinSymbol(symbol))) {
|
|
2892
2947
|
return withArgs({ ...builtinSchema(name) });
|
|
2893
2948
|
}
|
|
@@ -2900,6 +2955,9 @@ function buildSchemaFromTypeNode(node, checker, ctx) {
|
|
|
2900
2955
|
refId = name;
|
|
2901
2956
|
}
|
|
2902
2957
|
}
|
|
2958
|
+
if (ctx && symbol && symbol.flags & ts5.SymbolFlags.Alias && !ctx.typeRegistry.has(refId)) {
|
|
2959
|
+
ctx.typeRegistry.add({ id: refId, name, kind: "type", schema: { "x-ts-type": name } });
|
|
2960
|
+
}
|
|
2903
2961
|
return withArgs({ $ref: `#/types/${refId}` });
|
|
2904
2962
|
}
|
|
2905
2963
|
return {
|
|
@@ -2912,6 +2970,23 @@ function buildSchemaFromTypeNode(node, checker, ctx) {
|
|
|
2912
2970
|
}
|
|
2913
2971
|
return { "x-ts-type": scrubImportQualifiers(node.getText().replace(/\s+/g, " ")) };
|
|
2914
2972
|
}
|
|
2973
|
+
function openHeritageArms(declarations, checker, ctx) {
|
|
2974
|
+
return declarations.filter((decl) => ts5.isClassLike(decl) || ts5.isInterfaceDeclaration(decl)).flatMap((decl) => [...getExtendsExpressions(decl)]).flatMap((expr) => {
|
|
2975
|
+
const base = checker.getTypeAtLocation(expr);
|
|
2976
|
+
if (!(base.flags & ts5.TypeFlags.Any))
|
|
2977
|
+
return [];
|
|
2978
|
+
const registered = ctx?.typeRegistry.registerType(base, ctx);
|
|
2979
|
+
const written = checker.getSymbolAtLocation(expr.expression);
|
|
2980
|
+
const unresolvedImport = !!written && !!(written.flags & ts5.SymbolFlags.Alias) && resolvedSymbol(written, checker) === written;
|
|
2981
|
+
if (!registered && unresolvedImport) {
|
|
2982
|
+
return [{ "x-ts-type": scrubImportQualifiers(expr.getText()) }];
|
|
2983
|
+
}
|
|
2984
|
+
return [buildSchemaFromTypeNode(expr, checker, ctx)];
|
|
2985
|
+
});
|
|
2986
|
+
}
|
|
2987
|
+
function withOpenHeritage(schema, arms) {
|
|
2988
|
+
return arms.length > 0 ? { allOf: [schema, ...arms] } : schema;
|
|
2989
|
+
}
|
|
2915
2990
|
function stripUndefinedFromType(type, checker) {
|
|
2916
2991
|
if (!type.isUnion())
|
|
2917
2992
|
return type;
|
|
@@ -3318,7 +3393,12 @@ function isUtilityOverTypeParameter(type) {
|
|
|
3318
3393
|
const args = type.aliasTypeArguments;
|
|
3319
3394
|
if (!args || args.length === 0)
|
|
3320
3395
|
return false;
|
|
3321
|
-
|
|
3396
|
+
if (!args.some((t) => containsUnresolvedTypeParameter(t)))
|
|
3397
|
+
return false;
|
|
3398
|
+
if (args[0].flags & ts5.TypeFlags.TypeParameter || !(type.flags & ts5.TypeFlags.Object)) {
|
|
3399
|
+
return true;
|
|
3400
|
+
}
|
|
3401
|
+
return type.getProperties().length === 0;
|
|
3322
3402
|
}
|
|
3323
3403
|
function writtenUtilityText(type, checker, typeNode) {
|
|
3324
3404
|
let node = typeNode;
|
|
@@ -3398,6 +3478,14 @@ function buildSchema(type, checker, ctx, typeNode) {
|
|
|
3398
3478
|
const schema = buildSchemaInternal(type, checker, ctx, typeNode);
|
|
3399
3479
|
return ensureNonEmptySchema(schema, type, checker);
|
|
3400
3480
|
}
|
|
3481
|
+
function buildAliasBodySchema(type, checker, ctx) {
|
|
3482
|
+
ctx.aliasBody = type;
|
|
3483
|
+
try {
|
|
3484
|
+
return buildSchema(type, checker, ctx);
|
|
3485
|
+
} finally {
|
|
3486
|
+
ctx.aliasBody = undefined;
|
|
3487
|
+
}
|
|
3488
|
+
}
|
|
3401
3489
|
function buildMaxDepthSchema(type, checker, typeNode, ctx) {
|
|
3402
3490
|
if (type.flags & ts5.TypeFlags.Any) {
|
|
3403
3491
|
if (typeNode)
|
|
@@ -3446,13 +3534,44 @@ function buildMaxDepthSchema(type, checker, typeNode, ctx) {
|
|
|
3446
3534
|
}
|
|
3447
3535
|
return { type: checker.typeToString(type) };
|
|
3448
3536
|
}
|
|
3537
|
+
function writtenTypeArguments(typeNode, symbol, checker) {
|
|
3538
|
+
if (!typeNode || !symbol || !ts5.isTypeReferenceNode(typeNode) || !typeNode.typeArguments) {
|
|
3539
|
+
return;
|
|
3540
|
+
}
|
|
3541
|
+
const name = ts5.isQualifiedName(typeNode.typeName) ? typeNode.typeName.right : typeNode.typeName;
|
|
3542
|
+
const written = resolvedSymbol(checker.getSymbolAtLocation(name), checker);
|
|
3543
|
+
return written === symbol ? typeNode.typeArguments : undefined;
|
|
3544
|
+
}
|
|
3545
|
+
function genericAliasRef(type, checker, ctx, typeNode) {
|
|
3546
|
+
const aliasTypeArgs = type.aliasTypeArguments;
|
|
3547
|
+
const name = type.aliasSymbol?.getName();
|
|
3548
|
+
if (!name || !aliasTypeArgs?.length)
|
|
3549
|
+
return;
|
|
3550
|
+
if (name.startsWith("__") || BUILTIN_TYPES.has(name) || isBuiltinGeneric(name))
|
|
3551
|
+
return;
|
|
3552
|
+
const argNodes = writtenTypeArguments(typeNode, type.aliasSymbol, checker);
|
|
3553
|
+
const build = () => {
|
|
3554
|
+
const schema = {
|
|
3555
|
+
$ref: `#/types/${namedRefId(type, name, ctx)}`,
|
|
3556
|
+
typeArguments: aliasTypeArgs.map((t, i) => buildSchema(t, checker, ctx, argNodes?.[i]))
|
|
3557
|
+
};
|
|
3558
|
+
const packageOrigin = getTypeOrigin(type, checker);
|
|
3559
|
+
if (packageOrigin) {
|
|
3560
|
+
setSchemaExtension(schema, "x-ts-package", packageOrigin);
|
|
3561
|
+
}
|
|
3562
|
+
return schema;
|
|
3563
|
+
};
|
|
3564
|
+
return ctx ? withDepth(ctx, build) : build();
|
|
3565
|
+
}
|
|
3449
3566
|
function buildSchemaInternal(type, checker, ctx, typeNode) {
|
|
3450
3567
|
if (isAtMaxDepth(ctx)) {
|
|
3451
3568
|
return buildMaxDepthSchema(type, checker, typeNode, ctx);
|
|
3452
3569
|
}
|
|
3453
3570
|
if (ctx) {
|
|
3454
3571
|
ctx.schemaOps += 1;
|
|
3455
|
-
|
|
3572
|
+
ctx.budget.ops += 1;
|
|
3573
|
+
if (ctx.budget.ops > ctx.maxBudgetOps || ctx.schemaOps > ctx.maxSchemaOps) {
|
|
3574
|
+
ctx.budget.exceeded = true;
|
|
3456
3575
|
ctx.budgetExceeded = true;
|
|
3457
3576
|
return { "x-ts-type": cheapTypeText(type, checker, typeNode) };
|
|
3458
3577
|
}
|
|
@@ -3546,6 +3665,14 @@ function buildSchemaInternal(type, checker, ctx, typeNode) {
|
|
|
3546
3665
|
return schema;
|
|
3547
3666
|
}
|
|
3548
3667
|
}
|
|
3668
|
+
if (type.isUnion() || type.isIntersection()) {
|
|
3669
|
+
const ownBody = ctx?.aliasBody === type;
|
|
3670
|
+
if (ownBody && ctx)
|
|
3671
|
+
ctx.aliasBody = undefined;
|
|
3672
|
+
const aliasRef = ownBody ? undefined : genericAliasRef(type, checker, ctx, typeNode);
|
|
3673
|
+
if (aliasRef)
|
|
3674
|
+
return aliasRef;
|
|
3675
|
+
}
|
|
3549
3676
|
if (type.flags & ts5.TypeFlags.TemplateLiteral) {
|
|
3550
3677
|
return {
|
|
3551
3678
|
type: "string",
|
|
@@ -3670,11 +3797,12 @@ function buildSchemaInternal(type, checker, ctx, typeNode) {
|
|
|
3670
3797
|
}
|
|
3671
3798
|
if (name && !isAnonymous(typeRef.target)) {
|
|
3672
3799
|
const packageOrigin = getTypeOrigin(typeRef.target, checker);
|
|
3800
|
+
const argNodes = writtenTypeArguments(typeNode, symbol2, checker);
|
|
3673
3801
|
if (ctx) {
|
|
3674
3802
|
return withDepth(ctx, () => {
|
|
3675
3803
|
const schema2 = {
|
|
3676
3804
|
$ref: `#/types/${namedRefId(typeRef.target, name, ctx)}`,
|
|
3677
|
-
typeArguments: typeArgs.map((t) => buildSchema(t, checker, ctx))
|
|
3805
|
+
typeArguments: typeArgs.map((t, i) => buildSchema(t, checker, ctx, argNodes?.[i]))
|
|
3678
3806
|
};
|
|
3679
3807
|
if (packageOrigin) {
|
|
3680
3808
|
setSchemaExtension(schema2, "x-ts-package", packageOrigin);
|
|
@@ -3713,29 +3841,9 @@ function buildSchemaInternal(type, checker, ctx, typeNode) {
|
|
|
3713
3841
|
});
|
|
3714
3842
|
return ctx ? withDepth(ctx, build) : build();
|
|
3715
3843
|
}
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
return withDepth(ctx, () => {
|
|
3720
|
-
const schema2 = {
|
|
3721
|
-
$ref: `#/types/${namedRefId(type, name, ctx)}`,
|
|
3722
|
-
typeArguments: aliasTypeArgs.map((t) => buildSchema(t, checker, ctx))
|
|
3723
|
-
};
|
|
3724
|
-
if (packageOrigin) {
|
|
3725
|
-
setSchemaExtension(schema2, "x-ts-package", packageOrigin);
|
|
3726
|
-
}
|
|
3727
|
-
return schema2;
|
|
3728
|
-
});
|
|
3729
|
-
}
|
|
3730
|
-
const schema = {
|
|
3731
|
-
$ref: `#/types/${name}`,
|
|
3732
|
-
typeArguments: aliasTypeArgs.map((t) => buildSchema(t, checker, ctx))
|
|
3733
|
-
};
|
|
3734
|
-
if (packageOrigin) {
|
|
3735
|
-
setSchemaExtension(schema, "x-ts-package", packageOrigin);
|
|
3736
|
-
}
|
|
3737
|
-
return schema;
|
|
3738
|
-
}
|
|
3844
|
+
const aliasRef = genericAliasRef(type, checker, ctx, typeNode);
|
|
3845
|
+
if (aliasRef)
|
|
3846
|
+
return aliasRef;
|
|
3739
3847
|
}
|
|
3740
3848
|
if (type.flags & ts5.TypeFlags.Object) {
|
|
3741
3849
|
const callSignatures = type.getCallSignatures();
|
|
@@ -4000,219 +4108,7 @@ function findDiscriminatorProperty(unionTypes, checker) {
|
|
|
4000
4108
|
return;
|
|
4001
4109
|
}
|
|
4002
4110
|
|
|
4003
|
-
// src/types/parameters.ts
|
|
4004
|
-
function extractParameters(signature, ctx) {
|
|
4005
|
-
const { typeChecker: checker } = ctx;
|
|
4006
|
-
const result = [];
|
|
4007
|
-
const signatureDecl = signature.getDeclaration();
|
|
4008
|
-
const jsdocTags = signatureDecl ? ts6.getJSDocTags(signatureDecl) : [];
|
|
4009
|
-
for (const param of signature.getParameters()) {
|
|
4010
|
-
const decl = param.valueDeclaration;
|
|
4011
|
-
if (!decl)
|
|
4012
|
-
continue;
|
|
4013
|
-
const defer = typeNodeDefersExpansion(decl.type, checker, ctx.program);
|
|
4014
|
-
const type = defer ? undefined : checker.getTypeOfSymbolAtLocation(param, decl);
|
|
4015
|
-
if (decl && ts6.isObjectBindingPattern(decl.name)) {
|
|
4016
|
-
const expandedParams = expandBindingPattern(decl, type ?? checker.getTypeOfSymbolAtLocation(param, decl), jsdocTags, ctx);
|
|
4017
|
-
result.push(...expandedParams);
|
|
4018
|
-
} else {
|
|
4019
|
-
const isOptional = !!decl?.questionToken || !!decl?.initializer;
|
|
4020
|
-
const isRest = !!decl.dotDotDotToken;
|
|
4021
|
-
const paramName = param.getName();
|
|
4022
|
-
const description = getParamDescription(paramName, jsdocTags);
|
|
4023
|
-
const schema = defer ? buildSchemaFromTypeNode(decl.type, checker, ctx) : buildSchema(isOptional ? stripUndefinedFromType(type, checker) : type, checker, ctx, decl.type);
|
|
4024
|
-
if (!defer && type) {
|
|
4025
|
-
registerReferencedTypes(isOptional ? stripUndefinedFromType(type, checker) : type, ctx);
|
|
4026
|
-
}
|
|
4027
|
-
const paramResult = {
|
|
4028
|
-
name: paramName,
|
|
4029
|
-
schema,
|
|
4030
|
-
required: !isOptional && !isRest,
|
|
4031
|
-
...isRest ? { rest: true } : {}
|
|
4032
|
-
};
|
|
4033
|
-
if (description) {
|
|
4034
|
-
paramResult.description = description;
|
|
4035
|
-
const inlineTags = parseInlineTags(description);
|
|
4036
|
-
if (inlineTags)
|
|
4037
|
-
paramResult.inlineTags = inlineTags;
|
|
4038
|
-
}
|
|
4039
|
-
if (decl.initializer) {
|
|
4040
|
-
applyDefault(paramResult, decl.initializer);
|
|
4041
|
-
}
|
|
4042
|
-
result.push(paramResult);
|
|
4043
|
-
}
|
|
4044
|
-
}
|
|
4045
|
-
return result;
|
|
4046
|
-
}
|
|
4047
|
-
function expandBindingPattern(paramDecl, paramType, jsdocTags, ctx) {
|
|
4048
|
-
const { typeChecker: checker } = ctx;
|
|
4049
|
-
const result = [];
|
|
4050
|
-
const bindingPattern = paramDecl.name;
|
|
4051
|
-
const allProperties = getEffectiveProperties(paramType, checker);
|
|
4052
|
-
const inferredAlias = inferParamAlias(jsdocTags);
|
|
4053
|
-
for (const element of bindingPattern.elements) {
|
|
4054
|
-
if (!ts6.isBindingElement(element))
|
|
4055
|
-
continue;
|
|
4056
|
-
const propertyName = element.propertyName ? ts6.isIdentifier(element.propertyName) ? element.propertyName.text : element.propertyName.getText() : ts6.isIdentifier(element.name) ? element.name.text : element.name.getText();
|
|
4057
|
-
const propSymbol = allProperties.get(propertyName);
|
|
4058
|
-
if (!propSymbol)
|
|
4059
|
-
continue;
|
|
4060
|
-
const isOptional = !!(propSymbol.flags & ts6.SymbolFlags.Optional) || element.initializer !== undefined;
|
|
4061
|
-
const propType = checker.getTypeOfSymbol(propSymbol);
|
|
4062
|
-
const effectiveType = isOptional ? stripUndefinedFromType(propType, checker) : propType;
|
|
4063
|
-
registerReferencedTypes(effectiveType, ctx);
|
|
4064
|
-
const description = getParamDescription(propertyName, jsdocTags, inferredAlias);
|
|
4065
|
-
const param = {
|
|
4066
|
-
name: propertyName,
|
|
4067
|
-
schema: buildSchema(effectiveType, checker, ctx, declaredTypeNode(propSymbol.valueDeclaration)),
|
|
4068
|
-
required: !isOptional
|
|
4069
|
-
};
|
|
4070
|
-
if (description) {
|
|
4071
|
-
param.description = description;
|
|
4072
|
-
const inlineTags = parseInlineTags(description);
|
|
4073
|
-
if (inlineTags)
|
|
4074
|
-
param.inlineTags = inlineTags;
|
|
4075
|
-
}
|
|
4076
|
-
if (element.initializer) {
|
|
4077
|
-
applyDefault(param, element.initializer);
|
|
4078
|
-
}
|
|
4079
|
-
result.push(param);
|
|
4080
|
-
}
|
|
4081
|
-
return result;
|
|
4082
|
-
}
|
|
4083
|
-
function getEffectiveProperties(type, _checker) {
|
|
4084
|
-
const properties = new Map;
|
|
4085
|
-
if (type.isIntersection()) {
|
|
4086
|
-
for (const subType of type.types) {
|
|
4087
|
-
for (const prop of subType.getProperties()) {
|
|
4088
|
-
properties.set(prop.getName(), prop);
|
|
4089
|
-
}
|
|
4090
|
-
}
|
|
4091
|
-
} else {
|
|
4092
|
-
for (const prop of type.getProperties()) {
|
|
4093
|
-
properties.set(prop.getName(), prop);
|
|
4094
|
-
}
|
|
4095
|
-
}
|
|
4096
|
-
return properties;
|
|
4097
|
-
}
|
|
4098
|
-
function inferParamAlias(jsdocTags) {
|
|
4099
|
-
const prefixes = [];
|
|
4100
|
-
for (const tag of jsdocTags) {
|
|
4101
|
-
if (tag.tagName.text !== "param")
|
|
4102
|
-
continue;
|
|
4103
|
-
const tagText = typeof tag.comment === "string" ? tag.comment : ts6.getTextOfJSDocComment(tag.comment) ?? "";
|
|
4104
|
-
const paramTag = tag;
|
|
4105
|
-
const paramName = paramTag.name?.getText() ?? "";
|
|
4106
|
-
if (paramName.includes(".")) {
|
|
4107
|
-
const prefix = paramName.split(".")[0];
|
|
4108
|
-
if (prefix && !prefix.startsWith("__")) {
|
|
4109
|
-
prefixes.push(prefix);
|
|
4110
|
-
}
|
|
4111
|
-
} else if (tagText.includes(".")) {
|
|
4112
|
-
const match = tagText.match(/^(\w+)\./);
|
|
4113
|
-
if (match && !match[1].startsWith("__")) {
|
|
4114
|
-
prefixes.push(match[1]);
|
|
4115
|
-
}
|
|
4116
|
-
}
|
|
4117
|
-
}
|
|
4118
|
-
if (prefixes.length === 0)
|
|
4119
|
-
return;
|
|
4120
|
-
const counts = new Map;
|
|
4121
|
-
for (const p of prefixes)
|
|
4122
|
-
counts.set(p, (counts.get(p) ?? 0) + 1);
|
|
4123
|
-
return Array.from(counts.entries()).sort((a, b) => b[1] - a[1])[0]?.[0];
|
|
4124
|
-
}
|
|
4125
|
-
function extractLiteralDefault(initializer) {
|
|
4126
|
-
if (ts6.isStringLiteral(initializer)) {
|
|
4127
|
-
return { literal: true, value: initializer.text };
|
|
4128
|
-
}
|
|
4129
|
-
if (ts6.isNumericLiteral(initializer)) {
|
|
4130
|
-
return { literal: true, value: Number(initializer.text) };
|
|
4131
|
-
}
|
|
4132
|
-
if (ts6.isPrefixUnaryExpression(initializer) && initializer.operator === ts6.SyntaxKind.MinusToken && ts6.isNumericLiteral(initializer.operand)) {
|
|
4133
|
-
return { literal: true, value: -Number(initializer.operand.text) };
|
|
4134
|
-
}
|
|
4135
|
-
if (initializer.kind === ts6.SyntaxKind.TrueKeyword) {
|
|
4136
|
-
return { literal: true, value: true };
|
|
4137
|
-
}
|
|
4138
|
-
if (initializer.kind === ts6.SyntaxKind.FalseKeyword) {
|
|
4139
|
-
return { literal: true, value: false };
|
|
4140
|
-
}
|
|
4141
|
-
if (initializer.kind === ts6.SyntaxKind.NullKeyword) {
|
|
4142
|
-
return { literal: true, value: null };
|
|
4143
|
-
}
|
|
4144
|
-
return { literal: false, text: initializer.getText() };
|
|
4145
|
-
}
|
|
4146
|
-
function applyDefault(param, initializer) {
|
|
4147
|
-
const extracted = extractLiteralDefault(initializer);
|
|
4148
|
-
if (extracted.literal) {
|
|
4149
|
-
param.default = extracted.value;
|
|
4150
|
-
if (param.schema && typeof param.schema === "object" && !Array.isArray(param.schema)) {
|
|
4151
|
-
param.schema.default = extracted.value;
|
|
4152
|
-
}
|
|
4153
|
-
} else {
|
|
4154
|
-
param.default = extracted.text;
|
|
4155
|
-
if (param.schema && typeof param.schema === "object" && !Array.isArray(param.schema)) {
|
|
4156
|
-
param.schema["x-ts-default"] = extracted.text;
|
|
4157
|
-
}
|
|
4158
|
-
}
|
|
4159
|
-
}
|
|
4160
|
-
function registerReferencedTypes(type, ctx, depth = 0) {
|
|
4161
|
-
if (depth > ctx.maxTypeDepth)
|
|
4162
|
-
return;
|
|
4163
|
-
if (ctx.registeredTypes.has(type))
|
|
4164
|
-
return;
|
|
4165
|
-
const isPrimitive = type.flags & (ts6.TypeFlags.String | ts6.TypeFlags.Number | ts6.TypeFlags.Boolean | ts6.TypeFlags.Void | ts6.TypeFlags.Undefined | ts6.TypeFlags.Null | ts6.TypeFlags.Any | ts6.TypeFlags.Unknown | ts6.TypeFlags.Never | ts6.TypeFlags.StringLiteral | ts6.TypeFlags.NumberLiteral | ts6.TypeFlags.BooleanLiteral);
|
|
4166
|
-
if (!isPrimitive) {
|
|
4167
|
-
ctx.registeredTypes.add(type);
|
|
4168
|
-
}
|
|
4169
|
-
const { typeChecker: checker, typeRegistry } = ctx;
|
|
4170
|
-
typeRegistry.registerType(type, ctx);
|
|
4171
|
-
const typeArgs = type.typeArguments;
|
|
4172
|
-
if (typeArgs) {
|
|
4173
|
-
for (const arg of typeArgs) {
|
|
4174
|
-
registerReferencedTypes(arg, ctx, depth + 1);
|
|
4175
|
-
}
|
|
4176
|
-
}
|
|
4177
|
-
if (type.isUnion()) {
|
|
4178
|
-
for (const t of type.types) {
|
|
4179
|
-
registerReferencedTypes(t, ctx, depth + 1);
|
|
4180
|
-
}
|
|
4181
|
-
}
|
|
4182
|
-
if (type.isIntersection()) {
|
|
4183
|
-
for (const t of type.types) {
|
|
4184
|
-
registerReferencedTypes(t, ctx, depth + 1);
|
|
4185
|
-
}
|
|
4186
|
-
}
|
|
4187
|
-
const typeSymbol = type.aliasSymbol ?? type.getSymbol();
|
|
4188
|
-
if (typeSymbol && ctx.shouldExpandExternal && !typeSymbol.getName().startsWith("__") && !ctx.shouldExpandExternal(typeSymbol)) {
|
|
4189
|
-
return;
|
|
4190
|
-
}
|
|
4191
|
-
if (isForeignPackage(typeSymbol, ctx.workspacePackages)) {
|
|
4192
|
-
return;
|
|
4193
|
-
}
|
|
4194
|
-
if (isDeferredMappedOrConditional(type)) {
|
|
4195
|
-
return;
|
|
4196
|
-
}
|
|
4197
|
-
if (type.flags & ts6.TypeFlags.Object) {
|
|
4198
|
-
const props = type.getProperties();
|
|
4199
|
-
const limit = ctx.maxProperties;
|
|
4200
|
-
if (props.length > limit && ctx.onTruncation) {
|
|
4201
|
-
const typeName = type.getSymbol()?.getName() ?? "anonymous";
|
|
4202
|
-
ctx.onTruncation(typeName, props.length, limit);
|
|
4203
|
-
}
|
|
4204
|
-
for (const prop of props.slice(0, limit)) {
|
|
4205
|
-
const propType = checker.getTypeOfSymbol(prop);
|
|
4206
|
-
registerReferencedTypes(propType, ctx, depth + 1);
|
|
4207
|
-
}
|
|
4208
|
-
}
|
|
4209
|
-
}
|
|
4210
|
-
|
|
4211
|
-
// src/serializers/context.ts
|
|
4212
|
-
import ts8 from "typescript";
|
|
4213
|
-
|
|
4214
4111
|
// src/ast/registry.ts
|
|
4215
|
-
import ts7 from "typescript";
|
|
4216
4112
|
var BUILTINS = new Set([
|
|
4217
4113
|
"Array",
|
|
4218
4114
|
"ArrayBuffer",
|
|
@@ -4289,6 +4185,26 @@ function isExternalType(decl) {
|
|
|
4289
4185
|
return false;
|
|
4290
4186
|
return sourceFile.fileName.includes("node_modules");
|
|
4291
4187
|
}
|
|
4188
|
+
function declaredForm(type, checker, symbol = type.aliasSymbol ?? type.getSymbol()) {
|
|
4189
|
+
if (!symbol)
|
|
4190
|
+
return type;
|
|
4191
|
+
const generic = ts6.SymbolFlags.TypeAlias | ts6.SymbolFlags.Interface | ts6.SymbolFlags.Class;
|
|
4192
|
+
if (!(symbol.flags & generic))
|
|
4193
|
+
return type;
|
|
4194
|
+
const target = type.target;
|
|
4195
|
+
const instantiated = type.aliasTypeArguments?.length || target && target !== type;
|
|
4196
|
+
return instantiated ? declaredTypeOf(symbol, type, checker) : type;
|
|
4197
|
+
}
|
|
4198
|
+
function declaredTypeOf(symbol, fallback, checker) {
|
|
4199
|
+
const declared = checker.getDeclaredTypeOfSymbol(symbol);
|
|
4200
|
+
return declared.flags & ts6.TypeFlags.Any ? fallback : declared;
|
|
4201
|
+
}
|
|
4202
|
+
function registeredForm(type, symbol, checker) {
|
|
4203
|
+
const constructorSide = symbol.flags & ts6.SymbolFlags.Class && type.objectFlags & ts6.ObjectFlags.Anonymous;
|
|
4204
|
+
if (constructorSide)
|
|
4205
|
+
return declaredTypeOf(symbol, type, checker);
|
|
4206
|
+
return declaredForm(type, checker, symbol);
|
|
4207
|
+
}
|
|
4292
4208
|
|
|
4293
4209
|
class TypeRegistry {
|
|
4294
4210
|
types = new Map;
|
|
@@ -4322,13 +4238,13 @@ class TypeRegistry {
|
|
|
4322
4238
|
return;
|
|
4323
4239
|
if (name.startsWith('"'))
|
|
4324
4240
|
return;
|
|
4325
|
-
if (symbol.flags &
|
|
4241
|
+
if (symbol.flags & ts6.SymbolFlags.EnumMember)
|
|
4326
4242
|
return;
|
|
4327
|
-
if (symbol.flags &
|
|
4243
|
+
if (symbol.flags & ts6.SymbolFlags.TypeParameter)
|
|
4328
4244
|
return;
|
|
4329
|
-
if (symbol.flags &
|
|
4245
|
+
if (symbol.flags & ts6.SymbolFlags.Method)
|
|
4330
4246
|
return;
|
|
4331
|
-
if (symbol.flags &
|
|
4247
|
+
if (symbol.flags & ts6.SymbolFlags.Function)
|
|
4332
4248
|
return;
|
|
4333
4249
|
if (isGenericTypeParameter(name))
|
|
4334
4250
|
return;
|
|
@@ -4361,7 +4277,7 @@ class TypeRegistry {
|
|
|
4361
4277
|
return id;
|
|
4362
4278
|
this.processing.add(id);
|
|
4363
4279
|
try {
|
|
4364
|
-
const specType = this.buildSpecType(type, symbol, id, ctx);
|
|
4280
|
+
const specType = withExpansionBudget(ctx, `type ${id}`, () => this.buildSpecType(registeredForm(type, symbol, ctx.typeChecker), symbol, id, ctx));
|
|
4365
4281
|
if (specType) {
|
|
4366
4282
|
this.add(specType);
|
|
4367
4283
|
return specType.id;
|
|
@@ -4378,17 +4294,17 @@ class TypeRegistry {
|
|
|
4378
4294
|
let kind = "type";
|
|
4379
4295
|
const external = decl ? isExternalType(decl) : false;
|
|
4380
4296
|
if (decl) {
|
|
4381
|
-
if (
|
|
4297
|
+
if (ts6.isClassDeclaration(decl))
|
|
4382
4298
|
kind = "class";
|
|
4383
|
-
else if (
|
|
4299
|
+
else if (ts6.isInterfaceDeclaration(decl))
|
|
4384
4300
|
kind = "interface";
|
|
4385
|
-
else if (
|
|
4301
|
+
else if (ts6.isEnumDeclaration(decl))
|
|
4386
4302
|
kind = "enum";
|
|
4387
4303
|
}
|
|
4388
4304
|
if (external) {
|
|
4389
4305
|
kind = "external";
|
|
4390
4306
|
}
|
|
4391
|
-
let schema =
|
|
4307
|
+
let schema = buildAliasBodySchema(type, checker, ctx);
|
|
4392
4308
|
if (this.isSelfRef(schema, id)) {
|
|
4393
4309
|
schema = this.resolveSelRefSchema(type, checker, ctx);
|
|
4394
4310
|
}
|
|
@@ -4398,8 +4314,8 @@ class TypeRegistry {
|
|
|
4398
4314
|
schema = enumSchema;
|
|
4399
4315
|
}
|
|
4400
4316
|
}
|
|
4401
|
-
if (kind === "type" && decl &&
|
|
4402
|
-
const text = renderTypeText(type, checker, decl,
|
|
4317
|
+
if (kind === "type" && decl && ts6.isTypeAliasDeclaration(decl) && shouldEmitAliasTypeText(decl.type) && typeof schema === "object" && schema !== null && !("x-ts-type" in schema)) {
|
|
4318
|
+
const text = renderTypeText(type, checker, decl, ts6.TypeFormatFlags.InTypeAlias);
|
|
4403
4319
|
if (!PRIMITIVES.has(text) && text !== name) {
|
|
4404
4320
|
schema["x-ts-type"] = text;
|
|
4405
4321
|
const declared = writtenTypeText(declaredTypeNode(decl));
|
|
@@ -4408,8 +4324,11 @@ class TypeRegistry {
|
|
|
4408
4324
|
}
|
|
4409
4325
|
}
|
|
4410
4326
|
}
|
|
4327
|
+
const heritage = (symbol.declarations ?? []).filter((d) => ts6.isClassDeclaration(d) || ts6.isInterfaceDeclaration(d));
|
|
4328
|
+
const extendsText = heritage.map((d) => getExtendsText(d, checker)).find(Boolean);
|
|
4329
|
+
schema = withOpenHeritage(schema, openHeritageArms(heritage, checker, ctx));
|
|
4411
4330
|
let typeParameters;
|
|
4412
|
-
if (decl && (
|
|
4331
|
+
if (decl && (ts6.isTypeAliasDeclaration(decl) || ts6.isInterfaceDeclaration(decl) || ts6.isClassDeclaration(decl))) {
|
|
4413
4332
|
typeParameters = extractTypeParameters(decl, checker);
|
|
4414
4333
|
}
|
|
4415
4334
|
return {
|
|
@@ -4418,6 +4337,7 @@ class TypeRegistry {
|
|
|
4418
4337
|
kind,
|
|
4419
4338
|
...typeParameters && typeParameters.length > 0 ? { typeParameters } : {},
|
|
4420
4339
|
schema,
|
|
4340
|
+
...extendsText ? { extends: extendsText } : {},
|
|
4421
4341
|
...external ? { external: true } : {}
|
|
4422
4342
|
};
|
|
4423
4343
|
}
|
|
@@ -4430,14 +4350,14 @@ class TypeRegistry {
|
|
|
4430
4350
|
resolveSelRefSchema(type, checker, ctx) {
|
|
4431
4351
|
if (type.isUnion()) {
|
|
4432
4352
|
const types = type.types;
|
|
4433
|
-
const allStringLiterals = types.every((t) => t.flags &
|
|
4353
|
+
const allStringLiterals = types.every((t) => t.flags & ts6.TypeFlags.StringLiteral);
|
|
4434
4354
|
if (allStringLiterals) {
|
|
4435
4355
|
return {
|
|
4436
4356
|
type: "string",
|
|
4437
4357
|
enum: types.map((t) => t.value)
|
|
4438
4358
|
};
|
|
4439
4359
|
}
|
|
4440
|
-
const allNumberLiterals = types.every((t) => t.flags &
|
|
4360
|
+
const allNumberLiterals = types.every((t) => t.flags & ts6.TypeFlags.NumberLiteral);
|
|
4441
4361
|
if (allNumberLiterals) {
|
|
4442
4362
|
return {
|
|
4443
4363
|
type: "number",
|
|
@@ -4472,18 +4392,18 @@ class TypeRegistry {
|
|
|
4472
4392
|
const elementType = checker.getTypeArguments(type)?.[0];
|
|
4473
4393
|
return elementType ? { type: "array", items: buildSchema(elementType, checker, ctx) } : { type: "array" };
|
|
4474
4394
|
}
|
|
4475
|
-
if (type.flags &
|
|
4395
|
+
if (type.flags & ts6.TypeFlags.Conditional) {
|
|
4476
4396
|
return { "x-ts-type": renderTypeText(type, checker) };
|
|
4477
4397
|
}
|
|
4478
4398
|
const constraint = checker.getBaseConstraintOfType(type);
|
|
4479
|
-
const primitive = constraint && constraint.flags &
|
|
4399
|
+
const primitive = constraint && constraint.flags & ts6.TypeFlags.StringLike ? "string" : constraint && constraint.flags & ts6.TypeFlags.NumberLike ? "number" : constraint && constraint.flags & ts6.TypeFlags.BooleanLike ? "boolean" : undefined;
|
|
4480
4400
|
if (primitive) {
|
|
4481
4401
|
return { type: primitive, "x-ts-type": renderTypeText(type, checker) };
|
|
4482
4402
|
}
|
|
4483
4403
|
return this.buildObjectSchemaFromProperties(type, checker, ctx);
|
|
4484
4404
|
}
|
|
4485
4405
|
buildEnumSchema(symbol, checker) {
|
|
4486
|
-
const decl = symbol.declarations?.find(
|
|
4406
|
+
const decl = symbol.declarations?.find(ts6.isEnumDeclaration);
|
|
4487
4407
|
if (!decl)
|
|
4488
4408
|
return;
|
|
4489
4409
|
const members = [];
|
|
@@ -4510,8 +4430,8 @@ class TypeRegistry {
|
|
|
4510
4430
|
buildObjectSchemaFromProperties(type, checker, ctx) {
|
|
4511
4431
|
const properties = type.getProperties();
|
|
4512
4432
|
const indexInfos = checker.getIndexInfosOfType(type);
|
|
4513
|
-
const stringIndex = indexInfos.find((i) => i.keyType.flags &
|
|
4514
|
-
const numberIndex = indexInfos.find((i) => i.keyType.flags &
|
|
4433
|
+
const stringIndex = indexInfos.find((i) => i.keyType.flags & ts6.TypeFlags.String);
|
|
4434
|
+
const numberIndex = indexInfos.find((i) => i.keyType.flags & ts6.TypeFlags.Number);
|
|
4515
4435
|
if (properties.length === 0 && !stringIndex && !numberIndex) {
|
|
4516
4436
|
return { type: checker.typeToString(type) };
|
|
4517
4437
|
}
|
|
@@ -4519,8 +4439,8 @@ class TypeRegistry {
|
|
|
4519
4439
|
const required = [];
|
|
4520
4440
|
const limit = ctx.maxProperties;
|
|
4521
4441
|
const isArrayLike = checker.isArrayType(type) || checker.isTupleType(type) || type.symbol?.getName() === "Array" && isLibFile(type.symbol?.getDeclarations()?.[0]?.getSourceFile()?.fileName ?? "");
|
|
4522
|
-
const isStringLike = type.flags &
|
|
4523
|
-
const isNumberLike = type.flags &
|
|
4442
|
+
const isStringLike = type.flags & ts6.TypeFlags.StringLike;
|
|
4443
|
+
const isNumberLike = type.flags & ts6.TypeFlags.NumberLike;
|
|
4524
4444
|
const included = properties.filter((prop) => {
|
|
4525
4445
|
const propName = prop.getName();
|
|
4526
4446
|
if (propName.startsWith("__@"))
|
|
@@ -4540,7 +4460,7 @@ class TypeRegistry {
|
|
|
4540
4460
|
for (const prop of included.slice(0, limit)) {
|
|
4541
4461
|
const propName = prop.getName();
|
|
4542
4462
|
const rawPropType = checker.getTypeOfSymbol(prop);
|
|
4543
|
-
const propType = prop.flags &
|
|
4463
|
+
const propType = prop.flags & ts6.SymbolFlags.Optional ? stripUndefinedFromType(rawPropType, checker) : rawPropType;
|
|
4544
4464
|
this.registerType(propType, ctx);
|
|
4545
4465
|
let propSchema = buildSchema(propType, checker, ctx, declaredTypeNode(prop.valueDeclaration ?? prop.getDeclarations()?.[0]));
|
|
4546
4466
|
const docComment = prop.getDocumentationComment(checker);
|
|
@@ -4557,7 +4477,7 @@ class TypeRegistry {
|
|
|
4557
4477
|
}
|
|
4558
4478
|
propSchema = decoratePropertySchema(propSchema, prop, propType, checker);
|
|
4559
4479
|
props[propName] = propSchema;
|
|
4560
|
-
if (!(prop.flags &
|
|
4480
|
+
if (!(prop.flags & ts6.SymbolFlags.Optional)) {
|
|
4561
4481
|
required.push(propName);
|
|
4562
4482
|
}
|
|
4563
4483
|
}
|
|
@@ -4574,7 +4494,224 @@ class TypeRegistry {
|
|
|
4574
4494
|
}
|
|
4575
4495
|
}
|
|
4576
4496
|
|
|
4497
|
+
// src/types/parameters.ts
|
|
4498
|
+
function extractParameters(signature, ctx) {
|
|
4499
|
+
const { typeChecker: checker } = ctx;
|
|
4500
|
+
const result = [];
|
|
4501
|
+
const signatureDecl = signature.getDeclaration();
|
|
4502
|
+
const jsdocTags = signatureDecl ? ts7.getJSDocTags(signatureDecl) : [];
|
|
4503
|
+
for (const param of signature.getParameters()) {
|
|
4504
|
+
const decl = param.valueDeclaration;
|
|
4505
|
+
if (!decl)
|
|
4506
|
+
continue;
|
|
4507
|
+
const defer = typeNodeDefersExpansion(decl.type, checker, ctx.program);
|
|
4508
|
+
const type = defer ? undefined : checker.getTypeOfSymbolAtLocation(param, decl);
|
|
4509
|
+
if (decl && ts7.isObjectBindingPattern(decl.name)) {
|
|
4510
|
+
const expandedParams = expandBindingPattern(decl, type ?? checker.getTypeOfSymbolAtLocation(param, decl), jsdocTags, ctx);
|
|
4511
|
+
result.push(...expandedParams);
|
|
4512
|
+
} else {
|
|
4513
|
+
const isOptional = !!decl?.questionToken || !!decl?.initializer;
|
|
4514
|
+
const isRest = !!decl.dotDotDotToken;
|
|
4515
|
+
const paramName = param.getName();
|
|
4516
|
+
const description = getParamDescription(paramName, jsdocTags);
|
|
4517
|
+
const schema = defer ? buildSchemaFromTypeNode(decl.type, checker, ctx) : buildSchema(isOptional ? stripUndefinedFromType(type, checker) : type, checker, ctx, decl.type);
|
|
4518
|
+
if (!defer && type) {
|
|
4519
|
+
registerReferencedTypes(isOptional ? stripUndefinedFromType(type, checker) : type, ctx);
|
|
4520
|
+
}
|
|
4521
|
+
const paramResult = {
|
|
4522
|
+
name: paramName,
|
|
4523
|
+
schema,
|
|
4524
|
+
required: !isOptional && !isRest,
|
|
4525
|
+
...isRest ? { rest: true } : {}
|
|
4526
|
+
};
|
|
4527
|
+
if (description) {
|
|
4528
|
+
paramResult.description = description;
|
|
4529
|
+
const inlineTags = parseInlineTags(description);
|
|
4530
|
+
if (inlineTags)
|
|
4531
|
+
paramResult.inlineTags = inlineTags;
|
|
4532
|
+
}
|
|
4533
|
+
if (decl.initializer) {
|
|
4534
|
+
applyDefault(paramResult, decl.initializer);
|
|
4535
|
+
}
|
|
4536
|
+
result.push(paramResult);
|
|
4537
|
+
}
|
|
4538
|
+
}
|
|
4539
|
+
return result;
|
|
4540
|
+
}
|
|
4541
|
+
function expandBindingPattern(paramDecl, paramType, jsdocTags, ctx) {
|
|
4542
|
+
const { typeChecker: checker } = ctx;
|
|
4543
|
+
const result = [];
|
|
4544
|
+
const bindingPattern = paramDecl.name;
|
|
4545
|
+
const allProperties = getEffectiveProperties(paramType, checker);
|
|
4546
|
+
const inferredAlias = inferParamAlias(jsdocTags);
|
|
4547
|
+
for (const element of bindingPattern.elements) {
|
|
4548
|
+
if (!ts7.isBindingElement(element))
|
|
4549
|
+
continue;
|
|
4550
|
+
const propertyName = element.propertyName ? ts7.isIdentifier(element.propertyName) ? element.propertyName.text : element.propertyName.getText() : ts7.isIdentifier(element.name) ? element.name.text : element.name.getText();
|
|
4551
|
+
const propSymbol = allProperties.get(propertyName);
|
|
4552
|
+
if (!propSymbol)
|
|
4553
|
+
continue;
|
|
4554
|
+
const isOptional = !!(propSymbol.flags & ts7.SymbolFlags.Optional) || element.initializer !== undefined;
|
|
4555
|
+
const propType = checker.getTypeOfSymbol(propSymbol);
|
|
4556
|
+
const effectiveType = isOptional ? stripUndefinedFromType(propType, checker) : propType;
|
|
4557
|
+
registerReferencedTypes(effectiveType, ctx);
|
|
4558
|
+
const description = getParamDescription(propertyName, jsdocTags, inferredAlias);
|
|
4559
|
+
const param = {
|
|
4560
|
+
name: propertyName,
|
|
4561
|
+
schema: buildSchema(effectiveType, checker, ctx, declaredTypeNode(propSymbol.valueDeclaration)),
|
|
4562
|
+
required: !isOptional
|
|
4563
|
+
};
|
|
4564
|
+
if (description) {
|
|
4565
|
+
param.description = description;
|
|
4566
|
+
const inlineTags = parseInlineTags(description);
|
|
4567
|
+
if (inlineTags)
|
|
4568
|
+
param.inlineTags = inlineTags;
|
|
4569
|
+
}
|
|
4570
|
+
if (element.initializer) {
|
|
4571
|
+
applyDefault(param, element.initializer);
|
|
4572
|
+
}
|
|
4573
|
+
result.push(param);
|
|
4574
|
+
}
|
|
4575
|
+
return result;
|
|
4576
|
+
}
|
|
4577
|
+
function getEffectiveProperties(type, _checker) {
|
|
4578
|
+
const properties = new Map;
|
|
4579
|
+
if (type.isIntersection()) {
|
|
4580
|
+
for (const subType of type.types) {
|
|
4581
|
+
for (const prop of subType.getProperties()) {
|
|
4582
|
+
properties.set(prop.getName(), prop);
|
|
4583
|
+
}
|
|
4584
|
+
}
|
|
4585
|
+
} else {
|
|
4586
|
+
for (const prop of type.getProperties()) {
|
|
4587
|
+
properties.set(prop.getName(), prop);
|
|
4588
|
+
}
|
|
4589
|
+
}
|
|
4590
|
+
return properties;
|
|
4591
|
+
}
|
|
4592
|
+
function inferParamAlias(jsdocTags) {
|
|
4593
|
+
const prefixes = [];
|
|
4594
|
+
for (const tag of jsdocTags) {
|
|
4595
|
+
if (tag.tagName.text !== "param")
|
|
4596
|
+
continue;
|
|
4597
|
+
const tagText = typeof tag.comment === "string" ? tag.comment : ts7.getTextOfJSDocComment(tag.comment) ?? "";
|
|
4598
|
+
const paramTag = tag;
|
|
4599
|
+
const paramName = paramTag.name?.getText() ?? "";
|
|
4600
|
+
if (paramName.includes(".")) {
|
|
4601
|
+
const prefix = paramName.split(".")[0];
|
|
4602
|
+
if (prefix && !prefix.startsWith("__")) {
|
|
4603
|
+
prefixes.push(prefix);
|
|
4604
|
+
}
|
|
4605
|
+
} else if (tagText.includes(".")) {
|
|
4606
|
+
const match = tagText.match(/^(\w+)\./);
|
|
4607
|
+
if (match && !match[1].startsWith("__")) {
|
|
4608
|
+
prefixes.push(match[1]);
|
|
4609
|
+
}
|
|
4610
|
+
}
|
|
4611
|
+
}
|
|
4612
|
+
if (prefixes.length === 0)
|
|
4613
|
+
return;
|
|
4614
|
+
const counts = new Map;
|
|
4615
|
+
for (const p of prefixes)
|
|
4616
|
+
counts.set(p, (counts.get(p) ?? 0) + 1);
|
|
4617
|
+
return Array.from(counts.entries()).sort((a, b) => b[1] - a[1])[0]?.[0];
|
|
4618
|
+
}
|
|
4619
|
+
function extractLiteralDefault(initializer) {
|
|
4620
|
+
if (ts7.isStringLiteral(initializer)) {
|
|
4621
|
+
return { literal: true, value: initializer.text };
|
|
4622
|
+
}
|
|
4623
|
+
if (ts7.isNumericLiteral(initializer)) {
|
|
4624
|
+
return { literal: true, value: Number(initializer.text) };
|
|
4625
|
+
}
|
|
4626
|
+
if (ts7.isPrefixUnaryExpression(initializer) && initializer.operator === ts7.SyntaxKind.MinusToken && ts7.isNumericLiteral(initializer.operand)) {
|
|
4627
|
+
return { literal: true, value: -Number(initializer.operand.text) };
|
|
4628
|
+
}
|
|
4629
|
+
if (initializer.kind === ts7.SyntaxKind.TrueKeyword) {
|
|
4630
|
+
return { literal: true, value: true };
|
|
4631
|
+
}
|
|
4632
|
+
if (initializer.kind === ts7.SyntaxKind.FalseKeyword) {
|
|
4633
|
+
return { literal: true, value: false };
|
|
4634
|
+
}
|
|
4635
|
+
if (initializer.kind === ts7.SyntaxKind.NullKeyword) {
|
|
4636
|
+
return { literal: true, value: null };
|
|
4637
|
+
}
|
|
4638
|
+
return { literal: false, text: initializer.getText() };
|
|
4639
|
+
}
|
|
4640
|
+
function applyDefault(param, initializer) {
|
|
4641
|
+
const extracted = extractLiteralDefault(initializer);
|
|
4642
|
+
if (extracted.literal) {
|
|
4643
|
+
param.default = extracted.value;
|
|
4644
|
+
if (param.schema && typeof param.schema === "object" && !Array.isArray(param.schema)) {
|
|
4645
|
+
param.schema.default = extracted.value;
|
|
4646
|
+
}
|
|
4647
|
+
} else {
|
|
4648
|
+
param.default = extracted.text;
|
|
4649
|
+
if (param.schema && typeof param.schema === "object" && !Array.isArray(param.schema)) {
|
|
4650
|
+
param.schema["x-ts-default"] = extracted.text;
|
|
4651
|
+
}
|
|
4652
|
+
}
|
|
4653
|
+
}
|
|
4654
|
+
function registerReferencedTypes(type, ctx, depth = 0) {
|
|
4655
|
+
if (depth > ctx.maxTypeDepth)
|
|
4656
|
+
return;
|
|
4657
|
+
if (ctx.registeredTypes.has(type))
|
|
4658
|
+
return;
|
|
4659
|
+
const isPrimitive = type.flags & (ts7.TypeFlags.String | ts7.TypeFlags.Number | ts7.TypeFlags.Boolean | ts7.TypeFlags.Void | ts7.TypeFlags.Undefined | ts7.TypeFlags.Null | ts7.TypeFlags.Any | ts7.TypeFlags.Unknown | ts7.TypeFlags.Never | ts7.TypeFlags.StringLiteral | ts7.TypeFlags.NumberLiteral | ts7.TypeFlags.BooleanLiteral);
|
|
4660
|
+
if (!isPrimitive) {
|
|
4661
|
+
ctx.registeredTypes.add(type);
|
|
4662
|
+
}
|
|
4663
|
+
const { typeChecker: checker, typeRegistry } = ctx;
|
|
4664
|
+
typeRegistry.registerType(type, ctx);
|
|
4665
|
+
const typeArgs = type.typeArguments;
|
|
4666
|
+
if (typeArgs) {
|
|
4667
|
+
for (const arg of typeArgs) {
|
|
4668
|
+
registerReferencedTypes(arg, ctx, depth + 1);
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4671
|
+
for (const arg of type.aliasTypeArguments ?? []) {
|
|
4672
|
+
registerReferencedTypes(arg, ctx, depth + 1);
|
|
4673
|
+
}
|
|
4674
|
+
const declared = declaredForm(type, checker);
|
|
4675
|
+
if (declared !== type) {
|
|
4676
|
+
registerReferencedTypes(declared, ctx, depth);
|
|
4677
|
+
return;
|
|
4678
|
+
}
|
|
4679
|
+
if (type.isUnion()) {
|
|
4680
|
+
for (const t of type.types) {
|
|
4681
|
+
registerReferencedTypes(t, ctx, depth + 1);
|
|
4682
|
+
}
|
|
4683
|
+
}
|
|
4684
|
+
if (type.isIntersection()) {
|
|
4685
|
+
for (const t of type.types) {
|
|
4686
|
+
registerReferencedTypes(t, ctx, depth + 1);
|
|
4687
|
+
}
|
|
4688
|
+
}
|
|
4689
|
+
const typeSymbol = type.aliasSymbol ?? type.getSymbol();
|
|
4690
|
+
if (typeSymbol && ctx.shouldExpandExternal && !typeSymbol.getName().startsWith("__") && !ctx.shouldExpandExternal(typeSymbol)) {
|
|
4691
|
+
return;
|
|
4692
|
+
}
|
|
4693
|
+
if (isForeignPackage(typeSymbol, ctx.workspacePackages)) {
|
|
4694
|
+
return;
|
|
4695
|
+
}
|
|
4696
|
+
if (isDeferredMappedOrConditional(type)) {
|
|
4697
|
+
return;
|
|
4698
|
+
}
|
|
4699
|
+
if (type.flags & ts7.TypeFlags.Object) {
|
|
4700
|
+
const props = type.getProperties();
|
|
4701
|
+
const limit = ctx.maxProperties;
|
|
4702
|
+
if (props.length > limit && ctx.onTruncation) {
|
|
4703
|
+
const typeName = type.getSymbol()?.getName() ?? "anonymous";
|
|
4704
|
+
ctx.onTruncation(typeName, props.length, limit);
|
|
4705
|
+
}
|
|
4706
|
+
for (const prop of props.slice(0, limit)) {
|
|
4707
|
+
const propType = checker.getTypeOfSymbol(prop);
|
|
4708
|
+
registerReferencedTypes(propType, ctx, depth + 1);
|
|
4709
|
+
}
|
|
4710
|
+
}
|
|
4711
|
+
}
|
|
4712
|
+
|
|
4577
4713
|
// src/serializers/context.ts
|
|
4714
|
+
import ts8 from "typescript";
|
|
4578
4715
|
function createContext(program, sourceFile, options = {}) {
|
|
4579
4716
|
return {
|
|
4580
4717
|
typeChecker: program.getTypeChecker(),
|
|
@@ -4594,9 +4731,12 @@ function createContext(program, sourceFile, options = {}) {
|
|
|
4594
4731
|
declIds: new Map,
|
|
4595
4732
|
idOwner: new Map,
|
|
4596
4733
|
workspacePackages: options.workspacePackages ?? new Map,
|
|
4734
|
+
budget: { owner: "", ops: 0, exceeded: false },
|
|
4735
|
+
maxBudgetOps: MAX_BUDGET_OPS,
|
|
4597
4736
|
schemaOps: 0,
|
|
4598
|
-
maxSchemaOps:
|
|
4599
|
-
budgetExceeded: false
|
|
4737
|
+
maxSchemaOps: MAX_SCHEMA_OPS,
|
|
4738
|
+
budgetExceeded: false,
|
|
4739
|
+
exhaustedBudgets: []
|
|
4600
4740
|
};
|
|
4601
4741
|
}
|
|
4602
4742
|
function getInheritedMembers(classType, ownMemberNames, ctx, isStatic = false) {
|
|
@@ -4662,7 +4802,7 @@ function getStaticMembers(classType, checker) {
|
|
|
4662
4802
|
});
|
|
4663
4803
|
}
|
|
4664
4804
|
function inheritedMethodSchema(symbol, type, ctx) {
|
|
4665
|
-
if (!ctx.
|
|
4805
|
+
if (!ctx.budget.exceeded) {
|
|
4666
4806
|
return decoratePropertySchema({ "x-ts-function": true }, symbol, type, ctx.typeChecker);
|
|
4667
4807
|
}
|
|
4668
4808
|
return {
|
|
@@ -4680,7 +4820,7 @@ function serializeInheritedMember(symbol, inheritedFrom, ctx, isStatic) {
|
|
|
4680
4820
|
const isOptional = !!(symbol.flags & ts8.SymbolFlags.Optional);
|
|
4681
4821
|
const rawType = checker.getTypeOfSymbol(symbol);
|
|
4682
4822
|
const type = isOptional ? stripUndefinedFromType(rawType, checker) : rawType;
|
|
4683
|
-
const registerTypes = !ctx.
|
|
4823
|
+
const registerTypes = !ctx.budget.exceeded;
|
|
4684
4824
|
if (registerTypes)
|
|
4685
4825
|
registerReferencedTypes(type, ctx);
|
|
4686
4826
|
let visibility;
|
|
@@ -4849,7 +4989,8 @@ function serializeClass(node, ctx) {
|
|
|
4849
4989
|
members.push(...inheritedInstance);
|
|
4850
4990
|
const inheritedStatic = getInheritedMembers(classType, ownMemberNames, ctx, true);
|
|
4851
4991
|
members.push(...inheritedStatic);
|
|
4852
|
-
const extendsClause =
|
|
4992
|
+
const extendsClause = getExtendsText(node, checker);
|
|
4993
|
+
const openArms = openHeritageArms([node], checker, ctx);
|
|
4853
4994
|
const implementsClause = getImplementsClause(node, checker);
|
|
4854
4995
|
const classFlags = {};
|
|
4855
4996
|
const classModifiers = ts10.getModifiers(node);
|
|
@@ -4867,6 +5008,7 @@ function serializeClass(node, ctx) {
|
|
|
4867
5008
|
members: members.length > 0 ? members : undefined,
|
|
4868
5009
|
signatures: signatures.length > 0 ? signatures : undefined,
|
|
4869
5010
|
extends: extendsClause,
|
|
5011
|
+
...openArms.length > 0 ? { schema: { allOf: openArms } } : {},
|
|
4870
5012
|
implements: implementsClause?.length ? implementsClause : undefined,
|
|
4871
5013
|
...deprecated ? { deprecated: true, deprecationReason } : {},
|
|
4872
5014
|
...examples.length > 0 ? { examples } : {},
|
|
@@ -4879,11 +5021,7 @@ function getMemberName(member) {
|
|
|
4879
5021
|
return "constructor";
|
|
4880
5022
|
if (!member.name)
|
|
4881
5023
|
return;
|
|
4882
|
-
|
|
4883
|
-
return member.name.text;
|
|
4884
|
-
if (ts10.isPrivateIdentifier(member.name))
|
|
4885
|
-
return member.name.text;
|
|
4886
|
-
return member.name.getText();
|
|
5024
|
+
return propertyNameText(member.name);
|
|
4887
5025
|
}
|
|
4888
5026
|
function getVisibility(member) {
|
|
4889
5027
|
const modifiers = ts10.canHaveModifiers(member) ? ts10.getModifiers(member) : undefined;
|
|
@@ -5085,21 +5223,6 @@ function serializeAccessor(node, ctx) {
|
|
|
5085
5223
|
...inlineTags ? { inlineTags } : {}
|
|
5086
5224
|
};
|
|
5087
5225
|
}
|
|
5088
|
-
function getExtendsClause(node, checker) {
|
|
5089
|
-
if (!node.heritageClauses)
|
|
5090
|
-
return;
|
|
5091
|
-
for (const clause of node.heritageClauses) {
|
|
5092
|
-
if (clause.token === ts10.SyntaxKind.ExtendsKeyword) {
|
|
5093
|
-
const expr = clause.types[0];
|
|
5094
|
-
if (expr) {
|
|
5095
|
-
const type = checker.getTypeAtLocation(expr);
|
|
5096
|
-
const symbol = type.getSymbol();
|
|
5097
|
-
return symbol?.getName() ?? expr.expression.getText();
|
|
5098
|
-
}
|
|
5099
|
-
}
|
|
5100
|
-
}
|
|
5101
|
-
return;
|
|
5102
|
-
}
|
|
5103
5226
|
function getImplementsClause(node, checker) {
|
|
5104
5227
|
if (!node.heritageClauses)
|
|
5105
5228
|
return;
|
|
@@ -5336,7 +5459,8 @@ function serializeInterface(node, ctx) {
|
|
|
5336
5459
|
const { description, tags, examples, source, deprecated, deprecationReason, inlineTags } = extractExportMetadata(node, symbol, checker);
|
|
5337
5460
|
const typeParameters = extractTypeParameters(node, checker);
|
|
5338
5461
|
const { members, callSignatureMember } = serializeTypeElements(node.members, ctx);
|
|
5339
|
-
const extendsClause =
|
|
5462
|
+
const extendsClause = getExtendsText(node, checker);
|
|
5463
|
+
const openArms = openHeritageArms([node], checker, ctx);
|
|
5340
5464
|
const exportSignatures = callSignatureMember?.signatures && callSignatureMember.signatures.length > 0 ? callSignatureMember.signatures : undefined;
|
|
5341
5465
|
return {
|
|
5342
5466
|
id: name,
|
|
@@ -5349,6 +5473,7 @@ function serializeInterface(node, ctx) {
|
|
|
5349
5473
|
members: members.length > 0 ? members : undefined,
|
|
5350
5474
|
signatures: exportSignatures,
|
|
5351
5475
|
extends: extendsClause,
|
|
5476
|
+
...openArms.length > 0 ? { schema: { allOf: openArms } } : {},
|
|
5352
5477
|
...deprecated ? { deprecated: true, deprecationReason } : {},
|
|
5353
5478
|
...examples.length > 0 ? { examples } : {},
|
|
5354
5479
|
...inlineTags ? { inlineTags } : {}
|
|
@@ -5438,7 +5563,7 @@ function serializeMergedTypeSide(symbol, ctx) {
|
|
|
5438
5563
|
const { description, tags } = getJSDocComment(typeDecl);
|
|
5439
5564
|
return {
|
|
5440
5565
|
members,
|
|
5441
|
-
extends: interfaces.map((decl) =>
|
|
5566
|
+
extends: interfaces.map((decl) => getExtendsText(decl, checker)).find(Boolean),
|
|
5442
5567
|
typeParameters: extractTypeParameters(typeDecl, checker),
|
|
5443
5568
|
description,
|
|
5444
5569
|
tags
|
|
@@ -5446,7 +5571,7 @@ function serializeMergedTypeSide(symbol, ctx) {
|
|
|
5446
5571
|
}
|
|
5447
5572
|
function serializePropertySignature(node, ctx) {
|
|
5448
5573
|
const { typeChecker: checker } = ctx;
|
|
5449
|
-
const name = node.name
|
|
5574
|
+
const name = propertyNameText(node.name);
|
|
5450
5575
|
const { description, tags, inlineTags } = getJSDocComment(node);
|
|
5451
5576
|
const rawType = checker.getTypeAtLocation(node);
|
|
5452
5577
|
const type = node.questionToken ? stripUndefinedFromType(rawType, checker) : rawType;
|
|
@@ -5476,7 +5601,7 @@ function serializePropertySignature(node, ctx) {
|
|
|
5476
5601
|
}
|
|
5477
5602
|
function serializeMethodSignature(node, ctx) {
|
|
5478
5603
|
const { typeChecker: checker } = ctx;
|
|
5479
|
-
const name = node.name
|
|
5604
|
+
const name = propertyNameText(node.name);
|
|
5480
5605
|
const { description, tags, inlineTags } = getJSDocComment(node);
|
|
5481
5606
|
const rawType = checker.getTypeAtLocation(node);
|
|
5482
5607
|
const type = node.questionToken ? stripUndefinedFromType(rawType, checker) : rawType;
|
|
@@ -5544,20 +5669,6 @@ function serializeIndexSignature(node, ctx) {
|
|
|
5544
5669
|
...inlineTags ? { inlineTags } : {}
|
|
5545
5670
|
};
|
|
5546
5671
|
}
|
|
5547
|
-
function getInterfaceExtends(node, checker) {
|
|
5548
|
-
if (!node.heritageClauses)
|
|
5549
|
-
return;
|
|
5550
|
-
for (const clause of node.heritageClauses) {
|
|
5551
|
-
if (clause.token === ts12.SyntaxKind.ExtendsKeyword && clause.types.length > 0) {
|
|
5552
|
-
const names = clause.types.map((expr) => {
|
|
5553
|
-
const type = checker.getTypeAtLocation(expr);
|
|
5554
|
-
return type.getSymbol()?.getName() ?? expr.expression.getText();
|
|
5555
|
-
});
|
|
5556
|
-
return names.join(" & ");
|
|
5557
|
-
}
|
|
5558
|
-
}
|
|
5559
|
-
return;
|
|
5560
|
-
}
|
|
5561
5672
|
|
|
5562
5673
|
// src/serializers/type-aliases.ts
|
|
5563
5674
|
import ts13 from "typescript";
|
|
@@ -5602,7 +5713,7 @@ function serializeTypeAlias(node, ctx) {
|
|
|
5602
5713
|
schema = buildObjectSchema(type.getProperties(), ctx.typeChecker, ctx, type);
|
|
5603
5714
|
members = serializeResolvedMembers(type, node, ctx);
|
|
5604
5715
|
} else {
|
|
5605
|
-
schema =
|
|
5716
|
+
schema = buildAliasBodySchema(type, ctx.typeChecker, ctx);
|
|
5606
5717
|
if (isObjectShapedAlias(type, ctx)) {
|
|
5607
5718
|
members = serializeResolvedMembers(type, node, ctx);
|
|
5608
5719
|
}
|
|
@@ -6317,10 +6428,14 @@ function normalizeExport(exp, options = {}) {
|
|
|
6317
6428
|
result.members = exp.members.map((member) => normalizeMember(member, options));
|
|
6318
6429
|
}
|
|
6319
6430
|
if (!vendorSchema && shouldGenerateMembersSchema(exp.kind) && exp.members && exp.members.length > 0) {
|
|
6320
|
-
result.schema = normalizeMembers(exp.members, options);
|
|
6431
|
+
result.schema = withOpenArms(normalizeMembers(exp.members, options), result.schema);
|
|
6321
6432
|
}
|
|
6322
6433
|
return result;
|
|
6323
6434
|
}
|
|
6435
|
+
function withOpenArms(membersSchema, provided) {
|
|
6436
|
+
const arms = provided?.allOf;
|
|
6437
|
+
return Array.isArray(arms) ? { allOf: [membersSchema, ...arms] } : membersSchema;
|
|
6438
|
+
}
|
|
6324
6439
|
function normalizeType(type, options = {}) {
|
|
6325
6440
|
const result = { ...type };
|
|
6326
6441
|
if (type.schema) {
|
|
@@ -6330,7 +6445,7 @@ function normalizeType(type, options = {}) {
|
|
|
6330
6445
|
result.members = type.members.map((member) => normalizeMember(member, options));
|
|
6331
6446
|
}
|
|
6332
6447
|
if (shouldGenerateMembersSchema(type.kind) && type.members && type.members.length > 0) {
|
|
6333
|
-
result.schema = normalizeMembers(type.members, options);
|
|
6448
|
+
result.schema = withOpenArms(normalizeMembers(type.members, options), result.schema);
|
|
6334
6449
|
}
|
|
6335
6450
|
return result;
|
|
6336
6451
|
}
|
|
@@ -7708,6 +7823,11 @@ function expandReachableTypes(exportedSymbols, ctx, opts) {
|
|
|
7708
7823
|
visit(t, depth + 1);
|
|
7709
7824
|
}
|
|
7710
7825
|
}
|
|
7826
|
+
const declared = declaredForm(type, checker);
|
|
7827
|
+
if (declared !== type) {
|
|
7828
|
+
visit(declared, depth);
|
|
7829
|
+
return;
|
|
7830
|
+
}
|
|
7711
7831
|
if (!allowed || isDeferredMappedOrConditional(type) || !(type.flags & ts20.TypeFlags.Object || type.isClassOrInterface())) {
|
|
7712
7832
|
return;
|
|
7713
7833
|
}
|
|
@@ -7781,7 +7901,7 @@ function expandReachableTypes(exportedSymbols, ctx, opts) {
|
|
|
7781
7901
|
id,
|
|
7782
7902
|
name,
|
|
7783
7903
|
kind: symbolKind(symbol),
|
|
7784
|
-
schema: ensureNonEmptySchema(buildSchema(declared, checker, ctx, writtenWhenAny(symbol, declared)), declared, checker)
|
|
7904
|
+
schema: withExpansionBudget(ctx, `type ${id}`, () => ensureNonEmptySchema(buildSchema(declared, checker, ctx, writtenWhenAny(symbol, declared)), declared, checker))
|
|
7785
7905
|
});
|
|
7786
7906
|
}
|
|
7787
7907
|
symbolByName.set(name, symbol);
|
|
@@ -8231,7 +8351,7 @@ async function extract(options) {
|
|
|
8231
8351
|
}
|
|
8232
8352
|
continue;
|
|
8233
8353
|
}
|
|
8234
|
-
const exp = serializeDeclaration2(declaration, symbol, exportName, ctx, isTypeOnly);
|
|
8354
|
+
const exp = withExpansionBudget(ctx, exportName, () => serializeDeclaration2(declaration, symbol, exportName, ctx, isTypeOnly));
|
|
8235
8355
|
if (exp) {
|
|
8236
8356
|
const typeSide = mergedTypeSideOf(exp, declaration, targetSymbol, ctx);
|
|
8237
8357
|
if (typeSide) {
|
|
@@ -8260,7 +8380,7 @@ async function extract(options) {
|
|
|
8260
8380
|
}
|
|
8261
8381
|
}
|
|
8262
8382
|
for (const { index, symbol, ontoClass } of mergedTypeSides) {
|
|
8263
|
-
exports[index] = withMergedTypeSide(exports[index], symbol, ctx, ontoClass);
|
|
8383
|
+
exports[index] = withExpansionBudget(ctx, exports[index].name, () => withMergedTypeSide(exports[index], symbol, ctx, ontoClass));
|
|
8264
8384
|
}
|
|
8265
8385
|
const verification = buildVerificationSummary(exportedSymbols.length, exports.length, exportTracker);
|
|
8266
8386
|
const meta = await getPackageMeta(entryFile, baseDir);
|
|
@@ -8271,7 +8391,7 @@ async function extract(options) {
|
|
|
8271
8391
|
});
|
|
8272
8392
|
if (ctx.budgetExceeded) {
|
|
8273
8393
|
diagnostics.push({
|
|
8274
|
-
message:
|
|
8394
|
+
message: `Stopped expanding some types after hitting the schema expansion budget${exhaustedBudgetNote(ctx)}`,
|
|
8275
8395
|
severity: "warning",
|
|
8276
8396
|
code: "TYPE_EXPANSION_LIMIT"
|
|
8277
8397
|
});
|
|
@@ -8751,6 +8871,13 @@ function withMergedTypeSide(entry, symbol, ctx, ontoClass) {
|
|
|
8751
8871
|
...entry.description ? {} : { description, tags: [...entry.tags ?? [], ...tags ?? []] }
|
|
8752
8872
|
};
|
|
8753
8873
|
}
|
|
8874
|
+
function exhaustedBudgetNote(ctx) {
|
|
8875
|
+
const owners = [...new Set(ctx.exhaustedBudgets)];
|
|
8876
|
+
if (owners.length === 0)
|
|
8877
|
+
return "";
|
|
8878
|
+
const shown = owners.slice(0, 10).join(", ");
|
|
8879
|
+
return `: ${shown}${owners.length > 10 ? ` (+${owners.length - 10} more)` : ""}`;
|
|
8880
|
+
}
|
|
8754
8881
|
function withExportName(entry, exportName) {
|
|
8755
8882
|
if (entry.name === exportName) {
|
|
8756
8883
|
return entry;
|
|
@@ -9322,6 +9449,7 @@ function getNodeName(node) {
|
|
|
9322
9449
|
export {
|
|
9323
9450
|
zodAdapter,
|
|
9324
9451
|
writtenTypeText,
|
|
9452
|
+
withOpenHeritage,
|
|
9325
9453
|
withDescription,
|
|
9326
9454
|
withDeprecated,
|
|
9327
9455
|
validateSpec2 as validateSpec,
|
|
@@ -9367,6 +9495,7 @@ export {
|
|
|
9367
9495
|
query,
|
|
9368
9496
|
pickEntry,
|
|
9369
9497
|
parseGithubRepo,
|
|
9498
|
+
openHeritageArms,
|
|
9370
9499
|
normalizeType,
|
|
9371
9500
|
normalizeSchema,
|
|
9372
9501
|
normalizeMembers,
|
|
@@ -9448,6 +9577,7 @@ export {
|
|
|
9448
9577
|
buildSchema,
|
|
9449
9578
|
buildObjectSchema,
|
|
9450
9579
|
buildFunctionSchema,
|
|
9580
|
+
buildAliasBodySchema,
|
|
9451
9581
|
assertSpec,
|
|
9452
9582
|
asStandardSchema,
|
|
9453
9583
|
arktypeAdapter,
|