agent-readable-ts 0.1.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.
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Specifier parsing, type-declaration loading, and on-demand package
3
+ * acquisition for the CLI.
4
+ *
5
+ * Everything here is side-effect-light and free of `process.exit`: functions
6
+ * that hit an unrecoverable condition throw, so the CLI entry point can convert
7
+ * the error to a message and the logic stays unit-testable.
8
+ */
9
+ import { parseTypeSignatures } from "./source-types.js";
10
+ import { pathToFileURL } from "node:url";
11
+ import { join } from "node:path";
12
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, rmSync } from "node:fs";
13
+ import { createRequire } from "node:module";
14
+ import { execFileSync } from "node:child_process";
15
+ import { homedir } from "node:os";
16
+ import { randomUUID } from "node:crypto";
17
+ export const CACHE_DIR = process.env.AGENT_READABLE_CACHE ?? join(homedir(), ".cache", "agent-readable-ts");
18
+ // ── specifier parsing ──────────────────────────────────────────────────────────
19
+ export function parseSpecifier(specifier) {
20
+ const colonIdx = specifier.lastIndexOf(":");
21
+ // Ignore a Windows drive-letter colon (e.g. "C:\path") so paths without an
22
+ // explicit export are not split at the drive letter.
23
+ if (colonIdx <= 1) {
24
+ return { modulePath: specifier, exportName: null };
25
+ }
26
+ return { modulePath: specifier.slice(0, colonIdx), exportName: specifier.slice(colonIdx + 1) };
27
+ }
28
+ export function isBarePackageName(modulePath) {
29
+ if (modulePath.startsWith("."))
30
+ return false;
31
+ if (modulePath.startsWith("/"))
32
+ return false;
33
+ if (modulePath.startsWith("node:"))
34
+ return false;
35
+ if (/\.[a-zA-Z]{1,4}$/.test(modulePath))
36
+ return false;
37
+ return true;
38
+ }
39
+ export function splitPackageSpec(spec) {
40
+ // Separate an install spec (which may carry a version) from the import name.
41
+ // Scoped: "@scope/pkg@1.2.3" → name "@scope/pkg". Plain: "pkg@1" → name "pkg".
42
+ const at = spec.startsWith("@") ? spec.indexOf("@", 1) : spec.indexOf("@");
43
+ return at > 0 ? { name: spec.slice(0, at), install: spec } : { name: spec, install: spec };
44
+ }
45
+ // ── export walking ─────────────────────────────────────────────────────────────
46
+ export function walkExportPath(target, exportPath) {
47
+ let current = target;
48
+ for (const part of exportPath.split(".")) {
49
+ if (current === null || current === undefined) {
50
+ throw new Error(`Cannot resolve "${part}" on null/undefined while walking "${exportPath}".`);
51
+ }
52
+ const obj = current;
53
+ if (!(part in obj)) {
54
+ const available = Object.keys(obj).join(", ");
55
+ throw new Error(`Export "${part}" not found. Available exports: ${available || "(none)"}`);
56
+ }
57
+ current = obj[part];
58
+ }
59
+ return current;
60
+ }
61
+ // ── type signature loading ─────────────────────────────────────────────────────
62
+ function parseFile(path, exportName) {
63
+ try {
64
+ const source = readFileSync(path, "utf-8");
65
+ return parseTypeSignatures(source, exportName, path) ?? undefined;
66
+ }
67
+ catch {
68
+ return undefined;
69
+ }
70
+ }
71
+ function adjacentDtsPath(absolutePath) {
72
+ if (absolutePath.endsWith(".js"))
73
+ return absolutePath.replace(/\.js$/, ".d.ts");
74
+ if (absolutePath.endsWith(".mjs"))
75
+ return absolutePath.replace(/\.mjs$/, ".d.mts");
76
+ if (absolutePath.endsWith(".cjs"))
77
+ return absolutePath.replace(/\.cjs$/, ".d.cts");
78
+ return null;
79
+ }
80
+ export function loadTypeSigs(absolutePath, exportName) {
81
+ // Declaration files: parse directly.
82
+ if (absolutePath.endsWith(".d.ts") || absolutePath.endsWith(".d.mts") || absolutePath.endsWith(".d.cts")) {
83
+ return parseFile(absolutePath, exportName);
84
+ }
85
+ // Source files (.ts excluding .d.ts, or .tsx): parse directly.
86
+ if (absolutePath.endsWith(".tsx") || (absolutePath.endsWith(".ts") && !absolutePath.endsWith(".d.ts"))) {
87
+ return parseFile(absolutePath, exportName);
88
+ }
89
+ // .js/.mjs/.cjs: look for an adjacent declaration file.
90
+ const dtsPath = adjacentDtsPath(absolutePath);
91
+ return dtsPath ? parseFile(dtsPath, exportName) : undefined;
92
+ }
93
+ // ── export list formatting ─────────────────────────────────────────────────────
94
+ export function formatExportList(packageName, exports, typeSigs) {
95
+ const lines = exports.map((e) => {
96
+ if (e.kind === "class")
97
+ return `- \`${e.name}\` class`;
98
+ if (e.kind === "function") {
99
+ const sig = typeSigs?.get(e.name);
100
+ if (sig) {
101
+ const params = sig.params.map((p) => `${p.name}: ${p.type}`).join(", ");
102
+ const ret = sig.returnType ? `: ${sig.returnType}` : "";
103
+ return `- \`${e.name}(${params})${ret}\` function`;
104
+ }
105
+ return `- \`${e.name}(...)\` function`;
106
+ }
107
+ if (e.kind === "default")
108
+ return `- \`${e.name}\` (default export)`;
109
+ return `- \`${e.name}\` object`;
110
+ });
111
+ return `# ${packageName}\n\n## Exports\n\n${lines.join("\n")}\n`;
112
+ }
113
+ // ── on-demand package acquisition ───────────────────────────────────────────────
114
+ export function isModuleNotFound(err) {
115
+ const code = err.code;
116
+ return code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND";
117
+ }
118
+ export function isInstalledIn(name, dir) {
119
+ const req = createRequire(join(dir, "__resolve__.js"));
120
+ try {
121
+ req.resolve(name);
122
+ return true;
123
+ }
124
+ catch {
125
+ // ESM-only packages can refuse `require.resolve`; fall back to package.json.
126
+ }
127
+ try {
128
+ req.resolve(`${name}/package.json`);
129
+ return true;
130
+ }
131
+ catch {
132
+ return false;
133
+ }
134
+ }
135
+ export function ensureCacheInstall(name, install, dir = CACHE_DIR) {
136
+ mkdirSync(dir, { recursive: true });
137
+ const pkgJson = join(dir, "package.json");
138
+ if (!existsSync(pkgJson)) {
139
+ writeFileSync(pkgJson, JSON.stringify({ name: "agent-readable-cache", private: true }) + "\n");
140
+ }
141
+ if (!isInstalledIn(name, dir)) {
142
+ process.stderr.write(`Installing ${install} on demand into ${dir} ...\n`);
143
+ try {
144
+ // Save into the cache's own package.json so previously fetched packages are
145
+ // not pruned as "extraneous" when a different package is installed later.
146
+ execFileSync("npm", ["install", install, "--prefix", dir, "--save", "--no-audit", "--no-fund", "--loglevel=error"], { stdio: ["ignore", "ignore", "inherit"] });
147
+ }
148
+ catch (err) {
149
+ throw new Error(`Failed to install "${install}": ${err instanceof Error ? err.message : String(err)}`);
150
+ }
151
+ }
152
+ return dir;
153
+ }
154
+ function resolveEntry(name, dir) {
155
+ try {
156
+ return createRequire(join(dir, "__resolve__.js")).resolve(name);
157
+ }
158
+ catch {
159
+ return null;
160
+ }
161
+ }
162
+ export async function importFromDir(name, dir) {
163
+ // A loader placed in `dir` resolves the bare specifier against dir/node_modules;
164
+ // dynamic import transparently handles both CJS and ESM packages.
165
+ const loaderPath = join(dir, `.arload-${randomUUID()}.mjs`);
166
+ writeFileSync(loaderPath, `export default await import(${JSON.stringify(name)});\n`);
167
+ try {
168
+ const loaded = (await import(pathToFileURL(loaderPath).href));
169
+ return loaded.default;
170
+ }
171
+ catch (err) {
172
+ // Some package layouts (CJS, no "exports" map) trip ESM bare-specifier
173
+ // resolution, which falls back to a non-existent index.js. Resolve the real
174
+ // entry via Node's CJS resolver and import that file directly instead.
175
+ const entry = resolveEntry(name, dir);
176
+ if (!entry)
177
+ throw err;
178
+ return (await import(pathToFileURL(entry).href));
179
+ }
180
+ finally {
181
+ rmSync(loaderPath, { force: true });
182
+ }
183
+ }
184
+ export async function loadPackage(spec, cacheDir = CACHE_DIR) {
185
+ const { name, install } = splitPackageSpec(spec);
186
+ // Prefer a copy already resolvable from the current project.
187
+ try {
188
+ const mod = (await import(name));
189
+ return { mod, typesDir: process.cwd() };
190
+ }
191
+ catch (err) {
192
+ if (!isModuleNotFound(err)) {
193
+ throw new Error(`Cannot import package "${name}": ${err instanceof Error ? err.message : String(err)}`);
194
+ }
195
+ }
196
+ // Not installed locally: fetch on demand into the cache, then load from there.
197
+ const dir = ensureCacheInstall(name, install, cacheDir);
198
+ const mod = await importFromDir(name, dir);
199
+ return { mod, typesDir: dir };
200
+ }
201
+ //# sourceMappingURL=packages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packages.js","sourceRoot":"","sources":["../../src/packages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Agent-documentation protocols.
3
+ *
4
+ * A target may opt into either protocol independently:
5
+ * - {@link AgentHelper} is full replacement — its return value IS the output.
6
+ * - {@link AgentNoter} is additive — its return value is appended to auto-docs.
7
+ *
8
+ * The type guards here are the only place that decides whether a runtime value
9
+ * implements a protocol, so both the orchestrator and the extractor agree.
10
+ */
11
+ /** Full-replacement protocol. Returned string IS the output verbatim. */
12
+ export interface AgentHelper {
13
+ agentHelp(): string;
14
+ }
15
+ /** Additive protocol. Returned string is appended to auto-generated docs. */
16
+ export interface AgentNoter {
17
+ agentNotes(): string;
18
+ }
19
+ export declare function hasAgentHelper(target: unknown): target is AgentHelper;
20
+ export declare function hasAgentNoter(target: unknown): target is AgentNoter;
21
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,yEAAyE;AACzE,MAAM,WAAW,WAAW;IAC1B,SAAS,IAAI,MAAM,CAAC;CACrB;AAED,6EAA6E;AAC7E,MAAM,WAAW,UAAU;IACzB,UAAU,IAAI,MAAM,CAAC;CACtB;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,WAAW,CAMrE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,UAAU,CAMnE"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Agent-documentation protocols.
3
+ *
4
+ * A target may opt into either protocol independently:
5
+ * - {@link AgentHelper} is full replacement — its return value IS the output.
6
+ * - {@link AgentNoter} is additive — its return value is appended to auto-docs.
7
+ *
8
+ * The type guards here are the only place that decides whether a runtime value
9
+ * implements a protocol, so both the orchestrator and the extractor agree.
10
+ */
11
+ export function hasAgentHelper(target) {
12
+ return (target !== null &&
13
+ target !== undefined &&
14
+ typeof target.agentHelp === "function");
15
+ }
16
+ export function hasAgentNoter(target) {
17
+ return (target !== null &&
18
+ target !== undefined &&
19
+ typeof target.agentNotes === "function");
20
+ }
21
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAYH,MAAM,UAAU,cAAc,CAAC,MAAe;IAC5C,OAAO,CACL,MAAM,KAAK,IAAI;QACf,MAAM,KAAK,SAAS;QACpB,OAAQ,MAAkC,CAAC,SAAS,KAAK,UAAU,CACpE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAe;IAC3C,OAAO,CACL,MAAM,KAAK,IAAI;QACf,MAAM,KAAK,SAAS;QACpB,OAAQ,MAAkC,CAAC,UAAU,KAAK,UAAU,CACrE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Markdown renderer for the {@link HelpDoc} model.
3
+ *
4
+ * This is the only place that knows about Markdown syntax. Adding another
5
+ * output format (plain text, HTML, JSON for MCP servers) means adding a sibling
6
+ * renderer that consumes the same `model.ts` types — the introspection layer
7
+ * stays untouched.
8
+ */
9
+ import type { HelpDoc } from "./model.js";
10
+ /**
11
+ * Render a {@link HelpDoc} as the structured Markdown `agentHelp()` returns.
12
+ *
13
+ * Sections are emitted in a fixed order and only when their data is present, so
14
+ * a class (members), a plain object (members), and a function (signature) all
15
+ * flow through the same path. A `null` `members` omits the Public API section;
16
+ * an empty array renders it with `(none)`.
17
+ */
18
+ export declare function renderMarkdown(doc: HelpDoc): string;
19
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/render.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAwB,MAAM,YAAY,CAAC;AAEhE;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAkBnD"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Markdown renderer for the {@link HelpDoc} model.
3
+ *
4
+ * This is the only place that knows about Markdown syntax. Adding another
5
+ * output format (plain text, HTML, JSON for MCP servers) means adding a sibling
6
+ * renderer that consumes the same `model.ts` types — the introspection layer
7
+ * stays untouched.
8
+ */
9
+ /**
10
+ * Render a {@link HelpDoc} as the structured Markdown `agentHelp()` returns.
11
+ *
12
+ * Sections are emitted in a fixed order and only when their data is present, so
13
+ * a class (members), a plain object (members), and a function (signature) all
14
+ * flow through the same path. A `null` `members` omits the Public API section;
15
+ * an empty array renders it with `(none)`.
16
+ */
17
+ export function renderMarkdown(doc) {
18
+ const sections = [`# ${doc.title}`];
19
+ if (doc.signature !== null) {
20
+ sections.push(`## Signature\n\n\`\`\`ts\n${doc.signature}\n\`\`\``);
21
+ }
22
+ if (doc.members !== null) {
23
+ sections.push(`## Public API\n\n${renderMembers(doc.members)}`);
24
+ }
25
+ sections.push(`## Agent usage rules\n\n${doc.usageRules.join("\n")}`);
26
+ for (const note of doc.notes) {
27
+ sections.push(renderNote(note));
28
+ }
29
+ return sections.join("\n\n") + "\n";
30
+ }
31
+ function renderMembers(members) {
32
+ if (members.length === 0)
33
+ return "- (none)";
34
+ return members
35
+ .map((m) => `- \`${m.name}${m.signature ?? ""}\` ${m.kind}`)
36
+ .join("\n");
37
+ }
38
+ function renderNote(note) {
39
+ let header = `## Notes from ${note.className}`;
40
+ if (note.inherited.length > 0) {
41
+ header += ` (extends ${note.inherited.join(", ")}; if notes conflict, these take precedence)`;
42
+ }
43
+ return `${header}\n\n${note.body}`;
44
+ }
45
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/render.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,GAAY;IACzC,MAAM,QAAQ,GAAa,CAAC,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;IAE9C,IAAI,GAAG,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;QAC3B,QAAQ,CAAC,IAAI,CAAC,6BAA6B,GAAG,CAAC,SAAS,UAAU,CAAC,CAAC;IACtE,CAAC;IAED,IAAI,GAAG,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QACzB,QAAQ,CAAC,IAAI,CAAC,oBAAoB,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,QAAQ,CAAC,IAAI,CAAC,2BAA2B,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEtE,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;AACtC,CAAC;AAED,SAAS,aAAa,CAAC,OAAqB;IAC1C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC;IAC5C,OAAO,OAAO;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,SAAS,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;SAC3D,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,SAAS,UAAU,CAAC,IAAc;IAChC,IAAI,MAAM,GAAG,iBAAiB,IAAI,CAAC,SAAS,EAAE,CAAC;IAC/C,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,aAAa,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,6CAA6C,CAAC;IAChG,CAAC;IACD,OAAO,GAAG,MAAM,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;AACrC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { TypeSignatureMap } from "./model.js";
2
+ export declare function resolvePackageTypesPath(packageName: string, fromDir?: string): string | null;
3
+ export interface ExportDescriptor {
4
+ name: string;
5
+ kind: "class" | "function" | "constant" | "default";
6
+ }
7
+ export declare function listPackageExports(source: string, filePath: string): ExportDescriptor[];
8
+ export declare function parseTypeSignatures(source: string, exportName: string | null, filePath?: string): TypeSignatureMap | null;
9
+ //# sourceMappingURL=source-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-types.d.ts","sourceRoot":"","sources":["../../src/source-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAiB,MAAM,YAAY,CAAC;AAmQlE,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAK3G;AAID,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;CACrD;AAmFD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAKvF;AAID,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,QAAQ,CAAC,EAAE,MAAM,GAChB,gBAAgB,GAAG,IAAI,CASzB"}
@@ -0,0 +1,298 @@
1
+ import { createRequire } from "node:module";
2
+ import { existsSync, readFileSync, statSync } from "node:fs";
3
+ import { dirname, resolve } from "node:path";
4
+ let _ts;
5
+ function getTs() {
6
+ if (_ts === undefined) {
7
+ try {
8
+ _ts = createRequire(import.meta.url)("typescript"); /* node:coverage disable */
9
+ }
10
+ catch {
11
+ _ts = null;
12
+ } /* node:coverage enable */
13
+ }
14
+ return _ts;
15
+ }
16
+ function extractParams(params) {
17
+ return params.map((p) => ({
18
+ name: p.name.getText(),
19
+ type: p.type ? p.type.getText().replace(/\s+/g, " ").trim() : "any",
20
+ }));
21
+ }
22
+ function visitClass(ts, node, result) {
23
+ const decl = node;
24
+ for (const member of decl.members) {
25
+ const m = member;
26
+ if (!m.name)
27
+ continue;
28
+ if (m.kind === ts.SyntaxKind.MethodDeclaration && !result.has(m.name.getText())) {
29
+ result.set(m.name.getText(), {
30
+ params: extractParams(m.parameters),
31
+ returnType: m.type ? m.type.getText().replace(/\s+/g, " ").trim() : null,
32
+ });
33
+ }
34
+ else if (m.kind === ts.SyntaxKind.GetAccessor && !result.has(m.name.getText())) {
35
+ result.set(m.name.getText(), {
36
+ params: [],
37
+ returnType: m.type ? m.type.getText().replace(/\s+/g, " ").trim() : null,
38
+ });
39
+ }
40
+ }
41
+ }
42
+ // ── module resolution helpers ──────────────────────────────────────────────────
43
+ function makeResolutionHost() {
44
+ return {
45
+ fileExists(path) {
46
+ return existsSync(path);
47
+ },
48
+ readFile(path) {
49
+ try {
50
+ return readFileSync(path, "utf-8"); /* node:coverage disable */
51
+ }
52
+ catch {
53
+ return undefined;
54
+ } /* node:coverage enable */
55
+ },
56
+ directoryExists(path) {
57
+ try {
58
+ return existsSync(path) && statSync(path).isDirectory(); /* node:coverage disable */
59
+ }
60
+ catch {
61
+ return false;
62
+ } /* node:coverage enable */
63
+ },
64
+ getCurrentDirectory() {
65
+ return process.cwd();
66
+ },
67
+ };
68
+ }
69
+ function tryTsResolve(ts, specifier, fromFile) {
70
+ const host = makeResolutionHost();
71
+ for (const kind of [ts.ModuleResolutionKind.Node10, ts.ModuleResolutionKind.Node16]) {
72
+ const result = ts.resolveModuleName(specifier, fromFile, { moduleResolution: kind }, host);
73
+ if (result.resolvedModule?.resolvedFileName) {
74
+ return result.resolvedModule.resolvedFileName;
75
+ }
76
+ }
77
+ return null;
78
+ }
79
+ function resolveNodeSpecifier(specifier, fromFile) {
80
+ const nodeMatch = /^node:(.+)$/.exec(specifier);
81
+ if (!nodeMatch)
82
+ return null;
83
+ const moduleName = nodeMatch[1];
84
+ for (const searchDir of getSearchDirs(fromFile)) {
85
+ const dtsPath = resolve(searchDir, "node_modules", "@types", "node", `${moduleName}.d.ts`);
86
+ if (existsSync(dtsPath))
87
+ return dtsPath;
88
+ }
89
+ return null;
90
+ }
91
+ function resolveRelativeSpecifier(specifier, fromFile) {
92
+ if (!specifier.startsWith("."))
93
+ return null;
94
+ const dir = dirname(fromFile);
95
+ for (const ext of [".d.ts", ".d.mts", ".ts", ".tsx"]) {
96
+ const p = resolve(dir, specifier + ext);
97
+ if (existsSync(p))
98
+ return p;
99
+ }
100
+ for (const ext of [".d.ts", ".d.mts"]) {
101
+ const p = resolve(dir, specifier, "index" + ext);
102
+ if (existsSync(p))
103
+ return p;
104
+ }
105
+ return null;
106
+ }
107
+ function resolveModulePath(ts, specifier, fromFile) {
108
+ return tryTsResolve(ts, specifier, fromFile)
109
+ ?? resolveNodeSpecifier(specifier, fromFile)
110
+ ?? resolveRelativeSpecifier(specifier, fromFile);
111
+ }
112
+ function getSearchDirs(fromFile) {
113
+ const dirs = [];
114
+ let dir = dirname(fromFile);
115
+ while (dir !== dirname(dir)) {
116
+ dirs.push(dir);
117
+ dir = dirname(dir);
118
+ }
119
+ dirs.push(dir);
120
+ return dirs;
121
+ }
122
+ // ── AST visitor helpers ────────────────────────────────────────────────────────
123
+ function collectClassAndFunc(api, node, exportName, classMap, result) {
124
+ const n = node;
125
+ if (api.isClassDeclaration(node) && n.name) {
126
+ classMap.set(n.name.getText(), node);
127
+ }
128
+ if (api.isFunctionDeclaration(node) && n.name) {
129
+ const fnName = n.name.getText();
130
+ if (!exportName || fnName === exportName) {
131
+ if (!result.has(fnName)) {
132
+ result.set(fnName, {
133
+ params: extractParams(n.parameters ?? []),
134
+ returnType: n.type ? n.type.getText().replace(/\s+/g, " ").trim() : null,
135
+ });
136
+ }
137
+ }
138
+ }
139
+ }
140
+ function collectModuleBody(api, node, visit) {
141
+ if (!api.isModuleDeclaration(node))
142
+ return;
143
+ const body = node.body;
144
+ if (body && api.isModuleBlock(body)) {
145
+ for (const stmt of body.statements) {
146
+ visit(stmt);
147
+ }
148
+ }
149
+ }
150
+ function collectReExport(api, node, exportName, filePath, visited, result) {
151
+ if (!api.isExportDeclaration(node))
152
+ return;
153
+ const n = node;
154
+ if (!n.moduleSpecifier || typeof n.moduleSpecifier.text !== "string" || !filePath)
155
+ return;
156
+ const resolvedPath = resolveModulePath(api, n.moduleSpecifier.text, filePath);
157
+ if (!resolvedPath || visited.has(resolvedPath))
158
+ return;
159
+ visited.add(resolvedPath);
160
+ try {
161
+ const resolvedSource = readFileSync(resolvedPath, "utf-8");
162
+ const resolvedSigs = parseSourceForTypes(api, resolvedSource, exportName, resolvedPath, visited);
163
+ for (const [key, value] of resolvedSigs) {
164
+ if (!result.has(key))
165
+ result.set(key, value);
166
+ }
167
+ }
168
+ catch {
169
+ // resolved file not readable, skip
170
+ }
171
+ }
172
+ function collectInheritanceChain(api, exportName, classMap, result) {
173
+ const targetClass = classMap.get(exportName);
174
+ if (!targetClass)
175
+ return;
176
+ const chainVisited = new Set();
177
+ let current = exportName;
178
+ while (current) {
179
+ const decl = classMap.get(current);
180
+ if (!decl || chainVisited.has(current))
181
+ break;
182
+ chainVisited.add(current);
183
+ visitClass(api, decl, result);
184
+ const cls = decl;
185
+ const parent = cls.heritageClauses?.[0]?.types?.[0]?.expression?.getText();
186
+ current = parent && classMap.has(parent) ? parent : "";
187
+ }
188
+ }
189
+ // ── main parsing ───────────────────────────────────────────────────────────────
190
+ function parseSourceForTypes(ts, source, exportName, filePath, visited) {
191
+ const sf = ts.createSourceFile(filePath ?? "input.ts", source, ts.ScriptTarget.Latest, true);
192
+ const result = new Map();
193
+ const api = ts;
194
+ const classMap = new Map();
195
+ function visit(node) {
196
+ collectClassAndFunc(api, node, exportName, classMap, result);
197
+ collectModuleBody(api, node, visit);
198
+ collectReExport(api, node, exportName, filePath, visited, result);
199
+ api.forEachChild(node, visit);
200
+ }
201
+ api.forEachChild(sf, visit);
202
+ if (exportName) {
203
+ collectInheritanceChain(api, exportName, classMap, result);
204
+ }
205
+ else {
206
+ for (const [, decl] of classMap) {
207
+ visitClass(api, decl, result);
208
+ }
209
+ }
210
+ return result;
211
+ }
212
+ // ── package resolution ──────────────────────────────────────────────────────────
213
+ export function resolvePackageTypesPath(packageName, fromDir = process.cwd()) {
214
+ const ts = getTs();
215
+ if (!ts)
216
+ return null;
217
+ const virtualFrom = resolve(fromDir, "__resolve__.ts");
218
+ return tryTsResolve(ts, packageName, virtualFrom);
219
+ }
220
+ function hasExportModifier(api, node) {
221
+ const modifiers = node.modifiers;
222
+ if (!modifiers)
223
+ return false;
224
+ return modifiers.some((m) => m.kind === api.SyntaxKind.ExportKeyword);
225
+ }
226
+ function variableExports(n) {
227
+ return (n.declarationList?.declarations ?? []).map((d) => ({ name: d.name.getText(), kind: "constant" }));
228
+ }
229
+ function defaultExport(expression) {
230
+ if (!expression)
231
+ return [];
232
+ const name = expression.getText();
233
+ return /^[A-Za-z_$]/.test(name) ? [{ name, kind: "default" }] : [];
234
+ }
235
+ function reExportNames(clause) {
236
+ return (clause?.elements ?? []).map((e) => ({ name: e.name.getText(), kind: "constant" }));
237
+ }
238
+ function isExported(api, node) {
239
+ // `export { … }` / `export … from` (ExportDeclaration) and `export default …`
240
+ // (ExportAssignment) are exports by syntax and carry no `export` modifier.
241
+ return (hasExportModifier(api, node) ||
242
+ api.isExportDeclaration(node) ||
243
+ api.isExportAssignment(node));
244
+ }
245
+ function exportDescriptors(api, node, n) {
246
+ if (api.isClassDeclaration(node) && n.name) {
247
+ return [{ name: n.name.getText(), kind: "class" }];
248
+ }
249
+ if (api.isFunctionDeclaration(node) && n.name) {
250
+ return [{ name: n.name.getText(), kind: "function" }];
251
+ }
252
+ if (api.isVariableStatement(node)) {
253
+ return variableExports(n);
254
+ }
255
+ if (api.isExportAssignment(node)) {
256
+ return defaultExport(n.expression);
257
+ }
258
+ if (api.isExportDeclaration(node)) {
259
+ return reExportNames(n.exportClause);
260
+ }
261
+ return [];
262
+ }
263
+ function collectExportedDeclarations(api, sf) {
264
+ const seen = new Set();
265
+ const exports = [];
266
+ function visitStatement(node) {
267
+ if (!isExported(api, node))
268
+ return;
269
+ const n = node;
270
+ for (const d of exportDescriptors(api, node, n)) {
271
+ if (!seen.has(d.name)) {
272
+ seen.add(d.name);
273
+ exports.push(d);
274
+ }
275
+ }
276
+ }
277
+ api.forEachChild(sf, visitStatement);
278
+ return exports;
279
+ }
280
+ export function listPackageExports(source, filePath) {
281
+ const ts = getTs();
282
+ if (!ts)
283
+ return [];
284
+ const sf = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true);
285
+ return collectExportedDeclarations(ts, sf);
286
+ }
287
+ // ── type signature parsing ─────────────────────────────────────────────────────
288
+ export function parseTypeSignatures(source, exportName, filePath) {
289
+ const ts = getTs();
290
+ if (!ts)
291
+ return null;
292
+ const visited = new Set();
293
+ if (filePath)
294
+ visited.add(filePath);
295
+ const result = parseSourceForTypes(ts, source, exportName, filePath ?? null, visited);
296
+ return result.size > 0 ? result : null;
297
+ }
298
+ //# sourceMappingURL=source-types.js.map