Bug 1561435 - Format tools/, a=automatic-formatting

# ignore-this-changeset

Differential Revision: https://phabricator.services.mozilla.com/D35940

--HG--
extra : source : d214f0c82813e5a8d3987debc490a2c11f1308ff
This commit is contained in:
Victor Porof 2019-07-05 11:18:19 +02:00
Родитель 336c4fb8a4
Коммит 5c7cdbd4ba
88 изменённых файлов: 2499 добавлений и 1910 удалений

Просмотреть файл

@ -45,7 +45,6 @@ module.exports = {
"overrides": [{
"files": [
"devtools/**",
"tools/**",
"uriloader/**",
"view/**",
"widget/**",

Просмотреть файл

@ -40,7 +40,6 @@ toolkit/components/telemetry/datareporting-prefs.js
toolkit/components/telemetry/healthreport-prefs.js
# Ignore all top-level directories for now.
tools/**
uriloader/**
view/**
widget/**

Просмотреть файл

@ -8,9 +8,11 @@
var EXPORTED_SYMBOLS = ["PerTestCoverageUtils"];
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
const env = Cc["@mozilla.org/process/environment;1"].getService(
Ci.nsIEnvironment
);
// This is the directory where gcov is emitting the gcda files.
const gcovPrefixPath = env.get("GCOV_PREFIX");
// This is the directory where codecoverage.py is expecting to see the gcda files.
@ -20,7 +22,9 @@ const jsvmPrefixPath = env.get("JS_CODE_COVERAGE_OUTPUT_DIR");
// This is the directory where codecoverage.py is expecting to see the lcov files.
const jsvmResultsPath = env.get("JSVM_RESULTS_DIR");
const gcovPrefixDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
const gcovPrefixDir = Cc["@mozilla.org/file/local;1"].createInstance(
Ci.nsIFile
);
if (gcovPrefixPath) {
gcovPrefixDir.initWithPath(gcovPrefixPath);
}
@ -30,7 +34,9 @@ if (gcovResultsPath) {
gcovResultsDir.initWithPath(gcovResultsPath);
}
const jsvmPrefixDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
const jsvmPrefixDir = Cc["@mozilla.org/file/local;1"].createInstance(
Ci.nsIFile
);
if (jsvmPrefixPath) {
jsvmPrefixDir.initWithPath(jsvmPrefixPath);
}
@ -44,10 +50,12 @@ function awaitPromise(promise) {
let ret;
let complete = false;
let error = null;
promise.catch(e => error = e).then(v => {
ret = v;
complete = true;
});
promise
.catch(e => (error = e))
.then(v => {
ret = v;
complete = true;
});
Services.tm.spinEventLoopUntil(() => complete);
if (error) {
throw new Error(error);
@ -77,7 +85,9 @@ var PerTestCoverageUtils = class PerTestCoverageUtilsClass {
}
// Flush the counters.
let codeCoverageService = Cc["@mozilla.org/tools/code-coverage;1"].getService(Ci.nsICodeCoverage);
let codeCoverageService = Cc[
"@mozilla.org/tools/code-coverage;1"
].getService(Ci.nsICodeCoverage);
await codeCoverageService.flushCounters();
// Remove coverage files created by the flush, and those that might have been created between the end of a previous test and the beginning of the next one (e.g. some tests can create a new content process for every sub-test).
@ -100,7 +110,9 @@ var PerTestCoverageUtils = class PerTestCoverageUtilsClass {
}
// Flush the counters.
let codeCoverageService = Cc["@mozilla.org/tools/code-coverage;1"].getService(Ci.nsICodeCoverage);
let codeCoverageService = Cc[
"@mozilla.org/tools/code-coverage;1"
].getService(Ci.nsICodeCoverage);
await codeCoverageService.flushCounters();
// Move the coverage files in GCOV_RESULTS_DIR and JSVM_RESULTS_DIR, so that the execution from now to shutdown (or next test) is not counted.

Просмотреть файл

@ -2,15 +2,21 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
var {OS, require} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
var { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
var { OS, require } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
function getFiles() {
const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
const env = Cc["@mozilla.org/process/environment;1"].getService(
Ci.nsIEnvironment
);
// This is the directory where gcov is emitting the gcda files.
const jsCoveragePath = env.get("JS_CODE_COVERAGE_OUTPUT_DIR");
const jsCoverageDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
const jsCoverageDir = Cc["@mozilla.org/file/local;1"].createInstance(
Ci.nsIFile
);
jsCoverageDir.initWithPath(jsCoveragePath);
let files = [];
@ -47,9 +53,9 @@ function parseRecords(files) {
let [hits, name] = recordContent.split(",");
currentSF.push({
"type": "FNDA",
"hits": hits,
"name": name,
type: "FNDA",
hits,
name,
});
break;
}
@ -61,8 +67,8 @@ function parseRecords(files) {
let name = recordContent.split(",")[1];
currentSF.push({
"type": "FN",
"name": name,
type: "FN",
name,
});
break;
}

Просмотреть файл

@ -29,19 +29,41 @@ async function run_test() {
await codeCoverage.flushCounters();
const first_flush_files = getFiles();
const first_flush_records = parseRecords(diffFiles(first_flush_files, files_orig));
const first_flush_records = parseRecords(
diffFiles(first_flush_files, files_orig)
);
Assert.ok(first_flush_records.has("test_basic.js"));
let fnRecords = first_flush_records.get("test_basic.js").filter(record => record.type == "FN");
let fndaRecords = first_flush_records.get("test_basic.js").filter(record => record.type == "FNDA");
let fnRecords = first_flush_records
.get("test_basic.js")
.filter(record => record.type == "FN");
let fndaRecords = first_flush_records
.get("test_basic.js")
.filter(record => record.type == "FNDA");
Assert.ok(fnRecords.some(record => record.name == "top-level"));
Assert.ok(fnRecords.some(record => record.name == "run_test"));
Assert.ok(fnRecords.some(record => record.name == "test_code_coverage_func1"));
Assert.ok(fndaRecords.some(record => record.name == "run_test" && record.hits == 1));
Assert.ok(!fndaRecords.some(record => record.name == "run_test" && record.hits != 1));
Assert.ok(fndaRecords.some(record => record.name == "test_code_coverage_func1" && record.hits == 1));
Assert.ok(!fndaRecords.some(record => record.name == "test_code_coverage_func1" && record.hits != 1));
Assert.ok(!fndaRecords.some(record => record.name == "test_code_coverage_func2"));
Assert.ok(
fnRecords.some(record => record.name == "test_code_coverage_func1")
);
Assert.ok(
fndaRecords.some(record => record.name == "run_test" && record.hits == 1)
);
Assert.ok(
!fndaRecords.some(record => record.name == "run_test" && record.hits != 1)
);
Assert.ok(
fndaRecords.some(
record => record.name == "test_code_coverage_func1" && record.hits == 1
)
);
Assert.ok(
!fndaRecords.some(
record => record.name == "test_code_coverage_func1" && record.hits != 1
)
);
Assert.ok(
!fndaRecords.some(record => record.name == "test_code_coverage_func2")
);
test_code_coverage_func2();
@ -49,19 +71,45 @@ async function run_test() {
await codeCoverage.flushCounters();
const second_flush_files = getFiles();
const second_flush_records = parseRecords(diffFiles(second_flush_files, first_flush_files));
const second_flush_records = parseRecords(
diffFiles(second_flush_files, first_flush_files)
);
Assert.ok(second_flush_records.has("test_basic.js"));
fnRecords = second_flush_records.get("test_basic.js").filter(record => record.type == "FN");
fndaRecords = second_flush_records.get("test_basic.js").filter(record => record.type == "FNDA");
fnRecords = second_flush_records
.get("test_basic.js")
.filter(record => record.type == "FN");
fndaRecords = second_flush_records
.get("test_basic.js")
.filter(record => record.type == "FNDA");
Assert.ok(fnRecords.some(record => record.name == "top-level"));
Assert.ok(fnRecords.some(record => record.name == "run_test"));
Assert.ok(fnRecords.some(record => record.name == "test_code_coverage_func1"));
Assert.ok(fnRecords.some(record => record.name == "test_code_coverage_func2"));
Assert.ok(fndaRecords.some(record => record.name == "test_code_coverage_func1" && record.hits == 0));
Assert.ok(!fndaRecords.some(record => record.name == "test_code_coverage_func1" && record.hits != 0));
Assert.ok(fndaRecords.some(record => record.name == "test_code_coverage_func2" && record.hits == 1));
Assert.ok(!fndaRecords.some(record => record.name == "test_code_coverage_func2" && record.hits != 1));
Assert.ok(
fnRecords.some(record => record.name == "test_code_coverage_func1")
);
Assert.ok(
fnRecords.some(record => record.name == "test_code_coverage_func2")
);
Assert.ok(
fndaRecords.some(
record => record.name == "test_code_coverage_func1" && record.hits == 0
)
);
Assert.ok(
!fndaRecords.some(
record => record.name == "test_code_coverage_func1" && record.hits != 0
)
);
Assert.ok(
fndaRecords.some(
record => record.name == "test_code_coverage_func2" && record.hits == 1
)
);
Assert.ok(
!fndaRecords.some(
record => record.name == "test_code_coverage_func2" && record.hits != 1
)
);
do_test_finished();
}

Просмотреть файл

@ -10,7 +10,9 @@ async function run_test() {
do_load_child_test_harness();
do_test_pending();
const codeCoverage = Cc["@mozilla.org/tools/code-coverage;1"].getService(Ci.nsICodeCoverage);
const codeCoverage = Cc["@mozilla.org/tools/code-coverage;1"].getService(
Ci.nsICodeCoverage
);
const files_orig = getFiles();
@ -19,44 +21,100 @@ async function run_test() {
await codeCoverage.flushCounters();
const first_flush_files = getFiles();
const first_flush_records = parseRecords(diffFiles(first_flush_files, files_orig));
const first_flush_records = parseRecords(
diffFiles(first_flush_files, files_orig)
);
Assert.ok(first_flush_records.has("test_basic_child_and_parent.js"));
Assert.ok(!first_flush_records.has("support.js"));
let fnRecords = first_flush_records.get("test_basic_child_and_parent.js").filter(record => record.type == "FN");
let fndaRecords = first_flush_records.get("test_basic_child_and_parent.js").filter(record => record.type == "FNDA");
let fnRecords = first_flush_records
.get("test_basic_child_and_parent.js")
.filter(record => record.type == "FN");
let fndaRecords = first_flush_records
.get("test_basic_child_and_parent.js")
.filter(record => record.type == "FNDA");
Assert.ok(fnRecords.some(record => record.name == "top-level"));
Assert.ok(fnRecords.some(record => record.name == "run_test"));
Assert.ok(fnRecords.some(record => record.name == "test_code_coverage_func1"));
Assert.ok(fndaRecords.some(record => record.name == "run_test" && record.hits == 1));
Assert.ok(!fndaRecords.some(record => record.name == "run_test" && record.hits != 1));
Assert.ok(fndaRecords.some(record => record.name == "test_code_coverage_func1" && record.hits == 1));
Assert.ok(!fndaRecords.some(record => record.name == "test_code_coverage_func1" && record.hits != 1));
Assert.ok(
fnRecords.some(record => record.name == "test_code_coverage_func1")
);
Assert.ok(
fndaRecords.some(record => record.name == "run_test" && record.hits == 1)
);
Assert.ok(
!fndaRecords.some(record => record.name == "run_test" && record.hits != 1)
);
Assert.ok(
fndaRecords.some(
record => record.name == "test_code_coverage_func1" && record.hits == 1
)
);
Assert.ok(
!fndaRecords.some(
record => record.name == "test_code_coverage_func1" && record.hits != 1
)
);
sendCommand("load('support.js');", async function() {
await codeCoverage.flushCounters();
await codeCoverage.flushCounters();
const second_flush_files = getFiles();
const second_flush_records = parseRecords(diffFiles(second_flush_files, first_flush_files));
const second_flush_files = getFiles();
const second_flush_records = parseRecords(
diffFiles(second_flush_files, first_flush_files)
);
Assert.ok(second_flush_records.has("test_basic_child_and_parent.js"));
fnRecords = second_flush_records.get("test_basic_child_and_parent.js").filter(record => record.type == "FN");
fndaRecords = second_flush_records.get("test_basic_child_and_parent.js").filter(record => record.type == "FNDA");
Assert.ok(fnRecords.some(record => record.name == "top-level"));
Assert.ok(fnRecords.some(record => record.name == "run_test"));
Assert.ok(fnRecords.some(record => record.name == "test_code_coverage_func1"));
Assert.ok(fndaRecords.some(record => record.name == "test_code_coverage_func1" && record.hits == 0));
Assert.ok(!fndaRecords.some(record => record.name == "test_code_coverage_func1" && record.hits != 0));
Assert.ok(second_flush_records.has("support.js"));
fnRecords = second_flush_records.get("support.js").filter(record => record.type == "FN");
fndaRecords = second_flush_records.get("support.js").filter(record => record.type == "FNDA");
Assert.ok(fnRecords.some(record => record.name == "top-level"));
Assert.ok(fnRecords.some(record => record.name == "test_code_coverage_func2"));
Assert.ok(fndaRecords.some(record => record.name == "top-level" && record.hits == 1));
Assert.ok(!fndaRecords.some(record => record.name == "top-level" && record.hits != 1));
Assert.ok(fndaRecords.some(record => record.name == "test_code_coverage_func2" && record.hits == 1));
Assert.ok(!fndaRecords.some(record => record.name == "test_code_coverage_func2" && record.hits != 1));
Assert.ok(second_flush_records.has("test_basic_child_and_parent.js"));
fnRecords = second_flush_records
.get("test_basic_child_and_parent.js")
.filter(record => record.type == "FN");
fndaRecords = second_flush_records
.get("test_basic_child_and_parent.js")
.filter(record => record.type == "FNDA");
Assert.ok(fnRecords.some(record => record.name == "top-level"));
Assert.ok(fnRecords.some(record => record.name == "run_test"));
Assert.ok(
fnRecords.some(record => record.name == "test_code_coverage_func1")
);
Assert.ok(
fndaRecords.some(
record => record.name == "test_code_coverage_func1" && record.hits == 0
)
);
Assert.ok(
!fndaRecords.some(
record => record.name == "test_code_coverage_func1" && record.hits != 0
)
);
Assert.ok(second_flush_records.has("support.js"));
fnRecords = second_flush_records
.get("support.js")
.filter(record => record.type == "FN");
fndaRecords = second_flush_records
.get("support.js")
.filter(record => record.type == "FNDA");
Assert.ok(fnRecords.some(record => record.name == "top-level"));
Assert.ok(
fnRecords.some(record => record.name == "test_code_coverage_func2")
);
Assert.ok(
fndaRecords.some(record => record.name == "top-level" && record.hits == 1)
);
Assert.ok(
!fndaRecords.some(
record => record.name == "top-level" && record.hits != 1
)
);
Assert.ok(
fndaRecords.some(
record => record.name == "test_code_coverage_func2" && record.hits == 1
)
);
Assert.ok(
!fndaRecords.some(
record => record.name == "test_code_coverage_func2" && record.hits != 1
)
);
do_test_finished();
do_test_finished();
});
}

Просмотреть файл

@ -2,64 +2,62 @@
"use strict";
module.exports = {
"env": {
"browser": true,
env: {
browser: true,
"mozilla/browser-window": true,
"mozilla/simpletest": true,
// "node": true
},
// All globals made available in the test environment.
"globals": {
globals: {
// `$` is defined in SimpleTest.js
"$": false,
"Assert": false,
"BrowserTestUtils": false,
"ContentTask": false,
"ContentTaskUtils": false,
"EventUtils": false,
"PromiseDebugging": false,
"SpecialPowers": false,
"TestUtils": false,
"XPCNativeWrapper": false,
"XULDocument": false,
"addLoadEvent": false,
"add_task": false,
"content": false,
"executeSoon": false,
"expectUncaughtException": false,
"export_assertions": false,
"extractJarToTmp": false,
"finish": false,
"gTestPath": false,
"getChromeDir": false,
"getJar": false,
"getResolvedURI": false,
"getRootDirectory": false,
"getTestFilePath": false,
"ignoreAllUncaughtExceptions": false,
"info": false,
"is": false,
"isnot": false,
"ok": false,
"privateNoteIntentionalCrash": false,
"record": false,
"registerCleanupFunction": false,
"requestLongerTimeout": false,
"setExpectedFailuresForSelfTest": false,
"todo": false,
"todo_is": false,
"todo_isnot": false,
"waitForClipboard": false,
"waitForExplicitFinish": false,
"waitForFocus": false,
$: false,
Assert: false,
BrowserTestUtils: false,
ContentTask: false,
ContentTaskUtils: false,
EventUtils: false,
PromiseDebugging: false,
SpecialPowers: false,
TestUtils: false,
XPCNativeWrapper: false,
XULDocument: false,
addLoadEvent: false,
add_task: false,
content: false,
executeSoon: false,
expectUncaughtException: false,
export_assertions: false,
extractJarToTmp: false,
finish: false,
gTestPath: false,
getChromeDir: false,
getJar: false,
getResolvedURI: false,
getRootDirectory: false,
getTestFilePath: false,
ignoreAllUncaughtExceptions: false,
info: false,
is: false,
isnot: false,
ok: false,
privateNoteIntentionalCrash: false,
record: false,
registerCleanupFunction: false,
requestLongerTimeout: false,
setExpectedFailuresForSelfTest: false,
todo: false,
todo_is: false,
todo_isnot: false,
waitForClipboard: false,
waitForExplicitFinish: false,
waitForFocus: false,
},
"plugins": [
"mozilla",
],
plugins: ["mozilla"],
"rules": {
rules: {
"mozilla/import-content-task-globals": "error",
"mozilla/import-headjs-globals": "error",
"mozilla/mark-test-function-used": "error",

Просмотреть файл

@ -2,31 +2,31 @@
"use strict";
module.exports = {
"env": {
"browser": true,
env: {
browser: true,
"mozilla/browser-window": true,
},
// All globals made available in the test environment.
"globals": {
globals: {
// SpecialPowers is injected into the window object via SimpleTest.js
"SpecialPowers": false,
SpecialPowers: false,
},
"overrides": [{
"env": {
// Ideally we wouldn't be using the simpletest env here, but our uses of
// js files mean we pick up everything from the global scope, which could
// be any one of a number of html files. So we just allow the basics...
"mozilla/simpletest": true,
overrides: [
{
env: {
// Ideally we wouldn't be using the simpletest env here, but our uses of
// js files mean we pick up everything from the global scope, which could
// be any one of a number of html files. So we just allow the basics...
"mozilla/simpletest": true,
},
files: ["*.js"],
},
"files": ["*.js"],
}],
"plugins": [
"mozilla",
],
plugins: ["mozilla"],
rules: {
"mozilla/import-content-task-globals": "error",
"mozilla/import-headjs-globals": "error",

Просмотреть файл

@ -2,32 +2,32 @@
"use strict";
module.exports = {
"env": {
"browser": true,
env: {
browser: true,
},
// All globals made available in the test environment.
"globals": {
globals: {
// SpecialPowers is injected into the window object via SimpleTest.js
"SpecialPowers": false,
"XPCNativeWrapper": false,
SpecialPowers: false,
XPCNativeWrapper: false,
},
"overrides": [{
"env": {
// Ideally we wouldn't be using the simpletest env here, but our uses of
// js files mean we pick up everything from the global scope, which could
// be any one of a number of html files. So we just allow the basics...
"mozilla/simpletest": true,
overrides: [
{
env: {
// Ideally we wouldn't be using the simpletest env here, but our uses of
// js files mean we pick up everything from the global scope, which could
// be any one of a number of html files. So we just allow the basics...
"mozilla/simpletest": true,
},
files: ["*.js"],
},
"files": ["*.js"],
}],
"plugins": [
"mozilla",
],
"rules": {
plugins: ["mozilla"],
rules: {
"mozilla/import-content-task-globals": "error",
"mozilla/import-headjs-globals": "error",
"mozilla/mark-test-function-used": "error",

Просмотреть файл

@ -8,89 +8,88 @@
* https://eslint.org/docs/rules/
*/
module.exports = {
"env": {
"browser": true,
"es6": true,
env: {
browser: true,
es6: true,
"mozilla/privileged": true,
},
"extends": [
"eslint:recommended",
"plugin:prettier/recommended",
],
extends: ["eslint:recommended", "plugin:prettier/recommended"],
"globals": {
"Cc": false,
globals: {
Cc: false,
// Specific to Firefox (Chrome code only).
"ChromeUtils": false,
"Ci": false,
"Components": false,
"Cr": false,
"Cu": false,
"Debugger": false,
"InstallTrigger": false,
ChromeUtils: false,
Ci: false,
Components: false,
Cr: false,
Cu: false,
Debugger: false,
InstallTrigger: false,
// Specific to Firefox
// https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/InternalError
"InternalError": true,
"Intl": false,
"SharedArrayBuffer": false,
"StopIteration": false,
"dump": true,
InternalError: true,
Intl: false,
SharedArrayBuffer: false,
StopIteration: false,
dump: true,
// Override the "browser" env definition of "location" to allow writing as it
// is a writeable property.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1509270#c1 for more information.
"location": true,
"openDialog": false,
"saveStack": false,
"sizeToContent": false,
location: true,
openDialog: false,
saveStack: false,
sizeToContent: false,
// Specific to Firefox
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/uneval
"uneval": false,
uneval: false,
},
"overrides": [{
// Turn off use-services for xml files. XBL bindings are going away, and
// working out the valid globals for those is difficult.
"files": "**/*.xml",
"rules": {
"mozilla/use-services": "off",
overrides: [
{
// Turn off use-services for xml files. XBL bindings are going away, and
// working out the valid globals for those is difficult.
files: "**/*.xml",
rules: {
"mozilla/use-services": "off",
},
},
}, {
// We don't have the general browser environment for jsm files, but we do
// have our own special environments for them.
"env": {
"browser": false,
"mozilla/jsm": true,
{
// We don't have the general browser environment for jsm files, but we do
// have our own special environments for them.
env: {
browser: false,
"mozilla/jsm": true,
},
files: "**/*.jsm",
rules: {
"mozilla/mark-exported-symbols-as-used": "error",
// JSM modules are far easier to check for no-unused-vars on a global scope,
// than our content files. Hence we turn that on here.
"no-unused-vars": [
"error",
{
args: "none",
vars: "all",
},
],
},
},
"files": "**/*.jsm",
"rules": {
"mozilla/mark-exported-symbols-as-used": "error",
// JSM modules are far easier to check for no-unused-vars on a global scope,
// than our content files. Hence we turn that on here.
"no-unused-vars": ["error", {
"args": "none",
"vars": "all",
}],
},
}],
],
"parserOptions": {
"ecmaVersion": 9,
parserOptions: {
ecmaVersion: 9,
},
// When adding items to this file please check for effects on sub-directories.
"plugins": [
"html",
"fetch-options",
"no-unsanitized",
],
plugins: ["html", "fetch-options", "no-unsanitized"],
// When adding items to this file please check for effects on all of toolkit
// and browser
"rules": {
rules: {
// Warn about cyclomatic complexity in functions.
// XXX Get this down to 20?
"complexity": ["error", 34],
complexity: ["error", 34],
// Functions must always return something or nothing
"consistent-return": "error",
@ -100,7 +99,7 @@ module.exports = {
"constructor-super": "off",
// Require braces around blocks that start a new line
"curly": ["error", "all"],
curly: ["error", "all"],
// Encourage the use of dot notation whenever possible.
"dot-notation": "error",
@ -164,7 +163,7 @@ module.exports = {
"no-else-return": "error",
// No empty statements
"no-empty": ["error", {"allowEmptyCatch": true}],
"no-empty": ["error", { allowEmptyCatch: true }],
// Disallow eval and setInteral/setTimeout with strings
"no-eval": "error",
@ -189,7 +188,7 @@ module.exports = {
// Disallow the use of the __iterator__ property
"no-iterator": "error",
// No labels
// No labels
"no-labels": "error",
// Disallow unnecessary nested blocks
@ -238,10 +237,13 @@ module.exports = {
"no-unsanitized/property": "error",
// No declaring variables that are never used
"no-unused-vars": ["error", {
"args": "none",
"vars": "local",
}],
"no-unused-vars": [
"error",
{
args: "none",
vars: "local",
},
],
// No using variables before defined
// "no-use-before-define": ["error", "nofunc"],
@ -264,7 +266,7 @@ module.exports = {
"no-with": "error",
// Require object-literal shorthand with ES6 method syntax
"object-shorthand": ["error", "always", { "avoidQuotes": true }],
"object-shorthand": ["error", "always", { avoidQuotes: true }],
// XXX Bug 1487642 - decide if we want to enable this or not.
// Require generator functions to contain yield
@ -274,7 +276,7 @@ module.exports = {
// To avoid bad interactions of the html plugin with the xml preprocessor in
// eslint-plugin-mozilla, we turn off processing of the html plugin for .xml
// files.
"settings": {
"html/xml-extensions": [ ".xhtml" ],
settings: {
"html/xml-extensions": [".xhtml"],
},
};

Просмотреть файл

@ -3,80 +3,85 @@
module.exports = {
// All globals made available in the test environment.
"globals": {
"Assert": false,
"PromiseDebugging": false,
"_TEST_FILE": false,
"add_task": false,
"add_test": false,
globals: {
Assert: false,
PromiseDebugging: false,
_TEST_FILE: false,
add_task: false,
add_test: false,
// Test-only function.
"allocationMarker": false,
"byteSize": false,
"deepEqual": false,
"do_await_remote_message": false,
"do_check_instanceof": false,
"do_get_cwd": false,
"do_get_file": false,
"do_get_idle": false,
"do_get_profile": false,
"do_get_tempdir": false,
"do_load_child_test_harness": false,
"do_load_manifest": false,
"do_load_module": false,
"do_note_exception": false,
"do_parse_document": false,
"do_report_unexpected_exception": false,
"do_send_remote_message": false,
"do_test_finished": false,
"do_test_pending": false,
"do_throw": false,
"do_timeout": false,
"equal": false,
"executeSoon": false,
"gc": false,
allocationMarker: false,
byteSize: false,
deepEqual: false,
do_await_remote_message: false,
do_check_instanceof: false,
do_get_cwd: false,
do_get_file: false,
do_get_idle: false,
do_get_profile: false,
do_get_tempdir: false,
do_load_child_test_harness: false,
do_load_manifest: false,
do_load_module: false,
do_note_exception: false,
do_parse_document: false,
do_report_unexpected_exception: false,
do_send_remote_message: false,
do_test_finished: false,
do_test_pending: false,
do_throw: false,
do_timeout: false,
equal: false,
executeSoon: false,
gc: false,
// XPCShell specific function, see XPCShellEnvironment.cpp
"gczeal": false,
"greater": false,
"greaterOrEqual": false,
"info": false,
"less": false,
"lessOrEqual": false,
"load": false,
"mozinfo": false,
"notDeepEqual": false,
"notEqual": false,
"notStrictEqual": false,
"ok": false,
"registerCleanupFunction": false,
"run_next_test": false,
"run_test": false,
"run_test_in_child": false,
"runningInParent": false,
gczeal: false,
greater: false,
greaterOrEqual: false,
info: false,
less: false,
lessOrEqual: false,
load: false,
mozinfo: false,
notDeepEqual: false,
notEqual: false,
notStrictEqual: false,
ok: false,
registerCleanupFunction: false,
run_next_test: false,
run_test: false,
run_test_in_child: false,
runningInParent: false,
// Defined in XPCShellImpl.
"sendCommand": false,
"strictEqual": false,
"throws": false,
"todo": false,
"todo_check_false": false,
"todo_check_true": false,
sendCommand: false,
strictEqual: false,
throws: false,
todo: false,
todo_check_false: false,
todo_check_true: false,
// Firefox specific function.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/uneval
"uneval": false,
uneval: false,
},
"overrides": [{
// If it is a head file, we turn off global unused variable checks, as it
// would require searching the other test files to know if they are used or not.
// This would be expensive and slow, and it isn't worth it for head files.
// We could get developers to declare as exported, but that doesn't seem worth it.
"files": "head*.js",
"rules": {
"no-unused-vars": ["error", {
"args": "none",
"vars": "local",
}],
overrides: [
{
// If it is a head file, we turn off global unused variable checks, as it
// would require searching the other test files to know if they are used or not.
// This would be expensive and slow, and it isn't worth it for head files.
// We could get developers to declare as exported, but that doesn't seem worth it.
files: "head*.js",
rules: {
"no-unused-vars": [
"error",
{
args: "none",
vars: "local",
},
],
},
},
}],
],
rules: {
"mozilla/import-headjs-globals": "error",

Просмотреть файл

@ -38,8 +38,8 @@ const extraDefinitions = [
// Via Components.utils, defineModuleGetter, defineLazyModuleGetters or
// defineLazyScriptGetter (and map to
// single) variable.
{name: "XPCOMUtils", writable: false},
{name: "Task", writable: false},
{ name: "XPCOMUtils", writable: false },
{ name: "Task", writable: false },
];
// Some files in global-scripts.inc need mapping to specific locations.
@ -51,13 +51,12 @@ const MAPPINGS = {
"places-tree.js": "browser/components/places/content/places-tree.js",
};
const globalScriptsRegExp =
/^\s*Services.scriptloader.loadSubScript\(\"(.*?)\", this\);$/;
const globalScriptsRegExp = /^\s*Services.scriptloader.loadSubScript\(\"(.*?)\", this\);$/;
function getGlobalScriptIncludes(scriptPath) {
let fileData;
try {
fileData = fs.readFileSync(scriptPath, {encoding: "utf8"});
fileData = fs.readFileSync(scriptPath, { encoding: "utf8" });
} catch (ex) {
// The file isn't present, so this isn't an m-c repository.
return null;
@ -71,9 +70,12 @@ function getGlobalScriptIncludes(scriptPath) {
let match = line.match(globalScriptsRegExp);
if (match) {
let sourceFile = match[1]
.replace("chrome://browser/content/search/", "browser/components/search/content/")
.replace("chrome://browser/content/", "browser/base/content/")
.replace("chrome://global/content/", "toolkit/content/");
.replace(
"chrome://browser/content/search/",
"browser/components/search/content/"
)
.replace("chrome://browser/content/", "browser/base/content/")
.replace("chrome://global/content/", "toolkit/content/");
for (let mapping of Object.getOwnPropertyNames(MAPPINGS)) {
if (sourceFile.includes(mapping)) {
@ -110,7 +112,8 @@ function getScriptGlobals() {
} catch (e) {
console.error(`Could not load globals from file ${fileName}: ${e}`);
console.error(
`You may need to update the mappings in ${module.filename}`);
`You may need to update the mappings in ${module.filename}`
);
throw new Error(`Could not load globals from file ${fileName}: ${e}`);
}
}
@ -133,6 +136,6 @@ function getMozillaCentralItems() {
};
}
module.exports = helpers.isMozillaCentralBased() ?
getMozillaCentralItems() :
helpers.getSavedEnvironmentItems("browser-window");
module.exports = helpers.isMozillaCentralBased()
? getMozillaCentralItems()
: helpers.getSavedEnvironmentItems("browser-window");

Просмотреть файл

@ -13,9 +13,12 @@
var globals = require("globals");
var util = require("util");
var workerGlobals = util._extend({
ctypes: false,
}, globals.worker);
var workerGlobals = util._extend(
{
ctypes: false,
},
globals.worker
);
module.exports = {
globals: workerGlobals,

Просмотреть файл

@ -9,16 +9,16 @@
"use strict";
module.exports = {
"globals": {
globals: {
// These globals are hard-coded and available in .jsm scopes.
// https://searchfox.org/mozilla-central/rev/ed212c79cfe86357e9a5740082b9364e7f6e526f/js/xpconnect/loader/mozJSComponentLoader.cpp#134-140
"atob": false,
"btoa": false,
"debug": false,
"dump": false,
atob: false,
btoa: false,
debug: false,
dump: false,
// The WebAssembly global is available in most (if not all) contexts where
// JS can run. It's definitely available in JSMs. So even if this is not
// the perfect place to add it, it's not wrong, and we can move it later.
"WebAssembly": false,
WebAssembly: false,
},
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -54,7 +54,7 @@ function mapGlobals(fileGlobals) {
}
module.exports = {
globals: helpers.isMozillaCentralBased() ?
mapGlobals(getScriptGlobals()) :
helpers.getSavedEnvironmentItems("simpletest").globals,
globals: helpers.isMozillaCentralBased()
? mapGlobals(getScriptGlobals())
: helpers.getSavedEnvironmentItems("simpletest").globals,
};

Просмотреть файл

@ -45,7 +45,7 @@ function parseBooleanConfig(string, comment) {
}
items[name] = {
value: (value === "true"),
value: value === "true",
comment,
};
});
@ -135,7 +135,10 @@ GlobalsForNode.prototype = {
// Note: We check the expression types here and only call the necessary
// functions to aid performance.
if (node.expression.type === "AssignmentExpression") {
globals = helpers.convertThisAssignmentExpressionToGlobals(node, isGlobal);
globals = helpers.convertThisAssignmentExpressionToGlobals(
node,
isGlobal
);
} else if (node.expression.type === "CallExpression") {
globals = helpers.convertCallExpressionToGlobals(node, isGlobal);
}
@ -144,8 +147,11 @@ GlobalsForNode.prototype = {
// 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.dirname);
let workerDetails = helpers.convertWorkerExpressionToGlobals(
node,
isGlobal,
this.dirname
);
globals = globals.concat(workerDetails);
}
@ -265,19 +271,31 @@ module.exports = {
} else if (script.src.includes("chrome")) {
// This is one way of referencing test files.
script.src = script.src.replace("chrome://mochikit/content/", "/");
scriptName = path.join(helpers.rootDir, "testing", "mochitest", script.src);
scriptName = path.join(
helpers.rootDir,
"testing",
"mochitest",
script.src
);
} else if (script.src.includes("SimpleTest")) {
// This is another way of referencing test files...
scriptName = path.join(helpers.rootDir, "testing", "mochitest", script.src);
scriptName = path.join(
helpers.rootDir,
"testing",
"mochitest",
script.src
);
} else {
// Fallback to hoping this is a relative path.
scriptName = path.join(dir, script.src);
}
if (scriptName && fs.existsSync(scriptName)) {
globals.push(...module.exports.getGlobalsForFile(scriptName, {
ecmaVersion: helpers.getECMAVersion(),
sourceType: script.type,
}));
globals.push(
...module.exports.getGlobalsForFile(scriptName, {
ecmaVersion: helpers.getECMAVersion(),
sourceType: script.type,
})
);
}
}
@ -317,7 +335,11 @@ module.exports = {
helpers.addGlobals(extraHTMLGlobals, globalScope);
}
let globals = handler[type](node, context.getAncestors(), globalScope);
helpers.addGlobals(globals, globalScope, node.type !== "Program" && node);
helpers.addGlobals(
globals,
globalScope,
node.type !== "Program" && node
);
};
}

Просмотреть файл

@ -53,7 +53,13 @@ module.exports = {
get modulesGlobalData() {
if (!gModules) {
if (this.isMozillaCentralBased()) {
gModules = require(path.join(this.rootDir, "tools", "lint", "eslint", "modules.json"));
gModules = require(path.join(
this.rootDir,
"tools",
"lint",
"eslint",
"modules.json"
));
} else {
gModules = require("./modules.json");
}
@ -78,7 +84,7 @@ module.exports = {
getAST(sourceText, astOptions = {}) {
// Use a permissive config file to allow parsing of anything that Espree
// can parse.
let config = {...this.getPermissiveConfig(), ...astOptions};
let config = { ...this.getPermissiveConfig(), ...astOptions };
return espree.parse(sourceText, config);
},
@ -97,10 +103,15 @@ module.exports = {
case "MemberExpression":
if (node.computed) {
let filename = context && context.getFilename();
throw new Error(`getASTSource unsupported computed MemberExpression in ${filename}`);
throw new Error(
`getASTSource unsupported computed MemberExpression in ${filename}`
);
}
return this.getASTSource(node.object) + "." +
this.getASTSource(node.property);
return (
this.getASTSource(node.object) +
"." +
this.getASTSource(node.property)
);
case "ThisExpression":
return "this";
case "Identifier":
@ -121,10 +132,17 @@ module.exports = {
case "ArrowFunctionExpression":
return "() => {}";
case "AssignmentExpression":
return this.getASTSource(node.left) + " = " +
this.getASTSource(node.right);
return (
this.getASTSource(node.left) + " = " + this.getASTSource(node.right)
);
case "BinaryExpression":
return this.getASTSource(node.left) + " " + node.operator + " " + this.getASTSource(node.right);
return (
this.getASTSource(node.left) +
" " +
node.operator +
" " +
this.getASTSource(node.right)
);
default:
throw new Error("getASTSource unsupported node type: " + node.type);
}
@ -187,10 +205,12 @@ module.exports = {
let results = [];
let expr = node.expression;
if (node.expression.type === "CallExpression" &&
expr.callee &&
expr.callee.type === "Identifier" &&
expr.callee.name === "importScripts") {
if (
node.expression.type === "CallExpression" &&
expr.callee &&
expr.callee.type === "Identifier" &&
expr.callee.name === "importScripts"
) {
for (var arg of expr.arguments) {
var match = arg.value && arg.value.match(workerImportFilenameMatch);
if (match) {
@ -201,9 +221,11 @@ module.exports = {
results = results.concat(additionalGlobals);
}
} else if (match[2] in globalModules) {
results = results.concat(globalModules[match[2]].map(name => {
return { name, writable: true };
}));
results = results.concat(
globalModules[match[2]].map(name => {
return { name, writable: true };
})
);
} else {
results.push({ name: match[3], writable: true, explicit: true });
}
@ -231,12 +253,14 @@ module.exports = {
* If the global is writeable or not.
*/
convertThisAssignmentExpressionToGlobals(node, isGlobal) {
if (isGlobal &&
node.expression.left &&
node.expression.left.object &&
node.expression.left.object.type === "ThisExpression" &&
node.expression.left.property &&
node.expression.left.property.type === "Identifier") {
if (
isGlobal &&
node.expression.left &&
node.expression.left.object &&
node.expression.left.object.type === "ThisExpression" &&
node.expression.left.property &&
node.expression.left.property.type === "Identifier"
) {
return [{ name: node.expression.left.property.name, writable: true }];
}
return [];
@ -260,14 +284,16 @@ module.exports = {
*/
convertCallExpressionToGlobals(node, isGlobal) {
let express = node.expression;
if (express.type === "CallExpression" &&
express.callee.type === "MemberExpression" &&
express.callee.object &&
express.callee.object.type === "Identifier" &&
express.arguments.length === 1 &&
express.arguments[0].type === "ArrayExpression" &&
express.callee.property.type === "Identifier" &&
express.callee.property.name === "importGlobalProperties") {
if (
express.type === "CallExpression" &&
express.callee.type === "MemberExpression" &&
express.callee.object &&
express.callee.object.type === "Identifier" &&
express.arguments.length === 1 &&
express.arguments[0].type === "ArrayExpression" &&
express.callee.property.type === "Identifier" &&
express.callee.property.name === "importGlobalProperties"
) {
return express.arguments[0].elements.map(literal => {
return {
explicit: true,
@ -301,7 +327,9 @@ module.exports = {
// of them.
let explicit = globalModules[match[1]].length == 1;
return globalModules[match[1]].map(name => ({
name, writable: true, explicit,
name,
writable: true,
explicit,
}));
}
@ -322,27 +350,43 @@ module.exports = {
}
}
if (callExpressionMultiDefinitions.some(expr => source.startsWith(expr)) &&
node.expression.arguments[1]) {
if (
callExpressionMultiDefinitions.some(expr => source.startsWith(expr)) &&
node.expression.arguments[1]
) {
let arg = node.expression.arguments[1];
if (arg.type === "ObjectExpression") {
return arg.properties
.map(p => ({ name: p.type === "Property" && p.key.name, writable: true, explicit: true }))
.filter(g => g.name);
.map(p => ({
name: p.type === "Property" && p.key.name,
writable: true,
explicit: true,
}))
.filter(g => g.name);
}
if (arg.type === "ArrayExpression") {
return arg.elements
.map(p => ({ name: p.type === "Literal" && p.value, writable: true, explicit: true }))
.filter(g => typeof g.name == "string");
.map(p => ({
name: p.type === "Literal" && p.value,
writable: true,
explicit: true,
}))
.filter(g => typeof g.name == "string");
}
}
if (node.expression.callee.type == "MemberExpression" &&
node.expression.callee.property.type == "Identifier" &&
node.expression.callee.property.name == "defineLazyScriptGetter") {
if (
node.expression.callee.type == "MemberExpression" &&
node.expression.callee.property.type == "Identifier" &&
node.expression.callee.property.name == "defineLazyScriptGetter"
) {
// The case where we have a single symbol as a string has already been
// handled by the regexp, so we have an array of symbols here.
return node.expression.arguments[1].elements.map(n => ({ name: n.value, writable: true, explicit: true }));
return node.expression.arguments[1].elements.map(n => ({
name: n.value,
writable: true,
explicit: true,
}));
}
return [];
@ -368,7 +412,7 @@ module.exports = {
variable.eslintExplicitGlobal = false;
variable.writeable = writable;
if (node) {
variable.defs.push({node, name: {name}});
variable.defs.push({ node, name: { name } });
variable.identifiers.push(node);
}
@ -402,7 +446,9 @@ module.exports = {
* The AST node that defined the globals.
*/
addGlobals(globalVars, scope, node) {
globalVars.forEach(v => this.addVarToScope(v.name, scope, v.writable, v.explicit && node));
globalVars.forEach(v =>
this.addVarToScope(v.name, scope, v.writable, v.explicit && node)
);
},
/**
@ -503,11 +549,14 @@ module.exports = {
let filepath = this.cleanUpPath(scope.getFilename());
let dir = path.dirname(filepath);
let names =
fs.readdirSync(dir)
.filter(name => (name.startsWith("head") ||
name.startsWith("xpcshell-head")) && name.endsWith(".js"))
.map(name => path.join(dir, name));
let names = fs
.readdirSync(dir)
.filter(
name =>
(name.startsWith("head") || name.startsWith("xpcshell-head")) &&
name.endsWith(".js")
)
.map(name => path.join(dir, name));
return names;
},
@ -548,8 +597,7 @@ module.exports = {
file: path.join(dir, name),
manifest,
});
} catch (e) {
}
} catch (e) {}
}
directoryManifests.set(dir, manifests);
@ -673,7 +721,10 @@ module.exports = {
return null;
}
let possibleRoot = searchUpForIgnore(path.dirname(module.filename), ".eslintignore");
let possibleRoot = searchUpForIgnore(
path.dirname(module.filename),
".eslintignore"
);
if (!possibleRoot) {
possibleRoot = searchUpForIgnore(path.resolve(), ".eslintignore");
}
@ -717,9 +768,9 @@ module.exports = {
// without any path info (happens in Atom with linter-eslint)
return path.join(cwd, fileName);
}
// Case 1: executed form in a nested directory, e.g. from a text editor:
// fileName: a/b/c/d.js
// cwd: /path/to/mozilla/repo/a/b/c
// Case 1: executed form in a nested directory, e.g. from a text editor:
// fileName: a/b/c/d.js
// cwd: /path/to/mozilla/repo/a/b/c
var dirName = path.dirname(fileName);
return cwd.slice(0, cwd.length - dirName.length) + fileName;
},
@ -736,7 +787,13 @@ module.exports = {
get globalScriptPaths() {
return [
path.join(this.rootDir, "browser", "base", "content", "browser.xhtml"),
path.join(this.rootDir, "browser", "base", "content", "global-scripts.inc"),
path.join(
this.rootDir,
"browser",
"base",
"content",
"global-scripts.inc"
),
];
},
@ -745,7 +802,9 @@ module.exports = {
},
getSavedEnvironmentItems(environment) {
return require("./environments/saved-globals.json").environments[environment];
return require("./environments/saved-globals.json").environments[
environment
];
},
getSavedRuleData(rule) {

Просмотреть файл

@ -16,16 +16,16 @@ module.exports = {
"browser-test": require("../lib/configs/browser-test"),
"chrome-test": require("../lib/configs/chrome-test"),
"mochitest-test": require("../lib/configs/mochitest-test"),
"recommended": require("../lib/configs/recommended"),
recommended: require("../lib/configs/recommended"),
"xpcshell-test": require("../lib/configs/xpcshell-test"),
},
environments: {
"browser-window": require("../lib/environments/browser-window.js"),
"chrome-worker": require("../lib/environments/chrome-worker.js"),
"frame-script": require("../lib/environments/frame-script.js"),
"jsm": require("../lib/environments/jsm.js"),
"simpletest": require("../lib/environments/simpletest.js"),
"privileged": require("../lib/environments/privileged.js"),
jsm: require("../lib/environments/jsm.js"),
simpletest: require("../lib/environments/simpletest.js"),
privileged: require("../lib/environments/privileged.js"),
},
processors: {
".xml": require("../lib/processors/xbl-bindings"),
@ -36,10 +36,8 @@ module.exports = {
"avoid-removeChild": require("../lib/rules/avoid-removeChild"),
"balanced-listeners": require("../lib/rules/balanced-listeners"),
"consistent-if-bracing": require("../lib/rules/consistent-if-bracing"),
"import-browser-window-globals":
require("../lib/rules/import-browser-window-globals"),
"import-content-task-globals":
require("../lib/rules/import-content-task-globals"),
"import-browser-window-globals": require("../lib/rules/import-browser-window-globals"),
"import-content-task-globals": require("../lib/rules/import-content-task-globals"),
"import-globals": require("../lib/rules/import-globals"),
"import-headjs-globals": require("../lib/rules/import-headjs-globals"),
"mark-exported-symbols-as-used": require("../lib/rules/mark-exported-symbols-as-used"),
@ -50,19 +48,15 @@ module.exports = {
"no-define-cc-etc": require("../lib/rules/no-define-cc-etc"),
"no-task": require("../lib/rules/no-task"),
"no-useless-parameters": require("../lib/rules/no-useless-parameters"),
"no-useless-removeEventListener":
require("../lib/rules/no-useless-removeEventListener"),
"no-useless-run-test":
require("../lib/rules/no-useless-run-test"),
"reject-importGlobalProperties":
require("../lib/rules/reject-importGlobalProperties"),
"no-useless-removeEventListener": require("../lib/rules/no-useless-removeEventListener"),
"no-useless-run-test": require("../lib/rules/no-useless-run-test"),
"reject-importGlobalProperties": require("../lib/rules/reject-importGlobalProperties"),
"reject-some-requires": require("../lib/rules/reject-some-requires"),
"rejects-requires-await": require("../lib/rules/rejects-requires-await"),
"use-cc-etc": require("../lib/rules/use-cc-etc"),
"use-chromeutils-generateqi": require("../lib/rules/use-chromeutils-generateqi"),
"use-chromeutils-import": require("../lib/rules/use-chromeutils-import"),
"use-default-preference-values":
require("../lib/rules/use-default-preference-values"),
"use-default-preference-values": require("../lib/rules/use-default-preference-values"),
"use-ownerGlobal": require("../lib/rules/use-ownerGlobal"),
"use-includes-instead-of-indexOf": require("../lib/rules/use-includes-instead-of-indexOf"),
"use-returnValue": require("../lib/rules/use-returnValue"),

Просмотреть файл

@ -61,8 +61,11 @@ function addNodeLines(node, reindent) {
// If the second to last line is also blank and has a higher indent than the
// last one, then the CDATA block doesn't close with the closing tag.
if (lines.length > 2 && lines[lines.length - 2].trim() == "" &&
lines[lines.length - 2].length > lastIndent) {
if (
lines.length > 2 &&
lines[lines.length - 2].trim() == "" &&
lines[lines.length - 2].length > lastIndent
) {
lastIndent = lines[lines.length - 2].length;
}
@ -82,8 +85,9 @@ function addNodeLines(node, reindent) {
// Find the preceding whitespace for all lines that aren't entirely
// whitespace.
let indents = lines.filter(s => s.trim().length > 0)
.map(s => s.length - s.trimLeft().length);
let indents = lines
.filter(s => s.trim().length > 0)
.map(s => s.length - s.trimLeft().length);
// Find the smallest indent level in use
let minIndent = Math.min.apply(null, indents);
let indent = Math.max(2, minIndent - lastIndent);
@ -172,7 +176,10 @@ module.exports = {
continue;
}
addSyntheticLine(`get ${item.attributes.name}() {`, item.textLine);
addSyntheticLine(
`get ${item.attributes.name}() {`,
item.textLine
);
addSyntheticLine(`return (`, item.textLine);
// Remove trailing semicolons, as we are adding our own
@ -195,16 +202,20 @@ module.exports = {
// Methods become function declarations with the appropriate
// params.
let params = item.children.filter(n => {
return n.local == "parameter" && n.namespace == NS_XBL;
})
.map(n => n.attributes.name)
.join(", ");
let params = item.children
.filter(n => {
return n.local == "parameter" && n.namespace == NS_XBL;
})
.map(n => n.attributes.name)
.join(", ");
let body = item.children.filter(n => {
return n.local == "body" && n.namespace == NS_XBL;
})[0];
addSyntheticLine(`${item.attributes.name}(${params}) {`, item.textLine);
addSyntheticLine(
`${item.attributes.name}(${params}) {`,
item.textLine
);
addNodeLines(body, 4);
addSyntheticLine(`},`, item.textEndLine);
break;
@ -217,9 +228,15 @@ module.exports = {
}
if (propdef.local == "setter") {
addSyntheticLine(`set ${item.attributes.name}(val) {`, propdef.textLine);
addSyntheticLine(
`set ${item.attributes.name}(val) {`,
propdef.textLine
);
} else if (propdef.local == "getter") {
addSyntheticLine(`get ${item.attributes.name}() {`, propdef.textLine);
addSyntheticLine(
`get ${item.attributes.name}() {`,
propdef.textLine
);
} else {
continue;
}
@ -241,7 +258,10 @@ module.exports = {
}
}
addSyntheticLine((part.local == "implementation" ? `},` : `],`), part.textEndLine);
addSyntheticLine(
part.local == "implementation" ? `},` : `],`,
part.textEndLine
);
}
addSyntheticLine(`},`, binding.textEndLine);
}

Просмотреть файл

@ -51,8 +51,12 @@ function dealWithIfdefs(text, filename) {
if (!line.startsWith("#")) {
outputLines.push(shouldSkip ? "" : line);
} else {
if (line.startsWith("# ") || line.startsWith("#filter") ||
line == "#" || line.startsWith("#define")) {
if (
line.startsWith("# ") ||
line.startsWith("#filter") ||
line == "#" ||
line.startsWith("#define")
) {
outputLines.push("");
continue;
}
@ -86,7 +90,7 @@ function dealWithIfdefs(text, filename) {
if (!shouldSkip) {
let fileToInclude = line.substr("#include ".length).trim();
let subpath = path.join(path.dirname(innerFile), fileToInclude);
let contents = fs.readFileSync(subpath, {encoding: "utf-8"});
let contents = fs.readFileSync(subpath, { encoding: "utf-8" });
contents = contents.split(/\n/);
// Recurse:
contents = stripIfdefsFromLines(contents, subpath);
@ -188,7 +192,7 @@ module.exports = {
"/* eslint-disable quotes */",
"/* eslint-disable no-undef */",
];
lineMap = scriptLines.map(() => ({line: 0}));
lineMap = scriptLines.map(() => ({ line: 0 }));
includedRanges = [];
// Do C-style preprocessing first:
text = dealWithIfdefs(text, filename);
@ -225,17 +229,22 @@ module.exports = {
let mapped = lineMap[message.line - 1];
// Ensure we don't modify this by making a copy. We might need it for another failure.
let target = mapped.line;
let includedRange = includedRanges.find(r => (target >= r.start && target <= r.end));
let includedRange = includedRanges.find(
r => target >= r.start && target <= r.end
);
// If this came from an #included file, indicate this in the message
if (includedRange) {
target = includedRange.start;
message.message += " (from included file " + path.basename(includedRange.filename) + ")";
message.message +=
" (from included file " +
path.basename(includedRange.filename) +
")";
}
// Compensate for line numbers shifting as a result of #include:
let includeBallooning =
includedRanges.filter(r => (target >= r.end))
.map(r => r.end - r.start)
.reduce((acc, next) => acc + next, 0);
let includeBallooning = includedRanges
.filter(r => target >= r.end)
.map(r => r.end - r.start)
.reduce((acc, next) => acc + next, 0);
target -= includeBallooning;
// Add back the 1 to go back to 1-indexing.
message.line = target + 1;
@ -250,4 +259,3 @@ module.exports = {
return errors;
},
};

Просмотреть файл

@ -27,32 +27,41 @@ module.exports = {
create(context) {
return {
"CallExpression": function(node) {
CallExpression(node) {
let callee = node.callee;
if (callee.type !== "MemberExpression" ||
callee.object.type !== "Identifier" ||
callee.object.name !== "Date" ||
callee.property.type !== "Identifier" ||
callee.property.name !== "now") {
if (
callee.type !== "MemberExpression" ||
callee.object.type !== "Identifier" ||
callee.object.name !== "Date" ||
callee.property.type !== "Identifier" ||
callee.property.name !== "now"
) {
return;
}
context.report(node, "use performance.now() instead of Date.now() for timing " +
"measurements");
context.report(
node,
"use performance.now() instead of Date.now() for timing " +
"measurements"
);
},
"NewExpression": function(node) {
NewExpression(node) {
let callee = node.callee;
if (callee.type !== "Identifier" ||
callee.name !== "Date" ||
node.arguments.length > 0) {
if (
callee.type !== "Identifier" ||
callee.name !== "Date" ||
node.arguments.length > 0
) {
return;
}
context.report(node, "use performance.now() instead of new Date() for timing " +
"measurements");
context.report(
node,
"use performance.now() instead of new Date() for timing " +
"measurements"
);
},
};
},
};

Просмотреть файл

@ -21,31 +21,43 @@ module.exports = function(context) {
// --------------------------------------------------------------------------
return {
"CallExpression": function(node) {
CallExpression(node) {
let callee = node.callee;
if (callee.type !== "MemberExpression" ||
callee.property.type !== "Identifier" ||
callee.property.name != "removeChild" ||
node.arguments.length != 1) {
if (
callee.type !== "MemberExpression" ||
callee.property.type !== "Identifier" ||
callee.property.name != "removeChild" ||
node.arguments.length != 1
) {
return;
}
if (callee.object.type == "MemberExpression" &&
callee.object.property.type == "Identifier" &&
callee.object.property.name == "parentNode" &&
helpers.getASTSource(callee.object.object, context) ==
helpers.getASTSource(node.arguments[0])) {
context.report(node, "use element.remove() instead of " +
"element.parentNode.removeChild(element)");
if (
callee.object.type == "MemberExpression" &&
callee.object.property.type == "Identifier" &&
callee.object.property.name == "parentNode" &&
helpers.getASTSource(callee.object.object, context) ==
helpers.getASTSource(node.arguments[0])
) {
context.report(
node,
"use element.remove() instead of " +
"element.parentNode.removeChild(element)"
);
}
if (node.arguments[0].type == "MemberExpression" &&
node.arguments[0].property.type == "Identifier" &&
node.arguments[0].property.name == "firstChild" &&
helpers.getASTSource(callee.object, context) ==
helpers.getASTSource(node.arguments[0].object)) {
context.report(node, "use element.firstChild.remove() instead of " +
"element.removeChild(element.firstChild)");
if (
node.arguments[0].type == "MemberExpression" &&
node.arguments[0].property.type == "Identifier" &&
node.arguments[0].property.name == "firstChild" &&
helpers.getASTSource(callee.object, context) ==
helpers.getASTSource(node.arguments[0].object)
) {
context.report(
node,
"use element.firstChild.remove() instead of " +
"element.removeChild(element.firstChild)"
);
}
},
};

Просмотреть файл

@ -22,8 +22,8 @@ module.exports = function(context) {
// ---------------------------------------------------------------------------
var DICTIONARY = {
"addEventListener": "removeEventListener",
"on": "off",
addEventListener: "removeEventListener",
on: "off",
};
// Invert this dictionary to make it easy later.
var INVERTED_DICTIONARY = {};
@ -40,13 +40,17 @@ module.exports = function(context) {
let options = node.arguments[2];
if (options) {
if (options.type == "ObjectExpression") {
if (options.properties.some(p => p.key.name == "once" &&
p.value.value === true)) {
if (
options.properties.some(
p => p.key.name == "once" && p.value.value === true
)
) {
// No point in adding listeners using the 'once' option.
return;
}
capture = options.properties.some(p => p.key.name == "capture" &&
p.value.value === true);
capture = options.properties.some(
p => p.key.name == "capture" && p.value.value === true
);
} else {
capture = options.value;
}
@ -64,8 +68,9 @@ module.exports = function(context) {
let options = node.arguments[2];
if (options) {
if (options.type == "ObjectExpression") {
capture = options.properties.some(p => p.key.name == "capture" &&
p.value.value === true);
capture = options.properties.some(
p => p.key.name == "capture" && p.value.value === true
);
} else {
capture = options.value;
}
@ -93,9 +98,11 @@ module.exports = function(context) {
function hasRemovedListener(addedListener) {
for (var k = 0; k < removedListeners.length; k++) {
var listener = removedListeners[k];
if (DICTIONARY[addedListener.functionName] === listener.functionName &&
addedListener.type === listener.type &&
addedListener.useCapture === listener.useCapture) {
if (
DICTIONARY[addedListener.functionName] === listener.functionName &&
addedListener.type === listener.type &&
addedListener.useCapture === listener.useCapture
) {
return true;
}
}
@ -126,12 +133,14 @@ module.exports = function(context) {
"Program:exit": function() {
getUnbalancedListeners().forEach(function(listener) {
context.report(listener.node,
context.report(
listener.node,
"No corresponding '{{functionName}}({{type}})' was found.",
{
functionName: DICTIONARY[listener.functionName],
type: listener.type,
});
}
);
});
},
};

Просмотреть файл

@ -20,10 +20,17 @@ module.exports = {
IfStatement(node) {
if (node.parent.type !== "IfStatement") {
let types = new Set();
for (let currentNode = node; currentNode; currentNode = currentNode.alternate) {
for (
let currentNode = node;
currentNode;
currentNode = currentNode.alternate
) {
let type = currentNode.consequent.type;
types.add(type == "BlockStatement" ? "Block" : "NotBlock");
if (currentNode.alternate && currentNode.alternate.type !== "IfStatement") {
if (
currentNode.alternate &&
currentNode.alternate.type !== "IfStatement"
) {
type = currentNode.alternate.type;
types.add(type == "BlockStatement" ? "Block" : "NotBlock");
break;

Просмотреть файл

@ -32,11 +32,16 @@ module.exports = function(context) {
relativePath = relativePath.split(path.sep).join("/");
}
if (browserWindowEnv.browserjsScripts &&
browserWindowEnv.browserjsScripts.includes(relativePath)) {
if (
browserWindowEnv.browserjsScripts &&
browserWindowEnv.browserjsScripts.includes(relativePath)
) {
for (let global in browserWindowEnv.globals) {
helpers.addVarToScope(global, context.getScope(),
browserWindowEnv.globals[global]);
helpers.addVarToScope(
global,
context.getScope(),
browserWindowEnv.globals[global]
);
}
}
},

Просмотреть файл

@ -25,10 +25,15 @@ module.exports = function(context) {
// ---------------------------------------------------------------------------
return {
"CallExpression[callee.object.name='ContentTask'][callee.property.name='spawn']": function(node) {
"CallExpression[callee.object.name='ContentTask'][callee.property.name='spawn']": function(
node
) {
for (let global in frameScriptEnv.globals) {
helpers.addVarToScope(global, context.getScope(),
frameScriptEnv.globals[global]);
helpers.addVarToScope(
global,
context.getScope(),
frameScriptEnv.globals[global]
);
}
},
};

Просмотреть файл

@ -43,11 +43,13 @@ module.exports = function(context) {
return {
AssignmentExpression(node, parents) {
if (node.operator === "=" &&
node.left.type === "MemberExpression" &&
node.left.object.type === "ThisExpression" &&
node.left.property.name === "EXPORTED_SYMBOLS" &&
isGlobalScope()) {
if (
node.operator === "=" &&
node.left.type === "MemberExpression" &&
node.left.object.type === "ThisExpression" &&
node.left.property.name === "EXPORTED_SYMBOLS" &&
isGlobalScope()
) {
markArrayElementsAsUsed(context, node, node.right);
}
},
@ -58,15 +60,18 @@ module.exports = function(context) {
}
for (let item of node.declarations) {
if (item.id &&
item.id.type == "Identifier" &&
item.id.name === "EXPORTED_SYMBOLS") {
if (
item.id &&
item.id.type == "Identifier" &&
item.id.name === "EXPORTED_SYMBOLS"
) {
if (node.kind === "let") {
// The use of 'let' isn't allowed as the lexical scope may die after
// the script executes.
context.report({
node,
message: "EXPORTED_SYMBOLS cannot be declared via `let`. Use `var` or `this.EXPORTED_SYMBOLS =`",
message:
"EXPORTED_SYMBOLS cannot be declared via `let`. Use `var` or `this.EXPORTED_SYMBOLS =`",
});
}

Просмотреть файл

@ -23,8 +23,7 @@ module.exports = function(context) {
}
function deHungarianize(name) {
return name.substring(1, 2).toLowerCase() +
name.substring(2, name.length);
return name.substring(1, 2).toLowerCase() + name.substring(2, name.length);
}
function checkFunction(node) {
@ -35,10 +34,12 @@ module.exports = function(context) {
name: param.name,
suggestion: deHungarianize(param.name),
};
context.report(param,
"Parameter '{{name}}' uses Hungarian Notation, " +
"consider using '{{suggestion}}' instead.",
errorObj);
context.report(
param,
"Parameter '{{name}}' uses Hungarian Notation, " +
"consider using '{{suggestion}}' instead.",
errorObj
);
}
}
}
@ -48,8 +49,8 @@ module.exports = function(context) {
// ---------------------------------------------------------------------------
return {
"FunctionDeclaration": checkFunction,
"ArrowFunctionExpression": checkFunction,
"FunctionExpression": checkFunction,
FunctionDeclaration: checkFunction,
ArrowFunctionExpression: checkFunction,
FunctionExpression: checkFunction,
};
};

Просмотреть файл

@ -13,10 +13,7 @@
// -----------------------------------------------------------------------------
var helpers = require("../helpers");
var testTypes = new Set([
"browser",
"xpcshell",
]);
var testTypes = new Set(["browser", "xpcshell"]);
module.exports = {
meta: {
@ -33,7 +30,7 @@ module.exports = {
create(context) {
return {
"CallExpression": function(node) {
CallExpression(node) {
// We don't want to run this on mochitest plain as it already
// prevents flaky setTimeout at runtime. This check is built-in
// to the rule itself as sometimes other tests can live alongside
@ -44,14 +41,15 @@ module.exports = {
let callee = node.callee;
if (callee.type === "MemberExpression") {
if (callee.property.name !== "setTimeout" ||
callee.object.name !== "window" ||
node.arguments.length < 2) {
if (
callee.property.name !== "setTimeout" ||
callee.object.name !== "window" ||
node.arguments.length < 2
) {
return;
}
} else if (callee.type === "Identifier") {
if (callee.name !== "setTimeout" ||
node.arguments.length < 2) {
if (callee.name !== "setTimeout" || node.arguments.length < 2) {
return;
}
} else {
@ -60,8 +58,11 @@ module.exports = {
let timeout = node.arguments[1];
if (timeout.type !== "Literal" || timeout.value > 0) {
context.report(node, "listen for events instead of setTimeout() " +
"with arbitrary delay");
context.report(
node,
"listen for events instead of setTimeout() " +
"with arbitrary delay"
);
}
},
};

Просмотреть файл

@ -18,11 +18,16 @@ module.exports = function(context) {
// --------------------------------------------------------------------------
return {
"BinaryExpression": function(node) {
if (["==", "!="].includes(node.operator) &&
(["true", "false"].includes(node.left.raw) ||
["true", "false"].includes(node.right.raw))) {
context.report(node, "Don't compare for inexact equality against boolean literals");
BinaryExpression(node) {
if (
["==", "!="].includes(node.operator) &&
(["true", "false"].includes(node.left.raw) ||
["true", "false"].includes(node.right.raw))
) {
context.report(
node,
"Don't compare for inexact equality against boolean literals"
);
}
},
};

Просмотреть файл

@ -20,17 +20,31 @@ module.exports = function(context) {
// --------------------------------------------------------------------------
return {
"VariableDeclarator": function(node) {
if (node.id.type == "Identifier" && componentsBlacklist.includes(node.id.name)) {
context.report(node,
`${node.id.name} is now defined in global scope, a separate definition is no longer necessary.`);
VariableDeclarator(node) {
if (
node.id.type == "Identifier" &&
componentsBlacklist.includes(node.id.name)
) {
context.report(
node,
`${
node.id.name
} is now defined in global scope, a separate definition is no longer necessary.`
);
}
if (node.id.type == "ObjectPattern") {
for (let property of node.id.properties) {
if (property.type == "Property" && componentsBlacklist.includes(property.value.name)) {
context.report(node,
`${property.value.name} is now defined in global scope, a separate definition is no longer necessary.`);
if (
property.type == "Property" &&
componentsBlacklist.includes(property.value.name)
) {
context.report(
node,
`${
property.value.name
} is now defined in global scope, a separate definition is no longer necessary.`
);
}
}
}

Просмотреть файл

@ -19,12 +19,14 @@ module.exports = function(context) {
// --------------------------------------------------------------------------
return {
"CallExpression": function(node) {
CallExpression(node) {
let callee = node.callee;
if (callee.type === "MemberExpression" &&
callee.object.type === "Identifier" &&
callee.object.name === "Task") {
context.report({node, message: "Task.jsm is deprecated."});
if (
callee.type === "MemberExpression" &&
callee.object.type === "Identifier" &&
callee.object.name === "Task"
) {
context.report({ node, message: "Task.jsm is deprecated." });
}
},
};

Просмотреть файл

@ -16,8 +16,10 @@
module.exports = function(context) {
function getRangeAfterArgToEnd(argNumber, args) {
let sourceCode = context.getSourceCode();
return [sourceCode.getTokenAfter(args[argNumber]).range[0],
args[args.length - 1].range[1]];
return [
sourceCode.getTokenAfter(args[argNumber]).range[0],
args[args.length - 1].range[1],
];
}
// ---------------------------------------------------------------------------
@ -25,22 +27,29 @@ module.exports = function(context) {
// --------------------------------------------------------------------------
return {
"CallExpression": function(node) {
CallExpression(node) {
let callee = node.callee;
if (callee.type !== "MemberExpression" ||
callee.property.type !== "Identifier") {
if (
callee.type !== "MemberExpression" ||
callee.property.type !== "Identifier"
) {
return;
}
let isFalse = arg => arg.type === "Literal" && arg.value === false;
let isFalsy = arg => arg.type === "Literal" && !arg.value;
let isBool = arg => arg.type === "Literal" && (arg.value === false ||
arg.value === true);
let isBool = arg =>
arg.type === "Literal" && (arg.value === false || arg.value === true);
let name = callee.property.name;
let args = node.arguments;
if (["addEventListener", "removeEventListener", "addObserver"]
.includes(name) && args.length === 3 && isFalse(args[2])) {
if (
["addEventListener", "removeEventListener", "addObserver"].includes(
name
) &&
args.length === 3 &&
isFalse(args[2])
) {
context.report({
node,
fix: fixer => {
@ -80,8 +89,7 @@ module.exports = function(context) {
});
}
if (name === "notifyObservers" && args.length === 3 &&
isFalsy(args[2])) {
if (name === "notifyObservers" && args.length === 3 && isFalsy(args[2])) {
context.report({
node,
fix: fixer => {
@ -91,8 +99,11 @@ module.exports = function(context) {
});
}
if (name === "getComputedStyle" && args.length === 2 &&
isFalsy(args[1])) {
if (
name === "getComputedStyle" &&
args.length === 2 &&
isFalsy(args[1])
) {
context.report({
node,
fix: fixer => {
@ -102,8 +113,11 @@ module.exports = function(context) {
});
}
if (name === "newURI" && args.length > 1 &&
isFalsy(args[args.length - 1])) {
if (
name === "newURI" &&
args.length > 1 &&
isFalsy(args[args.length - 1])
) {
context.report({
node,
fix: fixer => {
@ -111,7 +125,9 @@ module.exports = function(context) {
return fixer.removeRange(getRangeAfterArgToEnd(0, args));
}
return fixer.removeRange(getRangeAfterArgToEnd(args.length - 2, args));
return fixer.removeRange(
getRangeAfterArgToEnd(args.length - 2, args)
);
},
message: "newURI's last parameters are optional.",
});

Просмотреть файл

@ -19,37 +19,45 @@ module.exports = function(context) {
// --------------------------------------------------------------------------
return {
"CallExpression": function(node) {
CallExpression(node) {
let callee = node.callee;
if (callee.type !== "MemberExpression" ||
callee.property.type !== "Identifier" ||
callee.property.name !== "addEventListener" ||
node.arguments.length == 4) {
if (
callee.type !== "MemberExpression" ||
callee.property.type !== "Identifier" ||
callee.property.name !== "addEventListener" ||
node.arguments.length == 4
) {
return;
}
let listener = node.arguments[1];
if (!listener ||
listener.type != "FunctionExpression" ||
!listener.body ||
listener.body.type != "BlockStatement" ||
!listener.body.body.length ||
listener.body.body[0].type != "ExpressionStatement" ||
listener.body.body[0].expression.type != "CallExpression") {
if (
!listener ||
listener.type != "FunctionExpression" ||
!listener.body ||
listener.body.type != "BlockStatement" ||
!listener.body.body.length ||
listener.body.body[0].type != "ExpressionStatement" ||
listener.body.body[0].expression.type != "CallExpression"
) {
return;
}
let call = listener.body.body[0].expression;
if (call.callee.type == "MemberExpression" &&
call.callee.property.type == "Identifier" &&
call.callee.property.name == "removeEventListener" &&
((call.arguments[0].type == "Literal" &&
call.arguments[0].value == node.arguments[0].value) ||
(call.arguments[0].type == "Identifier" &&
call.arguments[0].name == node.arguments[0].name))) {
context.report(call,
"use {once: true} instead of removeEventListener as " +
"the first instruction of the listener");
if (
call.callee.type == "MemberExpression" &&
call.callee.property.type == "Identifier" &&
call.callee.property.name == "removeEventListener" &&
((call.arguments[0].type == "Literal" &&
call.arguments[0].value == node.arguments[0].value) ||
(call.arguments[0].type == "Identifier" &&
call.arguments[0].name == node.arguments[0].name))
) {
context.report(
call,
"use {once: true} instead of removeEventListener as " +
"the first instruction of the listener"
);
}
},
};

Просмотреть файл

@ -19,12 +19,14 @@ module.exports = function(context) {
return {
"Program > FunctionDeclaration": function(node) {
if (node.id.name === "run_test" &&
node.body.type === "BlockStatement" &&
node.body.body.length === 1 &&
node.body.body[0].type === "ExpressionStatement" &&
node.body.body[0].expression.type === "CallExpression" &&
node.body.body[0].expression.callee.name === "run_next_test") {
if (
node.id.name === "run_test" &&
node.body.type === "BlockStatement" &&
node.body.body.length === 1 &&
node.body.body[0].type === "ExpressionStatement" &&
node.body.body[0].expression.type === "CallExpression" &&
node.body.body[0].expression.callee.name === "run_next_test"
) {
context.report({
node,
fix: fixer => {
@ -51,7 +53,7 @@ module.exports = function(context) {
return fixer.removeRange([
// If there's no startNode, we fall back to zero, i.e. start of
// file.
startNode ? (startNode.end + 1) : 0,
startNode ? startNode.end + 1 : 0,
// We know the function is a block and it'll end with }. Normally
// there's a new line after that, so just advance past it. This
// may be slightly not dodgy in some cases, but covers the existing
@ -59,7 +61,8 @@ module.exports = function(context) {
node.end + 1,
]);
},
message: "Useless run_test function - only contains run_next_test; whole function can be removed",
message:
"Useless run_test function - only contains run_next_test; whole function can be removed",
});
}
},

Просмотреть файл

@ -8,7 +8,9 @@
"use strict";
const privilegedGlobals = Object.keys(require("../environments/privileged.js").globals);
const privilegedGlobals = Object.keys(
require("../environments/privileged.js").globals
);
// -----------------------------------------------------------------------------
// Rule Definition
@ -18,35 +20,40 @@ module.exports = {
meta: {
messages: {
unexpectedCall: "Unexpected call to Cu.importGlobalProperties",
unexpectedCallWebIdl: "Unnecessary call to Cu.importGlobalProperties (webidl names are automatically imported)",
unexpectedCallWebIdl:
"Unnecessary call to Cu.importGlobalProperties (webidl names are automatically imported)",
},
schema: [{
// XXX Better name?
"enum": ["everything", "allownonwebidl"],
}],
schema: [
{
// XXX Better name?
enum: ["everything", "allownonwebidl"],
},
],
type: "problem",
},
create(context) {
return {
"CallExpression": function(node) {
CallExpression(node) {
if (node.callee.type !== "MemberExpression") {
return;
}
let memexp = node.callee;
if (memexp.object.type === "Identifier" &&
// Only Cu, not Components.utils; see bug 1230369.
memexp.object.name === "Cu" &&
memexp.property.type === "Identifier" &&
memexp.property.name === "importGlobalProperties") {
if (
memexp.object.type === "Identifier" &&
// Only Cu, not Components.utils; see bug 1230369.
memexp.object.name === "Cu" &&
memexp.property.type === "Identifier" &&
memexp.property.name === "importGlobalProperties"
) {
if (context.options.includes("allownonwebidl")) {
for (let element of node.arguments[0].elements) {
if (privilegedGlobals.includes(element.value)) {
context.report({ node, messageId: "unexpectedCallWebIdl"});
context.report({ node, messageId: "unexpectedCallWebIdl" });
}
}
} else {
context.report({node, messageId: "unexpectedCall"});
context.report({ node, messageId: "unexpectedCall" });
}
}
},

Просмотреть файл

@ -17,7 +17,7 @@ module.exports = function(context) {
// Public
// --------------------------------------------------------------------------
if (typeof(context.options[0]) !== "string") {
if (typeof context.options[0] !== "string") {
throw new Error("reject-some-requires expects a regexp");
}
const RX = new RegExp(context.options[0]);
@ -29,17 +29,21 @@ module.exports = function(context) {
};
return {
"CallExpression": function(node) {
if (node.callee.type == "Identifier" &&
node.callee.name == "require" &&
node.arguments.length == 1 &&
node.arguments[0].type == "Literal") {
CallExpression(node) {
if (
node.callee.type == "Identifier" &&
node.callee.name == "require" &&
node.arguments.length == 1 &&
node.arguments[0].type == "Literal"
) {
checkPath(node, node.arguments[0].value);
} else if (node.callee.type == "MemberExpression" &&
node.callee.property.type == "Identifier" &&
node.callee.property.name == "lazyRequireGetter" &&
node.arguments.length >= 3 &&
node.arguments[2].type == "Literal") {
} else if (
node.callee.type == "MemberExpression" &&
node.callee.property.type == "Identifier" &&
node.callee.property.name == "lazyRequireGetter" &&
node.arguments.length >= 3 &&
node.arguments[2].type == "Literal"
) {
checkPath(node, node.arguments[2].value);
}
},

Просмотреть файл

@ -17,13 +17,15 @@ module.exports = {
create(context) {
return {
"CallExpression": function(node) {
CallExpression(node) {
if (node.callee.type === "MemberExpression") {
let memexp = node.callee;
if (memexp.object.type === "Identifier" &&
memexp.object.name === "Assert" &&
memexp.property.type === "Identifier" &&
memexp.property.name === "rejects") {
if (
memexp.object.type === "Identifier" &&
memexp.object.name === "Assert" &&
memexp.property.type === "Identifier" &&
memexp.property.name === "rejects"
) {
// We have ourselves an Assert.rejects.
if (node.parent.type !== "AwaitExpression") {

Просмотреть файл

@ -25,13 +25,19 @@ module.exports = function(context) {
// --------------------------------------------------------------------------
return {
"MemberExpression": function(node) {
if (node.object.type === "Identifier" &&
node.object.name === "Components" &&
node.property.type === "Identifier" &&
Object.getOwnPropertyNames(componentsMap).includes(node.property.name)) {
context.report(node,
`Use ${componentsMap[node.property.name]} rather than Components.${node.property.name}`);
MemberExpression(node) {
if (
node.object.type === "Identifier" &&
node.object.name === "Components" &&
node.property.type === "Identifier" &&
Object.getOwnPropertyNames(componentsMap).includes(node.property.name)
) {
context.report(
node,
`Use ${componentsMap[node.property.name]} rather than Components.${
node.property.name
}`
);
}
},
};

Просмотреть файл

@ -18,17 +18,19 @@ function isIdentifier(node, id) {
}
function isMemberExpression(node, object, member) {
return (node.type === "MemberExpression" &&
isIdentifier(node.object, object) &&
isIdentifier(node.property, member));
return (
node.type === "MemberExpression" &&
isIdentifier(node.object, object) &&
isIdentifier(node.property, member)
);
}
const MSG_NO_JS_QUERY_INTERFACE = (
const MSG_NO_JS_QUERY_INTERFACE =
"Please use ChromeUtils.generateQI rather than manually creating " +
"JavaScript QueryInterface functions");
"JavaScript QueryInterface functions";
const MSG_NO_XPCOMUTILS_GENERATEQI = (
"Please use ChromeUtils.generateQI instead of XPCOMUtils.generateQI");
const MSG_NO_XPCOMUTILS_GENERATEQI =
"Please use ChromeUtils.generateQI instead of XPCOMUtils.generateQI";
function funcToGenerateQI(context, node) {
const sourceCode = context.getSourceCode();
@ -41,9 +43,10 @@ function funcToGenerateQI(context, node) {
interfaces.push(match[1] || match[2]);
}
let ifaces = interfaces.filter(iface => iface != "nsISupports")
.map(iface => JSON.stringify(iface))
.join(", ");
let ifaces = interfaces
.filter(iface => iface != "nsISupports")
.map(iface => JSON.stringify(iface))
.join(", ");
return `ChromeUtils.generateQI([${ifaces}])`;
}
@ -55,8 +58,8 @@ module.exports = {
create(context) {
return {
"CallExpression": function(node) {
let {callee} = node;
CallExpression(node) {
let { callee } = node;
if (isMemberExpression(callee, "XPCOMUtils", "generateQI")) {
context.report({
node,
@ -68,8 +71,10 @@ module.exports = {
}
},
"AssignmentExpression > MemberExpression[property.name='QueryInterface']": function(node) {
const {right} = node.parent;
"AssignmentExpression > MemberExpression[property.name='QueryInterface']": function(
node
) {
const { right } = node.parent;
if (right.type === "FunctionExpression") {
context.report({
node: node.parent,
@ -81,7 +86,9 @@ module.exports = {
}
},
"Property[key.name='QueryInterface'][value.type='FunctionExpression']": function(node) {
"Property[key.name='QueryInterface'][value.type='FunctionExpression']": function(
node
) {
context.report({
node,
message: MSG_NO_JS_QUERY_INTERFACE,
@ -94,4 +101,3 @@ module.exports = {
};
},
};

Просмотреть файл

@ -18,22 +18,24 @@ function isIdentifier(node, id) {
}
function isMemberExpression(node, object, member) {
return (node.type === "MemberExpression" &&
isIdentifier(node.object, object) &&
isIdentifier(node.property, member));
return (
node.type === "MemberExpression" &&
isIdentifier(node.object, object) &&
isIdentifier(node.property, member)
);
}
module.exports = {
meta: {
schema: [
{
"type": "object",
"properties": {
"allowCu": {
"type": "boolean",
type: "object",
properties: {
allowCu: {
type: "boolean",
},
},
"additionalProperties": false,
additionalProperties: false,
},
],
fixable: "code",
@ -41,18 +43,20 @@ module.exports = {
create(context) {
return {
"CallExpression": function(node) {
CallExpression(node) {
if (node.callee.type !== "MemberExpression") {
return;
}
let {allowCu} = context.options[0] || {};
let {callee} = node;
let { allowCu } = context.options[0] || {};
let { callee } = node;
// Is the expression starting with `Cu` or `Components.utils`?
if (((!allowCu && isIdentifier(callee.object, "Cu")) ||
isMemberExpression(callee.object, "Components", "utils")) &&
isIdentifier(callee.property, "import")) {
if (
((!allowCu && isIdentifier(callee.object, "Cu")) ||
isMemberExpression(callee.object, "Components", "utils")) &&
isIdentifier(callee.property, "import")
) {
context.report({
node,
message: "Please use ChromeUtils.import instead of Cu.import",
@ -62,14 +66,20 @@ module.exports = {
});
}
if (isMemberExpression(callee, "XPCOMUtils", "defineLazyModuleGetter") &&
node.arguments.length < 4) {
if (
isMemberExpression(callee, "XPCOMUtils", "defineLazyModuleGetter") &&
node.arguments.length < 4
) {
context.report({
node,
message: ("Please use ChromeUtils.defineModuleGetter instead of " +
"XPCOMUtils.defineLazyModuleGetter"),
message:
"Please use ChromeUtils.defineModuleGetter instead of " +
"XPCOMUtils.defineLazyModuleGetter",
fix(fixer) {
return fixer.replaceText(callee, "ChromeUtils.defineModuleGetter");
return fixer.replaceText(
callee,
"ChromeUtils.defineModuleGetter"
);
},
});
}

Просмотреть файл

@ -19,21 +19,22 @@ module.exports = function(context) {
// --------------------------------------------------------------------------
return {
"TryStatement": function(node) {
TryStatement(node) {
let types = ["Bool", "Char", "Float", "Int"];
let methods = types.map(type => "get" + type + "Pref");
if (node.block.type != "BlockStatement" ||
node.block.body.length != 1) {
if (node.block.type != "BlockStatement" || node.block.body.length != 1) {
return;
}
let firstStm = node.block.body[0];
if (firstStm.type != "ExpressionStatement" ||
firstStm.expression.type != "AssignmentExpression" ||
firstStm.expression.right.type != "CallExpression" ||
firstStm.expression.right.callee.type != "MemberExpression" ||
firstStm.expression.right.callee.property.type != "Identifier" ||
!methods.includes(firstStm.expression.right.callee.property.name)) {
if (
firstStm.type != "ExpressionStatement" ||
firstStm.expression.type != "AssignmentExpression" ||
firstStm.expression.right.type != "CallExpression" ||
firstStm.expression.right.callee.type != "MemberExpression" ||
firstStm.expression.right.callee.property.type != "Identifier" ||
!methods.includes(firstStm.expression.right.callee.property.name)
) {
return;
}

Просмотреть файл

@ -18,22 +18,26 @@ module.exports = function(context) {
// --------------------------------------------------------------------------
return {
"BinaryExpression": function(node) {
if (node.left.type != "CallExpression" ||
node.left.callee.type != "MemberExpression" ||
node.left.callee.property.type != "Identifier" ||
node.left.callee.property.name != "indexOf") {
BinaryExpression(node) {
if (
node.left.type != "CallExpression" ||
node.left.callee.type != "MemberExpression" ||
node.left.callee.property.type != "Identifier" ||
node.left.callee.property.name != "indexOf"
) {
return;
}
if ((["!=", "!==", "==", "==="].includes(node.operator) &&
node.right.type == "UnaryExpression" &&
node.right.operator == "-" &&
node.right.argument.type == "Literal" &&
node.right.argument.value == 1) ||
([">=", "<"].includes(node.operator) &&
node.right.type == "Literal" &&
node.right.value == 0)) {
if (
(["!=", "!==", "==", "==="].includes(node.operator) &&
node.right.type == "UnaryExpression" &&
node.right.operator == "-" &&
node.right.argument.type == "Literal" &&
node.right.argument.value == 1) ||
([">=", "<"].includes(node.operator) &&
node.right.type == "Literal" &&
node.right.value == 0)
) {
context.report(node, "use .includes instead of .indexOf");
}
},

Просмотреть файл

@ -18,17 +18,21 @@ module.exports = function(context) {
// --------------------------------------------------------------------------
return {
"MemberExpression": function(node) {
if (node.property.type != "Identifier" ||
node.property.name != "defaultView" ||
node.object.type != "MemberExpression" ||
node.object.property.type != "Identifier" ||
node.object.property.name != "ownerDocument") {
MemberExpression(node) {
if (
node.property.type != "Identifier" ||
node.property.name != "defaultView" ||
node.object.type != "MemberExpression" ||
node.object.property.type != "Identifier" ||
node.object.property.name != "ownerDocument"
) {
return;
}
context.report(node,
"use .ownerGlobal instead of .ownerDocument.defaultView");
context.report(
node,
"use .ownerGlobal instead of .ownerDocument.defaultView"
);
},
};
};

Просмотреть файл

@ -18,21 +18,27 @@ module.exports = function(context) {
// --------------------------------------------------------------------------
return {
"ExpressionStatement": function(node) {
if (!node.expression ||
node.expression.type != "CallExpression" ||
!node.expression.callee ||
node.expression.callee.type != "MemberExpression" ||
!node.expression.callee.property ||
node.expression.callee.property.type != "Identifier" ||
(node.expression.callee.property.name != "concat" &&
node.expression.callee.property.name != "join" &&
node.expression.callee.property.name != "slice")) {
ExpressionStatement(node) {
if (
!node.expression ||
node.expression.type != "CallExpression" ||
!node.expression.callee ||
node.expression.callee.type != "MemberExpression" ||
!node.expression.callee.property ||
node.expression.callee.property.type != "Identifier" ||
(node.expression.callee.property.name != "concat" &&
node.expression.callee.property.name != "join" &&
node.expression.callee.property.name != "slice")
) {
return;
}
context.report(node,
`{Array/String}.${node.expression.callee.property.name} doesn't modify the instance in-place`);
context.report(
node,
`{Array/String}.${
node.expression.callee.property.name
} doesn't modify the instance in-place`
);
},
};
};

Просмотреть файл

@ -22,16 +22,16 @@ var servicesASTParser = {
identifiers: {},
// These interfaces are difficult/not possible to get via processing.
result: {
"nsIPrefBranch": "prefs",
"nsIPrefService": "prefs",
"nsIXULRuntime": "appinfo",
"nsIXULAppInfo": "appinfo",
"nsIDirectoryService": "dirsvc",
"nsIProperties": "dirsvc",
"nsIIOService": "io",
"nsISpeculativeConnect": "io",
"nsICookieManager": "cookies",
"nsIBlocklistService": "blocklist",
nsIPrefBranch: "prefs",
nsIPrefService: "prefs",
nsIXULRuntime: "appinfo",
nsIXULAppInfo: "appinfo",
nsIDirectoryService: "dirsvc",
nsIProperties: "dirsvc",
nsIIOService: "io",
nsISpeculativeConnect: "io",
nsICookieManager: "cookies",
nsIBlocklistService: "blocklist",
},
/**
@ -39,10 +39,12 @@ var servicesASTParser = {
* with objects, and records the assumed interface definitions.
*/
VariableDeclaration(node, parents) {
if (node.declarations.length === 1 &&
node.declarations[0].id &&
helpers.getIsGlobalScope(parents) &&
node.declarations[0].init.type === "ObjectExpression") {
if (
node.declarations.length === 1 &&
node.declarations[0].id &&
helpers.getIsGlobalScope(parents) &&
node.declarations[0].init.type === "ObjectExpression"
) {
let name = node.declarations[0].id.name;
let interfaces = {};
@ -61,13 +63,16 @@ var servicesASTParser = {
* them to the identifier tables created by the VariableDeclaration calls.
*/
AssignmentExpression(node, parents) {
if (node.left.type === "MemberExpression" &&
node.right.type === "ArrayExpression" &&
helpers.getIsGlobalScope(parents)) {
if (
node.left.type === "MemberExpression" &&
node.right.type === "ArrayExpression" &&
helpers.getIsGlobalScope(parents)
) {
let variableName = node.left.object.name;
if (variableName in this.identifiers) {
let servicesPropName = node.left.property.name;
this.identifiers[variableName][servicesPropName] = node.right.elements[1].value;
this.identifiers[variableName][servicesPropName] =
node.right.elements[1].value;
}
}
},
@ -78,11 +83,13 @@ var servicesASTParser = {
* Services.jsm is caching.
*/
CallExpression(node) {
if (node.callee.object &&
node.callee.object.name === "XPCOMUtils" &&
node.callee.property &&
node.callee.property.name === "defineLazyServiceGetters" &&
node.arguments.length >= 2) {
if (
node.callee.object &&
node.callee.object.name === "XPCOMUtils" &&
node.callee.property &&
node.callee.property.name === "defineLazyServiceGetters" &&
node.arguments.length >= 2
) {
// The second argument has the getters name.
let gettersVarName = node.arguments[1].name;
if (!(gettersVarName in this.identifiers)) {
@ -97,7 +104,12 @@ var servicesASTParser = {
};
function getInterfacesFromServicesFile() {
let filePath = path.join(helpers.rootDir, "toolkit", "modules", "Services.jsm");
let filePath = path.join(
helpers.rootDir,
"toolkit",
"modules",
"Services.jsm"
);
let content = fs.readFileSync(filePath, "utf8");
@ -120,9 +132,9 @@ function getInterfacesFromServicesFile() {
return servicesASTParser.result;
}
let getServicesInterfaceMap = helpers.isMozillaCentralBased() ?
getInterfacesFromServicesFile() :
helpers.getSavedRuleData("use-services.js");
let getServicesInterfaceMap = helpers.isMozillaCentralBased()
? getInterfacesFromServicesFile()
: helpers.getSavedRuleData("use-services.js");
// -----------------------------------------------------------------------------
// Rule Definition
@ -141,22 +153,27 @@ module.exports = function(context) {
},
CallExpression(node) {
if (!node.callee ||
!node.callee.property ||
node.callee.property.type != "Identifier" ||
node.callee.property.name != "getService" ||
node.arguments.length != 1 ||
!node.arguments[0].property ||
node.arguments[0].property.type != "Identifier" ||
!node.arguments[0].property.name ||
!(node.arguments[0].property.name in getServicesInterfaceMap)) {
if (
!node.callee ||
!node.callee.property ||
node.callee.property.type != "Identifier" ||
node.callee.property.name != "getService" ||
node.arguments.length != 1 ||
!node.arguments[0].property ||
node.arguments[0].property.type != "Identifier" ||
!node.arguments[0].property.name ||
!(node.arguments[0].property.name in getServicesInterfaceMap)
) {
return;
}
let serviceName = getServicesInterfaceMap[node.arguments[0].property.name];
let serviceName =
getServicesInterfaceMap[node.arguments[0].property.name];
context.report(node,
`Use Services.${serviceName} rather than getService().`);
context.report(
node,
`Use Services.${serviceName} rather than getService().`
);
},
};
};

Просмотреть файл

@ -21,7 +21,7 @@ module.exports = function(context) {
// --------------------------------------------------------------------------
return {
"VariableDeclaration": function(node) {
VariableDeclaration(node) {
if (node.kind === "var") {
if (helpers.getIsGlobalScope(context.getAncestors())) {
return;

Просмотреть файл

@ -29,7 +29,11 @@ function MozillaFormatter(runner) {
failures++;
// Replace any newlines in the title.
let title = test.title.replace(/\n/g, "|");
console.log(`TEST-UNEXPECTED-FAIL | ${path.basename(test.file)} | ${title} | ${err.message}`);
console.log(
`TEST-UNEXPECTED-FAIL | ${path.basename(test.file)} | ${title} | ${
err.message
}`
);
});
runner.on("end", function() {

Просмотреть файл

@ -10,19 +10,32 @@ var fs = require("fs");
var path = require("path");
var helpers = require("../lib/helpers");
const eslintDir = path.join(helpers.rootDir,
"tools", "lint", "eslint");
const eslintDir = path.join(helpers.rootDir, "tools", "lint", "eslint");
const globalsFile = path.join(eslintDir, "eslint-plugin-mozilla",
"lib", "environments", "saved-globals.json");
const rulesFile = path.join(eslintDir, "eslint-plugin-mozilla",
"lib", "rules", "saved-rules-data.json");
const globalsFile = path.join(
eslintDir,
"eslint-plugin-mozilla",
"lib",
"environments",
"saved-globals.json"
);
const rulesFile = path.join(
eslintDir,
"eslint-plugin-mozilla",
"lib",
"rules",
"saved-rules-data.json"
);
console.log("Copying modules.json");
const modulesFile = path.join(eslintDir, "modules.json");
const shipModulesFile = path.join(eslintDir, "eslint-plugin-mozilla", "lib",
"modules.json");
const shipModulesFile = path.join(
eslintDir,
"eslint-plugin-mozilla",
"lib",
"modules.json"
);
fs.writeFileSync(shipModulesFile, fs.readFileSync(modulesFile));
@ -31,26 +44,30 @@ console.log("Generating globals file");
// Export the environments.
let environmentGlobals = require("../lib/index.js").environments;
return fs.writeFile(globalsFile, JSON.stringify({environments: environmentGlobals}), err => {
if (err) {
console.error(err);
process.exit(1);
}
console.log("Globals file generation complete");
console.log("Creating rules data file");
// Also export data for the use-services.js rule
let rulesData = {
"use-services.js": require("../lib/rules/use-services.js")().getServicesInterfaceMap(),
};
return fs.writeFile(rulesFile, JSON.stringify({rulesData}), err1 => {
if (err1) {
console.error(err1);
return fs.writeFile(
globalsFile,
JSON.stringify({ environments: environmentGlobals }),
err => {
if (err) {
console.error(err);
process.exit(1);
}
console.log("Globals file generation complete");
});
});
console.log("Creating rules data file");
// Also export data for the use-services.js rule
let rulesData = {
"use-services.js": require("../lib/rules/use-services.js")().getServicesInterfaceMap(),
};
return fs.writeFile(rulesFile, JSON.stringify({ rulesData }), err1 => {
if (err1) {
console.error(err1);
process.exit(1);
}
console.log("Globals file generation complete");
});
}
);

Просмотреть файл

@ -17,7 +17,7 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
// ------------------------------------------------------------------------------
function invalidCode(code, type, message) {
return {code, errors: [{message, type}]};
return { code, errors: [{ message, type }] };
}
ruleTester.run("avoid-Date-timing", rule, {
@ -28,12 +28,15 @@ ruleTester.run("avoid-Date-timing", rule, {
"Date.UTC(2017, 7);",
],
invalid: [
invalidCode("Date.now();", "CallExpression",
"use performance.now() instead of Date.now() " +
"for timing measurements"),
invalidCode("new Date();", "NewExpression",
"use performance.now() instead of new Date() " +
"for timing measurements"),
invalidCode(
"Date.now();",
"CallExpression",
"use performance.now() instead of Date.now() " + "for timing measurements"
),
invalidCode(
"new Date();",
"NewExpression",
"use performance.now() instead of new Date() " + "for timing measurements"
),
],
});

Просмотреть файл

@ -18,10 +18,11 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
function invalidCode(code, message) {
if (!message) {
message = "use element.remove() instead of " +
"element.parentNode.removeChild(element)";
message =
"use element.remove() instead of " +
"element.parentNode.removeChild(element)";
}
return {code, errors: [{message, type: "CallExpression"}]};
return { code, errors: [{ message, type: "CallExpression" }] };
}
ruleTester.run("avoid-removeChild", rule, {
@ -36,8 +37,10 @@ ruleTester.run("avoid-removeChild", rule, {
invalidCode("elt.parentNode.parentNode.removeChild(elt.parentNode);"),
invalidCode("$(e).parentNode.removeChild($(e));"),
invalidCode("$('e').parentNode.removeChild($('e'));"),
invalidCode("elt.removeChild(elt.firstChild);",
"use element.firstChild.remove() instead of " +
"element.removeChild(element.firstChild)"),
invalidCode(
"elt.removeChild(elt.firstChild);",
"use element.firstChild.remove() instead of " +
"element.removeChild(element.firstChild)"
),
],
});

Просмотреть файл

@ -19,61 +19,71 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
function error(code, message) {
return {
code,
errors: [{message, type: "Identifier"}],
errors: [{ message, type: "Identifier" }],
};
}
ruleTester.run("balanced-listeners", rule, {
valid: [
"elt.addEventListener('event', handler);" +
"elt.removeEventListener('event', handler);",
"elt.removeEventListener('event', handler);",
"elt.addEventListener('event', handler, true);" +
"elt.removeEventListener('event', handler, true);",
"elt.removeEventListener('event', handler, true);",
"elt.addEventListener('event', handler, false);" +
"elt.removeEventListener('event', handler, false);",
"elt.removeEventListener('event', handler, false);",
"elt.addEventListener('event', handler);" +
"elt.removeEventListener('event', handler, false);",
"elt.removeEventListener('event', handler, false);",
"elt.addEventListener('event', handler, false);" +
"elt.removeEventListener('event', handler);",
"elt.removeEventListener('event', handler);",
"elt.addEventListener('event', handler, {capture: false});" +
"elt.removeEventListener('event', handler);",
"elt.removeEventListener('event', handler);",
"elt.addEventListener('event', handler);" +
"elt.removeEventListener('event', handler, {capture: false});",
"elt.removeEventListener('event', handler, {capture: false});",
"elt.addEventListener('event', handler, {capture: true});" +
"elt.removeEventListener('event', handler, true);",
"elt.removeEventListener('event', handler, true);",
"elt.addEventListener('event', handler, true);" +
"elt.removeEventListener('event', handler, {capture: true});",
"elt.removeEventListener('event', handler, {capture: true});",
"elt.addEventListener('event', handler, {once: true});",
"elt.addEventListener('event', handler, {once: true, capture: true});",
],
invalid: [
error("elt.addEventListener('click', handler, false);",
"No corresponding 'removeEventListener(click)' was found."),
error(
"elt.addEventListener('click', handler, false);",
"No corresponding 'removeEventListener(click)' was found."
),
error("elt.addEventListener('click', handler, false);" +
"elt.removeEventListener('click', handler, true);",
"No corresponding 'removeEventListener(click)' was found."),
error(
"elt.addEventListener('click', handler, false);" +
"elt.removeEventListener('click', handler, true);",
"No corresponding 'removeEventListener(click)' was found."
),
error("elt.addEventListener('click', handler, {capture: false});" +
"elt.removeEventListener('click', handler, true);",
"No corresponding 'removeEventListener(click)' was found."),
error(
"elt.addEventListener('click', handler, {capture: false});" +
"elt.removeEventListener('click', handler, true);",
"No corresponding 'removeEventListener(click)' was found."
),
error("elt.addEventListener('click', handler, {capture: true});" +
"elt.removeEventListener('click', handler);",
"No corresponding 'removeEventListener(click)' was found."),
error(
"elt.addEventListener('click', handler, {capture: true});" +
"elt.removeEventListener('click', handler);",
"No corresponding 'removeEventListener(click)' was found."
),
error("elt.addEventListener('click', handler, true);" +
"elt.removeEventListener('click', handler);",
"No corresponding 'removeEventListener(click)' was found."),
error(
"elt.addEventListener('click', handler, true);" +
"elt.removeEventListener('click', handler);",
"No corresponding 'removeEventListener(click)' was found."
),
],
});

Просмотреть файл

@ -17,7 +17,7 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 8 } });
// ------------------------------------------------------------------------------
function invalidCode(code) {
return {code, errors: [{messageId: "consistentIfBracing"}]};
return { code, errors: [{ messageId: "consistentIfBracing" }] };
}
ruleTester.run("consistent-if-bracing", rule, {

Просмотреть файл

@ -17,7 +17,7 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
// ------------------------------------------------------------------------------
function invalidCode(code, type, message) {
return {code, errors: [{message, type}]};
return { code, errors: [{ message, type }] };
}
ruleTester.run("mark-exported-symbols-as-used", rule, {
@ -26,11 +26,20 @@ ruleTester.run("mark-exported-symbols-as-used", rule, {
"this.EXPORTED_SYMBOLS = ['foo'];",
],
invalid: [
invalidCode("let EXPORTED_SYMBOLS = ['foo'];", "VariableDeclaration",
"EXPORTED_SYMBOLS cannot be declared via `let`. Use `var` or `this.EXPORTED_SYMBOLS =`"),
invalidCode("var EXPORTED_SYMBOLS = 'foo';", "VariableDeclaration",
"Unexpected assignment of non-Array to EXPORTED_SYMBOLS"),
invalidCode("this.EXPORTED_SYMBOLS = 'foo';", "AssignmentExpression",
"Unexpected assignment of non-Array to EXPORTED_SYMBOLS"),
invalidCode(
"let EXPORTED_SYMBOLS = ['foo'];",
"VariableDeclaration",
"EXPORTED_SYMBOLS cannot be declared via `let`. Use `var` or `this.EXPORTED_SYMBOLS =`"
),
invalidCode(
"var EXPORTED_SYMBOLS = 'foo';",
"VariableDeclaration",
"Unexpected assignment of non-Array to EXPORTED_SYMBOLS"
),
invalidCode(
"this.EXPORTED_SYMBOLS = 'foo';",
"AssignmentExpression",
"Unexpected assignment of non-Array to EXPORTED_SYMBOLS"
),
],
});

Просмотреть файл

@ -17,13 +17,14 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
// ------------------------------------------------------------------------------
function wrapCode(code, filename = "xpcshell/test_foo.js") {
return {code, filename};
return { code, filename };
}
function invalidCode(code) {
let message = "listen for events instead of setTimeout() with arbitrary delay";
let message =
"listen for events instead of setTimeout() with arbitrary delay";
let obj = wrapCode(code);
obj.errors = [{message, type: "CallExpression"}];
obj.errors = [{ message, type: "CallExpression" }];
return obj;
}
@ -38,4 +39,3 @@ ruleTester.run("no-arbitrary-setTimeout", rule, {
invalidCode("setTimeout(function() {}, timeout);"),
],
});

Просмотреть файл

@ -17,16 +17,13 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
// ------------------------------------------------------------------------------
function callError(message) {
return [{message, type: "BinaryExpression"}];
return [{ message, type: "BinaryExpression" }];
}
const MESSAGE = "Don't compare for inexact equality against boolean literals";
ruleTester.run("no-compare-against-boolean-literals", rule, {
valid: [
`if (!foo) {}`,
`if (!!foo) {}`,
],
valid: [`if (!foo) {}`, `if (!!foo) {}`],
invalid: [
{
code: `if (foo == true) {}`,
@ -62,4 +59,3 @@ ruleTester.run("no-compare-against-boolean-literals", rule, {
},
],
});

Просмотреть файл

@ -21,10 +21,13 @@ function invalidCode(code, varNames) {
varNames = [varNames];
}
return {
code, errors: varNames.map(name => [{
message: `${name} is now defined in global scope, a separate definition is no longer necessary.`,
type: "VariableDeclarator",
}]),
code,
errors: varNames.map(name => [
{
message: `${name} is now defined in global scope, a separate definition is no longer necessary.`,
type: "VariableDeclarator",
},
]),
};
}
@ -47,7 +50,13 @@ ruleTester.run("no-define-cc-etc", rule, {
invalidCode("const {classes: Cc} = Components;", "Cc"),
invalidCode("let {classes: Cc, manager: Cm} = Components", "Cc"),
invalidCode("const Cu = Components.utils;", "Cu"),
invalidCode("var Ci = Components.interfaces, Cc = Components.classes;", ["Ci", "Cc"]),
invalidCode("var {'interfaces': Ci, 'classes': Cc} = Components;", ["Ci", "Cc"]),
invalidCode("var Ci = Components.interfaces, Cc = Components.classes;", [
"Ci",
"Cc",
]),
invalidCode("var {'interfaces': Ci, 'classes': Cc} = Components;", [
"Ci",
"Cc",
]),
],
});

Просмотреть файл

@ -17,7 +17,7 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
// ------------------------------------------------------------------------------
function callError(message) {
return [{message, type: "CallExpression"}];
return [{ message, type: "CallExpression" }];
}
ruleTester.run("no-useless-parameters", rule, {
@ -91,47 +91,47 @@ ruleTester.run("no-useless-parameters", rule, {
code: "elt.addEventListener('click', handler, false);",
output: "elt.addEventListener('click', handler);",
errors: callError(
"addEventListener's third parameter can be omitted when it's false."),
"addEventListener's third parameter can be omitted when it's false."
),
},
{
code: "elt.removeEventListener('click', handler, false);",
output: "elt.removeEventListener('click', handler);",
errors: callError(
"removeEventListener's third parameter can be omitted when it's" +
" false."),
" false."
),
},
{
code: "Services.obs.addObserver(this, 'topic', false);",
output: "Services.obs.addObserver(this, 'topic');",
errors: callError(
"addObserver's third parameter can be omitted when it's" +
" false."),
"addObserver's third parameter can be omitted when it's" + " false."
),
},
{
code: "Services.prefs.addObserver('branch', this, false);",
output: "Services.prefs.addObserver('branch', this);",
errors: callError(
"addObserver's third parameter can be omitted when it's" +
" false."),
"addObserver's third parameter can be omitted when it's" + " false."
),
},
{
code: "array.appendElement(elt, false);",
output: "array.appendElement(elt);",
errors: callError(
"appendElement's second parameter can be omitted when it's" +
" false."),
"appendElement's second parameter can be omitted when it's" + " false."
),
},
{
code: "Services.obs.notifyObservers(obj, 'topic', null);",
output: "Services.obs.notifyObservers(obj, 'topic');",
errors: callError(
"notifyObservers's third parameter can be omitted."),
errors: callError("notifyObservers's third parameter can be omitted."),
},
{
code: "Services.obs.notifyObservers(obj, 'topic', '');",
output: "Services.obs.notifyObservers(obj, 'topic');",
errors: callError(
"notifyObservers's third parameter can be omitted."),
errors: callError("notifyObservers's third parameter can be omitted."),
},
{
code: "window.getComputedStyle(elt, null);",

Просмотреть файл

@ -17,9 +17,10 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
// ------------------------------------------------------------------------------
function invalidCode(code) {
let message = "use {once: true} instead of removeEventListener " +
"as the first instruction of the listener";
return {code, errors: [{message, type: "CallExpression"}]};
let message =
"use {once: true} instead of removeEventListener " +
"as the first instruction of the listener";
return { code, errors: [{ message, type: "CallExpression" }] };
}
ruleTester.run("no-useless-removeEventListener", rule, {
@ -34,53 +35,65 @@ ruleTester.run("no-useless-removeEventListener", rule, {
// Should not reject when removing a listener for another event.
"elt.addEventListener('click', function listener() {" +
" elt.removeEventListener('keypress', listener);" +
"});",
" elt.removeEventListener('keypress', listener);" +
"});",
// Should not reject when there's another instruction before
// removeEventListener.
"elt.addEventListener('click', function listener() {" +
" elt.focus();" +
" elt.removeEventListener('click', listener);" +
"});",
" elt.focus();" +
" elt.removeEventListener('click', listener);" +
"});",
// Should not reject when wantsUntrusted is true.
"elt.addEventListener('click', function listener() {" +
" elt.removeEventListener('click', listener);" +
"}, false, true);",
" elt.removeEventListener('click', listener);" +
"}, false, true);",
// Should not reject when there's a literal and a variable
"elt.addEventListener('click', function listener() {" +
" elt.removeEventListener(eventName, listener);" +
"});",
" elt.removeEventListener(eventName, listener);" +
"});",
// Should not reject when there's 2 different variables
"elt.addEventListener(event1, function listener() {" +
" elt.removeEventListener(event2, listener);" +
"});",
" elt.removeEventListener(event2, listener);" +
"});",
// Should not fail if this is a different type of event listener function.
"myfunc.addEventListener(listener);",
],
invalid: [
invalidCode("elt.addEventListener('click', function listener() {" +
" elt.removeEventListener('click', listener);" +
"});"),
invalidCode("elt.addEventListener('click', function listener() {" +
" elt.removeEventListener('click', listener, true);" +
"}, true);"),
invalidCode("elt.addEventListener('click', function listener() {" +
" elt.removeEventListener('click', listener);" +
"}, {once: true});"),
invalidCode("elt.addEventListener('click', function listener() {" +
" /* Comment */" +
" elt.removeEventListener('click', listener);" +
"});"),
invalidCode("elt.addEventListener('click', function() {" +
" elt.removeEventListener('click', arguments.callee);" +
"});"),
invalidCode("elt.addEventListener(eventName, function listener() {" +
" elt.removeEventListener(eventName, listener);" +
"});"),
invalidCode(
"elt.addEventListener('click', function listener() {" +
" elt.removeEventListener('click', listener);" +
"});"
),
invalidCode(
"elt.addEventListener('click', function listener() {" +
" elt.removeEventListener('click', listener, true);" +
"}, true);"
),
invalidCode(
"elt.addEventListener('click', function listener() {" +
" elt.removeEventListener('click', listener);" +
"}, {once: true});"
),
invalidCode(
"elt.addEventListener('click', function listener() {" +
" /* Comment */" +
" elt.removeEventListener('click', listener);" +
"});"
),
invalidCode(
"elt.addEventListener('click', function() {" +
" elt.removeEventListener('click', arguments.callee);" +
"});"
),
invalidCode(
"elt.addEventListener(eventName, function listener() {" +
" elt.removeEventListener(eventName, listener);" +
"});"
),
],
});

Просмотреть файл

@ -19,7 +19,7 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
function invalidCode(code, output) {
let message =
"Useless run_test function - only contains run_next_test; whole function can be removed";
return {code, output, errors: [{message, type: "FunctionDeclaration"}]};
return { code, output, errors: [{ message, type: "FunctionDeclaration" }] };
}
ruleTester.run("no-useless-run-test", rule, {
@ -30,16 +30,17 @@ ruleTester.run("no-useless-run-test", rule, {
],
invalid: [
// Single-line case.
invalidCode(
"function run_test() { run_next_test(); }",
""),
invalidCode("function run_test() { run_next_test(); }", ""),
// Multiple-line cases
invalidCode(`
invalidCode(
`
function run_test() {
run_next_test();
}`,
``),
invalidCode(`
``
),
invalidCode(
`
foo();
function run_test() {
run_next_test();
@ -47,8 +48,10 @@ function run_test() {
`,
`
foo();
`),
invalidCode(`
`
),
invalidCode(
`
foo();
function run_test() {
run_next_test();
@ -58,8 +61,10 @@ bar();
`
foo();
bar();
`),
invalidCode(`
`
),
invalidCode(
`
foo();
function run_test() {
@ -70,8 +75,10 @@ bar();`,
`
foo();
bar();`),
invalidCode(`
bar();`
),
invalidCode(
`
foo();
function run_test() {
@ -86,8 +93,10 @@ foo();
// A comment
bar();
`),
invalidCode(`
`
),
invalidCode(
`
foo();
/**
@ -109,6 +118,7 @@ foo();
// A comment
bar();
`),
`
),
],
});

Просмотреть файл

@ -17,23 +17,30 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 8 } });
// ------------------------------------------------------------------------------
ruleTester.run("reject-importGlobalProperties", rule, {
valid: [{
code: "Cu.something();",
}, {
options: ["allownonwebidl"],
code: "Cu.importGlobalProperties(['fetch'])",
}],
invalid: [{
code: "Cu.importGlobalProperties(['fetch'])",
options: ["everything"],
errors: [{ messageId: "unexpectedCall"}],
}, {
code: "Cu.importGlobalProperties(['TextEncoder'])",
options: ["everything"],
errors: [{ messageId: "unexpectedCall"}],
}, {
code: "Cu.importGlobalProperties(['TextEncoder'])",
options: ["allownonwebidl"],
errors: [{ messageId: "unexpectedCallWebIdl"}],
}],
valid: [
{
code: "Cu.something();",
},
{
options: ["allownonwebidl"],
code: "Cu.importGlobalProperties(['fetch'])",
},
],
invalid: [
{
code: "Cu.importGlobalProperties(['fetch'])",
options: ["everything"],
errors: [{ messageId: "unexpectedCall" }],
},
{
code: "Cu.importGlobalProperties(['TextEncoder'])",
options: ["everything"],
errors: [{ messageId: "unexpectedCall" }],
},
{
code: "Cu.importGlobalProperties(['TextEncoder'])",
options: ["allownonwebidl"],
errors: [{ messageId: "unexpectedCallWebIdl" }],
},
],
});

Просмотреть файл

@ -17,7 +17,7 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 8 } });
// ------------------------------------------------------------------------------
function invalidCode(code, messageId) {
return {code, errors: [{messageId: "rejectRequiresAwait"}]};
return { code, errors: [{ messageId: "rejectRequiresAwait" }] };
}
ruleTester.run("reject-requires-await", rule, {

Просмотреть файл

@ -17,21 +17,39 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
// ------------------------------------------------------------------------------
function invalidCode(code, originalName, newName) {
return {code, errors: [{
message: `Use ${newName} rather than ${originalName}`,
type: "MemberExpression",
}]};
return {
code,
errors: [
{
message: `Use ${newName} rather than ${originalName}`,
type: "MemberExpression",
},
],
};
}
ruleTester.run("use-cc-etc", rule, {
valid: [
"Components.Constructor();",
"let x = Components.foo;",
],
valid: ["Components.Constructor();", "let x = Components.foo;"],
invalid: [
invalidCode("let foo = Components.classes['bar'];", "Components.classes", "Cc"),
invalidCode("let bar = Components.interfaces.bar;", "Components.interfaces", "Ci"),
invalidCode("Components.results.NS_ERROR_ILLEGAL_INPUT;", "Components.results", "Cr"),
invalidCode("Components.utils.reportError('fake');", "Components.utils", "Cu"),
invalidCode(
"let foo = Components.classes['bar'];",
"Components.classes",
"Cc"
),
invalidCode(
"let bar = Components.interfaces.bar;",
"Components.interfaces",
"Ci"
),
invalidCode(
"Components.results.NS_ERROR_ILLEGAL_INPUT;",
"Components.results",
"Cr"
),
invalidCode(
"Components.utils.reportError('fake');",
"Components.utils",
"Cu"
),
],
});

Просмотреть файл

@ -17,25 +17,27 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
// ------------------------------------------------------------------------------
function callError(message) {
return [{message, type: "CallExpression"}];
return [{ message, type: "CallExpression" }];
}
function error(message, type) {
return [{message, type}];
return [{ message, type }];
}
const MSG_NO_JS_QUERY_INTERFACE = (
const MSG_NO_JS_QUERY_INTERFACE =
"Please use ChromeUtils.generateQI rather than manually creating " +
"JavaScript QueryInterface functions");
"JavaScript QueryInterface functions";
const MSG_NO_XPCOMUTILS_GENERATEQI = (
"Please use ChromeUtils.generateQI instead of XPCOMUtils.generateQI");
const MSG_NO_XPCOMUTILS_GENERATEQI =
"Please use ChromeUtils.generateQI instead of XPCOMUtils.generateQI";
/* globals nsIFlug */
function QueryInterface(iid) {
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIMeh) ||
iid.equals(nsIFlug) ||
iid.equals(Ci.amIFoo)) {
if (
iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIMeh) ||
iid.equals(nsIFlug) ||
iid.equals(Ci.amIFoo)
) {
return this;
}
throw Cr.NS_ERROR_NO_INTERFACE;
@ -63,7 +65,10 @@ ruleTester.run("use-chromeutils-generateqi", rule, {
errors: error(MSG_NO_JS_QUERY_INTERFACE, "Property"),
},
{
code: `X.prototype = { ${String(QueryInterface).replace(/^function /, "")} };`,
code: `X.prototype = { ${String(QueryInterface).replace(
/^function /,
""
)} };`,
output: `X.prototype = { QueryInterface: ChromeUtils.generateQI(["nsIMeh", "nsIFlug", "amIFoo"]) };`,
errors: error(MSG_NO_JS_QUERY_INTERFACE, "Property"),
},
@ -74,4 +79,3 @@ ruleTester.run("use-chromeutils-generateqi", rule, {
},
],
});

Просмотреть файл

@ -17,12 +17,13 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
// ------------------------------------------------------------------------------
function callError(message) {
return [{message, type: "CallExpression"}];
return [{ message, type: "CallExpression" }];
}
const MESSAGE_IMPORT = "Please use ChromeUtils.import instead of Cu.import";
const MESSAGE_DEFINE = ("Please use ChromeUtils.defineModuleGetter instead of " +
"XPCOMUtils.defineLazyModuleGetter");
const MESSAGE_DEFINE =
"Please use ChromeUtils.defineModuleGetter instead of " +
"XPCOMUtils.defineLazyModuleGetter";
ruleTester.run("use-chromeutils-import", rule, {
valid: [
@ -37,7 +38,7 @@ ruleTester.run("use-chromeutils-import", rule, {
"resource://gre/modules/Service.jsm",
undefined, preServicesLambda);`,
{
options: [{allowCu: true}],
options: [{ allowCu: true }],
code: `Cu.import("resource://gre/modules/Service.jsm");`,
},
],
@ -63,7 +64,7 @@ ruleTester.run("use-chromeutils-import", rule, {
errors: callError(MESSAGE_IMPORT),
},
{
options: [{allowCu: true}],
options: [{ allowCu: true }],
code: `Components.utils.import("resource://gre/modules/Services.jsm", this);`,
output: `ChromeUtils.import("resource://gre/modules/Services.jsm", this);`,
errors: callError(MESSAGE_IMPORT),
@ -77,4 +78,3 @@ ruleTester.run("use-chromeutils-import", rule, {
},
],
});

Просмотреть файл

@ -18,7 +18,7 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
function invalidCode(code) {
let message = "provide a default value instead of using a try/catch block";
return {code, errors: [{message, type: "TryStatement"}]};
return { code, errors: [{ message, type: "TryStatement" }] };
}
let types = ["Bool", "Char", "Float", "Int"];
@ -28,12 +28,15 @@ ruleTester.run("use-default-preference-values", rule, {
valid: [].concat(
methods.map(m => "blah = branch." + m + "('blah', true);"),
methods.map(m => "blah = branch." + m + "('blah');"),
methods.map(m => "try { canThrow();" +
" blah = branch." + m + "('blah'); } catch(e) {}")
methods.map(
m =>
"try { canThrow();" + " blah = branch." + m + "('blah'); } catch(e) {}"
)
),
invalid: [].concat(
methods.map(m =>
invalidCode("try { blah = branch." + m + "('blah'); } catch(e) {}"))
invalidCode("try { blah = branch." + m + "('blah'); } catch(e) {}")
)
),
});

Просмотреть файл

@ -18,7 +18,7 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
function invalidCode(code) {
let message = "use .includes instead of .indexOf";
return {code, errors: [{message, type: "BinaryExpression"}]};
return { code, errors: [{ message, type: "BinaryExpression" }] };
}
ruleTester.run("use-includes-instead-of-indexOf", rule, {

Просмотреть файл

@ -18,7 +18,7 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
function invalidCode(code) {
let message = "use .ownerGlobal instead of .ownerDocument.defaultView";
return {code, errors: [{message, type: "MemberExpression"}]};
return { code, errors: [{ message, type: "MemberExpression" }] };
}
ruleTester.run("use-ownerGlobal", rule, {
@ -29,8 +29,7 @@ ruleTester.run("use-ownerGlobal", rule, {
],
invalid: [
invalidCode("aEvent.target.ownerDocument.defaultView;"),
invalidCode(
"this.DOMPointNode.ownerDocument.defaultView.getSelection();"),
invalidCode("this.DOMPointNode.ownerDocument.defaultView.getSelection();"),
invalidCode("windowToMessageManager(node.ownerDocument.defaultView);"),
],
});

Просмотреть файл

@ -18,7 +18,7 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
function invalidCode(code, methodName) {
let message = `{Array/String}.${methodName} doesn't modify the instance in-place`;
return {code, errors: [{message, type: "ExpressionStatement"}]};
return { code, errors: [{ message, type: "ExpressionStatement" }] };
}
ruleTester.run("use-returnValue", rule, {

Просмотреть файл

@ -18,7 +18,7 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
function invalidCode(code, name) {
let message = `Use Services.${name} rather than getService().`;
return {code, errors: [{message, type: "CallExpression"}]};
return { code, errors: [{ message, type: "CallExpression" }] };
}
ruleTester.run("use-services", rule, {
@ -28,10 +28,13 @@ ruleTester.run("use-services", rule, {
"Services.wm.addListener()",
],
invalid: [
invalidCode('Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);',
"wm"),
invalidCode(
'Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);',
"wm"
),
invalidCode(
'Components.classes["@mozilla.org/toolkit/app-startup;1"].getService(Components.interfaces.nsIAppStartup);',
"startup"),
"startup"
),
],
});

Просмотреть файл

@ -11,53 +11,73 @@ add_task(async function test_profile_feature_jsallocations() {
if (!AppConstants.MOZ_GECKO_PROFILER) {
return;
}
Assert.ok(!Services.profiler.IsActive(), "The profiler is not currently active");
Assert.ok(
!Services.profiler.IsActive(),
"The profiler is not currently active"
);
startProfiler({ features: ["threads", "js", "jsallocations"] });
const url = BASE_URL + "do_work_500ms.html";
await BrowserTestUtils.withNewTab(url, async (contentBrowser) => {
const contentPid = await ContentTask.spawn(contentBrowser, null,
() => Services.appinfo.processID);
await BrowserTestUtils.withNewTab(url, async contentBrowser => {
const contentPid = await ContentTask.spawn(
contentBrowser,
null,
() => Services.appinfo.processID
);
// Wait 500ms so that the tab finishes executing.
await wait(500);
// Wait 500ms so that the tab finishes executing.
await wait(500);
// Check that we can get some allocations when the feature is turned on.
{
const { parentThread, contentThread } = await stopProfilerAndGetThreads(contentPid);
Assert.greater(getPayloadsOfType(parentThread, "JS allocation").length, 0,
"Allocations were recorded for the parent process' main thread when the " +
"JS Allocation feature was turned on.");
Assert.greater(getPayloadsOfType(contentThread, "JS allocation").length, 0,
"Allocations were recorded for the content process' main thread when the " +
"JS Allocation feature was turned on.");
}
// Check that we can get some allocations when the feature is turned on.
{
const { parentThread, contentThread } = await stopProfilerAndGetThreads(
contentPid
);
Assert.greater(
getPayloadsOfType(parentThread, "JS allocation").length,
0,
"Allocations were recorded for the parent process' main thread when the " +
"JS Allocation feature was turned on."
);
Assert.greater(
getPayloadsOfType(contentThread, "JS allocation").length,
0,
"Allocations were recorded for the content process' main thread when the " +
"JS Allocation feature was turned on."
);
}
// Flush out any straggling allocation markers that may have not been collected
// yet by starting and stopping the profiler once.
startProfiler({ features: ["threads", "js"] });
await stopProfilerAndGetThreads(contentPid);
// Flush out any straggling allocation markers that may have not been collected
// yet by starting and stopping the profiler once.
startProfiler({ features: ["threads", "js"] });
await stopProfilerAndGetThreads(contentPid);
// Now reload the tab with a clean run.
gBrowser.reload();
await wait(500);
startProfiler({ features: ["threads", "js"] });
// Now reload the tab with a clean run.
gBrowser.reload();
await wait(500);
startProfiler({ features: ["threads", "js"] });
// Check that no allocations were recorded, and allocation tracking was correctly
// turned off.
{
const { parentThread, contentThread } = await stopProfilerAndGetThreads(contentPid);
Assert.equal(
getPayloadsOfType(parentThread, "JS allocation").length, 0,
"No allocations were recorded for the parent processes' main thread when " +
"JS allocation was not turned on.");
// Check that no allocations were recorded, and allocation tracking was correctly
// turned off.
{
const { parentThread, contentThread } = await stopProfilerAndGetThreads(
contentPid
);
Assert.equal(
getPayloadsOfType(parentThread, "JS allocation").length,
0,
"No allocations were recorded for the parent processes' main thread when " +
"JS allocation was not turned on."
);
Assert.equal(
getPayloadsOfType(contentThread, "JS allocation").length, 0,
"No allocations were recorded for the content processes' main thread when " +
"JS allocation was not turned on.");
}
Assert.equal(
getPayloadsOfType(contentThread, "JS allocation").length,
0,
"No allocations were recorded for the content processes' main thread when " +
"JS allocation was not turned on."
);
}
});
});
@ -74,7 +94,7 @@ async function doAtLeastOnePeriodicSample() {
const sampleCount = await getProfileSampleCount();
// Create an infinite loop until a sample has been collected.
while (true) {
if (sampleCount < await getProfileSampleCount()) {
if (sampleCount < (await getProfileSampleCount())) {
return;
}
}
@ -87,7 +107,9 @@ async function stopProfilerAndGetThreads(contentPid) {
Services.profiler.StopProfiler();
const parentThread = profile.threads[0];
const contentProcess = profile.processes.find(p => p.threads[0].pid == contentPid);
const contentProcess = profile.processes.find(
p => p.threads[0].pid == contentPid
);
if (!contentProcess) {
throw new Error("Could not find the content process.");
}

Просмотреть файл

@ -24,7 +24,9 @@ add_task(async function test_profile_single_frame_page_info() {
let pageFound = false;
// We need to find the correct content process for that tab.
let contentProcess = profile.processes.find(p => p.threads[0].pid == contentPid);
let contentProcess = profile.processes.find(
p => p.threads[0].pid == contentPid
);
for (const page of contentProcess.pages) {
if (page.url == url) {
Assert.equal(page.url, url);

Просмотреть файл

@ -24,7 +24,9 @@ add_task(async function test_profile_pushstate_page_info() {
let foundPage = 0;
// We need to find the correct content process for that tab.
let contentProcess = profile.processes.find(p => p.threads[0].pid == contentPid);
let contentProcess = profile.processes.find(
p => p.threads[0].pid == contentPid
);
for (const page of contentProcess.pages) {
// Before pushState
if (page.url == url) {

Просмотреть файл

@ -24,7 +24,9 @@ add_task(async function test_profile_replacestate_page_info() {
let foundPage = 0;
// We need to find the correct content process for that tab.
let contentProcess = profile.processes.find(p => p.threads[0].pid == contentPid);
let contentProcess = profile.processes.find(
p => p.threads[0].pid == contentPid
);
for (const page of contentProcess.pages) {
// Before replaceState
if (page.url == url) {

Просмотреть файл

@ -25,7 +25,9 @@ add_task(async function test_profile_multi_frame_page_info() {
let foundPage = 0;
// We need to find the correct content process for that tab.
let contentProcess = profile.processes.find(p => p.threads[0].pid == contentPid);
let contentProcess = profile.processes.find(
p => p.threads[0].pid == contentPid
);
for (const page of contentProcess.pages) {
// Parent page
if (page.url == url) {

Просмотреть файл

@ -1,5 +1,6 @@
const { BrowserTestUtils } = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
const { BrowserTestUtils } = ChromeUtils.import(
"resource://testing-common/BrowserTestUtils.jsm"
);
const BASE_URL = "http://example.com/browser/tools/profiler/tests/browser/";
@ -44,7 +45,7 @@ function wait(time) {
* @return {Array} The payloads.
*/
function getPayloadsOfType(thread, type) {
const {markers} = thread;
const { markers } = thread;
const results = [];
for (const markerTuple of markers.data) {
const payload = markerTuple[markers.schema.data];

Просмотреть файл

@ -1,59 +1,63 @@
"use strict";
(function() {
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
function startProfiler(settings) {
Services.profiler.StartProfiler(
settings.entries,
settings.interval,
settings.features,
settings.threads,
settings.duration
const { Services } = ChromeUtils.import(
"resource://gre/modules/Services.jsm"
);
info("Profiler has started");
}
function startProfiler(settings) {
Services.profiler.StartProfiler(
settings.entries,
settings.interval,
settings.features,
settings.threads,
settings.duration
);
function getProfile() {
const profile = Services.profiler.getProfileData();
info("We got a profile, run the mochitest with `--keep-open true` to see the logged profile in the Web Console.");
// Run the mochitest with `--keep-open true` to see the logged profile in the
// Web console.
console.log(profile);
return profile;
}
function stopProfiler() {
Services.profiler.StopProfiler();
info("Profiler has stopped");
}
function end(error) {
if (error) {
ok(false, `We got an error: ${error}`);
} else {
ok(true, "We ran the whole process");
info("Profiler has started");
}
SimpleTest.finish();
}
async function runTest(settings, workload) {
SimpleTest.waitForExplicitFinish();
try {
await startProfiler(settings);
await workload();
await getProfile();
await stopProfiler();
await end();
} catch (e) {
// By catching and handling the error, we're being nice to mochitest
// runners: instead of waiting for the timeout, we fail right away.
await end(e);
function getProfile() {
const profile = Services.profiler.getProfileData();
info(
"We got a profile, run the mochitest with `--keep-open true` to see the logged profile in the Web Console."
);
// Run the mochitest with `--keep-open true` to see the logged profile in the
// Web console.
console.log(profile);
return profile;
}
}
window.runTest = runTest;
function stopProfiler() {
Services.profiler.StopProfiler();
info("Profiler has stopped");
}
function end(error) {
if (error) {
ok(false, `We got an error: ${error}`);
} else {
ok(true, "We ran the whole process");
}
SimpleTest.finish();
}
async function runTest(settings, workload) {
SimpleTest.waitForExplicitFinish();
try {
await startProfiler(settings);
await workload();
await getProfile();
await stopProfiler();
await end();
} catch (e) {
// By catching and handling the error, we're being nice to mochitest
// runners: instead of waiting for the timeout, we fail right away.
await end(e);
}
}
window.runTest = runTest;
})();

Просмотреть файл

@ -1,10 +1,12 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
var {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
var {setTimeout} = ChromeUtils.import("resource://gre/modules/Timer.jsm");
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
var { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
var { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm");
/**
* Get the payloads of a type recursively, including from all subprocesses.
@ -15,7 +17,7 @@ var {setTimeout} = ChromeUtils.import("resource://gre/modules/Timer.jsm");
* @return {Array} The final payloads.
*/
function getAllPayloadsOfType(profile, type, payloadTarget = []) {
for (const {markers} of profile.threads) {
for (const { markers } of profile.threads) {
for (const markerTuple of markers.data) {
const payload = markerTuple[markers.schema.data];
if (payload && payload.type === type) {
@ -31,7 +33,6 @@ function getAllPayloadsOfType(profile, type, payloadTarget = []) {
return payloadTarget;
}
/**
* This is a helper function be able to run `await wait(500)`. Unfortunately this
* is needed as the act of collecting functions relies on the periodic sampling of

Просмотреть файл

@ -1,77 +1,81 @@
// Check that asm.js code shows up on the stack.
function run_test() {
// Just skip the test if the profiler component isn't present.
if (!AppConstants.MOZ_GECKO_PROFILER) {
return;
}
// Just skip the test if the profiler component isn't present.
if (!AppConstants.MOZ_GECKO_PROFILER) {
return;
}
// This test assumes that it's starting on an empty profiler stack.
// (Note that the other profiler tests also assume the profiler
// isn't already started.)
Assert.ok(!Services.profiler.IsActive());
// This test assumes that it's starting on an empty profiler stack.
// (Note that the other profiler tests also assume the profiler
// isn't already started.)
Assert.ok(!Services.profiler.IsActive());
let jsFuns = Cu.getJSTestingFunctions();
if (!jsFuns.isAsmJSCompilationAvailable())
let jsFuns = Cu.getJSTestingFunctions();
if (!jsFuns.isAsmJSCompilationAvailable()) {
return;
}
const ms = 10;
Services.profiler.StartProfiler(10000, ms, ["js"]);
let stack = null;
function ffi_function() {
var delayMS = 5;
while (1) {
let then = Date.now();
do {
// do nothing
} while (Date.now() - then < delayMS);
var thread0 = Services.profiler.getProfileData().threads[0];
if (delayMS > 30000) {
return;
}
const ms = 10;
Services.profiler.StartProfiler(10000, ms, ["js"]);
delayMS *= 2;
let stack = null;
function ffi_function() {
var delayMS = 5;
while (1) {
let then = Date.now();
do {
// do nothing
} while (Date.now() - then < delayMS);
if (thread0.samples.data.length == 0) {
continue;
}
var thread0 = Services.profiler.getProfileData().threads[0];
if (delayMS > 30000)
return;
delayMS *= 2;
if (thread0.samples.data.length == 0)
continue;
var lastSample = thread0.samples.data[thread0.samples.data.length - 1];
stack = String(getInflatedStackLocations(thread0, lastSample));
if (stack.includes("trampoline"))
return;
}
var lastSample = thread0.samples.data[thread0.samples.data.length - 1];
stack = String(getInflatedStackLocations(thread0, lastSample));
if (stack.includes("trampoline")) {
return;
}
}
}
function asmjs_module(global, ffis) {
"use asm";
var ffi = ffis.ffi;
function asmjs_function() {
ffi();
}
return asmjs_function;
function asmjs_module(global, ffis) {
"use asm";
var ffi = ffis.ffi;
function asmjs_function() {
ffi();
}
return asmjs_function;
}
Assert.ok(jsFuns.isAsmJSModule(asmjs_module));
Assert.ok(jsFuns.isAsmJSModule(asmjs_module));
var asmjs_function = asmjs_module(null, {ffi: ffi_function});
Assert.ok(jsFuns.isAsmJSFunction(asmjs_function));
var asmjs_function = asmjs_module(null, { ffi: ffi_function });
Assert.ok(jsFuns.isAsmJSFunction(asmjs_function));
asmjs_function();
asmjs_function();
Assert.notEqual(stack, null);
Assert.notEqual(stack, null);
var i1 = stack.indexOf("entry trampoline");
Assert.ok(i1 !== -1);
var i2 = stack.indexOf("asmjs_function");
Assert.ok(i2 !== -1);
var i3 = stack.indexOf("exit trampoline");
Assert.ok(i3 !== -1);
var i4 = stack.indexOf("ffi_function");
Assert.ok(i4 !== -1);
Assert.ok(i1 < i2);
Assert.ok(i2 < i3);
Assert.ok(i3 < i4);
var i1 = stack.indexOf("entry trampoline");
Assert.ok(i1 !== -1);
var i2 = stack.indexOf("asmjs_function");
Assert.ok(i2 !== -1);
var i3 = stack.indexOf("exit trampoline");
Assert.ok(i3 !== -1);
var i4 = stack.indexOf("ffi_function");
Assert.ok(i4 !== -1);
Assert.ok(i1 < i2);
Assert.ok(i2 < i3);
Assert.ok(i3 < i4);
Services.profiler.StopProfiler();
Services.profiler.StopProfiler();
}

Просмотреть файл

@ -2,51 +2,54 @@
// usable by a native unwinder to resume unwinding after encountering
// JIT code, is pushed as expected.
function run_test() {
if (!AppConstants.MOZ_GECKO_PROFILER) {
return;
}
if (!AppConstants.MOZ_GECKO_PROFILER) {
return;
}
// This test assumes that it's starting on an empty profiler stack.
// (Note that the other profiler tests also assume the profiler
// isn't already started.)
Assert.ok(!Services.profiler.IsActive());
// This test assumes that it's starting on an empty profiler stack.
// (Note that the other profiler tests also assume the profiler
// isn't already started.)
Assert.ok(!Services.profiler.IsActive());
const ms = 5;
Services.profiler.StartProfiler(10000, ms, ["js"]);
const ms = 5;
Services.profiler.StartProfiler(10000, ms, ["js"]);
function has_arbitrary_name_in_stack() {
// A frame for |arbitrary_name| has been pushed. Do a sequence of
// increasingly long spins until we get a sample.
var delayMS = 5;
while (1) {
info("loop: ms = " + delayMS);
const then = Date.now();
do {
let n = 10000;
while (--n); // OSR happens here
// Spin in the hope of getting a sample.
} while (Date.now() - then < delayMS);
let profile = Services.profiler.getProfileData().threads[0];
function has_arbitrary_name_in_stack() {
// A frame for |arbitrary_name| has been pushed. Do a sequence of
// increasingly long spins until we get a sample.
var delayMS = 5;
while (1) {
info("loop: ms = " + delayMS);
const then = Date.now();
do {
let n = 10000;
while (--n) {} // OSR happens here
// Spin in the hope of getting a sample.
} while (Date.now() - then < delayMS);
let profile = Services.profiler.getProfileData().threads[0];
// Go through all of the stacks, and search for this function name.
for (const sample of profile.samples.data) {
const stack = getInflatedStackLocations(profile, sample);
info(`The following stack was found: ${stack}`);
for (var i = 0; i < stack.length; i++) {
if (stack[i].match(/arbitrary_name/)) {
// This JS sample was correctly found.
return true;
}
}
}
// Continue running this function with an increasingly long delay.
delayMS *= 2;
if (delayMS > 30000) {
return false;
}
// Go through all of the stacks, and search for this function name.
for (const sample of profile.samples.data) {
const stack = getInflatedStackLocations(profile, sample);
info(`The following stack was found: ${stack}`);
for (var i = 0; i < stack.length; i++) {
if (stack[i].match(/arbitrary_name/)) {
// This JS sample was correctly found.
return true;
}
}
}
// Continue running this function with an increasingly long delay.
delayMS *= 2;
if (delayMS > 30000) {
return false;
}
}
Assert.ok(has_arbitrary_name_in_stack(), "A JS frame was found before the test timeout.");
Services.profiler.StopProfiler();
}
Assert.ok(
has_arbitrary_name_in_stack(),
"A JS frame was found before the test timeout."
);
Services.profiler.StopProfiler();
}

Просмотреть файл

@ -11,7 +11,7 @@ function run_test() {
(function() {
Services.profiler.StopProfiler();
let n = 10000;
while (--n); // OSR happens here with the profiler disabled.
while (--n) {} // OSR happens here with the profiler disabled.
// An assertion will fail when this function returns, if the
// profiler stack was misbalanced.
})();

Просмотреть файл

@ -9,7 +9,7 @@ function run_test() {
(function() {
Services.profiler.StartProfiler(100, 10, ["js"]);
let n = 10000;
while (--n); // OSR happens here with the profiler enabled.
while (--n) {} // OSR happens here with the profiler enabled.
// An assertion will fail when this function returns, if the
// profiler stack was misbalanced.
})();

Просмотреть файл

@ -2,7 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const {FileUtils} = ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
const { FileUtils } = ChromeUtils.import(
"resource://gre/modules/FileUtils.jsm"
);
/**
* Test that the IOInterposer is working correctly to capture main thread IO.
@ -21,10 +23,16 @@ add_task(async () => {
{
const filename = "profiler-mainthreadio-test-firstrun";
const payloads = await startProfilerAndgetFileIOPayloads(["mainthreadio"], filename);
const payloads = await startProfilerAndgetFileIOPayloads(
["mainthreadio"],
filename
);
greater(payloads.length, 0,
"FileIO markers were found when using the mainthreadio feature on the profiler.");
greater(
payloads.length,
0,
"FileIO markers were found when using the mainthreadio feature on the profiler."
);
// It would be better to check on the filename, but Linux does not currently include
// it. See https://bugzilla.mozilla.org/show_bug.cgi?id=1533531
@ -36,18 +44,27 @@ add_task(async () => {
const filename = "profiler-mainthreadio-test-no-instrumentation";
const payloads = await startProfilerAndgetFileIOPayloads([], filename);
equal(payloads.length, 0,
"No FileIO markers are found when the mainthreadio feature is not turned on " +
"in the profiler.");
equal(
payloads.length,
0,
"No FileIO markers are found when the mainthreadio feature is not turned on " +
"in the profiler."
);
}
{
const filename = "profiler-mainthreadio-test-secondrun";
const payloads = await startProfilerAndgetFileIOPayloads(["mainthreadio"], filename);
const payloads = await startProfilerAndgetFileIOPayloads(
["mainthreadio"],
filename
);
greater(payloads.length, 0,
"FileIO markers were found when re-starting the mainthreadio feature on the " +
"profiler.");
greater(
payloads.length,
0,
"FileIO markers were found when re-starting the mainthreadio feature on the " +
"profiler."
);
// It would be better to check on the filename, but Linux does not currently include
// it. See https://bugzilla.mozilla.org/show_bug.cgi?id=1533531
// ok(hasWritePayload(payloads, filename),
@ -67,14 +84,13 @@ async function startProfilerAndgetFileIOPayloads(features, filename) {
const threads = [];
Services.profiler.StartProfiler(entries, interval, features, threads);
const file = FileUtils.getFile("TmpD", [filename]);
if (file.exists()) {
console.warn(
"This test is triggering FileIO by writing to a file. However, the test found an " +
"existing file at the location it was trying to write to. This could happen " +
"because a previous run of the test failed to clean up after itself. This test " +
" will now clean up that file before running the test again."
"existing file at the location it was trying to write to. This could happen " +
"because a previous run of the test failed to clean up after itself. This test " +
" will now clean up that file before running the test again."
);
file.remove(false);
}

Просмотреть файл

@ -7,7 +7,11 @@
/* eslint-env webextensions */
const Quitter = {
quit() { browser.runtime.sendMessage("quit"); },
quit() {
browser.runtime.sendMessage("quit");
},
};
window.wrappedJSObject.Quitter = cloneInto(Quitter, window, {cloneFunctions: true});
window.wrappedJSObject.Quitter = cloneInto(Quitter, window, {
cloneFunctions: true,
});

Просмотреть файл

@ -2,14 +2,16 @@
/* globals ExtensionAPI */
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
this.quitter = class extends ExtensionAPI {
getAPI(context) {
return {
quitter: {
async quit() {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let browserWindow = Services.wm.getMostRecentWindow(
"navigator:browser"
);
if (browserWindow && browserWindow.gBrowserInit) {
await browserWindow.gBrowserInit.idleTasksFinishedPromise;
}

Просмотреть файл

@ -19,15 +19,17 @@ var apply = () => {
$(".filter:checked").each(function(index) {
for (let kind of this.name.split(",")) {
if (!(kinds.includes(kind)))
if (!kinds.includes(kind)) {
kinds.push(kind);
}
}
// Checkbox element values are generated by Section.get_context() in app.py
let attrs = JSON.parse(this.value);
for (let attr in attrs) {
if (!(attr in filters))
if (!(attr in filters)) {
filters[attr] = [];
}
let values = attrs[attr];
filters[attr] = filters[attr].concat(values);
@ -35,24 +37,29 @@ var apply = () => {
});
updateLabels();
if (Object.keys(filters).length == 0 || (Object.keys(filters).length == 1 && "build_type" in filters)) {
if (
Object.keys(filters).length == 0 ||
(Object.keys(filters).length == 1 && "build_type" in filters)
) {
selection.value = "";
count.innerHTML = "0 tasks selected";
return;
}
var taskMatches = (label) => {
var taskMatches = label => {
let task = tasks[label];
// If no box for the given kind has been checked, this task is
// automatically not selected.
if (!(kinds.includes(task.kind)))
if (!kinds.includes(task.kind)) {
return false;
}
for (let attr in filters) {
let values = filters[attr];
if (!(attr in task) || values.includes(task[attr]))
if (!(attr in task) || values.includes(task[attr])) {
continue;
}
return false;
}
return true;

Просмотреть файл

@ -4,8 +4,9 @@ var lastChecked = {};
// implements shift+click
labels.click(function(e) {
if (e.target.tagName === "INPUT")
if (e.target.tagName === "INPUT") {
return;
}
let box = $("#" + this.htmlFor)[0];
let activeSection = $("div.tab-pane.active")[0].id;
@ -15,13 +16,16 @@ labels.click(function(e) {
let isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
if (e.shiftKey) {
if (isFirefox)
if (isFirefox) {
box.checked = !box.checked;
}
let start = boxes.index(box);
let end = boxes.index(lastChecked[activeSection]);
boxes.slice(Math.min(start, end), Math.max(start, end) + 1).prop("checked", box.checked);
boxes
.slice(Math.min(start, end), Math.max(start, end) + 1)
.prop("checked", box.checked);
apply();
}
}