UNPKG

typescript-eslint-language-service

Version:
189 lines 7.97 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ESLintAdapter = exports.translateToCodeFixesFromESLintResult = exports.isIntersect = exports.translateToDiagnosticsFromESLintResult = void 0; const path_1 = __importDefault(require("path")); const typescript_1 = __importDefault(require("typescript")); const eslint_1 = require("eslint"); const parser_1 = require("@typescript-eslint/parser"); const errors_1 = require("./errors"); const consts_1 = require("./consts"); function translateToDiagnosticsFromESLintResult(result, sourceFile) { return result.map(({ message, severity, ruleId, line, column, endLine, endColumn }) => { const messageText = `[${ruleId}] ${message}`; const category = severity === 2 ? typescript_1.default.DiagnosticCategory.Error : severity === 1 ? typescript_1.default.DiagnosticCategory.Warning : typescript_1.default.DiagnosticCategory.Suggestion; /** * ESLint uses 1-started index. On the other hand, TypeScript 0-started index. * So we should minus from ESLint result's row/column to create TypeScript position. */ const start = typescript_1.default.getPositionOfLineAndCharacter(sourceFile, line - 1, column - 1); const end = endLine && endColumn ? typescript_1.default.getPositionOfLineAndCharacter(sourceFile, endLine - 1, endColumn - 1) : start; const length = Math.max(0, end - start); const diagnostic = { file: sourceFile, category, code: consts_1.TS_LANGSERVICE_ESLINT_DIAGNOSTIC_ERROR_CODE, messageText, start, length, }; return diagnostic; }); } exports.translateToDiagnosticsFromESLintResult = translateToDiagnosticsFromESLintResult; function isIntersect(message, range, sourceFile) { const { line, column, endLine, endColumn } = message; const mStart = typescript_1.default.getPositionOfLineAndCharacter(sourceFile, line - 1, column - 1); const mEnd = endLine && endColumn ? typescript_1.default.getPositionOfLineAndCharacter(sourceFile, endLine - 1, endColumn - 1) : mStart; return !(mEnd < range.start || mStart > range.end); } exports.isIntersect = isIntersect; function translateToCodeFixesFromESLintResult(result, fileName) { return result.reduce((acc, { message, ruleId, fix }) => { if (!fix) { return acc; } const rid = ruleId || "eslint"; const rangeStart = fix.range[0]; const rangeLength = fix.range[1] ? fix.range[1] - fix.range[0] : 0; const codeFixAction = { description: `Fix: ${message}`, fixId: rid, fixName: rid, changes: [ { fileName, isNewFile: false, textChanges: [ { span: { start: rangeStart, length: rangeLength, }, newText: fix.text, }, ], }, ], }; return [...acc, codeFixAction]; }, []); } exports.translateToCodeFixesFromESLintResult = translateToCodeFixesFromESLintResult; class ESLintAdapter { constructor({ logger, configProvider, getSourceFile }) { this.linter = new eslint_1.Linter(); this.logger = logger; this.configProvider = configProvider; this.getSourceFile = getSourceFile; this.ignoredFilepathMap = new Map(); } convertToESLintSourceCode(src, filename, options) { const code = src.getFullText(); const originalOpt = options !== null && options !== void 0 ? options : {}; const { ast, scopeManager, services, visitorKeys } = (0, parser_1.parseForESLint)(code, { ...originalOpt, filePath: filename, comment: true, loc: true, range: true, tokens: true, warnOnUnsupportedTypeScriptVersion: false, }); const source = new eslint_1.SourceCode({ text: code, ast, scopeManager, parserServices: services, visitorKeys, }); return source; } getESLintResult(fileName, sourceFile) { if (this.ignoredFilepathMap.get(fileName) === true) return []; const configArray = this.configProvider.getConfigArrayForFile(fileName); const configFileContent = configArray.extractConfig(fileName).toCompatibleObjectAsConfigFileContent(); if (!isParserModuleNameValid(configFileContent.parser, path_1.default.join("@typescript-eslint", "parser"))) { throw new errors_1.InvalidParserError(); } const parserOptions = (configFileContent.parserOptions ? configFileContent.parserOptions : {}); const sourceCode = this.convertToESLintSourceCode(sourceFile, fileName, parserOptions); // See https://github.com/eslint/eslint/blob/v6.1.0/lib/linter/linter.js#L1130 return this.linter.verify(sourceCode, configArray, { filename: fileName }); } checkFileToBeIgnored(fileName) { if (fileName.indexOf("node_modules" + path_1.default.sep) !== -1) return; if (!fileName.endsWith(".ts") && !fileName.endsWith(".tsx")) return; Promise.resolve() .then(() => new eslint_1.ESLint()) .then(eslint => eslint.isPathIgnored(fileName)) .then(result => this.ignoredFilepathMap.set(fileName, result)); } getSemanticDiagnostics(delegate, fileName) { const original = delegate(fileName); try { const sourceFile = this.getSourceFile(fileName); if (!sourceFile) { return original; } const eslintResult = this.getESLintResult(fileName, sourceFile); return [...original, ...translateToDiagnosticsFromESLintResult(eslintResult, sourceFile)]; } catch (error) { if (error instanceof Error) { this.logger(error.message); if (error.stack) { this.logger(error.stack); } } else { this.logger(`${error}`); } return original; } } getCodeFixesAtPosition(delegate, fileName, start, end, errorCodes, formatOptions, preferences) { const original = delegate(fileName, start, end, errorCodes, formatOptions, preferences); try { if (!errorCodes.includes(consts_1.TS_LANGSERVICE_ESLINT_DIAGNOSTIC_ERROR_CODE)) { return original; } const sourceFile = this.getSourceFile(fileName); if (!sourceFile) { return original; } const eslintResult = this.getESLintResult(fileName, sourceFile); return [ ...original, ...translateToCodeFixesFromESLintResult(eslintResult.filter(r => isIntersect(r, { start, end }, sourceFile)), fileName), ]; } catch (error) { this.logger(error.message ? error.message : "unknow error"); return original; } return original; } } exports.ESLintAdapter = ESLintAdapter; function isParserModuleNameValid(parserModuleSpecifier, parserModuleName) { if (!parserModuleSpecifier) return false; try { const p = require.resolve(parserModuleSpecifier); return p.indexOf(parserModuleName) !== -1; } catch (e) { return false; } } //# sourceMappingURL=eslint-adapter.js.map