@openpkg-ts/sdk 0.54.9 → 0.54.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts 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;
@@ -3318,7 +3393,12 @@ function isUtilityOverTypeParameter(type) {
3318
3393
  const args = type.aliasTypeArguments;
3319
3394
  if (!args || args.length === 0)
3320
3395
  return false;
3321
- return args.some((t) => containsUnresolvedTypeParameter(t));
3396
+ if (!args.some((t) => containsUnresolvedTypeParameter(t)))
3397
+ return false;
3398
+ if (args[0].flags & ts5.TypeFlags.TypeParameter || !(type.flags & ts5.TypeFlags.Object)) {
3399
+ return true;
3400
+ }
3401
+ return type.getProperties().length === 0;
3322
3402
  }
3323
3403
  function writtenUtilityText(type, checker, typeNode) {
3324
3404
  let node = typeNode;
@@ -3398,6 +3478,14 @@ function buildSchema(type, checker, ctx, typeNode) {
3398
3478
  const schema = buildSchemaInternal(type, checker, ctx, typeNode);
3399
3479
  return ensureNonEmptySchema(schema, type, checker);
3400
3480
  }
3481
+ function buildAliasBodySchema(type, checker, ctx) {
3482
+ ctx.aliasBody = type;
3483
+ try {
3484
+ return buildSchema(type, checker, ctx);
3485
+ } finally {
3486
+ ctx.aliasBody = undefined;
3487
+ }
3488
+ }
3401
3489
  function buildMaxDepthSchema(type, checker, typeNode, ctx) {
3402
3490
  if (type.flags & ts5.TypeFlags.Any) {
3403
3491
  if (typeNode)
@@ -3446,13 +3534,44 @@ function buildMaxDepthSchema(type, checker, typeNode, ctx) {
3446
3534
  }
3447
3535
  return { type: checker.typeToString(type) };
3448
3536
  }
3537
+ function writtenTypeArguments(typeNode, symbol, checker) {
3538
+ if (!typeNode || !symbol || !ts5.isTypeReferenceNode(typeNode) || !typeNode.typeArguments) {
3539
+ return;
3540
+ }
3541
+ const name = ts5.isQualifiedName(typeNode.typeName) ? typeNode.typeName.right : typeNode.typeName;
3542
+ const written = resolvedSymbol(checker.getSymbolAtLocation(name), checker);
3543
+ return written === symbol ? typeNode.typeArguments : undefined;
3544
+ }
3545
+ function genericAliasRef(type, checker, ctx, typeNode) {
3546
+ const aliasTypeArgs = type.aliasTypeArguments;
3547
+ const name = type.aliasSymbol?.getName();
3548
+ if (!name || !aliasTypeArgs?.length)
3549
+ return;
3550
+ if (name.startsWith("__") || BUILTIN_TYPES.has(name) || isBuiltinGeneric(name))
3551
+ return;
3552
+ const argNodes = writtenTypeArguments(typeNode, type.aliasSymbol, checker);
3553
+ const build = () => {
3554
+ const schema = {
3555
+ $ref: `#/types/${namedRefId(type, name, ctx)}`,
3556
+ typeArguments: aliasTypeArgs.map((t, i) => buildSchema(t, checker, ctx, argNodes?.[i]))
3557
+ };
3558
+ const packageOrigin = getTypeOrigin(type, checker);
3559
+ if (packageOrigin) {
3560
+ setSchemaExtension(schema, "x-ts-package", packageOrigin);
3561
+ }
3562
+ return schema;
3563
+ };
3564
+ return ctx ? withDepth(ctx, build) : build();
3565
+ }
3449
3566
  function buildSchemaInternal(type, checker, ctx, typeNode) {
3450
3567
  if (isAtMaxDepth(ctx)) {
3451
3568
  return buildMaxDepthSchema(type, checker, typeNode, ctx);
3452
3569
  }
3453
3570
  if (ctx) {
3454
3571
  ctx.schemaOps += 1;
3455
- if (ctx.schemaOps > ctx.maxSchemaOps) {
3572
+ ctx.budget.ops += 1;
3573
+ if (ctx.budget.ops > ctx.maxBudgetOps || ctx.schemaOps > ctx.maxSchemaOps) {
3574
+ ctx.budget.exceeded = true;
3456
3575
  ctx.budgetExceeded = true;
3457
3576
  return { "x-ts-type": cheapTypeText(type, checker, typeNode) };
3458
3577
  }
@@ -3546,6 +3665,14 @@ function buildSchemaInternal(type, checker, ctx, typeNode) {
3546
3665
  return schema;
3547
3666
  }
3548
3667
  }
3668
+ if (type.isUnion() || type.isIntersection()) {
3669
+ const ownBody = ctx?.aliasBody === type;
3670
+ if (ownBody && ctx)
3671
+ ctx.aliasBody = undefined;
3672
+ const aliasRef = ownBody ? undefined : genericAliasRef(type, checker, ctx, typeNode);
3673
+ if (aliasRef)
3674
+ return aliasRef;
3675
+ }
3549
3676
  if (type.flags & ts5.TypeFlags.TemplateLiteral) {
3550
3677
  return {
3551
3678
  type: "string",
@@ -3670,11 +3797,12 @@ function buildSchemaInternal(type, checker, ctx, typeNode) {
3670
3797
  }
3671
3798
  if (name && !isAnonymous(typeRef.target)) {
3672
3799
  const packageOrigin = getTypeOrigin(typeRef.target, checker);
3800
+ const argNodes = writtenTypeArguments(typeNode, symbol2, checker);
3673
3801
  if (ctx) {
3674
3802
  return withDepth(ctx, () => {
3675
3803
  const schema2 = {
3676
3804
  $ref: `#/types/${namedRefId(typeRef.target, name, ctx)}`,
3677
- typeArguments: typeArgs.map((t) => buildSchema(t, checker, ctx))
3805
+ typeArguments: typeArgs.map((t, i) => buildSchema(t, checker, ctx, argNodes?.[i]))
3678
3806
  };
3679
3807
  if (packageOrigin) {
3680
3808
  setSchemaExtension(schema2, "x-ts-package", packageOrigin);
@@ -3713,29 +3841,9 @@ function buildSchemaInternal(type, checker, ctx, typeNode) {
3713
3841
  });
3714
3842
  return ctx ? withDepth(ctx, build) : build();
3715
3843
  }
3716
- 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
- }
3844
+ const aliasRef = genericAliasRef(type, checker, ctx, typeNode);
3845
+ if (aliasRef)
3846
+ return aliasRef;
3739
3847
  }
3740
3848
  if (type.flags & ts5.TypeFlags.Object) {
3741
3849
  const callSignatures = type.getCallSignatures();
@@ -4000,219 +4108,7 @@ function findDiscriminatorProperty(unionTypes, checker) {
4000
4108
  return;
4001
4109
  }
4002
4110
 
4003
- // src/types/parameters.ts
4004
- function extractParameters(signature, ctx) {
4005
- const { typeChecker: checker } = ctx;
4006
- const result = [];
4007
- const signatureDecl = signature.getDeclaration();
4008
- const jsdocTags = signatureDecl ? ts6.getJSDocTags(signatureDecl) : [];
4009
- for (const param of signature.getParameters()) {
4010
- const decl = param.valueDeclaration;
4011
- if (!decl)
4012
- continue;
4013
- const defer = typeNodeDefersExpansion(decl.type, checker, ctx.program);
4014
- const type = defer ? undefined : checker.getTypeOfSymbolAtLocation(param, decl);
4015
- if (decl && ts6.isObjectBindingPattern(decl.name)) {
4016
- const expandedParams = expandBindingPattern(decl, type ?? checker.getTypeOfSymbolAtLocation(param, decl), jsdocTags, ctx);
4017
- result.push(...expandedParams);
4018
- } else {
4019
- const isOptional = !!decl?.questionToken || !!decl?.initializer;
4020
- const isRest = !!decl.dotDotDotToken;
4021
- const paramName = param.getName();
4022
- const description = getParamDescription(paramName, jsdocTags);
4023
- const schema = defer ? buildSchemaFromTypeNode(decl.type, checker, ctx) : buildSchema(isOptional ? stripUndefinedFromType(type, checker) : type, checker, ctx, decl.type);
4024
- if (!defer && type) {
4025
- registerReferencedTypes(isOptional ? stripUndefinedFromType(type, checker) : type, ctx);
4026
- }
4027
- const paramResult = {
4028
- name: paramName,
4029
- schema,
4030
- required: !isOptional && !isRest,
4031
- ...isRest ? { rest: true } : {}
4032
- };
4033
- if (description) {
4034
- paramResult.description = description;
4035
- const inlineTags = parseInlineTags(description);
4036
- if (inlineTags)
4037
- paramResult.inlineTags = inlineTags;
4038
- }
4039
- if (decl.initializer) {
4040
- applyDefault(paramResult, decl.initializer);
4041
- }
4042
- result.push(paramResult);
4043
- }
4044
- }
4045
- return result;
4046
- }
4047
- function expandBindingPattern(paramDecl, paramType, jsdocTags, ctx) {
4048
- const { typeChecker: checker } = ctx;
4049
- const result = [];
4050
- const bindingPattern = paramDecl.name;
4051
- const allProperties = getEffectiveProperties(paramType, checker);
4052
- const inferredAlias = inferParamAlias(jsdocTags);
4053
- for (const element of bindingPattern.elements) {
4054
- if (!ts6.isBindingElement(element))
4055
- continue;
4056
- const propertyName = element.propertyName ? ts6.isIdentifier(element.propertyName) ? element.propertyName.text : element.propertyName.getText() : ts6.isIdentifier(element.name) ? element.name.text : element.name.getText();
4057
- const propSymbol = allProperties.get(propertyName);
4058
- if (!propSymbol)
4059
- continue;
4060
- const isOptional = !!(propSymbol.flags & ts6.SymbolFlags.Optional) || element.initializer !== undefined;
4061
- const propType = checker.getTypeOfSymbol(propSymbol);
4062
- const effectiveType = isOptional ? stripUndefinedFromType(propType, checker) : propType;
4063
- registerReferencedTypes(effectiveType, ctx);
4064
- const description = getParamDescription(propertyName, jsdocTags, inferredAlias);
4065
- const param = {
4066
- name: propertyName,
4067
- schema: buildSchema(effectiveType, checker, ctx, declaredTypeNode(propSymbol.valueDeclaration)),
4068
- required: !isOptional
4069
- };
4070
- if (description) {
4071
- param.description = description;
4072
- const inlineTags = parseInlineTags(description);
4073
- if (inlineTags)
4074
- param.inlineTags = inlineTags;
4075
- }
4076
- if (element.initializer) {
4077
- applyDefault(param, element.initializer);
4078
- }
4079
- result.push(param);
4080
- }
4081
- return result;
4082
- }
4083
- function getEffectiveProperties(type, _checker) {
4084
- const properties = new Map;
4085
- if (type.isIntersection()) {
4086
- for (const subType of type.types) {
4087
- for (const prop of subType.getProperties()) {
4088
- properties.set(prop.getName(), prop);
4089
- }
4090
- }
4091
- } else {
4092
- for (const prop of type.getProperties()) {
4093
- properties.set(prop.getName(), prop);
4094
- }
4095
- }
4096
- return properties;
4097
- }
4098
- function inferParamAlias(jsdocTags) {
4099
- const prefixes = [];
4100
- for (const tag of jsdocTags) {
4101
- if (tag.tagName.text !== "param")
4102
- continue;
4103
- const tagText = typeof tag.comment === "string" ? tag.comment : ts6.getTextOfJSDocComment(tag.comment) ?? "";
4104
- const paramTag = tag;
4105
- const paramName = paramTag.name?.getText() ?? "";
4106
- if (paramName.includes(".")) {
4107
- const prefix = paramName.split(".")[0];
4108
- if (prefix && !prefix.startsWith("__")) {
4109
- prefixes.push(prefix);
4110
- }
4111
- } else if (tagText.includes(".")) {
4112
- const match = tagText.match(/^(\w+)\./);
4113
- if (match && !match[1].startsWith("__")) {
4114
- prefixes.push(match[1]);
4115
- }
4116
- }
4117
- }
4118
- if (prefixes.length === 0)
4119
- return;
4120
- const counts = new Map;
4121
- for (const p of prefixes)
4122
- counts.set(p, (counts.get(p) ?? 0) + 1);
4123
- return Array.from(counts.entries()).sort((a, b) => b[1] - a[1])[0]?.[0];
4124
- }
4125
- function extractLiteralDefault(initializer) {
4126
- if (ts6.isStringLiteral(initializer)) {
4127
- return { literal: true, value: initializer.text };
4128
- }
4129
- if (ts6.isNumericLiteral(initializer)) {
4130
- return { literal: true, value: Number(initializer.text) };
4131
- }
4132
- if (ts6.isPrefixUnaryExpression(initializer) && initializer.operator === ts6.SyntaxKind.MinusToken && ts6.isNumericLiteral(initializer.operand)) {
4133
- return { literal: true, value: -Number(initializer.operand.text) };
4134
- }
4135
- if (initializer.kind === ts6.SyntaxKind.TrueKeyword) {
4136
- return { literal: true, value: true };
4137
- }
4138
- if (initializer.kind === ts6.SyntaxKind.FalseKeyword) {
4139
- return { literal: true, value: false };
4140
- }
4141
- if (initializer.kind === ts6.SyntaxKind.NullKeyword) {
4142
- return { literal: true, value: null };
4143
- }
4144
- return { literal: false, text: initializer.getText() };
4145
- }
4146
- function applyDefault(param, initializer) {
4147
- const extracted = extractLiteralDefault(initializer);
4148
- if (extracted.literal) {
4149
- param.default = extracted.value;
4150
- if (param.schema && typeof param.schema === "object" && !Array.isArray(param.schema)) {
4151
- param.schema.default = extracted.value;
4152
- }
4153
- } else {
4154
- param.default = extracted.text;
4155
- if (param.schema && typeof param.schema === "object" && !Array.isArray(param.schema)) {
4156
- param.schema["x-ts-default"] = extracted.text;
4157
- }
4158
- }
4159
- }
4160
- function registerReferencedTypes(type, ctx, depth = 0) {
4161
- if (depth > ctx.maxTypeDepth)
4162
- return;
4163
- if (ctx.registeredTypes.has(type))
4164
- return;
4165
- const isPrimitive = type.flags & (ts6.TypeFlags.String | ts6.TypeFlags.Number | ts6.TypeFlags.Boolean | ts6.TypeFlags.Void | ts6.TypeFlags.Undefined | ts6.TypeFlags.Null | ts6.TypeFlags.Any | ts6.TypeFlags.Unknown | ts6.TypeFlags.Never | ts6.TypeFlags.StringLiteral | ts6.TypeFlags.NumberLiteral | ts6.TypeFlags.BooleanLiteral);
4166
- if (!isPrimitive) {
4167
- ctx.registeredTypes.add(type);
4168
- }
4169
- const { typeChecker: checker, typeRegistry } = ctx;
4170
- typeRegistry.registerType(type, ctx);
4171
- const typeArgs = type.typeArguments;
4172
- if (typeArgs) {
4173
- for (const arg of typeArgs) {
4174
- registerReferencedTypes(arg, ctx, depth + 1);
4175
- }
4176
- }
4177
- if (type.isUnion()) {
4178
- for (const t of type.types) {
4179
- registerReferencedTypes(t, ctx, depth + 1);
4180
- }
4181
- }
4182
- if (type.isIntersection()) {
4183
- for (const t of type.types) {
4184
- registerReferencedTypes(t, ctx, depth + 1);
4185
- }
4186
- }
4187
- const typeSymbol = type.aliasSymbol ?? type.getSymbol();
4188
- if (typeSymbol && ctx.shouldExpandExternal && !typeSymbol.getName().startsWith("__") && !ctx.shouldExpandExternal(typeSymbol)) {
4189
- return;
4190
- }
4191
- if (isForeignPackage(typeSymbol, ctx.workspacePackages)) {
4192
- return;
4193
- }
4194
- if (isDeferredMappedOrConditional(type)) {
4195
- return;
4196
- }
4197
- if (type.flags & ts6.TypeFlags.Object) {
4198
- const props = type.getProperties();
4199
- const limit = ctx.maxProperties;
4200
- if (props.length > limit && ctx.onTruncation) {
4201
- const typeName = type.getSymbol()?.getName() ?? "anonymous";
4202
- ctx.onTruncation(typeName, props.length, limit);
4203
- }
4204
- for (const prop of props.slice(0, limit)) {
4205
- const propType = checker.getTypeOfSymbol(prop);
4206
- registerReferencedTypes(propType, ctx, depth + 1);
4207
- }
4208
- }
4209
- }
4210
-
4211
- // src/serializers/context.ts
4212
- import ts8 from "typescript";
4213
-
4214
4111
  // src/ast/registry.ts
4215
- import ts7 from "typescript";
4216
4112
  var BUILTINS = new Set([
4217
4113
  "Array",
4218
4114
  "ArrayBuffer",
@@ -4289,6 +4185,26 @@ function isExternalType(decl) {
4289
4185
  return false;
4290
4186
  return sourceFile.fileName.includes("node_modules");
4291
4187
  }
4188
+ function declaredForm(type, checker, symbol = type.aliasSymbol ?? type.getSymbol()) {
4189
+ if (!symbol)
4190
+ return type;
4191
+ const generic = ts6.SymbolFlags.TypeAlias | ts6.SymbolFlags.Interface | ts6.SymbolFlags.Class;
4192
+ if (!(symbol.flags & generic))
4193
+ return type;
4194
+ const target = type.target;
4195
+ const instantiated = type.aliasTypeArguments?.length || target && target !== type;
4196
+ return instantiated ? declaredTypeOf(symbol, type, checker) : type;
4197
+ }
4198
+ function declaredTypeOf(symbol, fallback, checker) {
4199
+ const declared = checker.getDeclaredTypeOfSymbol(symbol);
4200
+ return declared.flags & ts6.TypeFlags.Any ? fallback : declared;
4201
+ }
4202
+ function registeredForm(type, symbol, checker) {
4203
+ const constructorSide = symbol.flags & ts6.SymbolFlags.Class && type.objectFlags & ts6.ObjectFlags.Anonymous;
4204
+ if (constructorSide)
4205
+ return declaredTypeOf(symbol, type, checker);
4206
+ return declaredForm(type, checker, symbol);
4207
+ }
4292
4208
 
4293
4209
  class TypeRegistry {
4294
4210
  types = new Map;
@@ -4322,13 +4238,13 @@ class TypeRegistry {
4322
4238
  return;
4323
4239
  if (name.startsWith('"'))
4324
4240
  return;
4325
- if (symbol.flags & ts7.SymbolFlags.EnumMember)
4241
+ if (symbol.flags & ts6.SymbolFlags.EnumMember)
4326
4242
  return;
4327
- if (symbol.flags & ts7.SymbolFlags.TypeParameter)
4243
+ if (symbol.flags & ts6.SymbolFlags.TypeParameter)
4328
4244
  return;
4329
- if (symbol.flags & ts7.SymbolFlags.Method)
4245
+ if (symbol.flags & ts6.SymbolFlags.Method)
4330
4246
  return;
4331
- if (symbol.flags & ts7.SymbolFlags.Function)
4247
+ if (symbol.flags & ts6.SymbolFlags.Function)
4332
4248
  return;
4333
4249
  if (isGenericTypeParameter(name))
4334
4250
  return;
@@ -4361,7 +4277,7 @@ class TypeRegistry {
4361
4277
  return id;
4362
4278
  this.processing.add(id);
4363
4279
  try {
4364
- const specType = this.buildSpecType(type, symbol, id, ctx);
4280
+ const specType = withExpansionBudget(ctx, `type ${id}`, () => this.buildSpecType(registeredForm(type, symbol, ctx.typeChecker), symbol, id, ctx));
4365
4281
  if (specType) {
4366
4282
  this.add(specType);
4367
4283
  return specType.id;
@@ -4378,17 +4294,17 @@ class TypeRegistry {
4378
4294
  let kind = "type";
4379
4295
  const external = decl ? isExternalType(decl) : false;
4380
4296
  if (decl) {
4381
- if (ts7.isClassDeclaration(decl))
4297
+ if (ts6.isClassDeclaration(decl))
4382
4298
  kind = "class";
4383
- else if (ts7.isInterfaceDeclaration(decl))
4299
+ else if (ts6.isInterfaceDeclaration(decl))
4384
4300
  kind = "interface";
4385
- else if (ts7.isEnumDeclaration(decl))
4301
+ else if (ts6.isEnumDeclaration(decl))
4386
4302
  kind = "enum";
4387
4303
  }
4388
4304
  if (external) {
4389
4305
  kind = "external";
4390
4306
  }
4391
- let schema = buildSchema(type, checker, ctx);
4307
+ let schema = buildAliasBodySchema(type, checker, ctx);
4392
4308
  if (this.isSelfRef(schema, id)) {
4393
4309
  schema = this.resolveSelRefSchema(type, checker, ctx);
4394
4310
  }
@@ -4398,8 +4314,8 @@ class TypeRegistry {
4398
4314
  schema = enumSchema;
4399
4315
  }
4400
4316
  }
4401
- if (kind === "type" && decl && 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);
4317
+ if (kind === "type" && decl && ts6.isTypeAliasDeclaration(decl) && shouldEmitAliasTypeText(decl.type) && typeof schema === "object" && schema !== null && !("x-ts-type" in schema)) {
4318
+ const text = renderTypeText(type, checker, decl, ts6.TypeFormatFlags.InTypeAlias);
4403
4319
  if (!PRIMITIVES.has(text) && text !== name) {
4404
4320
  schema["x-ts-type"] = text;
4405
4321
  const declared = writtenTypeText(declaredTypeNode(decl));
@@ -4408,8 +4324,11 @@ class TypeRegistry {
4408
4324
  }
4409
4325
  }
4410
4326
  }
4327
+ const heritage = (symbol.declarations ?? []).filter((d) => ts6.isClassDeclaration(d) || ts6.isInterfaceDeclaration(d));
4328
+ const extendsText = heritage.map((d) => getExtendsText(d, checker)).find(Boolean);
4329
+ schema = withOpenHeritage(schema, openHeritageArms(heritage, checker, ctx));
4411
4330
  let typeParameters;
4412
- if (decl && (ts7.isTypeAliasDeclaration(decl) || ts7.isInterfaceDeclaration(decl) || ts7.isClassDeclaration(decl))) {
4331
+ if (decl && (ts6.isTypeAliasDeclaration(decl) || ts6.isInterfaceDeclaration(decl) || ts6.isClassDeclaration(decl))) {
4413
4332
  typeParameters = extractTypeParameters(decl, checker);
4414
4333
  }
4415
4334
  return {
@@ -4418,6 +4337,7 @@ class TypeRegistry {
4418
4337
  kind,
4419
4338
  ...typeParameters && typeParameters.length > 0 ? { typeParameters } : {},
4420
4339
  schema,
4340
+ ...extendsText ? { extends: extendsText } : {},
4421
4341
  ...external ? { external: true } : {}
4422
4342
  };
4423
4343
  }
@@ -4430,14 +4350,14 @@ class TypeRegistry {
4430
4350
  resolveSelRefSchema(type, checker, ctx) {
4431
4351
  if (type.isUnion()) {
4432
4352
  const types = type.types;
4433
- const allStringLiterals = types.every((t) => t.flags & ts7.TypeFlags.StringLiteral);
4353
+ const allStringLiterals = types.every((t) => t.flags & ts6.TypeFlags.StringLiteral);
4434
4354
  if (allStringLiterals) {
4435
4355
  return {
4436
4356
  type: "string",
4437
4357
  enum: types.map((t) => t.value)
4438
4358
  };
4439
4359
  }
4440
- const allNumberLiterals = types.every((t) => t.flags & ts7.TypeFlags.NumberLiteral);
4360
+ const allNumberLiterals = types.every((t) => t.flags & ts6.TypeFlags.NumberLiteral);
4441
4361
  if (allNumberLiterals) {
4442
4362
  return {
4443
4363
  type: "number",
@@ -4472,18 +4392,18 @@ class TypeRegistry {
4472
4392
  const elementType = checker.getTypeArguments(type)?.[0];
4473
4393
  return elementType ? { type: "array", items: buildSchema(elementType, checker, ctx) } : { type: "array" };
4474
4394
  }
4475
- if (type.flags & ts7.TypeFlags.Conditional) {
4395
+ if (type.flags & ts6.TypeFlags.Conditional) {
4476
4396
  return { "x-ts-type": renderTypeText(type, checker) };
4477
4397
  }
4478
4398
  const constraint = checker.getBaseConstraintOfType(type);
4479
- const primitive = constraint && constraint.flags & ts7.TypeFlags.StringLike ? "string" : constraint && constraint.flags & ts7.TypeFlags.NumberLike ? "number" : constraint && constraint.flags & ts7.TypeFlags.BooleanLike ? "boolean" : undefined;
4399
+ const primitive = constraint && constraint.flags & ts6.TypeFlags.StringLike ? "string" : constraint && constraint.flags & ts6.TypeFlags.NumberLike ? "number" : constraint && constraint.flags & ts6.TypeFlags.BooleanLike ? "boolean" : undefined;
4480
4400
  if (primitive) {
4481
4401
  return { type: primitive, "x-ts-type": renderTypeText(type, checker) };
4482
4402
  }
4483
4403
  return this.buildObjectSchemaFromProperties(type, checker, ctx);
4484
4404
  }
4485
4405
  buildEnumSchema(symbol, checker) {
4486
- const decl = symbol.declarations?.find(ts7.isEnumDeclaration);
4406
+ const decl = symbol.declarations?.find(ts6.isEnumDeclaration);
4487
4407
  if (!decl)
4488
4408
  return;
4489
4409
  const members = [];
@@ -4510,8 +4430,8 @@ class TypeRegistry {
4510
4430
  buildObjectSchemaFromProperties(type, checker, ctx) {
4511
4431
  const properties = type.getProperties();
4512
4432
  const indexInfos = checker.getIndexInfosOfType(type);
4513
- const stringIndex = indexInfos.find((i) => i.keyType.flags & ts7.TypeFlags.String);
4514
- const numberIndex = indexInfos.find((i) => i.keyType.flags & ts7.TypeFlags.Number);
4433
+ const stringIndex = indexInfos.find((i) => i.keyType.flags & ts6.TypeFlags.String);
4434
+ const numberIndex = indexInfos.find((i) => i.keyType.flags & ts6.TypeFlags.Number);
4515
4435
  if (properties.length === 0 && !stringIndex && !numberIndex) {
4516
4436
  return { type: checker.typeToString(type) };
4517
4437
  }
@@ -4519,8 +4439,8 @@ class TypeRegistry {
4519
4439
  const required = [];
4520
4440
  const limit = ctx.maxProperties;
4521
4441
  const isArrayLike = checker.isArrayType(type) || checker.isTupleType(type) || type.symbol?.getName() === "Array" && isLibFile(type.symbol?.getDeclarations()?.[0]?.getSourceFile()?.fileName ?? "");
4522
- const isStringLike = type.flags & ts7.TypeFlags.StringLike;
4523
- const isNumberLike = type.flags & ts7.TypeFlags.NumberLike;
4442
+ const isStringLike = type.flags & ts6.TypeFlags.StringLike;
4443
+ const isNumberLike = type.flags & ts6.TypeFlags.NumberLike;
4524
4444
  const included = properties.filter((prop) => {
4525
4445
  const propName = prop.getName();
4526
4446
  if (propName.startsWith("__@"))
@@ -4540,7 +4460,7 @@ class TypeRegistry {
4540
4460
  for (const prop of included.slice(0, limit)) {
4541
4461
  const propName = prop.getName();
4542
4462
  const rawPropType = checker.getTypeOfSymbol(prop);
4543
- const propType = prop.flags & ts7.SymbolFlags.Optional ? stripUndefinedFromType(rawPropType, checker) : rawPropType;
4463
+ const propType = prop.flags & ts6.SymbolFlags.Optional ? stripUndefinedFromType(rawPropType, checker) : rawPropType;
4544
4464
  this.registerType(propType, ctx);
4545
4465
  let propSchema = buildSchema(propType, checker, ctx, declaredTypeNode(prop.valueDeclaration ?? prop.getDeclarations()?.[0]));
4546
4466
  const docComment = prop.getDocumentationComment(checker);
@@ -4557,7 +4477,7 @@ class TypeRegistry {
4557
4477
  }
4558
4478
  propSchema = decoratePropertySchema(propSchema, prop, propType, checker);
4559
4479
  props[propName] = propSchema;
4560
- if (!(prop.flags & ts7.SymbolFlags.Optional)) {
4480
+ if (!(prop.flags & ts6.SymbolFlags.Optional)) {
4561
4481
  required.push(propName);
4562
4482
  }
4563
4483
  }
@@ -4574,7 +4494,224 @@ class TypeRegistry {
4574
4494
  }
4575
4495
  }
4576
4496
 
4497
+ // src/types/parameters.ts
4498
+ function extractParameters(signature, ctx) {
4499
+ const { typeChecker: checker } = ctx;
4500
+ const result = [];
4501
+ const signatureDecl = signature.getDeclaration();
4502
+ const jsdocTags = signatureDecl ? ts7.getJSDocTags(signatureDecl) : [];
4503
+ for (const param of signature.getParameters()) {
4504
+ const decl = param.valueDeclaration;
4505
+ if (!decl)
4506
+ continue;
4507
+ const defer = typeNodeDefersExpansion(decl.type, checker, ctx.program);
4508
+ const type = defer ? undefined : checker.getTypeOfSymbolAtLocation(param, decl);
4509
+ if (decl && ts7.isObjectBindingPattern(decl.name)) {
4510
+ const expandedParams = expandBindingPattern(decl, type ?? checker.getTypeOfSymbolAtLocation(param, decl), jsdocTags, ctx);
4511
+ result.push(...expandedParams);
4512
+ } else {
4513
+ const isOptional = !!decl?.questionToken || !!decl?.initializer;
4514
+ const isRest = !!decl.dotDotDotToken;
4515
+ const paramName = param.getName();
4516
+ const description = getParamDescription(paramName, jsdocTags);
4517
+ const schema = defer ? buildSchemaFromTypeNode(decl.type, checker, ctx) : buildSchema(isOptional ? stripUndefinedFromType(type, checker) : type, checker, ctx, decl.type);
4518
+ if (!defer && type) {
4519
+ registerReferencedTypes(isOptional ? stripUndefinedFromType(type, checker) : type, ctx);
4520
+ }
4521
+ const paramResult = {
4522
+ name: paramName,
4523
+ schema,
4524
+ required: !isOptional && !isRest,
4525
+ ...isRest ? { rest: true } : {}
4526
+ };
4527
+ if (description) {
4528
+ paramResult.description = description;
4529
+ const inlineTags = parseInlineTags(description);
4530
+ if (inlineTags)
4531
+ paramResult.inlineTags = inlineTags;
4532
+ }
4533
+ if (decl.initializer) {
4534
+ applyDefault(paramResult, decl.initializer);
4535
+ }
4536
+ result.push(paramResult);
4537
+ }
4538
+ }
4539
+ return result;
4540
+ }
4541
+ function expandBindingPattern(paramDecl, paramType, jsdocTags, ctx) {
4542
+ const { typeChecker: checker } = ctx;
4543
+ const result = [];
4544
+ const bindingPattern = paramDecl.name;
4545
+ const allProperties = getEffectiveProperties(paramType, checker);
4546
+ const inferredAlias = inferParamAlias(jsdocTags);
4547
+ for (const element of bindingPattern.elements) {
4548
+ if (!ts7.isBindingElement(element))
4549
+ continue;
4550
+ const propertyName = element.propertyName ? ts7.isIdentifier(element.propertyName) ? element.propertyName.text : element.propertyName.getText() : ts7.isIdentifier(element.name) ? element.name.text : element.name.getText();
4551
+ const propSymbol = allProperties.get(propertyName);
4552
+ if (!propSymbol)
4553
+ continue;
4554
+ const isOptional = !!(propSymbol.flags & ts7.SymbolFlags.Optional) || element.initializer !== undefined;
4555
+ const propType = checker.getTypeOfSymbol(propSymbol);
4556
+ const effectiveType = isOptional ? stripUndefinedFromType(propType, checker) : propType;
4557
+ registerReferencedTypes(effectiveType, ctx);
4558
+ const description = getParamDescription(propertyName, jsdocTags, inferredAlias);
4559
+ const param = {
4560
+ name: propertyName,
4561
+ schema: buildSchema(effectiveType, checker, ctx, declaredTypeNode(propSymbol.valueDeclaration)),
4562
+ required: !isOptional
4563
+ };
4564
+ if (description) {
4565
+ param.description = description;
4566
+ const inlineTags = parseInlineTags(description);
4567
+ if (inlineTags)
4568
+ param.inlineTags = inlineTags;
4569
+ }
4570
+ if (element.initializer) {
4571
+ applyDefault(param, element.initializer);
4572
+ }
4573
+ result.push(param);
4574
+ }
4575
+ return result;
4576
+ }
4577
+ function getEffectiveProperties(type, _checker) {
4578
+ const properties = new Map;
4579
+ if (type.isIntersection()) {
4580
+ for (const subType of type.types) {
4581
+ for (const prop of subType.getProperties()) {
4582
+ properties.set(prop.getName(), prop);
4583
+ }
4584
+ }
4585
+ } else {
4586
+ for (const prop of type.getProperties()) {
4587
+ properties.set(prop.getName(), prop);
4588
+ }
4589
+ }
4590
+ return properties;
4591
+ }
4592
+ function inferParamAlias(jsdocTags) {
4593
+ const prefixes = [];
4594
+ for (const tag of jsdocTags) {
4595
+ if (tag.tagName.text !== "param")
4596
+ continue;
4597
+ const tagText = typeof tag.comment === "string" ? tag.comment : ts7.getTextOfJSDocComment(tag.comment) ?? "";
4598
+ const paramTag = tag;
4599
+ const paramName = paramTag.name?.getText() ?? "";
4600
+ if (paramName.includes(".")) {
4601
+ const prefix = paramName.split(".")[0];
4602
+ if (prefix && !prefix.startsWith("__")) {
4603
+ prefixes.push(prefix);
4604
+ }
4605
+ } else if (tagText.includes(".")) {
4606
+ const match = tagText.match(/^(\w+)\./);
4607
+ if (match && !match[1].startsWith("__")) {
4608
+ prefixes.push(match[1]);
4609
+ }
4610
+ }
4611
+ }
4612
+ if (prefixes.length === 0)
4613
+ return;
4614
+ const counts = new Map;
4615
+ for (const p of prefixes)
4616
+ counts.set(p, (counts.get(p) ?? 0) + 1);
4617
+ return Array.from(counts.entries()).sort((a, b) => b[1] - a[1])[0]?.[0];
4618
+ }
4619
+ function extractLiteralDefault(initializer) {
4620
+ if (ts7.isStringLiteral(initializer)) {
4621
+ return { literal: true, value: initializer.text };
4622
+ }
4623
+ if (ts7.isNumericLiteral(initializer)) {
4624
+ return { literal: true, value: Number(initializer.text) };
4625
+ }
4626
+ if (ts7.isPrefixUnaryExpression(initializer) && initializer.operator === ts7.SyntaxKind.MinusToken && ts7.isNumericLiteral(initializer.operand)) {
4627
+ return { literal: true, value: -Number(initializer.operand.text) };
4628
+ }
4629
+ if (initializer.kind === ts7.SyntaxKind.TrueKeyword) {
4630
+ return { literal: true, value: true };
4631
+ }
4632
+ if (initializer.kind === ts7.SyntaxKind.FalseKeyword) {
4633
+ return { literal: true, value: false };
4634
+ }
4635
+ if (initializer.kind === ts7.SyntaxKind.NullKeyword) {
4636
+ return { literal: true, value: null };
4637
+ }
4638
+ return { literal: false, text: initializer.getText() };
4639
+ }
4640
+ function applyDefault(param, initializer) {
4641
+ const extracted = extractLiteralDefault(initializer);
4642
+ if (extracted.literal) {
4643
+ param.default = extracted.value;
4644
+ if (param.schema && typeof param.schema === "object" && !Array.isArray(param.schema)) {
4645
+ param.schema.default = extracted.value;
4646
+ }
4647
+ } else {
4648
+ param.default = extracted.text;
4649
+ if (param.schema && typeof param.schema === "object" && !Array.isArray(param.schema)) {
4650
+ param.schema["x-ts-default"] = extracted.text;
4651
+ }
4652
+ }
4653
+ }
4654
+ function registerReferencedTypes(type, ctx, depth = 0) {
4655
+ if (depth > ctx.maxTypeDepth)
4656
+ return;
4657
+ if (ctx.registeredTypes.has(type))
4658
+ return;
4659
+ const isPrimitive = type.flags & (ts7.TypeFlags.String | ts7.TypeFlags.Number | ts7.TypeFlags.Boolean | ts7.TypeFlags.Void | ts7.TypeFlags.Undefined | ts7.TypeFlags.Null | ts7.TypeFlags.Any | ts7.TypeFlags.Unknown | ts7.TypeFlags.Never | ts7.TypeFlags.StringLiteral | ts7.TypeFlags.NumberLiteral | ts7.TypeFlags.BooleanLiteral);
4660
+ if (!isPrimitive) {
4661
+ ctx.registeredTypes.add(type);
4662
+ }
4663
+ const { typeChecker: checker, typeRegistry } = ctx;
4664
+ typeRegistry.registerType(type, ctx);
4665
+ const typeArgs = type.typeArguments;
4666
+ if (typeArgs) {
4667
+ for (const arg of typeArgs) {
4668
+ registerReferencedTypes(arg, ctx, depth + 1);
4669
+ }
4670
+ }
4671
+ for (const arg of type.aliasTypeArguments ?? []) {
4672
+ registerReferencedTypes(arg, ctx, depth + 1);
4673
+ }
4674
+ const declared = declaredForm(type, checker);
4675
+ if (declared !== type) {
4676
+ registerReferencedTypes(declared, ctx, depth);
4677
+ return;
4678
+ }
4679
+ if (type.isUnion()) {
4680
+ for (const t of type.types) {
4681
+ registerReferencedTypes(t, ctx, depth + 1);
4682
+ }
4683
+ }
4684
+ if (type.isIntersection()) {
4685
+ for (const t of type.types) {
4686
+ registerReferencedTypes(t, ctx, depth + 1);
4687
+ }
4688
+ }
4689
+ const typeSymbol = type.aliasSymbol ?? type.getSymbol();
4690
+ if (typeSymbol && ctx.shouldExpandExternal && !typeSymbol.getName().startsWith("__") && !ctx.shouldExpandExternal(typeSymbol)) {
4691
+ return;
4692
+ }
4693
+ if (isForeignPackage(typeSymbol, ctx.workspacePackages)) {
4694
+ return;
4695
+ }
4696
+ if (isDeferredMappedOrConditional(type)) {
4697
+ return;
4698
+ }
4699
+ if (type.flags & ts7.TypeFlags.Object) {
4700
+ const props = type.getProperties();
4701
+ const limit = ctx.maxProperties;
4702
+ if (props.length > limit && ctx.onTruncation) {
4703
+ const typeName = type.getSymbol()?.getName() ?? "anonymous";
4704
+ ctx.onTruncation(typeName, props.length, limit);
4705
+ }
4706
+ for (const prop of props.slice(0, limit)) {
4707
+ const propType = checker.getTypeOfSymbol(prop);
4708
+ registerReferencedTypes(propType, ctx, depth + 1);
4709
+ }
4710
+ }
4711
+ }
4712
+
4577
4713
  // src/serializers/context.ts
4714
+ import ts8 from "typescript";
4578
4715
  function createContext(program, sourceFile, options = {}) {
4579
4716
  return {
4580
4717
  typeChecker: program.getTypeChecker(),
@@ -4594,9 +4731,12 @@ function createContext(program, sourceFile, options = {}) {
4594
4731
  declIds: new Map,
4595
4732
  idOwner: new Map,
4596
4733
  workspacePackages: options.workspacePackages ?? new Map,
4734
+ budget: { owner: "", ops: 0, exceeded: false },
4735
+ maxBudgetOps: MAX_BUDGET_OPS,
4597
4736
  schemaOps: 0,
4598
- maxSchemaOps: 20000,
4599
- budgetExceeded: false
4737
+ maxSchemaOps: MAX_SCHEMA_OPS,
4738
+ budgetExceeded: false,
4739
+ exhaustedBudgets: []
4600
4740
  };
4601
4741
  }
4602
4742
  function getInheritedMembers(classType, ownMemberNames, ctx, isStatic = false) {
@@ -4662,7 +4802,7 @@ function getStaticMembers(classType, checker) {
4662
4802
  });
4663
4803
  }
4664
4804
  function inheritedMethodSchema(symbol, type, ctx) {
4665
- if (!ctx.budgetExceeded) {
4805
+ if (!ctx.budget.exceeded) {
4666
4806
  return decoratePropertySchema({ "x-ts-function": true }, symbol, type, ctx.typeChecker);
4667
4807
  }
4668
4808
  return {
@@ -4680,7 +4820,7 @@ function serializeInheritedMember(symbol, inheritedFrom, ctx, isStatic) {
4680
4820
  const isOptional = !!(symbol.flags & ts8.SymbolFlags.Optional);
4681
4821
  const rawType = checker.getTypeOfSymbol(symbol);
4682
4822
  const type = isOptional ? stripUndefinedFromType(rawType, checker) : rawType;
4683
- const registerTypes = !ctx.budgetExceeded;
4823
+ const registerTypes = !ctx.budget.exceeded;
4684
4824
  if (registerTypes)
4685
4825
  registerReferencedTypes(type, ctx);
4686
4826
  let visibility;
@@ -4849,7 +4989,8 @@ function serializeClass(node, ctx) {
4849
4989
  members.push(...inheritedInstance);
4850
4990
  const inheritedStatic = getInheritedMembers(classType, ownMemberNames, ctx, true);
4851
4991
  members.push(...inheritedStatic);
4852
- const extendsClause = getExtendsClause(node, checker);
4992
+ const extendsClause = getExtendsText(node, checker);
4993
+ const openArms = openHeritageArms([node], checker, ctx);
4853
4994
  const implementsClause = getImplementsClause(node, checker);
4854
4995
  const classFlags = {};
4855
4996
  const classModifiers = ts10.getModifiers(node);
@@ -4867,6 +5008,7 @@ function serializeClass(node, ctx) {
4867
5008
  members: members.length > 0 ? members : undefined,
4868
5009
  signatures: signatures.length > 0 ? signatures : undefined,
4869
5010
  extends: extendsClause,
5011
+ ...openArms.length > 0 ? { schema: { allOf: openArms } } : {},
4870
5012
  implements: implementsClause?.length ? implementsClause : undefined,
4871
5013
  ...deprecated ? { deprecated: true, deprecationReason } : {},
4872
5014
  ...examples.length > 0 ? { examples } : {},
@@ -4879,11 +5021,7 @@ function getMemberName(member) {
4879
5021
  return "constructor";
4880
5022
  if (!member.name)
4881
5023
  return;
4882
- 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();
5024
+ return propertyNameText(member.name);
4887
5025
  }
4888
5026
  function getVisibility(member) {
4889
5027
  const modifiers = ts10.canHaveModifiers(member) ? ts10.getModifiers(member) : undefined;
@@ -5085,21 +5223,6 @@ function serializeAccessor(node, ctx) {
5085
5223
  ...inlineTags ? { inlineTags } : {}
5086
5224
  };
5087
5225
  }
5088
- function getExtendsClause(node, checker) {
5089
- if (!node.heritageClauses)
5090
- return;
5091
- for (const clause of node.heritageClauses) {
5092
- if (clause.token === ts10.SyntaxKind.ExtendsKeyword) {
5093
- const expr = clause.types[0];
5094
- if (expr) {
5095
- const type = checker.getTypeAtLocation(expr);
5096
- const symbol = type.getSymbol();
5097
- return symbol?.getName() ?? expr.expression.getText();
5098
- }
5099
- }
5100
- }
5101
- return;
5102
- }
5103
5226
  function getImplementsClause(node, checker) {
5104
5227
  if (!node.heritageClauses)
5105
5228
  return;
@@ -5336,7 +5459,8 @@ function serializeInterface(node, ctx) {
5336
5459
  const { description, tags, examples, source, deprecated, deprecationReason, inlineTags } = extractExportMetadata(node, symbol, checker);
5337
5460
  const typeParameters = extractTypeParameters(node, checker);
5338
5461
  const { members, callSignatureMember } = serializeTypeElements(node.members, ctx);
5339
- const extendsClause = getInterfaceExtends(node, checker);
5462
+ const extendsClause = getExtendsText(node, checker);
5463
+ const openArms = openHeritageArms([node], checker, ctx);
5340
5464
  const exportSignatures = callSignatureMember?.signatures && callSignatureMember.signatures.length > 0 ? callSignatureMember.signatures : undefined;
5341
5465
  return {
5342
5466
  id: name,
@@ -5349,6 +5473,7 @@ function serializeInterface(node, ctx) {
5349
5473
  members: members.length > 0 ? members : undefined,
5350
5474
  signatures: exportSignatures,
5351
5475
  extends: extendsClause,
5476
+ ...openArms.length > 0 ? { schema: { allOf: openArms } } : {},
5352
5477
  ...deprecated ? { deprecated: true, deprecationReason } : {},
5353
5478
  ...examples.length > 0 ? { examples } : {},
5354
5479
  ...inlineTags ? { inlineTags } : {}
@@ -5438,7 +5563,7 @@ function serializeMergedTypeSide(symbol, ctx) {
5438
5563
  const { description, tags } = getJSDocComment(typeDecl);
5439
5564
  return {
5440
5565
  members,
5441
- extends: interfaces.map((decl) => getInterfaceExtends(decl, checker)).find(Boolean),
5566
+ extends: interfaces.map((decl) => getExtendsText(decl, checker)).find(Boolean),
5442
5567
  typeParameters: extractTypeParameters(typeDecl, checker),
5443
5568
  description,
5444
5569
  tags
@@ -5446,7 +5571,7 @@ function serializeMergedTypeSide(symbol, ctx) {
5446
5571
  }
5447
5572
  function serializePropertySignature(node, ctx) {
5448
5573
  const { typeChecker: checker } = ctx;
5449
- const name = node.name.getText();
5574
+ const name = propertyNameText(node.name);
5450
5575
  const { description, tags, inlineTags } = getJSDocComment(node);
5451
5576
  const rawType = checker.getTypeAtLocation(node);
5452
5577
  const type = node.questionToken ? stripUndefinedFromType(rawType, checker) : rawType;
@@ -5476,7 +5601,7 @@ function serializePropertySignature(node, ctx) {
5476
5601
  }
5477
5602
  function serializeMethodSignature(node, ctx) {
5478
5603
  const { typeChecker: checker } = ctx;
5479
- const name = node.name.getText();
5604
+ const name = propertyNameText(node.name);
5480
5605
  const { description, tags, inlineTags } = getJSDocComment(node);
5481
5606
  const rawType = checker.getTypeAtLocation(node);
5482
5607
  const type = node.questionToken ? stripUndefinedFromType(rawType, checker) : rawType;
@@ -5544,20 +5669,6 @@ function serializeIndexSignature(node, ctx) {
5544
5669
  ...inlineTags ? { inlineTags } : {}
5545
5670
  };
5546
5671
  }
5547
- function getInterfaceExtends(node, checker) {
5548
- if (!node.heritageClauses)
5549
- return;
5550
- for (const clause of node.heritageClauses) {
5551
- if (clause.token === ts12.SyntaxKind.ExtendsKeyword && clause.types.length > 0) {
5552
- const names = clause.types.map((expr) => {
5553
- const type = checker.getTypeAtLocation(expr);
5554
- return type.getSymbol()?.getName() ?? expr.expression.getText();
5555
- });
5556
- return names.join(" & ");
5557
- }
5558
- }
5559
- return;
5560
- }
5561
5672
 
5562
5673
  // src/serializers/type-aliases.ts
5563
5674
  import ts13 from "typescript";
@@ -5602,7 +5713,7 @@ function serializeTypeAlias(node, ctx) {
5602
5713
  schema = buildObjectSchema(type.getProperties(), ctx.typeChecker, ctx, type);
5603
5714
  members = serializeResolvedMembers(type, node, ctx);
5604
5715
  } else {
5605
- schema = buildSchema(type, ctx.typeChecker, ctx);
5716
+ schema = buildAliasBodySchema(type, ctx.typeChecker, ctx);
5606
5717
  if (isObjectShapedAlias(type, ctx)) {
5607
5718
  members = serializeResolvedMembers(type, node, ctx);
5608
5719
  }
@@ -6317,10 +6428,14 @@ function normalizeExport(exp, options = {}) {
6317
6428
  result.members = exp.members.map((member) => normalizeMember(member, options));
6318
6429
  }
6319
6430
  if (!vendorSchema && shouldGenerateMembersSchema(exp.kind) && exp.members && exp.members.length > 0) {
6320
- result.schema = normalizeMembers(exp.members, options);
6431
+ result.schema = withOpenArms(normalizeMembers(exp.members, options), result.schema);
6321
6432
  }
6322
6433
  return result;
6323
6434
  }
6435
+ function withOpenArms(membersSchema, provided) {
6436
+ const arms = provided?.allOf;
6437
+ return Array.isArray(arms) ? { allOf: [membersSchema, ...arms] } : membersSchema;
6438
+ }
6324
6439
  function normalizeType(type, options = {}) {
6325
6440
  const result = { ...type };
6326
6441
  if (type.schema) {
@@ -6330,7 +6445,7 @@ function normalizeType(type, options = {}) {
6330
6445
  result.members = type.members.map((member) => normalizeMember(member, options));
6331
6446
  }
6332
6447
  if (shouldGenerateMembersSchema(type.kind) && type.members && type.members.length > 0) {
6333
- result.schema = normalizeMembers(type.members, options);
6448
+ result.schema = withOpenArms(normalizeMembers(type.members, options), result.schema);
6334
6449
  }
6335
6450
  return result;
6336
6451
  }
@@ -7708,6 +7823,11 @@ function expandReachableTypes(exportedSymbols, ctx, opts) {
7708
7823
  visit(t, depth + 1);
7709
7824
  }
7710
7825
  }
7826
+ const declared = declaredForm(type, checker);
7827
+ if (declared !== type) {
7828
+ visit(declared, depth);
7829
+ return;
7830
+ }
7711
7831
  if (!allowed || isDeferredMappedOrConditional(type) || !(type.flags & ts20.TypeFlags.Object || type.isClassOrInterface())) {
7712
7832
  return;
7713
7833
  }
@@ -7781,7 +7901,7 @@ function expandReachableTypes(exportedSymbols, ctx, opts) {
7781
7901
  id,
7782
7902
  name,
7783
7903
  kind: symbolKind(symbol),
7784
- schema: ensureNonEmptySchema(buildSchema(declared, checker, ctx, writtenWhenAny(symbol, declared)), declared, checker)
7904
+ schema: withExpansionBudget(ctx, `type ${id}`, () => ensureNonEmptySchema(buildSchema(declared, checker, ctx, writtenWhenAny(symbol, declared)), declared, checker))
7785
7905
  });
7786
7906
  }
7787
7907
  symbolByName.set(name, symbol);
@@ -8231,7 +8351,7 @@ async function extract(options) {
8231
8351
  }
8232
8352
  continue;
8233
8353
  }
8234
- const exp = serializeDeclaration2(declaration, symbol, exportName, ctx, isTypeOnly);
8354
+ const exp = withExpansionBudget(ctx, exportName, () => serializeDeclaration2(declaration, symbol, exportName, ctx, isTypeOnly));
8235
8355
  if (exp) {
8236
8356
  const typeSide = mergedTypeSideOf(exp, declaration, targetSymbol, ctx);
8237
8357
  if (typeSide) {
@@ -8260,7 +8380,7 @@ async function extract(options) {
8260
8380
  }
8261
8381
  }
8262
8382
  for (const { index, symbol, ontoClass } of mergedTypeSides) {
8263
- exports[index] = withMergedTypeSide(exports[index], symbol, ctx, ontoClass);
8383
+ exports[index] = withExpansionBudget(ctx, exports[index].name, () => withMergedTypeSide(exports[index], symbol, ctx, ontoClass));
8264
8384
  }
8265
8385
  const verification = buildVerificationSummary(exportedSymbols.length, exports.length, exportTracker);
8266
8386
  const meta = await getPackageMeta(entryFile, baseDir);
@@ -8271,7 +8391,7 @@ async function extract(options) {
8271
8391
  });
8272
8392
  if (ctx.budgetExceeded) {
8273
8393
  diagnostics.push({
8274
- message: "Stopped expanding some types after hitting the schema expansion budget",
8394
+ message: `Stopped expanding some types after hitting the schema expansion budget${exhaustedBudgetNote(ctx)}`,
8275
8395
  severity: "warning",
8276
8396
  code: "TYPE_EXPANSION_LIMIT"
8277
8397
  });
@@ -8751,6 +8871,13 @@ function withMergedTypeSide(entry, symbol, ctx, ontoClass) {
8751
8871
  ...entry.description ? {} : { description, tags: [...entry.tags ?? [], ...tags ?? []] }
8752
8872
  };
8753
8873
  }
8874
+ function exhaustedBudgetNote(ctx) {
8875
+ const owners = [...new Set(ctx.exhaustedBudgets)];
8876
+ if (owners.length === 0)
8877
+ return "";
8878
+ const shown = owners.slice(0, 10).join(", ");
8879
+ return `: ${shown}${owners.length > 10 ? ` (+${owners.length - 10} more)` : ""}`;
8880
+ }
8754
8881
  function withExportName(entry, exportName) {
8755
8882
  if (entry.name === exportName) {
8756
8883
  return entry;
@@ -9322,6 +9449,7 @@ function getNodeName(node) {
9322
9449
  export {
9323
9450
  zodAdapter,
9324
9451
  writtenTypeText,
9452
+ withOpenHeritage,
9325
9453
  withDescription,
9326
9454
  withDeprecated,
9327
9455
  validateSpec2 as validateSpec,
@@ -9367,6 +9495,7 @@ export {
9367
9495
  query,
9368
9496
  pickEntry,
9369
9497
  parseGithubRepo,
9498
+ openHeritageArms,
9370
9499
  normalizeType,
9371
9500
  normalizeSchema,
9372
9501
  normalizeMembers,
@@ -9448,6 +9577,7 @@ export {
9448
9577
  buildSchema,
9449
9578
  buildObjectSchema,
9450
9579
  buildFunctionSchema,
9580
+ buildAliasBodySchema,
9451
9581
  assertSpec,
9452
9582
  asStandardSchema,
9453
9583
  arktypeAdapter,
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.10",
4
4
  "description": "TypeScript API extraction SDK - programmatic primitives for OpenPkg specs",
5
5
  "keywords": [
6
6
  "openpkg",