@openpkg-ts/sdk 0.37.1 → 0.39.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Ryan Waits
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.d.ts CHANGED
@@ -733,8 +733,7 @@ declare function loadSpec(spec: OpenPkg8): DocsInstance;
733
733
  * Creates a docs instance for querying and rendering API documentation.
734
734
  *
735
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.
736
+ * plain data objects — not React components. Bring your own UI components.
738
737
  *
739
738
  * @example
740
739
  * ```ts
@@ -1038,30 +1037,7 @@ declare class QueryBuilder {
1038
1037
  * Create a query builder for the given spec
1039
1038
  */
1040
1039
  declare function query(spec: OpenPkg10): QueryBuilder;
1041
- import { OpenPkg as OpenPkg11 } from "@openpkg-ts/spec";
1042
- interface ReactLayoutOptions {
1043
- /** Output directory for generated files */
1044
- outDir: string;
1045
- /** Layout variant: 'full' (single page) or 'index' (index with links) */
1046
- variant?: "full" | "index";
1047
- /** Components path alias (default: @/components/api) */
1048
- componentsPath?: string;
1049
- }
1050
- /**
1051
- * Generate React layout from an OpenPkg spec.
1052
- *
1053
- * Unlike the old per-approach, this generates a single layout file.
1054
- * Components are installed separately via the registry.
1055
- */
1056
- declare function toReact(spec: OpenPkg11, options: ReactLayoutOptions): Promise<void>;
1057
- /**
1058
- * Generate layout code as a string (for preview).
1059
- */
1060
- declare function toReactString(spec: OpenPkg11, options?: {
1061
- variant?: "full" | "index";
1062
- componentsPath?: string;
1063
- }): string;
1064
- import { OpenPkg as OpenPkg12, SpecExportKind as SpecExportKind7 } from "@openpkg-ts/spec";
1040
+ import { OpenPkg as OpenPkg11, SpecExportKind as SpecExportKind7 } from "@openpkg-ts/spec";
1065
1041
  type FilterCriteria = {
1066
1042
  /** Filter by kinds */
1067
1043
  kinds?: SpecExportKind7[];
@@ -1086,7 +1062,7 @@ type FilterCriteria = {
1086
1062
  };
1087
1063
  type FilterResult = {
1088
1064
  /** New spec with only matched exports (immutable) */
1089
- spec: OpenPkg12;
1065
+ spec: OpenPkg11;
1090
1066
  /** Number of exports that matched */
1091
1067
  matched: number;
1092
1068
  /** Total number of exports in original spec */
@@ -1102,7 +1078,7 @@ type FilterResult = {
1102
1078
  * @param criteria - Filter criteria (empty criteria matches all)
1103
1079
  * @returns FilterResult with new spec, matched count, total count
1104
1080
  */
1105
- declare function filterSpec(spec: OpenPkg12, criteria: FilterCriteria): FilterResult;
1081
+ declare function filterSpec(spec: OpenPkg11, criteria: FilterCriteria): FilterResult;
1106
1082
  import { SpecExport as SpecExport6, SpecType as SpecType3 } from "@openpkg-ts/spec";
1107
1083
  interface GetExportOptions {
1108
1084
  /** Entry point file path */
@@ -1259,7 +1235,7 @@ declare function getSourceLocation(node: ts4.Node, sourceFile: ts4.SourceFile):
1259
1235
  * - @param {type} paramName - type annotation format
1260
1236
  */
1261
1237
  declare function getParamDescription(propertyName: string, jsdocTags: readonly ts4.JSDocTag[], inferredAlias?: string): string | undefined;
1262
- type DeclarationWithTypeParams = ts4.FunctionDeclaration | ts4.ClassDeclaration | ts4.InterfaceDeclaration | ts4.TypeAliasDeclaration | ts4.MethodDeclaration | ts4.ArrowFunction;
1238
+ type DeclarationWithTypeParams = ts4.FunctionDeclaration | ts4.ClassDeclaration | ts4.InterfaceDeclaration | ts4.TypeAliasDeclaration | ts4.MethodDeclaration | ts4.ArrowFunction | ts4.FunctionExpression;
1263
1239
  /**
1264
1240
  * Extract type parameters from declarations like `<T extends Base, K = Default>`
1265
1241
  * Also captures variance annotations (in/out) and const modifier.
@@ -1274,7 +1250,7 @@ declare function isSymbolDeprecated(symbol: ts4.Symbol | undefined): {
1274
1250
  reason?: string;
1275
1251
  };
1276
1252
  /** Classify a declaration node into an kind */
1277
- declare function getExportKind(declaration: ts4.Declaration, type: ts4.Type): SpecExportKind8;
1253
+ declare function getExportKind(declaration: ts4.Declaration, type: ts4.Type): Exclude<SpecExportKind8, "module" | "reference" | "external">;
1278
1254
  /**
1279
1255
  * Target version for JSON Schema generation.
1280
1256
  * @see https://standardschema.dev/json-schema
@@ -1575,7 +1551,7 @@ interface ProgramResult {
1575
1551
  /** Resolved project references (workspace packages) */
1576
1552
  projectReferences?: ts7.ResolvedProjectReference[];
1577
1553
  }
1578
- declare function createProgram({ entryFile, baseDir, content }: ProgramOptions): ProgramResult;
1554
+ declare function createProgram(options: ProgramOptions): ProgramResult;
1579
1555
  import * as TS from "typescript";
1580
1556
  /**
1581
1557
  * A schema adapter can detect and extract output types from a specific
@@ -1791,4 +1767,4 @@ declare function normalizeMembers(members: SpecMember3[], options?: NormalizeOpt
1791
1767
  import ts16 from "typescript";
1792
1768
  declare function isExported(node: ts16.Node): boolean;
1793
1769
  declare function getNodeName(node: ts16.Node): string | undefined;
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 };
1770
+ export { zodAdapter, withDescription2 as withDescription, valibotAdapter, typeboxAdapter, toSearchIndexJSON, toSearchIndex2 as toSearchIndex, 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, 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
@@ -1191,221 +1191,6 @@ function extractModuleName(exp) {
1191
1191
  }
1192
1192
  return;
1193
1193
  }
1194
- // src/render/react.ts
1195
- import * as fs3 from "node:fs";
1196
- import * as path2 from "node:path";
1197
- function generateFullLayout(spec, componentsPath) {
1198
- const pkgName = spec.meta.name;
1199
- return `'use client';
1200
-
1201
- import type { OpenPkg, SpecExport } from '@openpkg-ts/spec';
1202
- import spec from './openpkg.json';
1203
-
1204
- // Add components via: openpkg docs add function-section class-section interface-section
1205
- // Then uncomment the imports below and customize as needed.
1206
-
1207
- // import { FunctionSection } from '${componentsPath}/function-section';
1208
- // import { ClassSection } from '${componentsPath}/class-section';
1209
- // import { InterfaceSection } from '${componentsPath}/interface-section';
1210
- // import { VariableSection } from '${componentsPath}/variable-section';
1211
- // import { EnumSection } from '${componentsPath}/enum-section';
1212
-
1213
- /**
1214
- * Renders a single export based on its kind.
1215
- * Customize this to match your design system.
1216
- */
1217
- function ExportSection({ exp }: { exp: SpecExport }) {
1218
- // Uncomment the switch once you've added components:
1219
- // switch (exp.kind) {
1220
- // case 'function':
1221
- // return <FunctionSection key={exp.id} export={exp} spec={spec as OpenPkg} />;
1222
- // case 'class':
1223
- // return <ClassSection key={exp.id} export={exp} spec={spec as OpenPkg} />;
1224
- // case 'interface':
1225
- // case 'type':
1226
- // return <InterfaceSection key={exp.id} export={exp} spec={spec as OpenPkg} />;
1227
- // case 'variable':
1228
- // return <VariableSection key={exp.id} export={exp} spec={spec as OpenPkg} />;
1229
- // case 'enum':
1230
- // return <EnumSection key={exp.id} export={exp} spec={spec as OpenPkg} />;
1231
- // default:
1232
- // return null;
1233
- // }
1234
-
1235
- // Placeholder: replace with component imports above
1236
- return (
1237
- <section id={exp.id} className="py-8 border-b">
1238
- <h2 className="text-xl font-semibold">{exp.name}</h2>
1239
- <p className="text-muted-foreground">{exp.description || 'No description'}</p>
1240
- <code className="text-sm">{exp.kind}</code>
1241
- </section>
1242
- );
1243
- }
1244
-
1245
- /**
1246
- * Full API Reference Page for ${pkgName}
1247
- *
1248
- * This layout renders all exports on a single page.
1249
- * Customize the grouping, styling, and components to match your docs.
1250
- */
1251
- export default function APIReferencePage() {
1252
- const typedSpec = spec as OpenPkg;
1253
- const exports = typedSpec.exports;
1254
-
1255
- // Group exports by kind
1256
- const functions = exports.filter((e) => e.kind === 'function');
1257
- const classes = exports.filter((e) => e.kind === 'class');
1258
- const interfaces = exports.filter((e) => e.kind === 'interface' || e.kind === 'type');
1259
- const variables = exports.filter((e) => e.kind === 'variable');
1260
- const enums = exports.filter((e) => e.kind === 'enum');
1261
-
1262
- return (
1263
- <div className="max-w-4xl mx-auto px-4 py-8">
1264
- <header className="mb-12">
1265
- <h1 className="text-3xl font-bold">{typedSpec.meta.name}</h1>
1266
- {typedSpec.meta.description && (
1267
- <p className="text-lg text-muted-foreground mt-2">{typedSpec.meta.description}</p>
1268
- )}
1269
- {typedSpec.meta.version && (
1270
- <p className="text-sm text-muted-foreground">v{typedSpec.meta.version}</p>
1271
- )}
1272
- </header>
1273
-
1274
- {functions.length > 0 && (
1275
- <section className="mb-12">
1276
- <h2 className="text-2xl font-bold mb-6">Functions</h2>
1277
- {functions.map((exp) => (
1278
- <ExportSection key={exp.id} exp={exp} />
1279
- ))}
1280
- </section>
1281
- )}
1282
-
1283
- {classes.length > 0 && (
1284
- <section className="mb-12">
1285
- <h2 className="text-2xl font-bold mb-6">Classes</h2>
1286
- {classes.map((exp) => (
1287
- <ExportSection key={exp.id} exp={exp} />
1288
- ))}
1289
- </section>
1290
- )}
1291
-
1292
- {interfaces.length > 0 && (
1293
- <section className="mb-12">
1294
- <h2 className="text-2xl font-bold mb-6">Types & Interfaces</h2>
1295
- {interfaces.map((exp) => (
1296
- <ExportSection key={exp.id} exp={exp} />
1297
- ))}
1298
- </section>
1299
- )}
1300
-
1301
- {variables.length > 0 && (
1302
- <section className="mb-12">
1303
- <h2 className="text-2xl font-bold mb-6">Variables</h2>
1304
- {variables.map((exp) => (
1305
- <ExportSection key={exp.id} exp={exp} />
1306
- ))}
1307
- </section>
1308
- )}
1309
-
1310
- {enums.length > 0 && (
1311
- <section className="mb-12">
1312
- <h2 className="text-2xl font-bold mb-6">Enums</h2>
1313
- {enums.map((exp) => (
1314
- <ExportSection key={exp.id} exp={exp} />
1315
- ))}
1316
- </section>
1317
- )}
1318
- </div>
1319
- );
1320
- }
1321
-
1322
- export { spec };
1323
- `;
1324
- }
1325
- function generateIndexLayout(spec, componentsPath) {
1326
- const pkgName = spec.meta.name;
1327
- return `'use client';
1328
-
1329
- import type { OpenPkg } from '@openpkg-ts/spec';
1330
- import spec from './openpkg.json';
1331
-
1332
- // Add the export-card component: openpkg docs add export-card
1333
- // import { ExportCard } from '${componentsPath}/export-card';
1334
-
1335
- /**
1336
- * API Reference Index Page for ${pkgName}
1337
- *
1338
- * Links to individual export pages. Best with file-based routing.
1339
- * Customize the card component and links to match your docs.
1340
- */
1341
- export default function APIReferenceIndex() {
1342
- const typedSpec = spec as OpenPkg;
1343
- const exports = typedSpec.exports;
1344
-
1345
- // Group exports by kind
1346
- const groups = [
1347
- { title: 'Functions', items: exports.filter((e) => e.kind === 'function') },
1348
- { title: 'Classes', items: exports.filter((e) => e.kind === 'class') },
1349
- { title: 'Types & Interfaces', items: exports.filter((e) => e.kind === 'interface' || e.kind === 'type') },
1350
- { title: 'Variables', items: exports.filter((e) => e.kind === 'variable') },
1351
- { title: 'Enums', items: exports.filter((e) => e.kind === 'enum') },
1352
- ].filter((g) => g.items.length > 0);
1353
-
1354
- return (
1355
- <div className="max-w-4xl mx-auto px-4 py-8">
1356
- <header className="mb-12">
1357
- <h1 className="text-3xl font-bold">{typedSpec.meta.name}</h1>
1358
- {typedSpec.meta.description && (
1359
- <p className="text-lg text-muted-foreground mt-2">{typedSpec.meta.description}</p>
1360
- )}
1361
- </header>
1362
-
1363
- {groups.map((group) => (
1364
- <section key={group.title} className="mb-12">
1365
- <h2 className="text-2xl font-bold mb-6">{group.title}</h2>
1366
- <div className="grid gap-4 md:grid-cols-2">
1367
- {group.items.map((exp) => (
1368
- // Replace with ExportCard once installed:
1369
- // <ExportCard key={exp.id} export={exp} href={\`/api/\${exp.name}\`} />
1370
- <a
1371
- key={exp.id}
1372
- href={\`/api/\${exp.name}\`}
1373
- className="block p-4 border rounded-lg hover:bg-muted transition-colors"
1374
- >
1375
- <h3 className="font-semibold">{exp.name}</h3>
1376
- <p className="text-sm text-muted-foreground line-clamp-2">
1377
- {exp.description || 'No description'}
1378
- </p>
1379
- <span className="text-xs bg-muted px-2 py-1 rounded mt-2 inline-block">
1380
- {exp.kind}
1381
- </span>
1382
- </a>
1383
- ))}
1384
- </div>
1385
- </section>
1386
- ))}
1387
- </div>
1388
- );
1389
- }
1390
-
1391
- export { spec };
1392
- `;
1393
- }
1394
- async function toReact(spec, options) {
1395
- const { outDir, variant = "full", componentsPath = "@/components/api" } = options;
1396
- if (!fs3.existsSync(outDir)) {
1397
- fs3.mkdirSync(outDir, { recursive: true });
1398
- }
1399
- const specPath = path2.join(outDir, "openpkg.json");
1400
- fs3.writeFileSync(specPath, JSON.stringify(spec, null, 2));
1401
- const layoutContent = variant === "index" ? generateIndexLayout(spec, componentsPath) : generateFullLayout(spec, componentsPath);
1402
- const layoutPath = path2.join(outDir, "page.tsx");
1403
- fs3.writeFileSync(layoutPath, layoutContent);
1404
- }
1405
- function toReactString(spec, options = {}) {
1406
- const { variant = "full", componentsPath = "@/components/api" } = options;
1407
- return variant === "index" ? generateIndexLayout(spec, componentsPath) : generateFullLayout(spec, componentsPath);
1408
- }
1409
1194
  // src/primitives/filter.ts
1410
1195
  function matchesExport(exp, criteria) {
1411
1196
  if (criteria.kinds && criteria.kinds.length > 0) {
@@ -1513,6 +1298,7 @@ function filterSpec(spec, criteria) {
1513
1298
  import ts11 from "typescript";
1514
1299
 
1515
1300
  // src/ast/utils.ts
1301
+ import * as path2 from "node:path";
1516
1302
  import ts from "typescript";
1517
1303
  function parseExamplesFromTags(tags) {
1518
1304
  const examples = [];
@@ -1657,8 +1443,10 @@ function getJSDocComment(node, symbol, checker) {
1657
1443
  }
1658
1444
  function getSourceLocation(node, sourceFile) {
1659
1445
  const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
1446
+ const relative2 = path2.relative(process.cwd(), sourceFile.fileName);
1447
+ const file = relative2.startsWith("..") ? sourceFile.fileName : relative2;
1660
1448
  return {
1661
- file: sourceFile.fileName,
1449
+ file,
1662
1450
  line: line + 1
1663
1451
  };
1664
1452
  }
@@ -1828,7 +1616,7 @@ function getExportKind(declaration, type) {
1828
1616
  }
1829
1617
 
1830
1618
  // src/compiler/program.ts
1831
- import * as fs4 from "node:fs";
1619
+ import * as fs3 from "node:fs";
1832
1620
  import * as path3 from "node:path";
1833
1621
  import ts2 from "typescript";
1834
1622
  function isJsFile(file) {
@@ -1850,6 +1638,22 @@ var DEFAULT_COMPILER_OPTIONS = {
1850
1638
  declaration: true,
1851
1639
  moduleResolution: ts2.ModuleResolutionKind.NodeJs
1852
1640
  };
1641
+ function resolveWorkspaceEntry(pkgDir) {
1642
+ const candidates = [
1643
+ path3.join(pkgDir, "src", "index.ts"),
1644
+ path3.join(pkgDir, "src", "index.tsx"),
1645
+ path3.join(pkgDir, "index.ts")
1646
+ ];
1647
+ try {
1648
+ const pkg = JSON.parse(fs3.readFileSync(path3.join(pkgDir, "package.json"), "utf-8"));
1649
+ for (const field of [pkg.types, pkg.typings]) {
1650
+ if (typeof field === "string") {
1651
+ candidates.push(path3.resolve(pkgDir, field));
1652
+ }
1653
+ }
1654
+ } catch {}
1655
+ return candidates.find((c) => fs3.existsSync(c));
1656
+ }
1853
1657
  function resolveProjectReferences(configPath, parsedConfig) {
1854
1658
  const additionalFiles = [];
1855
1659
  if (!parsedConfig.projectReferences?.length) {
@@ -1858,8 +1662,8 @@ function resolveProjectReferences(configPath, parsedConfig) {
1858
1662
  const configDir = path3.dirname(configPath);
1859
1663
  for (const ref of parsedConfig.projectReferences) {
1860
1664
  const refPath = path3.resolve(configDir, ref.path);
1861
- const refConfigPath = fs4.existsSync(path3.join(refPath, "tsconfig.json")) ? path3.join(refPath, "tsconfig.json") : refPath;
1862
- if (!fs4.existsSync(refConfigPath))
1665
+ const refConfigPath = fs3.existsSync(path3.join(refPath, "tsconfig.json")) ? path3.join(refPath, "tsconfig.json") : refPath;
1666
+ if (!fs3.existsSync(refConfigPath))
1863
1667
  continue;
1864
1668
  const refConfigFile = ts2.readConfigFile(refConfigPath, ts2.sys.readFile);
1865
1669
  if (refConfigFile.error)
@@ -1898,9 +1702,9 @@ function buildWorkspaceMap(baseDir) {
1898
1702
  let workspaceGlobs = [];
1899
1703
  for (let i = 0;i < 10; i++) {
1900
1704
  const pnpmPath = path3.join(currentDir, "pnpm-workspace.yaml");
1901
- if (fs4.existsSync(pnpmPath)) {
1705
+ if (fs3.existsSync(pnpmPath)) {
1902
1706
  try {
1903
- const yamlContent = fs4.readFileSync(pnpmPath, "utf-8");
1707
+ const yamlContent = fs3.readFileSync(pnpmPath, "utf-8");
1904
1708
  workspaceGlobs = parsePnpmWorkspace(yamlContent);
1905
1709
  if (workspaceGlobs.length > 0) {
1906
1710
  rootDir = currentDir;
@@ -1909,9 +1713,9 @@ function buildWorkspaceMap(baseDir) {
1909
1713
  } catch {}
1910
1714
  }
1911
1715
  const pkgPath = path3.join(currentDir, "package.json");
1912
- if (fs4.existsSync(pkgPath)) {
1716
+ if (fs3.existsSync(pkgPath)) {
1913
1717
  try {
1914
- const pkg = JSON.parse(fs4.readFileSync(pkgPath, "utf-8"));
1718
+ const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
1915
1719
  if (pkg.workspaces) {
1916
1720
  rootDir = currentDir;
1917
1721
  workspaceGlobs = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces?.packages || [];
@@ -1929,32 +1733,30 @@ function buildWorkspaceMap(baseDir) {
1929
1733
  const packages = new Map;
1930
1734
  for (const glob of workspaceGlobs) {
1931
1735
  const globDir = path3.join(rootDir, glob.replace(/\/\*$/, ""));
1932
- if (!fs4.existsSync(globDir) || !fs4.statSync(globDir).isDirectory())
1736
+ if (!fs3.existsSync(globDir) || !fs3.statSync(globDir).isDirectory())
1933
1737
  continue;
1934
- const entries = fs4.readdirSync(globDir, { withFileTypes: true });
1738
+ const entries = fs3.readdirSync(globDir, { withFileTypes: true });
1935
1739
  for (const entry of entries) {
1936
1740
  if (!entry.isDirectory())
1937
1741
  continue;
1938
1742
  const pkgDir = path3.join(globDir, entry.name);
1939
1743
  const pkgJsonPath = path3.join(pkgDir, "package.json");
1940
- if (!fs4.existsSync(pkgJsonPath))
1744
+ if (!fs3.existsSync(pkgJsonPath))
1941
1745
  continue;
1942
1746
  try {
1943
- const pkg = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
1747
+ const pkg = JSON.parse(fs3.readFileSync(pkgJsonPath, "utf-8"));
1944
1748
  if (pkg.name) {
1945
- const srcDir = fs4.existsSync(path3.join(pkgDir, "src")) ? path3.join(pkgDir, "src") : pkgDir;
1946
- packages.set(pkg.name, srcDir);
1749
+ packages.set(pkg.name, pkgDir);
1947
1750
  }
1948
1751
  } catch {}
1949
1752
  }
1950
1753
  }
1951
1754
  return packages.size > 0 ? { packages, rootDir } : undefined;
1952
1755
  }
1953
- function createProgram({
1954
- entryFile,
1955
- baseDir = path3.dirname(entryFile),
1956
- content
1957
- }) {
1756
+ function createProgram(options) {
1757
+ const { content } = options;
1758
+ const entryFile = path3.resolve(options.entryFile);
1759
+ const baseDir = path3.resolve(options.baseDir ?? path3.dirname(entryFile));
1958
1760
  let configPath = ts2.findConfigFile(baseDir, ts2.sys.fileExists, "tsconfig.json");
1959
1761
  if (!configPath) {
1960
1762
  configPath = ts2.findConfigFile(baseDir, ts2.sys.fileExists, "jsconfig.json");
@@ -1987,20 +1789,20 @@ function createProgram({
1987
1789
  let inMemorySource;
1988
1790
  if (workspaceMap) {
1989
1791
  const originalResolveModuleNames = compilerHost.resolveModuleNames?.bind(compilerHost);
1990
- compilerHost.resolveModuleNames = (moduleNames, containingFile, _reusedNames, redirectedReference, options) => {
1792
+ compilerHost.resolveModuleNames = (moduleNames, containingFile, _reusedNames, redirectedReference, options2) => {
1991
1793
  return moduleNames.map((moduleName) => {
1992
- const srcDir = workspaceMap.packages.get(moduleName);
1993
- if (srcDir) {
1994
- const indexFile = path3.join(srcDir, "index.ts");
1995
- if (fs4.existsSync(indexFile)) {
1996
- return { resolvedFileName: indexFile, isExternalLibraryImport: false };
1794
+ const pkgDir = workspaceMap.packages.get(moduleName);
1795
+ if (pkgDir) {
1796
+ const entryPath = resolveWorkspaceEntry(pkgDir);
1797
+ if (entryPath) {
1798
+ return { resolvedFileName: entryPath, isExternalLibraryImport: false };
1997
1799
  }
1998
1800
  }
1999
1801
  if (originalResolveModuleNames) {
2000
- const result = originalResolveModuleNames([moduleName], containingFile, _reusedNames, redirectedReference, options);
1802
+ const result = originalResolveModuleNames([moduleName], containingFile, _reusedNames, redirectedReference, options2);
2001
1803
  return result[0];
2002
1804
  }
2003
- const resolved = ts2.resolveModuleName(moduleName, containingFile, options, compilerHost);
1805
+ const resolved = ts2.resolveModuleName(moduleName, containingFile, options2, compilerHost);
2004
1806
  return resolved.resolvedModule;
2005
1807
  });
2006
1808
  };
@@ -2108,6 +1910,18 @@ var BUILTIN_GENERICS = new Set([
2108
1910
  "InstanceType",
2109
1911
  "Awaited"
2110
1912
  ]);
1913
+ var RESOLVED_UTILITY_TYPES = new Set([
1914
+ "Partial",
1915
+ "Required",
1916
+ "Readonly",
1917
+ "Pick",
1918
+ "Omit",
1919
+ "Record",
1920
+ "Exclude",
1921
+ "Extract",
1922
+ "NonNullable",
1923
+ "Awaited"
1924
+ ]);
2111
1925
  var BUILTIN_TYPES = new Set([
2112
1926
  "Date",
2113
1927
  "RegExp",
@@ -2533,6 +2347,13 @@ function buildSchemaInternal(type, checker, ctx) {
2533
2347
  if (BUILTIN_TYPES.has(name)) {
2534
2348
  return { $ref: `#/types/${name}` };
2535
2349
  }
2350
+ if (RESOLVED_UTILITY_TYPES.has(name) && type.flags & ts3.TypeFlags.Object) {
2351
+ const props = type.getProperties();
2352
+ const hasIndex = checker.getIndexInfosOfType(type).length > 0;
2353
+ if (props.length > 0 || hasIndex) {
2354
+ return buildObjectSchema(props, checker, ctx, type);
2355
+ }
2356
+ }
2536
2357
  if (isBuiltinGeneric(name) || !name.startsWith("__")) {
2537
2358
  const packageOrigin = getTypeOrigin(type, checker);
2538
2359
  if (ctx) {
@@ -2647,7 +2468,11 @@ function buildObjectSchema(properties, checker, ctx, originalType) {
2647
2468
  properties: props,
2648
2469
  ...required.length > 0 ? { required } : {}
2649
2470
  };
2650
- if (Object.keys(props).length === 0 && originalType) {
2471
+ const stringIndex = originalType ? checker.getIndexInfosOfType(originalType).find((i) => i.keyType.flags & ts3.TypeFlags.String) : undefined;
2472
+ if (stringIndex) {
2473
+ schema.additionalProperties = buildSchema(stringIndex.type, checker, ctx);
2474
+ }
2475
+ if (Object.keys(props).length === 0 && originalType && !stringIndex) {
2651
2476
  setSchemaExtension(schema, "x-ts-type", checker.typeToString(originalType));
2652
2477
  }
2653
2478
  return schema;
@@ -3162,7 +2987,8 @@ class TypeRegistry {
3162
2987
  }
3163
2988
  buildObjectSchemaFromProperties(type, checker, ctx) {
3164
2989
  const properties = type.getProperties();
3165
- if (properties.length === 0) {
2990
+ const stringIndex = checker.getIndexInfosOfType(type).find((i) => i.keyType.flags & ts5.TypeFlags.String);
2991
+ if (properties.length === 0 && !stringIndex) {
3166
2992
  return { type: checker.typeToString(type) };
3167
2993
  }
3168
2994
  const props = {};
@@ -3195,7 +3021,8 @@ class TypeRegistry {
3195
3021
  return {
3196
3022
  type: "object",
3197
3023
  properties: props,
3198
- ...required.length > 0 ? { required } : {}
3024
+ ...required.length > 0 ? { required } : {},
3025
+ ...stringIndex ? { additionalProperties: buildSchema(stringIndex.type, checker, ctx) } : {}
3199
3026
  };
3200
3027
  }
3201
3028
  }
@@ -4939,7 +4766,7 @@ function getDescriptionPreview(symbol, checker) {
4939
4766
  return `${firstLine.slice(0, 77)}...`;
4940
4767
  }
4941
4768
  // src/builder/spec-builder.ts
4942
- import * as fs7 from "node:fs";
4769
+ import * as fs6 from "node:fs";
4943
4770
  import * as path8 from "node:path";
4944
4771
  import { SCHEMA_URL, SCHEMA_VERSION } from "@openpkg-ts/spec";
4945
4772
  import ts16 from "typescript";
@@ -4976,7 +4803,7 @@ function resolveExportTarget2(symbol, checker) {
4976
4803
 
4977
4804
  // src/schema/standard-schema.ts
4978
4805
  import { spawn, spawnSync } from "node:child_process";
4979
- import * as fs5 from "node:fs";
4806
+ import * as fs4 from "node:fs";
4980
4807
  import * as os from "node:os";
4981
4808
  import * as path5 from "node:path";
4982
4809
  var MAX_BUFFER_SIZE = 10 * 1024 * 1024;
@@ -5232,14 +5059,14 @@ async function extractStandardSchemasFromTs(tsFilePath, options = {}) {
5232
5059
  result.errors.push("No TypeScript runtime available. Install bun, tsx, or ts-node, or use Node 22+.");
5233
5060
  return result;
5234
5061
  }
5235
- if (!fs5.existsSync(tsFilePath)) {
5062
+ if (!fs4.existsSync(tsFilePath)) {
5236
5063
  result.errors.push(`TypeScript file not found: ${tsFilePath}`);
5237
5064
  return result;
5238
5065
  }
5239
5066
  const tempDir = os.tmpdir();
5240
5067
  const workerPath = path5.join(tempDir, `openpkg-extract-worker-${Date.now()}.ts`);
5241
5068
  try {
5242
- fs5.writeFileSync(workerPath, TS_WORKER_SCRIPT);
5069
+ fs4.writeFileSync(workerPath, TS_WORKER_SCRIPT);
5243
5070
  const optionsJson = JSON.stringify({ target, libraryOptions });
5244
5071
  const args = [...runtime.args, workerPath, tsFilePath, optionsJson];
5245
5072
  return await new Promise((resolve2) => {
@@ -5270,7 +5097,7 @@ async function extractStandardSchemasFromTs(tsFilePath, options = {}) {
5270
5097
  });
5271
5098
  child.on("close", (code) => {
5272
5099
  try {
5273
- fs5.unlinkSync(workerPath);
5100
+ fs4.unlinkSync(workerPath);
5274
5101
  } catch (cleanupErr) {
5275
5102
  if (cleanupErr?.code !== "ENOENT") {
5276
5103
  result.warnings.push({ code: "CLEANUP_FAILED", message: String(cleanupErr) });
@@ -5324,7 +5151,7 @@ async function extractStandardSchemasFromTs(tsFilePath, options = {}) {
5324
5151
  });
5325
5152
  child.on("error", (err) => {
5326
5153
  try {
5327
- fs5.unlinkSync(workerPath);
5154
+ fs4.unlinkSync(workerPath);
5328
5155
  } catch (cleanupErr) {
5329
5156
  if (cleanupErr?.code !== "ENOENT") {
5330
5157
  result.warnings.push({ code: "CLEANUP_FAILED", message: String(cleanupErr) });
@@ -5336,7 +5163,7 @@ async function extractStandardSchemasFromTs(tsFilePath, options = {}) {
5336
5163
  });
5337
5164
  } catch (e) {
5338
5165
  try {
5339
- fs5.unlinkSync(workerPath);
5166
+ fs4.unlinkSync(workerPath);
5340
5167
  } catch (cleanupErr) {
5341
5168
  if (cleanupErr?.code !== "ENOENT") {
5342
5169
  result.warnings.push({ code: "CLEANUP_FAILED", message: String(cleanupErr) });
@@ -5349,10 +5176,10 @@ async function extractStandardSchemasFromTs(tsFilePath, options = {}) {
5349
5176
  function readTsconfigOutDir(baseDir) {
5350
5177
  const tsconfigPath = path5.join(baseDir, "tsconfig.json");
5351
5178
  try {
5352
- if (!fs5.existsSync(tsconfigPath)) {
5179
+ if (!fs4.existsSync(tsconfigPath)) {
5353
5180
  return null;
5354
5181
  }
5355
- const content = fs5.readFileSync(tsconfigPath, "utf-8");
5182
+ const content = fs4.readFileSync(tsconfigPath, "utf-8");
5356
5183
  const stripped = content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
5357
5184
  const tsconfig = JSON.parse(stripped);
5358
5185
  if (tsconfig.compilerOptions?.outDir) {
@@ -5392,7 +5219,7 @@ function resolveCompiledPath(tsPath, baseDir) {
5392
5219
  }
5393
5220
  }
5394
5221
  for (const candidate of candidates) {
5395
- if (fs5.existsSync(candidate)) {
5222
+ if (fs4.existsSync(candidate)) {
5396
5223
  return candidate;
5397
5224
  }
5398
5225
  }
@@ -5405,7 +5232,7 @@ async function extractStandardSchemas(compiledJsPath, options = {}) {
5405
5232
  errors: [],
5406
5233
  warnings: []
5407
5234
  };
5408
- if (!fs5.existsSync(compiledJsPath)) {
5235
+ if (!fs4.existsSync(compiledJsPath)) {
5409
5236
  result.errors.push(`Compiled JS not found: ${compiledJsPath}`);
5410
5237
  return result;
5411
5238
  }
@@ -5521,7 +5348,7 @@ async function extractStandardSchemasFromProject(entryFile, baseDir, options = {
5521
5348
  }
5522
5349
 
5523
5350
  // src/builder/external-resolver.ts
5524
- import * as fs6 from "node:fs";
5351
+ import * as fs5 from "node:fs";
5525
5352
  import * as path6 from "node:path";
5526
5353
  import picomatch from "picomatch";
5527
5354
  import ts14 from "typescript";
@@ -5561,9 +5388,9 @@ function findPackageJson(resolvedPath, packageName) {
5561
5388
  for (let i = 0;i < maxDepth; i++) {
5562
5389
  if (dir.endsWith(`node_modules/${packageDir}`)) {
5563
5390
  const pkgPath = path6.join(dir, "package.json");
5564
- if (fs6.existsSync(pkgPath)) {
5391
+ if (fs5.existsSync(pkgPath)) {
5565
5392
  try {
5566
- return JSON.parse(fs6.readFileSync(pkgPath, "utf-8"));
5393
+ return JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
5567
5394
  } catch {
5568
5395
  return;
5569
5396
  }
@@ -6600,8 +6427,8 @@ async function getPackageMeta(entryFile, baseDir) {
6600
6427
  while (dir !== path8.dirname(dir)) {
6601
6428
  const pkgPath = path8.join(dir, "package.json");
6602
6429
  try {
6603
- if (fs7.existsSync(pkgPath)) {
6604
- const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
6430
+ if (fs6.existsSync(pkgPath)) {
6431
+ const pkg = JSON.parse(fs6.readFileSync(pkgPath, "utf-8"));
6605
6432
  return {
6606
6433
  name: pkg.name ?? path8.basename(dir),
6607
6434
  version: pkg.version,
@@ -6638,8 +6465,6 @@ export {
6638
6465
  typeboxAdapter,
6639
6466
  toSearchIndexJSON,
6640
6467
  toSearchIndex,
6641
- toReactString,
6642
- toReact,
6643
6468
  toPagefindRecords,
6644
6469
  toNavigation,
6645
6470
  toMarkdown,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openpkg-ts/sdk",
3
- "version": "0.37.1",
3
+ "version": "0.39.0",
4
4
  "description": "TypeScript API extraction SDK - programmatic primitives for OpenPkg specs",
5
5
  "keywords": [
6
6
  "openpkg",
@@ -39,6 +39,7 @@
39
39
  "lint": "biome check src/",
40
40
  "lint:fix": "biome check --write src/",
41
41
  "format": "biome format --write src/",
42
+ "typecheck": "tsc --noEmit -p .",
42
43
  "test": "bun test"
43
44
  },
44
45
  "dependencies": {
@@ -57,7 +58,11 @@
57
58
  "devDependencies": {
58
59
  "@types/bun": "latest",
59
60
  "@types/node": "^20.0.0",
60
- "bunup": "^0.16.20"
61
+ "@types/picomatch": "4.0.3",
62
+ "ajv": "^8.17.1",
63
+ "ajv-formats": "^3.0.1",
64
+ "bunup": "^0.16.20",
65
+ "zod": "^4.3.6"
61
66
  },
62
67
  "publishConfig": {
63
68
  "access": "public"