@metamask-previews/messenger-cli 0.1.0-preview-2a71f636e → 0.1.0-preview-212d43f

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 (58) hide show
  1. package/CHANGELOG.md +0 -4
  2. package/package.json +4 -19
  3. package/dist/docs/cli.cjs +0 -199
  4. package/dist/docs/cli.cjs.map +0 -1
  5. package/dist/docs/cli.d.cts +0 -3
  6. package/dist/docs/cli.d.cts.map +0 -1
  7. package/dist/docs/cli.d.mts +0 -3
  8. package/dist/docs/cli.d.mts.map +0 -1
  9. package/dist/docs/cli.mjs +0 -198
  10. package/dist/docs/cli.mjs.map +0 -1
  11. package/dist/docs/discovery.cjs +0 -46
  12. package/dist/docs/discovery.cjs.map +0 -1
  13. package/dist/docs/discovery.d.cts +0 -17
  14. package/dist/docs/discovery.d.cts.map +0 -1
  15. package/dist/docs/discovery.d.mts +0 -17
  16. package/dist/docs/discovery.d.mts.map +0 -1
  17. package/dist/docs/discovery.mjs +0 -41
  18. package/dist/docs/discovery.mjs.map +0 -1
  19. package/dist/docs/extraction.cjs +0 -580
  20. package/dist/docs/extraction.cjs.map +0 -1
  21. package/dist/docs/extraction.d.cts +0 -10
  22. package/dist/docs/extraction.d.cts.map +0 -1
  23. package/dist/docs/extraction.d.mts +0 -10
  24. package/dist/docs/extraction.d.mts.map +0 -1
  25. package/dist/docs/extraction.mjs +0 -554
  26. package/dist/docs/extraction.mjs.map +0 -1
  27. package/dist/docs/generate.cjs +0 -254
  28. package/dist/docs/generate.cjs.map +0 -1
  29. package/dist/docs/generate.d.cts +0 -27
  30. package/dist/docs/generate.d.cts.map +0 -1
  31. package/dist/docs/generate.d.mts +0 -27
  32. package/dist/docs/generate.d.mts.map +0 -1
  33. package/dist/docs/generate.mjs +0 -227
  34. package/dist/docs/generate.mjs.map +0 -1
  35. package/dist/docs/markdown.cjs +0 -210
  36. package/dist/docs/markdown.cjs.map +0 -1
  37. package/dist/docs/markdown.d.cts +0 -35
  38. package/dist/docs/markdown.d.cts.map +0 -1
  39. package/dist/docs/markdown.d.mts +0 -35
  40. package/dist/docs/markdown.d.mts.map +0 -1
  41. package/dist/docs/markdown.mjs +0 -203
  42. package/dist/docs/markdown.mjs.map +0 -1
  43. package/dist/docs/types.cjs +0 -3
  44. package/dist/docs/types.cjs.map +0 -1
  45. package/dist/docs/types.d.cts +0 -23
  46. package/dist/docs/types.d.cts.map +0 -1
  47. package/dist/docs/types.d.mts +0 -23
  48. package/dist/docs/types.d.mts.map +0 -1
  49. package/dist/docs/types.mjs +0 -2
  50. package/dist/docs/types.mjs.map +0 -1
  51. package/template/docusaurus.config.ts +0 -123
  52. package/template/src/css/custom.css +0 -314
  53. package/template/static/fonts/MM-Sans/MM_Sans_Mono-Regular.woff2 +0 -0
  54. package/template/static/img/favicons/favicon-96x96.png +0 -0
  55. package/template/static/img/metamask-fox.svg +0 -12
  56. package/template/static/img/metamask-logo-dark.svg +0 -3
  57. package/template/static/img/metamask-logo.svg +0 -3
  58. package/template/tsconfig.json +0 -13
@@ -1,41 +0,0 @@
1
- import { glob } from "glob";
2
- /**
3
- * Find all non-test TypeScript source files in a directory.
4
- * Skips node_modules, dist, test directories, and declaration files.
5
- *
6
- * @param dir - The directory to search.
7
- * @returns A promise that resolves to an array of absolute file paths.
8
- */
9
- export async function findTsFiles(dir) {
10
- return await glob('**/*.ts', {
11
- cwd: dir,
12
- absolute: true,
13
- ignore: [
14
- '**/node_modules/**',
15
- '**/dist/**',
16
- '**/__tests__/**',
17
- '**/tests/**',
18
- '**/test/**',
19
- '**/__mocks__/**',
20
- '**/*.test.ts',
21
- '**/*.test-d.ts',
22
- '**/*.spec.ts',
23
- '**/*.d.ts',
24
- ],
25
- });
26
- }
27
- /**
28
- * Find all `.d.cts` declaration files in a directory.
29
- * Skips nested node_modules subdirectories.
30
- *
31
- * @param dir - The directory to search.
32
- * @returns A promise that resolves to an array of absolute file paths.
33
- */
34
- export async function findDtsFiles(dir) {
35
- return await glob('**/*.d.cts', {
36
- cwd: dir,
37
- absolute: true,
38
- ignore: ['**/node_modules/**'],
39
- });
40
- }
41
- //# sourceMappingURL=discovery.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"discovery.mjs","sourceRoot":"","sources":["../../src/docs/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,aAAa;AAE5B;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW;IAC3C,OAAO,MAAM,IAAI,CAAC,SAAS,EAAE;QAC3B,GAAG,EAAE,GAAG;QACR,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE;YACN,oBAAoB;YACpB,YAAY;YACZ,iBAAiB;YACjB,aAAa;YACb,YAAY;YACZ,iBAAiB;YACjB,cAAc;YACd,gBAAgB;YAChB,cAAc;YACd,WAAW;SACZ;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAW;IAC5C,OAAO,MAAM,IAAI,CAAC,YAAY,EAAE;QAC9B,GAAG,EAAE,GAAG;QACR,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,CAAC,oBAAoB,CAAC;KAC/B,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { glob } from 'glob';\n\n/**\n * Find all non-test TypeScript source files in a directory.\n * Skips node_modules, dist, test directories, and declaration files.\n *\n * @param dir - The directory to search.\n * @returns A promise that resolves to an array of absolute file paths.\n */\nexport async function findTsFiles(dir: string): Promise<string[]> {\n return await glob('**/*.ts', {\n cwd: dir,\n absolute: true,\n ignore: [\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 ],\n });\n}\n\n/**\n * Find all `.d.cts` declaration files in a directory.\n * Skips nested node_modules subdirectories.\n *\n * @param dir - The directory to search.\n * @returns A promise that resolves to an array of absolute file paths.\n */\nexport async function findDtsFiles(dir: string): Promise<string[]> {\n return await glob('**/*.d.cts', {\n cwd: dir,\n absolute: true,\n ignore: ['**/node_modules/**'],\n });\n}\n"]}
@@ -1,580 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.extractFromFile = void 0;
27
- const node_1 = require("@metamask/utils/node");
28
- const fs = __importStar(require("node:fs/promises"));
29
- const path = __importStar(require("node:path"));
30
- const typescript_1 = require("typescript");
31
- /**
32
- * Extract string constants from top-level variable declarations in a source file.
33
- * Only looks at top-level `const x = 'string'` or `const x = 'string' as const`.
34
- *
35
- * @param sourceFile - The TypeScript source file to extract constants from.
36
- * @returns A map of constant name to string value.
37
- */
38
- function extractStringConstants(sourceFile) {
39
- const names = new Map();
40
- for (const statement of sourceFile.statements) {
41
- if (!(0, typescript_1.isVariableStatement)(statement)) {
42
- continue;
43
- }
44
- for (const decl of statement.declarationList.declarations) {
45
- if (!(0, typescript_1.isIdentifier)(decl.name)) {
46
- continue;
47
- }
48
- if (decl.initializer) {
49
- const init = decl.initializer;
50
- if ((0, typescript_1.isStringLiteral)(init)) {
51
- names.set(decl.name.text, init.text);
52
- }
53
- else if ((0, typescript_1.isAsExpression)(init) && (0, typescript_1.isStringLiteral)(init.expression)) {
54
- names.set(decl.name.text, init.expression.text);
55
- }
56
- }
57
- // Handle `declare const x: "value"` (common in .d.cts files)
58
- if (!decl.initializer &&
59
- decl.type &&
60
- (0, typescript_1.isLiteralTypeNode)(decl.type) &&
61
- (0, typescript_1.isStringLiteral)(decl.type.literal)) {
62
- names.set(decl.name.text, decl.type.literal.text);
63
- }
64
- }
65
- }
66
- return names;
67
- }
68
- /**
69
- * Resolve the value of `controllerName` (or similar constant) defined in the
70
- * same file or imported from a local `./constants*` module (single-hop only).
71
- *
72
- * @param sourceFile - The TypeScript source file to search.
73
- * @param filePath - The absolute path of the source file on disk.
74
- * @returns A promise that resolves to a map of constant name to resolved string value.
75
- */
76
- async function resolveControllerName(sourceFile, filePath) {
77
- const names = extractStringConstants(sourceFile);
78
- // Chase single-hop local imports (no further recursion):
79
- // import { BRIDGE_CONTROLLER_NAME } from './constants/bridge';
80
- for (const statement of sourceFile.statements) {
81
- if (!(0, typescript_1.isImportDeclaration)(statement) ||
82
- !statement.moduleSpecifier ||
83
- !(0, typescript_1.isStringLiteral)(statement.moduleSpecifier)) {
84
- continue;
85
- }
86
- const spec = statement.moduleSpecifier.text;
87
- if (!spec.startsWith('.')) {
88
- continue;
89
- }
90
- const dir = path.dirname(filePath);
91
- const isDts = filePath.endsWith('.d.cts') || filePath.endsWith('.d.ts');
92
- // Strip .cjs/.js extension from specifier for .d.cts resolution
93
- const bareSpec = spec.replace(/\.(c|m)?js$/u, '');
94
- const candidates = isDts
95
- ? [
96
- path.join(dir, `${bareSpec}.d.cts`),
97
- path.join(dir, bareSpec, 'index.d.cts'),
98
- path.join(dir, `${bareSpec}.d.ts`),
99
- path.join(dir, bareSpec, 'index.d.ts'),
100
- ]
101
- : [path.join(dir, `${spec}.ts`), path.join(dir, spec, 'index.ts')];
102
- for (const candidate of candidates) {
103
- if (!(await (0, node_1.fileExists)(candidate))) {
104
- continue;
105
- }
106
- const content = await fs.readFile(candidate, 'utf8');
107
- const sf = (0, typescript_1.createSourceFile)(candidate, content, typescript_1.ScriptTarget.Latest, true);
108
- // Only extract constants — do NOT follow further imports
109
- const imported = extractStringConstants(sf);
110
- if (statement.importClause?.namedBindings &&
111
- (0, typescript_1.isNamedImports)(statement.importClause.namedBindings)) {
112
- for (const element of statement.importClause.namedBindings.elements) {
113
- const importedName = (element.propertyName ?? element.name).text;
114
- const localName = element.name.text;
115
- const value = imported.get(importedName);
116
- if (value !== undefined) {
117
- names.set(localName, value);
118
- }
119
- }
120
- }
121
- break;
122
- }
123
- }
124
- return names;
125
- }
126
- /**
127
- * Resolve a template-literal or string-literal `type` property to its string
128
- * value. Returns null if unresolvable.
129
- *
130
- * @param node - The expression node to resolve.
131
- * @param constants - A map of known constant names to their string values.
132
- * @returns The resolved string value, or null if unresolvable.
133
- */
134
- function resolveTypeString(node, constants) {
135
- if ((0, typescript_1.isStringLiteral)(node) || (0, typescript_1.isNoSubstitutionTemplateLiteral)(node)) {
136
- return node.text;
137
- }
138
- if ((0, typescript_1.isTemplateExpression)(node)) {
139
- let result = node.head.text;
140
- for (const span of node.templateSpans) {
141
- // typeof X → resolve X
142
- if ((0, typescript_1.isTypeOfExpression)(span.expression)) {
143
- if ((0, typescript_1.isIdentifier)(span.expression.expression)) {
144
- const val = constants.get(span.expression.expression.text);
145
- if (val === undefined) {
146
- return null;
147
- }
148
- result += val;
149
- }
150
- else {
151
- return null;
152
- }
153
- }
154
- else if ((0, typescript_1.isIdentifier)(span.expression)) {
155
- const val = constants.get(span.expression.text);
156
- if (val === undefined) {
157
- return null;
158
- }
159
- result += val;
160
- }
161
- else {
162
- return null;
163
- }
164
- result += span.literal.text;
165
- }
166
- return result;
167
- }
168
- return null;
169
- }
170
- /**
171
- * Resolve a TemplateLiteralTypeNode (used in type positions like
172
- * `type: \`${typeof controllerName}:name\``) to its string value.
173
- *
174
- * @param node - The template literal type node to resolve.
175
- * @param constants - A map of known constant names to their string values.
176
- * @returns The resolved string value, or null if unresolvable.
177
- */
178
- function resolveTemplateLiteralType(node, constants) {
179
- let result = node.head.text;
180
- for (const span of node.templateSpans) {
181
- // In type position, `typeof X` is a TypeQueryNode
182
- if ((0, typescript_1.isTypeQueryNode)(span.type) && (0, typescript_1.isIdentifier)(span.type.exprName)) {
183
- const val = constants.get(span.type.exprName.text);
184
- if (val === undefined) {
185
- return null;
186
- }
187
- result += val;
188
- }
189
- else if ((0, typescript_1.isLiteralTypeNode)(span.type) &&
190
- (0, typescript_1.isStringLiteral)(span.type.literal)) {
191
- result += span.type.literal.text;
192
- }
193
- else {
194
- return null;
195
- }
196
- result += span.literal.text;
197
- }
198
- return result;
199
- }
200
- /**
201
- * Extract cleaned JSDoc body text from a node.
202
- *
203
- * @param node - The AST node to extract JSDoc from.
204
- * @param sourceFile - The source file containing the node.
205
- * @returns The cleaned JSDoc text, or empty string if none.
206
- */
207
- function extractJsDocText(node, sourceFile) {
208
- const jsDocs = (0, typescript_1.getJSDocCommentsAndTags)(node);
209
- if (jsDocs.length === 0) {
210
- return '';
211
- }
212
- const jsDoc = jsDocs[0];
213
- if (!(0, typescript_1.isJSDoc)(jsDoc)) {
214
- return '';
215
- }
216
- const fullText = sourceFile.getFullText();
217
- const raw = fullText.substring(jsDoc.getFullStart(), jsDoc.getEnd()).trim();
218
- // Handle single-line JSDoc: /** Gets the current state. */
219
- const singleLineMatch = raw.match(/^\/\*\*\s*(.*?)\s*\*\/$/u);
220
- if (singleLineMatch) {
221
- let text = singleLineMatch[1].replace(/^\*\s*/u, '');
222
- // Apply same escaping as multi-line path
223
- text = text.replace(/\{@link\s+([^}]+)\}/gu, '`$1`');
224
- text = text.replace(/`[^`]*`|(\{)|(\})/gu, (match, open, close) => {
225
- if (open) {
226
- return '\\{';
227
- }
228
- if (close) {
229
- return '\\}';
230
- }
231
- return match;
232
- });
233
- return text || '';
234
- }
235
- // Strip comment delimiters, leading asterisks, and @param/@returns/@see tags
236
- const lines = raw.split('\n');
237
- const cleaned = [];
238
- const skippedTags = [
239
- '@param',
240
- '@returns',
241
- '@see',
242
- '@throws',
243
- '@template',
244
- '@example',
245
- ];
246
- let currentTag = null;
247
- let deprecatedParts = [];
248
- for (const rawLine of lines) {
249
- let trimmed = rawLine.trim();
250
- if (trimmed === '/**' || trimmed === '*/') {
251
- continue;
252
- }
253
- if (trimmed.startsWith('* ')) {
254
- trimmed = trimmed.slice(2);
255
- }
256
- else if (trimmed === '*') {
257
- trimmed = '';
258
- }
259
- else if (trimmed.startsWith('*')) {
260
- trimmed = trimmed.slice(1);
261
- }
262
- // Check if this line starts a new tag
263
- if (trimmed.startsWith('@')) {
264
- // Flush any accumulated deprecated text
265
- if (currentTag === 'deprecated' && deprecatedParts.length > 0) {
266
- cleaned.push(`**Deprecated:** ${deprecatedParts.join(' ')}`);
267
- deprecatedParts = [];
268
- }
269
- if (trimmed.startsWith('@deprecated')) {
270
- currentTag = 'deprecated';
271
- const depText = trimmed.slice('@deprecated'.length).trim();
272
- if (depText) {
273
- deprecatedParts.push(depText);
274
- }
275
- continue;
276
- }
277
- currentTag = skippedTags.some((tag) => trimmed.startsWith(tag))
278
- ? 'skip'
279
- : null;
280
- if (currentTag === 'skip') {
281
- continue;
282
- }
283
- }
284
- else if (currentTag === 'skip') {
285
- if (trimmed === '') {
286
- currentTag = null;
287
- }
288
- else {
289
- continue;
290
- }
291
- }
292
- else if (currentTag === 'deprecated') {
293
- if (trimmed === '') {
294
- // End of deprecated tag
295
- if (deprecatedParts.length > 0) {
296
- cleaned.push(`**Deprecated:** ${deprecatedParts.join(' ')}`);
297
- deprecatedParts = [];
298
- }
299
- currentTag = null;
300
- }
301
- else {
302
- deprecatedParts.push(trimmed);
303
- continue;
304
- }
305
- }
306
- cleaned.push(trimmed);
307
- }
308
- // Flush any remaining deprecated text
309
- if (deprecatedParts.length > 0) {
310
- cleaned.push(`**Deprecated:** ${deprecatedParts.join(' ')}`);
311
- }
312
- let result = cleaned.join('\n').trim();
313
- // Convert JSDoc {@link X} references to markdown backtick code
314
- result = result.replace(/\{@link\s+([^}]+)\}/gu, '`$1`');
315
- // Escape remaining curly braces for MDX safety (but not inside backtick code spans)
316
- result = result.replace(/`[^`]*`|(\{)|(\})/gu, (match, open, close) => {
317
- if (open) {
318
- return '\\{';
319
- }
320
- if (close) {
321
- return '\\}';
322
- }
323
- return match; // preserve content inside backticks
324
- });
325
- return result;
326
- }
327
- /**
328
- * Check whether a node has an `@deprecated` JSDoc tag.
329
- *
330
- * @param node - The AST node to check.
331
- * @returns True if the node has an `@deprecated` tag.
332
- */
333
- function isDeprecated(node) {
334
- const tags = (0, typescript_1.getJSDocTags)(node);
335
- return tags.some((tag) => tag.tagName.text === 'deprecated');
336
- }
337
- /**
338
- * Collect method info from all class declarations in a source file.
339
- * Returns a map keyed by "ClassName.methodName".
340
- *
341
- * @param sourceFile - The TypeScript source file to scan.
342
- * @returns A map of "ClassName.methodName" to method info.
343
- */
344
- function collectClassMethods(sourceFile) {
345
- const methods = new Map();
346
- for (const statement of sourceFile.statements) {
347
- if (!(0, typescript_1.isClassDeclaration)(statement) || !statement.name) {
348
- continue;
349
- }
350
- const className = statement.name.text;
351
- for (const member of statement.members) {
352
- if (!(0, typescript_1.isMethodDeclaration)(member) ||
353
- !member.name ||
354
- !(0, typescript_1.isIdentifier)(member.name)) {
355
- continue;
356
- }
357
- const methodName = member.name.text;
358
- // Build parameter list
359
- const params = member.parameters
360
- .map((param) => {
361
- const paramName = param.name.getText(sourceFile);
362
- const optional = param.questionToken ? '?' : '';
363
- const paramType = param.type
364
- ? param.type.getText(sourceFile)
365
- : 'unknown';
366
- return `${paramName}${optional}: ${paramType}`;
367
- })
368
- .join(', ');
369
- // Get return type
370
- const returnType = member.type ? member.type.getText(sourceFile) : 'void';
371
- // For async methods, the declared return type already includes Promise<>,
372
- // so we don't need to wrap again.
373
- const methodSignature = `(${params}) => ${returnType}`;
374
- const jsDoc = extractJsDocText(member, sourceFile);
375
- methods.set(`${className}.${methodName}`, {
376
- jsDoc,
377
- signature: methodSignature,
378
- });
379
- }
380
- }
381
- return methods;
382
- }
383
- /**
384
- * If `handlerText` matches `ClassName['methodName']`, look it up in classMethodInfo
385
- * and return the resolved signature. Otherwise return the original text.
386
- *
387
- * @param handlerText - The raw handler text to resolve.
388
- * @param classMethods - A map of class methods collected from the source file.
389
- * @returns An object with the resolved signature and any associated JSDoc.
390
- */
391
- function resolveHandler(handlerText, classMethods) {
392
- const match = handlerText.match(/^(\w+)\['(\w+)'\]$/u);
393
- if (match) {
394
- const key = `${match[1]}.${match[2]}`;
395
- const info = classMethods.get(key);
396
- if (info) {
397
- return { signature: info.signature, methodJsDoc: info.jsDoc };
398
- }
399
- }
400
- return { signature: handlerText, methodJsDoc: '' };
401
- }
402
- /**
403
- * Get the raw source text for a property value inside a type literal.
404
- *
405
- * @param members - The type literal members to search.
406
- * @param propName - The property name to find.
407
- * @param sourceFile - The source file for getText calls.
408
- * @returns The raw text of the property type, or empty string if not found.
409
- */
410
- function getPropertyText(members, propName, sourceFile) {
411
- for (const member of members) {
412
- if ((0, typescript_1.isPropertySignature)(member) &&
413
- member.name &&
414
- (0, typescript_1.isIdentifier)(member.name) &&
415
- member.name.text === propName &&
416
- member.type) {
417
- return member.type.getText(sourceFile).trim();
418
- }
419
- }
420
- return '';
421
- }
422
- // ---------------------------------------------------------------------------
423
- // Main extraction
424
- // ---------------------------------------------------------------------------
425
- /**
426
- * Extract messenger action/event type definitions from a single TypeScript file.
427
- *
428
- * @param filePath - The absolute path to the TypeScript file.
429
- * @param relBase - Base path for computing relative source paths.
430
- * @returns A promise that resolves to an array of extracted messenger item docs.
431
- */
432
- async function extractFromFile(filePath, relBase) {
433
- const content = await fs.readFile(filePath, 'utf8');
434
- const sourceFile = (0, typescript_1.createSourceFile)(filePath, content, typescript_1.ScriptTarget.Latest, true);
435
- const constants = await resolveControllerName(sourceFile, filePath);
436
- const classMethods = collectClassMethods(sourceFile);
437
- const items = [];
438
- const relPath = path.relative(relBase, filePath);
439
- // Type aliases and interfaces are always top-level statements
440
- for (const statement of sourceFile.statements) {
441
- // ---------------------------------------------------------------
442
- // Pattern 1: { type: '...'; handler/payload: ... }
443
- // Matches both:
444
- // type X = { type: '...'; handler: ... } (type alias with literal body)
445
- // interface X { type: '...'; handler: ... } (interface declaration)
446
- // ---------------------------------------------------------------
447
- let inlineNode;
448
- let inlineMembers;
449
- if ((0, typescript_1.isTypeAliasDeclaration)(statement) &&
450
- (0, typescript_1.isTypeLiteralNode)(statement.type)) {
451
- inlineNode = statement;
452
- inlineMembers = statement.type.members;
453
- }
454
- else if ((0, typescript_1.isInterfaceDeclaration)(statement)) {
455
- inlineNode = statement;
456
- inlineMembers = statement.members;
457
- }
458
- if (inlineNode && inlineMembers) {
459
- const typeName = inlineNode.name.text;
460
- const line = sourceFile.getLineAndCharacterOfPosition(inlineNode.getStart()).line +
461
- 1;
462
- // Find `type` property
463
- let typeString = null;
464
- for (const member of inlineMembers) {
465
- if ((0, typescript_1.isPropertySignature)(member) &&
466
- member.name &&
467
- (0, typescript_1.isIdentifier)(member.name) &&
468
- member.name.text === 'type' &&
469
- member.type) {
470
- if ((0, typescript_1.isLiteralTypeNode)(member.type)) {
471
- typeString = resolveTypeString(member.type.literal, constants);
472
- }
473
- else if ((0, typescript_1.isTemplateLiteralTypeNode)(member.type)) {
474
- typeString = resolveTemplateLiteralType(member.type, constants);
475
- }
476
- }
477
- }
478
- if (typeString?.includes(':')) {
479
- const handlerText = getPropertyText(inlineMembers, 'handler', sourceFile);
480
- const payloadText = getPropertyText(inlineMembers, 'payload', sourceFile);
481
- if (handlerText || payloadText) {
482
- const kind = handlerText ? 'action' : 'event';
483
- // For actions, resolve ClassName['methodName'] to actual signature + JSDoc
484
- let resolvedHandler = handlerText || payloadText;
485
- let typeAliasJsDoc = extractJsDocText(inlineNode, sourceFile);
486
- if (handlerText) {
487
- const resolved = resolveHandler(handlerText, classMethods);
488
- resolvedHandler = resolved.signature;
489
- // If the type alias has no JSDoc, use the method's JSDoc
490
- if (!typeAliasJsDoc && resolved.methodJsDoc) {
491
- typeAliasJsDoc = resolved.methodJsDoc;
492
- }
493
- }
494
- items.push({
495
- typeName,
496
- typeString,
497
- kind,
498
- jsDoc: typeAliasJsDoc,
499
- handlerOrPayload: resolvedHandler,
500
- sourceFile: relPath,
501
- line,
502
- deprecated: isDeprecated(inlineNode),
503
- });
504
- }
505
- }
506
- }
507
- // -------------------------------------------------------------------
508
- // Patterns 2 & 3 only apply to type aliases (generic type references)
509
- // -------------------------------------------------------------------
510
- if (!(0, typescript_1.isTypeAliasDeclaration)(statement)) {
511
- continue;
512
- }
513
- const node = statement;
514
- const typeName = node.name.text;
515
- const line = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
516
- // -------------------------------------------------------------------
517
- // Pattern 2: ControllerGetStateAction<typeof cn, State>
518
- // -------------------------------------------------------------------
519
- if ((0, typescript_1.isTypeReferenceNode)(node.type) &&
520
- (0, typescript_1.isIdentifier)(node.type.typeName) &&
521
- node.type.typeName.text === 'ControllerGetStateAction' &&
522
- node.type.typeArguments &&
523
- node.type.typeArguments.length >= 2) {
524
- const firstArg = node.type.typeArguments[0];
525
- const stateArg = node.type.typeArguments[1];
526
- let namespace = null;
527
- if ((0, typescript_1.isTypeQueryNode)(firstArg) && (0, typescript_1.isIdentifier)(firstArg.exprName)) {
528
- namespace = constants.get(firstArg.exprName.text) ?? null;
529
- }
530
- if ((0, typescript_1.isLiteralTypeNode)(firstArg) && (0, typescript_1.isStringLiteral)(firstArg.literal)) {
531
- namespace = firstArg.literal.text;
532
- }
533
- if (namespace) {
534
- items.push({
535
- typeName,
536
- typeString: `${namespace}:getState`,
537
- kind: 'action',
538
- jsDoc: extractJsDocText(node, sourceFile),
539
- handlerOrPayload: `() => ${stateArg.getText(sourceFile)}`,
540
- sourceFile: relPath,
541
- line,
542
- deprecated: isDeprecated(node),
543
- });
544
- }
545
- }
546
- // -------------------------------------------------------------------
547
- // Pattern 3: ControllerStateChangeEvent<typeof cn, State>
548
- // -------------------------------------------------------------------
549
- if ((0, typescript_1.isTypeReferenceNode)(node.type) &&
550
- (0, typescript_1.isIdentifier)(node.type.typeName) &&
551
- node.type.typeName.text === 'ControllerStateChangeEvent' &&
552
- node.type.typeArguments &&
553
- node.type.typeArguments.length >= 2) {
554
- const firstArg = node.type.typeArguments[0];
555
- const stateArg = node.type.typeArguments[1];
556
- let namespace = null;
557
- if ((0, typescript_1.isTypeQueryNode)(firstArg) && (0, typescript_1.isIdentifier)(firstArg.exprName)) {
558
- namespace = constants.get(firstArg.exprName.text) ?? null;
559
- }
560
- if ((0, typescript_1.isLiteralTypeNode)(firstArg) && (0, typescript_1.isStringLiteral)(firstArg.literal)) {
561
- namespace = firstArg.literal.text;
562
- }
563
- if (namespace) {
564
- items.push({
565
- typeName,
566
- typeString: `${namespace}:stateChange`,
567
- kind: 'event',
568
- jsDoc: extractJsDocText(node, sourceFile),
569
- handlerOrPayload: `[${stateArg.getText(sourceFile)}, Patch[]]`,
570
- sourceFile: relPath,
571
- line,
572
- deprecated: isDeprecated(node),
573
- });
574
- }
575
- }
576
- }
577
- return items;
578
- }
579
- exports.extractFromFile = extractFromFile;
580
- //# sourceMappingURL=extraction.cjs.map