diff --git a/lib/helpers.js b/lib/helpers.js
index 39aec3ad..f82ca0f7 100644
--- a/lib/helpers.js
+++ b/lib/helpers.js
@@ -4,10 +4,164 @@
Object.defineProperty(exports, "__esModule", {
value: true
});
+exports.processESLintMessages = exports.generateDebugString = exports.getDebugInfo = undefined;
+
+var getDebugInfo = exports.getDebugInfo = function () {
+ var _ref = _asyncToGenerator(function* (worker) {
+ var textEditor = atom.workspace.getActiveTextEditor();
+ var filePath = textEditor.getPath();
+ var packagePath = atom.packages.resolvePackagePath('linter-eslint');
+ // eslint-disable-next-line import/no-dynamic-require
+ var linterEslintMeta = require((0, _path.join)(packagePath, 'package.json'));
+ var config = atom.config.get('linter-eslint');
+ var hoursSinceRestart = Math.round(process.uptime() / 3600 * 10) / 10;
+ var returnVal = void 0;
+ try {
+ var response = yield worker.request('job', {
+ type: 'debug',
+ config: config,
+ filePath: filePath
+ });
+ returnVal = {
+ atomVersion: atom.getVersion(),
+ linterEslintVersion: linterEslintMeta.version,
+ linterEslintConfig: config,
+ // eslint-disable-next-line import/no-dynamic-require
+ eslintVersion: require((0, _path.join)(response.path, 'package.json')).version,
+ hoursSinceRestart: hoursSinceRestart,
+ platform: process.platform,
+ eslintType: response.type,
+ eslintPath: response.path
+ };
+ } catch (error) {
+ atom.notifications.addError('' + error);
+ }
+ return returnVal;
+ });
+
+ return function getDebugInfo(_x3) {
+ return _ref.apply(this, arguments);
+ };
+}();
+
+var generateDebugString = exports.generateDebugString = function () {
+ var _ref2 = _asyncToGenerator(function* (worker) {
+ var debug = yield getDebugInfo(worker);
+ var details = ['Atom version: ' + debug.atomVersion, 'linter-eslint version: ' + debug.linterEslintVersion, 'ESLint version: ' + debug.eslintVersion, 'Hours since last Atom restart: ' + debug.hoursSinceRestart, 'Platform: ' + debug.platform, 'Using ' + debug.eslintType + ' ESLint from ' + debug.eslintPath, 'linter-eslint configuration: ' + JSON.stringify(debug.linterEslintConfig, null, 2)];
+ return details.join('\n');
+ });
+
+ return function generateDebugString(_x4) {
+ return _ref2.apply(this, arguments);
+ };
+}();
+
+/**
+ * Given a raw response from ESLint, this processes the messages into a format
+ * compatible with the Linter API.
+ * @param {Object} response The raw response from ESLint
+ * @param {TextEditor} textEditor The Atom::TextEditor of the file the messages belong to
+ * @param {bool} showRule Whether to show the rule in the messages
+ * @param {Object} worker The current Worker process to send Debug jobs to
+ * @return {Promise} The messages transformed into Linter messages
+ */
+var processESLintMessages = exports.processESLintMessages = function () {
+ var _ref4 = _asyncToGenerator(function* (response, textEditor, showRule, worker) {
+ return Promise.all(response.map(function () {
+ var _ref5 = _asyncToGenerator(function* (_ref6) {
+ var message = _ref6.message,
+ line = _ref6.line,
+ severity = _ref6.severity,
+ ruleId = _ref6.ruleId,
+ column = _ref6.column,
+ fix = _ref6.fix,
+ endLine = _ref6.endLine,
+ endColumn = _ref6.endColumn;
+
+ var filePath = textEditor.getPath();
+ var textBuffer = textEditor.getBuffer();
+ var linterFix = null;
+ if (fix) {
+ var fixRange = new _atom.Range(textBuffer.positionForCharacterIndex(fix.range[0]), textBuffer.positionForCharacterIndex(fix.range[1]));
+ linterFix = {
+ range: fixRange,
+ newText: fix.text
+ };
+ }
+ var msgCol = void 0;
+ var msgEndLine = void 0;
+ var msgEndCol = void 0;
+ var eslintFullRange = false;
+
+ /*
+ Note: ESLint positions are 1-indexed, while Atom expects 0-indexed,
+ positions. We are subtracting 1 from these values here so we don't have to
+ keep doing so in later uses.
+ */
+ var msgLine = line - 1;
+ if (typeof endColumn !== 'undefined' && typeof endLine !== 'undefined') {
+ eslintFullRange = true;
+ // Here we always want the column to be a number
+ msgCol = Math.max(0, column - 1);
+ msgEndLine = endLine - 1;
+ msgEndCol = endColumn - 1;
+ } else {
+ // We want msgCol to remain undefined if it was initially so
+ // `rangeFromLineNumber` will give us a range over the entire line
+ msgCol = typeof column !== 'undefined' ? column - 1 : column;
+ }
+
+ var ret = void 0;
+ var range = void 0;
+ try {
+ if (eslintFullRange) {
+ validatePoint(textEditor, msgLine, msgCol);
+ validatePoint(textEditor, msgEndLine, msgEndCol);
+ range = [[msgLine, msgCol], [msgEndLine, msgEndCol]];
+ } else {
+ range = (0, _atomLinter.rangeFromLineNumber)(textEditor, msgLine, msgCol);
+ }
+ ret = {
+ filePath: filePath,
+ type: severity === 1 ? 'Warning' : 'Error',
+ range: range
+ };
+
+ if (showRule) {
+ var elName = ruleId ? 'a' : 'span';
+ var href = ruleId ? ' href=' + (0, _eslintRuleDocumentation2.default)(ruleId).url : '';
+ ret.html = '<' + elName + href + ' class="badge badge-flexible eslint">' + ((ruleId || 'Fatal') + '' + elName + '> ' + (0, _escapeHtml2.default)(message));
+ } else {
+ ret.text = message;
+ }
+ if (linterFix) {
+ ret.fix = linterFix;
+ }
+ } catch (err) {
+ if (!err.message.startsWith('Line number ') && !err.message.startsWith('Column start ')) {
+ // This isn't an invalid point error from `rangeFromLineNumber`, re-throw it
+ throw err;
+ }
+ ret = yield generateInvalidTrace(msgLine, msgCol, msgEndLine, msgEndCol, eslintFullRange, filePath, textEditor, ruleId, message, worker);
+ }
+
+ return ret;
+ });
+
+ return function (_x19) {
+ return _ref5.apply(this, arguments);
+ };
+ }()));
+ });
+
+ return function processESLintMessages(_x15, _x16, _x17, _x18) {
+ return _ref4.apply(this, arguments);
+ };
+}();
+
exports.spawnWorker = spawnWorker;
exports.showError = showError;
exports.idsToIgnoredRules = idsToIgnoredRules;
-exports.validatePoint = validatePoint;
var _child_process = require('child_process');
@@ -17,13 +171,27 @@ var _processCommunication = require('process-communication');
var _path = require('path');
+var _escapeHtml = require('escape-html');
+
+var _escapeHtml2 = _interopRequireDefault(_escapeHtml);
+
+var _eslintRuleDocumentation = require('eslint-rule-documentation');
+
+var _eslintRuleDocumentation2 = _interopRequireDefault(_eslintRuleDocumentation);
+
+var _atomLinter = require('atom-linter');
+
var _atom = require('atom');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-var RULE_OFF_SEVERITY = 0;
+function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
// eslint-disable-next-line import/no-extraneous-dependencies, import/extensions
+
+
+var RULE_OFF_SEVERITY = 0;
+
function spawnWorker() {
var env = Object.create(process.env);
@@ -83,3 +251,40 @@ function validatePoint(textEditor, line, col) {
throw new Error(line + ':' + col + ' isn\'t a valid point!');
}
}
+
+var generateInvalidTrace = function () {
+ var _ref3 = _asyncToGenerator(function* (msgLine, msgCol, msgEndLine, msgEndCol, eslintFullRange, filePath, textEditor, ruleId, message, worker) {
+ var errMsgRange = msgLine + 1 + ':' + msgCol;
+ if (eslintFullRange) {
+ errMsgRange += ' - ' + (msgEndLine + 1) + ':' + (msgEndCol + 1);
+ }
+ var rangeText = 'Requested ' + (eslintFullRange ? 'start point' : 'range') + ': ' + errMsgRange;
+ var issueURL = 'https://github.com/AtomLinter/linter-eslint/issues/new';
+ var titleText = 'Invalid position given by \'' + ruleId + '\'';
+ var title = encodeURIComponent(titleText);
+ var body = encodeURIComponent(['ESLint returned a point that did not exist in the document being edited.', 'Rule: `' + ruleId + '`', rangeText, '', '', '', '', '', 'Debug information:', '```json', JSON.stringify((yield getDebugInfo(worker)), null, 2), '```'].join('\n'));
+ var newIssueURL = issueURL + '?title=' + title + '&body=' + body;
+ return {
+ type: 'Error',
+ severity: 'error',
+ html: (0, _escapeHtml2.default)(titleText) + '. See the trace for details. ' + ('Report this!'),
+ filePath: filePath,
+ range: (0, _atomLinter.rangeFromLineNumber)(textEditor, 0),
+ trace: [{
+ type: 'Trace',
+ text: 'Original message: ' + ruleId + ' - ' + message,
+ filePath: filePath,
+ severity: 'info'
+ }, {
+ type: 'Trace',
+ text: rangeText,
+ filePath: filePath,
+ severity: 'info'
+ }]
+ };
+ });
+
+ return function generateInvalidTrace(_x5, _x6, _x7, _x8, _x9, _x10, _x11, _x12, _x13, _x14) {
+ return _ref3.apply(this, arguments);
+ };
+}();
diff --git a/lib/main.js b/lib/main.js
index cd4c98e4..afb38494 100644
--- a/lib/main.js
+++ b/lib/main.js
@@ -1,28 +1,15 @@
'use strict';
'use babel';
-var _path = require('path');
-
-var _path2 = _interopRequireDefault(_path);
-
-var _escapeHtml = require('escape-html');
-
-var _escapeHtml2 = _interopRequireDefault(_escapeHtml);
-
-var _eslintRuleDocumentation = require('eslint-rule-documentation');
-
-var _eslintRuleDocumentation2 = _interopRequireDefault(_eslintRuleDocumentation);
+// eslint-disable-next-line import/no-extraneous-dependencies, import/extensions
var _atom = require('atom');
var _helpers = require('./helpers');
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
// Configuration
-
-
-// eslint-disable-next-line import/no-extraneous-dependencies, import/extensions
var scopes = [];
var showRule = void 0;
var ignoredRulesWhenModified = void 0;
@@ -72,28 +59,17 @@ module.exports = {
}));
this.subscriptions.add(atom.commands.add('atom-text-editor', {
- 'linter-eslint:debug': function linterEslintDebug() {
- var textEditor = atom.workspace.getActiveTextEditor();
- var filePath = textEditor.getPath();
- // eslint-disable-next-line import/no-dynamic-require
- var linterEslintMeta = require(_path2.default.join(atom.packages.resolvePackagePath('linter-eslint'), 'package.json'));
- var config = atom.config.get('linter-eslint');
- var configString = JSON.stringify(config, null, 2);
- var hoursSinceRestart = process.uptime() / 3600;
- _this.worker.request('job', {
- type: 'debug',
- config: config,
- filePath: filePath
- }).then(function (response) {
- var detail = ['atom version: ' + atom.getVersion(), 'linter-eslint version: ' + linterEslintMeta.version,
- // eslint-disable-next-line import/no-dynamic-require
- 'eslint version: ' + require(_path2.default.join(response.path, 'package.json')).version, 'hours since last atom restart: ' + Math.round(hoursSinceRestart * 10) / 10, 'platform: ' + process.platform, 'Using ' + response.type + ' eslint from ' + response.path, 'linter-eslint configuration: ' + configString].join('\n');
- var notificationOptions = { detail: detail, dismissable: true };
+ 'linter-eslint:debug': function () {
+ var _ref = _asyncToGenerator(function* () {
+ var debugString = yield (0, _helpers.generateDebugString)(_this.worker);
+ var notificationOptions = { detail: debugString, dismissable: true };
atom.notifications.addInfo('linter-eslint debugging information', notificationOptions);
- }).catch(function (response) {
- atom.notifications.addError('' + response);
});
- }
+
+ return function linterEslintDebug() {
+ return _ref.apply(this, arguments);
+ };
+ }()
}));
this.subscriptions.add(atom.commands.add('atom-text-editor', {
@@ -130,10 +106,9 @@ module.exports = {
}));
var initializeWorker = function initializeWorker() {
- var _spawnWorker = (0, _helpers.spawnWorker)();
-
- var worker = _spawnWorker.worker;
- var subscription = _spawnWorker.subscription;
+ var _spawnWorker = (0, _helpers.spawnWorker)(),
+ worker = _spawnWorker.worker,
+ subscription = _spawnWorker.subscription;
_this.worker = worker;
_this.subscriptions.add(subscription);
@@ -153,8 +128,6 @@ module.exports = {
provideLinter: function provideLinter() {
var _this2 = this;
- var Helpers = require('atom-linter');
-
return {
name: 'ESLint',
grammarScopes: scopes,
@@ -189,62 +162,7 @@ module.exports = {
*/
return null;
}
- return response.map(function (_ref) {
- var message = _ref.message;
- var line = _ref.line;
- var severity = _ref.severity;
- var ruleId = _ref.ruleId;
- var column = _ref.column;
- var fix = _ref.fix;
- var endLine = _ref.endLine;
- var endColumn = _ref.endColumn;
-
- var textBuffer = textEditor.getBuffer();
- var linterFix = null;
- if (fix) {
- var fixRange = new _atom.Range(textBuffer.positionForCharacterIndex(fix.range[0]), textBuffer.positionForCharacterIndex(fix.range[1]));
- linterFix = {
- range: fixRange,
- newText: fix.text
- };
- }
- var range = void 0;
- var msgLine = line - 1;
- try {
- if (typeof endColumn !== 'undefined' && typeof endLine !== 'undefined') {
- // Here we always want the column to be a number
- var msgCol = Math.max(0, column - 1);
- (0, _helpers.validatePoint)(textEditor, msgLine, msgCol);
- (0, _helpers.validatePoint)(textEditor, endLine - 1, endColumn - 1);
- range = [[msgLine, msgCol], [endLine - 1, endColumn - 1]];
- } else {
- // We want msgCol to remain undefined if it was initially so
- // `rangeFromLineNumber` will give us a range over the entire line
- var _msgCol = typeof column !== 'undefined' ? column - 1 : column;
- range = Helpers.rangeFromLineNumber(textEditor, msgLine, _msgCol);
- }
- } catch (err) {
- throw new Error('Cannot mark location in editor for (' + ruleId + ') - (' + message + ')' + (' at line (' + line + ') column (' + column + ')'));
- }
- var ret = {
- filePath: filePath,
- type: severity === 1 ? 'Warning' : 'Error',
- range: range
- };
-
- if (showRule) {
- var elName = ruleId ? 'a' : 'span';
- var href = ruleId ? ' href=' + (0, _eslintRuleDocumentation2.default)(ruleId).url : '';
- ret.html = '<' + elName + href + ' class="badge badge-flexible eslint">' + ((ruleId || 'Fatal') + '' + elName + '> ' + (0, _escapeHtml2.default)(message));
- } else {
- ret.text = message;
- }
- if (linterFix) {
- ret.fix = linterFix;
- }
-
- return ret;
- });
+ return (0, _helpers.processESLintMessages)(response, textEditor, showRule, _this2.worker);
});
}
};
diff --git a/lib/worker-helpers.js b/lib/worker-helpers.js
index fbf71f91..4f55b01c 100644
--- a/lib/worker-helpers.js
+++ b/lib/worker-helpers.js
@@ -97,9 +97,8 @@ function findESLintDirectory(modulesDir, config, projectPath) {
}
function getESLintFromDirectory(modulesDir, config, projectPath) {
- var _findESLintDirectory = findESLintDirectory(modulesDir, config, projectPath);
-
- var ESLintDirectory = _findESLintDirectory.path;
+ var _findESLintDirectory = findESLintDirectory(modulesDir, config, projectPath),
+ ESLintDirectory = _findESLintDirectory.path;
try {
// eslint-disable-next-line import/no-dynamic-require
diff --git a/lib/worker.js b/lib/worker.js
index 0d4965d3..edeeba69 100644
--- a/lib/worker.js
+++ b/lib/worker.js
@@ -51,12 +51,12 @@ function fixJob(argv, eslint) {
}
(0, _processCommunication.create)().onRequest('job', function (_ref, job) {
- var contents = _ref.contents;
- var type = _ref.type;
- var config = _ref.config;
- var filePath = _ref.filePath;
- var projectPath = _ref.projectPath;
- var rules = _ref.rules;
+ var contents = _ref.contents,
+ type = _ref.type,
+ config = _ref.config,
+ filePath = _ref.filePath,
+ projectPath = _ref.projectPath,
+ rules = _ref.rules;
global.__LINTER_ESLINT_RESPONSE = [];
diff --git a/spec/linter-eslint-spec.js b/spec/linter-eslint-spec.js
index 877f3c48..71e346a9 100644
--- a/spec/linter-eslint-spec.js
+++ b/spec/linter-eslint-spec.js
@@ -325,11 +325,11 @@ describe('The eslint provider for Linter', () => {
const checkNotificaton = (notification) => {
if (notification.getMessage() === 'linter-eslint debugging information') {
const detail = notification.getDetail()
- expect(detail.includes(`atom version: ${atom.getVersion()}`)).toBe(true)
+ expect(detail.includes(`Atom version: ${atom.getVersion()}`)).toBe(true)
expect(detail.includes('linter-eslint version:')).toBe(true)
- expect(detail.includes(`platform: ${process.platform}`)).toBe(true)
+ expect(detail.includes(`Platform: ${process.platform}`)).toBe(true)
expect(detail.includes('linter-eslint configuration:')).toBe(true)
- expect(detail.includes('Using local project eslint')).toBe(true)
+ expect(detail.includes('Using local project ESLint')).toBe(true)
done = true
}
}
diff --git a/src/helpers.js b/src/helpers.js
index c3e89b50..96fb01be 100644
--- a/src/helpers.js
+++ b/src/helpers.js
@@ -3,9 +3,12 @@
import ChildProcess from 'child_process'
import { createFromProcess } from 'process-communication'
import { join } from 'path'
+import escapeHTML from 'escape-html'
+import ruleURI from 'eslint-rule-documentation'
+import { rangeFromLineNumber } from 'atom-linter'
// eslint-disable-next-line import/no-extraneous-dependencies, import/extensions
-import { Disposable } from 'atom'
+import { Disposable, Range } from 'atom'
const RULE_OFF_SEVERITY = 0
@@ -57,10 +60,198 @@ export function idsToIgnoredRules(ruleIds = []) {
}, {})
}
-export function validatePoint(textEditor, line, col) {
+function validatePoint(textEditor, line, col) {
const buffer = textEditor.getBuffer()
// Clip the given point to a valid one, and check if it equals the original
if (!buffer.clipPosition([line, col]).isEqual([line, col])) {
throw new Error(`${line}:${col} isn't a valid point!`)
}
}
+
+export async function getDebugInfo(worker) {
+ const textEditor = atom.workspace.getActiveTextEditor()
+ const filePath = textEditor.getPath()
+ const packagePath = atom.packages.resolvePackagePath('linter-eslint')
+ // eslint-disable-next-line import/no-dynamic-require
+ const linterEslintMeta = require(join(packagePath, 'package.json'))
+ const config = atom.config.get('linter-eslint')
+ const hoursSinceRestart = Math.round((process.uptime() / 3600) * 10) / 10
+ let returnVal
+ try {
+ const response = await worker.request('job', {
+ type: 'debug',
+ config,
+ filePath
+ })
+ returnVal = {
+ atomVersion: atom.getVersion(),
+ linterEslintVersion: linterEslintMeta.version,
+ linterEslintConfig: config,
+ // eslint-disable-next-line import/no-dynamic-require
+ eslintVersion: require(join(response.path, 'package.json')).version,
+ hoursSinceRestart,
+ platform: process.platform,
+ eslintType: response.type,
+ eslintPath: response.path,
+ }
+ } catch (error) {
+ atom.notifications.addError(`${error}`)
+ }
+ return returnVal
+}
+
+export async function generateDebugString(worker) {
+ const debug = await getDebugInfo(worker)
+ const details = [
+ `Atom version: ${debug.atomVersion}`,
+ `linter-eslint version: ${debug.linterEslintVersion}`,
+ `ESLint version: ${debug.eslintVersion}`,
+ `Hours since last Atom restart: ${debug.hoursSinceRestart}`,
+ `Platform: ${debug.platform}`,
+ `Using ${debug.eslintType} ESLint from ${debug.eslintPath}`,
+ `linter-eslint configuration: ${JSON.stringify(debug.linterEslintConfig, null, 2)}`
+ ]
+ return details.join('\n')
+}
+
+const generateInvalidTrace = async (
+ msgLine, msgCol, msgEndLine, msgEndCol,
+ eslintFullRange, filePath, textEditor, ruleId, message, worker
+) => {
+ let errMsgRange = `${msgLine + 1}:${msgCol}`
+ if (eslintFullRange) {
+ errMsgRange += ` - ${msgEndLine + 1}:${msgEndCol + 1}`
+ }
+ const rangeText = `Requested ${eslintFullRange ? 'start point' : 'range'}: ${errMsgRange}`
+ const issueURL = 'https://github.com/AtomLinter/linter-eslint/issues/new'
+ const titleText = `Invalid position given by '${ruleId}'`
+ const title = encodeURIComponent(titleText)
+ const body = encodeURIComponent([
+ 'ESLint returned a point that did not exist in the document being edited.',
+ `Rule: \`${ruleId}\``,
+ rangeText,
+ '', '',
+ '',
+ '', '',
+ 'Debug information:',
+ '```json',
+ JSON.stringify(await getDebugInfo(worker), null, 2),
+ '```'
+ ].join('\n'))
+ const newIssueURL = `${issueURL}?title=${title}&body=${body}`
+ return {
+ type: 'Error',
+ severity: 'error',
+ html: `${escapeHTML(titleText)}. See the trace for details. ` +
+ `Report this!`,
+ filePath,
+ range: rangeFromLineNumber(textEditor, 0),
+ trace: [
+ {
+ type: 'Trace',
+ text: `Original message: ${ruleId} - ${message}`,
+ filePath,
+ severity: 'info',
+ },
+ {
+ type: 'Trace',
+ text: rangeText,
+ filePath,
+ severity: 'info',
+ },
+ ]
+ }
+}
+
+/**
+ * Given a raw response from ESLint, this processes the messages into a format
+ * compatible with the Linter API.
+ * @param {Object} response The raw response from ESLint
+ * @param {TextEditor} textEditor The Atom::TextEditor of the file the messages belong to
+ * @param {bool} showRule Whether to show the rule in the messages
+ * @param {Object} worker The current Worker process to send Debug jobs to
+ * @return {Promise} The messages transformed into Linter messages
+ */
+export async function processESLintMessages(response, textEditor, showRule, worker) {
+ return Promise.all(response.map(async ({
+ message, line, severity, ruleId, column, fix, endLine, endColumn
+ }) => {
+ const filePath = textEditor.getPath()
+ const textBuffer = textEditor.getBuffer()
+ let linterFix = null
+ if (fix) {
+ const fixRange = new Range(
+ textBuffer.positionForCharacterIndex(fix.range[0]),
+ textBuffer.positionForCharacterIndex(fix.range[1])
+ )
+ linterFix = {
+ range: fixRange,
+ newText: fix.text
+ }
+ }
+ let msgCol
+ let msgEndLine
+ let msgEndCol
+ let eslintFullRange = false
+
+ /*
+ Note: ESLint positions are 1-indexed, while Atom expects 0-indexed,
+ positions. We are subtracting 1 from these values here so we don't have to
+ keep doing so in later uses.
+ */
+ const msgLine = line - 1
+ if (typeof endColumn !== 'undefined' && typeof endLine !== 'undefined') {
+ eslintFullRange = true
+ // Here we always want the column to be a number
+ msgCol = Math.max(0, column - 1)
+ msgEndLine = endLine - 1
+ msgEndCol = endColumn - 1
+ } else {
+ // We want msgCol to remain undefined if it was initially so
+ // `rangeFromLineNumber` will give us a range over the entire line
+ msgCol = typeof column !== 'undefined' ? column - 1 : column
+ }
+
+ let ret
+ let range
+ try {
+ if (eslintFullRange) {
+ validatePoint(textEditor, msgLine, msgCol)
+ validatePoint(textEditor, msgEndLine, msgEndCol)
+ range = [[msgLine, msgCol], [msgEndLine, msgEndCol]]
+ } else {
+ range = rangeFromLineNumber(textEditor, msgLine, msgCol)
+ }
+ ret = {
+ filePath,
+ type: severity === 1 ? 'Warning' : 'Error',
+ range
+ }
+
+ if (showRule) {
+ const elName = ruleId ? 'a' : 'span'
+ const href = ruleId ? ` href=${ruleURI(ruleId).url}` : ''
+ ret.html = `<${elName}${href} class="badge badge-flexible eslint">` +
+ `${ruleId || 'Fatal'}${elName}> ${escapeHTML(message)}`
+ } else {
+ ret.text = message
+ }
+ if (linterFix) {
+ ret.fix = linterFix
+ }
+ } catch (err) {
+ if (!err.message.startsWith('Line number ') &&
+ !err.message.startsWith('Column start ')
+ ) {
+ // This isn't an invalid point error from `rangeFromLineNumber`, re-throw it
+ throw err
+ }
+ ret = await generateInvalidTrace(
+ msgLine, msgCol, msgEndLine, msgEndCol,
+ eslintFullRange, filePath, textEditor, ruleId, message, worker
+ )
+ }
+
+ return ret
+ }))
+}
diff --git a/src/main.js b/src/main.js
index f120032d..be0a4041 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,13 +1,12 @@
'use babel'
-import Path from 'path'
-import escapeHTML from 'escape-html'
-import ruleURI from 'eslint-rule-documentation'
-
// eslint-disable-next-line import/no-extraneous-dependencies, import/extensions
-import { CompositeDisposable, Range } from 'atom'
+import { CompositeDisposable, } from 'atom'
-import { spawnWorker, showError, idsToIgnoredRules, validatePoint } from './helpers'
+import {
+ spawnWorker, showError, idsToIgnoredRules, processESLintMessages,
+ generateDebugString
+} from './helpers'
// Configuration
const scopes = []
@@ -62,34 +61,10 @@ module.exports = {
}))
this.subscriptions.add(atom.commands.add('atom-text-editor', {
- 'linter-eslint:debug': () => {
- const textEditor = atom.workspace.getActiveTextEditor()
- const filePath = textEditor.getPath()
- // eslint-disable-next-line import/no-dynamic-require
- const linterEslintMeta = require(Path.join(atom.packages.resolvePackagePath('linter-eslint'), 'package.json'))
- const config = atom.config.get('linter-eslint')
- const configString = JSON.stringify(config, null, 2)
- const hoursSinceRestart = process.uptime() / 3600
- this.worker.request('job', {
- type: 'debug',
- config,
- filePath
- }).then((response) => {
- const detail = [
- `atom version: ${atom.getVersion()}`,
- `linter-eslint version: ${linterEslintMeta.version}`,
- // eslint-disable-next-line import/no-dynamic-require
- `eslint version: ${require(Path.join(response.path, 'package.json')).version}`,
- `hours since last atom restart: ${Math.round(hoursSinceRestart * 10) / 10}`,
- `platform: ${process.platform}`,
- `Using ${response.type} eslint from ${response.path}`,
- `linter-eslint configuration: ${configString}`
- ].join('\n')
- const notificationOptions = { detail, dismissable: true }
- atom.notifications.addInfo('linter-eslint debugging information', notificationOptions)
- }).catch((response) => {
- atom.notifications.addError(`${response}`)
- })
+ 'linter-eslint:debug': async () => {
+ const debugString = await generateDebugString(this.worker)
+ const notificationOptions = { detail: debugString, dismissable: true }
+ atom.notifications.addInfo('linter-eslint debugging information', notificationOptions)
}
}))
@@ -147,8 +122,6 @@ module.exports = {
this.subscriptions.dispose()
},
provideLinter() {
- const Helpers = require('atom-linter')
-
return {
name: 'ESLint',
grammarScopes: scopes,
@@ -183,62 +156,7 @@ module.exports = {
*/
return null
}
- return response.map(({
- message, line, severity, ruleId, column, fix, endLine, endColumn }
- ) => {
- const textBuffer = textEditor.getBuffer()
- let linterFix = null
- if (fix) {
- const fixRange = new Range(
- textBuffer.positionForCharacterIndex(fix.range[0]),
- textBuffer.positionForCharacterIndex(fix.range[1])
- )
- linterFix = {
- range: fixRange,
- newText: fix.text
- }
- }
- let range
- const msgLine = line - 1
- try {
- if (typeof endColumn !== 'undefined' && typeof endLine !== 'undefined') {
- // Here we always want the column to be a number
- const msgCol = Math.max(0, column - 1)
- validatePoint(textEditor, msgLine, msgCol)
- validatePoint(textEditor, endLine - 1, endColumn - 1)
- range = [[msgLine, msgCol], [endLine - 1, endColumn - 1]]
- } else {
- // We want msgCol to remain undefined if it was initially so
- // `rangeFromLineNumber` will give us a range over the entire line
- const msgCol = typeof column !== 'undefined' ? column - 1 : column
- range = Helpers.rangeFromLineNumber(textEditor, msgLine, msgCol)
- }
- } catch (err) {
- throw new Error(
- `Cannot mark location in editor for (${ruleId}) - (${message})` +
- ` at line (${line}) column (${column})`
- )
- }
- const ret = {
- filePath,
- type: severity === 1 ? 'Warning' : 'Error',
- range
- }
-
- if (showRule) {
- const elName = ruleId ? 'a' : 'span'
- const href = ruleId ? ` href=${ruleURI(ruleId).url}` : ''
- ret.html = `<${elName}${href} class="badge badge-flexible eslint">` +
- `${ruleId || 'Fatal'}${elName}> ${escapeHTML(message)}`
- } else {
- ret.text = message
- }
- if (linterFix) {
- ret.fix = linterFix
- }
-
- return ret
- })
+ return processESLintMessages(response, textEditor, showRule, this.worker)
})
}
}