Skip to content
This repository has been archived by the owner on Aug 7, 2023. It is now read-only.

Commit

Permalink
Re-implement file ignoring
Browse files Browse the repository at this point in the history
Since JSHint can't handle `.jshintignore` files for content sent in via
stdin, check this manually using `minimatch`.

Also sets the CWD for better automatic resolution of the configuration,
since that at least works within JSHint.
  • Loading branch information
Arcanemagus committed May 5, 2017
1 parent 5360103 commit 96b6436
Showing 3 changed files with 81 additions and 29 deletions.
20 changes: 20 additions & 0 deletions decls/minimatch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @flow

declare type MinimatchOptions = {
debug?: boolean,
nobrace?: boolean,
noglobstar?: boolean,
dot?: boolean,
noext?: boolean,
nocase?: boolean,
nonull?: boolean,
matchBase?: boolean,
nocomment?: boolean,
nonegate?: boolean,
flipNegate?: boolean,
}

declare module 'minimatch' {
declare module.exports:
(path: string, pattern: string, options?: MinimatchOptions) => boolean;
}
87 changes: 59 additions & 28 deletions lib/main.js
Original file line number Diff line number Diff line change
@@ -3,11 +3,24 @@
/* @flow */

import Path from 'path';
import { readFile } from 'fs';
import minimatch from 'minimatch';
/* eslint-disable import/extensions, import/no-extraneous-dependencies */
import { CompositeDisposable } from 'atom';
import type { TextEditor } from 'atom';
/* eslint-enable import/extensions, import/no-extraneous-dependencies */

async function readIgnoreList(ignorePath) {
return new Promise((resolve, reject) => {
readFile(ignorePath, 'utf8', (err, data) => {
if (err) {
reject(err);
}
resolve(data.split(/[\r\n]/));
});
});
}

module.exports = {
config: {
executablePath: {
@@ -18,17 +31,22 @@ module.exports = {
lintInlineJavaScript: {
type: 'boolean',
default: false,
description: 'Lint JavaScript inside `<script>` blocks in HTML or PHP files.',
description: 'Attempts to lint JavaScript inside `<script>` blocks in HTML or PHP files.',
},
disableWhenNoJshintrcFileInPath: {
type: 'boolean',
default: false,
description: 'Disable linter when no `.jshintrc` is found in project.',
description: 'Disable the provider when no configuration file is found.',
},
jshintFileName: {
type: 'string',
default: '.jshintrc',
description: 'jshint file name',
description: 'Custom name for the .jshintrc file',
},
jshintignoreFilename: {
type: 'string',
default: '.jshintignore',
description: 'Custom name for the .jshintignore file',
},
},

@@ -37,32 +55,30 @@ module.exports = {

this.scopes = ['source.js', 'source.js-semantic'];
this.subscriptions = new CompositeDisposable();
this.subscriptions.add(atom.config.observe('linter-jshint.executablePath', (executablePath) => {
this.executablePath = executablePath;
}));
this.subscriptions.add(
atom.config.observe('linter-jshint.disableWhenNoJshintrcFileInPath',
(disableWhenNoJshintrcFileInPath) => {
this.disableWhenNoJshintrcFileInPath = disableWhenNoJshintrcFileInPath;
},
),
);

this.subscriptions.add(atom.config.observe('linter-jshint.jshintFileName', (jshintFileName) => {
this.jshintFileName = jshintFileName;
}));

const scopeEmbedded = 'source.js.embedded.html';
this.subscriptions.add(atom.config.observe('linter-jshint.lintInlineJavaScript',
(lintInlineJavaScript) => {
this.lintInlineJavaScript = lintInlineJavaScript;
if (lintInlineJavaScript) {
this.subscriptions.add(
atom.config.observe('linter-jshint.executablePath', (value) => {
this.executablePath = value;
}),
atom.config.observe('linter-jshint.disableWhenNoJshintrcFileInPath', (value) => {
this.disableWhenNoJshintrcFileInPath = value;
}),
atom.config.observe('linter-jshint.jshintFileName', (value) => {
this.jshintFileName = value;
}),
atom.config.observe('linter-jshint.jshintignoreFilename', (value) => {
this.jshintignoreFilename = value;
}),
atom.config.observe('linter-jshint.lintInlineJavaScript', (value) => {
const scopeEmbedded = 'source.js.embedded.html';
this.lintInlineJavaScript = value;
if (value) {
this.scopes.push(scopeEmbedded);
} else if (this.scopes.indexOf(scopeEmbedded) !== -1) {
this.scopes.splice(this.scopes.indexOf(scopeEmbedded), 1);
}
},
));
}),
);
},

deactivate() {
@@ -81,27 +97,42 @@ module.exports = {
lint: async (textEditor: TextEditor) => {
const results = [];
const filePath = textEditor.getPath();
const fileDir = Path.dirname(filePath);
const fileContents = textEditor.getText();
const parameters = ['--reporter', Reporter, '--filename', filePath];

const configFile = await Helpers.findCachedAsync(
Path.dirname(filePath), this.jshintFileName,
);
const configFile = await Helpers.findCachedAsync(fileDir, this.jshintFileName);

if (configFile) {
parameters.push('--config', configFile);
} else if (this.disableWhenNoJshintrcFileInPath) {
return results;
}

const ignoreFile = await Helpers.findCachedAsync(fileDir, this.jshintignoreFilename);

if (ignoreFile) {
// JSHint completely ignores .jshintignore files for STDIN on it's own
// so we must re-implement the functionality
const ignoreList = await readIgnoreList(ignoreFile);
if (ignoreList.some(pattern => minimatch(filePath, pattern))) {
// The file is ignored by one of the patterns
return [];
}
}

if (this.lintInlineJavaScript &&
textEditor.getGrammar().scopeName.indexOf('text.html') !== -1
) {
parameters.push('--extract', 'always');
}
parameters.push('-');

const execOpts = { stdin: fileContents, ignoreExitCode: true };
const execOpts = {
stdin: fileContents,
ignoreExitCode: true,
cwd: fileDir,
};
const result = await Helpers.execNode(
this.executablePath, parameters, execOpts,
);
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -16,7 +16,8 @@
"atom-linter": "^10.0.0",
"atom-package-deps": "^4.0.1",
"jshint": "2.9.4",
"jshint-json": "^1.0.0"
"jshint-json": "^1.0.0",
"minimatch": "^3.0.3"
},
"devDependencies": {
"babel-eslint": "^7.2.3",

0 comments on commit 96b6436

Please sign in to comment.