Skip to content
This repository has been archived by the owner on Sep 6, 2021. It is now read-only.

add ESLint as a default Brackets extension #11988

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .brackets.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"defaultExtension": "js",
"language": {
"javascript": {
"linting.prefer": ["ESLint", "JSLint"],
"linting.prefer": ["ESLint"],
"linting.usePreferredOnly": true
}
},
Expand Down
6 changes: 3 additions & 3 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@
"new-parens": 2,
"no-new-object": 2,
"no-invalid-this": 0,
indent: [0, 4],
indent: [2, 4],

"valid-jsdoc": 0,
"valid-typeof": 2,

"no-trailing-spaces": 0,
"eol-last": 0
"no-trailing-spaces": [2, { "skipBlankLines": true }],
"eol-last": 2
},
"globals": {
"brackets": false,
Expand Down
155 changes: 155 additions & 0 deletions src/extensions/default/ESLint/domain.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*eslint no-process-env:0*/
/*global require, exports*/

(function () {
'use strict';

var fs = require('fs');
var CLIEngine = require('eslint').CLIEngine;
var cli = new CLIEngine();
var currentProjectRoot = null;
var domainName = 'brackets-eslint';
var domainManager = null;
var globalPackagesAvailable = false;

function _setProjectRoot(projectRoot) {
var opts = { useEslintrc: true };
var configPath;
var rulesDirPath;
var ignorePath;

if (projectRoot) {
try {
var dirContent = fs.readdirSync(projectRoot);
dirContent = dirContent.filter(function (entry) {
return /^\.eslintrc(\.(js|yaml|yml|json))?$/.test(entry);
});
if (dirContent.length === 0) {
throw new Error('no config file found!');
}
} catch (e) {
// config file not found, use default
opts.rules = require('eslint/conf/eslint.json').rules;
}

rulesDirPath = projectRoot + '.eslintrules';
try {
if (fs.statSync(rulesDirPath).isDirectory()) {
opts.rulePaths = [rulesDirPath];
}
} catch (err) {
// ignore err
}

ignorePath = projectRoot + '.eslintignore';
try {
if (fs.statSync(ignorePath).isFile()) {
opts.ignore = true;
opts.ignorePath = ignorePath;
}
} catch (err) {
// ignore err
}
}

cli = new CLIEngine(opts);
}

require('enable-global-packages').on('ready', function () {
// global packages are available now
_setProjectRoot(currentProjectRoot);
globalPackagesAvailable = true;
});

function lintFile(fullPath, projectRoot, callback) {
if (!globalPackagesAvailable) {
setTimeout(function () {
lintFile(fullPath, projectRoot, callback);
}, 250);
return;
}
if (projectRoot !== currentProjectRoot) {
_setProjectRoot(projectRoot);
currentProjectRoot = projectRoot;
}
fs.readFile(fullPath, {encoding: 'utf8'}, function (err, text) {
if (err) {
return callback(err);
}
var relativePath = fullPath.indexOf(projectRoot) === 0 ? fullPath.substring(projectRoot.length) : fullPath;

// this is important for ESLint so .eslintrc is properly loaded
// we could go around this by parsing .eslintrc manually but that'd
// bring complexity we don't need here right now
// related: https://github.com/eslint/eslint/issues/4472
process.chdir(projectRoot);

var res;
try {
res = cli.executeOnText(text, relativePath);
} catch (e) {
err = e.toString();
}
callback(err, res);
});
}

function configFileModified(projectRoot) {
_setProjectRoot(projectRoot);
currentProjectRoot = projectRoot;
}

exports.init = function (_domainManager) {
domainManager = _domainManager;

if (!domainManager.hasDomain(domainName)) {
domainManager.registerDomain(domainName, {
major: 0,
minor: 1
});
}

domainManager.registerCommand(
domainName,
'lintFile', // command name
lintFile, // handler function
true, // is async
'lint given file with eslint', // description
[
{
name: 'fullPath',
type: 'string'
},
{
name: 'projectRoot',
type: 'string'
}
], [
{
name: 'report',
type: 'object'
}
]
);

domainManager.registerCommand(
domainName,
'configFileModified',
configFileModified,
false,
'notify that config file was modified',
[
{
name: 'projectRoot',
type: 'string'
}
], [
{
name: 'result',
type: 'boolean'
}
]
);
};

}());
76 changes: 76 additions & 0 deletions src/extensions/default/ESLint/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*global $, brackets, define*/

define(function (require, exports, module) {
'use strict';

// imports
var CodeInspection = brackets.getModule('language/CodeInspection');
var LanguageManager = brackets.getModule('language/LanguageManager');
var ProjectManager = brackets.getModule('project/ProjectManager');
var ExtensionUtils = brackets.getModule('utils/ExtensionUtils');
var NodeDomain = brackets.getModule('utils/NodeDomain');
var FileSystem = brackets.getModule("filesystem/FileSystem");

// constants
var JS_LANGUAGE = LanguageManager.getLanguageForExtension('js');
var LINTER_NAME = 'ESLint';
var nodeDomain = new NodeDomain('brackets-eslint', ExtensionUtils.getModulePath(module, 'domain'));

// this will map ESLint output to match format expected by Brackets
function remapResults(results) {
return {
errors: results.map(function (result) {
var message = result.message;
if (result.ruleId) {
message += ' [' + result.ruleId + ']';
}
return {
message: message,
pos: {
line: result.line - 1,
ch: result.column
},
type: result.ruleId
};
})
};
}

function handleLintSync(text, fullPath) {
throw new Error('ESLint sync is not available, use async for ' + fullPath);
}

function handleLintAsync(text, fullPath) {
var deferred = new $.Deferred();
var projectRoot = ProjectManager.getProjectRoot().fullPath;

nodeDomain.exec('lintFile', fullPath, projectRoot)
.then(function (report) {
if (report.results.length > 1) {
console.warn('ESLint returned multiple results, where only one set was expected');
}
var results = report.results[0];
var remapped = remapResults(results.messages);
deferred.resolve(remapped);
}, function (err) {
deferred.reject(err);
});

return deferred.promise();
}

FileSystem.on("change", function (evt, file) {
if (/^\.eslintrc(\.(js|yaml|yml|json))?$/.test(file.name)) {
var projectRoot = ProjectManager.getProjectRoot().fullPath;
nodeDomain.exec('configFileModified', projectRoot);
}
});

// register a linter with CodeInspection
CodeInspection.register(JS_LANGUAGE.getId(), {
name: LINTER_NAME,
scanFile: handleLintSync,
scanFileAsync: handleLintAsync
});

});
15 changes: 15 additions & 0 deletions src/extensions/default/ESLint/node_modules/.bin/eslint

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions src/extensions/default/ESLint/node_modules/.bin/eslint.cmd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions src/extensions/default/ESLint/node_modules/.bin/esparse

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions src/extensions/default/ESLint/node_modules/.bin/esparse.cmd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions src/extensions/default/ESLint/node_modules/.bin/esvalidate

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions src/extensions/default/ESLint/node_modules/.bin/handlebars

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions src/extensions/default/ESLint/node_modules/.bin/js-yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions src/extensions/default/ESLint/node_modules/.bin/js-yaml.cmd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions src/extensions/default/ESLint/node_modules/.bin/mkdirp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading