From 2aa063122194dd755e4571b61e7a8e88a8960a27 Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Thu, 13 Oct 2016 16:01:16 -0700 Subject: [PATCH 1/4] Properly dispose of the subscriptions --- lib/index.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 439f19e..8d66a4d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -5,10 +5,12 @@ import { CompositeDisposable } from 'atom'; const grammarScopes = []; +let subscriptions; + export function activate() { require('atom-package-deps').install('linter-htmlhint'); - const subscriptions = new CompositeDisposable(); + subscriptions = new CompositeDisposable(); subscriptions.add(atom.config.observe('linter-htmlhint.enabledScopes', (scopes) => { // Remove any old scopes grammarScopes.splice(0, grammarScopes.length); @@ -17,6 +19,10 @@ export function activate() { })); } +export function deactivate() { + subscriptions.dispose(); +} + function getConfig(filePath) { const fs = require('fs'); const path = require('path'); From 641fd15392567905a7c873b87af621b12d554fc9 Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Fri, 14 Oct 2016 10:31:44 -0700 Subject: [PATCH 2/4] Utilize async/await Simplify the flow of the code quite a bit by using async/await. --- lib/index.js | 65 ++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/lib/index.js b/lib/index.js index 8d66a4d..5e10dd0 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,6 +2,12 @@ // eslint-disable-next-line import/extensions, import/no-extraneous-dependencies import { CompositeDisposable } from 'atom'; +import fs from 'fs'; +import path from 'path'; +import { findAsync, rangeFromLineNumber } from 'atom-linter'; +import stripJSONComments from 'strip-json-comments'; + +const readFile = require('tiny-promisify')(fs.readFile); const grammarScopes = []; @@ -23,26 +29,17 @@ export function deactivate() { subscriptions.dispose(); } -function getConfig(filePath) { - const fs = require('fs'); - const path = require('path'); - const readFile = require('tiny-promisify')(fs.readFile); - const { findAsync } = require('atom-linter'); - - return findAsync(path.dirname(filePath), '.htmlhintrc') - .then((configPath) => { - if (configPath) { - return readFile(configPath, 'utf8'); - } - return null; - }) - .then((conf) => { - if (conf) { - return JSON.parse(require('strip-json-comments')(conf)); - } - return null; - }); -} +const getConfig = async (filePath) => { + const configPath = await findAsync(path.dirname(filePath), '.htmlhintrc'); + let conf = null; + if (configPath !== null) { + conf = await readFile(configPath, 'utf8'); + } + if (conf) { + return JSON.parse(stripJSONComments(conf)); + } + return null; +}; export function provideLinter() { return { @@ -50,28 +47,26 @@ export function provideLinter() { grammarScopes, scope: 'file', lintOnFly: true, - lint: (editor) => { + lint: async (editor) => { const { HTMLHint } = require('htmlhint'); - const text = editor.getText(); + const fileText = editor.getText(); const filePath = editor.getPath(); - if (!text) { - return Promise.resolve([]); + if (!fileText) { + return []; } - return getConfig(filePath) - .then(ruleset => HTMLHint.verify(text, ruleset || undefined)) - .then((messages) => { - const { rangeFromLineNumber } = require('atom-linter'); + const ruleset = await getConfig(filePath); + + const messages = HTMLHint.verify(fileText, ruleset || undefined); - return messages.map(message => ({ - range: rangeFromLineNumber(editor, message.line - 1, message.col - 1), - type: message.type, - text: message.message, - filePath - })); - }); + return messages.map(message => ({ + range: rangeFromLineNumber(editor, message.line - 1, message.col - 1), + type: message.type, + text: message.message, + filePath + })); } }; } From 550f3990a7f7702ecea19d42a4c5d23a844fe653 Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Fri, 14 Oct 2016 10:32:33 -0700 Subject: [PATCH 3/4] Fix a race condition Make it so if the editor contents have changed between when the lint was triggered and the results came back we simply tell Linter to not update the current messages, instead of attempting to mark up the contents based on the old (potentially leading to "invalid" ranges, that _were_ valid when the lint was triggered). --- lib/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/index.js b/lib/index.js index 5e10dd0..3124132 100644 --- a/lib/index.js +++ b/lib/index.js @@ -61,6 +61,11 @@ export function provideLinter() { const messages = HTMLHint.verify(fileText, ruleset || undefined); + if (editor.getText() !== fileText) { + // Editor contents have changed, tell Linter not to update + return null; + } + return messages.map(message => ({ range: rangeFromLineNumber(editor, message.line - 1, message.col - 1), type: message.type, From 1ea13e7ac90ee6a956787e6a4ac7f9b44040eb4f Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Fri, 14 Oct 2016 10:45:22 -0700 Subject: [PATCH 4/4] Use lazy-req to only load modules when needed --- lib/index.js | 17 ++++++++++------- package.json | 1 + 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/index.js b/lib/index.js index 3124132..767f5ad 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,12 +2,14 @@ // eslint-disable-next-line import/extensions, import/no-extraneous-dependencies import { CompositeDisposable } from 'atom'; -import fs from 'fs'; -import path from 'path'; -import { findAsync, rangeFromLineNumber } from 'atom-linter'; -import stripJSONComments from 'strip-json-comments'; +import { readFile as fsReadFile } from 'fs'; +import { dirname } from 'path'; -const readFile = require('tiny-promisify')(fs.readFile); +const lazyReq = require('lazy-req')(require); + +const { findAsync, rangeFromLineNumber } = lazyReq('atom-linter')('findAsync', 'rangeFromLineNumber'); +const stripJSONComments = lazyReq('strip-json-comments'); +const tinyPromisify = lazyReq('tiny-promisify'); const grammarScopes = []; @@ -30,13 +32,14 @@ export function deactivate() { } const getConfig = async (filePath) => { - const configPath = await findAsync(path.dirname(filePath), '.htmlhintrc'); + const readFile = tinyPromisify()(fsReadFile); + const configPath = await findAsync(dirname(filePath), '.htmlhintrc'); let conf = null; if (configPath !== null) { conf = await readFile(configPath, 'utf8'); } if (conf) { - return JSON.parse(stripJSONComments(conf)); + return JSON.parse(stripJSONComments()(conf)); } return null; }; diff --git a/package.json b/package.json index a9b5deb..fa47603 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "atom-linter": "^8.0.0", "atom-package-deps": "^4.0.1", "htmlhint": "0.9.13", + "lazy-req": "^1.1.0", "strip-json-comments": "^2.0.1", "tiny-promisify": "^0.1.1" },