{"version":3,"file":"ExcerptBuilder.js","sourceRoot":"","sources":["../../src/generators/ExcerptBuilder.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as ts from 'typescript';\nimport type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference';\nimport {\n ExcerptTokenKind,\n type IExcerptToken,\n type IExcerptTokenRange\n} from '@microsoft/api-extractor-model';\n\nimport { Span } from '../analyzer/Span';\nimport type { DeclarationReferenceGenerator } from './DeclarationReferenceGenerator';\nimport type { AstDeclaration } from '../analyzer/AstDeclaration';\n\n/**\n * Used to provide ExcerptBuilder with a list of nodes whose token range we want to capture.\n */\nexport interface IExcerptBuilderNodeToCapture {\n /**\n * The node to capture\n */\n node: ts.Node | undefined;\n /**\n * The token range whose startIndex/endIndex will be overwritten with the indexes for the\n * tokens corresponding to IExcerptBuilderNodeToCapture.node\n */\n tokenRange: IExcerptTokenRange;\n}\n\n/**\n * Internal state for ExcerptBuilder\n */\ninterface IBuildSpanState {\n referenceGenerator: DeclarationReferenceGenerator;\n\n /**\n * The AST node that we will traverse to extract tokens\n */\n startingNode: ts.Node;\n\n /**\n * Normally, the excerpt will include all child nodes for `startingNode`; whereas if `childKindToStopBefore`\n * is specified, then the node traversal will stop before (i.e. excluding) the first immediate child\n * of `startingNode` with the specified syntax kind.\n *\n * @remarks\n * For example, suppose the signature is `interface X: Y { z: string }`. The token `{` has syntax kind\n * `ts.SyntaxKind.FirstPunctuation`, so we can specify that to truncate the excerpt to `interface X: Y`.\n */\n stopBeforeChildKind: ts.SyntaxKind | undefined;\n\n tokenRangesByNode: Map;\n\n /**\n * Tracks whether the last appended token was a separator. If so, and we're in the middle of\n * capturing a token range, then omit the separator from the range.\n */\n lastAppendedTokenIsSeparator: boolean;\n}\n\nexport class ExcerptBuilder {\n /**\n * Appends a blank line to the `excerptTokens` list.\n * @param excerptTokens - The target token list to append to\n */\n public static addBlankLine(excerptTokens: IExcerptToken[]): void {\n let newlines: string = '\\n\\n';\n // If the existing text already ended with a newline, then only append one newline\n if (excerptTokens.length > 0) {\n const previousText: string = excerptTokens[excerptTokens.length - 1].text;\n if (/\\n$/.test(previousText)) {\n newlines = '\\n';\n }\n }\n excerptTokens.push({ kind: ExcerptTokenKind.Content, text: newlines });\n }\n\n /**\n * Appends the signature for the specified `AstDeclaration` to the `excerptTokens` list.\n * @param excerptTokens - The target token list to append to\n * @param nodesToCapture - A list of child nodes whose token ranges we want to capture\n */\n public static addDeclaration(\n excerptTokens: IExcerptToken[],\n astDeclaration: AstDeclaration,\n nodesToCapture: IExcerptBuilderNodeToCapture[],\n referenceGenerator: DeclarationReferenceGenerator\n ): void {\n let stopBeforeChildKind: ts.SyntaxKind | undefined = undefined;\n\n switch (astDeclaration.declaration.kind) {\n case ts.SyntaxKind.ClassDeclaration:\n case ts.SyntaxKind.EnumDeclaration:\n case ts.SyntaxKind.InterfaceDeclaration:\n // FirstPunctuation = \"{\"\n stopBeforeChildKind = ts.SyntaxKind.FirstPunctuation;\n break;\n case ts.SyntaxKind.ModuleDeclaration:\n // ModuleBlock = the \"{ ... }\" block\n stopBeforeChildKind = ts.SyntaxKind.ModuleBlock;\n break;\n }\n\n const span: Span = new Span(astDeclaration.declaration);\n\n const tokenRangesByNode: Map = new Map();\n for (const excerpt of nodesToCapture || []) {\n if (excerpt.node) {\n tokenRangesByNode.set(excerpt.node, excerpt.tokenRange);\n }\n }\n\n ExcerptBuilder._buildSpan(excerptTokens, span, {\n referenceGenerator: referenceGenerator,\n startingNode: span.node,\n stopBeforeChildKind,\n tokenRangesByNode,\n lastAppendedTokenIsSeparator: false\n });\n ExcerptBuilder._condenseTokens(excerptTokens, [...tokenRangesByNode.values()]);\n }\n\n public static createEmptyTokenRange(): IExcerptTokenRange {\n return { startIndex: 0, endIndex: 0 };\n }\n\n private static _buildSpan(excerptTokens: IExcerptToken[], span: Span, state: IBuildSpanState): boolean {\n if (span.kind === ts.SyntaxKind.JSDocComment) {\n // Discard any comments\n return true;\n }\n\n // Can this node start a excerpt?\n const capturedTokenRange: IExcerptTokenRange | undefined = state.tokenRangesByNode.get(span.node);\n let excerptStartIndex: number = 0;\n\n if (capturedTokenRange) {\n // We will assign capturedTokenRange.startIndex to be the index of the next token to be appended\n excerptStartIndex = excerptTokens.length;\n }\n\n if (span.prefix) {\n let canonicalReference: DeclarationReference | undefined = undefined;\n\n if (span.kind === ts.SyntaxKind.Identifier) {\n const name: ts.Identifier = span.node as ts.Identifier;\n if (!ExcerptBuilder._isDeclarationName(name)) {\n canonicalReference = state.referenceGenerator.getDeclarationReferenceForIdentifier(name);\n }\n }\n\n if (canonicalReference) {\n ExcerptBuilder._appendToken(\n excerptTokens,\n ExcerptTokenKind.Reference,\n span.prefix,\n canonicalReference\n );\n } else {\n ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, span.prefix);\n }\n state.lastAppendedTokenIsSeparator = false;\n }\n\n for (const child of span.children) {\n if (span.node === state.startingNode) {\n if (state.stopBeforeChildKind && child.kind === state.stopBeforeChildKind) {\n // We reached a child whose kind is stopBeforeChildKind, so stop traversing\n return false;\n }\n }\n\n if (!this._buildSpan(excerptTokens, child, state)) {\n return false;\n }\n }\n\n if (span.suffix) {\n ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, span.suffix);\n state.lastAppendedTokenIsSeparator = false;\n }\n if (span.separator) {\n ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, span.separator);\n state.lastAppendedTokenIsSeparator = true;\n }\n\n // Are we building a excerpt? If so, set its range\n if (capturedTokenRange) {\n capturedTokenRange.startIndex = excerptStartIndex;\n\n // We will assign capturedTokenRange.startIndex to be the index after the last token\n // that was appended so far. However, if the last appended token was a separator, omit\n // it from the range.\n let excerptEndIndex: number = excerptTokens.length;\n if (state.lastAppendedTokenIsSeparator) {\n excerptEndIndex--;\n }\n\n capturedTokenRange.endIndex = excerptEndIndex;\n }\n\n return true;\n }\n\n private static _appendToken(\n excerptTokens: IExcerptToken[],\n excerptTokenKind: ExcerptTokenKind,\n text: string,\n canonicalReference?: DeclarationReference\n ): void {\n if (text.length === 0) {\n return;\n }\n\n const excerptToken: IExcerptToken = { kind: excerptTokenKind, text: text };\n if (canonicalReference !== undefined) {\n excerptToken.canonicalReference = canonicalReference.toString();\n }\n excerptTokens.push(excerptToken);\n }\n\n /**\n * Condenses the provided excerpt tokens by merging tokens where possible. Updates the provided token ranges to\n * remain accurate after token merging.\n *\n * @remarks\n * For example, suppose we have excerpt tokens [\"A\", \"B\", \"C\"] and a token range [0, 2]. If the excerpt tokens\n * are condensed to [\"AB\", \"C\"], then the token range would be updated to [0, 1]. Note that merges are only\n * performed if they are compatible with the provided token ranges. In the example above, if our token range was\n * originally [0, 1], we would not be able to merge tokens \"A\" and \"B\".\n */\n private static _condenseTokens(excerptTokens: IExcerptToken[], tokenRanges: IExcerptTokenRange[]): void {\n // This set is used to quickly lookup a start or end index.\n const startOrEndIndices: Set = new Set();\n for (const tokenRange of tokenRanges) {\n startOrEndIndices.add(tokenRange.startIndex);\n startOrEndIndices.add(tokenRange.endIndex);\n }\n\n for (let currentIndex: number = 1; currentIndex < excerptTokens.length; ++currentIndex) {\n while (currentIndex < excerptTokens.length) {\n const prevPrevToken: IExcerptToken = excerptTokens[currentIndex - 2]; // May be undefined\n const prevToken: IExcerptToken = excerptTokens[currentIndex - 1];\n const currentToken: IExcerptToken = excerptTokens[currentIndex];\n\n // The number of excerpt tokens that are merged in this iteration. We need this to determine\n // how to update the start and end indices of our token ranges.\n let mergeCount: number;\n\n // There are two types of merges that can occur. We only perform these merges if they are\n // compatible with all of our token ranges.\n if (\n prevPrevToken &&\n prevPrevToken.kind === ExcerptTokenKind.Reference &&\n prevToken.kind === ExcerptTokenKind.Content &&\n prevToken.text.trim() === '.' &&\n currentToken.kind === ExcerptTokenKind.Reference &&\n !startOrEndIndices.has(currentIndex) &&\n !startOrEndIndices.has(currentIndex - 1)\n ) {\n // If the current token is a reference token, the previous token is a \".\", and the previous-\n // previous token is a reference token, then merge all three tokens into a reference token.\n //\n // For example: Given [\"MyNamespace\" (R), \".\", \"MyClass\" (R)], tokens \".\" and \"MyClass\" might\n // be merged into \"MyNamespace\". The condensed token would be [\"MyNamespace.MyClass\" (R)].\n prevPrevToken.text += prevToken.text + currentToken.text;\n prevPrevToken.canonicalReference = currentToken.canonicalReference;\n mergeCount = 2;\n currentIndex--;\n } else if (\n // If the current and previous tokens are both content tokens, then merge the tokens into a\n // single content token. For example: Given [\"export \", \"declare class\"], these tokens\n // might be merged into \"export declare class\".\n prevToken.kind === ExcerptTokenKind.Content &&\n prevToken.kind === currentToken.kind &&\n !startOrEndIndices.has(currentIndex)\n ) {\n prevToken.text += currentToken.text;\n mergeCount = 1;\n } else {\n // Otherwise, no merging can occur here. Continue to the next index.\n break;\n }\n\n // Remove the now redundant excerpt token(s), as they were merged into a previous token.\n excerptTokens.splice(currentIndex, mergeCount);\n\n // Update the start and end indices for all token ranges based upon how many excerpt\n // tokens were merged and in what positions.\n for (const tokenRange of tokenRanges) {\n if (tokenRange.startIndex > currentIndex) {\n tokenRange.startIndex -= mergeCount;\n }\n\n if (tokenRange.endIndex > currentIndex) {\n tokenRange.endIndex -= mergeCount;\n }\n }\n\n // Clear and repopulate our set with the updated indices.\n startOrEndIndices.clear();\n for (const tokenRange of tokenRanges) {\n startOrEndIndices.add(tokenRange.startIndex);\n startOrEndIndices.add(tokenRange.endIndex);\n }\n }\n }\n }\n\n private static _isDeclarationName(name: ts.Identifier): boolean {\n return ExcerptBuilder._isDeclaration(name.parent) && name.parent.name === name;\n }\n\n private static _isDeclaration(node: ts.Node): node is ts.NamedDeclaration {\n switch (node.kind) {\n case ts.SyntaxKind.FunctionDeclaration:\n case ts.SyntaxKind.FunctionExpression:\n case ts.SyntaxKind.VariableDeclaration:\n case ts.SyntaxKind.Parameter:\n case ts.SyntaxKind.EnumDeclaration:\n case ts.SyntaxKind.ClassDeclaration:\n case ts.SyntaxKind.ClassExpression:\n case ts.SyntaxKind.ModuleDeclaration:\n case ts.SyntaxKind.MethodDeclaration:\n case ts.SyntaxKind.MethodSignature:\n case ts.SyntaxKind.PropertyDeclaration:\n case ts.SyntaxKind.PropertySignature:\n case ts.SyntaxKind.GetAccessor:\n case ts.SyntaxKind.SetAccessor:\n case ts.SyntaxKind.InterfaceDeclaration:\n case ts.SyntaxKind.TypeAliasDeclaration:\n case ts.SyntaxKind.TypeParameter:\n case ts.SyntaxKind.EnumMember:\n case ts.SyntaxKind.BindingElement:\n return true;\n default:\n return false;\n }\n }\n}\n"]}