@metamask-previews/platform-api-docs 0.0.0-preview-1275d0fda → 0.0.0-preview-6235c3779
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/extraction.cjs +357 -317
- package/dist/extraction.cjs.map +1 -1
- package/dist/extraction.d.cts +8 -7
- package/dist/extraction.d.cts.map +1 -1
- package/dist/extraction.d.mts +8 -7
- package/dist/extraction.d.mts.map +1 -1
- package/dist/extraction.mjs +357 -317
- package/dist/extraction.mjs.map +1 -1
- package/dist/generate.cjs.map +1 -1
- package/dist/generate.mjs.map +1 -1
- package/dist/markdown.cjs.map +1 -1
- package/dist/markdown.d.cts +2 -2
- package/dist/markdown.d.cts.map +1 -1
- package/dist/markdown.d.mts +2 -2
- package/dist/markdown.d.mts.map +1 -1
- package/dist/markdown.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +5 -5
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +5 -5
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +2 -2
- package/site/tsconfig.json +2 -4
package/dist/extraction.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extraction.mjs","sourceRoot":"","sources":["../src/extraction.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'node:path';\nimport type {\n InterfaceDeclaration,\n JSDocableNode,\n JSDocTag,\n MethodDeclaration,\n Node as TsMorphNode,\n PropertySignature,\n SourceFile,\n TemplateLiteralTypeNode,\n TypeAliasDeclaration,\n TypeElementTypes,\n TypeNode,\n} from 'ts-morph';\nimport { Node as NodeGuards, Project, ts } from 'ts-morph';\n\nimport type {\n ExtractedMessengerCapabilityType,\n MethodInfo,\n DocumentedParameter,\n} from './types';\n\n// ---------------------------------------------------------------------------\n// JSDoc utilities\n// ---------------------------------------------------------------------------\n\n/**\n * Convert `{@link X}` references inside a string to plain backtick code spans,\n * and escape any remaining (out-of-backtick) curly braces so the output is\n * safe to drop into MDX.\n *\n * @param text - The raw text to normalize.\n * @returns The text with `@link` resolved and stray braces escaped.\n */\nfunction escapeJsDocTextForMdx(text: string): string {\n const withLinksResolved = text.replace(/\\{@link\\s+([^}]+)\\}/gu, '`$1`');\n return withLinksResolved.replace(\n /`[^`]*`|(\\{)|(\\})/gu,\n (match, open: string | undefined, close: string | undefined) => {\n if (open) {\n return '\\\\{';\n }\n if (close) {\n return '\\\\}';\n }\n return match;\n },\n );\n}\n\n/**\n * Extract a JSDoc tag's comment text, normalizing whitespace so continuation\n * lines are joined with single spaces. ts-morph returns the raw comment with\n * embedded newlines preserved; we collapse those for the markdown output.\n *\n * @param tag - The JSDoc tag.\n * @returns The flattened comment text.\n */\nfunction extractJsDocTagComment(tag: JSDocTag): string {\n // istanbul ignore next: ts-morph returns null for tags without comment text,\n // but every fixture tag we extract from carries a comment.\n return (tag.getCommentText() ?? '').replace(/\\s+/gu, ' ').trim();\n}\n\n/**\n * Strip the conventional `- ` separator from the start of a `@param` tag's\n * comment. JSDoc style is `@param name - description`, and ts-morph hands us\n * back `- description` for the comment. The hyphen is purely cosmetic; we'd\n * rather render the description without it.\n *\n * @param comment - The flattened comment text from a `@param` tag.\n * @returns The comment with any leading `- ` (or `– `, `— `) removed.\n */\nfunction stripParamSeparator(comment: string): string {\n return comment.replace(/^[-–—]\\s*/u, '');\n}\n\n/**\n * Decompose a node's JSDoc into the parts the rendered docs need:\n *\n * - `description` — the body above the first tag, with `@deprecated` comments\n * appended as `**Deprecated:** <comment>` lines and normalized for MDX\n * (curly braces escaped, `{@link}` resolved),\n * - `params` — every `@param` tag in source order, with name and description,\n * - `returns` — the `@returns` tag's comment, or empty string if absent.\n *\n * Other tags (`@see`, `@throws`, `@template`, `@example`) are dropped.\n *\n * @param node - The AST node to extract JSDoc from.\n * @returns The decomposed JSDoc; empty strings/arrays when the node has no JSDoc.\n */\nfunction extractJsDoc(node: JSDocableNode): {\n description: string;\n params: DocumentedParameter[];\n returns: string;\n} {\n const jsDocs = node.getJsDocs();\n if (jsDocs.length === 0) {\n return { description: '', params: [], returns: '' };\n }\n\n const jsDoc = jsDocs[0];\n const descriptionBody = jsDoc.getDescription().trim();\n\n const deprecatedLines: string[] = [];\n const params: DocumentedParameter[] = [];\n let returns = '';\n\n for (const tag of jsDoc.getTags()) {\n const tagName = tag.getTagName();\n if (tagName === 'deprecated') {\n const comment = extractJsDocTagComment(tag);\n // istanbul ignore next: bare `@deprecated` (without explanatory text)\n // doesn't appear in messenger JSDoc in practice.\n deprecatedLines.push(\n comment ? `**Deprecated:** ${comment}` : '**Deprecated:**',\n );\n } else if (tagName === 'param' && NodeGuards.isJSDocParameterTag(tag)) {\n const nameNode = tag.getNameNode();\n // istanbul ignore next: `@param` tags without a name aren't valid JSDoc.\n if (!nameNode) {\n continue;\n }\n params.push({\n name: nameNode.getText(),\n description: escapeJsDocTextForMdx(\n stripParamSeparator(extractJsDocTagComment(tag)),\n ),\n });\n } else if (tagName === 'returns' || tagName === 'return') {\n returns = escapeJsDocTextForMdx(extractJsDocTagComment(tag));\n }\n }\n\n const description = escapeJsDocTextForMdx(\n [descriptionBody, ...deprecatedLines]\n .filter((line) => line.length > 0)\n .join('\\n'),\n );\n\n return { description, params, returns };\n}\n\n/**\n * Check whether a node has an `@deprecated` JSDoc tag.\n *\n * @param node - The AST node to check.\n * @returns True if the node has an `@deprecated` tag.\n */\nfunction isDeprecated(node: JSDocableNode): boolean {\n return node\n .getJsDocs()\n .flatMap((jsDoc) => jsDoc.getTags())\n .some((tag) => tag.getTagName() === 'deprecated');\n}\n\n// ---------------------------------------------------------------------------\n// Type-resolution helpers (powered by ts-morph's type checker)\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a TemplateLiteralTypeNode (e.g. `` `${typeof X}:foo` ``) to its\n * concrete string value, using the type checker to follow `typeof X` to its\n * literal type. Returns null if the type checker can't reduce it to a single\n * string literal.\n *\n * @param node - The template literal type node.\n * @returns The resolved string, or null.\n */\nfunction resolveTemplateLiteralType(\n node: TemplateLiteralTypeNode,\n): string | null {\n const type = node.getType();\n if (type.isStringLiteral()) {\n return type.getLiteralValueOrThrow() as string;\n }\n // istanbul ignore next: messenger fixtures always reduce template literal\n // types to a single string literal via `typeof X` constants.\n return null;\n}\n\n/**\n * Resolve a capability-type-constructor's first generic argument to a\n * namespace string. Accepts either `typeof X` (resolved via the type checker)\n * or a string literal.\n *\n * @param typeArg - The first generic argument node.\n * @returns The resolved namespace, or null.\n */\nfunction resolveNamespaceFromTypeArg(typeArg: TsMorphNode): string | null {\n if (NodeGuards.isTypeQuery(typeArg)) {\n const type = typeArg.getType();\n if (type.isStringLiteral()) {\n return type.getLiteralValueOrThrow() as string;\n }\n }\n if (NodeGuards.isLiteralTypeNode(typeArg)) {\n const literal = typeArg.getLiteral();\n // istanbul ignore else: only string literals are valid namespace args.\n if (NodeGuards.isStringLiteral(literal)) {\n return literal.getLiteralValue();\n }\n }\n // istanbul ignore next: namespace args are always a `typeof X` query or a\n // string literal in valid messenger usage.\n return null;\n}\n\n/**\n * If `typeNode` is `Class['method']`, resolve `Class` to its declaration\n * (across files if needed via the type checker) and look up the method by\n * name. Returns the method declaration when found.\n *\n * @param typeNode - The handler's type node.\n * @returns The method declaration, or null.\n */\nfunction resolveIndexedAccessMethod(\n typeNode: TypeNode | undefined,\n): MethodDeclaration | null {\n if (!typeNode || !NodeGuards.isIndexedAccessTypeNode(typeNode)) {\n return null;\n }\n const objectType = typeNode.getObjectTypeNode();\n const indexType = typeNode.getIndexTypeNode();\n\n // istanbul ignore next: handler indexed-access types in messenger fixtures\n // always reference a class via TypeReference.\n if (!NodeGuards.isTypeReference(objectType)) {\n return null;\n }\n // istanbul ignore next: the index in `Class['method']` is always a literal\n // type node in valid handler syntax.\n if (!NodeGuards.isLiteralTypeNode(indexType)) {\n return null;\n }\n const indexLiteral = indexType.getLiteral();\n // The index can be written as `'method'`, `\"method\"`, or `` `method` ``.\n // The first two land as `StringLiteral`; the bare template literal is a\n // `NoSubstitutionTemplateLiteral`.\n // istanbul ignore next: numeric/boolean indices aren't valid method names.\n if (\n !NodeGuards.isStringLiteral(indexLiteral) &&\n !NodeGuards.isNoSubstitutionTemplateLiteral(indexLiteral)\n ) {\n return null;\n }\n const methodName = indexLiteral.getLiteralValue();\n\n const classNameNode = objectType.getTypeName();\n // istanbul ignore next: qualified-name class references aren't used in\n // messenger handler types.\n if (!NodeGuards.isIdentifier(classNameNode)) {\n return null;\n }\n const localSymbol = classNameNode.getSymbol();\n // istanbul ignore next: a referenced class name always resolves to a symbol\n // in a typechecked project.\n if (!localSymbol) {\n return null;\n }\n // Follow the import alias (if any) so we can find the class declaration in\n // its home file.\n const symbol = localSymbol.getAliasedSymbol() ?? localSymbol;\n\n // istanbul ignore next: a resolved symbol always exposes its declarations\n // array in a typechecked project.\n for (const declaration of symbol.getDeclarations() ?? []) {\n if (NodeGuards.isClassDeclaration(declaration)) {\n const method = declaration.getMethod(methodName);\n if (method) {\n return method;\n }\n }\n }\n // istanbul ignore next: only reached if the indexed method isn't declared\n // on any of the resolved class declarations, which doesn't happen in valid\n // handler types.\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Method info\n// ---------------------------------------------------------------------------\n\n/**\n * Build a {@link MethodInfo} record for a class method — its textual\n * signature plus the JSDoc description, `@param`, and `@returns` extracted\n * from the method itself.\n *\n * @param method - The method declaration.\n * @returns The method info.\n */\nfunction buildMethodInfo(method: MethodDeclaration): MethodInfo {\n const signatureParams = method\n .getParameters()\n .map((param) => {\n const paramName = param.getNameNode().getText();\n const optional = param.hasQuestionToken() ? '?' : '';\n const typeNode = param.getTypeNode();\n // istanbul ignore next: handler parameters in messenger fixtures always\n // declare an explicit type.\n const paramType = typeNode ? typeNode.getText() : 'unknown';\n return `${paramName}${optional}: ${paramType}`;\n })\n .join(', ');\n\n const returnTypeNode = method.getReturnTypeNode();\n // istanbul ignore next: handler class methods in messenger fixtures always\n // declare an explicit return type.\n const returnType = returnTypeNode ? returnTypeNode.getText() : 'void';\n // For async methods, the declared return type already includes `Promise<>`,\n // so we don't need to wrap again.\n const signature = `(${signatureParams}) => ${returnType}`;\n\n const { description, params, returns } = extractJsDoc(method);\n\n return { jsDoc: description, params, returns, signature };\n}\n\n// ---------------------------------------------------------------------------\n// Messenger discovery\n// ---------------------------------------------------------------------------\n\n/**\n * A capability type declared somewhere reachable from a `*Messenger`, along\n * with the kind (action/event) it was found under.\n */\ntype MessengerCapabilityTypeDeclaration = {\n statement: TypeAliasDeclaration | InterfaceDeclaration;\n kind: 'action' | 'event';\n};\n\n/**\n * Find every `*Messenger` type alias in a source file, parse its\n * `Messenger<Namespace, Actions, Events>` generic arguments, and return the\n * capability-type declarations referenced from the Actions and Events slots\n * — paired with the kind under which they were referenced.\n *\n * The walker follows imported references via ts-morph's symbol resolution,\n * so capability types declared in sibling files (e.g. the auto-generated\n * `*-method-action-types.ts` files) are discovered even though only the\n * `*Messenger` declaration is local to this file.\n *\n * @param sourceFile - The TypeScript source file to scan.\n * @returns The list of locally- and transitively-referenced capability types.\n */\nfunction collectMessengerCapabilityTypeDeclarations(\n sourceFile: SourceFile,\n): MessengerCapabilityTypeDeclaration[] {\n const declarations: MessengerCapabilityTypeDeclaration[] = [];\n const seen = new Set<TsMorphNode>();\n\n for (const typeAlias of sourceFile.getTypeAliases()) {\n if (!typeAlias.getName().endsWith('Messenger')) {\n continue;\n }\n const body = typeAlias.getTypeNode();\n if (!body || !NodeGuards.isTypeReference(body)) {\n continue;\n }\n const typeArgs = body.getTypeArguments();\n if (typeArgs.length < 3) {\n continue;\n }\n\n walkCapabilityTypes(typeArgs[1], 'action', declarations, seen);\n walkCapabilityTypes(typeArgs[2], 'event', declarations, seen);\n }\n\n return declarations;\n}\n\n/**\n * Walk an Actions or Events type-argument tree and append the underlying\n * capability-type declarations to `output`. Unions are expanded. Type\n * references are resolved via ts-morph's symbol resolution (so imported\n * names are followed across files); a resolved alias whose body is itself a\n * union expands transparently, leaving the intermediate alias unrecorded.\n *\n * A resolved alias whose body is a single non-union type reference (e.g.\n * `type AllowedActions = ConnectivityControllerGetStateAction`) is treated\n * as an opaque re-export — the walk stops there, leaving the target to be\n * documented from its home package by the dedup logic later.\n *\n * For example, given:\n *\n * ```typescript\n * // NetworkController.ts\n * import type { NetworkControllerMethodActions } from './NetworkController-method-action-types';\n * type NetworkControllerActions =\n * | NetworkControllerGetStateAction\n * | NetworkControllerMethodActions;\n * type NetworkControllerMessenger = Messenger<typeof name, NetworkControllerActions, ...>;\n *\n * // NetworkController-method-action-types.ts\n * export type NetworkControllerAddNetworkAction = {\n * type: 'NetworkController:addNetwork';\n * handler: NetworkController['addNetwork'];\n * };\n * // ... more ...\n * export type NetworkControllerMethodActions =\n * | NetworkControllerAddNetworkAction\n * | ...;\n * ```\n *\n * walking the Actions slot yields each individual `NetworkController*Action`\n * declaration — both the local `NetworkControllerGetStateAction` and the\n * cross-file ones reached via `NetworkControllerMethodActions`.\n *\n * @param node - The Actions or Events type-argument node to walk.\n * @param kind - Whether to tag found declarations as 'action' or 'event'.\n * @param output - The list to append discovered declarations to.\n * @param seen - Declaration nodes already visited (prevents cycles and\n * duplicate work).\n */\nfunction walkCapabilityTypes(\n node: TsMorphNode,\n kind: 'action' | 'event',\n output: MessengerCapabilityTypeDeclaration[],\n seen: Set<TsMorphNode>,\n): void {\n if (NodeGuards.isUnionTypeNode(node)) {\n for (const member of node.getTypeNodes()) {\n walkCapabilityTypes(member, kind, output, seen);\n }\n return;\n }\n\n if (!NodeGuards.isTypeReference(node)) {\n return;\n }\n const nameNode = node.getTypeName();\n // istanbul ignore next: qualified-name references aren't used in messenger\n // generic arguments.\n if (!NodeGuards.isIdentifier(nameNode)) {\n return;\n }\n // For a TypeReference whose name was imported, `getSymbol()` returns the\n // import alias symbol — its only declaration is the `ImportSpecifier`.\n // `getAliasedSymbol()` follows the alias to the original declaration in\n // the imported file. Use it when present; otherwise fall back to the\n // (already-local) symbol.\n const localSymbol = nameNode.getSymbol();\n // istanbul ignore next: a referenced type name always resolves to a symbol\n // in a typechecked project.\n if (!localSymbol) {\n return;\n }\n const symbol = localSymbol.getAliasedSymbol() ?? localSymbol;\n\n // istanbul ignore next: a resolved symbol always exposes its declarations\n // array in a typechecked project.\n for (const declaration of symbol.getDeclarations() ?? []) {\n if (seen.has(declaration)) {\n continue;\n }\n seen.add(declaration);\n\n if (NodeGuards.isTypeAliasDeclaration(declaration)) {\n const aliasBody = declaration.getTypeNode();\n if (aliasBody && NodeGuards.isUnionTypeNode(aliasBody)) {\n // Umbrella union — descend through it without documenting the alias.\n walkCapabilityTypes(aliasBody, kind, output, seen);\n continue;\n }\n // A bare TypeReference body with no type arguments (e.g.\n // `type AllowedActions = ConnectivityControllerGetStateAction`) is a\n // plain re-export — leave the target to be documented from its home\n // package, not this one. TypeReferences *with* type arguments are\n // capability-type-constructor invocations (e.g.\n // `ControllerGetStateAction<typeof name, State>`) and are recorded.\n if (\n aliasBody &&\n NodeGuards.isTypeReference(aliasBody) &&\n aliasBody.getTypeArguments().length === 0\n ) {\n continue;\n }\n // TypeLiteral body, capability-type-constructor invocation, etc.\n output.push({ statement: declaration, kind });\n } else if (NodeGuards.isInterfaceDeclaration(declaration)) {\n output.push({ statement: declaration, kind });\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Per-statement extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Extract a single capability-type declaration to an\n * {@link ExtractedMessengerCapabilityType}.\n *\n * @param statement - The type alias or interface declaration.\n * @param kind - Whether this statement is referenced as an action or an event.\n * @param projectPath - Project root, used for computing relative source paths.\n * @returns The extracted capability, or null if no recognized pattern matches.\n */\nfunction extractFromMessengerCapabilityType(\n statement: TypeAliasDeclaration | InterfaceDeclaration,\n kind: 'action' | 'event',\n projectPath: string,\n): ExtractedMessengerCapabilityType | null {\n const inlineCapability = extractFromInlineMessengerCapabilityType(\n statement,\n kind,\n projectPath,\n );\n if (inlineCapability) {\n return inlineCapability;\n }\n\n if (NodeGuards.isTypeAliasDeclaration(statement)) {\n return extractFromCapabilityTypeConstructor(statement, kind, projectPath);\n }\n\n // istanbul ignore next: interface declarations always have members and\n // therefore an inline shape, so the inline branch above always returns\n // non-null here.\n return null;\n}\n\n/**\n * Try the inline messenger-capability-type pattern:\n * `{ type: '...'; handler: ... }` (action) or\n * `{ type: '...'; payload: ... }` (event), expressed as either a type alias\n * body or an interface body.\n *\n * @param statement - The type alias or interface declaration.\n * @param kind - The expected kind (action or event).\n * @param projectPath - Project root, used for computing relative source paths.\n * @returns The extracted capability, or null if the shape doesn't match.\n */\nfunction extractFromInlineMessengerCapabilityType(\n statement: TypeAliasDeclaration | InterfaceDeclaration,\n kind: 'action' | 'event',\n projectPath: string,\n): ExtractedMessengerCapabilityType | null {\n let members: TypeElementTypes[] | undefined;\n if (NodeGuards.isTypeAliasDeclaration(statement)) {\n const body = statement.getTypeNode();\n if (body && NodeGuards.isTypeLiteral(body)) {\n members = body.getMembers();\n }\n } else {\n members = statement.getMembers();\n }\n if (!members) {\n return null;\n }\n\n const typeString = resolveInlineTypeString(members);\n // istanbul ignore next: capabilities reachable via the messenger walk\n // always have a resolvable `Namespace:name` type string.\n if (!typeString?.includes(':')) {\n return null;\n }\n\n const handlerMember = getPropertyMember(members, 'handler');\n const payloadMember = getPropertyMember(members, 'payload');\n const rawSourceMember = kind === 'action' ? handlerMember : payloadMember;\n // istanbul ignore next: actions always have `handler` and events always\n // have `payload`; the messenger walk wouldn't have surfaced this\n // declaration otherwise.\n if (!rawSourceMember) {\n return null;\n }\n const rawSourceTypeNode = rawSourceMember.getTypeNode();\n // istanbul ignore next: property signatures we care about always have an\n // explicit type.\n if (!rawSourceTypeNode) {\n return null;\n }\n\n let handlerOrPayload = rawSourceTypeNode.getText().trim();\n let { description: jsDoc, params, returns } = extractJsDoc(statement);\n\n // For actions, if the handler resolves to a class method (`Class['method']`\n // — possibly in another file), inherit its signature plus any JSDoc fields\n // the type alias itself doesn't already provide.\n if (kind === 'action') {\n const resolvedMethod = resolveIndexedAccessMethod(rawSourceTypeNode);\n if (resolvedMethod) {\n const info = buildMethodInfo(resolvedMethod);\n handlerOrPayload = info.signature;\n if (!jsDoc && info.jsDoc) {\n jsDoc = info.jsDoc;\n }\n if (params.length === 0 && info.params.length > 0) {\n params = info.params;\n }\n if (!returns && info.returns) {\n returns = info.returns;\n }\n }\n }\n\n const sourceFile = statement.getSourceFile();\n return {\n typeName: statement.getName(),\n typeString,\n kind,\n jsDoc,\n params,\n returns,\n handlerOrPayload,\n sourceFile: path.relative(projectPath, sourceFile.getFilePath()),\n line: statement.getStartLineNumber(),\n deprecated: isDeprecated(statement),\n };\n}\n\n/**\n * Resolve the literal value of an inline shape's `type` property — either a\n * direct string literal or a template literal type with `typeof X`\n * substitutions (resolved via the type checker).\n *\n * @param members - The type elements of the inline shape.\n * @returns The resolved type string, or null if it can't be resolved.\n */\nfunction resolveInlineTypeString(members: TypeElementTypes[]): string | null {\n for (const member of members) {\n // istanbul ignore next: capability-type bodies only contain property\n // signatures.\n if (!NodeGuards.isPropertySignature(member)) {\n continue;\n }\n const memberNameNode = member.getNameNode();\n if (\n // istanbul ignore next: `type` is always a plain identifier.\n !NodeGuards.isIdentifier(memberNameNode) ||\n memberNameNode.getText() !== 'type'\n ) {\n continue;\n }\n const typeNode = member.getTypeNode();\n // istanbul ignore next: a `type` property without an explicit type\n // wouldn't compile.\n if (!typeNode) {\n continue;\n }\n if (NodeGuards.isLiteralTypeNode(typeNode)) {\n const literal = typeNode.getLiteral();\n // istanbul ignore next: messenger `type` fields are written as\n // quoted string literals in real fixtures; backtick template literals\n // are valid TypeScript but don't appear in practice.\n if (\n NodeGuards.isStringLiteral(literal) ||\n NodeGuards.isNoSubstitutionTemplateLiteral(literal)\n ) {\n return literal.getLiteralValue();\n }\n // istanbul ignore next: numeric/boolean literal types aren't valid as a\n // messenger `type` and don't appear in real fixtures.\n return null;\n }\n if (NodeGuards.isTemplateLiteralTypeNode(typeNode)) {\n return resolveTemplateLiteralType(typeNode);\n }\n }\n // istanbul ignore next: the inline shape always has a `type` member that\n // produces either a literal or template-literal type.\n return null;\n}\n\n/**\n * Find the `PropertySignature` named `propName` in a type literal body.\n *\n * @param members - The type literal members to search.\n * @param propName - The property name to find.\n * @returns The property signature, or null.\n */\nfunction getPropertyMember(\n members: TypeElementTypes[],\n propName: string,\n): PropertySignature | null {\n for (const member of members) {\n // istanbul ignore next: capability-type bodies only contain property\n // signatures.\n if (!NodeGuards.isPropertySignature(member)) {\n continue;\n }\n const memberNameNode = member.getNameNode();\n if (\n // istanbul ignore next: capability properties always have identifier names.\n !NodeGuards.isIdentifier(memberNameNode) ||\n memberNameNode.getText() !== propName\n ) {\n continue;\n }\n return member;\n }\n return null;\n}\n\n/**\n * Try the capability-type-constructor pattern:\n * `ControllerGetStateAction<typeof X, State>` for actions, or\n * `ControllerStateChangeEvent<typeof X, State>` for events.\n *\n * @param statement - The type alias declaration.\n * @param kind - The expected kind (action or event).\n * @param projectPath - Project root, used for computing relative source paths.\n * @returns The extracted capability, or null if the constructor doesn't match.\n */\nfunction extractFromCapabilityTypeConstructor(\n statement: TypeAliasDeclaration,\n kind: 'action' | 'event',\n projectPath: string,\n): ExtractedMessengerCapabilityType | null {\n const aliasBody = statement.getTypeNode();\n // istanbul ignore next: walker only records aliases whose body matches.\n if (!aliasBody || !NodeGuards.isTypeReference(aliasBody)) {\n return null;\n }\n const nameNode = aliasBody.getTypeName();\n // istanbul ignore next: qualified-name type references aren't used.\n if (!NodeGuards.isIdentifier(nameNode)) {\n return null;\n }\n const constructorName = nameNode.getText();\n const typeArgs = aliasBody.getTypeArguments();\n if (typeArgs.length < 2) {\n return null;\n }\n\n const expectedConstructor =\n kind === 'action'\n ? 'ControllerGetStateAction'\n : 'ControllerStateChangeEvent';\n if (constructorName !== expectedConstructor) {\n return null;\n }\n\n const namespace = resolveNamespaceFromTypeArg(typeArgs[0]);\n // istanbul ignore next: recognized constructors always have resolvable args.\n if (!namespace) {\n return null;\n }\n const stateArgText = typeArgs[1].getText();\n const { description, params, returns } = extractJsDoc(statement);\n\n const sourceFile = statement.getSourceFile();\n return {\n typeName: statement.getName(),\n typeString:\n kind === 'action' ? `${namespace}:getState` : `${namespace}:stateChange`,\n kind,\n jsDoc: description,\n params,\n returns,\n handlerOrPayload:\n kind === 'action'\n ? `() => ${stateArgText}`\n : `[${stateArgText}, Patch[]]`,\n sourceFile: path.relative(projectPath, sourceFile.getFilePath()),\n line: statement.getStartLineNumber(),\n deprecated: isDeprecated(statement),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public entry points\n// ---------------------------------------------------------------------------\n\n/**\n * Create a ts-morph Project configured for messenger-docs extraction. The\n * caller should add every source file that may be referenced (directly or\n * transitively) before calling {@link extractFromSourceFile}, so the type\n * checker can resolve cross-file references.\n *\n * @returns A new ts-morph Project.\n */\nexport function createExtractionProject(): Project {\n return new Project({\n compilerOptions: {\n allowJs: false,\n noEmit: true,\n // Match the project's permissive defaults — we just need symbol\n // resolution, not full typechecking.\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\n/**\n * Extract every messenger action/event type reachable from a single source\n * file's `*Messenger` declarations.\n *\n * The caller is responsible for ensuring `sourceFile` (plus any files it\n * imports from) belongs to a ts-morph Project so cross-file symbol resolution\n * works.\n *\n * @param sourceFile - The TypeScript source file to extract from.\n * @param projectPath - Project root, used for computing relative source paths.\n * @returns The extracted capability list.\n */\nexport function extractFromSourceFile(\n sourceFile: SourceFile,\n projectPath: string,\n): ExtractedMessengerCapabilityType[] {\n const declarations = collectMessengerCapabilityTypeDeclarations(sourceFile);\n if (declarations.length === 0) {\n return [];\n }\n\n const items: ExtractedMessengerCapabilityType[] = [];\n for (const { statement, kind } of declarations) {\n const item = extractFromMessengerCapabilityType(\n statement,\n kind,\n projectPath,\n );\n if (item) {\n items.push(item);\n }\n }\n return items;\n}\n\n/**\n * Convenience wrapper: extract from a single file by path. Loads the file\n * and any sibling files in its parent directory into a fresh Project so\n * relative imports resolve.\n *\n * For batch operations across many files, prefer\n * {@link createExtractionProject} + {@link extractFromSourceFile} so one\n * Project amortizes the type-checker setup across the whole run.\n *\n * @param filePath - The absolute path to the TypeScript file.\n * @param projectPath - Base path for computing relative source paths.\n * @returns A promise that resolves to the extracted capability list.\n */\nexport async function extractFromFile(\n filePath: string,\n projectPath: string,\n): Promise<ExtractedMessengerCapabilityType[]> {\n const project = createExtractionProject();\n const parentDir = path.dirname(filePath);\n // Load the file's directory so single-hop relative imports resolve.\n project.addSourceFilesAtPaths([\n path.join(parentDir, '**/*.ts'),\n path.join(parentDir, '**/*.d.cts'),\n ]);\n const sourceFile = project.getSourceFile(filePath);\n // istanbul ignore next: the path always exists since the caller just\n // wrote the file or it was scanned from disk.\n if (!sourceFile) {\n return [];\n }\n return extractFromSourceFile(sourceFile, projectPath);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"extraction.mjs","sourceRoot":"","sources":["../src/extraction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,kBAAkB;AAalC,OAAO,EAAE,IAAI,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,EAAE,iBAAiB;AAQ3D,8EAA8E;AAC9E,qEAAqE;AACrE,uEAAuE;AACvE,8EAA8E;AAC9E,sEAAsE;AACtE,8EAA8E;AAE9E,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E;;;;;;;GAOG;AACH,SAAS,qBAAqB,CAAC,IAAY;IACzC,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC;IACxE,OAAO,iBAAiB,CAAC,OAAO,CAC9B,qBAAqB,EACrB,CAAC,KAAK,EAAE,IAAwB,EAAE,KAAyB,EAAE,EAAE;QAC7D,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CACF,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,sBAAsB,CAAC,GAAa;IAC3C,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACnE,CAAC;AAED;;;;;;GAMG;AACH,SAAS,wBAAwB,CAAC,OAAe;IAC/C,OAAO,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAS,YAAY,CAAC,IAAmB;IAKvC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;IAChC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACtD,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACxB,MAAM,eAAe,GAAG,KAAK,CAAC,cAAc,EAAE,CAAC,IAAI,EAAE,CAAC;IAEtD,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,MAAM,MAAM,GAA0B,EAAE,CAAC;IACzC,IAAI,OAAO,GAAG,EAAE,CAAC;IAEjB,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC;QACjC,IAAI,OAAO,KAAK,YAAY,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;YAC5C,eAAe,CAAC,IAAI,CAClB,OAAO,CAAC,CAAC,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAC3D,CAAC;QACJ,CAAC;aAAM,IAAI,OAAO,KAAK,OAAO,IAAI,UAAU,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC;YACtE,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;YACnC,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;YACrC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS;YACX,CAAC;YACD,MAAM,OAAO,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;YAC5C,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,SAAS;gBACf,WAAW,EAAE,qBAAqB,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC;aACtE,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;YACzD,MAAM,OAAO,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;YAC5C,OAAO,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,qBAAqB,CACvC,CAAC,eAAe,EAAE,GAAG,eAAe,CAAC;SAClC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;SACjC,IAAI,CAAC,IAAI,CAAC,CACd,CAAC;IAEF,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC1C,CAAC;AAED;;;;;GAKG;AACH,SAAS,qBAAqB,CAAC,IAAmB;IAChD,OAAO,IAAI;SACR,SAAS,EAAE;SACX,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;SACnC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,YAAY,CAAC,CAAC;AACtD,CAAC;AAED,8EAA8E;AAC9E,+DAA+D;AAC/D,8EAA8E;AAE9E;;;;;;;GAOG;AACH,SAAS,0BAA0B,CACjC,QAA8B;IAE9B,IAAI,CAAC,QAAQ,IAAI,CAAC,UAAU,CAAC,uBAAuB,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/D,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,UAAU,GAAG,QAAQ,CAAC,iBAAiB,EAAE,CAAC;IAChD,MAAM,SAAS,GAAG,QAAQ,CAAC,gBAAgB,EAAE,CAAC;IAE9C,2EAA2E;IAC3E,8CAA8C;IAC9C,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,2EAA2E;IAC3E,qCAAqC;IACrC,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,YAAY,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC;IAC5C,yEAAyE;IACzE,wEAAwE;IACxE,mCAAmC;IACnC,2EAA2E;IAC3E,IACE,CAAC,UAAU,CAAC,eAAe,CAAC,YAAY,CAAC;QACzC,CAAC,UAAU,CAAC,+BAA+B,CAAC,YAAY,CAAC,EACzD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,UAAU,GAAG,YAAY,CAAC,eAAe,EAAE,CAAC;IAElD,MAAM,aAAa,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IAC/C,uEAAuE;IACvE,2BAA2B;IAC3B,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,aAAa,CAAC,EAAE,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,WAAW,GAAG,aAAa,CAAC,SAAS,EAAE,CAAC;IAC9C,4EAA4E;IAC5E,4BAA4B;IAC5B,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,2EAA2E;IAC3E,iBAAiB;IACjB,MAAM,MAAM,GAAG,WAAW,CAAC,gBAAgB,EAAE,IAAI,WAAW,CAAC;IAE7D,0EAA0E;IAC1E,kCAAkC;IAClC,KAAK,MAAM,WAAW,IAAI,MAAM,CAAC,eAAe,EAAE,IAAI,EAAE,EAAE,CAAC;QACzD,IAAI,UAAU,CAAC,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/C,MAAM,MAAM,GAAG,WAAW,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;YACjD,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;IACH,CAAC;IACD,0EAA0E;IAC1E,2EAA2E;IAC3E,iBAAiB;IACjB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E;;;;;;;GAOG;AACH,SAAS,eAAe,CAAC,MAAyB;IAChD,MAAM,eAAe,GAAG,MAAM;SAC3B,aAAa,EAAE;SACf,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACb,MAAM,SAAS,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,CAAC;QAChD,MAAM,QAAQ,GAAG,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAC5D,OAAO,GAAG,SAAS,GAAG,QAAQ,KAAK,SAAS,EAAE,CAAC;IACjD,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,cAAc,GAAG,MAAM,CAAC,iBAAiB,EAAE,CAAC;IAClD,MAAM,UAAU,GAAG,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACtE,4EAA4E;IAC5E,kCAAkC;IAClC,MAAM,SAAS,GAAG,IAAI,eAAe,QAAQ,UAAU,EAAE,CAAC;IAE1D,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAE9D,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAC5D,CAAC;AAwBD;;;;;;;GAOG;AACH,SAAS,wBAAwB,CAC/B,UAAsB;IAEtB,MAAM,0BAA0B,GAA+B,EAAE,CAAC;IAElE,KAAK,MAAM,SAAS,IAAI,UAAU,CAAC,cAAc,EAAE,EAAE,CAAC;QACpD,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/C,SAAS;QACX,CAAC;QAED,MAAM,IAAI,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;QACrC,cAAc;QACd,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/C,SAAS;QACX,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACzC,gDAAgD;QAChD,uDAAuD;QACvD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,SAAS;QACX,CAAC;QAED,0BAA0B,CAAC,IAAI,CAAC;YAC9B,oBAAoB,EAAE,QAAQ,CAAC,CAAC,CAAC;YACjC,mBAAmB,EAAE,QAAQ,CAAC,CAAC,CAAC;SACjC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,0BAA0B,CAAC;AACpC,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,0CAA0C,CACjD,0BAAsD;IAEtD,MAAM,6BAA6B,GACjC,EAAE,CAAC;IACL,IAAI,0BAA0B,GAAqB,IAAI,GAAG,EAAE,CAAC;IAE7D,KAAK,MAAM,EACT,oBAAoB,EACpB,mBAAmB,GACpB,IAAI,0BAA0B,EAAE,CAAC;QAChC,KAAK,MAAM,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI;YAClC,CAAC,oBAAoB,EAAE,QAAQ,CAAC;YAChC,CAAC,mBAAmB,EAAE,OAAO,CAAC;SACtB,EAAE,CAAC;YACX,MAAM,MAAM,GAAG,kDAAkD,CAC/D,aAAa,EACb,IAAI,EACJ,0BAA0B,CAC3B,CAAC;YACF,6BAA6B,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,0BAA0B,CAAC,CAAC;YACzE,0BAA0B,GAAG,MAAM,CAAC,uBAAuB,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,OAAO,6BAA6B,CAAC;AACvC,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAS,kDAAkD,CACzD,IAAiB,EACjB,IAAwB,EACxB,uBAAyC;IAKzC,MAAM,MAAM,GAGR;QACF,0BAA0B,EAAE,EAAE;QAC9B,uBAAuB,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,uBAAuB,CAAC,CAAC;KAC/D,CAAC;IAEF,uDAAuD;IACvD,YAAY;IACZ,0EAA0E;IAC1E,0EAA0E;IAC1E,uFAAuF;IACvF,uFAAuF;IACvF,IAAI,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YAC3C,MAAM,WAAW,GAAG,kDAAkD,CACpE,QAAQ,EACR,IAAI,EACJ,MAAM,CAAC,uBAAuB,CAC/B,CAAC;YACF,MAAM,CAAC,0BAA0B,CAAC,IAAI,CACpC,GAAG,WAAW,CAAC,0BAA0B,CAC1C,CAAC;YACF,KAAK,MAAM,eAAe,IAAI,WAAW,CAAC,uBAAuB,EAAE,CAAC;gBAClE,MAAM,CAAC,uBAAuB,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,oDAAoD;IACpD,WAAW;IACX,WAAW;IACX,2BAA2B;IAC3B,2BAA2B;IAC3B,YAAY;IACZ,4CAA4C;IAC5C,YAAY;IACZ,kDAAkD;IAClD,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAEpC,mEAAmE;IACnE,WAAW;IACX,wCAAwC;IACxC,wDAAwD;IACxD,uDAAuD;IACvD,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,+EAA+E;IAC/E,oEAAoE;IACpE,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,EAAG,CAAC;IAC1C,2EAA2E;IAC3E,0EAA0E;IAC1E,qCAAqC;IACrC,WAAW;IACX,wEAAwE;IACxE,4CAA4C;IAC5C,2CAA2C;IAC3C,MAAM,MAAM,GAAG,WAAW,CAAC,gBAAgB,EAAE,IAAI,WAAW,CAAC;IAE7D,0EAA0E;IAC1E,iBAAiB;IACjB,sEAAsE;IACtE,2DAA2D;IAC3D,KAAK,MAAM,WAAW,IAAI,MAAM,CAAC,eAAe,EAAE,EAAE,CAAC;QACnD,qBAAqB;QACrB,IAAI,MAAM,CAAC,uBAAuB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YACpD,SAAS;QACX,CAAC;QACD,MAAM,CAAC,uBAAuB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAEhD,mEAAmE;QACnE,YAAY;QACZ,0CAA0C;QAC1C,uCAAuC;QACvC,IAAI,UAAU,CAAC,sBAAsB,CAAC,WAAW,CAAC,EAAE,CAAC;YACnD,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC;YAEvC,6DAA6D;YAC7D,WAAW;YACX,6FAA6F;YAC7F,6FAA6F;YAC7F,IAAI,IAAI,IAAI,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7C,MAAM,WAAW,GAAG,kDAAkD,CACpE,IAAI,EACJ,IAAI,EACJ,MAAM,CAAC,uBAAuB,CAC/B,CAAC;gBACF,MAAM,CAAC,0BAA0B,CAAC,IAAI,CACpC,GAAG,WAAW,CAAC,0BAA0B,CAC1C,CAAC;gBACF,KAAK,MAAM,eAAe,IAAI,WAAW,CAAC,uBAAuB,EAAE,CAAC;oBAClE,MAAM,CAAC,uBAAuB,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;gBACtD,CAAC;gBACD,SAAS;YACX,CAAC;YAED,2BAA2B;YAC3B,yDAAyD;YACzD,qEAAqE;YACrE,oEAAoE;YACpE,kEAAkE;YAClE,gDAAgD;YAChD,oEAAoE;YACpE,IACE,IAAI;gBACJ,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC;gBAChC,IAAI,CAAC,gBAAgB,EAAE,CAAC,MAAM,KAAK,CAAC,EACpC,CAAC;gBACD,SAAS;YACX,CAAC;YAED,yEAAyE;YACzE,kCAAkC;YAClC,WAAW;YACX,2CAA2C;YAC3C,2CAA2C;YAC3C,MAAM,CAAC,0BAA0B,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,CAAC;QAED,qEAAqE;QACrE,oBAAoB;QACpB,WAAW;QACX,8CAA8C;QAC9C,8CAA8C;aACzC,IAAI,UAAU,CAAC,sBAAsB,CAAC,WAAW,CAAC,EAAE,CAAC;YACxD,MAAM,CAAC,0BAA0B,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,8EAA8E;AAC9E,2BAA2B;AAC3B,8EAA8E;AAE9E;;;;;;;;;;GAUG;AACH,SAAS,6CAA6C,CACpD,yBAA6D,EAC7D,WAAmB;IAEnB,OAAO,CACL,8CAA8C,CAC5C,yBAAyB,EACzB,WAAW,CACZ;QACD,yCAAyC,CACvC,yBAAyB,EACzB,WAAW,CACZ,CACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,SAAS,8CAA8C,CACrD,yBAA6D,EAC7D,WAAmB;IAEnB,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,yBAAyB,CAAC;IAExD,2CAA2C;IAC3C,YAAY;IACZ,YAAY;IACZ,qCAAqC;IACrC,sCAAsC;IACtC,0CAA0C;IAC1C,MAAM;IACN,YAAY;IACZ,wCAAwC;IACxC,sCAAsC;IACtC,0CAA0C;IAC1C,MAAM;IACN,WAAW;IACX,uCAAuC;IACvC,WAAW;IACX,0CAA0C;IAC1C,IAAI,OAAuC,CAAC;IAC5C,IAAI,UAAU,CAAC,sBAAsB,CAAC,WAAW,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC;QACvC,IAAI,IAAI,IAAI,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC9B,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,WAAW,CAAC,UAAU,EAAE,CAAC;IACrC,CAAC;IACD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,kBAAkB,GAAG,OAAO,CAAC,MAAM,CACvC,UAAU,CAAC,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CAChD,CAAC;IAEF,kEAAkE;IAClE,MAAM,UAAU,GAAG,gCAAgC,CAAC,kBAAkB,CAAC,CAAC;IACxE,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,mEAAmE;IACnE,MAAM,wBAAwB,GAAG,YAAY,CAC3C,kBAAkB,EAClB,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAC1C,CAAC;IACF,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gCAAgC;IACpC,wEAAwE;IACxE,oEAAoE;IACpE,wBAAwB,CAAC,WAAW,EAAG,CAAC;IAC1C,IAAI,yBAAyB,GAAG,gCAAgC;SAC7D,OAAO,EAAE;SACT,IAAI,EAAE,CAAC;IAEV,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IAExE,+DAA+D;IAC/D,8EAA8E;IAC9E,6CAA6C;IAC7C,kCAAkC;IAClC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,MAAM,cAAc,GAAG,0BAA0B,CAC/C,gCAAgC,CACjC,CAAC;QACF,IAAI,cAAc,EAAE,CAAC;YACnB,MAAM,IAAI,GAAG,eAAe,CAAC,cAAc,CAAC,CAAC;YAC7C,yBAAyB,GAAG,IAAI,CAAC,SAAS,CAAC;YAC3C,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACzB,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;YACrB,CAAC;YACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClD,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;YACvB,CAAC;YACD,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC7B,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,WAAW,CAAC,aAAa,EAAE,CAAC;IAC/C,OAAO;QACL,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE;QAC/B,UAAU;QACV,IAAI;QACJ,KAAK;QACL,MAAM;QACN,OAAO;QACP,gBAAgB,EAAE,yBAAyB;QAC3C,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAC,WAAW,EAAE,CAAC;QAChE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE;QACtC,UAAU,EAAE,qBAAqB,CAAC,WAAW,CAAC;KAC/C,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,gCAAgC,CACvC,wBAA6C;IAE7C,MAAM,YAAY,GAAG,YAAY,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;IACpE,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,+DAA+D;IAC/D,oEAAoE;IACpE,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,EAAG,CAAC;IAE7C,yEAAyE;IACzE,4DAA4D;IAC5D,EAAE;IACF,YAAY;IACZ,qCAAqC;IACrC,wCAAwC;IACxC,uCAAuC;IACvC,MAAM;IACN,qCAAqC;IACrC,wCAAwC;IACxC,uCAAuC;IACvC,MAAM;IACN,qCAAqC;IACrC,oDAAoD;IACpD,oDAAoD;IACpD,MAAM;IACN,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;IACxC,IAAI,YAAY,CAAC,eAAe,EAAE,EAAE,CAAC;QACnC,yEAAyE;QACzE,gBAAgB;QAChB,MAAM,YAAY,GAAG,YAAY,CAAC,sBAAsB,EAAY,CAAC;QAErE,sDAAsD;QACtD,IAAI,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/B,OAAO,YAAY,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,YAAY,CACnB,kBAAuC,EACvC,IAAY;IAEZ,KAAK,MAAM,QAAQ,IAAI,kBAAkB,EAAE,CAAC;QAC1C,MAAM,gBAAgB,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;QAChD,IACE,CAAC,UAAU,CAAC,YAAY,CAAC,gBAAgB,CAAC;YAC1C,gBAAgB,CAAC,OAAO,EAAE,KAAK,IAAI,EACnC,CAAC;YACD,SAAS;QACX,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,yCAAyC,CAChD,yBAA6D,EAC7D,WAAmB;IAEnB,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,yBAAyB,CAAC;IAExD,4EAA4E;IAC5E,WAAW;IACX,uCAAuC;IACvC,IAAI,CAAC,UAAU,CAAC,sBAAsB,CAAC,WAAW,CAAC,EAAE,CAAC;QACpD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,8DAA8D;IAC9D,sEAAsE;IACtE,iCAAiC;IACjC,oEAAoE;IACpE,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,EAAG,CAAC;IACxC,2BAA2B;IAC3B,4EAA4E;IAC5E,uBAAuB;IACvB,4EAA4E;IAC5E,oBAAoB;IACpB,uBAAuB;IACvB,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACpC,2BAA2B;IAC3B,2EAA2E;IAC3E,cAAc;IACd,4EAA4E;IAC5E,oBAAoB;IACpB,uBAAuB;IACvB,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,2EAA2E;IAC3E,8DAA8D;IAC9D,YAAY;IACZ,iEAAiE;IACjE,kEAAkE;IAClE,MAAM,mBAAmB,GACvB,IAAI,KAAK,QAAQ;QACf,CAAC,CAAC,0BAA0B;QAC5B,CAAC,CAAC,4BAA4B,CAAC;IACnC,IAAI,QAAQ,CAAC,OAAO,EAAE,KAAK,mBAAmB,EAAE,CAAC;QAC/C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,+CAA+C;IAC/C,YAAY;IACZ,sEAAsE;IACtE,uEAAuE;IACvE,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;IACzC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IAC/C,kDAAkD;IAClD,YAAY;IACZ,kFAAkF;IAClF,yFAAyF;IACzF,IAAI,CAAC,gBAAgB,CAAC,eAAe,EAAE,EAAE,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,8EAA8E;IAC9E,WAAW;IACX,MAAM,SAAS,GAAG,gBAAgB,CAAC,sBAAsB,EAAY,CAAC;IAEtE,MAAM,UAAU,GACd,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,cAAc,CAAC;IAC3E,MAAM,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IAC3C,MAAM,gBAAgB,GACpB,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,YAAY,YAAY,CAAC;IAC7E,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IACnE,MAAM,UAAU,GAAG,WAAW,CAAC,aAAa,EAAE,CAAC;IAE/C,OAAO;QACL,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE;QAC/B,UAAU;QACV,IAAI;QACJ,KAAK,EAAE,WAAW;QAClB,MAAM;QACN,OAAO;QACP,gBAAgB;QAChB,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAC,WAAW,EAAE,CAAC;QAChE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE;QACtC,UAAU,EAAE,qBAAqB,CAAC,WAAW,CAAC;KAC/C,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO,IAAI,OAAO,CAAC;QACjB,eAAe,EAAE;YACf,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,IAAI;YACZ,gEAAgE;YAChE,qCAAqC;YACrC,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;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,qBAAqB,CACnC,UAAsB,EACtB,WAAmB;IAEnB,MAAM,oBAAoB,GAAG,wBAAwB,CAAC,UAAU,CAAC,CAAC;IAElE,MAAM,0BAA0B,GAC9B,0CAA0C,CAAC,oBAAoB,CAAC,CAAC;IAEnE,MAAM,0BAA0B,GAAgC,EAAE,CAAC;IACnE,KAAK,MAAM,yBAAyB,IAAI,0BAA0B,EAAE,CAAC;QACnE,MAAM,yBAAyB,GAC7B,6CAA6C,CAC3C,yBAAyB,EACzB,WAAW,CACZ,CAAC;QACJ,IAAI,yBAAyB,EAAE,CAAC;YAC9B,0BAA0B,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IACD,OAAO,0BAA0B,CAAC;AACpC,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,WAAmB;IAEnB,MAAM,OAAO,GAAG,uBAAuB,EAAE,CAAC;IAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzC,oEAAoE;IACpE,OAAO,CAAC,qBAAqB,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC;KACnC,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IACnD,qEAAqE;IACrE,8CAA8C;IAC9C,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,qBAAqB,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AACxD,CAAC","sourcesContent":["import * as path from 'node:path';\nimport type {\n InterfaceDeclaration,\n JSDocableNode,\n JSDocTag,\n MethodDeclaration,\n Node as TsMorphNode,\n PropertySignature,\n SourceFile,\n TypeAliasDeclaration,\n TypeElementTypes,\n TypeNode,\n} from 'ts-morph';\nimport { Node as NodeGuards, Project, ts } from 'ts-morph';\n\nimport type {\n MessengerCapabilityPacket,\n MethodInfo,\n DocumentedParameter,\n} from './types';\n\n// ---------------------------------------------------------------------------\n// NOTE: `ts-morph` is used heavily in this file to parse and extract\n// information from TypeScript files. Although this library is not well\n// documented, it wraps the TypeScript AST fairly well, and you can get a good\n// sense of the AST by using this website: <https://ts-ast-viewer.com>\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// JSDoc utilities\n// ---------------------------------------------------------------------------\n\n/**\n * Convert `{@link X}` references inside a JSDoc comment string to plain\n * backtick code spans and escape any remaining (out-of-backtick) curly braces.\n * This way the output is safe to render in a MDX document.\n *\n * @param text - The raw text to normalize.\n * @returns The text with `@link` resolved and stray braces escaped.\n */\nfunction escapeJsDocTextForMdx(text: string): string {\n const withLinksResolved = text.replace(/\\{@link\\s+([^}]+)\\}/gu, '`$1`');\n return withLinksResolved.replace(\n /`[^`]*`|(\\{)|(\\})/gu,\n (match, open: string | undefined, close: string | undefined) => {\n if (open) {\n return '\\\\{';\n }\n if (close) {\n return '\\\\}';\n }\n return match;\n },\n );\n}\n\n/**\n * Extract the comment text of a JSDoc tag — the part that comes after the tag\n * and any identifier, e.g. \"Some param\" in \"@param foo Some param\" —\n * normalizing whitespace to a single space so we can better control how it's\n * rendered within the site.\n *\n * @param tag - The JSDoc tag.\n * @returns The flattened comment text.\n */\nfunction extractJsDocTagComment(tag: JSDocTag): string {\n return (tag.getCommentText() ?? '').replace(/\\s+/gu, ' ').trim();\n}\n\n/**\n * Strip the conventional `- ` separator from the start of a `@param` tag's\n * comment.\n *\n * @param comment - The flattened comment text from a `@param` tag.\n * @returns The comment with any leading `- ` (or `– `, `— `) removed.\n */\nfunction stripJsDocParamSeparator(comment: string): string {\n return comment.replace(/^[-–—]\\s*/u, '');\n}\n\n/**\n * Extract JSDoc from a TypeScript AST node and decompose it into the parts we\n * need to render docs:\n *\n * - `description` — the body above the first tag, with `@deprecated` comments\n * appended as `**Deprecated:** <comment>` lines and normalized for MDX\n * (curly braces escaped, `{@link}` resolved),\n * - `params` — every `@param` tag in source order, with name and description,\n * - `returns` — the `@returns` tag's comment, or empty string if absent.\n *\n * Other tags (`@see`, `@throws`, `@template`, `@example`) are dropped.\n *\n * @param node - The AST node to extract JSDoc from (e.g. a type or a method).\n * @returns The decomposed JSDoc; empty strings/arrays when the node has no JSDoc.\n */\nfunction extractJsDoc(node: JSDocableNode): {\n description: string;\n params: DocumentedParameter[];\n returns: string;\n} {\n const jsDocs = node.getJsDocs();\n if (jsDocs.length === 0) {\n return { description: '', params: [], returns: '' };\n }\n\n const jsDoc = jsDocs[0];\n const descriptionBody = jsDoc.getDescription().trim();\n\n const deprecatedLines: string[] = [];\n const params: DocumentedParameter[] = [];\n let returns = '';\n\n for (const tag of jsDoc.getTags()) {\n const tagName = tag.getTagName();\n if (tagName === 'deprecated') {\n const comment = extractJsDocTagComment(tag);\n deprecatedLines.push(\n comment ? `**Deprecated:** ${comment}` : '**Deprecated:**',\n );\n } else if (tagName === 'param' && NodeGuards.isJSDocParameterTag(tag)) {\n const nameNode = tag.getNameNode();\n const paramName = nameNode.getText();\n if (!paramName) {\n continue;\n }\n const comment = extractJsDocTagComment(tag);\n params.push({\n name: paramName,\n description: escapeJsDocTextForMdx(stripJsDocParamSeparator(comment)),\n });\n } else if (tagName === 'returns' || tagName === 'return') {\n const comment = extractJsDocTagComment(tag);\n returns = escapeJsDocTextForMdx(comment);\n }\n }\n\n const description = escapeJsDocTextForMdx(\n [descriptionBody, ...deprecatedLines]\n .filter((line) => line.length > 0)\n .join('\\n'),\n );\n\n return { description, params, returns };\n}\n\n/**\n * Check whether a node has an `@deprecated` JSDoc tag.\n *\n * @param node - The AST node to check.\n * @returns True if the node has an `@deprecated` tag.\n */\nfunction hasDeprecatedJsDocTag(node: JSDocableNode): boolean {\n return node\n .getJsDocs()\n .flatMap((jsDoc) => jsDoc.getTags())\n .some((tag) => tag.getTagName() === 'deprecated');\n}\n\n// ---------------------------------------------------------------------------\n// Type-resolution helpers (powered by ts-morph's type checker)\n// ---------------------------------------------------------------------------\n\n/**\n * If `typeNode` is `Class['method']`, resolve `Class` to its declaration\n * (across files if needed via the type checker) and look up the method by\n * name. Returns the method declaration when found.\n *\n * @param typeNode - The handler's type node.\n * @returns The method declaration, or null.\n */\nfunction resolveIndexedAccessMethod(\n typeNode: TypeNode | undefined,\n): MethodDeclaration | null {\n if (!typeNode || !NodeGuards.isIndexedAccessTypeNode(typeNode)) {\n return null;\n }\n const objectType = typeNode.getObjectTypeNode();\n const indexType = typeNode.getIndexTypeNode();\n\n // istanbul ignore next: handler indexed-access types in messenger fixtures\n // always reference a class via TypeReference.\n if (!NodeGuards.isTypeReference(objectType)) {\n return null;\n }\n // istanbul ignore next: the index in `Class['method']` is always a literal\n // type node in valid handler syntax.\n if (!NodeGuards.isLiteralTypeNode(indexType)) {\n return null;\n }\n const indexLiteral = indexType.getLiteral();\n // The index can be written as `'method'`, `\"method\"`, or `` `method` ``.\n // The first two land as `StringLiteral`; the bare template literal is a\n // `NoSubstitutionTemplateLiteral`.\n // istanbul ignore next: numeric/boolean indices aren't valid method names.\n if (\n !NodeGuards.isStringLiteral(indexLiteral) &&\n !NodeGuards.isNoSubstitutionTemplateLiteral(indexLiteral)\n ) {\n return null;\n }\n const methodName = indexLiteral.getLiteralValue();\n\n const classNameNode = objectType.getTypeName();\n // istanbul ignore next: qualified-name class references aren't used in\n // messenger handler types.\n if (!NodeGuards.isIdentifier(classNameNode)) {\n return null;\n }\n const localSymbol = classNameNode.getSymbol();\n // istanbul ignore next: a referenced class name always resolves to a symbol\n // in a typechecked project.\n if (!localSymbol) {\n return null;\n }\n // Follow the import alias (if any) so we can find the class declaration in\n // its home file.\n const symbol = localSymbol.getAliasedSymbol() ?? localSymbol;\n\n // istanbul ignore next: a resolved symbol always exposes its declarations\n // array in a typechecked project.\n for (const declaration of symbol.getDeclarations() ?? []) {\n if (NodeGuards.isClassDeclaration(declaration)) {\n const method = declaration.getMethod(methodName);\n if (method) {\n return method;\n }\n }\n }\n // istanbul ignore next: only reached if the indexed method isn't declared\n // on any of the resolved class declarations, which doesn't happen in valid\n // handler types.\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Method info\n// ---------------------------------------------------------------------------\n\n/**\n * Build a {@link MethodInfo} record for a class method — its textual\n * signature plus the JSDoc description, `@param`, and `@returns` extracted\n * from the method itself.\n *\n * @param method - The method declaration.\n * @returns The method info.\n */\nfunction buildMethodInfo(method: MethodDeclaration): MethodInfo {\n const signatureParams = method\n .getParameters()\n .map((param) => {\n const paramName = param.getNameNode().getText();\n const optional = param.hasQuestionToken() ? '?' : '';\n const typeNode = param.getTypeNode();\n const paramType = typeNode ? typeNode.getText() : 'unknown';\n return `${paramName}${optional}: ${paramType}`;\n })\n .join(', ');\n\n const returnTypeNode = method.getReturnTypeNode();\n const returnType = returnTypeNode ? returnTypeNode.getText() : 'void';\n // For async methods, the declared return type already includes `Promise<>`,\n // so we don't need to wrap again.\n const signature = `(${signatureParams}) => ${returnType}`;\n\n const { description, params, returns } = extractJsDoc(method);\n\n return { jsDoc: description, params, returns, signature };\n}\n\n// ---------------------------------------------------------------------------\n// Messenger discovery\n// ---------------------------------------------------------------------------\n\n/**\n * Represents a type declaration (type alias or interface) for an individual\n * messenger action or event.\n */\ntype MessengerCapabilityTypeDeclaration = {\n declaration: TypeAliasDeclaration | InterfaceDeclaration;\n kind: 'action' | 'event';\n};\n\n/**\n * Represents a type alias for a messenger. Only includes nodes representing the\n * `Actions` and `Events` type parameters.\n */\ntype ParsedMessengerTypeAlias = {\n actionsTypeParameter: TypeNode;\n eventsTypeParameter: TypeNode;\n};\n\n/**\n * Looks for Messenger types in the source file (that is, those that are type\n * aliases whose names end with \"Messenger\"), then extracts the `Actions` and\n * `Events` parameters from these types.\n *\n * @param sourceFile - The TypeScript source file to scan.\n * @returns A list of objects that represent messenger types.\n */\nfunction findMessengerTypeAliases(\n sourceFile: SourceFile,\n): ParsedMessengerTypeAlias[] {\n const parsedMessengerTypeAliases: ParsedMessengerTypeAlias[] = [];\n\n for (const typeAlias of sourceFile.getTypeAliases()) {\n if (!typeAlias.getName().endsWith('Messenger')) {\n continue;\n }\n\n const body = typeAlias.getTypeNode();\n // Basic check\n if (!body || !NodeGuards.isTypeReference(body)) {\n continue;\n }\n\n const typeArgs = body.getTypeArguments();\n // Messenger types always have 3 type parameters\n // (e.g. `Messenger<'FooController', Actions, Events>`)\n if (typeArgs.length < 3) {\n continue;\n }\n\n parsedMessengerTypeAliases.push({\n actionsTypeParameter: typeArgs[1],\n eventsTypeParameter: typeArgs[2],\n });\n }\n\n return parsedMessengerTypeAliases;\n}\n\n/**\n * Walks the `Actions` and `Events` type parameters of the given messenger\n * types, extracted in a previous step, to find all type declarations (i.e.,\n * statements) that represent individual messenger actions or events.\n *\n * @param parsedMessengerTypeAliases - The list of objects representing\n * messenger types, parsed in a previous step.\n * @returns The list of type aliases that represent messenger capabilities among\n * the given messenger types.\n */\nfunction findAllMessengerCapabilityTypeDeclarations(\n parsedMessengerTypeAliases: ParsedMessengerTypeAlias[],\n): MessengerCapabilityTypeDeclaration[] {\n const allCapabilityTypeDeclarations: MessengerCapabilityTypeDeclaration[] =\n [];\n let allVisitedTypeDeclarations: Set<TsMorphNode> = new Set();\n\n for (const {\n actionsTypeParameter,\n eventsTypeParameter,\n } of parsedMessengerTypeAliases) {\n for (const [typeParameter, kind] of [\n [actionsTypeParameter, 'action'],\n [eventsTypeParameter, 'event'],\n ] as const) {\n const result = recursivelyFindMessengerCapabilityTypeDeclarations(\n typeParameter,\n kind,\n allVisitedTypeDeclarations,\n );\n allCapabilityTypeDeclarations.push(...result.capabilityTypeDeclarations);\n allVisitedTypeDeclarations = result.visitedTypeDeclarations;\n }\n }\n\n return allCapabilityTypeDeclarations;\n}\n\n/**\n * Recursively walks a `ts-morph` AST node — at first the `Actions` or `Events`\n * type parameter of a messenger type, and then a node within that parameter —\n * to find all type aliases that represent individual messenger actions or\n * events, no matter how deeply the type aliases exist in the tree or in which\n * file they are located.\n *\n * @param node - The `ts-morph` AST node to walk.\n * @param kind - Whether to tag found type aliases as 'action' or 'event'.\n * @param visitedTypeDeclarations - A variable that tracks visited type aliases\n * and prevents duplicates.\n * @returns The list of extracted messenger capability type aliases as well as\n * an updated version of `visitedTypeDeclarations`.\n */\nfunction recursivelyFindMessengerCapabilityTypeDeclarations(\n node: TsMorphNode,\n kind: 'action' | 'event',\n visitedTypeDeclarations: Set<TsMorphNode>,\n): {\n capabilityTypeDeclarations: MessengerCapabilityTypeDeclaration[];\n visitedTypeDeclarations: Set<TsMorphNode>;\n} {\n const result: {\n capabilityTypeDeclarations: MessengerCapabilityTypeDeclaration[];\n visitedTypeDeclarations: Set<TsMorphNode>;\n } = {\n capabilityTypeDeclarations: [],\n visitedTypeDeclarations: new Set([...visitedTypeDeclarations]),\n };\n\n // If `node` is a union type, walk each type within it.\n // EXAMPLES:\n // type Actions = FooControllerSomeAction | FooControllerSomeOtherAction\n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n // type FooControllerActions = FooControllerSomeAction | FooControllerSomeOtherAction\n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n if (NodeGuards.isUnionTypeNode(node)) {\n for (const typeNode of node.getTypeNodes()) {\n const innerResult = recursivelyFindMessengerCapabilityTypeDeclarations(\n typeNode,\n kind,\n result.visitedTypeDeclarations,\n );\n result.capabilityTypeDeclarations.push(\n ...innerResult.capabilityTypeDeclarations,\n );\n for (const typeDeclaration of innerResult.visitedTypeDeclarations) {\n result.visitedTypeDeclarations.add(typeDeclaration);\n }\n }\n return result;\n }\n\n // If `node` is not a type reference, don't walk it.\n // EXAMPLE:\n // // Bad\n // type Actions = { ... }\n // ^^^^^^^\n // // Good\n // type Actions = FooControllerSomeAction;\n // // Good\n // type Actions = ControllerGetStateAction<...>;\n if (!NodeGuards.isTypeReference(node)) {\n return result;\n }\n\n const nameNode = node.getTypeName();\n\n // Reject qualified-name type references, as we can't follow those.\n // EXAMPLE:\n // import * as somePackage from '...';\n // type Actions = somePackage.FooControllerSomeAction;\n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n if (!NodeGuards.isIdentifier(nameNode)) {\n return result;\n }\n\n // Since we know we have a type reference, we can assume that we have a symbol.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const localSymbol = nameNode.getSymbol()!;\n // If we have a type imported from another file, ensure that when we access\n // the declaration, it's the *type* declaration in the other file, not the\n // *import* declaration in this file.\n // EXAMPLE:\n // import { FooControllerSomeAction } from '@metamask/foo-controller';\n // type Actions = FooControllerSomeAction;\n // ^^^^^^^^^^^^^^^^^^^^^^^\n const symbol = localSymbol.getAliasedSymbol() ?? localSymbol;\n\n // At this point, we have a type *reference*, but we need to find the type\n // *declaration*.\n // For instance, if we have `FooControllerSomeAction`, we need to find\n // the full `type FooControllerSomeAction = ...` statement.\n for (const declaration of symbol.getDeclarations()) {\n // Prevent duplicates\n if (result.visitedTypeDeclarations.has(declaration)) {\n continue;\n }\n result.visitedTypeDeclarations.add(declaration);\n\n // If we have a type alias, then we have to handle a few scenarios.\n // EXAMPLES:\n // type FooControllerMethodActions = ...\n // type FooControllerSomeAction = ...\n if (NodeGuards.isTypeAliasDeclaration(declaration)) {\n const body = declaration.getTypeNode();\n\n // If we have a union type, then walk each type in the union.\n // EXAMPLE:\n // type FooControllerMethodActions = FooControllerSomeAction | FooControllerSomeOtherAction\n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n if (body && NodeGuards.isUnionTypeNode(body)) {\n const innerResult = recursivelyFindMessengerCapabilityTypeDeclarations(\n body,\n kind,\n result.visitedTypeDeclarations,\n );\n result.capabilityTypeDeclarations.push(\n ...innerResult.capabilityTypeDeclarations,\n );\n for (const typeDeclaration of innerResult.visitedTypeDeclarations) {\n result.visitedTypeDeclarations.add(typeDeclaration);\n }\n continue;\n }\n\n // TODO: Is this necessary?\n // A bare TypeReference body with no type arguments (e.g.\n // `type AllowedActions = ConnectivityControllerGetStateAction`) is a\n // plain re-export — leave the target to be documented from its home\n // package, not this one. TypeReferences *with* type arguments are\n // capability-type-constructor invocations (e.g.\n // `ControllerGetStateAction<typeof name, State>`) and are recorded.\n if (\n body &&\n NodeGuards.isTypeReference(body) &&\n body.getTypeArguments().length === 0\n ) {\n continue;\n }\n\n // We finally found a messenger capability type! Capture the whole thing.\n // (We will parse the body later.)\n // EXAMPLE:\n // type FooControllerSomeAction = { ... }\n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n result.capabilityTypeDeclarations.push({ declaration, kind });\n }\n\n // If we have an interface, we don't have any scenarios to handle, so\n // capture it as is.\n // EXAMPLE:\n // interface FooControllerSomeAction { ... }\n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n else if (NodeGuards.isInterfaceDeclaration(declaration)) {\n result.capabilityTypeDeclarations.push({ declaration, kind });\n }\n }\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Per-statement extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Given the declaration of a messenger capability type, extract information\n * about it (action/event type string, handler/payload arguments and return\n * type, etc.)\n *\n * @param capabilityTypeDeclaration - The statement that declared the type for a\n * messenger action or event, extracted in a previous step.\n * @param projectPath - Project root, used for computing relative source paths.\n * @returns Information that may be extracted from the messenger capability type\n * (may be `null` if the type is ineligible for extraction).\n */\nfunction extractFromMessengerCapabilityTypeDeclaration(\n capabilityTypeDeclaration: MessengerCapabilityTypeDeclaration,\n projectPath: string,\n): MessengerCapabilityPacket | null {\n return (\n tryToExtractFromMessengerCapabilityTypeLiteral(\n capabilityTypeDeclaration,\n projectPath,\n ) ??\n tryToExtractFromCapabilityTypeConstructor(\n capabilityTypeDeclaration,\n projectPath,\n )\n );\n}\n\n/**\n * If a messenger capability type is a type alias or interface and its body is\n * a literal object type — i.e. one of:\n *\n * - `{ type: '...'; handler: ... }` (action)\n * - `{ type: '...'; payload: ... }` (event)\n *\n * then this function extracts information about the type (action/event type\n * string, handler/payload arguments and return type, etc.)\n *\n * @param capabilityTypeDeclaration - The statement that declared the type for a\n * messenger action or event, extracted in a previous step.\n * @param projectPath - Project root, used for computing relative source paths.\n * @returns The extracted capability packet, or null if the shape of the type\n * doesn't match.\n */\nfunction tryToExtractFromMessengerCapabilityTypeLiteral(\n capabilityTypeDeclaration: MessengerCapabilityTypeDeclaration,\n projectPath: string,\n): MessengerCapabilityPacket | null {\n const { declaration, kind } = capabilityTypeDeclaration;\n\n // Reject empty type aliases or interfaces.\n // EXAMPLES:\n // // Good\n // type FooControllerSomeAction = {\n // type: 'FooController:getState';\n // handler: FooController['getState'];\n // }\n // // Good\n // interface FooControllerSomeAction {\n // type: 'FooController:getState';\n // handler: FooController['getState'];\n // }\n // // Bad\n // type FooControllerSomeAction = {};\n // // Bad\n // interface FooControllerSomeAction {};\n let members: TypeElementTypes[] | undefined;\n if (NodeGuards.isTypeAliasDeclaration(declaration)) {\n const body = declaration.getTypeNode();\n if (body && NodeGuards.isTypeLiteral(body)) {\n members = body.getMembers();\n }\n } else {\n members = declaration.getMembers();\n }\n if (!members) {\n return null;\n }\n\n const propertySignatures = members.filter(\n NodeGuards.isPropertySignature.bind(NodeGuards),\n );\n\n // Actions and events must have a `type`, and it must be a string.\n const typeString = getMessengerCapabilityTypeString(propertySignatures);\n if (!typeString) {\n return null;\n }\n\n // Actions must have a `handler`, and events must have a `payload`.\n const handlerOrPayloadProperty = findProperty(\n propertySignatures,\n kind === 'action' ? 'handler' : 'payload',\n );\n if (!handlerOrPayloadProperty) {\n return null;\n }\n\n const handlerOrPayloadPropertyTypeNode =\n // We can assume the property has a type; otherwise it wouldn't compile.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n handlerOrPayloadProperty.getTypeNode()!;\n let handlerOrPayloadSignature = handlerOrPayloadPropertyTypeNode\n .getText()\n .trim();\n\n let { description: jsDoc, params, returns } = extractJsDoc(declaration);\n\n // For actions, if the handler resolves to a class method (e.g.\n // `FooController['method']`), inherit its signature plus any JSDoc fields the\n // type alias itself doesn't already provide.\n // TODO: We don't want to do this.\n if (kind === 'action') {\n const resolvedMethod = resolveIndexedAccessMethod(\n handlerOrPayloadPropertyTypeNode,\n );\n if (resolvedMethod) {\n const info = buildMethodInfo(resolvedMethod);\n handlerOrPayloadSignature = info.signature;\n if (!jsDoc && info.jsDoc) {\n jsDoc = info.jsDoc;\n }\n if (params.length === 0 && info.params.length > 0) {\n params = info.params;\n }\n if (!returns && info.returns) {\n returns = info.returns;\n }\n }\n }\n\n const sourceFile = declaration.getSourceFile();\n return {\n typeName: declaration.getName(),\n typeString,\n kind,\n jsDoc,\n params,\n returns,\n handlerOrPayload: handlerOrPayloadSignature,\n sourceFile: path.relative(projectPath, sourceFile.getFilePath()),\n line: declaration.getStartLineNumber(),\n deprecated: hasDeprecatedJsDocTag(declaration),\n };\n}\n\n/**\n * Searches the property signatures of a messenger capability type alias or\n * interface to find the value of the `type` property, and then resolves it to a\n * string (assuming it is already a string or a resolvable template literal).\n *\n * @param capabilityTypeProperties - The property signatures of the messenger\n * capability type.\n * @returns The extracted capability type string, or null if `type` cannot be\n * found in the members or it is an unexpected node.\n */\nfunction getMessengerCapabilityTypeString(\n capabilityTypeProperties: PropertySignature[],\n): string | null {\n const typeProperty = findProperty(capabilityTypeProperties, 'type');\n if (!typeProperty) {\n return null;\n }\n\n // A `type` property without an explicit type wouldn't compile.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const typeNode = typeProperty.getTypeNode()!;\n\n // Ask the type checker to resolve the value of `type`. We're looking for\n // `type` to be either a string literal or template literal.\n //\n // EXAMPLES:\n // type FooControllerSomeAction = {\n // type: 'FooController:someAction';\n // ^^^^^^^^^^^^^^^^^^^^^^^^^^\n // }\n // type FooControllerSomeAction = {\n // type: `FooController:someAction`;\n // ^^^^^^^^^^^^^^^^^^^^^^^^^^\n // }\n // type FooControllerSomeAction = {\n // type: `${typeof CONTROLLER_NAME}:someAction`;\n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n // }\n const resolvedType = typeNode.getType();\n if (resolvedType.isStringLiteral()) {\n // Type assertion: There aren't any type guards we can use to narrow this\n // type further.\n const literalValue = resolvedType.getLiteralValueOrThrow() as string;\n\n // Messenger action/event types need to be namespaced.\n if (literalValue.includes(':')) {\n return literalValue;\n }\n }\n\n return null;\n}\n\n/**\n * Finds a specific property in a list of property signatures for an object\n * type.\n *\n * @param propertySignatures - The property signatures of the messenger\n * capability type.\n * @param name - The property name to find.\n * @returns The property signature, or null.\n */\nfunction findProperty(\n propertySignatures: PropertySignature[],\n name: string,\n): PropertySignature | null {\n for (const property of propertySignatures) {\n const propertyNameNode = property.getNameNode();\n if (\n !NodeGuards.isIdentifier(propertyNameNode) ||\n propertyNameNode.getText() !== name\n ) {\n continue;\n }\n\n return property;\n }\n\n return null;\n}\n\n/**\n * If a messenger capability type is a type alias for either the\n * `ControllerGetStateAction` or `ControllerStateChangeEvent` type constructors,\n * then this function extracts information about the type (action/event type\n * string, handler/payload arguments and return type, etc.)\n *\n * @param capabilityTypeDeclaration - The statement that declared the type for a\n * messenger action or event, extracted in a previous step.\n * @param projectPath - Project root, used for computing relative source paths.\n * @returns The extracted capability packet, or null if the shape of the type\n * doesn't match.\n */\nfunction tryToExtractFromCapabilityTypeConstructor(\n capabilityTypeDeclaration: MessengerCapabilityTypeDeclaration,\n projectPath: string,\n): MessengerCapabilityPacket | null {\n const { declaration, kind } = capabilityTypeDeclaration;\n\n // Basic check: we need a type alias, otherwise the rest doesn't make sense.\n // EXAMPLE:\n // type FooControllerSomeAction = ...\n if (!NodeGuards.isTypeAliasDeclaration(declaration)) {\n return null;\n }\n\n // We want our type alias to be a reference to a utility type.\n // Non-null assertion: We can assume the type has a body of some kind,\n // otherwise it wouldn't compile.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const body = declaration.getTypeNode()!;\n // We already determined in\n // `recursivelyFindMessengerCapabilityTypeDeclarations` that the declaration\n // is a type reference.\n // TODO: Capture the following information ahead of time so we don't need to\n // check this again.\n // istanbul ignore next\n if (!NodeGuards.isTypeReference(body)) {\n return null;\n }\n const typeName = body.getTypeName();\n // We already determined in\n // `recursivelyFindMessengerCapabilityTypeDeclarations` that the type is an\n // identifier.\n // TODO: Capture the following information ahead of time so we don't need to\n // check this again.\n // istanbul ignore next\n if (!NodeGuards.isIdentifier(typeName)) {\n return null;\n }\n\n // The name of the utility type should be either `ControllerGetStateAction`\n // (for actions) or `ControllerStateChangeEvent` (for events).\n // EXAMPLES:\n // type FooControllerSomeAction = ControllerGetStateAction<...>\n // type FooControllerSomeEvent = ControllerStateChangeEvent<...>\n const expectedConstructor =\n kind === 'action'\n ? 'ControllerGetStateAction'\n : 'ControllerStateChangeEvent';\n if (typeName.getText() !== expectedConstructor) {\n return null;\n }\n\n // The utility type should take two parameters.\n // EXAMPLES:\n // type FooControllerSomeAction = ControllerGetStateAction<..., ...>\n // type FooControllerSomeEvent = ControllerStateChangeEvent<..., ...>\n const typeArgs = body.getTypeArguments();\n if (typeArgs.length < 2) {\n return null;\n }\n\n const namespaceArgType = typeArgs[0].getType();\n // The first parameter should be a string literal.\n // EXAMPLES:\n // type FooControllerSomeAction = ControllerGetStateAction<'FooController', ...>\n // type FooControllerSomeAction = ControllerGetStateAction<typeof CONTROLLER_NAME, ...>\n if (!namespaceArgType.isStringLiteral()) {\n return null;\n }\n // Type assertion: There aren't any type guards we can use to narrow this type\n // further.\n const namespace = namespaceArgType.getLiteralValueOrThrow() as string;\n\n const typeString =\n kind === 'action' ? `${namespace}:getState` : `${namespace}:stateChange`;\n const stateArgText = typeArgs[1].getText();\n const handlerOrPayload =\n kind === 'action' ? `() => ${stateArgText}` : `[${stateArgText}, Patch[]]`;\n const { description, params, returns } = extractJsDoc(declaration);\n const sourceFile = declaration.getSourceFile();\n\n return {\n typeName: declaration.getName(),\n typeString,\n kind,\n jsDoc: description,\n params,\n returns,\n handlerOrPayload,\n sourceFile: path.relative(projectPath, sourceFile.getFilePath()),\n line: declaration.getStartLineNumber(),\n deprecated: hasDeprecatedJsDocTag(declaration),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public entry points\n// ---------------------------------------------------------------------------\n\n/**\n * Create a ts-morph Project configured for messenger-docs extraction. The\n * caller should add every source file that may be referenced (directly or\n * transitively) before calling {@link extractFromSourceFile}, so the type\n * checker can resolve cross-file references.\n *\n * @returns A new ts-morph Project.\n */\nexport function createExtractionProject(): Project {\n return new Project({\n compilerOptions: {\n allowJs: false,\n noEmit: true,\n // Match the project's permissive defaults — we just need symbol\n // resolution, not full typechecking.\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\n/**\n * Extract information (action/event type string, handler/payload arguments and\n * return type, etc.) about every messenger action or event type which is\n * reachable through all of a source file's `*Messenger` type declarations.\n *\n * The caller is responsible for ensuring `sourceFile` (plus any files it\n * imports from) belongs to a `ts-morph` Project so cross-file symbol resolution\n * works.\n *\n * @param sourceFile - The TypeScript source file to extract from.\n * @param projectPath - Project root, used for computing relative source paths.\n * @returns The extracted information about actions and events.\n */\nexport function extractFromSourceFile(\n sourceFile: SourceFile,\n projectPath: string,\n): MessengerCapabilityPacket[] {\n const messengerTypeAliases = findMessengerTypeAliases(sourceFile);\n\n const capabilityTypeDeclarations =\n findAllMessengerCapabilityTypeDeclarations(messengerTypeAliases);\n\n const messengerCapabilityPackets: MessengerCapabilityPacket[] = [];\n for (const capabilityTypeDeclaration of capabilityTypeDeclarations) {\n const messengerCapabilityPacket =\n extractFromMessengerCapabilityTypeDeclaration(\n capabilityTypeDeclaration,\n projectPath,\n );\n if (messengerCapabilityPacket) {\n messengerCapabilityPackets.push(messengerCapabilityPacket);\n }\n }\n return messengerCapabilityPackets;\n}\n\n/**\n * Convenience wrapper: extract from a single file by path. Loads the file\n * and any sibling files in its parent directory into a fresh Project so\n * relative imports resolve.\n *\n * For batch operations across many files, prefer\n * {@link createExtractionProject} + {@link extractFromSourceFile} so one\n * Project amortizes the type-checker setup across the whole run.\n *\n * @param filePath - The absolute path to the TypeScript file.\n * @param projectPath - Base path for computing relative source paths.\n * @returns A promise that resolves to the extracted capability list.\n */\nexport async function extractFromFile(\n filePath: string,\n projectPath: string,\n): Promise<MessengerCapabilityPacket[]> {\n const project = createExtractionProject();\n const parentDir = path.dirname(filePath);\n // Load the file's directory so single-hop relative imports resolve.\n project.addSourceFilesAtPaths([\n path.join(parentDir, '**/*.ts'),\n path.join(parentDir, '**/*.d.cts'),\n ]);\n const sourceFile = project.getSourceFile(filePath);\n // istanbul ignore next: the path always exists since the caller just\n // wrote the file or it was scanned from disk.\n if (!sourceFile) {\n return [];\n }\n return extractFromSourceFile(sourceFile, projectPath);\n}\n"]}
|
package/dist/generate.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.cjs","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 { findDtsFiles, findTsFiles } from './discovery';\nimport { createExtractionProject, extractFromSourceFile } from './extraction';\nimport {\n generateIndexPage,\n generateNamespacePage,\n generateSidebars,\n} from './markdown';\nimport type { ExtractedMessengerCapabilityType, NamespaceGroup } from './types';\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: ExtractedMessengerCapabilityType): 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 GitHub blob base URL for a project by reading its git remote\n * and default branch.\n *\n * @param projectPath - Absolute path to the project root.\n * @returns A base URL like \"https://github.com/Owner/Repo/blob/<branch>/\" or null.\n */\nasync function resolveRepoBaseUrl(projectPath: string): 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 const branch = await resolveDefaultBranch(projectPath);\n return `https://github.com/${match[1]}/blob/${branch}/`;\n } catch {\n return null;\n }\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 /** Directories (relative to projectPath) to scan for .ts source files. */\n scanDirs: 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};\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 * 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 * Run extraction against every file in a single directory, logging and\n * swallowing per-file failures. All files are added to the shared `project`\n * up front so the type checker can resolve cross-file references when the\n * walker descends into imported types.\n *\n * @param project - The shared ts-morph project.\n * @param directory - The directory to scan.\n * @param projectPath - The project root, used for relative path display.\n * @param findFiles - The function used to enumerate files in the directory.\n * @returns The list of extracted messenger items.\n */\nasync function extractFromDirectory(\n project: Project,\n directory: string,\n projectPath: string,\n findFiles: (dir: string) => Promise<string[]>,\n): Promise<ExtractedMessengerCapabilityType[]> {\n const items: ExtractedMessengerCapabilityType[] = [];\n const files = await findFiles(directory);\n for (const file of files) {\n try {\n const sourceFile =\n project.getSourceFile(file) ?? project.addSourceFileAtPath(file);\n items.push(...extractFromSourceFile(sourceFile, projectPath));\n } catch (error) {\n console.warn(\n `Warning: failed to parse ${path.relative(projectPath, file)}`,\n );\n console.warn(error);\n }\n }\n return items;\n}\n\n/**\n * Enumerate the subdirectories of a parent directory that match the expected\n * layout (e.g., `packages/*/src` or `node_modules/@metamask/*/dist`), keeping\n * only those that actually exist.\n *\n * @param parentDir - The parent directory to enumerate.\n * @param subPath - The trailing path component appended to each entry.\n * @param includeSymlinks - Whether to include symbolic links (true for\n * node_modules where workspaces are symlinked).\n * @returns The list of absolute paths to existing target subdirectories.\n */\nasync function listTargetSubdirectories(\n parentDir: string,\n subPath: string,\n includeSymlinks: boolean,\n): Promise<string[]> {\n const entries = await fs.readdir(parentDir, { withFileTypes: true });\n const candidates = entries\n .filter(\n (entry) =>\n entry.isDirectory() || (includeSymlinks && entry.isSymbolicLink()),\n )\n .map((entry) => path.join(parentDir, entry.name, subPath));\n\n const existing: string[] = [];\n for (const candidate of candidates) {\n if (await directoryExists(candidate)) {\n existing.push(candidate);\n }\n }\n return existing;\n}\n\n/**\n * Scan every source location described by `sources` and return all extracted\n * messenger items. A single ts-morph Project is shared across every file so\n * the type checker can resolve cross-file references (e.g. a `*Messenger`\n * declaration in one file walking through an imported umbrella union into\n * an auto-generated `*-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<ExtractedMessengerCapabilityType[]> {\n const project = createExtractionProject();\n const allItems: ExtractedMessengerCapabilityType[] = [];\n\n for (const dir of sources.scanDirs) {\n allItems.push(\n ...(await extractFromDirectory(\n project,\n path.join(projectPath, dir),\n projectPath,\n findTsFiles,\n )),\n );\n }\n\n if (sources.packagesDir) {\n const srcDirs = await listTargetSubdirectories(\n sources.packagesDir,\n 'src',\n false,\n );\n for (const srcDir of srcDirs) {\n allItems.push(\n ...(await extractFromDirectory(\n project,\n srcDir,\n projectPath,\n findTsFiles,\n )),\n );\n }\n }\n\n if (sources.nodeModulesDir) {\n const distDirs = await listTargetSubdirectories(\n sources.nodeModulesDir,\n 'dist',\n true,\n );\n for (const distDir of distDirs) {\n allItems.push(\n ...(await extractFromDirectory(\n project,\n distDir,\n projectPath,\n findDtsFiles,\n )),\n );\n }\n }\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: ExtractedMessengerCapabilityType,\n replacement: ExtractedMessengerCapabilityType,\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: ExtractedMessengerCapabilityType[],\n): NamespaceGroup[] {\n const byNamespace = new Map<string, NamespaceGroup>();\n const seen = new Map<string, ExtractedMessengerCapabilityType>();\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 * 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, scanDirs, projectLabel, commitSha } = options;\n\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 const allItems = await scanSources(projectPath, sources);\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);\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
|
+
{"version":3,"file":"generate.cjs","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAuD;AACvD,2DAA8C;AAC9C,qDAAuC;AACvC,gDAAkC;AAClC,yCAAsC;AAGtC,+CAAwD;AACxD,iDAA8E;AAC9E,6CAIoB;AAGpB;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,IAA+B;IACzD,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,eAAe,GAAG,IAAI,CAAC,UAAU;SACpC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;SACb,OAAO,CAAC,0BAA0B,EAAE,EAAE,CAAC;SACvC,WAAW,EAAE,CAAC;IACjB,MAAM,SAAS,GACb,eAAe,CAAC,MAAM,GAAG,CAAC;QAC1B,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;QACrD,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,CAAC,CAAC;IACR,OAAO,UAAU,GAAG,SAAS,CAAC;AAChC,CAAC;AAED,MAAM,aAAa,GAAG,IAAA,qBAAS,EAAC,6BAAQ,CAAC,CAAC;AAE1C;;;;;;;GAOG;AACH,KAAK,UAAU,oBAAoB,CAAC,WAAmB;IACrD,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CACpC,KAAK,EACL,CAAC,cAAc,EAAE,SAAS,EAAE,0BAA0B,CAAC,EACvD,EAAE,GAAG,EAAE,WAAW,EAAE,CACrB,CAAC;QACF,gEAAgE;QAChE,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,OAAO,KAAK,KAAK,CAAC,CAAC;YACjB,CAAC,CAAC,kEAAkE;gBAClE,+DAA+D;gBAC/D,6DAA6D;gBAC7D,OAAO,IAAI,MAAM;YACnB,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC;IAChB,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,kBAAkB,CAAC,WAAmB;IACnD,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,aAAa,CAC/C,KAAK,EACL,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,EAC/B,EAAE,GAAG,EAAE,WAAW,EAAE,CACrB,CAAC;QAEF,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;QAEhC,iDAAiD;QACjD,0DAA0D;QAC1D,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CACxB,kDAAkD,CACnD,CAAC;QACF,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,WAAW,CAAC,CAAC;QACvD,OAAO,sBAAsB,KAAK,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AA8CD;;;;;;GAMG;AACH,KAAK,UAAU,mBAAmB,CAChC,WAAmB,EACnB,QAAkB;IAElB,MAAM,gBAAgB,GAAa,EAAE,CAAC;IACtC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,MAAM,IAAA,sBAAe,EAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;YACvD,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACvD,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC;IAE3E,OAAO;QACL,QAAQ,EAAE,gBAAgB;QAC1B,WAAW,EAAE,CAAC,MAAM,IAAA,sBAAe,EAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI;QACtE,cAAc,EAAE,CAAC,MAAM,IAAA,sBAAe,EAAC,cAAc,CAAC,CAAC;YACrD,CAAC,CAAC,cAAc;YAChB,CAAC,CAAC,IAAI;KACT,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CAAC,OAAoB;IACvC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACnC,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACvC,CAAC;IACD,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,CAAC,GAAG,CACT,YAAY,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,sCAAsC,CACrE,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,KAAK,UAAU,oBAAoB,CACjC,OAAgB,EAChB,SAAiB,EACjB,WAAmB,EACnB,SAA6C;IAE7C,MAAM,KAAK,GAAgC,EAAE,CAAC;IAC9C,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,SAAS,CAAC,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,UAAU,GACd,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;YACnE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAA,kCAAqB,EAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;QAChE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CACV,4BAA4B,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,CAC/D,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;GAUG;AACH,KAAK,UAAU,wBAAwB,CACrC,SAAiB,EACjB,OAAe,EACf,eAAwB;IAExB,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,OAAO;SACvB,MAAM,CACL,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,eAAe,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC,CACrE;SACA,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAE7D,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,MAAM,IAAA,sBAAe,EAAC,SAAS,CAAC,EAAE,CAAC;YACrC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;;;;GAUG;AACH,KAAK,UAAU,WAAW,CACxB,WAAmB,EACnB,OAAoB;IAEpB,MAAM,OAAO,GAAG,IAAA,oCAAuB,GAAE,CAAC;IAC1C,MAAM,QAAQ,GAAgC,EAAE,CAAC;IAEjD,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACnC,QAAQ,CAAC,IAAI,CACX,GAAG,CAAC,MAAM,oBAAoB,CAC5B,OAAO,EACP,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,EAC3B,WAAW,EACX,uBAAW,CACZ,CAAC,CACH,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,MAAM,wBAAwB,CAC5C,OAAO,CAAC,WAAW,EACnB,KAAK,EACL,KAAK,CACN,CAAC;QACF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,QAAQ,CAAC,IAAI,CACX,GAAG,CAAC,MAAM,oBAAoB,CAC5B,OAAO,EACP,MAAM,EACN,WAAW,EACX,uBAAW,CACZ,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,MAAM,wBAAwB,CAC7C,OAAO,CAAC,cAAc,EACtB,MAAM,EACN,IAAI,CACL,CAAC;QACF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,QAAQ,CAAC,IAAI,CACX,GAAG,CAAC,MAAM,oBAAoB,CAC5B,OAAO,EACP,OAAO,EACP,WAAW,EACX,wBAAY,CACb,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,uBAAuB,CAC9B,WAAwC,EACxC,QAAmC,EACnC,WAAsC;IAEtC,MAAM,SAAS,GAAG,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACzC,mEAAmE;IACnE,kEAAkE;IAClE,oEAAoE;IACpE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;IACT,CAAC;IACD,MAAM,YAAY,GAChB,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;IAC5D,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7C,mEAAmE;IACnE,sEAAsE;IACtE,mCAAmC;IACnC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;QACjB,OAAO;IACT,CAAC;IACD,IAAI,QAAQ,CAAC,IAAI,KAAK,WAAW,CAAC,IAAI,EAAE,CAAC;QACvC,YAAY,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC9B,MAAM,OAAO,GACX,WAAW,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;QAC/D,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC5B,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,gBAAgB,CACvB,KAAkC;IAElC,MAAM,WAAW,GAAG,IAAI,GAAG,EAA0B,CAAC;IACtD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAqC,CAAC;IAE1D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7D,SAAS;YACX,CAAC;YACD,uBAAuB,CAAC,WAAW,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YACrD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YAChC,SAAS;QACX,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,IAAI,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,KAAK,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;YAC/C,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACpC,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC3B,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAChE,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CACvC,CAAC;IAEF,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;QAC5B,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;QACpE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,KAAK,UAAU,WAAW,CACxB,UAA4B,EAC5B,SAAiB,EACjB,WAA0B,EAC1B,YAGC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAE7C,IAAI,MAAM,IAAA,sBAAe,EAAC,OAAO,CAAC,EAAE,CAAC;QACnC,MAAM,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE7C,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;QAC/C,MAAM,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE3C,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,EAC9B,IAAA,gCAAqB,EAAC,EAAE,EAAE,QAAQ,EAAE,WAAW,CAAC,CACjD,CAAC;QACJ,CAAC;QAED,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,EAC7B,IAAA,gCAAqB,EAAC,EAAE,EAAE,OAAO,EAAE,WAAW,CAAC,CAChD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAC9B,IAAA,4BAAiB,EAAC,UAAU,EAAE,YAAY,CAAC,CAC5C,CAAC;IAEF,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,EACnC,IAAA,2BAAgB,EAAC,UAAU,CAAC,CAC7B,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,QAAQ,CAC5B,OAAwB;IAExB,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAE9E,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAEjE,IACE,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;QAC7B,CAAC,OAAO,CAAC,WAAW;QACpB,CAAC,OAAO,CAAC,cAAc,EACvB,CAAC;QACD,MAAM,IAAI,KAAK,CACb,qCAAqC,WAAW,IAAI;YAClD,eAAe,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,sCAAsC,CAC3E,CAAC;IACJ,CAAC;IAED,WAAW,CAAC,OAAO,CAAC,CAAC;IAErB,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CACT,SAAS,QAAQ,CAAC,MAAM,cAAc,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,SAAS,CACxF,CAAC;IAEF,MAAM,UAAU,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,WAAW,CAAC,CAAC;IAE1D,MAAM,WAAW,CAAC,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE;QACpD,YAAY;QACZ,SAAS;KACV,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CACpC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,EACpC,CAAC,CACF,CAAC;IACF,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAE9E,OAAO,CAAC,GAAG,CACT,sBAAsB,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,GAAG,CACnG,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,cAAc,YAAY,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,aAAa,WAAW,EAAE,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IAExD,OAAO;QACL,UAAU,EAAE,UAAU,CAAC,MAAM;QAC7B,OAAO,EAAE,YAAY;QACrB,MAAM,EAAE,WAAW;KACpB,CAAC;AACJ,CAAC;AAnDD,4BAmDC","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 { findDtsFiles, findTsFiles } from './discovery';\nimport { createExtractionProject, extractFromSourceFile } from './extraction';\nimport {\n generateIndexPage,\n generateNamespacePage,\n generateSidebars,\n} from './markdown';\nimport type { MessengerCapabilityPacket, NamespaceGroup } from './types';\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 GitHub blob base URL for a project by reading its git remote\n * and default branch.\n *\n * @param projectPath - Absolute path to the project root.\n * @returns A base URL like \"https://github.com/Owner/Repo/blob/<branch>/\" or null.\n */\nasync function resolveRepoBaseUrl(projectPath: string): 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 const branch = await resolveDefaultBranch(projectPath);\n return `https://github.com/${match[1]}/blob/${branch}/`;\n } catch {\n return null;\n }\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 /** Directories (relative to projectPath) to scan for .ts source files. */\n scanDirs: 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};\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 * 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 * Run extraction against every file in a single directory, logging and\n * swallowing per-file failures. All files are added to the shared `project`\n * up front so the type checker can resolve cross-file references when the\n * walker descends into imported types.\n *\n * @param project - The shared ts-morph project.\n * @param directory - The directory to scan.\n * @param projectPath - The project root, used for relative path display.\n * @param findFiles - The function used to enumerate files in the directory.\n * @returns The list of extracted messenger items.\n */\nasync function extractFromDirectory(\n project: Project,\n directory: string,\n projectPath: string,\n findFiles: (dir: string) => Promise<string[]>,\n): Promise<MessengerCapabilityPacket[]> {\n const items: MessengerCapabilityPacket[] = [];\n const files = await findFiles(directory);\n for (const file of files) {\n try {\n const sourceFile =\n project.getSourceFile(file) ?? project.addSourceFileAtPath(file);\n items.push(...extractFromSourceFile(sourceFile, projectPath));\n } catch (error) {\n console.warn(\n `Warning: failed to parse ${path.relative(projectPath, file)}`,\n );\n console.warn(error);\n }\n }\n return items;\n}\n\n/**\n * Enumerate the subdirectories of a parent directory that match the expected\n * layout (e.g., `packages/*/src` or `node_modules/@metamask/*/dist`), keeping\n * only those that actually exist.\n *\n * @param parentDir - The parent directory to enumerate.\n * @param subPath - The trailing path component appended to each entry.\n * @param includeSymlinks - Whether to include symbolic links (true for\n * node_modules where workspaces are symlinked).\n * @returns The list of absolute paths to existing target subdirectories.\n */\nasync function listTargetSubdirectories(\n parentDir: string,\n subPath: string,\n includeSymlinks: boolean,\n): Promise<string[]> {\n const entries = await fs.readdir(parentDir, { withFileTypes: true });\n const candidates = entries\n .filter(\n (entry) =>\n entry.isDirectory() || (includeSymlinks && entry.isSymbolicLink()),\n )\n .map((entry) => path.join(parentDir, entry.name, subPath));\n\n const existing: string[] = [];\n for (const candidate of candidates) {\n if (await directoryExists(candidate)) {\n existing.push(candidate);\n }\n }\n return existing;\n}\n\n/**\n * Scan every source location described by `sources` and return all extracted\n * messenger items. A single ts-morph Project is shared across every file so\n * the type checker can resolve cross-file references (e.g. a `*Messenger`\n * declaration in one file walking through an imported umbrella union into\n * an auto-generated `*-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 = createExtractionProject();\n const allItems: MessengerCapabilityPacket[] = [];\n\n for (const dir of sources.scanDirs) {\n allItems.push(\n ...(await extractFromDirectory(\n project,\n path.join(projectPath, dir),\n projectPath,\n findTsFiles,\n )),\n );\n }\n\n if (sources.packagesDir) {\n const srcDirs = await listTargetSubdirectories(\n sources.packagesDir,\n 'src',\n false,\n );\n for (const srcDir of srcDirs) {\n allItems.push(\n ...(await extractFromDirectory(\n project,\n srcDir,\n projectPath,\n findTsFiles,\n )),\n );\n }\n }\n\n if (sources.nodeModulesDir) {\n const distDirs = await listTargetSubdirectories(\n sources.nodeModulesDir,\n 'dist',\n true,\n );\n for (const distDir of distDirs) {\n allItems.push(\n ...(await extractFromDirectory(\n project,\n distDir,\n projectPath,\n findDtsFiles,\n )),\n );\n }\n }\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 * 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, scanDirs, projectLabel, commitSha } = options;\n\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 const allItems = await scanSources(projectPath, sources);\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);\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"]}
|
package/dist/generate.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.mjs","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 { findDtsFiles, findTsFiles } from './discovery';\nimport { createExtractionProject, extractFromSourceFile } from './extraction';\nimport {\n generateIndexPage,\n generateNamespacePage,\n generateSidebars,\n} from './markdown';\nimport type { ExtractedMessengerCapabilityType, NamespaceGroup } from './types';\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: ExtractedMessengerCapabilityType): 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 GitHub blob base URL for a project by reading its git remote\n * and default branch.\n *\n * @param projectPath - Absolute path to the project root.\n * @returns A base URL like \"https://github.com/Owner/Repo/blob/<branch>/\" or null.\n */\nasync function resolveRepoBaseUrl(projectPath: string): 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 const branch = await resolveDefaultBranch(projectPath);\n return `https://github.com/${match[1]}/blob/${branch}/`;\n } catch {\n return null;\n }\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 /** Directories (relative to projectPath) to scan for .ts source files. */\n scanDirs: 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};\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 * 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 * Run extraction against every file in a single directory, logging and\n * swallowing per-file failures. All files are added to the shared `project`\n * up front so the type checker can resolve cross-file references when the\n * walker descends into imported types.\n *\n * @param project - The shared ts-morph project.\n * @param directory - The directory to scan.\n * @param projectPath - The project root, used for relative path display.\n * @param findFiles - The function used to enumerate files in the directory.\n * @returns The list of extracted messenger items.\n */\nasync function extractFromDirectory(\n project: Project,\n directory: string,\n projectPath: string,\n findFiles: (dir: string) => Promise<string[]>,\n): Promise<ExtractedMessengerCapabilityType[]> {\n const items: ExtractedMessengerCapabilityType[] = [];\n const files = await findFiles(directory);\n for (const file of files) {\n try {\n const sourceFile =\n project.getSourceFile(file) ?? project.addSourceFileAtPath(file);\n items.push(...extractFromSourceFile(sourceFile, projectPath));\n } catch (error) {\n console.warn(\n `Warning: failed to parse ${path.relative(projectPath, file)}`,\n );\n console.warn(error);\n }\n }\n return items;\n}\n\n/**\n * Enumerate the subdirectories of a parent directory that match the expected\n * layout (e.g., `packages/*/src` or `node_modules/@metamask/*/dist`), keeping\n * only those that actually exist.\n *\n * @param parentDir - The parent directory to enumerate.\n * @param subPath - The trailing path component appended to each entry.\n * @param includeSymlinks - Whether to include symbolic links (true for\n * node_modules where workspaces are symlinked).\n * @returns The list of absolute paths to existing target subdirectories.\n */\nasync function listTargetSubdirectories(\n parentDir: string,\n subPath: string,\n includeSymlinks: boolean,\n): Promise<string[]> {\n const entries = await fs.readdir(parentDir, { withFileTypes: true });\n const candidates = entries\n .filter(\n (entry) =>\n entry.isDirectory() || (includeSymlinks && entry.isSymbolicLink()),\n )\n .map((entry) => path.join(parentDir, entry.name, subPath));\n\n const existing: string[] = [];\n for (const candidate of candidates) {\n if (await directoryExists(candidate)) {\n existing.push(candidate);\n }\n }\n return existing;\n}\n\n/**\n * Scan every source location described by `sources` and return all extracted\n * messenger items. A single ts-morph Project is shared across every file so\n * the type checker can resolve cross-file references (e.g. a `*Messenger`\n * declaration in one file walking through an imported umbrella union into\n * an auto-generated `*-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<ExtractedMessengerCapabilityType[]> {\n const project = createExtractionProject();\n const allItems: ExtractedMessengerCapabilityType[] = [];\n\n for (const dir of sources.scanDirs) {\n allItems.push(\n ...(await extractFromDirectory(\n project,\n path.join(projectPath, dir),\n projectPath,\n findTsFiles,\n )),\n );\n }\n\n if (sources.packagesDir) {\n const srcDirs = await listTargetSubdirectories(\n sources.packagesDir,\n 'src',\n false,\n );\n for (const srcDir of srcDirs) {\n allItems.push(\n ...(await extractFromDirectory(\n project,\n srcDir,\n projectPath,\n findTsFiles,\n )),\n );\n }\n }\n\n if (sources.nodeModulesDir) {\n const distDirs = await listTargetSubdirectories(\n sources.nodeModulesDir,\n 'dist',\n true,\n );\n for (const distDir of distDirs) {\n allItems.push(\n ...(await extractFromDirectory(\n project,\n distDir,\n projectPath,\n findDtsFiles,\n )),\n );\n }\n }\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: ExtractedMessengerCapabilityType,\n replacement: ExtractedMessengerCapabilityType,\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: ExtractedMessengerCapabilityType[],\n): NamespaceGroup[] {\n const byNamespace = new Map<string, NamespaceGroup>();\n const seen = new Map<string, ExtractedMessengerCapabilityType>();\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 * 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, scanDirs, projectLabel, commitSha } = options;\n\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 const allItems = await scanSources(projectPath, sources);\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);\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
|
+
{"version":3,"file":"generate.mjs","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 { findDtsFiles, findTsFiles } from './discovery';\nimport { createExtractionProject, extractFromSourceFile } from './extraction';\nimport {\n generateIndexPage,\n generateNamespacePage,\n generateSidebars,\n} from './markdown';\nimport type { MessengerCapabilityPacket, NamespaceGroup } from './types';\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 GitHub blob base URL for a project by reading its git remote\n * and default branch.\n *\n * @param projectPath - Absolute path to the project root.\n * @returns A base URL like \"https://github.com/Owner/Repo/blob/<branch>/\" or null.\n */\nasync function resolveRepoBaseUrl(projectPath: string): 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 const branch = await resolveDefaultBranch(projectPath);\n return `https://github.com/${match[1]}/blob/${branch}/`;\n } catch {\n return null;\n }\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 /** Directories (relative to projectPath) to scan for .ts source files. */\n scanDirs: 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};\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 * 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 * Run extraction against every file in a single directory, logging and\n * swallowing per-file failures. All files are added to the shared `project`\n * up front so the type checker can resolve cross-file references when the\n * walker descends into imported types.\n *\n * @param project - The shared ts-morph project.\n * @param directory - The directory to scan.\n * @param projectPath - The project root, used for relative path display.\n * @param findFiles - The function used to enumerate files in the directory.\n * @returns The list of extracted messenger items.\n */\nasync function extractFromDirectory(\n project: Project,\n directory: string,\n projectPath: string,\n findFiles: (dir: string) => Promise<string[]>,\n): Promise<MessengerCapabilityPacket[]> {\n const items: MessengerCapabilityPacket[] = [];\n const files = await findFiles(directory);\n for (const file of files) {\n try {\n const sourceFile =\n project.getSourceFile(file) ?? project.addSourceFileAtPath(file);\n items.push(...extractFromSourceFile(sourceFile, projectPath));\n } catch (error) {\n console.warn(\n `Warning: failed to parse ${path.relative(projectPath, file)}`,\n );\n console.warn(error);\n }\n }\n return items;\n}\n\n/**\n * Enumerate the subdirectories of a parent directory that match the expected\n * layout (e.g., `packages/*/src` or `node_modules/@metamask/*/dist`), keeping\n * only those that actually exist.\n *\n * @param parentDir - The parent directory to enumerate.\n * @param subPath - The trailing path component appended to each entry.\n * @param includeSymlinks - Whether to include symbolic links (true for\n * node_modules where workspaces are symlinked).\n * @returns The list of absolute paths to existing target subdirectories.\n */\nasync function listTargetSubdirectories(\n parentDir: string,\n subPath: string,\n includeSymlinks: boolean,\n): Promise<string[]> {\n const entries = await fs.readdir(parentDir, { withFileTypes: true });\n const candidates = entries\n .filter(\n (entry) =>\n entry.isDirectory() || (includeSymlinks && entry.isSymbolicLink()),\n )\n .map((entry) => path.join(parentDir, entry.name, subPath));\n\n const existing: string[] = [];\n for (const candidate of candidates) {\n if (await directoryExists(candidate)) {\n existing.push(candidate);\n }\n }\n return existing;\n}\n\n/**\n * Scan every source location described by `sources` and return all extracted\n * messenger items. A single ts-morph Project is shared across every file so\n * the type checker can resolve cross-file references (e.g. a `*Messenger`\n * declaration in one file walking through an imported umbrella union into\n * an auto-generated `*-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 = createExtractionProject();\n const allItems: MessengerCapabilityPacket[] = [];\n\n for (const dir of sources.scanDirs) {\n allItems.push(\n ...(await extractFromDirectory(\n project,\n path.join(projectPath, dir),\n projectPath,\n findTsFiles,\n )),\n );\n }\n\n if (sources.packagesDir) {\n const srcDirs = await listTargetSubdirectories(\n sources.packagesDir,\n 'src',\n false,\n );\n for (const srcDir of srcDirs) {\n allItems.push(\n ...(await extractFromDirectory(\n project,\n srcDir,\n projectPath,\n findTsFiles,\n )),\n );\n }\n }\n\n if (sources.nodeModulesDir) {\n const distDirs = await listTargetSubdirectories(\n sources.nodeModulesDir,\n 'dist',\n true,\n );\n for (const distDir of distDirs) {\n allItems.push(\n ...(await extractFromDirectory(\n project,\n distDir,\n projectPath,\n findDtsFiles,\n )),\n );\n }\n }\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 * 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, scanDirs, projectLabel, commitSha } = options;\n\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 const allItems = await scanSources(projectPath, sources);\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);\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"]}
|