@metamask-previews/platform-api-docs 0.1.0-preview-8bfa290fb → 0.2.0-preview-0a30e47

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.
Files changed (75) hide show
  1. package/CHANGELOG.md +10 -1
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/{cli.mjs → cli.js} +10 -40
  5. package/dist/cli.js.map +1 -0
  6. package/dist/{extraction.d.cts → extraction.d.ts} +3 -13
  7. package/dist/extraction.d.ts.map +1 -0
  8. package/dist/{extraction.mjs → extraction.js} +3 -28
  9. package/dist/{extraction.cjs.map → extraction.js.map} +1 -1
  10. package/dist/{generate.d.cts → generate.d.ts} +2 -2
  11. package/dist/generate.d.ts.map +1 -0
  12. package/dist/{generate.mjs → generate.js} +111 -68
  13. package/dist/generate.js.map +1 -0
  14. package/dist/{markdown.d.cts → markdown.d.ts} +2 -2
  15. package/dist/markdown.d.ts.map +1 -0
  16. package/dist/{markdown.mjs → markdown.js} +1 -1
  17. package/dist/markdown.js.map +1 -0
  18. package/dist/{root-messenger-discovery.d.cts → root-messenger-discovery.d.ts} +2 -2
  19. package/dist/root-messenger-discovery.d.ts.map +1 -0
  20. package/dist/{root-messenger-discovery.mjs → root-messenger-discovery.js} +9 -30
  21. package/dist/root-messenger-discovery.js.map +1 -0
  22. package/dist/ts-project.d.ts +12 -0
  23. package/dist/ts-project.d.ts.map +1 -0
  24. package/dist/ts-project.js +29 -0
  25. package/dist/ts-project.js.map +1 -0
  26. package/dist/{types.d.cts → types.d.ts} +1 -1
  27. package/dist/types.d.ts.map +1 -0
  28. package/dist/types.js +2 -0
  29. package/dist/types.js.map +1 -0
  30. package/package.json +12 -9
  31. package/dist/cli.cjs +0 -328
  32. package/dist/cli.cjs.map +0 -1
  33. package/dist/cli.d.cts +0 -3
  34. package/dist/cli.d.cts.map +0 -1
  35. package/dist/cli.d.mts +0 -3
  36. package/dist/cli.d.mts.map +0 -1
  37. package/dist/cli.mjs.map +0 -1
  38. package/dist/discovery.cjs +0 -53
  39. package/dist/discovery.cjs.map +0 -1
  40. package/dist/discovery.d.cts +0 -22
  41. package/dist/discovery.d.cts.map +0 -1
  42. package/dist/discovery.d.mts +0 -22
  43. package/dist/discovery.d.mts.map +0 -1
  44. package/dist/discovery.mjs +0 -48
  45. package/dist/discovery.mjs.map +0 -1
  46. package/dist/extraction.cjs +0 -780
  47. package/dist/extraction.d.cts.map +0 -1
  48. package/dist/extraction.d.mts +0 -83
  49. package/dist/extraction.d.mts.map +0 -1
  50. package/dist/extraction.mjs.map +0 -1
  51. package/dist/generate.cjs +0 -462
  52. package/dist/generate.cjs.map +0 -1
  53. package/dist/generate.d.cts.map +0 -1
  54. package/dist/generate.d.mts +0 -70
  55. package/dist/generate.d.mts.map +0 -1
  56. package/dist/generate.mjs.map +0 -1
  57. package/dist/markdown.cjs +0 -239
  58. package/dist/markdown.cjs.map +0 -1
  59. package/dist/markdown.d.cts.map +0 -1
  60. package/dist/markdown.d.mts +0 -52
  61. package/dist/markdown.d.mts.map +0 -1
  62. package/dist/markdown.mjs.map +0 -1
  63. package/dist/root-messenger-discovery.cjs +0 -380
  64. package/dist/root-messenger-discovery.cjs.map +0 -1
  65. package/dist/root-messenger-discovery.d.cts.map +0 -1
  66. package/dist/root-messenger-discovery.d.mts +0 -61
  67. package/dist/root-messenger-discovery.d.mts.map +0 -1
  68. package/dist/root-messenger-discovery.mjs.map +0 -1
  69. package/dist/types.cjs +0 -3
  70. package/dist/types.cjs.map +0 -1
  71. package/dist/types.d.cts.map +0 -1
  72. package/dist/types.d.mts +0 -47
  73. package/dist/types.d.mts.map +0 -1
  74. package/dist/types.mjs +0 -2
  75. package/dist/types.mjs.map +0 -1
@@ -1,12 +1,12 @@
1
- import { directoryExists } from "@metamask/utils/node";
2
- import { execFile } from "node:child_process";
3
- import * as fs from "node:fs/promises";
4
- import * as path from "node:path";
5
- import { promisify } from "node:util";
6
- import { findDtsFiles, findTsFiles } from "./discovery.mjs";
7
- import { createExtractionProject, extractFromSourceFile } from "./extraction.mjs";
8
- import { generateIndexPage, generateNamespacePage, generateSidebars } from "./markdown.mjs";
9
- import { discoverFromRootMessengerCapabilitiesTypes } from "./root-messenger-discovery.mjs";
1
+ import { directoryExists } from '@metamask/utils/node';
2
+ import { execFile } from 'node:child_process';
3
+ import * as fs from 'node:fs/promises';
4
+ import * as path from 'node:path';
5
+ import { promisify } from 'node:util';
6
+ import { extractFromSourceFile } from './extraction.js';
7
+ import { generateIndexPage, generateNamespacePage, generateSidebars, } from './markdown.js';
8
+ import { discoverFromRootMessengerCapabilitiesTypes } from './root-messenger-discovery.js';
9
+ import { createProject } from './ts-project.js';
10
10
  /** How many skipped capability types to name before summarizing the rest. */
11
11
  const MAX_SKIPPED_SHOWN = 10;
12
12
  /**
@@ -141,84 +141,127 @@ function logScanPlan(sources) {
141
141
  console.log(`Scanning ${summary.join(', ')} for Messenger action/event types...`);
142
142
  }
143
143
  /**
144
- * Run extraction against every file in a single directory, logging and
145
- * swallowing per-file failures. All files are added to the shared `project`
146
- * up front so the type checker can resolve cross-file references when the
147
- * walker descends into imported types.
144
+ * Patterns excluded when scanning TypeScript sources: build output, tests, and
145
+ * declaration files (which are only read under `node_modules/@metamask`, via
146
+ * the separate set below).
147
+ *
148
+ * Every pattern is anchored to `root` rather than written as a bare
149
+ * `!**‍/*.test.ts`. A matcher resolves an unanchored negation against the
150
+ * process's working directory, not against the pattern it accompanies, so an
151
+ * unanchored exclusion silently stops excluding anything the moment the scanned
152
+ * path falls outside the working directory — which is the normal case, since
153
+ * this runs from wherever the consumer invoked it.
154
+ *
155
+ * `contentRoot` must be the directory the matched *files* live under, not an
156
+ * ancestor of it. Anchoring at `packages/` rather than `packages/*‍/src` would
157
+ * make the first path segment a package name, so a workspace package called
158
+ * `test` or `dist` would match `test/**` and be dropped whole.
159
+ *
160
+ * @param contentRoot - Resolved directory, or directory glob, that the matched
161
+ * files live directly under.
162
+ * @returns The exclusion patterns.
163
+ */
164
+ function buildTsSourceExclusions(contentRoot) {
165
+ return [
166
+ 'node_modules/**',
167
+ 'dist/**',
168
+ '__tests__/**',
169
+ 'tests/**',
170
+ 'test/**',
171
+ '__mocks__/**',
172
+ '*.test.ts',
173
+ '*.test-d.ts',
174
+ '*.spec.ts',
175
+ '*.d.ts',
176
+ ].map((pattern) => `!${contentRoot}/**/${pattern}`);
177
+ }
178
+ /**
179
+ * Add every file matching a set of glob patterns to the project, in a stable
180
+ * order.
181
+ *
182
+ * ts-morph promises nothing about the order it returns matches in, and
183
+ * deduplication downstream keeps the first of two equally-scored items, so an
184
+ * unsorted list would let the filesystem decide which source link a capability
185
+ * gets.
186
+ *
187
+ * Ordering is by code unit rather than `localeCompare`, which collates
188
+ * differently depending on the locale the process happens to run under.
148
189
  *
149
190
  * @param project - The shared ts-morph project.
150
- * @param directory - The directory to scan.
151
- * @param projectPath - The project root, used for relative path display.
152
- * @param findFiles - The function used to enumerate files in the directory.
153
- * @returns The list of extracted messenger items.
191
+ * @param patterns - Glob patterns to match, including `!` exclusions.
192
+ * @returns The added source files, sorted by path.
154
193
  */
155
- async function extractFromDirectory(project, directory, projectPath, findFiles) {
156
- const items = [];
157
- const files = await findFiles(directory);
158
- for (const file of files) {
159
- try {
160
- const sourceFile = project.getSourceFile(file) ?? project.addSourceFileAtPath(file);
161
- items.push(...extractFromSourceFile(sourceFile, projectPath));
162
- }
163
- catch (error) {
164
- console.warn(`Warning: failed to parse ${path.relative(projectPath, file)}`);
165
- console.warn(error);
166
- }
167
- }
168
- return items;
194
+ function addSourceFiles(project, patterns) {
195
+ return project.addSourceFilesAtPaths(patterns).sort((fileA, fileB) =>
196
+ // Subtracting the two comparisons keeps this branchless, so it reads
197
+ // the same whichever order the matcher happened to return.
198
+ Number(fileA.getFilePath() > fileB.getFilePath()) -
199
+ Number(fileA.getFilePath() < fileB.getFilePath()));
169
200
  }
170
201
  /**
171
- * Enumerate the subdirectories of a parent directory that match the expected
172
- * layout (e.g., `packages/*‍/src` or `node_modules/@metamask/*‍/dist`), keeping
173
- * only those that actually exist.
202
+ * Build a glob pattern from a directory path.
203
+ *
204
+ * Two things have to be true of the result. Glob syntax is always
205
+ * forward-slashed, including on Windows, where `path.join` would produce
206
+ * backslashes that a matcher reads as escapes. And the path must be fully
207
+ * resolved: the matcher does not follow a symlinked *ancestor* of the pattern,
208
+ * so a project under `/tmp` or `/var` on macOS (both symlinks) would match
209
+ * nothing at all.
174
210
  *
175
- * @param parentDir - The parent directory to enumerate.
176
- * @param subPath - The trailing path component appended to each entry.
177
- * @param includeSymlinks - Whether to include symbolic links (true for
178
- * node_modules where workspaces are symlinked).
179
- * @returns The list of absolute paths to existing target subdirectories.
211
+ * @param segments - Path segments to join.
212
+ * @returns The joined, resolved path with forward slashes.
180
213
  */
181
- async function listTargetSubdirectories(parentDir, subPath, includeSymlinks) {
182
- const entries = await fs.readdir(parentDir, { withFileTypes: true });
183
- const candidates = entries
184
- .filter((entry) => entry.isDirectory() || (includeSymlinks && entry.isSymbolicLink()))
185
- .map((entry) => path.join(parentDir, entry.name, subPath));
186
- const existing = [];
187
- for (const candidate of candidates) {
188
- if (await directoryExists(candidate)) {
189
- existing.push(candidate);
190
- }
191
- }
192
- return existing;
214
+ async function toGlobPath(...segments) {
215
+ // Safe to resolve without a fallback: `discoverScanSources` has already
216
+ // confirmed every directory reaching this point exists.
217
+ const resolved = await fs.realpath(path.join(...segments));
218
+ return resolved.replace(/\\/gu, '/');
193
219
  }
194
220
  /**
195
- * Scan every source location described by `sources` and return all extracted
196
- * messenger items. A single ts-morph Project is shared across every file so
197
- * the type checker can resolve cross-file references (e.g. a `*Messenger`
198
- * declaration in one file walking through an imported umbrella union into
199
- * an auto-generated `*-method-action-types.ts` sibling).
221
+ * Scan every source location described by `sources` (scan directories first,
222
+ * then workspace packages, then published declaration files) and return all
223
+ * extracted messenger items.
224
+ *
225
+ * A single ts-morph Project is shared across every file so the type checker can
226
+ * resolve cross-file references (e.g. a `*Messenger` declaration in one file
227
+ * walking through an imported umbrella union into an auto-generated
228
+ * `*-method-action-types.ts` sibling).
200
229
  *
201
230
  * @param projectPath - The project root path.
202
231
  * @param sources - The set of source locations to scan.
203
232
  * @returns A flat list of all extracted messenger items.
204
233
  */
205
234
  async function scanSources(projectPath, sources) {
206
- const project = createExtractionProject();
207
- const allItems = [];
235
+ const project = createProject();
236
+ const sourceFiles = [];
208
237
  for (const dir of sources.scanDirs) {
209
- allItems.push(...(await extractFromDirectory(project, path.join(projectPath, dir), projectPath, findTsFiles)));
238
+ const root = await toGlobPath(projectPath, dir);
239
+ sourceFiles.push(...addSourceFiles(project, [
240
+ `${root}/**/*.ts`,
241
+ ...buildTsSourceExclusions(root),
242
+ ]));
210
243
  }
211
244
  if (sources.packagesDir) {
212
- const srcDirs = await listTargetSubdirectories(sources.packagesDir, 'src', false);
213
- for (const srcDir of srcDirs) {
214
- allItems.push(...(await extractFromDirectory(project, srcDir, projectPath, findTsFiles)));
215
- }
245
+ const root = await toGlobPath(sources.packagesDir);
246
+ // Anchored at each package's `src`, not at `packages` itself, so a package
247
+ // whose name collides with an exclusion (`test`, `dist`) isn't dropped.
248
+ const contentRoot = `${root}/*/src`;
249
+ sourceFiles.push(...addSourceFiles(project, [
250
+ `${contentRoot}/**/*.ts`,
251
+ ...buildTsSourceExclusions(contentRoot),
252
+ ]));
216
253
  }
217
254
  if (sources.nodeModulesDir) {
218
- const distDirs = await listTargetSubdirectories(sources.nodeModulesDir, 'dist', true);
219
- for (const distDir of distDirs) {
220
- allItems.push(...(await extractFromDirectory(project, distDir, projectPath, findDtsFiles)));
221
- }
255
+ const root = await toGlobPath(sources.nodeModulesDir);
256
+ sourceFiles.push(...addSourceFiles(project, [`${root}/*/dist/**/*.d.cts`]));
257
+ }
258
+ // Matched paths are fully resolved, so the root they are made relative to
259
+ // has to be resolved the same way or every source link becomes a `../..`
260
+ // walk out of the project.
261
+ const resolvedProjectPath = await fs.realpath(projectPath);
262
+ const allItems = [];
263
+ for (const sourceFile of sourceFiles) {
264
+ allItems.push(...extractFromSourceFile(sourceFile, resolvedProjectPath));
222
265
  }
223
266
  return allItems;
224
267
  }
@@ -431,4 +474,4 @@ export async function generate(options) {
431
474
  events: totalEvents,
432
475
  };
433
476
  }
434
- //# sourceMappingURL=generate.mjs.map
477
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"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","sourcesContent":["import { directoryExists } from '@metamask/utils/node';\nimport { execFile } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { promisify } from 'node:util';\nimport type { Project } from 'ts-morph';\n\nimport { extractFromSourceFile } from './extraction.js';\nimport {\n generateIndexPage,\n generateNamespacePage,\n generateSidebars,\n} from './markdown.js';\nimport type { RootCapabilitiesTypeReference } from './root-messenger-discovery.js';\nimport { discoverFromRootMessengerCapabilitiesTypes } from './root-messenger-discovery.js';\nimport { createProject } from './ts-project.js';\nimport type { MessengerCapabilityPacket, NamespaceGroup } from './types.js';\n\n/** How many skipped capability types to name before summarizing the rest. */\nconst MAX_SKIPPED_SHOWN = 10;\n\n/**\n * Options for the `scan` strategy, which reads every `*Messenger` type alias\n * in every file it can find. Used when no single messenger aggregates every\n * capability.\n */\ntype ScanStrategyOptions = {\n /** The selected strategy. */\n strategy: 'scan';\n /** Directories, relative to the project root, to scan. */\n scanDirs: string[];\n};\n\n/**\n * Options for the `root-messenger` strategy, which walks the types a\n * project declares for its root messenger capabilities instead of scanning the\n * entire repo. Used when one messenger carries every action and event.\n */\ntype RootMessengerStrategyOptions = {\n /** The selected strategy. */\n strategy: 'root-messenger';\n /** The root messenger actions type reference. */\n rootActions: RootCapabilitiesTypeReference;\n /** The root messenger events type reference. */\n rootEvents: RootCapabilitiesTypeReference;\n};\n\n/**\n * Options for the generate function.\n */\nexport type GenerateOptions = {\n /** Absolute path to the project to scan. */\n projectPath: string;\n /** Absolute path to the output directory for generated docs. */\n outputDir: string;\n /**\n * Short label identifying the project the docs were generated from (e.g.\n * \"Core\", \"Extension\"). Stamped in the index page title.\n */\n projectLabel?: string | null;\n /**\n * Git commit SHA the docs were generated from. Stamped in the index page\n * intro so engineers know how current the site is.\n */\n commitSha?: string | null;\n} & (ScanStrategyOptions | RootMessengerStrategyOptions);\n\n/**\n * Result returned by the generate function.\n */\nexport type GenerateResult = {\n namespaces: number;\n actions: number;\n events: number;\n};\n\n/**\n * The set of directories available to scan for messenger types, resolved from\n * the project's filesystem layout.\n */\ntype ScanSources = {\n /** User-configured scan dirs that exist on disk (relative to projectPath). */\n scanDirs: string[];\n /** Absolute path to `packages/` if it exists, otherwise null. */\n packagesDir: string | null;\n /** Absolute path to `node_modules/@metamask/` if it exists, otherwise null. */\n nodeModulesDir: string | null;\n};\n\n/**\n * Compute a deduplication score for a messenger item, preferring items with\n * JSDoc and from the \"home\" package whose name matches the namespace.\n *\n * @param item - The messenger item to score.\n * @returns A numeric score (higher is better).\n */\nfunction deduplicationScore(item: MessengerCapabilityPacket): number {\n const jsDocScore = item.jsDoc ? 2 : 0;\n const namespacePrefix = item.typeString\n .split(':')[0]\n .replace(/(?:Controller|Service)$/u, '')\n .toLowerCase();\n const homeScore =\n namespacePrefix.length > 0 &&\n item.sourceFile.toLowerCase().includes(namespacePrefix)\n ? 1\n : 0;\n return jsDocScore + homeScore;\n}\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Resolve the default branch of a project's `origin` remote by reading the\n * symbolic ref `refs/remotes/origin/HEAD`. Falls back to `main` if the\n * symbolic ref isn't set (e.g. in shallow CI clones).\n *\n * @param projectPath - Absolute path to the project root.\n * @returns The default branch name (e.g. \"main\", \"master\", \"develop\").\n */\nasync function resolveDefaultBranch(projectPath: string): Promise<string> {\n try {\n const { stdout } = await execFileAsync(\n 'git',\n ['symbolic-ref', '--short', 'refs/remotes/origin/HEAD'],\n { cwd: projectPath },\n );\n // stdout looks like \"origin/main\"; strip the leading \"origin/\".\n const trimmed = stdout.trim();\n const slash = trimmed.indexOf('/');\n return slash === -1\n ? // istanbul ignore next: defensive — `symbolic-ref --short` always\n // returns `origin/<branch>` when the symbolic ref is set; this\n // fallback only matters if git's output format ever changes.\n trimmed || 'main'\n : trimmed.slice(slash + 1);\n } catch {\n return 'main';\n }\n}\n\n/**\n * Resolve the bare GitHub repository URL for a project by reading its\n * `origin` remote.\n *\n * @param projectPath - Absolute path to the project root.\n * @returns A URL like \"https://github.com/Owner/Repo\" or null when the remote\n * isn't a GitHub URL or can't be read.\n */\nexport async function resolveRepoUrl(\n projectPath: string,\n): Promise<string | null> {\n try {\n const { stdout: remoteRaw } = await execFileAsync(\n 'git',\n ['remote', 'get-url', 'origin'],\n { cwd: projectPath },\n );\n\n const remote = remoteRaw.trim();\n\n // Parse owner/repo from SSH or HTTPS remote URLs\n // Handles aliases like github.com-Org used in SSH configs\n const match = remote.match(\n /github\\.com[^:/]*[:/]([^/]+\\/[^/]+?)(?:\\.git)?$/u,\n );\n if (!match) {\n return null;\n }\n\n return `https://github.com/${match[1]}`;\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve the GitHub blob base URL used for per-line source links.\n *\n * Prefers the documented commit SHA when one is available so the links point\n * at the exact revision the docs were generated from; falls back to the\n * default branch otherwise.\n *\n * @param projectPath - Absolute path to the project root.\n * @param commitSha - Optional commit SHA to use as the ref. When null, the\n * default branch is used instead.\n * @returns A base URL like \"https://github.com/Owner/Repo/blob/<ref>/\" or null.\n */\nasync function resolveRepoBaseUrl(\n projectPath: string,\n commitSha: string | null,\n): Promise<string | null> {\n const repoUrl = await resolveRepoUrl(projectPath);\n if (!repoUrl) {\n return null;\n }\n const ref = commitSha ?? (await resolveDefaultBranch(projectPath));\n return `${repoUrl}/blob/${ref}/`;\n}\n\n/**\n * Discover which configured source locations actually exist on disk.\n *\n * @param projectPath - The project root path.\n * @param scanDirs - User-configured scan directories relative to projectPath.\n * @returns A ScanSources object describing the locations to scan.\n */\nasync function discoverScanSources(\n projectPath: string,\n scanDirs: string[],\n): Promise<ScanSources> {\n const existingScanDirs: string[] = [];\n for (const dir of scanDirs) {\n if (await directoryExists(path.join(projectPath, dir))) {\n existingScanDirs.push(dir);\n }\n }\n\n const packagesDir = path.join(projectPath, 'packages');\n const nodeModulesDir = path.join(projectPath, 'node_modules', '@metamask');\n\n return {\n scanDirs: existingScanDirs,\n packagesDir: (await directoryExists(packagesDir)) ? packagesDir : null,\n nodeModulesDir: (await directoryExists(nodeModulesDir))\n ? nodeModulesDir\n : null,\n };\n}\n\n/**\n * Log a human-readable description of which source locations will be scanned.\n *\n * @param sources - The resolved scan sources.\n */\nfunction logScanPlan(sources: ScanSources): void {\n const summary: string[] = [];\n for (const dir of sources.scanDirs) {\n summary.push(`${dir}/ (.ts)`);\n }\n if (sources.packagesDir) {\n summary.push('packages/*/src (.ts)');\n }\n if (sources.nodeModulesDir) {\n summary.push('node_modules/@metamask/*/dist (.d.cts)');\n }\n console.log(\n `Scanning ${summary.join(', ')} for Messenger action/event types...`,\n );\n}\n\n/**\n * Patterns excluded when scanning TypeScript sources: build output, tests, and\n * declaration files (which are only read under `node_modules/@metamask`, via\n * the separate set below).\n *\n * Every pattern is anchored to `root` rather than written as a bare\n * `!**‍/*.test.ts`. A matcher resolves an unanchored negation against the\n * process's working directory, not against the pattern it accompanies, so an\n * unanchored exclusion silently stops excluding anything the moment the scanned\n * path falls outside the working directory — which is the normal case, since\n * this runs from wherever the consumer invoked it.\n *\n * `contentRoot` must be the directory the matched *files* live under, not an\n * ancestor of it. Anchoring at `packages/` rather than `packages/*‍/src` would\n * make the first path segment a package name, so a workspace package called\n * `test` or `dist` would match `test/**` and be dropped whole.\n *\n * @param contentRoot - Resolved directory, or directory glob, that the matched\n * files live directly under.\n * @returns The exclusion patterns.\n */\nfunction buildTsSourceExclusions(contentRoot: string): string[] {\n return [\n 'node_modules/**',\n 'dist/**',\n '__tests__/**',\n 'tests/**',\n 'test/**',\n '__mocks__/**',\n '*.test.ts',\n '*.test-d.ts',\n '*.spec.ts',\n '*.d.ts',\n ].map((pattern) => `!${contentRoot}/**/${pattern}`);\n}\n\n/**\n * Add every file matching a set of glob patterns to the project, in a stable\n * order.\n *\n * ts-morph promises nothing about the order it returns matches in, and\n * deduplication downstream keeps the first of two equally-scored items, so an\n * unsorted list would let the filesystem decide which source link a capability\n * gets.\n *\n * Ordering is by code unit rather than `localeCompare`, which collates\n * differently depending on the locale the process happens to run under.\n *\n * @param project - The shared ts-morph project.\n * @param patterns - Glob patterns to match, including `!` exclusions.\n * @returns The added source files, sorted by path.\n */\nfunction addSourceFiles(\n project: Project,\n patterns: string[],\n): ReturnType<Project['addSourceFilesAtPaths']> {\n return project.addSourceFilesAtPaths(patterns).sort(\n (fileA, fileB) =>\n // Subtracting the two comparisons keeps this branchless, so it reads\n // the same whichever order the matcher happened to return.\n Number(fileA.getFilePath() > fileB.getFilePath()) -\n Number(fileA.getFilePath() < fileB.getFilePath()),\n );\n}\n\n/**\n * Build a glob pattern from a directory path.\n *\n * Two things have to be true of the result. Glob syntax is always\n * forward-slashed, including on Windows, where `path.join` would produce\n * backslashes that a matcher reads as escapes. And the path must be fully\n * resolved: the matcher does not follow a symlinked *ancestor* of the pattern,\n * so a project under `/tmp` or `/var` on macOS (both symlinks) would match\n * nothing at all.\n *\n * @param segments - Path segments to join.\n * @returns The joined, resolved path with forward slashes.\n */\nasync function toGlobPath(...segments: string[]): Promise<string> {\n // Safe to resolve without a fallback: `discoverScanSources` has already\n // confirmed every directory reaching this point exists.\n const resolved = await fs.realpath(path.join(...segments));\n return resolved.replace(/\\\\/gu, '/');\n}\n\n/**\n * Scan every source location described by `sources` (scan directories first,\n * then workspace packages, then published declaration files) and return all\n * extracted messenger items.\n *\n * A single ts-morph Project is shared across every file so the type checker can\n * resolve cross-file references (e.g. a `*Messenger` declaration in one file\n * walking through an imported umbrella union into an auto-generated\n * `*-method-action-types.ts` sibling).\n *\n * @param projectPath - The project root path.\n * @param sources - The set of source locations to scan.\n * @returns A flat list of all extracted messenger items.\n */\nasync function scanSources(\n projectPath: string,\n sources: ScanSources,\n): Promise<MessengerCapabilityPacket[]> {\n const project = createProject();\n const sourceFiles = [];\n\n for (const dir of sources.scanDirs) {\n const root = await toGlobPath(projectPath, dir);\n sourceFiles.push(\n ...addSourceFiles(project, [\n `${root}/**/*.ts`,\n ...buildTsSourceExclusions(root),\n ]),\n );\n }\n\n if (sources.packagesDir) {\n const root = await toGlobPath(sources.packagesDir);\n // Anchored at each package's `src`, not at `packages` itself, so a package\n // whose name collides with an exclusion (`test`, `dist`) isn't dropped.\n const contentRoot = `${root}/*/src`;\n sourceFiles.push(\n ...addSourceFiles(project, [\n `${contentRoot}/**/*.ts`,\n ...buildTsSourceExclusions(contentRoot),\n ]),\n );\n }\n\n if (sources.nodeModulesDir) {\n const root = await toGlobPath(sources.nodeModulesDir);\n sourceFiles.push(...addSourceFiles(project, [`${root}/*/dist/**/*.d.cts`]));\n }\n\n // Matched paths are fully resolved, so the root they are made relative to\n // has to be resolved the same way or every source link becomes a `../..`\n // walk out of the project.\n const resolvedProjectPath = await fs.realpath(projectPath);\n\n const allItems: MessengerCapabilityPacket[] = [];\n for (const sourceFile of sourceFiles) {\n allItems.push(...extractFromSourceFile(sourceFile, resolvedProjectPath));\n }\n return allItems;\n}\n\n/**\n * Replace a previously-seen item in its existing namespace group with a\n * higher-scoring duplicate. Handles the case where the duplicate is a\n * different kind (action vs event) by moving it between lists.\n *\n * @param byNamespace - Map of namespace to its group.\n * @param previous - The previously stored item.\n * @param replacement - The new item to replace it with.\n */\nfunction replaceDuplicateInGroup(\n byNamespace: Map<string, NamespaceGroup>,\n previous: MessengerCapabilityPacket,\n replacement: MessengerCapabilityPacket,\n): void {\n const namespace = replacement.typeString.split(':')[0];\n const group = byNamespace.get(namespace);\n // istanbul ignore next: `previous` and `replacement` have the same\n // typeString, so they share a namespace, and we always insert the\n // namespace into `byNamespace` before recording the original entry.\n if (!group) {\n return;\n }\n const previousList =\n previous.kind === 'action' ? group.actions : group.events;\n const index = previousList.indexOf(previous);\n // istanbul ignore next: `previous` was added to its kind's list by\n // `groupByNamespace` before being recorded in `seen`, so it is always\n // present when we look it up here.\n if (index === -1) {\n return;\n }\n if (previous.kind === replacement.kind) {\n previousList[index] = replacement;\n } else {\n previousList.splice(index, 1);\n const newList =\n replacement.kind === 'action' ? group.actions : group.events;\n newList.push(replacement);\n }\n}\n\n/**\n * Group items by namespace, deduplicating duplicate typeStrings using\n * `deduplicationScore`. Returns groups sorted alphabetically by namespace,\n * with each group's items sorted alphabetically by typeString.\n *\n * @param items - The full list of extracted items.\n * @returns The deduplicated and sorted namespace groups.\n */\nfunction groupByNamespace(\n items: MessengerCapabilityPacket[],\n): NamespaceGroup[] {\n const byNamespace = new Map<string, NamespaceGroup>();\n const seen = new Map<string, MessengerCapabilityPacket>();\n\n for (const item of items) {\n const existing = seen.get(item.typeString);\n if (existing) {\n if (deduplicationScore(item) <= deduplicationScore(existing)) {\n continue;\n }\n replaceDuplicateInGroup(byNamespace, existing, item);\n seen.set(item.typeString, item);\n continue;\n }\n\n seen.set(item.typeString, item);\n const namespace = item.typeString.split(':')[0];\n let group = byNamespace.get(namespace);\n if (!group) {\n group = { namespace, actions: [], events: [] };\n byNamespace.set(namespace, group);\n }\n if (item.kind === 'action') {\n group.actions.push(item);\n } else {\n group.events.push(item);\n }\n }\n\n const namespaces = Array.from(byNamespace.values()).sort((a, b) =>\n a.namespace.localeCompare(b.namespace),\n );\n\n for (const ns of namespaces) {\n ns.actions.sort((a, b) => a.typeString.localeCompare(b.typeString));\n ns.events.sort((a, b) => a.typeString.localeCompare(b.typeString));\n }\n\n return namespaces;\n}\n\n/**\n * Write generated docs (namespace pages, index page, sidebars) to disk,\n * replacing any existing `docs/` directory.\n *\n * @param namespaces - The grouped namespaces to render.\n * @param outputDir - The root output directory.\n * @param repoBaseUrl - GitHub blob base URL for source links, or null.\n * @param indexOptions - Options stamped on the index page header.\n * @param indexOptions.projectLabel - Short label identifying the project.\n * @param indexOptions.commitSha - Git commit SHA the docs were generated from.\n * @returns Promise that resolves once all files are written.\n */\nasync function writeOutput(\n namespaces: NamespaceGroup[],\n outputDir: string,\n repoBaseUrl: string | null,\n indexOptions: {\n projectLabel?: string | null;\n commitSha?: string | null;\n },\n): Promise<void> {\n const docsDir = path.join(outputDir, 'docs');\n\n if (await directoryExists(docsDir)) {\n await fs.rm(docsDir, { recursive: true });\n }\n await fs.mkdir(docsDir, { recursive: true });\n\n for (const ns of namespaces) {\n const nsDir = path.join(docsDir, ns.namespace);\n await fs.mkdir(nsDir, { recursive: true });\n\n if (ns.actions.length > 0) {\n await fs.writeFile(\n path.join(nsDir, 'actions.md'),\n generateNamespacePage(ns, 'action', repoBaseUrl),\n );\n }\n\n if (ns.events.length > 0) {\n await fs.writeFile(\n path.join(nsDir, 'events.md'),\n generateNamespacePage(ns, 'event', repoBaseUrl),\n );\n }\n }\n\n await fs.writeFile(\n path.join(docsDir, 'index.md'),\n generateIndexPage(namespaces, indexOptions),\n );\n\n await fs.writeFile(\n path.join(outputDir, 'sidebars.ts'),\n generateSidebars(namespaces),\n );\n}\n\n/**\n * Collect capabilities by scanning the project's files.\n *\n * @param projectPath - The project root path.\n * @param scanDirs - Directories (relative to projectPath) to scan.\n * @returns The extracted capabilities.\n * @throws If the project has no scannable directories at all.\n */\nasync function collectByScanning(\n projectPath: string,\n scanDirs: string[],\n): Promise<MessengerCapabilityPacket[]> {\n const sources = await discoverScanSources(projectPath, scanDirs);\n\n if (\n sources.scanDirs.length === 0 &&\n !sources.packagesDir &&\n !sources.nodeModulesDir\n ) {\n throw new Error(\n `No scannable directories found in ${projectPath}. ` +\n `Looked for: ${scanDirs.join(', ')}, packages/, node_modules/@metamask/`,\n );\n }\n\n logScanPlan(sources);\n\n return await scanSources(projectPath, sources);\n}\n\n/**\n * Using the project's root messenger capability collection types as\n * entrypoints, collect the constituent individual capability types and package\n * them so that they can be displayed within the documentation site.\n *\n * @param projectPath - The project root path.\n * @param options - The root-messenger strategy options.\n * @returns The extracted capabilities.\n */\nfunction collectFromRootMessengerCapabilities(\n projectPath: string,\n options: RootMessengerStrategyOptions,\n): MessengerCapabilityPacket[] {\n const { rootActions, rootEvents } = options;\n\n console.log(\n `Resolving actions from ${rootActions.filePath}#${rootActions.typeName} ` +\n `and events from ${rootEvents.filePath}#${rootEvents.typeName}...`,\n );\n\n const { capabilityPackets, skippedCapabilities } =\n discoverFromRootMessengerCapabilitiesTypes({\n projectPath,\n rootActionsTypeReference: rootActions,\n rootEventsTypeReference: rootEvents,\n });\n\n // Report rather than drop silently: a jump in any of these usually means the\n // project changed how it declares its capabilities.\n warnSkipped(\n 'declared inline, with no name to document',\n skippedCapabilities.unnamedCapabilities,\n );\n warnSkipped(\n 'whose shape could not be read',\n skippedCapabilities.unextractableCapabilities,\n );\n\n // If both capability collection types resolve to nothing, it's always a\n // misconfiguration (a wrong type name, or imports that didn't resolve).\n // Failing here matters because generation would otherwise replace an existing\n // docs directory with an empty one and exit successfully.\n if (capabilityPackets.length === 0) {\n throw new Error(\n `No messenger actions or events found in ` +\n `${rootActions.filePath}#${rootActions.typeName} or ` +\n `${rootEvents.filePath}#${rootEvents.typeName}. ` +\n `Check that these types name the collections carrying every ` +\n `capability, and that their imports resolve.`,\n );\n }\n\n return capabilityPackets;\n}\n\n/**\n * Warn about capability types that couldn't be documented, naming them so the\n * warning is actionable.\n *\n * @param description - Why they were skipped, as a noun phrase.\n * @param labels - Labels identifying each skipped type.\n */\nfunction warnSkipped(description: string, labels: string[]): void {\n if (labels.length === 0) {\n return;\n }\n\n const shown = labels.slice(0, MAX_SKIPPED_SHOWN);\n const remaining = labels.length - shown.length;\n console.warn(\n `Warning: skipped ${labels.length} capability ` +\n `${labels.length === 1 ? 'type' : 'types'} ${description}: ` +\n `${shown.join(', ')}${remaining > 0 ? `, and ${remaining} more` : ''}`,\n );\n}\n\n/**\n * Scan a project for messenger action/event types and generate documentation.\n *\n * @param options - Generation options.\n * @returns A promise resolving to counts of generated namespaces, actions, and events.\n */\nexport async function generate(\n options: GenerateOptions,\n): Promise<GenerateResult> {\n const { projectPath, outputDir, projectLabel, commitSha } = options;\n\n const allItems =\n options.strategy === 'root-messenger'\n ? collectFromRootMessengerCapabilities(projectPath, options)\n : await collectByScanning(projectPath, options.scanDirs);\n\n console.log(\n `Found ${allItems.length} messenger ${allItems.length === 1 ? 'item' : 'items'} total.`,\n );\n\n const namespaces = groupByNamespace(allItems);\n const repoBaseUrl = await resolveRepoBaseUrl(projectPath, commitSha ?? null);\n\n await writeOutput(namespaces, outputDir, repoBaseUrl, {\n projectLabel,\n commitSha,\n });\n\n const totalActions = namespaces.reduce(\n (sum, ns) => sum + ns.actions.length,\n 0,\n );\n const totalEvents = namespaces.reduce((sum, ns) => sum + ns.events.length, 0);\n\n console.log(\n `Generated docs for ${namespaces.length} ${namespaces.length === 1 ? 'namespace' : 'namespaces'}.`,\n );\n console.log(` Actions: ${totalActions}`);\n console.log(` Events: ${totalEvents}`);\n console.log(`Output: ${path.join(outputDir, 'docs')}/`);\n\n return {\n namespaces: namespaces.length,\n actions: totalActions,\n events: totalEvents,\n };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { MessengerCapabilityPacket, NamespaceGroup } from "./types.cjs";
1
+ import type { MessengerCapabilityPacket, NamespaceGroup } from './types.js';
2
2
  /**
3
3
  * Generate markdown documentation for a single messenger item.
4
4
  *
@@ -49,4 +49,4 @@ export declare function generateIndexPage(namespaces: NamespaceGroup[], options?
49
49
  * @returns The generated TypeScript source string.
50
50
  */
51
51
  export declare function generateSidebars(namespaces: NamespaceGroup[]): string;
52
- //# sourceMappingURL=markdown.d.cts.map
52
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAuC5E;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,yBAAyB,EAC/B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,GACzB,MAAM,CAqER;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,cAAc,EAClB,IAAI,EAAE,QAAQ,GAAG,OAAO,EACxB,WAAW,GAAE,MAAM,GAAG,IAAW,GAChC,MAAM,CAiER;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,cAAc,EAAE,EAC5B,OAAO,GAAE,gBAAqB,GAC7B,MAAM,CA+CR;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,cAAc,EAAE,GAAG,MAAM,CA0BrE"}
@@ -229,4 +229,4 @@ export function generateSidebars(namespaces) {
229
229
  };
230
230
  return `// This file is auto-generated by @metamask/platform-api-docs\n// Do not edit manually.\nconst sidebars = ${JSON.stringify(sidebar, null, 2)};\nexport default sidebars;\n`;
231
231
  }
232
- //# sourceMappingURL=markdown.mjs.map
232
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MessengerCapabilityPacket, NamespaceGroup } from './types.js';\n\n/**\n * Convert backtick-quoted action/event names in text into links when they\n * match a known item in the same namespace. For example, `` `setActiveNetwork` ``\n * becomes a link to `#networkcontrollersetactivenetwork` on the actions page.\n *\n * @param text - The markdown text to process.\n * @param namespace - The current namespace (e.g. \"NetworkController\").\n * @param knownNames - Map from short name (e.g. \"setActiveNetwork\") to the page-relative path and anchor.\n * @returns The text with backtick references replaced by links.\n */\nfunction linkifyReferences(\n text: string,\n namespace: string,\n knownNames: Map<string, string>,\n): string {\n return text.replace(/`([a-zA-Z]\\w*)`/gu, (match, name: string) => {\n const link = knownNames.get(name);\n if (link) {\n return `[\\`${name}\\`](${link})`;\n }\n // Also try with namespace prefix (e.g. \"NetworkController:setActiveNetwork\")\n const fullName = `${namespace}:${name}`;\n const anchor = fullName.toLowerCase().replace(/[^a-z0-9]/gu, '');\n const linkFull = knownNames.get(fullName);\n if (linkFull) {\n return `[\\`${name}\\`](${linkFull})`;\n }\n // Check if the anchor matches exactly in known names values\n for (const [, href] of knownNames) {\n if (href.endsWith(`#${anchor}`)) {\n return `[\\`${name}\\`](${href})`;\n }\n }\n return match;\n });\n}\n\n/**\n * Generate markdown documentation for a single messenger item.\n *\n * @param item - The messenger item to document.\n * @param namespace - The current namespace.\n * @param knownNames - Map from short/full names to their link paths.\n * @param repoBaseUrl - Optional GitHub blob base URL (e.g. \"https://github.com/Owner/Repo/blob/sha/\").\n * @returns The generated markdown string.\n */\nexport function generateItemMarkdown(\n item: MessengerCapabilityPacket,\n namespace: string,\n knownNames: Map<string, string>,\n repoBaseUrl: string | null,\n): string {\n const parts: string[] = [];\n\n parts.push(`### \\`${item.typeString}\\``);\n parts.push('');\n\n if (item.deprecated) {\n parts.push('> **Deprecated**');\n parts.push('');\n }\n\n // For sources scanned out of an @metamask/*/dist directory we render an\n // npm link, since the original .ts paths are not part of the repo we're\n // documenting. Other `node_modules/` paths fall through to the normal\n // source-link branches.\n const metamaskPkgMatch = item.sourceFile.match(\n /node_modules\\/(@metamask\\/[^/]+)/u,\n );\n if (metamaskPkgMatch) {\n const pkgName = metamaskPkgMatch[1];\n const npmUrl = `https://www.npmjs.com/package/${pkgName}`;\n parts.push(`**Package**: [\\`${pkgName}\\`](${npmUrl})`);\n } else if (repoBaseUrl) {\n const ghUrl = `${repoBaseUrl}${item.sourceFile}#L${item.line}`;\n parts.push(`**Source**: [${item.sourceFile}:${item.line}](${ghUrl})`);\n } else {\n parts.push(`**Source**: \\`${item.sourceFile}:${item.line}\\``);\n }\n parts.push('');\n\n if (item.jsDoc) {\n parts.push(linkifyReferences(item.jsDoc, namespace, knownNames));\n parts.push('');\n }\n\n // Only actions get a parameters table — events carry a positional tuple\n // payload, not named arguments, so a `@param` table doesn't fit.\n if (item.kind === 'action' && item.params.length > 0) {\n parts.push('**Parameters**:');\n parts.push('');\n parts.push('| Name | Description |');\n parts.push('|------|-------------|');\n for (const param of item.params) {\n const description = linkifyReferences(\n param.description,\n namespace,\n knownNames,\n );\n parts.push(`| \\`${param.name}\\` | ${description} |`);\n }\n parts.push('');\n }\n\n if (item.kind === 'action' && item.returns) {\n parts.push(\n `**Returns**: ${linkifyReferences(item.returns, namespace, knownNames)}`,\n );\n parts.push('');\n }\n\n const signatureLabel = item.kind === 'action' ? 'Handler' : 'Payload';\n parts.push(`**${signatureLabel} signature**:`);\n parts.push('');\n parts.push('```typescript');\n parts.push(item.handlerOrPayload);\n parts.push('```');\n parts.push('');\n\n return parts.join('\\n');\n}\n\n/**\n * Generate a full markdown page for a namespace's actions or events.\n *\n * @param ns - The namespace group to generate a page for.\n * @param kind - Whether to generate the actions or events page.\n * @param repoBaseUrl - Optional GitHub blob base URL for source links.\n * @returns The generated markdown string.\n */\nexport function generateNamespacePage(\n ns: NamespaceGroup,\n kind: 'action' | 'event',\n repoBaseUrl: string | null = null,\n): string {\n const items = kind === 'action' ? ns.actions : ns.events;\n const title = kind === 'action' ? 'Actions' : 'Events';\n const parts: string[] = [];\n\n parts.push('---');\n parts.push(`title: \"${ns.namespace} ${title}\"`);\n parts.push(`sidebar_label: \"${title}\"`);\n parts.push('---');\n parts.push('');\n parts.push(`# ${ns.namespace} ${title}`);\n parts.push('');\n\n if (items.length === 0) {\n parts.push(`_No ${kind}s found for this namespace._`);\n parts.push('');\n return parts.join('\\n');\n }\n\n parts.push(\n `${items.length} ${kind}${items.length === 1 ? '' : 's'} registered.`,\n );\n parts.push('');\n\n // Build a map of known names → link paths for cross-referencing.\n // Actions on same page get #anchor, actions/events on sibling page get relative path.\n const knownNames = new Map<string, string>();\n for (const action of ns.actions) {\n const shortName = action.typeString.split(':')[1];\n const anchor = action.typeString.toLowerCase().replace(/[^a-z0-9]/gu, '');\n const href = kind === 'action' ? `#${anchor}` : `./actions#${anchor}`;\n knownNames.set(shortName, href);\n knownNames.set(action.typeString, href);\n }\n for (const event of ns.events) {\n const shortName = event.typeString.split(':')[1];\n const anchor = event.typeString.toLowerCase().replace(/[^a-z0-9]/gu, '');\n const href = kind === 'event' ? `#${anchor}` : `./events#${anchor}`;\n knownNames.set(shortName, href);\n knownNames.set(event.typeString, href);\n }\n\n // Table of contents\n parts.push('| Name | Deprecated |');\n parts.push('|------|-----------|');\n for (const item of items) {\n const name = item.typeString.split(':')[1];\n // Docusaurus uses github-slugger: strips non-alphanumeric, lowercases, no dashes for special chars in code spans\n const anchor = item.typeString.toLowerCase().replace(/[^a-z0-9]/gu, '');\n const dep = item.deprecated ? 'Yes' : '';\n parts.push(`| [\\`${name}\\`](#${anchor}) | ${dep} |`);\n }\n parts.push('');\n parts.push('---');\n parts.push('');\n\n for (const item of items) {\n parts.push(\n generateItemMarkdown(item, ns.namespace, knownNames, repoBaseUrl),\n );\n parts.push('---');\n parts.push('');\n }\n\n return parts.join('\\n');\n}\n\n/**\n * Options controlling how {@link generateIndexPage} renders the index header.\n */\nexport type IndexPageOptions = {\n /**\n * Short label identifying the project the docs were generated from (e.g.\n * \"Core\", \"Extension\"). When provided, the title is rendered as\n * `Platform API (Core)`.\n */\n projectLabel?: string | null;\n /**\n * Git commit SHA the docs were generated from. When provided, it's shown\n * in the intro so engineers know how current the site is.\n */\n commitSha?: string | null;\n};\n\n/**\n * Generate the index/overview page listing all namespaces.\n *\n * @param namespaces - All namespace groups sorted alphabetically.\n * @param options - Optional project label and commit SHA to stamp in the header.\n * @returns The generated markdown string.\n */\nexport function generateIndexPage(\n namespaces: NamespaceGroup[],\n options: IndexPageOptions = {},\n): string {\n const totalActions = namespaces.reduce(\n (sum, ns) => sum + ns.actions.length,\n 0,\n );\n const totalEvents = namespaces.reduce((sum, ns) => sum + ns.events.length, 0);\n const projectSuffix = options.projectLabel\n ? ` (${options.projectLabel})`\n : '';\n\n const parts: string[] = [];\n parts.push('---');\n parts.push(`title: \"Platform API${projectSuffix} Reference\"`);\n parts.push('slug: \"/\"');\n parts.push('---');\n parts.push('');\n parts.push(`# Platform API${projectSuffix}`);\n parts.push('');\n parts.push(\n 'This site documents every action and event registered on the Messenger — the type-safe message bus used across all controllers.',\n );\n parts.push('');\n if (options.commitSha) {\n parts.push(`Generated from commit \\`${options.commitSha}\\`.`);\n parts.push('');\n }\n parts.push(`- **${namespaces.length}** namespaces`);\n parts.push(`- **${totalActions}** actions`);\n parts.push(`- **${totalEvents}** events`);\n parts.push('');\n parts.push('## Namespaces');\n parts.push('');\n parts.push('| Namespace | Actions | Events |');\n parts.push('|-----------|---------|--------|');\n\n for (const ns of namespaces) {\n const firstLink =\n ns.actions.length > 0\n ? `${ns.namespace}/actions`\n : `${ns.namespace}/events`;\n parts.push(\n `| [${ns.namespace}](${firstLink}) | ${ns.actions.length} | ${ns.events.length} |`,\n );\n }\n\n parts.push('');\n return parts.join('\\n');\n}\n\n/**\n * Generate the sidebars.ts file content for Docusaurus.\n *\n * @param namespaces - All namespace groups sorted alphabetically.\n * @returns The generated TypeScript source string.\n */\nexport function generateSidebars(namespaces: NamespaceGroup[]): string {\n const items = namespaces.map((ns) => ({\n type: 'category',\n label: ns.namespace,\n items: [\n ...(ns.actions.length > 0 ? [`${ns.namespace}/actions`] : []),\n ...(ns.events.length > 0 ? [`${ns.namespace}/events`] : []),\n ],\n }));\n\n const sidebar = {\n messengerSidebar: [\n {\n type: 'doc',\n id: 'index',\n label: 'Overview',\n },\n ...items,\n ],\n };\n\n return `// This file is auto-generated by @metamask/platform-api-docs\\n// Do not edit manually.\\nconst sidebars = ${JSON.stringify(\n sidebar,\n null,\n 2,\n )};\\nexport default sidebars;\\n`;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { MessengerCapabilityPacket } from "./types.cjs";
1
+ import type { MessengerCapabilityPacket } from './types.js';
2
2
  /**
3
3
  * A reference to a type declared in a file, written as `<file>#<TypeName>`.
4
4
  *
@@ -58,4 +58,4 @@ export declare function discoverFromRootMessengerCapabilitiesTypes({ projectPath
58
58
  skippedCapabilities: SkippedCapabilities;
59
59
  };
60
60
  export {};
61
- //# sourceMappingURL=root-messenger-discovery.d.cts.map
61
+ //# sourceMappingURL=root-messenger-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root-messenger-discovery.d.ts","sourceRoot":"","sources":["../src/root-messenger-discovery.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAS5D;;;;;;;GAOG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;GAGG;AACH,KAAK,mBAAmB,GAAG;IACzB;;;OAGG;IACH,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAI9B,yBAAyB,EAAE,MAAM,EAAE,CAAC;CACrC,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,kCAAkC,CAChD,SAAS,EAAE,MAAM,GAChB,6BAA6B,CAiB/B;AA6VD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,0CAA0C,CAAC,EACzD,WAAW,EACX,wBAAwB,EACxB,uBAAuB,GACxB,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,wBAAwB,EAAE,6BAA6B,CAAC;IACxD,uBAAuB,EAAE,6BAA6B,CAAC;CACxD,GAAG;IACF,iBAAiB,EAAE,yBAAyB,EAAE,CAAC;IAC/C,mBAAmB,EAAE,mBAAmB,CAAC;CAC1C,CA8CA"}
@@ -1,6 +1,7 @@
1
- import * as path from "node:path";
2
- import { Node as NodeGuards, Project, ts } from "ts-morph";
3
- import { classifyMessengerCapabilityTypeDeclaration, extractFromMessengerCapabilityTypeDeclaration } from "./extraction.mjs";
1
+ import * as path from 'node:path';
2
+ import { Node as NodeGuards } from 'ts-morph';
3
+ import { classifyMessengerCapabilityTypeDeclaration, extractFromMessengerCapabilityTypeDeclaration, } from './extraction.js';
4
+ import { createProject } from './ts-project.js';
4
5
  /**
5
6
  * Split a `<file>#<TypeName>` reference into its parts, on the last `#` so
6
7
  * that paths containing a `#` still work.
@@ -21,28 +22,6 @@ export function parseRootCapabilitiesTypeReference(reference) {
21
22
  }
22
23
  return { filePath, typeName };
23
24
  }
24
- /**
25
- * Create a ts-morph Project for resolving root messenger types.
26
- *
27
- * No file list is loaded: this strategy opens only the entry files and lets
28
- * the checker pull in the rest.
29
- *
30
- * @returns A new ts-morph Project.
31
- */
32
- function createRootMessengerProject() {
33
- return new Project({
34
- compilerOptions: {
35
- noEmit: true,
36
- // We need symbol resolution, not full typechecking, so a project's own
37
- // strictness settings shouldn't be able to fail the docs build.
38
- strict: false,
39
- skipLibCheck: true,
40
- target: ts.ScriptTarget.ESNext,
41
- module: ts.ModuleKind.ESNext,
42
- moduleResolution: ts.ModuleResolutionKind.NodeJs,
43
- },
44
- });
45
- }
46
25
  /**
47
26
  * A `<file>#<TypeName>` string, passed from the command line, refers to an
48
27
  * messenger actions or events collection type. This function reads the file and
@@ -62,9 +41,9 @@ function resolveMessengerCapabilitiesTypeReference({ project, projectPath, refer
62
41
  const absolutePath = path.resolve(projectPath, reference.filePath);
63
42
  let sourceFile;
64
43
  try {
65
- sourceFile =
66
- project.getSourceFile(absolutePath) ??
67
- project.addSourceFileAtPath(absolutePath);
44
+ // `addSourceFileAtPath` is idempotent: the two references often name the
45
+ // same file, and the second call returns the source file added by the first.
46
+ sourceFile = project.addSourceFileAtPath(absolutePath);
68
47
  }
69
48
  catch {
70
49
  throw new Error(`Could not read ${absolutePath}, which was named by ${commandLineOptionName}.`);
@@ -316,7 +295,7 @@ function extractFromMessengerCapabilitiesUnionTypeDeclaration({ projectPath, cap
316
295
  * @returns The extracted capabilities plus any capabilities that were skipped.
317
296
  */
318
297
  export function discoverFromRootMessengerCapabilitiesTypes({ projectPath, rootActionsTypeReference, rootEventsTypeReference, }) {
319
- const project = createRootMessengerProject();
298
+ const project = createProject();
320
299
  const capabilityPacketCollections = [
321
300
  [rootActionsTypeReference, 'action', '--root-actions'],
322
301
  [rootEventsTypeReference, 'event', '--root-events'],
@@ -349,4 +328,4 @@ export function discoverFromRootMessengerCapabilitiesTypes({ projectPath, rootAc
349
328
  skippedCapabilities: allSkippedCapabilities,
350
329
  };
351
330
  }
352
- //# sourceMappingURL=root-messenger-discovery.mjs.map
331
+ //# sourceMappingURL=root-messenger-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root-messenger-discovery.js","sourceRoot":"","sources":["../src/root-messenger-discovery.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'node:path';\nimport type {\n InterfaceDeclaration,\n Project as TsMorphProject,\n Type,\n TypeAliasDeclaration,\n} from 'ts-morph';\nimport { Node as NodeGuards } from 'ts-morph';\n\nimport {\n classifyMessengerCapabilityTypeDeclaration,\n extractFromMessengerCapabilityTypeDeclaration,\n} from './extraction.js';\nimport { createProject } from './ts-project.js';\nimport type { MessengerCapabilityPacket } from './types.js';\n\n// ---------------------------------------------------------------------------\n// The `root-messenger` strategy: resolve the types a project declares for its\n// collection of root messenger actions and events and let TypeScript walk them.\n// Each capability type found is handed to the shared extractor in\n// `extraction.ts`, so the output matches what the `scan` strategy produces.\n// ---------------------------------------------------------------------------\n\n/**\n * A reference to a type declared in a file, written as `<file>#<TypeName>`.\n *\n * The `root-messenger` strategy takes two of these on the command line — one\n * naming a collection of messenger action types, one naming a collection of\n * messenger event types — and uses them to locate the type declarations to\n * enumerate.\n */\nexport type RootCapabilitiesTypeReference = {\n /** Path to the declaring file, relative to the project root. */\n filePath: string;\n /** Name of the type alias within that file. */\n typeName: string;\n};\n\n/**\n * Labels for capability types that were found but couldn't be documented,\n * grouped by why. Labels rather than counts, so warnings can name what to fix.\n */\ntype SkippedCapabilities = {\n /**\n * Capabilities declared inline in the capability collection type, so there is\n * no name or JSDoc to document.\n */\n unnamedCapabilities: string[];\n /*\n * Capabilities that are named, but of a shape the extractor rejects.\n */\n unextractableCapabilities: string[];\n};\n\n/**\n * Split a `<file>#<TypeName>` reference into its parts, on the last `#` so\n * that paths containing a `#` still work.\n *\n * @param reference - The raw reference, e.g. `src/messenger.ts#RootActions`.\n * @returns The parsed reference.\n * @throws If the reference has no `#`, or either side of it is empty.\n */\nexport function parseRootCapabilitiesTypeReference(\n reference: string,\n): RootCapabilitiesTypeReference {\n const separatorIndex = reference.lastIndexOf('#');\n if (separatorIndex === -1) {\n throw new Error(\n `Expected a reference of the form \"<file>#<TypeName>\", got \"${reference}\".`,\n );\n }\n\n const filePath = reference.slice(0, separatorIndex);\n const typeName = reference.slice(separatorIndex + 1);\n if (filePath.length === 0 || typeName.length === 0) {\n throw new Error(\n `Expected a reference of the form \"<file>#<TypeName>\", got \"${reference}\".`,\n );\n }\n\n return { filePath, typeName };\n}\n\n/**\n * A `<file>#<TypeName>` string, passed from the command line, refers to an\n * messenger actions or events collection type. This function reads the file and\n * looks up the matching type alias.\n *\n * @param args - The arguments to this function.\n * @param args.project - The ts-morph project to load the file into.\n * @param args.projectPath - Absolute path to the project root.\n * @param args.reference - The root capability collection type reference to\n * resolve.\n * @param args.commandLineOptionName - The command-line option the reference\n * came from, used in errors.\n * @returns The type alias declaration the reference names.\n * @throws If the file can't be read or declares no such type alias.\n */\nfunction resolveMessengerCapabilitiesTypeReference({\n project,\n projectPath,\n reference,\n commandLineOptionName,\n}: {\n project: TsMorphProject;\n projectPath: string;\n reference: RootCapabilitiesTypeReference;\n commandLineOptionName: string;\n}): TypeAliasDeclaration {\n const absolutePath = path.resolve(projectPath, reference.filePath);\n\n let sourceFile;\n try {\n // `addSourceFileAtPath` is idempotent: the two references often name the\n // same file, and the second call returns the source file added by the first.\n sourceFile = project.addSourceFileAtPath(absolutePath);\n } catch {\n throw new Error(\n `Could not read ${absolutePath}, which was named by ${commandLineOptionName}.`,\n );\n }\n\n // EXAMPLES:\n // type RootMessengerActions = ...\n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n // type RootMessengerEvents = ...\n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n const declaration = sourceFile.getTypeAlias(reference.typeName);\n if (!declaration) {\n throw new Error(\n `No type alias named \"${reference.typeName}\" in ${reference.filePath}, which was named by ${commandLineOptionName}.`,\n );\n }\n\n return declaration;\n}\n\n/**\n * Given the type of a messenger capability (e.g.\n * `NetworkControllerAddNetworkAction`) as obtained from a collection of\n * capability types (e.g. `RootMessengerActions` or `RootMessengerEvents`),\n * locate the type declaration for that capability type.\n *\n * This is not as simple as following the type to its declaration, because both\n * a collection of capability types and the capability type itself can have\n * multiple representations. So there are three strategies for finding the type:\n *\n * 1. If the capability type was declared as a type alias (e.g. `type\n * FooControllerSomeAction = { ... }`), then we need to use the symbol to\n * find the declaration.\n * 2. If the capability type was declared as an interface (e.g. `interface\n * FooControllerSomeAction { ... }`), we don't need to do this; interfaces\n * are their own declaration.\n * 3. If the capability *collection* type is not a union but merely a type alias\n * (e.g. `type RootMessengerActions = NetworkControllerAddNetworkAction`)\n * then we follow the right-hand side of the type alias.\n *\n * When none of these find a type declaration, the capability is anonymous\n * (e.g. an inline object type with no name to document) and `undefined` is\n * returned, so the caller can record it as skipped rather than document it.\n *\n * @param capabilityType - The type of the individual capability to find the\n * declaration for.\n * @param capabilityCollectionTypeDeclaration - The declaration of the whole\n * collection the capability came from (e.g. `type RootMessengerActions = ...`).\n * @param isLoneConstituent - Whether the capability collection only includes\n * one capability type.\n * @returns The type alias or interface declaration for the capability, or\n * `undefined` when the capability is anonymous.\n */\nfunction findMessengerCapabilityTypeDeclaration(\n capabilityType: Type,\n capabilityCollectionTypeDeclaration: TypeAliasDeclaration,\n isLoneConstituent: boolean,\n): TypeAliasDeclaration | InterfaceDeclaration | undefined {\n // If we have a type alias, look for its symbol.\n //\n // EXAMPLE:\n // type FooControllerSomeAction = { type: '...'; handler: () => void };\n // ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n // the alias symbol names the plain symbol points at this anonymous\n // this declaration object\n //\n // But skip an alias that resolves back to the capability collection itself,\n // which is what TypeScript reports for a lone generic instantiation.\n //\n // EXAMPLE:\n // Here the alias symbol of the sole member is `Actions`, i.e.\n // `capabilityCollectionTypeDeclaration`, which is not the capability we\n // want to document:\n //\n // type Actions = Foo<Bar>;\n // ^^^^^^^ capabilityCollectionTypeDeclaration\n const typeAliasDeclarations = (\n capabilityType.getAliasSymbol()?.getDeclarations() ?? []\n ).filter((node) => node !== capabilityCollectionTypeDeclaration);\n\n // An interface has no alias symbol, being its own declaration, so fall back\n // to the plain symbol to reach it.\n // EXAMPLE:\n // interface FooControllerSomeAction { type: '...'; handler: () => void }\n // ^^^^^^^^^^^^^^^^^^^^^^^ reached via the plain symbol\n const typeDeclarations =\n typeAliasDeclarations.length > 0\n ? typeAliasDeclarations\n : (capabilityType.getSymbol()?.getDeclarations() ?? []);\n\n // Of the declarations behind whichever symbol we used, pick the type alias or\n // interface.\n // EXAMPLES:\n // type FooControllerSomeAction = { ... }\n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n // interface FooControllerSomeAction { ... }\n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n const foundTypeDeclaration = typeDeclarations.find(\n (node): node is TypeAliasDeclaration | InterfaceDeclaration =>\n NodeGuards.isTypeAliasDeclaration(node) ||\n NodeGuards.isInterfaceDeclaration(node),\n );\n if (foundTypeDeclaration) {\n return foundTypeDeclaration;\n }\n\n // If the capability collection type has only one constituent, we can safely\n // assume it's a type alias. If, in this case, it's also generic, the\n // declaration we want is the one its type node references, so follow it.\n //\n // EXAMPLE:\n // type Actions = Foo<Bar>;\n // ^^^ follow this reference to its declaration\n //\n if (isLoneConstituent) {\n return resolveGenericCapabilityCollectionTypeDeclaration(\n capabilityCollectionTypeDeclaration,\n );\n }\n\n // If, after all of this, the capability collection is a union with an\n // anonymous constituent, we ignore it:\n //\n // EXAMPLE:\n // type Actions = FooControllerSomeAction | { type: '...'; handler: ... };\n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n return undefined;\n}\n\n/**\n * Given a messenger capability collection with one constituent which is a\n * generic capability type, follow that type to find its declaration.\n *\n * A type that is aliased to a generic type is a special case we need to handle,\n * because it won't have a direct alias symbol; we need to pick out the type\n * that acts as the \"box\" in the generic (e.g. the `Foo` in `type Actions =\n * Foo<Bar>`).\n *\n * @param capabilityCollectionTypeDeclaration - The declaration for a\n * collection of capability types (e.g. `type RootMessengerActions = ...`).\n * @returns The resolved sole capability type.\n */\nfunction resolveGenericCapabilityCollectionTypeDeclaration(\n capabilityCollectionTypeDeclaration: TypeAliasDeclaration,\n): TypeAliasDeclaration | InterfaceDeclaration | undefined {\n // The root alias must reference another type by name for there to be a\n // declaration to follow.\n // EXAMPLE:\n // type Actions = Foo<Bar>;\n // ^^^^^^^^\n const typeNode = capabilityCollectionTypeDeclaration.getTypeNode();\n if (!typeNode || !NodeGuards.isTypeReference(typeNode)) {\n return undefined;\n }\n\n // Resolve the referenced name (e.g. `Foo` in `Foo<Bar>`) to its symbol.\n const localSymbol = typeNode.getTypeName().getSymbol();\n // If the type is imported from another file, ensure that when we access the\n // declaration, it's the type declaration in the other file, not the import\n // declaration in this file.\n // EXAMPLE:\n // import { Foo } from '@metamask/foo';\n // type Actions = Foo<Bar>;\n // ^^^\n const symbol = localSymbol?.getAliasedSymbol() ?? localSymbol;\n\n // Follow the reference to the type alias or interface it names.\n // EXAMPLES:\n // type Foo<T> = { ... }\n // ^^^^^^^^^^^^^^^^^^^^\n // interface Foo<T> { ... }\n // ^^^^^^^^^^^^^^^^^^^^^^^\n return symbol\n ?.getDeclarations()\n .find(\n (node): node is TypeAliasDeclaration | InterfaceDeclaration =>\n NodeGuards.isTypeAliasDeclaration(node) ||\n NodeGuards.isInterfaceDeclaration(node),\n );\n}\n\n/**\n * Render a short, single-line label for an anonymous type.\n *\n * @param type - The type to describe.\n * @param enclosingNode - Node to render the type relative to, so an aliased\n * type reads as its name rather than `import(\"<absolute path>\").Name`.\n * @returns The label.\n */\nfunction summarizeType(\n type: Type,\n enclosingNode: TypeAliasDeclaration,\n): string {\n const text = type.getText(enclosingNode).replace(/\\s+/gu, ' ');\n return text.length > 80 ? `${text.slice(0, 77)}...` : text;\n}\n\n/**\n * Walk a messenger capability collection type (e.g. `RootMessengerActions` or\n * `RootMessengerEvents`) to gather all of the consitutent capability types\n * (e.g. `NetworkControllerAddNetworkAction`), then package them so that they\n * can be displayed within the documentation.\n *\n * Messenger capabilities that cannot be extracted for some reason are captured\n * separately.\n *\n * @param args - The arguments to this function.\n * @param args.projectPath - Absolute path to the project root.\n * @param args.capabilityKind - Whether these are actions or events.\n * @param args.capabilityCollectionTypeReference - A reference to a messenger\n * capability collection type within the project, in `<file>#<TypeName>` format.\n * @param args.capabilityCollectionTypeDeclaration - The type declaration\n * representing a collection of messenger capabilities.\n * @param args.commandLineOptionName - The command-line option the reference\n * came from, used in errors.\n * @returns The extracted capabilities along with skipped capabilities.\n * @throws If the capability collection type resolved to `any` or `unknown`.\n */\nfunction extractFromMessengerCapabilitiesUnionTypeDeclaration({\n projectPath,\n capabilityKind,\n capabilityCollectionTypeReference,\n capabilityCollectionTypeDeclaration,\n commandLineOptionName,\n}: {\n projectPath: string;\n capabilityKind: 'action' | 'event';\n capabilityCollectionTypeReference: RootCapabilitiesTypeReference;\n capabilityCollectionTypeDeclaration: TypeAliasDeclaration;\n commandLineOptionName: string;\n}): {\n capabilityPackets: MessengerCapabilityPacket[];\n skippedCapabilities: SkippedCapabilities;\n} {\n const capabilityCollectionType = capabilityCollectionTypeDeclaration\n .getTypeNodeOrThrow()\n .getType();\n\n // If one or more of the constituent capabilities in the collection is `any`\n // or `unknown` — e.g. its import failed — then the type of the whole\n // collection will also be `any` or `unknown`. Fail instead of emitting a\n // catalog that looks complete but silently isn't.\n if (\n capabilityCollectionType.isAny() ||\n capabilityCollectionType.isUnknown()\n ) {\n throw new Error(\n `${capabilityCollectionTypeReference.filePath}#${capabilityCollectionTypeReference.typeName}, named by ${commandLineOptionName}, ` +\n `resolved to \\`${capabilityCollectionType.getText()}\\`. ` +\n `It's likely that an individual action or event type is also \\`${capabilityCollectionType.getText()}\\`, ` +\n `which may be due to a failed import. ` +\n `You will need to fix this first before generating docs for this project.`,\n );\n }\n\n const skippedCapabilities: SkippedCapabilities = {\n unnamedCapabilities: [],\n unextractableCapabilities: [],\n };\n\n // A project with no capabilities of this kind aliases the union to `never`.\n if (capabilityCollectionType.isNever()) {\n return {\n capabilityPackets: [],\n skippedCapabilities,\n };\n }\n\n const individualCapabilityTypes = capabilityCollectionType.isUnion()\n ? capabilityCollectionType.getUnionTypes()\n : [capabilityCollectionType];\n const capabilityPackets: MessengerCapabilityPacket[] = [];\n\n for (const capabilityType of individualCapabilityTypes) {\n const capabilityTypeDeclaration = findMessengerCapabilityTypeDeclaration(\n capabilityType,\n capabilityCollectionTypeDeclaration,\n individualCapabilityTypes.length === 1,\n );\n if (!capabilityTypeDeclaration) {\n skippedCapabilities.unnamedCapabilities.push(\n summarizeType(capabilityType, capabilityCollectionTypeDeclaration),\n );\n continue;\n }\n\n const classifiedTypeDeclaration =\n classifyMessengerCapabilityTypeDeclaration(\n capabilityTypeDeclaration,\n capabilityKind,\n );\n const capabilityPacket =\n classifiedTypeDeclaration &&\n extractFromMessengerCapabilityTypeDeclaration(\n classifiedTypeDeclaration,\n projectPath,\n );\n if (!capabilityPacket) {\n const sourceFile = capabilityTypeDeclaration\n .getSourceFile()\n .getFilePath();\n skippedCapabilities.unextractableCapabilities.push(\n `${capabilityTypeDeclaration.getName()} (${path.relative(projectPath, sourceFile)}:${capabilityTypeDeclaration.getStartLineNumber()})`,\n );\n continue;\n }\n\n capabilityPackets.push(capabilityPacket);\n }\n\n return { capabilityPackets, skippedCapabilities };\n}\n\n/**\n * Resolves `<file>#<TypeName>` references to messenger actions and events\n * collection types within the given project (e.g. `RootMessengerActions` or\n * `RootMessengerEvents`), walks the collection to gather all of the containing\n * capability types (e.g. `NetworkControllerAddNetworkAction`), then packages\n * them so that they can be displayed within the documentation site.\n *\n * @param args - The arguments to this function.\n * @param args.projectPath -Absolute path to the project to scan.\n * @param args.rootActionsTypeReference - A reference to a messenger\n * actions collection type within the project, in `<file>#<TypeName>` format.\n * @param args.rootEventsTypeReference - A reference to a messenger events\n * collection type within the project, in `<file>#<TypeName>` format.\n * @returns The extracted capabilities plus any capabilities that were skipped.\n */\nexport function discoverFromRootMessengerCapabilitiesTypes({\n projectPath,\n rootActionsTypeReference,\n rootEventsTypeReference,\n}: {\n projectPath: string;\n rootActionsTypeReference: RootCapabilitiesTypeReference;\n rootEventsTypeReference: RootCapabilitiesTypeReference;\n}): {\n capabilityPackets: MessengerCapabilityPacket[];\n skippedCapabilities: SkippedCapabilities;\n} {\n const project = createProject();\n const capabilityPacketCollections = [\n [rootActionsTypeReference, 'action', '--root-actions'],\n [rootEventsTypeReference, 'event', '--root-events'],\n ] as const;\n const allCapabilityPackets: MessengerCapabilityPacket[] = [];\n const allSkippedCapabilities: SkippedCapabilities = {\n unnamedCapabilities: [],\n unextractableCapabilities: [],\n };\n\n for (const [\n capabilitiesCollectionTypeReference,\n kind,\n commandLineOptionName,\n ] of capabilityPacketCollections) {\n const capabilitiesCollectionTypeDeclaration =\n resolveMessengerCapabilitiesTypeReference({\n project,\n projectPath,\n reference: capabilitiesCollectionTypeReference,\n commandLineOptionName,\n });\n const { capabilityPackets, skippedCapabilities } =\n extractFromMessengerCapabilitiesUnionTypeDeclaration({\n projectPath,\n capabilityKind: kind,\n capabilityCollectionTypeReference: capabilitiesCollectionTypeReference,\n capabilityCollectionTypeDeclaration:\n capabilitiesCollectionTypeDeclaration,\n commandLineOptionName,\n });\n allCapabilityPackets.push(...capabilityPackets);\n allSkippedCapabilities.unnamedCapabilities.push(\n ...skippedCapabilities.unnamedCapabilities,\n );\n allSkippedCapabilities.unextractableCapabilities.push(\n ...skippedCapabilities.unextractableCapabilities,\n );\n }\n\n return {\n capabilityPackets: allCapabilityPackets,\n skippedCapabilities: allSkippedCapabilities,\n };\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import { Project } from 'ts-morph';
2
+ /**
3
+ * Create a ts-morph Project configured for reading messenger capability types.
4
+ *
5
+ * Both discovery strategies share this: `scan` adds every file it can find so
6
+ * the checker can resolve cross-file references, while `root-messenger` adds
7
+ * only the entry files and lets the checker pull in the rest.
8
+ *
9
+ * @returns A new ts-morph Project.
10
+ */
11
+ export declare function createProject(): Project;
12
+ //# sourceMappingURL=ts-project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ts-project.d.ts","sourceRoot":"","sources":["../src/ts-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAM,MAAM,UAAU,CAAC;AAEvC;;;;;;;;GAQG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAiBvC"}
@@ -0,0 +1,29 @@
1
+ import { Project, ts } from 'ts-morph';
2
+ /**
3
+ * Create a ts-morph Project configured for reading messenger capability types.
4
+ *
5
+ * Both discovery strategies share this: `scan` adds every file it can find so
6
+ * the checker can resolve cross-file references, while `root-messenger` adds
7
+ * only the entry files and lets the checker pull in the rest.
8
+ *
9
+ * @returns A new ts-morph Project.
10
+ */
11
+ export function createProject() {
12
+ return new Project({
13
+ compilerOptions: {
14
+ allowJs: false,
15
+ noEmit: true,
16
+ // Match the project's permissive defaults — we only need symbol
17
+ // resolution, not full typechecking, so a project's own strictness
18
+ // settings shouldn't be able to fail the docs build.
19
+ strict: false,
20
+ skipLibCheck: true,
21
+ // Explicit module options so cross-file symbol resolution works
22
+ // regardless of the host process's tsconfig.
23
+ target: ts.ScriptTarget.ESNext,
24
+ module: ts.ModuleKind.ESNext,
25
+ moduleResolution: ts.ModuleResolutionKind.NodeJs,
26
+ },
27
+ });
28
+ }
29
+ //# sourceMappingURL=ts-project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ts-project.js","sourceRoot":"","sources":["../src/ts-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAEvC;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,OAAO,CAAC;QACjB,eAAe,EAAE;YACf,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,IAAI;YACZ,gEAAgE;YAChE,mEAAmE;YACnE,qDAAqD;YACrD,MAAM,EAAE,KAAK;YACb,YAAY,EAAE,IAAI;YAClB,gEAAgE;YAChE,6CAA6C;YAC7C,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM;YAC9B,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM;YAC5B,gBAAgB,EAAE,EAAE,CAAC,oBAAoB,CAAC,MAAM;SACjD;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { Project, ts } from 'ts-morph';\n\n/**\n * Create a ts-morph Project configured for reading messenger capability types.\n *\n * Both discovery strategies share this: `scan` adds every file it can find so\n * the checker can resolve cross-file references, while `root-messenger` adds\n * only the entry files and lets the checker pull in the rest.\n *\n * @returns A new ts-morph Project.\n */\nexport function createProject(): Project {\n return new Project({\n compilerOptions: {\n allowJs: false,\n noEmit: true,\n // Match the project's permissive defaults — we only need symbol\n // resolution, not full typechecking, so a project's own strictness\n // settings shouldn't be able to fail the docs build.\n strict: false,\n skipLibCheck: true,\n // Explicit module options so cross-file symbol resolution works\n // regardless of the host process's tsconfig.\n target: ts.ScriptTarget.ESNext,\n module: ts.ModuleKind.ESNext,\n moduleResolution: ts.ModuleResolutionKind.NodeJs,\n },\n });\n}\n"]}
@@ -44,4 +44,4 @@ export type NamespaceGroup = {
44
44
  actions: MessengerCapabilityPacket[];
45
45
  events: MessengerCapabilityPacket[];
46
46
  };
47
- //# sourceMappingURL=types.d.cts.map
47
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,2FAA2F;IAC3F,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;IACzB,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,gBAAgB,EAAE,MAAM,CAAC;IACzB,qFAAqF;IACrF,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,yBAAyB,EAAE,CAAC;IACrC,MAAM,EAAE,yBAAyB,EAAE,CAAC;CACrC,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * A documented parameter for an action handler or event payload — name from\n * the JSDoc `@param` tag, description from the tag's comment body.\n */\nexport type DocumentedParameter = {\n name: string;\n description: string;\n};\n\n/**\n * Information about a messenger action or event extracted from its type\n * in a source file.\n */\nexport type MessengerCapabilityPacket = {\n /** The capability type's TypeScript identifier, e.g. `NetworkControllerGetStateAction`. */\n typeName: string;\n /** The capability's messenger key, e.g. `NetworkController:getState`. */\n typeString: string;\n /** Whether the capability is an action (request/response) or an event (broadcast). */\n kind: 'action' | 'event';\n /** Cleaned description body — content above the first JSDoc tag. */\n jsDoc: string;\n /**\n * Documented parameters — populated from `@param` tags, in source order.\n * For actions these describe the handler's arguments; for events they\n * describe the payload tuple's positional elements.\n */\n params: DocumentedParameter[];\n /** Documented return value — populated from a `@returns` tag, if any. */\n returns: string;\n /** Raw type text of the handler (action) or payload (event). */\n handlerOrPayload: string;\n /** Path to the file the capability was declared in, relative to the project root. */\n sourceFile: string;\n /** 1-based line number of the capability declaration. */\n line: number;\n /** Whether the capability is marked `@deprecated`. */\n deprecated: boolean;\n};\n\n/**\n * A namespace's actions and events, after dedup and sorting.\n */\nexport type NamespaceGroup = {\n namespace: string;\n actions: MessengerCapabilityPacket[];\n events: MessengerCapabilityPacket[];\n};\n"]}