Bug 1347709 - Allow modules.json to be loaded from a local version for out-of-tree uses of eslint-plugin-mozilla. r?Mossop
MozReview-Commit-ID: 7RzAUqNJQ15
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js
@@ -14,17 +14,17 @@
// -----------------------------------------------------------------------------
var fs = require("fs");
var path = require("path");
var helpers = require("../helpers");
var globals = require("../globals");
var placesGlobals = require("./places-overlay").globals;
-const rootDir = helpers.getRootDir(module.filename);
+const rootDir = helpers.rootDir;
// These are scripts not included in global-scripts.inc, but which are loaded
// via overlays.
const EXTRA_SCRIPTS = [
"browser/base/content/nsContextMenu.js",
"toolkit/content/contentAreaUtils.js",
"browser/components/places/content/editBookmarkOverlay.js",
"browser/components/downloads/content/downloads.js",
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/places-overlay.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/places-overlay.js
@@ -11,19 +11,17 @@
"use strict";
// -----------------------------------------------------------------------------
// Rule Definition
// -----------------------------------------------------------------------------
var path = require("path");
var helpers = require("../helpers");
var globals = require("../globals");
-var root = helpers.getRootDir(module.filename);
-var modules = require(path.join(root,
- "tools", "lint", "eslint", "modules.json"));
+var modules = helpers.modulesGlobalData;
const placesOverlayFiles = [
"toolkit/content/globalOverlay.js",
"browser/base/content/utilityOverlay.js",
"browser/components/places/content/controller.js",
"browser/components/places/content/treeView.js"
];
@@ -43,17 +41,17 @@ const extraPlacesDefinitions = [
const placesOverlayModules = [
"PlacesUtils.jsm"
];
function getScriptGlobals() {
let fileGlobals = [];
for (let file of placesOverlayFiles) {
- let fileName = path.join(root, file);
+ let fileName = path.join(helpers.rootDir, file);
try {
fileGlobals = fileGlobals.concat(globals.getGlobalsForFile(fileName));
} catch (e) {
// The file isn't present, this is probably not an m-c repo.
}
}
for (let file of placesOverlayModules) {
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/simpletest.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/simpletest.js
@@ -22,17 +22,17 @@ const simpleTestFiles = [
"MockObjects.js",
"SimpleTest.js",
"WindowSnapshot.js"
];
const simpleTestPath = "testing/mochitest/tests/SimpleTest";
function getScriptGlobals() {
let fileGlobals = [];
- let root = helpers.getRootDir(module.filename);
+ let root = helpers.rootDir;
for (let file of simpleTestFiles) {
let fileName = path.join(root, simpleTestPath, file);
try {
fileGlobals = fileGlobals.concat(globals.getGlobalsForFile(fileName));
} catch (e) {
// The files may not be available in non-m-c repositories.
return [];
}
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/globals.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/globals.js
@@ -72,17 +72,16 @@ var globalDiscoveryInProgressForFiles =
* Each returns an array of globals found.
*
* @param {String} filePath
* The absolute path of the file being parsed.
*/
function GlobalsForNode(filePath) {
this.path = filePath;
this.dirname = path.dirname(this.path);
- this.root = helpers.getRootDir(this.path);
}
GlobalsForNode.prototype = {
BlockComment(node, parents) {
let value = node.value.trim();
let match = /^import-globals-from\s+(.+)$/.exec(value);
if (!match) {
return [];
@@ -94,28 +93,28 @@ GlobalsForNode.prototype = {
filePath = path.resolve(this.dirname, filePath);
}
return module.exports.getGlobalsForFile(filePath);
},
ExpressionStatement(node, parents, globalScope) {
let isGlobal = helpers.getIsGlobalScope(parents);
- let globals = helpers.convertExpressionToGlobals(node, isGlobal, this.root);
+ let globals = helpers.convertExpressionToGlobals(node, isGlobal);
// Map these globals now, as getGlobalsForFile is pre-mapped.
globals = globals.map(name => {
return { name, writable: true };
});
// Here we assume that if importScripts is set in the global scope, then
// this is a worker. It would be nice if eslint gave us a way of getting
// the environment directly.
if (globalScope && globalScope.set.get("importScripts")) {
let workerDetails = helpers.convertWorkerExpressionToGlobals(node,
- isGlobal, this.root, this.dirname);
+ isGlobal, this.dirname);
globals = globals.concat(workerDetails);
}
return globals;
}
};
module.exports = {
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/helpers.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/helpers.js
@@ -7,17 +7,18 @@
"use strict";
var espree = require("espree");
var estraverse = require("estraverse");
var path = require("path");
var fs = require("fs");
var ini = require("ini-parser");
-var modules = null;
+var gModules = null;
+var gRootDir = null;
var directoryManifests = new Map();
var definitions = [
/^loader\.lazyGetter\(this, "(\w+)"/,
/^loader\.lazyImporter\(this, "(\w+)"/,
/^loader\.lazyServiceGetter\(this, "(\w+)"/,
/^loader\.lazyRequireGetter\(this, "(\w+)"/,
/^XPCOMUtils\.defineLazyGetter\(this, "(\w+)"/,
@@ -35,16 +36,28 @@ var definitions = [
var imports = [
/^(?:Cu|Components\.utils)\.import\(".*\/((.*?)\.jsm?)"(?:, this)?\)/
];
var workerImportFilenameMatch = /(.*\/)*(.*?\.jsm?)/;
module.exports = {
+ get modulesGlobalData() {
+ if (!gModules) {
+ if (this.isMozillaCentralBased()) {
+ gModules = require(path.join(this.rootDir, "tools", "lint", "eslint", "modules.json"));
+ } else {
+ gModules = require("./modules.json");
+ }
+ }
+
+ return gModules;
+ },
+
/**
* Gets the abstract syntax tree (AST) of the JavaScript source code contained
* in sourceText.
*
* @param {String} sourceText
* Text containing valid JavaScript.
*
* @return {Object}
@@ -163,34 +176,28 @@ module.exports = {
/**
* Attempts to convert an ExpressionStatement to likely global variable
* definitions.
*
* @param {Object} node
* The AST node to convert.
* @param {boolean} isGlobal
* True if the current node is in the global scope.
- * @param {String} repository
- * The root of the repository.
*
* @return {Array}
* An array of objects that contain details about the globals:
* - {String} name
* The name of the global.
* - {Boolean} writable
* If the global is writeable or not.
*/
- convertWorkerExpressionToGlobals(node, isGlobal, repository,
- dirname) {
+ convertWorkerExpressionToGlobals(node, isGlobal, dirname) {
var getGlobalsForFile = require("./globals").getGlobalsForFile;
- if (!modules) {
- modules = require(path.join(repository,
- "tools", "lint", "eslint", "modules.json"));
- }
+ let globalModules = this.modulesGlobalData;
let results = [];
let expr = node.expression;
if (node.expression.type === "CallExpression" &&
expr.callee &&
expr.callee.type === "Identifier" &&
expr.callee.name === "importScripts") {
@@ -198,34 +205,29 @@ module.exports = {
var match = arg.value.match(workerImportFilenameMatch);
if (match) {
if (!match[1]) {
let filePath = path.resolve(dirname, match[2]);
if (fs.existsSync(filePath)) {
let additionalGlobals = getGlobalsForFile(filePath);
results = results.concat(additionalGlobals);
}
- } else if (match[2] in modules) {
- results = results.concat(modules[match[2]].map(name => {
+ } else if (match[2] in globalModules) {
+ results = results.concat(globalModules[match[2]].map(name => {
return { name, writable: true };
}));
}
}
}
}
return results;
},
- convertExpressionToGlobals(node, isGlobal, repository) {
- if (!modules) {
- modules = require(path.join(repository,
- "tools", "lint", "eslint", "modules.json"));
- }
-
+ convertExpressionToGlobals(node, isGlobal) {
try {
var source = this.getASTSource(node);
} catch (e) {
return [];
}
for (var reg of definitions) {
let match = source.match(reg);
@@ -234,26 +236,28 @@ module.exports = {
if (!isGlobal) {
return [];
}
return [match[1]];
}
}
+ let globalModules = this.modulesGlobalData;
+
for (reg of imports) {
let match = source.match(reg);
if (match) {
// The two argument form is only acceptable in the global scope
if (node.expression.arguments.length > 1 && !isGlobal) {
return [];
}
- if (match[1] in modules) {
- return modules[match[1]];
+ if (match[1] in globalModules) {
+ return globalModules[match[1]];
}
return [match[2]];
}
}
return [];
},
@@ -508,35 +512,36 @@ module.exports = {
getIsWorker(filePath) {
let filename = path.basename(this.cleanUpPath(filePath)).toLowerCase();
return filename.includes("worker");
},
/**
- * Gets the root directory of the repository by walking up directories until
- * a .eslintignore file is found.
- * @param {String} fileName
- * The absolute path of a file in the repository
- *
+ * Gets the root directory of the repository by walking up directories from
+ * this file until a .eslintignore file is found.
* @return {String} The absolute path of the repository directory
*/
- getRootDir(fileName) {
- var dirName = path.dirname(fileName);
+ get rootDir() {
+ if (!gRootDir) {
+ let dirName = path.dirname(module.filename);
- while (dirName && !fs.existsSync(path.join(dirName, ".eslintignore"))) {
- dirName = path.dirname(dirName);
+ while (dirName && !fs.existsSync(path.join(dirName, ".eslintignore"))) {
+ dirName = path.dirname(dirName);
+ }
+
+ if (!dirName) {
+ throw new Error("Unable to find root of repository");
+ }
+
+ gRootDir = dirName;
}
- if (!dirName) {
- throw new Error("Unable to find root of repository");
- }
-
- return dirName;
+ return gRootDir;
},
/**
* ESLint may be executed from various places: from mach, at the root of the
* repository, or from a directory in the repository when, for instance,
* executed by a text editor's plugin.
* The value returned by context.getFileName() varies because of this.
* This helper function makes sure to return an absolute file path for the
@@ -571,17 +576,17 @@ module.exports = {
* context.getFileName contain leading and trailing double-quote characters.
* These characters need to be removed.
*/
cleanUpPath(pathName) {
return pathName.replace(/^"/, "").replace(/"$/, "");
},
get globalScriptsPath() {
- return path.join(this.getRootDir(module.filename), "browser",
+ return path.join(this.rootDir, "browser",
"base", "content", "global-scripts.inc");
},
isMozillaCentralBased() {
return fs.existsSync(this.globalScriptsPath);
},
getSavedEnvironmentItems(environment) {
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-browser-window-globals.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-browser-window-globals.js
@@ -20,17 +20,17 @@ var browserWindowEnv = require("../envir
module.exports = function(context) {
// ---------------------------------------------------------------------------
// Public
// ---------------------------------------------------------------------------
return {
Program(node) {
let filePath = helpers.getAbsoluteFilePath(context);
- let relativePath = path.relative(helpers.getRootDir(filePath), filePath);
+ let relativePath = path.relative(helpers.rootDir, filePath);
if (browserWindowEnv.browserjsScripts &&
browserWindowEnv.browserjsScripts.includes(relativePath)) {
for (let global in browserWindowEnv.globals) {
helpers.addVarToScope(global, context.getScope(),
browserWindowEnv.globals[global]);
}
}
--- a/tools/lint/eslint/eslint-plugin-mozilla/package.json
+++ b/tools/lint/eslint/eslint-plugin-mozilla/package.json
@@ -1,11 +1,11 @@
{
"name": "eslint-plugin-mozilla",
- "version": "0.2.37",
+ "version": "0.2.38",
"description": "A collection of rules that help enforce JavaScript coding standard in the Mozilla project.",
"keywords": [
"eslint",
"eslintplugin",
"eslint-plugin",
"mozilla",
"firefox"
],
@@ -27,12 +27,13 @@
"ini-parser": "^0.0.2",
"sax": "^1.2.2"
},
"engines": {
"node": ">=6.9.1"
},
"scripts": {
"prepublishOnly": "node scripts/createExports.js",
- "test": "node tests/test-run-all.js"
+ "test": "node tests/test-run-all.js",
+ "postpublish": "rm -f lib/modules.json lib/environments/saved-globals.json"
},
"license": "MPL-2.0"
}
--- a/tools/lint/eslint/eslint-plugin-mozilla/scripts/createExports.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/scripts/createExports.js
@@ -5,20 +5,30 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
"use strict";
var fs = require("fs");
var path = require("path");
var helpers = require("../lib/helpers");
-const globalsFile = path.join(helpers.getRootDir(module.filename),
- "tools", "lint", "eslint", "eslint-plugin-mozilla",
+const eslintDir = path.join(helpers.getRootDir(module.filename),
+ "tools", "lint", "eslint");
+
+const globalsFile = path.join(eslintDir, "eslint-plugin-mozilla",
"lib", "environments", "saved-globals.json");
+console.log("Copying modules.json");
+
+const modulesFile = path.join(eslintDir, "modules.json");
+const shipModulesFile = path.join(eslintDir, "eslint-plugin-mozilla", "lib",
+ "modules.json");
+
+fs.writeFileSync(shipModulesFile, fs.readFileSync(modulesFile));
+
console.log("Generating globals file");
// We only export the configs section.
let environmentGlobals = require("../lib/index.js").environments;
return fs.writeFile(globalsFile, JSON.stringify({environments: environmentGlobals}), err => {
if (err) {
console.error(err);