@openpkg-ts/sdk 0.36.0 → 0.37.0

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/browser.d.ts CHANGED
@@ -381,19 +381,19 @@ interface DocsInstance {
381
381
  getDeprecated(): SpecExport3[];
382
382
  /** Get exports grouped by kind */
383
383
  groupByKind(): Record<SpecExportKind4, SpecExport3[]>;
384
- /** Render spec or single to MDX */
384
+ /** Render spec or single to an MDX string */
385
385
  toMarkdown(options?: ExportMarkdownOptions): string;
386
- /** Render spec or single to HTML */
386
+ /** Render spec or single to an HTML string */
387
387
  toHTML(options?: HTMLOptions): string;
388
- /** Render spec or single to JSON structure */
388
+ /** Render spec or single to a simplified JSON structure */
389
389
  toJSON(options?: JSONOptions): SimplifiedSpec | SimplifiedExport;
390
- /** Generate navigation structure */
390
+ /** Generate navigation data structure (JSON object, not a component) */
391
391
  toNavigation(options?: NavOptions): GenericNav | FumadocsMeta | DocusaurusSidebar;
392
- /** Generate search index */
392
+ /** Generate search index data */
393
393
  toSearchIndex(options?: SearchOptions): SearchIndex;
394
- /** Generate Pagefind-compatible records */
394
+ /** Generate Pagefind-compatible record objects */
395
395
  toPagefindRecords(options?: SearchOptions): PagefindRecord[];
396
- /** Generate Algolia-compatible records */
396
+ /** Generate Algolia-compatible record objects */
397
397
  toAlgoliaRecords(options?: SearchOptions): AlgoliaRecord[];
398
398
  }
399
399
  import { OpenPkg as OpenPkg8, SpecExport as SpecExport4, SpecMember as SpecMember2, SpecSchema, SpecSignature, SpecType as SpecType2, SpecTypeParameter } from "@openpkg-ts/spec";
package/dist/index.d.ts CHANGED
@@ -229,9 +229,12 @@ interface HTMLOptions {
229
229
  /**
230
230
  * Render spec to standalone HTML page.
231
231
  *
232
+ * Returns an HTML string — not a React component. Write the result to an
233
+ * `.html` file or embed it in a template.
234
+ *
232
235
  * @param spec - The OpenPkg spec to render
233
236
  * @param options - HTML rendering options
234
- * @returns Complete HTML document or fragment
237
+ * @returns Complete HTML document string or HTML fragment string
235
238
  *
236
239
  * @example
237
240
  * ```ts
@@ -403,6 +406,9 @@ declare function exportToMarkdown(exp: SpecExport2, options?: MarkdownOptions):
403
406
  /**
404
407
  * Render entire spec to MDX.
405
408
  *
409
+ * Returns an MDX-formatted string — not a React component. Write the result to
410
+ * a `.mdx` file or pass it to your docs framework's content pipeline.
411
+ *
406
412
  * @param spec - The OpenPkg spec to render
407
413
  * @param options - Markdown options, optionally with name for single mode
408
414
  * @returns MDX string
@@ -499,6 +505,8 @@ declare function toNavigation2(spec: OpenPkg6, options?: NavOptions): GenericNav
499
505
  /**
500
506
  * Generate Fumadocs meta.json file content.
501
507
  *
508
+ * Returns a JSON string suitable for writing to a meta.json file — not a React component.
509
+ *
502
510
  * @param spec - The OpenPkg spec
503
511
  * @param options - Navigation options (format is forced to fumadocs)
504
512
  * @returns JSON string for meta.json file
@@ -513,6 +521,8 @@ declare function toFumadocsMetaJSON(spec: OpenPkg6, options?: Omit<NavOptions, "
513
521
  /**
514
522
  * Generate Docusaurus sidebar config.
515
523
  *
524
+ * Returns a JavaScript module.exports string suitable for writing to a sidebars.js file — not a React component.
525
+ *
516
526
  * @param spec - The OpenPkg spec
517
527
  * @param options - Navigation options (format is forced to docusaurus)
518
528
  * @returns JavaScript module.exports string for sidebars.js
@@ -691,19 +701,19 @@ interface DocsInstance {
691
701
  getDeprecated(): SpecExport3[];
692
702
  /** Get exports grouped by kind */
693
703
  groupByKind(): Record<SpecExportKind4, SpecExport3[]>;
694
- /** Render spec or single to MDX */
704
+ /** Render spec or single to an MDX string */
695
705
  toMarkdown(options?: ExportMarkdownOptions): string;
696
- /** Render spec or single to HTML */
706
+ /** Render spec or single to an HTML string */
697
707
  toHTML(options?: HTMLOptions): string;
698
- /** Render spec or single to JSON structure */
708
+ /** Render spec or single to a simplified JSON structure */
699
709
  toJSON(options?: JSONOptions): SimplifiedSpec | SimplifiedExport;
700
- /** Generate navigation structure */
710
+ /** Generate navigation data structure (JSON object, not a component) */
701
711
  toNavigation(options?: NavOptions): GenericNav | FumadocsMeta | DocusaurusSidebar;
702
- /** Generate search index */
712
+ /** Generate search index data */
703
713
  toSearchIndex(options?: SearchOptions): SearchIndex;
704
- /** Generate Pagefind-compatible records */
714
+ /** Generate Pagefind-compatible record objects */
705
715
  toPagefindRecords(options?: SearchOptions): PagefindRecord[];
706
- /** Generate Algolia-compatible records */
716
+ /** Generate Algolia-compatible record objects */
707
717
  toAlgoliaRecords(options?: SearchOptions): AlgoliaRecord[];
708
718
  }
709
719
  /**
@@ -722,6 +732,10 @@ declare function loadSpec(spec: OpenPkg8): DocsInstance;
722
732
  /**
723
733
  * Creates a docs instance for querying and rendering API documentation.
724
734
  *
735
+ * Render methods (toMarkdown, toHTML, toJSON, toNavigation) return strings or
736
+ * plain data objects — not React components. For React UI components, see the
737
+ * `@openpkg-ts/registry` package.
738
+ *
725
739
  * @example
726
740
  * ```ts
727
741
  * import { createDocs } from '@openpkg-ts/sdk'
@@ -1125,7 +1139,7 @@ interface ExportItem {
1125
1139
  /** Export name */
1126
1140
  name: string;
1127
1141
  /** Export kind */
1128
- kind: "function" | "class" | "interface" | "type" | "enum" | "variable" | "namespace";
1142
+ kind: "function" | "class" | "interface" | "type" | "enum" | "variable" | "namespace" | "external";
1129
1143
  /** Source file path */
1130
1144
  file: string;
1131
1145
  /** Line number (1-indexed) */
@@ -1207,9 +1221,14 @@ declare class TypeRegistry {
1207
1221
  */
1208
1222
  private isSelfRef;
1209
1223
  /**
1224
+ * Resolve a self-referential $ref to the actual type structure.
1225
+ * Handles unions (string literal → enum), enums (numeric → enum), and objects.
1226
+ */
1227
+ private resolveSelRefSchema;
1228
+ /**
1210
1229
  * Build object schema from type properties (for interfaces/classes)
1211
1230
  */
1212
- private buildObjectSchemaFromType;
1231
+ private buildObjectSchemaFromProperties;
1213
1232
  }
1214
1233
  import ts3 from "typescript";
1215
1234
  /**
@@ -1618,7 +1637,7 @@ import ts9 from "typescript";
1618
1637
  declare function serializeEnum(node: ts9.EnumDeclaration, ctx: SerializerContext): SpecExport10 | null;
1619
1638
  import { SpecExport as SpecExport11 } from "@openpkg-ts/spec";
1620
1639
  import ts10 from "typescript";
1621
- declare function serializeFunctionExport(node: ts10.FunctionDeclaration | ts10.ArrowFunction, ctx: SerializerContext, nameOverride?: string): SpecExport11 | null;
1640
+ declare function serializeFunctionExport(node: ts10.FunctionDeclaration | ts10.ArrowFunction | ts10.FunctionExpression, ctx: SerializerContext, nameOverride?: string): SpecExport11 | null;
1622
1641
  import { SpecExport as SpecExport12 } from "@openpkg-ts/spec";
1623
1642
  import ts11 from "typescript";
1624
1643
  declare function serializeInterface(node: ts11.InterfaceDeclaration, ctx: SerializerContext): SpecExport12 | null;
@@ -1645,6 +1664,8 @@ import ts15 from "typescript";
1645
1664
  declare const BUILTIN_TYPE_SCHEMAS: Record<string, SpecSchema2>;
1646
1665
  declare const PRIMITIVES: Set<string>;
1647
1666
  declare const ARRAY_PROTOTYPE_METHODS: Set<string>;
1667
+ declare const STRING_PROTOTYPE_METHODS: Set<string>;
1668
+ declare const NUMBER_PROTOTYPE_METHODS: Set<string>;
1648
1669
  /**
1649
1670
  * Check if a name is a primitive type
1650
1671
  */
@@ -1770,4 +1791,4 @@ declare function normalizeMembers(members: SpecMember3[], options?: NormalizeOpt
1770
1791
  import ts16 from "typescript";
1771
1792
  declare function isExported(node: ts16.Node): boolean;
1772
1793
  declare function getNodeName(node: ts16.Node): string | undefined;
1773
- export { zodAdapter, withDescription2 as withDescription, valibotAdapter, typeboxAdapter, toSearchIndexJSON, toSearchIndex2 as toSearchIndex, toReactString, toReact, toPagefindRecords2 as toPagefindRecords, toNavigation2 as toNavigation, toMarkdown2 as toMarkdown, toJSONString, toJSON2 as toJSON, toHTML2 as toHTML, toFumadocsMetaJSON, toDocusaurusSidebarJS, toAlgoliaRecords2 as toAlgoliaRecords, sortByName, serializeVariable, serializeTypeAlias, serializeInterface, serializeFunctionExport, serializeEnum, serializeClass, schemasAreEqual, schemaIsAny, resolveTypeRef, resolveExportTarget, resolveCompiledPath, registerReferencedTypes, registerAdapter, recommendSemverBump, query, normalizeType, normalizeSchema, normalizeMembers, normalizeExport, mergeConfig, loadSpec, loadConfig, listExports, isTypeReference, isTypeOnlyExport, isSymbolDeprecated, isStandardJSONSchema, isSchemaType, isPureRefSchema, isProperty, isPrimitiveName, isMethod, isExported, isBuiltinGeneric, isAnonymous, hasDeprecatedTag, groupByVisibility, getTypeOrigin, getSourceLocation, getProperties, getParamDescription, getNonNullableType, getNodeName, getMethods, getMemberBadges, getJSDocComment, getExportKind, getExport2 as getExport, getDeprecationMessage, toMarkdown2 as generateDocs, formatTypeParameters, formatSchema, formatReturnType, formatParameters, formatMappedType, formatConditionalType, formatBadges, findMissingParamDocs, findDiscriminatorProperty, findAdapter, filterSpec, extractTypeParameters, extractStandardSchemasFromTs, extractStandardSchemasFromProject, extractStandardSchemas, extractSpec, extractSchemaType, extractParameters, extract, exportToMarkdown, ensureNonEmptySchema, diffSpec2 as diffSpecs, diffSpec, detectTsRuntime, deduplicateSchemas, createProgram, createDocs, categorizeBreakingChanges, calculateNextVersion, buildSignatureString, buildSchema, arktypeAdapter, analyzeSpec, TypeRegistry, TypeReference2 as TypeReference, TsRuntime, StandardSchemaExtractionResult, StandardSchemaExtractionOutput, StandardJSONSchemaV1, StandardJSONSchemaTarget, StandardJSONSchemaOptions, SpecMappedType, SpecDiff, SpecDiagnostics, SpecConditionalType, SkippedExportDetail, SimplifiedSpec, SimplifiedSignature, SimplifiedReturn, SimplifiedParameter, SimplifiedMember, SimplifiedExport, SimplifiedExample, SerializerContext, SemverRecommendation, SemverBump, SearchRecord, SearchOptions, SearchIndex, SchemaExtractionResult, SchemaAdapter, ReactLayoutOptions, QueryBuilder, ProjectExtractionOutput, ProjectExtractionInfo, ProgramResult, ProgramOptions, PagefindRecord, PRIMITIVES, OpenpkgConfig, NormalizeOptions, NavOptions, NavItem, NavGroup, NavFormat, MemberChangeInfo, MarkdownOptions, LoadOptions, ListExportsResult, ListExportsOptions, 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, DiagnosticItem, Diagnostic, CategorizedBreaking, CacheManagerOptions, CacheManager, CONFIG_FILENAME, BreakingSeverity, BUILTIN_TYPE_SCHEMAS, AlgoliaRecord, ARRAY_PROTOTYPE_METHODS };
1794
+ export { zodAdapter, withDescription2 as withDescription, valibotAdapter, typeboxAdapter, toSearchIndexJSON, toSearchIndex2 as toSearchIndex, toReactString, toReact, toPagefindRecords2 as toPagefindRecords, toNavigation2 as toNavigation, toMarkdown2 as toMarkdown, toJSONString, toJSON2 as toJSON, toHTML2 as toHTML, toFumadocsMetaJSON, toDocusaurusSidebarJS, toAlgoliaRecords2 as toAlgoliaRecords, sortByName, serializeVariable, serializeTypeAlias, serializeInterface, serializeFunctionExport, serializeEnum, serializeClass, schemasAreEqual, schemaIsAny, resolveTypeRef, resolveExportTarget, resolveCompiledPath, registerReferencedTypes, registerAdapter, recommendSemverBump, query, normalizeType, normalizeSchema, normalizeMembers, normalizeExport, mergeConfig, loadSpec, loadConfig, listExports, isTypeReference, isTypeOnlyExport, isSymbolDeprecated, isStandardJSONSchema, isSchemaType, isPureRefSchema, isProperty, isPrimitiveName, isMethod, isExported, isBuiltinGeneric, isAnonymous, hasDeprecatedTag, groupByVisibility, getTypeOrigin, getSourceLocation, getProperties, getParamDescription, getNonNullableType, getNodeName, getMethods, getMemberBadges, getJSDocComment, getExportKind, getExport2 as getExport, getDeprecationMessage, toMarkdown2 as generateDocs, formatTypeParameters, formatSchema, formatReturnType, formatParameters, formatMappedType, formatConditionalType, formatBadges, findMissingParamDocs, findDiscriminatorProperty, findAdapter, filterSpec, extractTypeParameters, extractStandardSchemasFromTs, extractStandardSchemasFromProject, extractStandardSchemas, extractSpec, extractSchemaType, extractParameters, extract, exportToMarkdown, ensureNonEmptySchema, diffSpec2 as diffSpecs, diffSpec, detectTsRuntime, deduplicateSchemas, createProgram, createDocs, categorizeBreakingChanges, calculateNextVersion, buildSignatureString, buildSchema, arktypeAdapter, analyzeSpec, TypeRegistry, TypeReference2 as TypeReference, TsRuntime, StandardSchemaExtractionResult, StandardSchemaExtractionOutput, StandardJSONSchemaV1, StandardJSONSchemaTarget, StandardJSONSchemaOptions, SpecMappedType, SpecDiff, SpecDiagnostics, SpecConditionalType, SkippedExportDetail, SimplifiedSpec, SimplifiedSignature, SimplifiedReturn, SimplifiedParameter, SimplifiedMember, SimplifiedExport, SimplifiedExample, SerializerContext, SemverRecommendation, SemverBump, SearchRecord, SearchOptions, SearchIndex, SchemaExtractionResult, SchemaAdapter, STRING_PROTOTYPE_METHODS, ReactLayoutOptions, QueryBuilder, ProjectExtractionOutput, ProjectExtractionInfo, ProgramResult, ProgramOptions, PagefindRecord, PRIMITIVES, OpenpkgConfig, NormalizeOptions, NavOptions, NavItem, NavGroup, NavFormat, NUMBER_PROTOTYPE_METHODS, MemberChangeInfo, MarkdownOptions, LoadOptions, ListExportsResult, ListExportsOptions, 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, DiagnosticItem, Diagnostic, CategorizedBreaking, CacheManagerOptions, CacheManager, CONFIG_FILENAME, BreakingSeverity, BUILTIN_TYPE_SCHEMAS, AlgoliaRecord, ARRAY_PROTOTYPE_METHODS };
package/dist/index.js CHANGED
@@ -1953,6 +1953,21 @@ function isSymbolDeprecated(symbol) {
1953
1953
  }
1954
1954
  return { deprecated: true, reason };
1955
1955
  }
1956
+ if (ts2.isExportSpecifier(declaration)) {
1957
+ const exportDecl = declaration.parent?.parent;
1958
+ if (exportDecl && ts2.isExportDeclaration(exportDecl)) {
1959
+ const parentTag = ts2.getJSDocDeprecatedTag(exportDecl);
1960
+ if (parentTag) {
1961
+ let reason;
1962
+ if (typeof parentTag.comment === "string") {
1963
+ reason = parentTag.comment;
1964
+ } else if (Array.isArray(parentTag.comment)) {
1965
+ reason = parentTag.comment.map((c) => typeof c === "string" ? c : c.text).join("");
1966
+ }
1967
+ return { deprecated: true, reason };
1968
+ }
1969
+ }
1970
+ }
1956
1971
  }
1957
1972
  return { deprecated: false };
1958
1973
  }
@@ -2013,6 +2028,8 @@ function getExportKind(declaration, type) {
2013
2028
  return "enum";
2014
2029
  if (ts2.isModuleDeclaration(declaration) || ts2.isNamespaceExport(declaration))
2015
2030
  return "namespace";
2031
+ if (ts2.isVariableDeclaration(declaration) && type.getConstructSignatures().length > 0)
2032
+ return "class";
2016
2033
  if (ts2.isVariableDeclaration(declaration) && type.getCallSignatures().length > 0)
2017
2034
  return "function";
2018
2035
  return "variable";
@@ -2157,6 +2174,63 @@ var ARRAY_PROTOTYPE_METHODS = new Set([
2157
2174
  "toString",
2158
2175
  "toLocaleString"
2159
2176
  ]);
2177
+ var STRING_PROTOTYPE_METHODS = new Set([
2178
+ "charAt",
2179
+ "charCodeAt",
2180
+ "codePointAt",
2181
+ "concat",
2182
+ "endsWith",
2183
+ "includes",
2184
+ "indexOf",
2185
+ "lastIndexOf",
2186
+ "localeCompare",
2187
+ "match",
2188
+ "matchAll",
2189
+ "normalize",
2190
+ "padEnd",
2191
+ "padStart",
2192
+ "repeat",
2193
+ "replace",
2194
+ "replaceAll",
2195
+ "search",
2196
+ "slice",
2197
+ "split",
2198
+ "startsWith",
2199
+ "substring",
2200
+ "toLocaleLowerCase",
2201
+ "toLocaleUpperCase",
2202
+ "toLowerCase",
2203
+ "toUpperCase",
2204
+ "trim",
2205
+ "trimEnd",
2206
+ "trimStart",
2207
+ "at",
2208
+ "bold",
2209
+ "fixed",
2210
+ "italics",
2211
+ "link",
2212
+ "small",
2213
+ "strike",
2214
+ "sub",
2215
+ "sup",
2216
+ "anchor",
2217
+ "big",
2218
+ "blink",
2219
+ "fontcolor",
2220
+ "fontsize",
2221
+ "substr",
2222
+ "toString",
2223
+ "valueOf",
2224
+ "length"
2225
+ ]);
2226
+ var NUMBER_PROTOTYPE_METHODS = new Set([
2227
+ "toFixed",
2228
+ "toExponential",
2229
+ "toPrecision",
2230
+ "toString",
2231
+ "valueOf",
2232
+ "toLocaleString"
2233
+ ]);
2160
2234
  function isPrimitiveName(name) {
2161
2235
  return PRIMITIVES.has(name);
2162
2236
  }
@@ -2301,7 +2375,7 @@ function buildSchemaInternal(type, checker, ctx) {
2301
2375
  return { type: "bigint" };
2302
2376
  if (type.flags & ts3.TypeFlags.ESSymbol)
2303
2377
  return { type: "symbol" };
2304
- if (type.isThisType?.()) {
2378
+ if (type.isThisType === true) {
2305
2379
  const constraint = type.getConstraint?.();
2306
2380
  const symbol2 = constraint?.getSymbol() ?? type.getSymbol();
2307
2381
  if (symbol2 && !isAnonymous(type)) {
@@ -2556,6 +2630,7 @@ function buildFunctionSchema(callSignatures, checker, ctx) {
2556
2630
  return { type: "function", signatures: buildSignatures() };
2557
2631
  }
2558
2632
  function buildObjectSchema(properties, checker, ctx, originalType) {
2633
+ const isArrayLikeType = originalType ? checker.isArrayType(originalType) || checker.isTupleType(originalType) || originalType.symbol?.getName() === "Array" && isBuiltinSymbol(originalType.symbol) : false;
2559
2634
  const buildProps = () => {
2560
2635
  const props = {};
2561
2636
  const required = [];
@@ -2563,7 +2638,7 @@ function buildObjectSchema(properties, checker, ctx, originalType) {
2563
2638
  const propName = prop.getName();
2564
2639
  if (propName.startsWith("_"))
2565
2640
  continue;
2566
- if (ARRAY_PROTOTYPE_METHODS.has(propName)) {
2641
+ if (isArrayLikeType && ARRAY_PROTOTYPE_METHODS.has(propName)) {
2567
2642
  continue;
2568
2643
  }
2569
2644
  const propType = checker.getTypeOfSymbol(prop);
@@ -2945,8 +3020,6 @@ function isGenericTypeParameter(name) {
2945
3020
  return true;
2946
3021
  if (/^T[A-Z]/.test(name))
2947
3022
  return true;
2948
- if (["Key", "Value", "Item", "Element"].includes(name))
2949
- return true;
2950
3023
  return false;
2951
3024
  }
2952
3025
  function isExternalType(decl) {
@@ -2972,7 +3045,7 @@ class TypeRegistry {
2972
3045
  return Array.from(this.types.values());
2973
3046
  }
2974
3047
  registerType(type, ctx) {
2975
- const symbol = type.getSymbol() || type.aliasSymbol;
3048
+ const symbol = type.aliasSymbol || type.getSymbol();
2976
3049
  if (!symbol)
2977
3050
  return;
2978
3051
  const name = symbol.getName();
@@ -3027,7 +3100,7 @@ class TypeRegistry {
3027
3100
  }
3028
3101
  let schema = buildSchema(type, checker, ctx);
3029
3102
  if (this.isSelfRef(schema, name)) {
3030
- schema = this.buildObjectSchemaFromType(type, checker, ctx);
3103
+ schema = this.resolveSelRefSchema(type, checker, ctx);
3031
3104
  }
3032
3105
  return {
3033
3106
  id: name,
@@ -3043,7 +3116,56 @@ class TypeRegistry {
3043
3116
  const obj = schema;
3044
3117
  return obj.$ref === `#/types/${typeName}`;
3045
3118
  }
3046
- buildObjectSchemaFromType(type, checker, ctx) {
3119
+ resolveSelRefSchema(type, checker, ctx) {
3120
+ if (type.isUnion()) {
3121
+ const types = type.types;
3122
+ const allStringLiterals = types.every((t) => t.flags & ts5.TypeFlags.StringLiteral);
3123
+ if (allStringLiterals) {
3124
+ return {
3125
+ type: "string",
3126
+ enum: types.map((t) => t.value)
3127
+ };
3128
+ }
3129
+ const allNumberLiterals = types.every((t) => t.flags & ts5.TypeFlags.NumberLiteral);
3130
+ if (allNumberLiterals) {
3131
+ return {
3132
+ type: "number",
3133
+ enum: types.map((t) => t.value)
3134
+ };
3135
+ }
3136
+ return {
3137
+ anyOf: types.map((t) => buildSchema(t, checker, ctx))
3138
+ };
3139
+ }
3140
+ const symbol = type.getSymbol() ?? type.aliasSymbol;
3141
+ if (symbol) {
3142
+ const decl = symbol.declarations?.find(ts5.isEnumDeclaration);
3143
+ if (decl) {
3144
+ const members = [];
3145
+ for (const member of decl.members) {
3146
+ const memberSymbol = checker.getSymbolAtLocation(member.name);
3147
+ if (memberSymbol) {
3148
+ const constantValue = checker.getConstantValue(member);
3149
+ if (constantValue !== undefined) {
3150
+ members.push({
3151
+ name: memberSymbol.getName(),
3152
+ value: constantValue
3153
+ });
3154
+ }
3155
+ }
3156
+ }
3157
+ if (members.length > 0) {
3158
+ return {
3159
+ type: typeof members[0].value === "string" ? "string" : "number",
3160
+ enum: members.map((m) => m.value),
3161
+ "x-enum-members": members
3162
+ };
3163
+ }
3164
+ }
3165
+ }
3166
+ return this.buildObjectSchemaFromProperties(type, checker, ctx);
3167
+ }
3168
+ buildObjectSchemaFromProperties(type, checker, ctx) {
3047
3169
  const properties = type.getProperties();
3048
3170
  if (properties.length === 0) {
3049
3171
  return { type: checker.typeToString(type) };
@@ -3055,11 +3177,18 @@ class TypeRegistry {
3055
3177
  const typeName = type.getSymbol()?.getName() ?? "anonymous";
3056
3178
  ctx.onTruncation(typeName, properties.length, limit);
3057
3179
  }
3180
+ const isArrayLike = checker.isArrayType(type) || checker.isTupleType(type) || type.symbol?.getName() === "Array" && type.symbol?.getDeclarations()?.[0]?.getSourceFile()?.fileName?.includes("/typescript/lib/lib.");
3181
+ const isStringLike = type.flags & ts5.TypeFlags.StringLike;
3182
+ const isNumberLike = type.flags & ts5.TypeFlags.NumberLike;
3058
3183
  for (const prop of properties.slice(0, limit)) {
3059
3184
  const propName = prop.getName();
3060
3185
  if (propName.startsWith("_"))
3061
3186
  continue;
3062
- if (ARRAY_PROTOTYPE_METHODS.has(propName))
3187
+ if (isArrayLike && ARRAY_PROTOTYPE_METHODS.has(propName))
3188
+ continue;
3189
+ if (isStringLike && STRING_PROTOTYPE_METHODS.has(propName))
3190
+ continue;
3191
+ if (isNumberLike && NUMBER_PROTOTYPE_METHODS.has(propName))
3063
3192
  continue;
3064
3193
  const propType = checker.getTypeOfSymbol(prop);
3065
3194
  this.registerType(propType, ctx);
@@ -3091,7 +3220,7 @@ function createContext(program, sourceFile, options = {}) {
3091
3220
  visitedTypes: new Set,
3092
3221
  registeredTypes: new Set,
3093
3222
  includePrivate: options.includePrivate ?? false,
3094
- maxProperties: options.maxProperties ?? 20,
3223
+ maxProperties: options.maxProperties ?? 100,
3095
3224
  onTruncation: options.onTruncation
3096
3225
  };
3097
3226
  }
@@ -3388,6 +3517,8 @@ function serializeProperty(node, ctx) {
3388
3517
  flags.readonly = true;
3389
3518
  if (node.questionToken)
3390
3519
  flags.optional = true;
3520
+ const symbol = checker.getSymbolAtLocation(node.name ?? node);
3521
+ const { deprecated, reason: deprecationReason } = isSymbolDeprecated(symbol);
3391
3522
  return {
3392
3523
  name,
3393
3524
  kind: "property",
@@ -3395,7 +3526,8 @@ function serializeProperty(node, ctx) {
3395
3526
  tags: tags.length > 0 ? tags : undefined,
3396
3527
  visibility,
3397
3528
  schema,
3398
- flags: Object.keys(flags).length > 0 ? flags : undefined
3529
+ flags: Object.keys(flags).length > 0 ? flags : undefined,
3530
+ ...deprecated ? { deprecated: true, deprecationReason } : {}
3399
3531
  };
3400
3532
  }
3401
3533
  function serializeMethod(node, ctx) {
@@ -3423,6 +3555,8 @@ function serializeMethod(node, ctx) {
3423
3555
  if (modifiers?.some((m) => m.kind === ts7.SyntaxKind.AbstractKeyword)) {
3424
3556
  flags.abstract = true;
3425
3557
  }
3558
+ const symbol = checker.getSymbolAtLocation(node.name ?? node);
3559
+ const { deprecated, reason: deprecationReason } = isSymbolDeprecated(symbol);
3426
3560
  return {
3427
3561
  name,
3428
3562
  kind: "method",
@@ -3430,7 +3564,8 @@ function serializeMethod(node, ctx) {
3430
3564
  tags: tags.length > 0 ? tags : undefined,
3431
3565
  visibility,
3432
3566
  signatures: signatures.length > 0 ? signatures : undefined,
3433
- flags: Object.keys(flags).length > 0 ? flags : undefined
3567
+ flags: Object.keys(flags).length > 0 ? flags : undefined,
3568
+ ...deprecated ? { deprecated: true, deprecationReason } : {}
3434
3569
  };
3435
3570
  }
3436
3571
  function serializeConstructor(node, ctx) {
@@ -3616,6 +3751,14 @@ function serializeFunctionExport(node, ctx, nameOverride) {
3616
3751
  ...callSignatures.length > 1 ? { overloadIndex: index } : {}
3617
3752
  };
3618
3753
  });
3754
+ const flags = {};
3755
+ const modifiers = ts8.getModifiers(node);
3756
+ if (modifiers?.some((m) => m.kind === ts8.SyntaxKind.AsyncKeyword)) {
3757
+ flags.async = true;
3758
+ }
3759
+ if (node.asteriskToken) {
3760
+ flags.generator = true;
3761
+ }
3619
3762
  return {
3620
3763
  id: name,
3621
3764
  name,
@@ -3625,6 +3768,7 @@ function serializeFunctionExport(node, ctx, nameOverride) {
3625
3768
  source,
3626
3769
  typeParameters,
3627
3770
  signatures,
3771
+ ...Object.keys(flags).length > 0 ? { flags } : {},
3628
3772
  ...deprecated ? { deprecated: true, deprecationReason } : {},
3629
3773
  ...examples.length > 0 ? { examples } : {}
3630
3774
  };
@@ -3732,13 +3876,16 @@ function serializePropertySignature(node, ctx) {
3732
3876
  if (node.modifiers?.some((m) => m.kind === ts9.SyntaxKind.ReadonlyKeyword)) {
3733
3877
  flags.readonly = true;
3734
3878
  }
3879
+ const symbol = checker.getSymbolAtLocation(node.name);
3880
+ const { deprecated, reason: deprecationReason } = isSymbolDeprecated(symbol);
3735
3881
  return {
3736
3882
  name,
3737
3883
  kind: "property",
3738
3884
  description,
3739
3885
  tags: tags.length > 0 ? tags : undefined,
3740
3886
  schema,
3741
- flags: Object.keys(flags).length > 0 ? flags : undefined
3887
+ flags: Object.keys(flags).length > 0 ? flags : undefined,
3888
+ ...deprecated ? { deprecated: true, deprecationReason } : {}
3742
3889
  };
3743
3890
  }
3744
3891
  function serializeMethodSignature(node, ctx) {
@@ -3751,13 +3898,16 @@ function serializeMethodSignature(node, ctx) {
3751
3898
  const flags = {};
3752
3899
  if (node.questionToken)
3753
3900
  flags.optional = true;
3901
+ const symbol = checker.getSymbolAtLocation(node.name);
3902
+ const { deprecated, reason: deprecationReason } = isSymbolDeprecated(symbol);
3754
3903
  return {
3755
3904
  name,
3756
3905
  kind: "method",
3757
3906
  description,
3758
3907
  tags: tags.length > 0 ? tags : undefined,
3759
3908
  signatures: signatures.length > 0 ? signatures : undefined,
3760
- flags: Object.keys(flags).length > 0 ? flags : undefined
3909
+ flags: Object.keys(flags).length > 0 ? flags : undefined,
3910
+ ...deprecated ? { deprecated: true, deprecationReason } : {}
3761
3911
  };
3762
3912
  }
3763
3913
  function serializeCallSignature(node, ctx) {
@@ -4497,12 +4647,12 @@ async function getExport(options) {
4497
4647
  const result = createProgram({ entryFile, baseDir, content });
4498
4648
  const { program, sourceFile } = result;
4499
4649
  if (!sourceFile) {
4500
- return { export: null, types: [], errors: [`Could not load source file: ${entryFile}`] };
4650
+ return { export: null, types: [], errors: [`Entry file not found: ${entryFile}. Specify with: drift get src/index.ts <name>`] };
4501
4651
  }
4502
4652
  const checker = program.getTypeChecker();
4503
4653
  const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
4504
4654
  if (!moduleSymbol) {
4505
- return { export: null, types: [], errors: ["Could not get module symbol"] };
4655
+ return { export: null, types: [], errors: [`No exports found in ${entryFile}. Is this the right entry point?`] };
4506
4656
  }
4507
4657
  const exportedSymbols = checker.getExportsOfModule(moduleSymbol);
4508
4658
  const targetSymbol = exportedSymbols.find((s) => s.getName() === exportName);
@@ -4516,12 +4666,39 @@ async function getExport(options) {
4516
4666
  const ctx = createContext(program, sourceFile, { maxTypeDepth });
4517
4667
  ctx.exportedIds = exportedIds;
4518
4668
  try {
4669
+ const originalDecls = targetSymbol.declarations ?? [];
4670
+ const isNamespaceExportDecl = originalDecls.some((d) => ts11.isNamespaceExport(d) || ts11.isNamespaceImport(d));
4671
+ if (isNamespaceExportDecl) {
4672
+ const spec2 = serializeNamespaceForGet(targetSymbol, exportName, ctx);
4673
+ const types2 = ctx.typeRegistry.getAll().map((t) => normalizeType(t, { dialect: "draft-2020-12" }));
4674
+ return { export: normalizeExport(spec2, { dialect: "draft-2020-12" }), types: types2, errors };
4675
+ }
4519
4676
  const { declaration, resolvedSymbol, isTypeOnly } = resolveExportTarget(targetSymbol, checker);
4520
4677
  if (!declaration) {
4678
+ const externalPackage = detectExternalPackage(targetSymbol, checker);
4679
+ if (externalPackage) {
4680
+ const stub = {
4681
+ id: exportName,
4682
+ name: exportName,
4683
+ kind: "external",
4684
+ source: { package: externalPackage }
4685
+ };
4686
+ return { export: stub, types: [], errors };
4687
+ }
4521
4688
  return { export: null, types: [], errors: [`No declaration found for '${exportName}'`] };
4522
4689
  }
4523
4690
  let spec = serializeDeclaration(declaration, targetSymbol, resolvedSymbol, exportName, ctx, isTypeOnly);
4524
4691
  if (!spec) {
4692
+ const externalPackage = detectExternalPackage(targetSymbol, checker);
4693
+ if (externalPackage) {
4694
+ const stub = {
4695
+ id: exportName,
4696
+ name: exportName,
4697
+ kind: "external",
4698
+ source: { package: externalPackage }
4699
+ };
4700
+ return { export: stub, types: [], errors };
4701
+ }
4525
4702
  return { export: null, types: [], errors: [`Could not serialize '${exportName}'`] };
4526
4703
  }
4527
4704
  spec = normalizeExport(spec, { dialect: "draft-2020-12" });
@@ -4571,17 +4748,27 @@ function serializeDeclaration(declaration, _exportSymbol, _targetSymbol, exportN
4571
4748
  } else if (ts11.isVariableDeclaration(declaration)) {
4572
4749
  const varStatement = declaration.parent?.parent;
4573
4750
  if (varStatement && ts11.isVariableStatement(varStatement)) {
4574
- if (declaration.initializer && ts11.isArrowFunction(declaration.initializer)) {
4751
+ if (declaration.initializer && (ts11.isArrowFunction(declaration.initializer) || ts11.isFunctionExpression(declaration.initializer))) {
4575
4752
  const varName = ts11.isIdentifier(declaration.name) ? declaration.name.text : declaration.name.getText();
4576
4753
  result = serializeFunctionExport(declaration.initializer, ctx, varName);
4577
4754
  } else {
4578
- result = serializeVariable(declaration, varStatement, ctx);
4755
+ const checker = ctx.program.getTypeChecker();
4756
+ const varType = checker.getTypeAtLocation(declaration);
4757
+ if (varType.getCallSignatures().length > 0) {
4758
+ result = serializeVariable(declaration, varStatement, ctx);
4759
+ if (result)
4760
+ result = { ...result, kind: "function" };
4761
+ } else {
4762
+ result = serializeVariable(declaration, varStatement, ctx);
4763
+ }
4579
4764
  }
4580
4765
  }
4766
+ } else if (ts11.isNamespaceExport(declaration) || ts11.isModuleDeclaration(declaration) || ts11.isNamespaceImport(declaration) || ts11.isSourceFile(declaration)) {
4767
+ result = serializeNamespaceForGet(_exportSymbol, exportName, ctx);
4581
4768
  }
4582
4769
  if (result) {
4583
4770
  if (result.name !== exportName) {
4584
- result = { ...result, id: exportName, name: result.name };
4771
+ result = { ...result, id: exportName, name: exportName };
4585
4772
  }
4586
4773
  if (isTypeOnly) {
4587
4774
  result = { ...result, flags: { ...result.flags ?? {}, typeOnly: true } };
@@ -4589,6 +4776,65 @@ function serializeDeclaration(declaration, _exportSymbol, _targetSymbol, exportN
4589
4776
  }
4590
4777
  return result;
4591
4778
  }
4779
+ function serializeNamespaceForGet(symbol, exportName, ctx) {
4780
+ const checker = ctx.program.getTypeChecker();
4781
+ let targetSymbol = symbol;
4782
+ if (symbol.flags & ts11.SymbolFlags.Alias) {
4783
+ const aliased = checker.getAliasedSymbol(symbol);
4784
+ if (aliased && aliased !== symbol) {
4785
+ targetSymbol = aliased;
4786
+ }
4787
+ }
4788
+ const members = [];
4789
+ try {
4790
+ const nsExports = checker.getExportsOfModule(targetSymbol);
4791
+ for (const memberSymbol of nsExports) {
4792
+ const memberName = memberSymbol.getName();
4793
+ const memberDecls = memberSymbol.declarations ?? [];
4794
+ const memberDecl = memberSymbol.valueDeclaration || memberDecls[0];
4795
+ if (memberDecl) {
4796
+ const type = checker.getTypeAtLocation(memberDecl);
4797
+ const kind = getExportKind(memberDecl, type);
4798
+ members.push({ name: memberName, kind });
4799
+ }
4800
+ }
4801
+ } catch {}
4802
+ return {
4803
+ id: exportName,
4804
+ name: exportName,
4805
+ kind: "namespace",
4806
+ tags: [],
4807
+ ...members.length > 0 ? { members } : {}
4808
+ };
4809
+ }
4810
+ function detectExternalPackage(symbol, checker) {
4811
+ let targetSymbol = symbol;
4812
+ if (symbol.flags & ts11.SymbolFlags.Alias) {
4813
+ const aliased = checker.getAliasedSymbol(symbol);
4814
+ if (aliased && aliased !== symbol) {
4815
+ targetSymbol = aliased;
4816
+ }
4817
+ }
4818
+ const allDecls = [...targetSymbol.declarations ?? [], ...symbol.declarations ?? []];
4819
+ for (const decl of allDecls) {
4820
+ const sf = decl.getSourceFile();
4821
+ if (sf?.fileName.includes("node_modules")) {
4822
+ const match = sf.fileName.match(/node_modules\/(@[^/]+\/[^/]+|[^/]+)/);
4823
+ if (match)
4824
+ return match[1];
4825
+ }
4826
+ if (ts11.isExportSpecifier(decl)) {
4827
+ const exportDecl = decl.parent?.parent;
4828
+ if (exportDecl && ts11.isExportDeclaration(exportDecl) && exportDecl.moduleSpecifier) {
4829
+ const moduleText = exportDecl.moduleSpecifier.text;
4830
+ if (!moduleText.startsWith(".") && !moduleText.startsWith("/")) {
4831
+ return moduleText;
4832
+ }
4833
+ }
4834
+ }
4835
+ }
4836
+ return;
4837
+ }
4592
4838
  // src/primitives/list.ts
4593
4839
  import * as path4 from "node:path";
4594
4840
  import ts12 from "typescript";
@@ -4599,12 +4845,12 @@ async function listExports(options) {
4599
4845
  const result = createProgram({ entryFile, baseDir, content });
4600
4846
  const { program, sourceFile } = result;
4601
4847
  if (!sourceFile) {
4602
- return { exports: [], errors: [`Could not load source file: ${entryFile}`] };
4848
+ return { exports: [], errors: [`Entry file not found: ${entryFile}. Specify with: drift list src/index.ts`] };
4603
4849
  }
4604
4850
  const checker = program.getTypeChecker();
4605
4851
  const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
4606
4852
  if (!moduleSymbol) {
4607
- return { exports: [], errors: ["Could not get module symbol"] };
4853
+ return { exports: [], errors: [`No exports found in ${entryFile}. Is this the right entry point?`] };
4608
4854
  }
4609
4855
  const exportedSymbols = checker.getExportsOfModule(moduleSymbol);
4610
4856
  for (const symbol of exportedSymbols) {
@@ -4632,8 +4878,15 @@ function extractExportItem(symbol, checker, entryFile, entrySourceFile) {
4632
4878
  }
4633
4879
  const declarations = targetSymbol.declarations ?? [];
4634
4880
  const declaration = targetSymbol.valueDeclaration || declarations.find((d) => d.kind !== ts12.SyntaxKind.ExportSpecifier) || declarations[0];
4635
- if (!declaration)
4636
- return null;
4881
+ if (!declaration) {
4882
+ return {
4883
+ name,
4884
+ kind: "external",
4885
+ file: "<external>",
4886
+ line: 0,
4887
+ reexport: true
4888
+ };
4889
+ }
4637
4890
  if (ts12.isSourceFile(declaration)) {
4638
4891
  return {
4639
4892
  name,
@@ -5803,7 +6056,7 @@ async function extract(options) {
5803
6056
  if (!sourceFile) {
5804
6057
  return {
5805
6058
  spec: createEmptySpec(entryFile, includeSchema, isDtsSource),
5806
- diagnostics: [{ message: `Could not load source file: ${entryFile}`, severity: "error" }]
6059
+ diagnostics: [{ message: `Entry file not found: ${entryFile}. Specify with: drift list src/index.ts`, severity: "error" }]
5807
6060
  };
5808
6061
  }
5809
6062
  const typeChecker = program.getTypeChecker();
@@ -5811,7 +6064,7 @@ async function extract(options) {
5811
6064
  if (!moduleSymbol) {
5812
6065
  return {
5813
6066
  spec: createEmptySpec(entryFile, includeSchema, isDtsSource),
5814
- diagnostics: [{ message: "Could not get module symbol", severity: "warning" }]
6067
+ diagnostics: [{ message: `No exports found in ${entryFile}. Is this the right entry point?`, severity: "warning" }]
5815
6068
  };
5816
6069
  }
5817
6070
  const exportedSymbols = typeChecker.getExportsOfModule(moduleSymbol);
@@ -6091,11 +6344,17 @@ function serializeDeclaration2(declaration, exportSymbol, exportName, ctx, isTyp
6091
6344
  } else if (ts16.isVariableDeclaration(declaration)) {
6092
6345
  const varStatement = declaration.parent?.parent;
6093
6346
  if (varStatement && ts16.isVariableStatement(varStatement)) {
6094
- if (declaration.initializer && ts16.isArrowFunction(declaration.initializer)) {
6347
+ if (declaration.initializer && (ts16.isArrowFunction(declaration.initializer) || ts16.isFunctionExpression(declaration.initializer))) {
6095
6348
  const varName = ts16.isIdentifier(declaration.name) ? declaration.name.text : declaration.name.getText();
6096
6349
  result = serializeFunctionExport(declaration.initializer, ctx, varName);
6097
6350
  } else {
6098
6351
  result = serializeVariable(declaration, varStatement, ctx);
6352
+ if (result?.kind === "variable") {
6353
+ const type = ctx.typeChecker.getTypeAtLocation(declaration);
6354
+ if (type.getConstructSignatures().length > 0) {
6355
+ result = { ...result, kind: "class" };
6356
+ }
6357
+ }
6099
6358
  }
6100
6359
  }
6101
6360
  } else if (ts16.isNamespaceExport(declaration) || ts16.isModuleDeclaration(declaration) || ts16.isNamespaceImport(declaration) || ts16.isSourceFile(declaration)) {
@@ -6120,6 +6379,12 @@ function serializeDeclaration2(declaration, exportSymbol, exportName, ctx, isTyp
6120
6379
  flags: { ...result.flags ?? {}, typeOnly: true }
6121
6380
  };
6122
6381
  }
6382
+ if (!result.deprecated) {
6383
+ const { deprecated, reason: deprecationReason } = isSymbolDeprecated(exportSymbol);
6384
+ if (deprecated) {
6385
+ result = { ...result, deprecated: true, deprecationReason };
6386
+ }
6387
+ }
6123
6388
  }
6124
6389
  return result;
6125
6390
  }
@@ -6167,7 +6432,7 @@ function serializeNamespaceMember(symbol, memberName, ctx) {
6167
6432
  return null;
6168
6433
  const type = checker.getTypeAtLocation(declaration);
6169
6434
  const callSignatures = type.getCallSignatures();
6170
- const deprecated = isSymbolDeprecated(targetSymbol);
6435
+ const { deprecated } = isSymbolDeprecated(targetSymbol);
6171
6436
  let kind = "variable";
6172
6437
  if (ts16.isFunctionDeclaration(declaration) || ts16.isFunctionExpression(declaration)) {
6173
6438
  kind = "function";
@@ -6446,8 +6711,10 @@ export {
6446
6711
  arktypeAdapter,
6447
6712
  analyzeSpec,
6448
6713
  TypeRegistry,
6714
+ STRING_PROTOTYPE_METHODS,
6449
6715
  QueryBuilder,
6450
6716
  PRIMITIVES,
6717
+ NUMBER_PROTOTYPE_METHODS,
6451
6718
  CacheManager,
6452
6719
  CONFIG_FILENAME,
6453
6720
  BUILTIN_TYPE_SCHEMAS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openpkg-ts/sdk",
3
- "version": "0.36.0",
3
+ "version": "0.37.0",
4
4
  "description": "TypeScript API extraction SDK - programmatic primitives for OpenPkg specs",
5
5
  "keywords": [
6
6
  "openpkg",
@@ -42,7 +42,7 @@
42
42
  "test": "bun test"
43
43
  },
44
44
  "dependencies": {
45
- "@openpkg-ts/spec": "^0.35.1",
45
+ "@openpkg-ts/spec": "^0.37.0",
46
46
  "picomatch": "4.0.3",
47
47
  "typescript": "^5.0.0"
48
48
  },