@openpkg-ts/sdk 0.54.9 → 0.54.11
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 +450 -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;
|
|
@@ -2991,6 +3066,7 @@ var BUILTIN_GENERICS = new Set([
|
|
|
2991
3066
|
"AsyncIterableIterator",
|
|
2992
3067
|
"Generator",
|
|
2993
3068
|
"AsyncGenerator",
|
|
3069
|
+
"ArrayLike",
|
|
2994
3070
|
"Partial",
|
|
2995
3071
|
"Required",
|
|
2996
3072
|
"Readonly",
|
|
@@ -3135,6 +3211,7 @@ var BUILTIN_TYPES = new Set([
|
|
|
3135
3211
|
"Error",
|
|
3136
3212
|
"Function",
|
|
3137
3213
|
"ArrayBuffer",
|
|
3214
|
+
"ArrayBufferLike",
|
|
3138
3215
|
"SharedArrayBuffer",
|
|
3139
3216
|
"DataView",
|
|
3140
3217
|
"Uint8Array",
|
|
@@ -3318,7 +3395,12 @@ function isUtilityOverTypeParameter(type) {
|
|
|
3318
3395
|
const args = type.aliasTypeArguments;
|
|
3319
3396
|
if (!args || args.length === 0)
|
|
3320
3397
|
return false;
|
|
3321
|
-
|
|
3398
|
+
if (!args.some((t) => containsUnresolvedTypeParameter(t)))
|
|
3399
|
+
return false;
|
|
3400
|
+
if (args[0].flags & ts5.TypeFlags.TypeParameter || !(type.flags & ts5.TypeFlags.Object)) {
|
|
3401
|
+
return true;
|
|
3402
|
+
}
|
|
3403
|
+
return type.getProperties().length === 0;
|
|
3322
3404
|
}
|
|
3323
3405
|
function writtenUtilityText(type, checker, typeNode) {
|
|
3324
3406
|
let node = typeNode;
|
|
@@ -3398,6 +3480,14 @@ function buildSchema(type, checker, ctx, typeNode) {
|
|
|
3398
3480
|
const schema = buildSchemaInternal(type, checker, ctx, typeNode);
|
|
3399
3481
|
return ensureNonEmptySchema(schema, type, checker);
|
|
3400
3482
|
}
|
|
3483
|
+
function buildAliasBodySchema(type, checker, ctx) {
|
|
3484
|
+
ctx.aliasBody = type;
|
|
3485
|
+
try {
|
|
3486
|
+
return buildSchema(type, checker, ctx);
|
|
3487
|
+
} finally {
|
|
3488
|
+
ctx.aliasBody = undefined;
|
|
3489
|
+
}
|
|
3490
|
+
}
|
|
3401
3491
|
function buildMaxDepthSchema(type, checker, typeNode, ctx) {
|
|
3402
3492
|
if (type.flags & ts5.TypeFlags.Any) {
|
|
3403
3493
|
if (typeNode)
|
|
@@ -3446,13 +3536,44 @@ function buildMaxDepthSchema(type, checker, typeNode, ctx) {
|
|
|
3446
3536
|
}
|
|
3447
3537
|
return { type: checker.typeToString(type) };
|
|
3448
3538
|
}
|
|
3539
|
+
function writtenTypeArguments(typeNode, symbol, checker) {
|
|
3540
|
+
if (!typeNode || !symbol || !ts5.isTypeReferenceNode(typeNode) || !typeNode.typeArguments) {
|
|
3541
|
+
return;
|
|
3542
|
+
}
|
|
3543
|
+
const name = ts5.isQualifiedName(typeNode.typeName) ? typeNode.typeName.right : typeNode.typeName;
|
|
3544
|
+
const written = resolvedSymbol(checker.getSymbolAtLocation(name), checker);
|
|
3545
|
+
return written === symbol ? typeNode.typeArguments : undefined;
|
|
3546
|
+
}
|
|
3547
|
+
function genericAliasRef(type, checker, ctx, typeNode) {
|
|
3548
|
+
const aliasTypeArgs = type.aliasTypeArguments;
|
|
3549
|
+
const name = type.aliasSymbol?.getName();
|
|
3550
|
+
if (!name || !aliasTypeArgs?.length)
|
|
3551
|
+
return;
|
|
3552
|
+
if (name.startsWith("__") || BUILTIN_TYPES.has(name) || isBuiltinGeneric(name))
|
|
3553
|
+
return;
|
|
3554
|
+
const argNodes = writtenTypeArguments(typeNode, type.aliasSymbol, checker);
|
|
3555
|
+
const build = () => {
|
|
3556
|
+
const schema = {
|
|
3557
|
+
$ref: `#/types/${namedRefId(type, name, ctx)}`,
|
|
3558
|
+
typeArguments: aliasTypeArgs.map((t, i) => buildSchema(t, checker, ctx, argNodes?.[i]))
|
|
3559
|
+
};
|
|
3560
|
+
const packageOrigin = getTypeOrigin(type, checker);
|
|
3561
|
+
if (packageOrigin) {
|
|
3562
|
+
setSchemaExtension(schema, "x-ts-package", packageOrigin);
|
|
3563
|
+
}
|
|
3564
|
+
return schema;
|
|
3565
|
+
};
|
|
3566
|
+
return ctx ? withDepth(ctx, build) : build();
|
|
3567
|
+
}
|
|
3449
3568
|
function buildSchemaInternal(type, checker, ctx, typeNode) {
|
|
3450
3569
|
if (isAtMaxDepth(ctx)) {
|
|
3451
3570
|
return buildMaxDepthSchema(type, checker, typeNode, ctx);
|
|
3452
3571
|
}
|
|
3453
3572
|
if (ctx) {
|
|
3454
3573
|
ctx.schemaOps += 1;
|
|
3455
|
-
|
|
3574
|
+
ctx.budget.ops += 1;
|
|
3575
|
+
if (ctx.budget.ops > ctx.maxBudgetOps || ctx.schemaOps > ctx.maxSchemaOps) {
|
|
3576
|
+
ctx.budget.exceeded = true;
|
|
3456
3577
|
ctx.budgetExceeded = true;
|
|
3457
3578
|
return { "x-ts-type": cheapTypeText(type, checker, typeNode) };
|
|
3458
3579
|
}
|
|
@@ -3537,6 +3658,9 @@ function buildSchemaInternal(type, checker, ctx, typeNode) {
|
|
|
3537
3658
|
}
|
|
3538
3659
|
if (type.aliasSymbol && !type.aliasTypeArguments?.length) {
|
|
3539
3660
|
const aliasName = type.aliasSymbol.getName();
|
|
3661
|
+
if ((BUILTIN_TYPES.has(aliasName) || isBuiltinGeneric(aliasName)) && isBuiltinSymbol(type.aliasSymbol)) {
|
|
3662
|
+
return builtinSchema(aliasName);
|
|
3663
|
+
}
|
|
3540
3664
|
if (!aliasName.startsWith("__") && !isPrimitiveName(aliasName)) {
|
|
3541
3665
|
const packageOrigin = getTypeOrigin(type, checker);
|
|
3542
3666
|
const schema = { $ref: `#/types/${namedRefId(type, aliasName, ctx)}` };
|
|
@@ -3546,6 +3670,14 @@ function buildSchemaInternal(type, checker, ctx, typeNode) {
|
|
|
3546
3670
|
return schema;
|
|
3547
3671
|
}
|
|
3548
3672
|
}
|
|
3673
|
+
if (type.isUnion() || type.isIntersection()) {
|
|
3674
|
+
const ownBody = ctx?.aliasBody === type;
|
|
3675
|
+
if (ownBody && ctx)
|
|
3676
|
+
ctx.aliasBody = undefined;
|
|
3677
|
+
const aliasRef = ownBody ? undefined : genericAliasRef(type, checker, ctx, typeNode);
|
|
3678
|
+
if (aliasRef)
|
|
3679
|
+
return aliasRef;
|
|
3680
|
+
}
|
|
3549
3681
|
if (type.flags & ts5.TypeFlags.TemplateLiteral) {
|
|
3550
3682
|
return {
|
|
3551
3683
|
type: "string",
|
|
@@ -3670,11 +3802,12 @@ function buildSchemaInternal(type, checker, ctx, typeNode) {
|
|
|
3670
3802
|
}
|
|
3671
3803
|
if (name && !isAnonymous(typeRef.target)) {
|
|
3672
3804
|
const packageOrigin = getTypeOrigin(typeRef.target, checker);
|
|
3805
|
+
const argNodes = writtenTypeArguments(typeNode, symbol2, checker);
|
|
3673
3806
|
if (ctx) {
|
|
3674
3807
|
return withDepth(ctx, () => {
|
|
3675
3808
|
const schema2 = {
|
|
3676
3809
|
$ref: `#/types/${namedRefId(typeRef.target, name, ctx)}`,
|
|
3677
|
-
typeArguments: typeArgs.map((t) => buildSchema(t, checker, ctx))
|
|
3810
|
+
typeArguments: typeArgs.map((t, i) => buildSchema(t, checker, ctx, argNodes?.[i]))
|
|
3678
3811
|
};
|
|
3679
3812
|
if (packageOrigin) {
|
|
3680
3813
|
setSchemaExtension(schema2, "x-ts-package", packageOrigin);
|
|
@@ -3713,29 +3846,9 @@ function buildSchemaInternal(type, checker, ctx, typeNode) {
|
|
|
3713
3846
|
});
|
|
3714
3847
|
return ctx ? withDepth(ctx, build) : build();
|
|
3715
3848
|
}
|
|
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
|
-
}
|
|
3849
|
+
const aliasRef = genericAliasRef(type, checker, ctx, typeNode);
|
|
3850
|
+
if (aliasRef)
|
|
3851
|
+
return aliasRef;
|
|
3739
3852
|
}
|
|
3740
3853
|
if (type.flags & ts5.TypeFlags.Object) {
|
|
3741
3854
|
const callSignatures = type.getCallSignatures();
|
|
@@ -4000,219 +4113,7 @@ function findDiscriminatorProperty(unionTypes, checker) {
|
|
|
4000
4113
|
return;
|
|
4001
4114
|
}
|
|
4002
4115
|
|
|
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
4116
|
// src/ast/registry.ts
|
|
4215
|
-
import ts7 from "typescript";
|
|
4216
4117
|
var BUILTINS = new Set([
|
|
4217
4118
|
"Array",
|
|
4218
4119
|
"ArrayBuffer",
|
|
@@ -4289,6 +4190,26 @@ function isExternalType(decl) {
|
|
|
4289
4190
|
return false;
|
|
4290
4191
|
return sourceFile.fileName.includes("node_modules");
|
|
4291
4192
|
}
|
|
4193
|
+
function declaredForm(type, checker, symbol = type.aliasSymbol ?? type.getSymbol()) {
|
|
4194
|
+
if (!symbol)
|
|
4195
|
+
return type;
|
|
4196
|
+
const generic = ts6.SymbolFlags.TypeAlias | ts6.SymbolFlags.Interface | ts6.SymbolFlags.Class;
|
|
4197
|
+
if (!(symbol.flags & generic))
|
|
4198
|
+
return type;
|
|
4199
|
+
const target = type.target;
|
|
4200
|
+
const instantiated = type.aliasTypeArguments?.length || target && target !== type;
|
|
4201
|
+
return instantiated ? declaredTypeOf(symbol, type, checker) : type;
|
|
4202
|
+
}
|
|
4203
|
+
function declaredTypeOf(symbol, fallback, checker) {
|
|
4204
|
+
const declared = checker.getDeclaredTypeOfSymbol(symbol);
|
|
4205
|
+
return declared.flags & ts6.TypeFlags.Any ? fallback : declared;
|
|
4206
|
+
}
|
|
4207
|
+
function registeredForm(type, symbol, checker) {
|
|
4208
|
+
const constructorSide = symbol.flags & ts6.SymbolFlags.Class && type.objectFlags & ts6.ObjectFlags.Anonymous;
|
|
4209
|
+
if (constructorSide)
|
|
4210
|
+
return declaredTypeOf(symbol, type, checker);
|
|
4211
|
+
return declaredForm(type, checker, symbol);
|
|
4212
|
+
}
|
|
4292
4213
|
|
|
4293
4214
|
class TypeRegistry {
|
|
4294
4215
|
types = new Map;
|
|
@@ -4322,13 +4243,13 @@ class TypeRegistry {
|
|
|
4322
4243
|
return;
|
|
4323
4244
|
if (name.startsWith('"'))
|
|
4324
4245
|
return;
|
|
4325
|
-
if (symbol.flags &
|
|
4246
|
+
if (symbol.flags & ts6.SymbolFlags.EnumMember)
|
|
4326
4247
|
return;
|
|
4327
|
-
if (symbol.flags &
|
|
4248
|
+
if (symbol.flags & ts6.SymbolFlags.TypeParameter)
|
|
4328
4249
|
return;
|
|
4329
|
-
if (symbol.flags &
|
|
4250
|
+
if (symbol.flags & ts6.SymbolFlags.Method)
|
|
4330
4251
|
return;
|
|
4331
|
-
if (symbol.flags &
|
|
4252
|
+
if (symbol.flags & ts6.SymbolFlags.Function)
|
|
4332
4253
|
return;
|
|
4333
4254
|
if (isGenericTypeParameter(name))
|
|
4334
4255
|
return;
|
|
@@ -4361,7 +4282,7 @@ class TypeRegistry {
|
|
|
4361
4282
|
return id;
|
|
4362
4283
|
this.processing.add(id);
|
|
4363
4284
|
try {
|
|
4364
|
-
const specType = this.buildSpecType(type, symbol, id, ctx);
|
|
4285
|
+
const specType = withExpansionBudget(ctx, `type ${id}`, () => this.buildSpecType(registeredForm(type, symbol, ctx.typeChecker), symbol, id, ctx));
|
|
4365
4286
|
if (specType) {
|
|
4366
4287
|
this.add(specType);
|
|
4367
4288
|
return specType.id;
|
|
@@ -4378,17 +4299,17 @@ class TypeRegistry {
|
|
|
4378
4299
|
let kind = "type";
|
|
4379
4300
|
const external = decl ? isExternalType(decl) : false;
|
|
4380
4301
|
if (decl) {
|
|
4381
|
-
if (
|
|
4302
|
+
if (ts6.isClassDeclaration(decl))
|
|
4382
4303
|
kind = "class";
|
|
4383
|
-
else if (
|
|
4304
|
+
else if (ts6.isInterfaceDeclaration(decl))
|
|
4384
4305
|
kind = "interface";
|
|
4385
|
-
else if (
|
|
4306
|
+
else if (ts6.isEnumDeclaration(decl))
|
|
4386
4307
|
kind = "enum";
|
|
4387
4308
|
}
|
|
4388
4309
|
if (external) {
|
|
4389
4310
|
kind = "external";
|
|
4390
4311
|
}
|
|
4391
|
-
let schema =
|
|
4312
|
+
let schema = buildAliasBodySchema(type, checker, ctx);
|
|
4392
4313
|
if (this.isSelfRef(schema, id)) {
|
|
4393
4314
|
schema = this.resolveSelRefSchema(type, checker, ctx);
|
|
4394
4315
|
}
|
|
@@ -4398,8 +4319,8 @@ class TypeRegistry {
|
|
|
4398
4319
|
schema = enumSchema;
|
|
4399
4320
|
}
|
|
4400
4321
|
}
|
|
4401
|
-
if (kind === "type" && decl &&
|
|
4402
|
-
const text = renderTypeText(type, checker, decl,
|
|
4322
|
+
if (kind === "type" && decl && ts6.isTypeAliasDeclaration(decl) && shouldEmitAliasTypeText(decl.type) && typeof schema === "object" && schema !== null && !("x-ts-type" in schema)) {
|
|
4323
|
+
const text = renderTypeText(type, checker, decl, ts6.TypeFormatFlags.InTypeAlias);
|
|
4403
4324
|
if (!PRIMITIVES.has(text) && text !== name) {
|
|
4404
4325
|
schema["x-ts-type"] = text;
|
|
4405
4326
|
const declared = writtenTypeText(declaredTypeNode(decl));
|
|
@@ -4408,8 +4329,11 @@ class TypeRegistry {
|
|
|
4408
4329
|
}
|
|
4409
4330
|
}
|
|
4410
4331
|
}
|
|
4332
|
+
const heritage = (symbol.declarations ?? []).filter((d) => ts6.isClassDeclaration(d) || ts6.isInterfaceDeclaration(d));
|
|
4333
|
+
const extendsText = heritage.map((d) => getExtendsText(d, checker)).find(Boolean);
|
|
4334
|
+
schema = withOpenHeritage(schema, openHeritageArms(heritage, checker, ctx));
|
|
4411
4335
|
let typeParameters;
|
|
4412
|
-
if (decl && (
|
|
4336
|
+
if (decl && (ts6.isTypeAliasDeclaration(decl) || ts6.isInterfaceDeclaration(decl) || ts6.isClassDeclaration(decl))) {
|
|
4413
4337
|
typeParameters = extractTypeParameters(decl, checker);
|
|
4414
4338
|
}
|
|
4415
4339
|
return {
|
|
@@ -4418,6 +4342,7 @@ class TypeRegistry {
|
|
|
4418
4342
|
kind,
|
|
4419
4343
|
...typeParameters && typeParameters.length > 0 ? { typeParameters } : {},
|
|
4420
4344
|
schema,
|
|
4345
|
+
...extendsText ? { extends: extendsText } : {},
|
|
4421
4346
|
...external ? { external: true } : {}
|
|
4422
4347
|
};
|
|
4423
4348
|
}
|
|
@@ -4430,14 +4355,14 @@ class TypeRegistry {
|
|
|
4430
4355
|
resolveSelRefSchema(type, checker, ctx) {
|
|
4431
4356
|
if (type.isUnion()) {
|
|
4432
4357
|
const types = type.types;
|
|
4433
|
-
const allStringLiterals = types.every((t) => t.flags &
|
|
4358
|
+
const allStringLiterals = types.every((t) => t.flags & ts6.TypeFlags.StringLiteral);
|
|
4434
4359
|
if (allStringLiterals) {
|
|
4435
4360
|
return {
|
|
4436
4361
|
type: "string",
|
|
4437
4362
|
enum: types.map((t) => t.value)
|
|
4438
4363
|
};
|
|
4439
4364
|
}
|
|
4440
|
-
const allNumberLiterals = types.every((t) => t.flags &
|
|
4365
|
+
const allNumberLiterals = types.every((t) => t.flags & ts6.TypeFlags.NumberLiteral);
|
|
4441
4366
|
if (allNumberLiterals) {
|
|
4442
4367
|
return {
|
|
4443
4368
|
type: "number",
|
|
@@ -4472,18 +4397,18 @@ class TypeRegistry {
|
|
|
4472
4397
|
const elementType = checker.getTypeArguments(type)?.[0];
|
|
4473
4398
|
return elementType ? { type: "array", items: buildSchema(elementType, checker, ctx) } : { type: "array" };
|
|
4474
4399
|
}
|
|
4475
|
-
if (type.flags &
|
|
4400
|
+
if (type.flags & ts6.TypeFlags.Conditional) {
|
|
4476
4401
|
return { "x-ts-type": renderTypeText(type, checker) };
|
|
4477
4402
|
}
|
|
4478
4403
|
const constraint = checker.getBaseConstraintOfType(type);
|
|
4479
|
-
const primitive = constraint && constraint.flags &
|
|
4404
|
+
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
4405
|
if (primitive) {
|
|
4481
4406
|
return { type: primitive, "x-ts-type": renderTypeText(type, checker) };
|
|
4482
4407
|
}
|
|
4483
4408
|
return this.buildObjectSchemaFromProperties(type, checker, ctx);
|
|
4484
4409
|
}
|
|
4485
4410
|
buildEnumSchema(symbol, checker) {
|
|
4486
|
-
const decl = symbol.declarations?.find(
|
|
4411
|
+
const decl = symbol.declarations?.find(ts6.isEnumDeclaration);
|
|
4487
4412
|
if (!decl)
|
|
4488
4413
|
return;
|
|
4489
4414
|
const members = [];
|
|
@@ -4510,8 +4435,8 @@ class TypeRegistry {
|
|
|
4510
4435
|
buildObjectSchemaFromProperties(type, checker, ctx) {
|
|
4511
4436
|
const properties = type.getProperties();
|
|
4512
4437
|
const indexInfos = checker.getIndexInfosOfType(type);
|
|
4513
|
-
const stringIndex = indexInfos.find((i) => i.keyType.flags &
|
|
4514
|
-
const numberIndex = indexInfos.find((i) => i.keyType.flags &
|
|
4438
|
+
const stringIndex = indexInfos.find((i) => i.keyType.flags & ts6.TypeFlags.String);
|
|
4439
|
+
const numberIndex = indexInfos.find((i) => i.keyType.flags & ts6.TypeFlags.Number);
|
|
4515
4440
|
if (properties.length === 0 && !stringIndex && !numberIndex) {
|
|
4516
4441
|
return { type: checker.typeToString(type) };
|
|
4517
4442
|
}
|
|
@@ -4519,8 +4444,8 @@ class TypeRegistry {
|
|
|
4519
4444
|
const required = [];
|
|
4520
4445
|
const limit = ctx.maxProperties;
|
|
4521
4446
|
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 &
|
|
4447
|
+
const isStringLike = type.flags & ts6.TypeFlags.StringLike;
|
|
4448
|
+
const isNumberLike = type.flags & ts6.TypeFlags.NumberLike;
|
|
4524
4449
|
const included = properties.filter((prop) => {
|
|
4525
4450
|
const propName = prop.getName();
|
|
4526
4451
|
if (propName.startsWith("__@"))
|
|
@@ -4540,7 +4465,7 @@ class TypeRegistry {
|
|
|
4540
4465
|
for (const prop of included.slice(0, limit)) {
|
|
4541
4466
|
const propName = prop.getName();
|
|
4542
4467
|
const rawPropType = checker.getTypeOfSymbol(prop);
|
|
4543
|
-
const propType = prop.flags &
|
|
4468
|
+
const propType = prop.flags & ts6.SymbolFlags.Optional ? stripUndefinedFromType(rawPropType, checker) : rawPropType;
|
|
4544
4469
|
this.registerType(propType, ctx);
|
|
4545
4470
|
let propSchema = buildSchema(propType, checker, ctx, declaredTypeNode(prop.valueDeclaration ?? prop.getDeclarations()?.[0]));
|
|
4546
4471
|
const docComment = prop.getDocumentationComment(checker);
|
|
@@ -4557,7 +4482,7 @@ class TypeRegistry {
|
|
|
4557
4482
|
}
|
|
4558
4483
|
propSchema = decoratePropertySchema(propSchema, prop, propType, checker);
|
|
4559
4484
|
props[propName] = propSchema;
|
|
4560
|
-
if (!(prop.flags &
|
|
4485
|
+
if (!(prop.flags & ts6.SymbolFlags.Optional)) {
|
|
4561
4486
|
required.push(propName);
|
|
4562
4487
|
}
|
|
4563
4488
|
}
|
|
@@ -4574,7 +4499,224 @@ class TypeRegistry {
|
|
|
4574
4499
|
}
|
|
4575
4500
|
}
|
|
4576
4501
|
|
|
4502
|
+
// src/types/parameters.ts
|
|
4503
|
+
function extractParameters(signature, ctx) {
|
|
4504
|
+
const { typeChecker: checker } = ctx;
|
|
4505
|
+
const result = [];
|
|
4506
|
+
const signatureDecl = signature.getDeclaration();
|
|
4507
|
+
const jsdocTags = signatureDecl ? ts7.getJSDocTags(signatureDecl) : [];
|
|
4508
|
+
for (const param of signature.getParameters()) {
|
|
4509
|
+
const decl = param.valueDeclaration;
|
|
4510
|
+
if (!decl)
|
|
4511
|
+
continue;
|
|
4512
|
+
const defer = typeNodeDefersExpansion(decl.type, checker, ctx.program);
|
|
4513
|
+
const type = defer ? undefined : checker.getTypeOfSymbolAtLocation(param, decl);
|
|
4514
|
+
if (decl && ts7.isObjectBindingPattern(decl.name)) {
|
|
4515
|
+
const expandedParams = expandBindingPattern(decl, type ?? checker.getTypeOfSymbolAtLocation(param, decl), jsdocTags, ctx);
|
|
4516
|
+
result.push(...expandedParams);
|
|
4517
|
+
} else {
|
|
4518
|
+
const isOptional = !!decl?.questionToken || !!decl?.initializer;
|
|
4519
|
+
const isRest = !!decl.dotDotDotToken;
|
|
4520
|
+
const paramName = param.getName();
|
|
4521
|
+
const description = getParamDescription(paramName, jsdocTags);
|
|
4522
|
+
const schema = defer ? buildSchemaFromTypeNode(decl.type, checker, ctx) : buildSchema(isOptional ? stripUndefinedFromType(type, checker) : type, checker, ctx, decl.type);
|
|
4523
|
+
if (!defer && type) {
|
|
4524
|
+
registerReferencedTypes(isOptional ? stripUndefinedFromType(type, checker) : type, ctx);
|
|
4525
|
+
}
|
|
4526
|
+
const paramResult = {
|
|
4527
|
+
name: paramName,
|
|
4528
|
+
schema,
|
|
4529
|
+
required: !isOptional && !isRest,
|
|
4530
|
+
...isRest ? { rest: true } : {}
|
|
4531
|
+
};
|
|
4532
|
+
if (description) {
|
|
4533
|
+
paramResult.description = description;
|
|
4534
|
+
const inlineTags = parseInlineTags(description);
|
|
4535
|
+
if (inlineTags)
|
|
4536
|
+
paramResult.inlineTags = inlineTags;
|
|
4537
|
+
}
|
|
4538
|
+
if (decl.initializer) {
|
|
4539
|
+
applyDefault(paramResult, decl.initializer);
|
|
4540
|
+
}
|
|
4541
|
+
result.push(paramResult);
|
|
4542
|
+
}
|
|
4543
|
+
}
|
|
4544
|
+
return result;
|
|
4545
|
+
}
|
|
4546
|
+
function expandBindingPattern(paramDecl, paramType, jsdocTags, ctx) {
|
|
4547
|
+
const { typeChecker: checker } = ctx;
|
|
4548
|
+
const result = [];
|
|
4549
|
+
const bindingPattern = paramDecl.name;
|
|
4550
|
+
const allProperties = getEffectiveProperties(paramType, checker);
|
|
4551
|
+
const inferredAlias = inferParamAlias(jsdocTags);
|
|
4552
|
+
for (const element of bindingPattern.elements) {
|
|
4553
|
+
if (!ts7.isBindingElement(element))
|
|
4554
|
+
continue;
|
|
4555
|
+
const propertyName = element.propertyName ? ts7.isIdentifier(element.propertyName) ? element.propertyName.text : element.propertyName.getText() : ts7.isIdentifier(element.name) ? element.name.text : element.name.getText();
|
|
4556
|
+
const propSymbol = allProperties.get(propertyName);
|
|
4557
|
+
if (!propSymbol)
|
|
4558
|
+
continue;
|
|
4559
|
+
const isOptional = !!(propSymbol.flags & ts7.SymbolFlags.Optional) || element.initializer !== undefined;
|
|
4560
|
+
const propType = checker.getTypeOfSymbol(propSymbol);
|
|
4561
|
+
const effectiveType = isOptional ? stripUndefinedFromType(propType, checker) : propType;
|
|
4562
|
+
registerReferencedTypes(effectiveType, ctx);
|
|
4563
|
+
const description = getParamDescription(propertyName, jsdocTags, inferredAlias);
|
|
4564
|
+
const param = {
|
|
4565
|
+
name: propertyName,
|
|
4566
|
+
schema: buildSchema(effectiveType, checker, ctx, declaredTypeNode(propSymbol.valueDeclaration)),
|
|
4567
|
+
required: !isOptional
|
|
4568
|
+
};
|
|
4569
|
+
if (description) {
|
|
4570
|
+
param.description = description;
|
|
4571
|
+
const inlineTags = parseInlineTags(description);
|
|
4572
|
+
if (inlineTags)
|
|
4573
|
+
param.inlineTags = inlineTags;
|
|
4574
|
+
}
|
|
4575
|
+
if (element.initializer) {
|
|
4576
|
+
applyDefault(param, element.initializer);
|
|
4577
|
+
}
|
|
4578
|
+
result.push(param);
|
|
4579
|
+
}
|
|
4580
|
+
return result;
|
|
4581
|
+
}
|
|
4582
|
+
function getEffectiveProperties(type, _checker) {
|
|
4583
|
+
const properties = new Map;
|
|
4584
|
+
if (type.isIntersection()) {
|
|
4585
|
+
for (const subType of type.types) {
|
|
4586
|
+
for (const prop of subType.getProperties()) {
|
|
4587
|
+
properties.set(prop.getName(), prop);
|
|
4588
|
+
}
|
|
4589
|
+
}
|
|
4590
|
+
} else {
|
|
4591
|
+
for (const prop of type.getProperties()) {
|
|
4592
|
+
properties.set(prop.getName(), prop);
|
|
4593
|
+
}
|
|
4594
|
+
}
|
|
4595
|
+
return properties;
|
|
4596
|
+
}
|
|
4597
|
+
function inferParamAlias(jsdocTags) {
|
|
4598
|
+
const prefixes = [];
|
|
4599
|
+
for (const tag of jsdocTags) {
|
|
4600
|
+
if (tag.tagName.text !== "param")
|
|
4601
|
+
continue;
|
|
4602
|
+
const tagText = typeof tag.comment === "string" ? tag.comment : ts7.getTextOfJSDocComment(tag.comment) ?? "";
|
|
4603
|
+
const paramTag = tag;
|
|
4604
|
+
const paramName = paramTag.name?.getText() ?? "";
|
|
4605
|
+
if (paramName.includes(".")) {
|
|
4606
|
+
const prefix = paramName.split(".")[0];
|
|
4607
|
+
if (prefix && !prefix.startsWith("__")) {
|
|
4608
|
+
prefixes.push(prefix);
|
|
4609
|
+
}
|
|
4610
|
+
} else if (tagText.includes(".")) {
|
|
4611
|
+
const match = tagText.match(/^(\w+)\./);
|
|
4612
|
+
if (match && !match[1].startsWith("__")) {
|
|
4613
|
+
prefixes.push(match[1]);
|
|
4614
|
+
}
|
|
4615
|
+
}
|
|
4616
|
+
}
|
|
4617
|
+
if (prefixes.length === 0)
|
|
4618
|
+
return;
|
|
4619
|
+
const counts = new Map;
|
|
4620
|
+
for (const p of prefixes)
|
|
4621
|
+
counts.set(p, (counts.get(p) ?? 0) + 1);
|
|
4622
|
+
return Array.from(counts.entries()).sort((a, b) => b[1] - a[1])[0]?.[0];
|
|
4623
|
+
}
|
|
4624
|
+
function extractLiteralDefault(initializer) {
|
|
4625
|
+
if (ts7.isStringLiteral(initializer)) {
|
|
4626
|
+
return { literal: true, value: initializer.text };
|
|
4627
|
+
}
|
|
4628
|
+
if (ts7.isNumericLiteral(initializer)) {
|
|
4629
|
+
return { literal: true, value: Number(initializer.text) };
|
|
4630
|
+
}
|
|
4631
|
+
if (ts7.isPrefixUnaryExpression(initializer) && initializer.operator === ts7.SyntaxKind.MinusToken && ts7.isNumericLiteral(initializer.operand)) {
|
|
4632
|
+
return { literal: true, value: -Number(initializer.operand.text) };
|
|
4633
|
+
}
|
|
4634
|
+
if (initializer.kind === ts7.SyntaxKind.TrueKeyword) {
|
|
4635
|
+
return { literal: true, value: true };
|
|
4636
|
+
}
|
|
4637
|
+
if (initializer.kind === ts7.SyntaxKind.FalseKeyword) {
|
|
4638
|
+
return { literal: true, value: false };
|
|
4639
|
+
}
|
|
4640
|
+
if (initializer.kind === ts7.SyntaxKind.NullKeyword) {
|
|
4641
|
+
return { literal: true, value: null };
|
|
4642
|
+
}
|
|
4643
|
+
return { literal: false, text: initializer.getText() };
|
|
4644
|
+
}
|
|
4645
|
+
function applyDefault(param, initializer) {
|
|
4646
|
+
const extracted = extractLiteralDefault(initializer);
|
|
4647
|
+
if (extracted.literal) {
|
|
4648
|
+
param.default = extracted.value;
|
|
4649
|
+
if (param.schema && typeof param.schema === "object" && !Array.isArray(param.schema)) {
|
|
4650
|
+
param.schema.default = extracted.value;
|
|
4651
|
+
}
|
|
4652
|
+
} else {
|
|
4653
|
+
param.default = extracted.text;
|
|
4654
|
+
if (param.schema && typeof param.schema === "object" && !Array.isArray(param.schema)) {
|
|
4655
|
+
param.schema["x-ts-default"] = extracted.text;
|
|
4656
|
+
}
|
|
4657
|
+
}
|
|
4658
|
+
}
|
|
4659
|
+
function registerReferencedTypes(type, ctx, depth = 0) {
|
|
4660
|
+
if (depth > ctx.maxTypeDepth)
|
|
4661
|
+
return;
|
|
4662
|
+
if (ctx.registeredTypes.has(type))
|
|
4663
|
+
return;
|
|
4664
|
+
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);
|
|
4665
|
+
if (!isPrimitive) {
|
|
4666
|
+
ctx.registeredTypes.add(type);
|
|
4667
|
+
}
|
|
4668
|
+
const { typeChecker: checker, typeRegistry } = ctx;
|
|
4669
|
+
typeRegistry.registerType(type, ctx);
|
|
4670
|
+
const typeArgs = type.typeArguments;
|
|
4671
|
+
if (typeArgs) {
|
|
4672
|
+
for (const arg of typeArgs) {
|
|
4673
|
+
registerReferencedTypes(arg, ctx, depth + 1);
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
for (const arg of type.aliasTypeArguments ?? []) {
|
|
4677
|
+
registerReferencedTypes(arg, ctx, depth + 1);
|
|
4678
|
+
}
|
|
4679
|
+
const declared = declaredForm(type, checker);
|
|
4680
|
+
if (declared !== type) {
|
|
4681
|
+
registerReferencedTypes(declared, ctx, depth);
|
|
4682
|
+
return;
|
|
4683
|
+
}
|
|
4684
|
+
if (type.isUnion()) {
|
|
4685
|
+
for (const t of type.types) {
|
|
4686
|
+
registerReferencedTypes(t, ctx, depth + 1);
|
|
4687
|
+
}
|
|
4688
|
+
}
|
|
4689
|
+
if (type.isIntersection()) {
|
|
4690
|
+
for (const t of type.types) {
|
|
4691
|
+
registerReferencedTypes(t, ctx, depth + 1);
|
|
4692
|
+
}
|
|
4693
|
+
}
|
|
4694
|
+
const typeSymbol = type.aliasSymbol ?? type.getSymbol();
|
|
4695
|
+
if (typeSymbol && ctx.shouldExpandExternal && !typeSymbol.getName().startsWith("__") && !ctx.shouldExpandExternal(typeSymbol)) {
|
|
4696
|
+
return;
|
|
4697
|
+
}
|
|
4698
|
+
if (isForeignPackage(typeSymbol, ctx.workspacePackages)) {
|
|
4699
|
+
return;
|
|
4700
|
+
}
|
|
4701
|
+
if (isDeferredMappedOrConditional(type)) {
|
|
4702
|
+
return;
|
|
4703
|
+
}
|
|
4704
|
+
if (type.flags & ts7.TypeFlags.Object) {
|
|
4705
|
+
const props = type.getProperties();
|
|
4706
|
+
const limit = ctx.maxProperties;
|
|
4707
|
+
if (props.length > limit && ctx.onTruncation) {
|
|
4708
|
+
const typeName = type.getSymbol()?.getName() ?? "anonymous";
|
|
4709
|
+
ctx.onTruncation(typeName, props.length, limit);
|
|
4710
|
+
}
|
|
4711
|
+
for (const prop of props.slice(0, limit)) {
|
|
4712
|
+
const propType = checker.getTypeOfSymbol(prop);
|
|
4713
|
+
registerReferencedTypes(propType, ctx, depth + 1);
|
|
4714
|
+
}
|
|
4715
|
+
}
|
|
4716
|
+
}
|
|
4717
|
+
|
|
4577
4718
|
// src/serializers/context.ts
|
|
4719
|
+
import ts8 from "typescript";
|
|
4578
4720
|
function createContext(program, sourceFile, options = {}) {
|
|
4579
4721
|
return {
|
|
4580
4722
|
typeChecker: program.getTypeChecker(),
|
|
@@ -4594,9 +4736,12 @@ function createContext(program, sourceFile, options = {}) {
|
|
|
4594
4736
|
declIds: new Map,
|
|
4595
4737
|
idOwner: new Map,
|
|
4596
4738
|
workspacePackages: options.workspacePackages ?? new Map,
|
|
4739
|
+
budget: { owner: "", ops: 0, exceeded: false },
|
|
4740
|
+
maxBudgetOps: MAX_BUDGET_OPS,
|
|
4597
4741
|
schemaOps: 0,
|
|
4598
|
-
maxSchemaOps:
|
|
4599
|
-
budgetExceeded: false
|
|
4742
|
+
maxSchemaOps: MAX_SCHEMA_OPS,
|
|
4743
|
+
budgetExceeded: false,
|
|
4744
|
+
exhaustedBudgets: []
|
|
4600
4745
|
};
|
|
4601
4746
|
}
|
|
4602
4747
|
function getInheritedMembers(classType, ownMemberNames, ctx, isStatic = false) {
|
|
@@ -4662,7 +4807,7 @@ function getStaticMembers(classType, checker) {
|
|
|
4662
4807
|
});
|
|
4663
4808
|
}
|
|
4664
4809
|
function inheritedMethodSchema(symbol, type, ctx) {
|
|
4665
|
-
if (!ctx.
|
|
4810
|
+
if (!ctx.budget.exceeded) {
|
|
4666
4811
|
return decoratePropertySchema({ "x-ts-function": true }, symbol, type, ctx.typeChecker);
|
|
4667
4812
|
}
|
|
4668
4813
|
return {
|
|
@@ -4680,7 +4825,7 @@ function serializeInheritedMember(symbol, inheritedFrom, ctx, isStatic) {
|
|
|
4680
4825
|
const isOptional = !!(symbol.flags & ts8.SymbolFlags.Optional);
|
|
4681
4826
|
const rawType = checker.getTypeOfSymbol(symbol);
|
|
4682
4827
|
const type = isOptional ? stripUndefinedFromType(rawType, checker) : rawType;
|
|
4683
|
-
const registerTypes = !ctx.
|
|
4828
|
+
const registerTypes = !ctx.budget.exceeded;
|
|
4684
4829
|
if (registerTypes)
|
|
4685
4830
|
registerReferencedTypes(type, ctx);
|
|
4686
4831
|
let visibility;
|
|
@@ -4849,7 +4994,8 @@ function serializeClass(node, ctx) {
|
|
|
4849
4994
|
members.push(...inheritedInstance);
|
|
4850
4995
|
const inheritedStatic = getInheritedMembers(classType, ownMemberNames, ctx, true);
|
|
4851
4996
|
members.push(...inheritedStatic);
|
|
4852
|
-
const extendsClause =
|
|
4997
|
+
const extendsClause = getExtendsText(node, checker);
|
|
4998
|
+
const openArms = openHeritageArms([node], checker, ctx);
|
|
4853
4999
|
const implementsClause = getImplementsClause(node, checker);
|
|
4854
5000
|
const classFlags = {};
|
|
4855
5001
|
const classModifiers = ts10.getModifiers(node);
|
|
@@ -4867,6 +5013,7 @@ function serializeClass(node, ctx) {
|
|
|
4867
5013
|
members: members.length > 0 ? members : undefined,
|
|
4868
5014
|
signatures: signatures.length > 0 ? signatures : undefined,
|
|
4869
5015
|
extends: extendsClause,
|
|
5016
|
+
...openArms.length > 0 ? { schema: { allOf: openArms } } : {},
|
|
4870
5017
|
implements: implementsClause?.length ? implementsClause : undefined,
|
|
4871
5018
|
...deprecated ? { deprecated: true, deprecationReason } : {},
|
|
4872
5019
|
...examples.length > 0 ? { examples } : {},
|
|
@@ -4879,11 +5026,7 @@ function getMemberName(member) {
|
|
|
4879
5026
|
return "constructor";
|
|
4880
5027
|
if (!member.name)
|
|
4881
5028
|
return;
|
|
4882
|
-
|
|
4883
|
-
return member.name.text;
|
|
4884
|
-
if (ts10.isPrivateIdentifier(member.name))
|
|
4885
|
-
return member.name.text;
|
|
4886
|
-
return member.name.getText();
|
|
5029
|
+
return propertyNameText(member.name);
|
|
4887
5030
|
}
|
|
4888
5031
|
function getVisibility(member) {
|
|
4889
5032
|
const modifiers = ts10.canHaveModifiers(member) ? ts10.getModifiers(member) : undefined;
|
|
@@ -5085,21 +5228,6 @@ function serializeAccessor(node, ctx) {
|
|
|
5085
5228
|
...inlineTags ? { inlineTags } : {}
|
|
5086
5229
|
};
|
|
5087
5230
|
}
|
|
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
5231
|
function getImplementsClause(node, checker) {
|
|
5104
5232
|
if (!node.heritageClauses)
|
|
5105
5233
|
return;
|
|
@@ -5336,7 +5464,8 @@ function serializeInterface(node, ctx) {
|
|
|
5336
5464
|
const { description, tags, examples, source, deprecated, deprecationReason, inlineTags } = extractExportMetadata(node, symbol, checker);
|
|
5337
5465
|
const typeParameters = extractTypeParameters(node, checker);
|
|
5338
5466
|
const { members, callSignatureMember } = serializeTypeElements(node.members, ctx);
|
|
5339
|
-
const extendsClause =
|
|
5467
|
+
const extendsClause = getExtendsText(node, checker);
|
|
5468
|
+
const openArms = openHeritageArms([node], checker, ctx);
|
|
5340
5469
|
const exportSignatures = callSignatureMember?.signatures && callSignatureMember.signatures.length > 0 ? callSignatureMember.signatures : undefined;
|
|
5341
5470
|
return {
|
|
5342
5471
|
id: name,
|
|
@@ -5349,6 +5478,7 @@ function serializeInterface(node, ctx) {
|
|
|
5349
5478
|
members: members.length > 0 ? members : undefined,
|
|
5350
5479
|
signatures: exportSignatures,
|
|
5351
5480
|
extends: extendsClause,
|
|
5481
|
+
...openArms.length > 0 ? { schema: { allOf: openArms } } : {},
|
|
5352
5482
|
...deprecated ? { deprecated: true, deprecationReason } : {},
|
|
5353
5483
|
...examples.length > 0 ? { examples } : {},
|
|
5354
5484
|
...inlineTags ? { inlineTags } : {}
|
|
@@ -5438,7 +5568,7 @@ function serializeMergedTypeSide(symbol, ctx) {
|
|
|
5438
5568
|
const { description, tags } = getJSDocComment(typeDecl);
|
|
5439
5569
|
return {
|
|
5440
5570
|
members,
|
|
5441
|
-
extends: interfaces.map((decl) =>
|
|
5571
|
+
extends: interfaces.map((decl) => getExtendsText(decl, checker)).find(Boolean),
|
|
5442
5572
|
typeParameters: extractTypeParameters(typeDecl, checker),
|
|
5443
5573
|
description,
|
|
5444
5574
|
tags
|
|
@@ -5446,7 +5576,7 @@ function serializeMergedTypeSide(symbol, ctx) {
|
|
|
5446
5576
|
}
|
|
5447
5577
|
function serializePropertySignature(node, ctx) {
|
|
5448
5578
|
const { typeChecker: checker } = ctx;
|
|
5449
|
-
const name = node.name
|
|
5579
|
+
const name = propertyNameText(node.name);
|
|
5450
5580
|
const { description, tags, inlineTags } = getJSDocComment(node);
|
|
5451
5581
|
const rawType = checker.getTypeAtLocation(node);
|
|
5452
5582
|
const type = node.questionToken ? stripUndefinedFromType(rawType, checker) : rawType;
|
|
@@ -5476,7 +5606,7 @@ function serializePropertySignature(node, ctx) {
|
|
|
5476
5606
|
}
|
|
5477
5607
|
function serializeMethodSignature(node, ctx) {
|
|
5478
5608
|
const { typeChecker: checker } = ctx;
|
|
5479
|
-
const name = node.name
|
|
5609
|
+
const name = propertyNameText(node.name);
|
|
5480
5610
|
const { description, tags, inlineTags } = getJSDocComment(node);
|
|
5481
5611
|
const rawType = checker.getTypeAtLocation(node);
|
|
5482
5612
|
const type = node.questionToken ? stripUndefinedFromType(rawType, checker) : rawType;
|
|
@@ -5544,20 +5674,6 @@ function serializeIndexSignature(node, ctx) {
|
|
|
5544
5674
|
...inlineTags ? { inlineTags } : {}
|
|
5545
5675
|
};
|
|
5546
5676
|
}
|
|
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
5677
|
|
|
5562
5678
|
// src/serializers/type-aliases.ts
|
|
5563
5679
|
import ts13 from "typescript";
|
|
@@ -5602,7 +5718,7 @@ function serializeTypeAlias(node, ctx) {
|
|
|
5602
5718
|
schema = buildObjectSchema(type.getProperties(), ctx.typeChecker, ctx, type);
|
|
5603
5719
|
members = serializeResolvedMembers(type, node, ctx);
|
|
5604
5720
|
} else {
|
|
5605
|
-
schema =
|
|
5721
|
+
schema = buildAliasBodySchema(type, ctx.typeChecker, ctx);
|
|
5606
5722
|
if (isObjectShapedAlias(type, ctx)) {
|
|
5607
5723
|
members = serializeResolvedMembers(type, node, ctx);
|
|
5608
5724
|
}
|
|
@@ -6317,10 +6433,14 @@ function normalizeExport(exp, options = {}) {
|
|
|
6317
6433
|
result.members = exp.members.map((member) => normalizeMember(member, options));
|
|
6318
6434
|
}
|
|
6319
6435
|
if (!vendorSchema && shouldGenerateMembersSchema(exp.kind) && exp.members && exp.members.length > 0) {
|
|
6320
|
-
result.schema = normalizeMembers(exp.members, options);
|
|
6436
|
+
result.schema = withOpenArms(normalizeMembers(exp.members, options), result.schema);
|
|
6321
6437
|
}
|
|
6322
6438
|
return result;
|
|
6323
6439
|
}
|
|
6440
|
+
function withOpenArms(membersSchema, provided) {
|
|
6441
|
+
const arms = provided?.allOf;
|
|
6442
|
+
return Array.isArray(arms) ? { allOf: [membersSchema, ...arms] } : membersSchema;
|
|
6443
|
+
}
|
|
6324
6444
|
function normalizeType(type, options = {}) {
|
|
6325
6445
|
const result = { ...type };
|
|
6326
6446
|
if (type.schema) {
|
|
@@ -6330,7 +6450,7 @@ function normalizeType(type, options = {}) {
|
|
|
6330
6450
|
result.members = type.members.map((member) => normalizeMember(member, options));
|
|
6331
6451
|
}
|
|
6332
6452
|
if (shouldGenerateMembersSchema(type.kind) && type.members && type.members.length > 0) {
|
|
6333
|
-
result.schema = normalizeMembers(type.members, options);
|
|
6453
|
+
result.schema = withOpenArms(normalizeMembers(type.members, options), result.schema);
|
|
6334
6454
|
}
|
|
6335
6455
|
return result;
|
|
6336
6456
|
}
|
|
@@ -7708,6 +7828,11 @@ function expandReachableTypes(exportedSymbols, ctx, opts) {
|
|
|
7708
7828
|
visit(t, depth + 1);
|
|
7709
7829
|
}
|
|
7710
7830
|
}
|
|
7831
|
+
const declared = declaredForm(type, checker);
|
|
7832
|
+
if (declared !== type) {
|
|
7833
|
+
visit(declared, depth);
|
|
7834
|
+
return;
|
|
7835
|
+
}
|
|
7711
7836
|
if (!allowed || isDeferredMappedOrConditional(type) || !(type.flags & ts20.TypeFlags.Object || type.isClassOrInterface())) {
|
|
7712
7837
|
return;
|
|
7713
7838
|
}
|
|
@@ -7781,7 +7906,7 @@ function expandReachableTypes(exportedSymbols, ctx, opts) {
|
|
|
7781
7906
|
id,
|
|
7782
7907
|
name,
|
|
7783
7908
|
kind: symbolKind(symbol),
|
|
7784
|
-
schema: ensureNonEmptySchema(buildSchema(declared, checker, ctx, writtenWhenAny(symbol, declared)), declared, checker)
|
|
7909
|
+
schema: withExpansionBudget(ctx, `type ${id}`, () => ensureNonEmptySchema(buildSchema(declared, checker, ctx, writtenWhenAny(symbol, declared)), declared, checker))
|
|
7785
7910
|
});
|
|
7786
7911
|
}
|
|
7787
7912
|
symbolByName.set(name, symbol);
|
|
@@ -8231,7 +8356,7 @@ async function extract(options) {
|
|
|
8231
8356
|
}
|
|
8232
8357
|
continue;
|
|
8233
8358
|
}
|
|
8234
|
-
const exp = serializeDeclaration2(declaration, symbol, exportName, ctx, isTypeOnly);
|
|
8359
|
+
const exp = withExpansionBudget(ctx, exportName, () => serializeDeclaration2(declaration, symbol, exportName, ctx, isTypeOnly));
|
|
8235
8360
|
if (exp) {
|
|
8236
8361
|
const typeSide = mergedTypeSideOf(exp, declaration, targetSymbol, ctx);
|
|
8237
8362
|
if (typeSide) {
|
|
@@ -8260,7 +8385,7 @@ async function extract(options) {
|
|
|
8260
8385
|
}
|
|
8261
8386
|
}
|
|
8262
8387
|
for (const { index, symbol, ontoClass } of mergedTypeSides) {
|
|
8263
|
-
exports[index] = withMergedTypeSide(exports[index], symbol, ctx, ontoClass);
|
|
8388
|
+
exports[index] = withExpansionBudget(ctx, exports[index].name, () => withMergedTypeSide(exports[index], symbol, ctx, ontoClass));
|
|
8264
8389
|
}
|
|
8265
8390
|
const verification = buildVerificationSummary(exportedSymbols.length, exports.length, exportTracker);
|
|
8266
8391
|
const meta = await getPackageMeta(entryFile, baseDir);
|
|
@@ -8271,7 +8396,7 @@ async function extract(options) {
|
|
|
8271
8396
|
});
|
|
8272
8397
|
if (ctx.budgetExceeded) {
|
|
8273
8398
|
diagnostics.push({
|
|
8274
|
-
message:
|
|
8399
|
+
message: `Stopped expanding some types after hitting the schema expansion budget${exhaustedBudgetNote(ctx)}`,
|
|
8275
8400
|
severity: "warning",
|
|
8276
8401
|
code: "TYPE_EXPANSION_LIMIT"
|
|
8277
8402
|
});
|
|
@@ -8751,6 +8876,13 @@ function withMergedTypeSide(entry, symbol, ctx, ontoClass) {
|
|
|
8751
8876
|
...entry.description ? {} : { description, tags: [...entry.tags ?? [], ...tags ?? []] }
|
|
8752
8877
|
};
|
|
8753
8878
|
}
|
|
8879
|
+
function exhaustedBudgetNote(ctx) {
|
|
8880
|
+
const owners = [...new Set(ctx.exhaustedBudgets)];
|
|
8881
|
+
if (owners.length === 0)
|
|
8882
|
+
return "";
|
|
8883
|
+
const shown = owners.slice(0, 10).join(", ");
|
|
8884
|
+
return `: ${shown}${owners.length > 10 ? ` (+${owners.length - 10} more)` : ""}`;
|
|
8885
|
+
}
|
|
8754
8886
|
function withExportName(entry, exportName) {
|
|
8755
8887
|
if (entry.name === exportName) {
|
|
8756
8888
|
return entry;
|
|
@@ -9322,6 +9454,7 @@ function getNodeName(node) {
|
|
|
9322
9454
|
export {
|
|
9323
9455
|
zodAdapter,
|
|
9324
9456
|
writtenTypeText,
|
|
9457
|
+
withOpenHeritage,
|
|
9325
9458
|
withDescription,
|
|
9326
9459
|
withDeprecated,
|
|
9327
9460
|
validateSpec2 as validateSpec,
|
|
@@ -9367,6 +9500,7 @@ export {
|
|
|
9367
9500
|
query,
|
|
9368
9501
|
pickEntry,
|
|
9369
9502
|
parseGithubRepo,
|
|
9503
|
+
openHeritageArms,
|
|
9370
9504
|
normalizeType,
|
|
9371
9505
|
normalizeSchema,
|
|
9372
9506
|
normalizeMembers,
|
|
@@ -9448,6 +9582,7 @@ export {
|
|
|
9448
9582
|
buildSchema,
|
|
9449
9583
|
buildObjectSchema,
|
|
9450
9584
|
buildFunctionSchema,
|
|
9585
|
+
buildAliasBodySchema,
|
|
9451
9586
|
assertSpec,
|
|
9452
9587
|
asStandardSchema,
|
|
9453
9588
|
arktypeAdapter,
|