123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- /**
- * Obtained originally from {@link https://github.com/eslint/eslint/blob/master/lib/util/source-code.js#L313}.
- *
- * @license MIT
- */
-
- /**
- * Checks if the given token is a comment token or not.
- *
- * @param {Token} token - The token to check.
- * @returns {boolean} `true` if the token is a comment token.
- */
- const isCommentToken = (token) => {
- return token.type === 'Line' || token.type === 'Block' ||
- token.type === 'Shebang';
- };
-
- const getDecorator = (node) => {
- return node?.declaration?.decorators?.[0] || node?.decorators?.[0] ||
- node?.parent?.decorators?.[0];
- };
-
- /**
- * Check to see if its a ES6 export declaration.
- *
- * @param {ASTNode} astNode An AST node.
- * @returns {boolean} whether the given node represents an export declaration.
- * @private
- */
- const looksLikeExport = function (astNode) {
- return astNode.type === 'ExportDefaultDeclaration' ||
- astNode.type === 'ExportNamedDeclaration' ||
- astNode.type === 'ExportAllDeclaration' ||
- astNode.type === 'ExportSpecifier';
- };
-
- const getTSFunctionComment = function (astNode) {
- const {parent} = astNode;
- const grandparent = parent.parent;
- const greatGrandparent = grandparent.parent;
- const greatGreatGrandparent = greatGrandparent && greatGrandparent.parent;
-
- // istanbul ignore if
- if (parent.type !== 'TSTypeAnnotation') {
- return astNode;
- }
-
- switch (grandparent.type) {
- case 'ClassProperty':
- case 'TSDeclareFunction':
- case 'TSMethodSignature':
- case 'TSPropertySignature':
- return grandparent;
- case 'ArrowFunctionExpression':
- // istanbul ignore else
- if (
- greatGrandparent.type === 'VariableDeclarator'
-
- // && greatGreatGrandparent.parent.type === 'VariableDeclaration'
- ) {
- return greatGreatGrandparent.parent;
- }
-
- // istanbul ignore next
- return astNode;
- case 'FunctionExpression':
- // istanbul ignore else
- if (greatGrandparent.type === 'MethodDefinition') {
- return greatGrandparent;
- }
-
- // Fallthrough
- default:
- // istanbul ignore if
- if (grandparent.type !== 'Identifier') {
- // istanbul ignore next
- return astNode;
- }
- }
-
- // istanbul ignore next
- switch (greatGrandparent.type) {
- case 'ArrowFunctionExpression':
- // istanbul ignore else
- if (
- greatGreatGrandparent.type === 'VariableDeclarator' &&
- greatGreatGrandparent.parent.type === 'VariableDeclaration'
- ) {
- return greatGreatGrandparent.parent;
- }
-
- // istanbul ignore next
- return astNode;
- case 'FunctionDeclaration':
- return greatGrandparent;
- case 'VariableDeclarator':
- // istanbul ignore else
- if (greatGreatGrandparent.type === 'VariableDeclaration') {
- return greatGreatGrandparent;
- }
-
- // Fallthrough
- default:
- // istanbul ignore next
- return astNode;
- }
- };
-
- const invokedExpression = new Set(
- ['CallExpression', 'OptionalCallExpression', 'NewExpression']
- );
- const allowableCommentNode = new Set([
- 'VariableDeclaration',
- 'ExpressionStatement',
- 'MethodDefinition',
- 'Property',
- 'ObjectProperty',
- 'ClassProperty'
- ]);
-
- /**
- * Reduces the provided node to the appropriate node for evaluating
- * JSDoc comment status.
- *
- * @param {ASTNode} node An AST node.
- * @param {SourceCode} sourceCode The ESLint SourceCode.
- * @returns {ASTNode} The AST node that can be evaluated for appropriate
- * JSDoc comments.
- * @private
- */
- const getReducedASTNode = function (node, sourceCode) {
- let {parent} = node;
-
- switch (node.type) {
- case 'TSFunctionType':
- return getTSFunctionComment(node);
- case 'TSInterfaceDeclaration':
- case 'TSTypeAliasDeclaration':
- case 'TSEnumDeclaration':
- case 'ClassDeclaration':
- case 'FunctionDeclaration':
- return looksLikeExport(parent) ? parent : node;
-
- case 'TSDeclareFunction':
- case 'ClassExpression':
- case 'ObjectExpression':
- case 'ArrowFunctionExpression':
- case 'TSEmptyBodyFunctionExpression':
- case 'FunctionExpression':
- if (
- !invokedExpression.has(parent.type)
- ) {
- while (
- !sourceCode.getCommentsBefore(parent).length &&
- !(/Function/u).test(parent.type) &&
- !allowableCommentNode.has(parent.type)
- ) {
- ({parent} = parent);
-
- if (!parent) {
- break;
- }
- }
- if (parent && parent.type !== 'FunctionDeclaration' &&
- parent.type !== 'Program'
- ) {
- if (parent.parent && parent.parent.type === 'ExportNamedDeclaration') {
- return parent.parent;
- }
-
- return parent;
- }
- }
-
- return node;
-
- default:
- return node;
- }
- };
-
- /**
- * Checks for the presence of a JSDoc comment for the given node and returns it.
- *
- * @param {ASTNode} astNode The AST node to get the comment for.
- * @param {SourceCode} sourceCode
- * @param {{maxLines: Integer, minLines: Integer}} settings
- * @returns {Token|null} The Block comment token containing the JSDoc comment
- * for the given node or null if not found.
- * @private
- */
- const findJSDocComment = (astNode, sourceCode, settings) => {
- const {minLines, maxLines} = settings;
- let currentNode = astNode;
- let tokenBefore = null;
-
- while (currentNode) {
- const decorator = getDecorator(currentNode);
- if (decorator) {
- currentNode = decorator;
- }
- tokenBefore = sourceCode.getTokenBefore(
- currentNode, {includeComments: true}
- );
- if (!tokenBefore || !isCommentToken(tokenBefore)) {
- return null;
- }
- if (tokenBefore.type === 'Line') {
- currentNode = tokenBefore;
- continue;
- }
- break;
- }
-
- if (
- tokenBefore.type === 'Block' &&
- tokenBefore.value.charAt(0) === '*' &&
- currentNode.loc.start.line - tokenBefore.loc.end.line >= minLines &&
- currentNode.loc.start.line - tokenBefore.loc.end.line <= maxLines
- ) {
- return tokenBefore;
- }
-
- return null;
- };
-
- /**
- * Retrieves the JSDoc comment for a given node.
- *
- * @param {SourceCode} sourceCode The ESLint SourceCode
- * @param {ASTNode} node The AST node to get the comment for.
- * @param {PlainObject} settings The settings in context
- * @returns {Token|null} The Block comment token containing the JSDoc comment
- * for the given node or null if not found.
- * @public
- */
- const getJSDocComment = function (sourceCode, node, settings) {
- const reducedNode = getReducedASTNode(node, sourceCode);
-
- return findJSDocComment(reducedNode, sourceCode, settings);
- };
-
- export {
- getReducedASTNode, getJSDocComment, getDecorator, findJSDocComment
- };
|