@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 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
- /** Structural schema-build steps taken this extract. */
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
- /** Cap on schema-build steps; past this, emit x-ts-type text. */
1263
+ /** Safety ceiling on schemaOps against runaway expansion; past this, everything emits text. */
1248
1264
  maxSchemaOps: number;
1249
- /** True once schemaOps exceeded maxSchemaOps. */
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
- return checker.getAliasedSymbol(symbol);
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
- if (ts5.isTypeReferenceNode(node)) {
2873
- const raw = checker.getSymbolAtLocation(ts5.isQualifiedName(node.typeName) ? node.typeName.right : node.typeName);
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() ?? node.typeName.getText();
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
- return args.some((t) => containsUnresolvedTypeParameter(t));
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
- if (ctx.schemaOps > ctx.maxSchemaOps) {
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
- if (!name.startsWith("__")) {
3717
- const packageOrigin = getTypeOrigin(type, checker);
3718
- if (ctx) {
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 & ts7.SymbolFlags.EnumMember)
4246
+ if (symbol.flags & ts6.SymbolFlags.EnumMember)
4326
4247
  return;
4327
- if (symbol.flags & ts7.SymbolFlags.TypeParameter)
4248
+ if (symbol.flags & ts6.SymbolFlags.TypeParameter)
4328
4249
  return;
4329
- if (symbol.flags & ts7.SymbolFlags.Method)
4250
+ if (symbol.flags & ts6.SymbolFlags.Method)
4330
4251
  return;
4331
- if (symbol.flags & ts7.SymbolFlags.Function)
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 (ts7.isClassDeclaration(decl))
4302
+ if (ts6.isClassDeclaration(decl))
4382
4303
  kind = "class";
4383
- else if (ts7.isInterfaceDeclaration(decl))
4304
+ else if (ts6.isInterfaceDeclaration(decl))
4384
4305
  kind = "interface";
4385
- else if (ts7.isEnumDeclaration(decl))
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 = buildSchema(type, checker, ctx);
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 && ts7.isTypeAliasDeclaration(decl) && shouldEmitAliasTypeText(decl.type) && typeof schema === "object" && schema !== null && !("x-ts-type" in schema)) {
4402
- const text = renderTypeText(type, checker, decl, ts7.TypeFormatFlags.InTypeAlias);
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 && (ts7.isTypeAliasDeclaration(decl) || ts7.isInterfaceDeclaration(decl) || ts7.isClassDeclaration(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 & ts7.TypeFlags.StringLiteral);
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 & ts7.TypeFlags.NumberLiteral);
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 & ts7.TypeFlags.Conditional) {
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 & ts7.TypeFlags.StringLike ? "string" : constraint && constraint.flags & ts7.TypeFlags.NumberLike ? "number" : constraint && constraint.flags & ts7.TypeFlags.BooleanLike ? "boolean" : undefined;
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(ts7.isEnumDeclaration);
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 & ts7.TypeFlags.String);
4514
- const numberIndex = indexInfos.find((i) => i.keyType.flags & ts7.TypeFlags.Number);
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 & ts7.TypeFlags.StringLike;
4523
- const isNumberLike = type.flags & ts7.TypeFlags.NumberLike;
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 & ts7.SymbolFlags.Optional ? stripUndefinedFromType(rawPropType, checker) : rawPropType;
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 & ts7.SymbolFlags.Optional)) {
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: 20000,
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.budgetExceeded) {
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.budgetExceeded;
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 = getExtendsClause(node, checker);
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
- if (ts10.isIdentifier(member.name))
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 = getInterfaceExtends(node, checker);
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) => getInterfaceExtends(decl, checker)).find(Boolean),
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.getText();
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.getText();
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 = buildSchema(type, ctx.typeChecker, ctx);
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: "Stopped expanding some types after hitting the schema expansion budget",
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openpkg-ts/sdk",
3
- "version": "0.54.9",
3
+ "version": "0.54.11",
4
4
  "description": "TypeScript API extraction SDK - programmatic primitives for OpenPkg specs",
5
5
  "keywords": [
6
6
  "openpkg",