UNPKG

eslint-plugin-tsdoc

Version:

An ESLint plugin that validates TypeScript doc comments

137 lines 6.94 kB
"use strict"; // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. const utils_1 = require("@typescript-eslint/utils"); const tsdoc_1 = require("@microsoft/tsdoc"); const Debug_1 = require("./Debug"); const ConfigCache_1 = require("./ConfigCache"); const tsdocMessageIds = {}; const defaultTSDocConfiguration = new tsdoc_1.TSDocConfiguration(); defaultTSDocConfiguration.allTsdocMessageIds.forEach((messageId) => { tsdocMessageIds[messageId] = `${messageId}: {{unformattedText}}`; }); function getRootDirectoryFromContext(context) { var _a, _b, _c, _d, _e, _f, _g; let rootDirectory; try { // First attempt to get the root directory from the tsconfig baseUrl, then the program current directory // eslint-disable-next-line @typescript-eslint/no-explicit-any const program = ((_b = (_a = context.sourceCode) === null || _a === void 0 ? void 0 : _a.parserServices) !== null && _b !== void 0 ? _b : utils_1.ESLintUtils.getParserServices(context)) .program; rootDirectory = (_c = program === null || program === void 0 ? void 0 : program.getCompilerOptions().baseUrl) !== null && _c !== void 0 ? _c : program === null || program === void 0 ? void 0 : program.getCurrentDirectory(); } catch (_h) { // Ignore the error if we cannot retrieve a TS program } // Fall back to the parserOptions.tsconfigRootDir if available, otherwise the eslint working directory if (!rootDirectory) { rootDirectory = (_f = (_e = (_d = context.parserOptions) === null || _d === void 0 ? void 0 : _d.tsconfigRootDir) !== null && _e !== void 0 ? _e : context.cwd) !== null && _f !== void 0 ? _f : (_g = context.getCwd) === null || _g === void 0 ? void 0 : _g.call(context); } return rootDirectory; } const plugin = { rules: { // NOTE: The actual ESLint rule name will be "tsdoc/syntax". It is calculated by deleting "eslint-plugin-" // from the NPM package name, and then appending this string. syntax: { meta: { messages: { 'error-loading-config-file': 'Error loading TSDoc config file:\n{{details}}', 'error-applying-config': 'Error applying TSDoc configuration: {{details}}', ...tsdocMessageIds }, type: 'problem', docs: { description: 'Validates that TypeScript documentation comments conform to the TSDoc standard', category: 'Stylistic Issues', // This package is experimental recommended: false, url: 'https://tsdoc.org/pages/packages/eslint-plugin-tsdoc' } }, create: (context) => { var _a; const sourceFilePath = context.filename; // If eslint is configured with @typescript-eslint/parser, there is a parser option // to explicitly specify where the tsconfig file is. Use that if available. const tsConfigDir = getRootDirectoryFromContext(context); Debug_1.Debug.log(`Linting: "${sourceFilePath}"`); const tsdocConfiguration = new tsdoc_1.TSDocConfiguration(); try { const tsdocConfigFile = ConfigCache_1.ConfigCache.getForSourceFile(sourceFilePath, tsConfigDir); if (!tsdocConfigFile.fileNotFound) { if (tsdocConfigFile.hasErrors) { context.report({ loc: { line: 1, column: 1 }, messageId: 'error-loading-config-file', data: { details: tsdocConfigFile.getErrorSummary() } }); } try { tsdocConfigFile.configureParser(tsdocConfiguration); } catch (e) { context.report({ loc: { line: 1, column: 1 }, messageId: 'error-applying-config', data: { details: e.message } }); } } } catch (e) { context.report({ loc: { line: 1, column: 1 }, messageId: 'error-loading-config-file', data: { details: `Unexpected exception: ${e.message}` } }); } const tsdocParser = new tsdoc_1.TSDocParser(tsdocConfiguration); const sourceCode = (_a = context.sourceCode) !== null && _a !== void 0 ? _a : context.getSourceCode(); function checkCommentBlocks() { for (const comment of sourceCode.getAllComments()) { if (comment.type !== 'Block') { continue; } if (!comment.range) { continue; } const textRange = tsdoc_1.TextRange.fromStringRange(sourceCode.text, comment.range[0], comment.range[1]); // Smallest comment is "/***/" if (textRange.length < 5) { continue; } // Make sure it starts with "/**" if (textRange.buffer[textRange.pos + 2] !== '*') { continue; } const parserContext = tsdocParser.parseRange(textRange); for (const message of parserContext.log.messages) { context.report({ loc: { start: sourceCode.getLocFromIndex(message.textRange.pos), end: sourceCode.getLocFromIndex(message.textRange.end) }, messageId: message.messageId, data: { unformattedText: message.unformattedText } }); } } } return { Program: checkCommentBlocks }; } } } }; module.exports = plugin; //# sourceMappingURL=index.js.map