@metamask-previews/platform-api-docs 0.0.0-preview-1275d0fda
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/CHANGELOG.md +14 -0
- package/LICENSE +6 -0
- package/LICENSE.APACHE2 +201 -0
- package/LICENSE.MIT +21 -0
- package/README.md +39 -0
- package/dist/cli.cjs +214 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +3 -0
- package/dist/cli.d.cts.map +1 -0
- package/dist/cli.d.mts +3 -0
- package/dist/cli.d.mts.map +1 -0
- package/dist/cli.mjs +212 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/discovery.cjs +53 -0
- package/dist/discovery.cjs.map +1 -0
- package/dist/discovery.d.cts +22 -0
- package/dist/discovery.d.cts.map +1 -0
- package/dist/discovery.d.mts +22 -0
- package/dist/discovery.d.mts.map +1 -0
- package/dist/discovery.mjs +48 -0
- package/dist/discovery.mjs.map +1 -0
- package/dist/extraction.cjs +745 -0
- package/dist/extraction.cjs.map +1 -0
- package/dist/extraction.d.cts +40 -0
- package/dist/extraction.d.cts.map +1 -0
- package/dist/extraction.d.mts +40 -0
- package/dist/extraction.d.mts.map +1 -0
- package/dist/extraction.mjs +716 -0
- package/dist/extraction.mjs.map +1 -0
- package/dist/generate.cjs +373 -0
- package/dist/generate.cjs.map +1 -0
- package/dist/generate.d.cts +37 -0
- package/dist/generate.d.cts.map +1 -0
- package/dist/generate.d.mts +37 -0
- package/dist/generate.d.mts.map +1 -0
- package/dist/generate.mjs +346 -0
- package/dist/generate.mjs.map +1 -0
- package/dist/markdown.cjs +239 -0
- package/dist/markdown.cjs.map +1 -0
- package/dist/markdown.d.cts +52 -0
- package/dist/markdown.d.cts.map +1 -0
- package/dist/markdown.d.mts +52 -0
- package/dist/markdown.d.mts.map +1 -0
- package/dist/markdown.mjs +232 -0
- package/dist/markdown.mjs.map +1 -0
- package/dist/types.cjs +3 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +63 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.mts +63 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +2 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +75 -0
- package/site/docusaurus.config.ts +103 -0
- package/site/src/css/custom.css +336 -0
- package/site/static/fonts/MM-Sans/MM_Sans_Mono-Regular.woff2 +0 -0
- package/site/static/img/favicons/favicon-96x96.png +0 -0
- package/site/static/img/metamask-fox.svg +12 -0
- package/site/static/img/metamask-logo-dark.svg +3 -0
- package/site/static/img/metamask-logo.svg +3 -0
- package/site/tsconfig.json +13 -0
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.generate = void 0;
|
|
27
|
+
const node_1 = require("@metamask/utils/node");
|
|
28
|
+
const node_child_process_1 = require("node:child_process");
|
|
29
|
+
const fs = __importStar(require("node:fs/promises"));
|
|
30
|
+
const path = __importStar(require("node:path"));
|
|
31
|
+
const node_util_1 = require("node:util");
|
|
32
|
+
const discovery_1 = require("./discovery.cjs");
|
|
33
|
+
const extraction_1 = require("./extraction.cjs");
|
|
34
|
+
const markdown_1 = require("./markdown.cjs");
|
|
35
|
+
/**
|
|
36
|
+
* Compute a deduplication score for a messenger item, preferring items with
|
|
37
|
+
* JSDoc and from the "home" package whose name matches the namespace.
|
|
38
|
+
*
|
|
39
|
+
* @param item - The messenger item to score.
|
|
40
|
+
* @returns A numeric score (higher is better).
|
|
41
|
+
*/
|
|
42
|
+
function deduplicationScore(item) {
|
|
43
|
+
const jsDocScore = item.jsDoc ? 2 : 0;
|
|
44
|
+
const namespacePrefix = item.typeString
|
|
45
|
+
.split(':')[0]
|
|
46
|
+
.replace(/(?:Controller|Service)$/u, '')
|
|
47
|
+
.toLowerCase();
|
|
48
|
+
const homeScore = namespacePrefix.length > 0 &&
|
|
49
|
+
item.sourceFile.toLowerCase().includes(namespacePrefix)
|
|
50
|
+
? 1
|
|
51
|
+
: 0;
|
|
52
|
+
return jsDocScore + homeScore;
|
|
53
|
+
}
|
|
54
|
+
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
55
|
+
/**
|
|
56
|
+
* Resolve the default branch of a project's `origin` remote by reading the
|
|
57
|
+
* symbolic ref `refs/remotes/origin/HEAD`. Falls back to `main` if the
|
|
58
|
+
* symbolic ref isn't set (e.g. in shallow CI clones).
|
|
59
|
+
*
|
|
60
|
+
* @param projectPath - Absolute path to the project root.
|
|
61
|
+
* @returns The default branch name (e.g. "main", "master", "develop").
|
|
62
|
+
*/
|
|
63
|
+
async function resolveDefaultBranch(projectPath) {
|
|
64
|
+
try {
|
|
65
|
+
const { stdout } = await execFileAsync('git', ['symbolic-ref', '--short', 'refs/remotes/origin/HEAD'], { cwd: projectPath });
|
|
66
|
+
// stdout looks like "origin/main"; strip the leading "origin/".
|
|
67
|
+
const trimmed = stdout.trim();
|
|
68
|
+
const slash = trimmed.indexOf('/');
|
|
69
|
+
return slash === -1
|
|
70
|
+
? // istanbul ignore next: defensive — `symbolic-ref --short` always
|
|
71
|
+
// returns `origin/<branch>` when the symbolic ref is set; this
|
|
72
|
+
// fallback only matters if git's output format ever changes.
|
|
73
|
+
trimmed || 'main'
|
|
74
|
+
: trimmed.slice(slash + 1);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return 'main';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Resolve the GitHub blob base URL for a project by reading its git remote
|
|
82
|
+
* and default branch.
|
|
83
|
+
*
|
|
84
|
+
* @param projectPath - Absolute path to the project root.
|
|
85
|
+
* @returns A base URL like "https://github.com/Owner/Repo/blob/<branch>/" or null.
|
|
86
|
+
*/
|
|
87
|
+
async function resolveRepoBaseUrl(projectPath) {
|
|
88
|
+
try {
|
|
89
|
+
const { stdout: remoteRaw } = await execFileAsync('git', ['remote', 'get-url', 'origin'], { cwd: projectPath });
|
|
90
|
+
const remote = remoteRaw.trim();
|
|
91
|
+
// Parse owner/repo from SSH or HTTPS remote URLs
|
|
92
|
+
// Handles aliases like github.com-Org used in SSH configs
|
|
93
|
+
const match = remote.match(/github\.com[^:/]*[:/]([^/]+\/[^/]+?)(?:\.git)?$/u);
|
|
94
|
+
if (!match) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const branch = await resolveDefaultBranch(projectPath);
|
|
98
|
+
return `https://github.com/${match[1]}/blob/${branch}/`;
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Discover which configured source locations actually exist on disk.
|
|
106
|
+
*
|
|
107
|
+
* @param projectPath - The project root path.
|
|
108
|
+
* @param scanDirs - User-configured scan directories relative to projectPath.
|
|
109
|
+
* @returns A ScanSources object describing the locations to scan.
|
|
110
|
+
*/
|
|
111
|
+
async function discoverScanSources(projectPath, scanDirs) {
|
|
112
|
+
const existingScanDirs = [];
|
|
113
|
+
for (const dir of scanDirs) {
|
|
114
|
+
if (await (0, node_1.directoryExists)(path.join(projectPath, dir))) {
|
|
115
|
+
existingScanDirs.push(dir);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const packagesDir = path.join(projectPath, 'packages');
|
|
119
|
+
const nodeModulesDir = path.join(projectPath, 'node_modules', '@metamask');
|
|
120
|
+
return {
|
|
121
|
+
scanDirs: existingScanDirs,
|
|
122
|
+
packagesDir: (await (0, node_1.directoryExists)(packagesDir)) ? packagesDir : null,
|
|
123
|
+
nodeModulesDir: (await (0, node_1.directoryExists)(nodeModulesDir))
|
|
124
|
+
? nodeModulesDir
|
|
125
|
+
: null,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Log a human-readable description of which source locations will be scanned.
|
|
130
|
+
*
|
|
131
|
+
* @param sources - The resolved scan sources.
|
|
132
|
+
*/
|
|
133
|
+
function logScanPlan(sources) {
|
|
134
|
+
const summary = [];
|
|
135
|
+
for (const dir of sources.scanDirs) {
|
|
136
|
+
summary.push(`${dir}/ (.ts)`);
|
|
137
|
+
}
|
|
138
|
+
if (sources.packagesDir) {
|
|
139
|
+
summary.push('packages/*/src (.ts)');
|
|
140
|
+
}
|
|
141
|
+
if (sources.nodeModulesDir) {
|
|
142
|
+
summary.push('node_modules/@metamask/*/dist (.d.cts)');
|
|
143
|
+
}
|
|
144
|
+
console.log(`Scanning ${summary.join(', ')} for Messenger action/event types...`);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Run extraction against every file in a single directory, logging and
|
|
148
|
+
* swallowing per-file failures. All files are added to the shared `project`
|
|
149
|
+
* up front so the type checker can resolve cross-file references when the
|
|
150
|
+
* walker descends into imported types.
|
|
151
|
+
*
|
|
152
|
+
* @param project - The shared ts-morph project.
|
|
153
|
+
* @param directory - The directory to scan.
|
|
154
|
+
* @param projectPath - The project root, used for relative path display.
|
|
155
|
+
* @param findFiles - The function used to enumerate files in the directory.
|
|
156
|
+
* @returns The list of extracted messenger items.
|
|
157
|
+
*/
|
|
158
|
+
async function extractFromDirectory(project, directory, projectPath, findFiles) {
|
|
159
|
+
const items = [];
|
|
160
|
+
const files = await findFiles(directory);
|
|
161
|
+
for (const file of files) {
|
|
162
|
+
try {
|
|
163
|
+
const sourceFile = project.getSourceFile(file) ?? project.addSourceFileAtPath(file);
|
|
164
|
+
items.push(...(0, extraction_1.extractFromSourceFile)(sourceFile, projectPath));
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
console.warn(`Warning: failed to parse ${path.relative(projectPath, file)}`);
|
|
168
|
+
console.warn(error);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return items;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Enumerate the subdirectories of a parent directory that match the expected
|
|
175
|
+
* layout (e.g., `packages/*/src` or `node_modules/@metamask/*/dist`), keeping
|
|
176
|
+
* only those that actually exist.
|
|
177
|
+
*
|
|
178
|
+
* @param parentDir - The parent directory to enumerate.
|
|
179
|
+
* @param subPath - The trailing path component appended to each entry.
|
|
180
|
+
* @param includeSymlinks - Whether to include symbolic links (true for
|
|
181
|
+
* node_modules where workspaces are symlinked).
|
|
182
|
+
* @returns The list of absolute paths to existing target subdirectories.
|
|
183
|
+
*/
|
|
184
|
+
async function listTargetSubdirectories(parentDir, subPath, includeSymlinks) {
|
|
185
|
+
const entries = await fs.readdir(parentDir, { withFileTypes: true });
|
|
186
|
+
const candidates = entries
|
|
187
|
+
.filter((entry) => entry.isDirectory() || (includeSymlinks && entry.isSymbolicLink()))
|
|
188
|
+
.map((entry) => path.join(parentDir, entry.name, subPath));
|
|
189
|
+
const existing = [];
|
|
190
|
+
for (const candidate of candidates) {
|
|
191
|
+
if (await (0, node_1.directoryExists)(candidate)) {
|
|
192
|
+
existing.push(candidate);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return existing;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Scan every source location described by `sources` and return all extracted
|
|
199
|
+
* messenger items. A single ts-morph Project is shared across every file so
|
|
200
|
+
* the type checker can resolve cross-file references (e.g. a `*Messenger`
|
|
201
|
+
* declaration in one file walking through an imported umbrella union into
|
|
202
|
+
* an auto-generated `*-method-action-types.ts` sibling).
|
|
203
|
+
*
|
|
204
|
+
* @param projectPath - The project root path.
|
|
205
|
+
* @param sources - The set of source locations to scan.
|
|
206
|
+
* @returns A flat list of all extracted messenger items.
|
|
207
|
+
*/
|
|
208
|
+
async function scanSources(projectPath, sources) {
|
|
209
|
+
const project = (0, extraction_1.createExtractionProject)();
|
|
210
|
+
const allItems = [];
|
|
211
|
+
for (const dir of sources.scanDirs) {
|
|
212
|
+
allItems.push(...(await extractFromDirectory(project, path.join(projectPath, dir), projectPath, discovery_1.findTsFiles)));
|
|
213
|
+
}
|
|
214
|
+
if (sources.packagesDir) {
|
|
215
|
+
const srcDirs = await listTargetSubdirectories(sources.packagesDir, 'src', false);
|
|
216
|
+
for (const srcDir of srcDirs) {
|
|
217
|
+
allItems.push(...(await extractFromDirectory(project, srcDir, projectPath, discovery_1.findTsFiles)));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (sources.nodeModulesDir) {
|
|
221
|
+
const distDirs = await listTargetSubdirectories(sources.nodeModulesDir, 'dist', true);
|
|
222
|
+
for (const distDir of distDirs) {
|
|
223
|
+
allItems.push(...(await extractFromDirectory(project, distDir, projectPath, discovery_1.findDtsFiles)));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return allItems;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Replace a previously-seen item in its existing namespace group with a
|
|
230
|
+
* higher-scoring duplicate. Handles the case where the duplicate is a
|
|
231
|
+
* different kind (action vs event) by moving it between lists.
|
|
232
|
+
*
|
|
233
|
+
* @param byNamespace - Map of namespace to its group.
|
|
234
|
+
* @param previous - The previously stored item.
|
|
235
|
+
* @param replacement - The new item to replace it with.
|
|
236
|
+
*/
|
|
237
|
+
function replaceDuplicateInGroup(byNamespace, previous, replacement) {
|
|
238
|
+
const namespace = replacement.typeString.split(':')[0];
|
|
239
|
+
const group = byNamespace.get(namespace);
|
|
240
|
+
// istanbul ignore next: `previous` and `replacement` have the same
|
|
241
|
+
// typeString, so they share a namespace, and we always insert the
|
|
242
|
+
// namespace into `byNamespace` before recording the original entry.
|
|
243
|
+
if (!group) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const previousList = previous.kind === 'action' ? group.actions : group.events;
|
|
247
|
+
const index = previousList.indexOf(previous);
|
|
248
|
+
// istanbul ignore next: `previous` was added to its kind's list by
|
|
249
|
+
// `groupByNamespace` before being recorded in `seen`, so it is always
|
|
250
|
+
// present when we look it up here.
|
|
251
|
+
if (index === -1) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (previous.kind === replacement.kind) {
|
|
255
|
+
previousList[index] = replacement;
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
previousList.splice(index, 1);
|
|
259
|
+
const newList = replacement.kind === 'action' ? group.actions : group.events;
|
|
260
|
+
newList.push(replacement);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Group items by namespace, deduplicating duplicate typeStrings using
|
|
265
|
+
* `deduplicationScore`. Returns groups sorted alphabetically by namespace,
|
|
266
|
+
* with each group's items sorted alphabetically by typeString.
|
|
267
|
+
*
|
|
268
|
+
* @param items - The full list of extracted items.
|
|
269
|
+
* @returns The deduplicated and sorted namespace groups.
|
|
270
|
+
*/
|
|
271
|
+
function groupByNamespace(items) {
|
|
272
|
+
const byNamespace = new Map();
|
|
273
|
+
const seen = new Map();
|
|
274
|
+
for (const item of items) {
|
|
275
|
+
const existing = seen.get(item.typeString);
|
|
276
|
+
if (existing) {
|
|
277
|
+
if (deduplicationScore(item) <= deduplicationScore(existing)) {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
replaceDuplicateInGroup(byNamespace, existing, item);
|
|
281
|
+
seen.set(item.typeString, item);
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
seen.set(item.typeString, item);
|
|
285
|
+
const namespace = item.typeString.split(':')[0];
|
|
286
|
+
let group = byNamespace.get(namespace);
|
|
287
|
+
if (!group) {
|
|
288
|
+
group = { namespace, actions: [], events: [] };
|
|
289
|
+
byNamespace.set(namespace, group);
|
|
290
|
+
}
|
|
291
|
+
if (item.kind === 'action') {
|
|
292
|
+
group.actions.push(item);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
group.events.push(item);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
const namespaces = Array.from(byNamespace.values()).sort((a, b) => a.namespace.localeCompare(b.namespace));
|
|
299
|
+
for (const ns of namespaces) {
|
|
300
|
+
ns.actions.sort((a, b) => a.typeString.localeCompare(b.typeString));
|
|
301
|
+
ns.events.sort((a, b) => a.typeString.localeCompare(b.typeString));
|
|
302
|
+
}
|
|
303
|
+
return namespaces;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Write generated docs (namespace pages, index page, sidebars) to disk,
|
|
307
|
+
* replacing any existing `docs/` directory.
|
|
308
|
+
*
|
|
309
|
+
* @param namespaces - The grouped namespaces to render.
|
|
310
|
+
* @param outputDir - The root output directory.
|
|
311
|
+
* @param repoBaseUrl - GitHub blob base URL for source links, or null.
|
|
312
|
+
* @param indexOptions - Options stamped on the index page header.
|
|
313
|
+
* @param indexOptions.projectLabel - Short label identifying the project.
|
|
314
|
+
* @param indexOptions.commitSha - Git commit SHA the docs were generated from.
|
|
315
|
+
* @returns Promise that resolves once all files are written.
|
|
316
|
+
*/
|
|
317
|
+
async function writeOutput(namespaces, outputDir, repoBaseUrl, indexOptions) {
|
|
318
|
+
const docsDir = path.join(outputDir, 'docs');
|
|
319
|
+
if (await (0, node_1.directoryExists)(docsDir)) {
|
|
320
|
+
await fs.rm(docsDir, { recursive: true });
|
|
321
|
+
}
|
|
322
|
+
await fs.mkdir(docsDir, { recursive: true });
|
|
323
|
+
for (const ns of namespaces) {
|
|
324
|
+
const nsDir = path.join(docsDir, ns.namespace);
|
|
325
|
+
await fs.mkdir(nsDir, { recursive: true });
|
|
326
|
+
if (ns.actions.length > 0) {
|
|
327
|
+
await fs.writeFile(path.join(nsDir, 'actions.md'), (0, markdown_1.generateNamespacePage)(ns, 'action', repoBaseUrl));
|
|
328
|
+
}
|
|
329
|
+
if (ns.events.length > 0) {
|
|
330
|
+
await fs.writeFile(path.join(nsDir, 'events.md'), (0, markdown_1.generateNamespacePage)(ns, 'event', repoBaseUrl));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
await fs.writeFile(path.join(docsDir, 'index.md'), (0, markdown_1.generateIndexPage)(namespaces, indexOptions));
|
|
334
|
+
await fs.writeFile(path.join(outputDir, 'sidebars.ts'), (0, markdown_1.generateSidebars)(namespaces));
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Scan a project for messenger action/event types and generate documentation.
|
|
338
|
+
*
|
|
339
|
+
* @param options - Generation options.
|
|
340
|
+
* @returns A promise resolving to counts of generated namespaces, actions, and events.
|
|
341
|
+
*/
|
|
342
|
+
async function generate(options) {
|
|
343
|
+
const { projectPath, outputDir, scanDirs, projectLabel, commitSha } = options;
|
|
344
|
+
const sources = await discoverScanSources(projectPath, scanDirs);
|
|
345
|
+
if (sources.scanDirs.length === 0 &&
|
|
346
|
+
!sources.packagesDir &&
|
|
347
|
+
!sources.nodeModulesDir) {
|
|
348
|
+
throw new Error(`No scannable directories found in ${projectPath}. ` +
|
|
349
|
+
`Looked for: ${scanDirs.join(', ')}, packages/, node_modules/@metamask/`);
|
|
350
|
+
}
|
|
351
|
+
logScanPlan(sources);
|
|
352
|
+
const allItems = await scanSources(projectPath, sources);
|
|
353
|
+
console.log(`Found ${allItems.length} messenger ${allItems.length === 1 ? 'item' : 'items'} total.`);
|
|
354
|
+
const namespaces = groupByNamespace(allItems);
|
|
355
|
+
const repoBaseUrl = await resolveRepoBaseUrl(projectPath);
|
|
356
|
+
await writeOutput(namespaces, outputDir, repoBaseUrl, {
|
|
357
|
+
projectLabel,
|
|
358
|
+
commitSha,
|
|
359
|
+
});
|
|
360
|
+
const totalActions = namespaces.reduce((sum, ns) => sum + ns.actions.length, 0);
|
|
361
|
+
const totalEvents = namespaces.reduce((sum, ns) => sum + ns.events.length, 0);
|
|
362
|
+
console.log(`Generated docs for ${namespaces.length} ${namespaces.length === 1 ? 'namespace' : 'namespaces'}.`);
|
|
363
|
+
console.log(` Actions: ${totalActions}`);
|
|
364
|
+
console.log(` Events: ${totalEvents}`);
|
|
365
|
+
console.log(`Output: ${path.join(outputDir, 'docs')}/`);
|
|
366
|
+
return {
|
|
367
|
+
namespaces: namespaces.length,
|
|
368
|
+
actions: totalActions,
|
|
369
|
+
events: totalEvents,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
exports.generate = generate;
|
|
373
|
+
//# sourceMappingURL=generate.cjs.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for the generate function.
|
|
3
|
+
*/
|
|
4
|
+
export type GenerateOptions = {
|
|
5
|
+
/** Absolute path to the project to scan. */
|
|
6
|
+
projectPath: string;
|
|
7
|
+
/** Absolute path to the output directory for generated docs. */
|
|
8
|
+
outputDir: string;
|
|
9
|
+
/** Directories (relative to projectPath) to scan for .ts source files. */
|
|
10
|
+
scanDirs: string[];
|
|
11
|
+
/**
|
|
12
|
+
* Short label identifying the project the docs were generated from (e.g.
|
|
13
|
+
* "Core", "Extension"). Stamped in the index page title.
|
|
14
|
+
*/
|
|
15
|
+
projectLabel?: string | null;
|
|
16
|
+
/**
|
|
17
|
+
* Git commit SHA the docs were generated from. Stamped in the index page
|
|
18
|
+
* intro so engineers know how current the site is.
|
|
19
|
+
*/
|
|
20
|
+
commitSha?: string | null;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Result returned by the generate function.
|
|
24
|
+
*/
|
|
25
|
+
export type GenerateResult = {
|
|
26
|
+
namespaces: number;
|
|
27
|
+
actions: number;
|
|
28
|
+
events: number;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Scan a project for messenger action/event types and generate documentation.
|
|
32
|
+
*
|
|
33
|
+
* @param options - Generation options.
|
|
34
|
+
* @returns A promise resolving to counts of generated namespaces, actions, and events.
|
|
35
|
+
*/
|
|
36
|
+
export declare function generate(options: GenerateOptions): Promise<GenerateResult>;
|
|
37
|
+
//# sourceMappingURL=generate.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.d.cts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAqGA;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAgWF;;;;;GAKG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CAiDzB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for the generate function.
|
|
3
|
+
*/
|
|
4
|
+
export type GenerateOptions = {
|
|
5
|
+
/** Absolute path to the project to scan. */
|
|
6
|
+
projectPath: string;
|
|
7
|
+
/** Absolute path to the output directory for generated docs. */
|
|
8
|
+
outputDir: string;
|
|
9
|
+
/** Directories (relative to projectPath) to scan for .ts source files. */
|
|
10
|
+
scanDirs: string[];
|
|
11
|
+
/**
|
|
12
|
+
* Short label identifying the project the docs were generated from (e.g.
|
|
13
|
+
* "Core", "Extension"). Stamped in the index page title.
|
|
14
|
+
*/
|
|
15
|
+
projectLabel?: string | null;
|
|
16
|
+
/**
|
|
17
|
+
* Git commit SHA the docs were generated from. Stamped in the index page
|
|
18
|
+
* intro so engineers know how current the site is.
|
|
19
|
+
*/
|
|
20
|
+
commitSha?: string | null;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Result returned by the generate function.
|
|
24
|
+
*/
|
|
25
|
+
export type GenerateResult = {
|
|
26
|
+
namespaces: number;
|
|
27
|
+
actions: number;
|
|
28
|
+
events: number;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Scan a project for messenger action/event types and generate documentation.
|
|
32
|
+
*
|
|
33
|
+
* @param options - Generation options.
|
|
34
|
+
* @returns A promise resolving to counts of generated namespaces, actions, and events.
|
|
35
|
+
*/
|
|
36
|
+
export declare function generate(options: GenerateOptions): Promise<GenerateResult>;
|
|
37
|
+
//# sourceMappingURL=generate.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.d.mts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAqGA;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAgWF;;;;;GAKG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CAiDzB"}
|