diff --git a/lib/index.js b/lib/index.js index 6a1cbb3..bce3841 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,79 +2,126 @@ // eslint-disable-next-line import/extensions, import/no-extraneous-dependencies import { CompositeDisposable } from 'atom'; -import { readFile as fsReadFile } from 'fs'; -import { dirname } from 'path'; -const lazyReq = require('lazy-req')(require); - -const { findAsync, generateRange } = lazyReq('atom-linter')('findAsync', 'generateRange'); -const stripJSONComments = lazyReq('strip-json-comments'); -const tinyPromisify = lazyReq('tiny-promisify'); - -const grammarScopes = []; - -let subscriptions; - -export function activate() { - require('atom-package-deps').install('linter-htmlhint'); - - subscriptions = new CompositeDisposable(); - subscriptions.add(atom.config.observe('linter-htmlhint.enabledScopes', (scopes) => { - // Remove any old scopes - grammarScopes.splice(0, grammarScopes.length); - // Add the current scopes - Array.prototype.push.apply(grammarScopes, scopes); - })); -} - -export function deactivate() { - subscriptions.dispose(); -} +// Dependencies +let dirname; +let HTMLHint; +let findAsync; +let fsReadFile; +let generateRange; +let tinyPromisify; +let stripJSONComments; const getConfig = async (filePath) => { - const readFile = tinyPromisify()(fsReadFile); + 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; }; -export function provideLinter() { - return { - name: 'htmlhint', - grammarScopes, - scope: 'file', - lintOnFly: true, - lint: async (editor) => { - const { HTMLHint } = require('htmlhint'); - - const fileText = editor.getText(); - const filePath = editor.getPath(); +const loadDeps = () => { + if (loadDeps.loaded) { + return; + } + if (!dirname) { + ({ dirname } = require('path')); + } + if (!HTMLHint) { + ({ HTMLHint } = require('htmlhint')); + } + if (!findAsync || !generateRange) { + ({ findAsync, generateRange } = require('atom-linter')); + } + if (!fsReadFile) { + ({ readFile: fsReadFile } = require('fs')); + } + if (!tinyPromisify) { + tinyPromisify = require('tiny-promisify'); + } + if (!stripJSONComments) { + stripJSONComments = require('strip-json-comments'); + } + loadDeps.loaded = true; +}; - if (!fileText) { - return []; +export default { + activate() { + this.idleCallbacks = new Set(); + let depsCallbackID; + const installLinterHtmlhintDeps = () => { + this.idleCallbacks.delete(depsCallbackID); + if (!atom.inSpecMode()) { + require('atom-package-deps').install('linter-htmlhint'); } - - const ruleset = await getConfig(filePath); - - const messages = HTMLHint.verify(fileText, ruleset || undefined); - - if (editor.getText() !== fileText) { - // Editor contents have changed, tell Linter not to update - return null; + loadDeps(); + }; + depsCallbackID = window.requestIdleCallback(installLinterHtmlhintDeps); + this.idleCallbacks.add(depsCallbackID); + + this.grammarScopes = []; + + this.subscriptions = new CompositeDisposable(); + this.subscriptions.add(atom.config.observe('linter-htmlhint.enabledScopes', (scopes) => { + // Remove any old scopes + this.grammarScopes.splice(0, this.grammarScopes.length); + // Add the current scopes + Array.prototype.push.apply(this.grammarScopes, scopes); + })); + }, + + deactivate() { + this.idleCallbacks.forEach(callbackID => window.cancelIdleCallback(callbackID)); + this.idleCallbacks.clear(); + this.subscriptions.dispose(); + }, + + provideLinter() { + return { + name: 'htmlhint', + grammarScopes: this.grammarScopes, + scope: 'file', + lintOnFly: true, + lint: async (editor) => { + if (!atom.workspace.isTextEditor(editor)) { + return null; + } + + const filePath = editor.getPath(); + if (!filePath) { + // Invalid path + return null; + } + + const fileText = editor.getText(); + if (!fileText) { + return []; + } + + // Ensure that all dependencies are loaded + loadDeps(); + + const ruleset = await getConfig(filePath); + + 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: generateRange(editor, message.line - 1, message.col - 1), + type: message.type, + text: message.message, + filePath + })); } - - return messages.map(message => ({ - range: generateRange(editor, message.line - 1, message.col - 1), - type: message.type, - text: message.message, - filePath - })); - } - }; -} + }; + } +}; diff --git a/package.json b/package.json index 7dae334..867a249 100644 --- a/package.json +++ b/package.json @@ -43,9 +43,8 @@ "homepage": "https://github.com/AtomLinter/linter-htmlhint#readme", "dependencies": { "atom-linter": "^10.0.0", - "atom-package-deps": "^4.0.1", + "atom-package-deps": "^4.6.0", "htmlhint": "0.9.13", - "lazy-req": "^2.0.0", "strip-json-comments": "^2.0.1", "tiny-promisify": "^1.0.0" }, @@ -76,6 +75,7 @@ "atom": true }, "env": { + "browser": true, "node": true } },