From ae4aee795c493b19be2dabb026f9cb9f92ed16a4 Mon Sep 17 00:00:00 2001 From: Ian VanSchooten Date: Fri, 7 Oct 2016 20:45:58 -0400 Subject: [PATCH] Add debug command This is a rebase and re-commit of 2310e861c7c667ae5f3e1d121004200b26bda22b, which was reverted in 6cd62e869419c1896f8887ca4a933ffe0ce5140c. --- lib/helpers.js | 4 +- lib/main.js | 26 +++++++++ lib/worker-helpers.js | 48 ++++++++++++++--- lib/worker.js | 3 ++ .../node_modules/eslint/.gitkeep | 0 .../node_modules/eslint/bin/eslint.js | 0 .../node_modules/eslint/lib/cli.js | 1 + spec/linter-eslint-spec.js | 54 +++++++++++++++++++ spec/worker-helpers-spec.js | 49 +++++++++++++++++ src/main.js | 31 +++++++++++ src/worker-helpers.js | 43 ++++++++++++--- src/worker.js | 5 +- 12 files changed, 245 insertions(+), 19 deletions(-) create mode 100644 spec/fixtures/global-eslint/node_modules/eslint/.gitkeep create mode 100644 spec/fixtures/global-eslint/node_modules/eslint/bin/eslint.js create mode 100644 spec/fixtures/global-eslint/node_modules/eslint/lib/cli.js diff --git a/lib/helpers.js b/lib/helpers.js index 6cb50a6d..931fe8de 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -49,7 +49,7 @@ function spawnWorker() { } function showError(givenMessage) { - var givenDetail = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + var givenDetail = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1]; var detail = void 0; var message = void 0; @@ -67,7 +67,7 @@ function showError(givenMessage) { } function idsToIgnoredRules() { - var ruleIds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + var ruleIds = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; return ruleIds.reduce(function (ids, id) { ids[id] = RULE_OFF_SEVERITY; diff --git a/lib/main.js b/lib/main.js index 4d047634..fbde4a62 100644 --- a/lib/main.js +++ b/lib/main.js @@ -1,6 +1,10 @@ 'use strict'; 'use babel'; +var _path = require('path'); + +var _path2 = _interopRequireDefault(_path); + var _escapeHtml = require('escape-html'); var _escapeHtml2 = _interopRequireDefault(_escapeHtml); @@ -67,6 +71,28 @@ 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(); + 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 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 }; + atom.notifications.addInfo('linter-eslint debugging information', notificationOptions); + }).catch(function (response) { + atom.notifications.addError('' + response); + }); + } + })); + this.subscriptions.add(atom.commands.add('atom-text-editor', { 'linter-eslint:fix-file': function linterEslintFixFile() { var textEditor = atom.workspace.getActiveTextEditor(); diff --git a/lib/worker-helpers.js b/lib/worker-helpers.js index f073258d..fbf71f91 100644 --- a/lib/worker-helpers.js +++ b/lib/worker-helpers.js @@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.getNodePrefixPath = getNodePrefixPath; +exports.findESLintDirectory = findESLintDirectory; exports.getESLintFromDirectory = getESLintFromDirectory; exports.refreshModulesPath = refreshModulesPath; exports.getESLintInstance = getESLintInstance; @@ -16,6 +17,10 @@ var _path = require('path'); var _path2 = _interopRequireDefault(_path); +var _fs = require('fs'); + +var _fs2 = _interopRequireDefault(_fs); + var _child_process = require('child_process'); var _child_process2 = _interopRequireDefault(_child_process); @@ -52,23 +57,50 @@ function getNodePrefixPath() { return Cache.NODE_PREFIX_PATH; } -function getESLintFromDirectory(modulesDir, config, projectPath) { - var ESLintDirectory = null; - +function findESLintDirectory(modulesDir, config, projectPath) { + var eslintDir = null; + var locationType = null; if (config.useGlobalEslint) { + locationType = 'global'; var prefixPath = config.globalNodePath || getNodePrefixPath(); if (process.platform === 'win32') { - ESLintDirectory = _path2.default.join(prefixPath, 'node_modules', 'eslint'); + eslintDir = _path2.default.join(prefixPath, 'node_modules', 'eslint'); } else { - ESLintDirectory = _path2.default.join(prefixPath, 'lib', 'node_modules', 'eslint'); + eslintDir = _path2.default.join(prefixPath, 'lib', 'node_modules', 'eslint'); } } else if (!config.advancedLocalNodeModules) { - ESLintDirectory = _path2.default.join(modulesDir || '', 'eslint'); + locationType = 'local project'; + eslintDir = _path2.default.join(modulesDir || '', 'eslint'); } else if (_path2.default.isAbsolute(config.advancedLocalNodeModules)) { - ESLintDirectory = _path2.default.join(config.advancedLocalNodeModules || '', 'eslint'); + locationType = 'advanced specified'; + eslintDir = _path2.default.join(config.advancedLocalNodeModules || '', 'eslint'); } else { - ESLintDirectory = _path2.default.join(projectPath, config.advancedLocalNodeModules, 'eslint'); + locationType = 'advanced specified'; + eslintDir = _path2.default.join(projectPath, config.advancedLocalNodeModules, 'eslint'); } + try { + if (_fs2.default.statSync(eslintDir).isDirectory()) { + return { + path: eslintDir, + type: locationType + }; + } + } catch (e) { + if (config.useGlobalEslint && e.code === 'ENOENT') { + throw new Error('ESLint not found, Please install or make sure Atom is getting $PATH correctly'); + } + } + return { + path: Cache.ESLINT_LOCAL_PATH, + type: 'bundled fallback' + }; +} + +function getESLintFromDirectory(modulesDir, config, projectPath) { + var _findESLintDirectory = findESLintDirectory(modulesDir, config, projectPath); + + var ESLintDirectory = _findESLintDirectory.path; + try { // eslint-disable-next-line import/no-dynamic-require return require(_path2.default.join(ESLintDirectory, 'lib', 'cli.js')); diff --git a/lib/worker.js b/lib/worker.js index 76dba0a8..0d4965d3 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -75,6 +75,9 @@ function fixJob(argv, eslint) { job.response = lintJob(argv, contents, eslint, configPath, config); } else if (type === 'fix') { job.response = fixJob(argv, eslint); + } else if (type === 'debug') { + var modulesDir = _path2.default.dirname((0, _atomLinter.findCached)(fileDir, 'node_modules/eslint') || ''); + job.response = Helpers.findESLintDirectory(modulesDir, config); } }); diff --git a/spec/fixtures/global-eslint/node_modules/eslint/.gitkeep b/spec/fixtures/global-eslint/node_modules/eslint/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/spec/fixtures/global-eslint/node_modules/eslint/bin/eslint.js b/spec/fixtures/global-eslint/node_modules/eslint/bin/eslint.js new file mode 100644 index 00000000..e69de29b diff --git a/spec/fixtures/global-eslint/node_modules/eslint/lib/cli.js b/spec/fixtures/global-eslint/node_modules/eslint/lib/cli.js new file mode 100644 index 00000000..620463e4 --- /dev/null +++ b/spec/fixtures/global-eslint/node_modules/eslint/lib/cli.js @@ -0,0 +1 @@ +module.exports = "located" diff --git a/spec/linter-eslint-spec.js b/spec/linter-eslint-spec.js index 0b264a8c..47ade60b 100644 --- a/spec/linter-eslint-spec.js +++ b/spec/linter-eslint-spec.js @@ -288,4 +288,58 @@ describe('The eslint provider for Linter', () => { ) }) }) + + describe('prints debugging information with the `debug` command', () => { + let editor + beforeEach(() => { + waitsForPromise(() => + atom.workspace.open(goodPath).then((openEditor) => { + editor = openEditor + }) + ) + }) + + it('shows an info notification', () => { + let done + const checkNotificaton = (notification) => { + if (notification.getMessage() === 'linter-eslint debugging information') { + expect(notification.getType()).toEqual('info') + done = true + } + } + atom.notifications.onDidAddNotification(checkNotificaton) + + atom.commands.dispatch(atom.views.getView(editor), 'linter-eslint:debug') + + waitsFor( + () => done, + 'Notification type should be checked', + 2000 + ) + }) + + it('includes debugging information in the details', () => { + let done + 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('linter-eslint version:')).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) + done = true + } + } + atom.notifications.onDidAddNotification(checkNotificaton) + + atom.commands.dispatch(atom.views.getView(editor), 'linter-eslint:debug') + + waitsFor( + () => done, + 'Notification details should be checked', + 2000 + ) + }) + }) }) diff --git a/spec/worker-helpers-spec.js b/spec/worker-helpers-spec.js index 9ce0dbe8..70812734 100644 --- a/spec/worker-helpers-spec.js +++ b/spec/worker-helpers-spec.js @@ -5,6 +5,55 @@ import * as Helpers from '../lib/worker-helpers' import { getFixturesPath } from './common' describe('Worker Helpers', () => { + describe('findESLintDirectory', () => { + it('returns an object with path and type keys', () => { + const modulesDir = Path.join(getFixturesPath('local-eslint'), 'node_modules') + const foundEslint = Helpers.findESLintDirectory(modulesDir, {}) + expect(typeof foundEslint === 'object').toBe(true) + expect(foundEslint.path).toBeDefined() + expect(foundEslint.type).toBeDefined() + }) + + it('finds a local eslint when useGlobalEslint is false', () => { + const modulesDir = Path.join(getFixturesPath('local-eslint'), 'node_modules') + const foundEslint = Helpers.findESLintDirectory(modulesDir, { useGlobalEslint: false }) + const expectedEslintPath = Path.join(getFixturesPath('local-eslint'), 'node_modules', 'eslint') + expect(foundEslint.path).toEqual(expectedEslintPath) + expect(foundEslint.type).toEqual('local project') + }) + + it('does not find a local eslint when useGlobalEslint is true', () => { + const modulesDir = Path.join(getFixturesPath('local-eslint'), 'node_modules') + const globalNodePath = getFixturesPath('global-eslint') + const config = { useGlobalEslint: true, globalNodePath } + const foundEslint = Helpers.findESLintDirectory(modulesDir, config) + const expectedEslintPath = Path.join(getFixturesPath('local-eslint'), 'node_modules', 'eslint') + expect(foundEslint.path).not.toEqual(expectedEslintPath) + expect(foundEslint.type).not.toEqual('local project') + }) + + it('finds a global eslint when useGlobalEslint is true and a valid globalNodePath is provided', () => { + const modulesDir = Path.join(getFixturesPath('local-eslint'), 'node_modules') + const globalNodePath = getFixturesPath('global-eslint') + const config = { useGlobalEslint: true, globalNodePath } + const foundEslint = Helpers.findESLintDirectory(modulesDir, config) + const expectedEslintPath = process.platform === 'win32' + ? Path.join(globalNodePath, 'node_modules', 'eslint') + : Path.join(globalNodePath, 'lib', 'node_modules', 'eslint') + expect(foundEslint.path).toEqual(expectedEslintPath) + expect(foundEslint.type).toEqual('global') + }) + + it('falls back to the packaged eslint when no local eslint is found', () => { + const modulesDir = 'not/a/real/path' + const config = { useGlobalEslint: false } + const foundEslint = Helpers.findESLintDirectory(modulesDir, config) + const expectedBundledPath = Path.join(__dirname, '..', 'node_modules', 'eslint') + expect(foundEslint.path).toEqual(expectedBundledPath) + expect(foundEslint.type).toEqual('bundled fallback') + }) + }) + describe('getESLintInstance && getESLintFromDirectory', () => { it('tries to find an indirect local eslint using an absolute path', () => { const path = Path.join( diff --git a/src/main.js b/src/main.js index bdee035d..41d327cc 100644 --- a/src/main.js +++ b/src/main.js @@ -1,5 +1,6 @@ 'use babel' +import Path from 'path' import escapeHTML from 'escape-html' import ruleURI from 'eslint-rule-documentation' @@ -60,6 +61,36 @@ module.exports = { }) })) + this.subscriptions.add(atom.commands.add('atom-text-editor', { + 'linter-eslint:debug': () => { + const textEditor = atom.workspace.getActiveTextEditor() + const filePath = textEditor.getPath() + 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 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}`) + }) + } + })) + this.subscriptions.add(atom.commands.add('atom-text-editor', { 'linter-eslint:fix-file': () => { const textEditor = atom.workspace.getActiveTextEditor() diff --git a/src/worker-helpers.js b/src/worker-helpers.js index d9fac393..1ddc28a0 100644 --- a/src/worker-helpers.js +++ b/src/worker-helpers.js @@ -1,6 +1,7 @@ 'use babel' import Path from 'path' +import fs from 'fs' import ChildProcess from 'child_process' import resolveEnv from 'resolve-env' import { findCached } from 'atom-linter' @@ -29,23 +30,49 @@ export function getNodePrefixPath() { return Cache.NODE_PREFIX_PATH } -export function getESLintFromDirectory(modulesDir, config, projectPath) { - let ESLintDirectory = null - +export function findESLintDirectory(modulesDir, config, projectPath) { + let eslintDir = null + let locationType = null if (config.useGlobalEslint) { + locationType = 'global' const prefixPath = config.globalNodePath || getNodePrefixPath() if (process.platform === 'win32') { - ESLintDirectory = Path.join(prefixPath, 'node_modules', 'eslint') + eslintDir = Path.join(prefixPath, 'node_modules', 'eslint') } else { - ESLintDirectory = Path.join(prefixPath, 'lib', 'node_modules', 'eslint') + eslintDir = Path.join(prefixPath, 'lib', 'node_modules', 'eslint') } } else if (!config.advancedLocalNodeModules) { - ESLintDirectory = Path.join(modulesDir || '', 'eslint') + locationType = 'local project' + eslintDir = Path.join(modulesDir || '', 'eslint') } else if (Path.isAbsolute(config.advancedLocalNodeModules)) { - ESLintDirectory = Path.join(config.advancedLocalNodeModules || '', 'eslint') + locationType = 'advanced specified' + eslintDir = Path.join(config.advancedLocalNodeModules || '', 'eslint') } else { - ESLintDirectory = Path.join(projectPath, config.advancedLocalNodeModules, 'eslint') + locationType = 'advanced specified' + eslintDir = Path.join(projectPath, config.advancedLocalNodeModules, 'eslint') + } + try { + if (fs.statSync(eslintDir).isDirectory()) { + return { + path: eslintDir, + type: locationType, + } + } + } catch (e) { + if (config.useGlobalEslint && e.code === 'ENOENT') { + throw new Error( + 'ESLint not found, Please install or make sure Atom is getting $PATH correctly' + ) + } + } + return { + path: Cache.ESLINT_LOCAL_PATH, + type: 'bundled fallback', } +} + +export function getESLintFromDirectory(modulesDir, config, projectPath) { + const { path: ESLintDirectory } = findESLintDirectory(modulesDir, config, projectPath) try { // eslint-disable-next-line import/no-dynamic-require return require(Path.join(ESLintDirectory, 'lib', 'cli.js')) diff --git a/src/worker.js b/src/worker.js index 1a4b1dd6..887ba6a6 100644 --- a/src/worker.js +++ b/src/worker.js @@ -4,7 +4,7 @@ import Path from 'path' import { create } from 'process-communication' -import { FindCache } from 'atom-linter' +import { FindCache, findCached } from 'atom-linter' import * as Helpers from './worker-helpers' process.title = 'linter-eslint helper' @@ -59,6 +59,9 @@ create().onRequest('job', ({ contents, type, config, filePath, projectPath, rule job.response = lintJob(argv, contents, eslint, configPath, config) } else if (type === 'fix') { job.response = fixJob(argv, eslint) + } else if (type === 'debug') { + const modulesDir = Path.dirname(findCached(fileDir, 'node_modules/eslint') || '') + job.response = Helpers.findESLintDirectory(modulesDir, config) } })