mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-24 01:17:34 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
363
tools/lint/eslint/eslint-plugin-mozilla/LICENSE
Normal file
363
tools/lint/eslint/eslint-plugin-mozilla/LICENSE
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
Mozilla Public License, version 2.0
|
||||
|
||||
1. Definitions
|
||||
|
||||
1.1. "Contributor"
|
||||
|
||||
means each individual or legal entity that creates, contributes to the
|
||||
creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
|
||||
means the combination of the Contributions of others (if any) used by a
|
||||
Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
|
||||
means Source Code Form to which the initial Contributor has attached the
|
||||
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||
Modifications of such Source Code Form, in each case including portions
|
||||
thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
a. that the initial Contributor has attached the notice described in
|
||||
Exhibit B to the Covered Software; or
|
||||
|
||||
b. that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the terms of
|
||||
a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
|
||||
means a work that combines Covered Software with other material, in a
|
||||
separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
|
||||
means having the right to grant, to the maximum extent possible, whether
|
||||
at the time of the initial grant or subsequently, any and all of the
|
||||
rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
|
||||
means any of the following:
|
||||
|
||||
a. any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered Software; or
|
||||
|
||||
b. any new file in Source Code Form that contains any Covered Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the License,
|
||||
by the making, using, selling, offering for sale, having made, import,
|
||||
or transfer of either its Contributions or its Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
|
||||
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||
General Public License, Version 2.1, the GNU Affero General Public
|
||||
License, Version 3.0, or any later versions of those licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that controls, is
|
||||
controlled by, or is under common control with You. For purposes of this
|
||||
definition, "control" means (a) the power, direct or indirect, to cause
|
||||
the direction or management of such entity, whether by contract or
|
||||
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||
outstanding shares or beneficial ownership of such entity.
|
||||
|
||||
|
||||
2. License Grants and Conditions
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
a. under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||
sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
a. for any code that a Contributor has removed from Covered Software; or
|
||||
|
||||
b. for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
c. under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights to
|
||||
grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||
Section 2.1.
|
||||
|
||||
|
||||
3. Responsibilities
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
a. such Covered Software must also be made available in Source Code Form,
|
||||
as described in Section 3.1, and You must inform recipients of the
|
||||
Executable Form how they can obtain a copy of such Source Code Form by
|
||||
reasonable means in a timely manner, at a charge no more than the cost
|
||||
of distribution to the recipient; and
|
||||
|
||||
b. You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter the
|
||||
recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||
limitations of liability) contained within the Source Code Form of the
|
||||
Covered Software, except that You may alter any license notices to the
|
||||
extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this License
|
||||
with respect to some or all of the Covered Software due to statute,
|
||||
judicial order, or regulation then You must: (a) comply with the terms of
|
||||
this License to the maximum extent possible; and (b) describe the
|
||||
limitations and the code they affect. Such description must be placed in a
|
||||
text file included with all distributions of the Covered Software under
|
||||
this License. Except to the extent prohibited by statute or regulation,
|
||||
such description must be sufficiently detailed for a recipient of ordinary
|
||||
skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically if You
|
||||
fail to comply with any of its terms. However, if You become compliant,
|
||||
then the rights granted under this License from a particular Contributor
|
||||
are reinstated (a) provisionally, unless and until such Contributor
|
||||
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||
basis, if such Contributor fails to notify You of the non-compliance by
|
||||
some reasonable means prior to 60 days after You have come back into
|
||||
compliance. Moreover, Your grants from a particular Contributor are
|
||||
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||
non-compliance by some reasonable means, this is the first time You have
|
||||
received notice of non-compliance with this License from such
|
||||
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||
of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||
license agreements (excluding distributors and resellers) which have been
|
||||
validly granted by You or Your distributors under this License prior to
|
||||
termination shall survive termination.
|
||||
|
||||
6. Disclaimer of Warranty
|
||||
|
||||
Covered Software is provided under this License on an "as is" basis,
|
||||
without warranty of any kind, either expressed, implied, or statutory,
|
||||
including, without limitation, warranties that the Covered Software is free
|
||||
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||
The entire risk as to the quality and performance of the Covered Software
|
||||
is with You. Should any Covered Software prove defective in any respect,
|
||||
You (not any Contributor) assume the cost of any necessary servicing,
|
||||
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||
part of this License. No use of any Covered Software is authorized under
|
||||
this License except under this disclaimer.
|
||||
|
||||
7. Limitation of Liability
|
||||
|
||||
Under no circumstances and under no legal theory, whether tort (including
|
||||
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||
distributes Covered Software as permitted above, be liable to You for any
|
||||
direct, indirect, special, incidental, or consequential damages of any
|
||||
character including, without limitation, damages for lost profits, loss of
|
||||
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses, even if such party shall have been
|
||||
informed of the possibility of such damages. This limitation of liability
|
||||
shall not apply to liability for death or personal injury resulting from
|
||||
such party's negligence to the extent applicable law prohibits such
|
||||
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||
incidental or consequential damages, so this exclusion and limitation may
|
||||
not apply to You.
|
||||
|
||||
8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the courts
|
||||
of a jurisdiction where the defendant maintains its principal place of
|
||||
business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||
in this Section shall prevent a party's ability to bring cross-claims or
|
||||
counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides that
|
||||
the language of a contract shall be construed against the drafter shall not
|
||||
be used to construe this License against a Contributor.
|
||||
|
||||
|
||||
10. Versions of the License
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses If You choose to distribute Source Code Form that is
|
||||
Incompatible With Secondary Licenses under the terms of this version of
|
||||
the License, the notice described in Exhibit B of this License must be
|
||||
attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
|
||||
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/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file,
|
||||
then You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a
|
||||
notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
|
||||
This Source Code Form is "Incompatible
|
||||
With Secondary Licenses", as defined by
|
||||
the Mozilla Public License, v. 2.0.
|
||||
|
||||
188
tools/lint/eslint/eslint-plugin-mozilla/lib/globals.js
Normal file
188
tools/lint/eslint/eslint-plugin-mozilla/lib/globals.js
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/**
|
||||
* @fileoverview functions for scanning an AST for globals including
|
||||
* traversing referenced scripts.
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const helpers = require("./helpers");
|
||||
const escope = require("escope");
|
||||
const estraverse = require("estraverse");
|
||||
|
||||
/**
|
||||
* Parses a list of "name:boolean_value" or/and "name" options divided by comma or
|
||||
* whitespace.
|
||||
*
|
||||
* This function was copied from eslint.js
|
||||
*
|
||||
* @param {string} string The string to parse.
|
||||
* @param {Comment} comment The comment node which has the string.
|
||||
* @returns {Object} Result map object of names and boolean values
|
||||
*/
|
||||
function parseBooleanConfig(string, comment) {
|
||||
let items = {};
|
||||
|
||||
// Collapse whitespace around : to make parsing easier
|
||||
string = string.replace(/\s*:\s*/g, ":");
|
||||
// Collapse whitespace around ,
|
||||
string = string.replace(/\s*,\s*/g, ",");
|
||||
|
||||
string.split(/\s|,+/).forEach(function(name) {
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
let pos = name.indexOf(":");
|
||||
let value = undefined;
|
||||
if (pos !== -1) {
|
||||
value = name.substring(pos + 1, name.length);
|
||||
name = name.substring(0, pos);
|
||||
}
|
||||
|
||||
items[name] = {
|
||||
value: (value === "true"),
|
||||
comment: comment
|
||||
};
|
||||
});
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Global discovery can require parsing many files. This map of
|
||||
* {String} => {Object} caches what globals were discovered for a file path.
|
||||
*/
|
||||
const globalCache = new Map();
|
||||
|
||||
/**
|
||||
* An object that returns found globals for given AST node types. Each prototype
|
||||
* property should be named for a node type and accepts a node parameter and a
|
||||
* parents parameter which is a list of the parent nodes of the current node.
|
||||
* Each returns an array of globals found.
|
||||
*
|
||||
* @param {String} path
|
||||
* The absolute path of the file being parsed.
|
||||
*/
|
||||
function GlobalsForNode(path) {
|
||||
this.path = path;
|
||||
this.root = helpers.getRootDir(path);
|
||||
}
|
||||
|
||||
GlobalsForNode.prototype = {
|
||||
BlockComment(node, parents) {
|
||||
let value = node.value.trim();
|
||||
let match = /^import-globals-from\s+(.+)$/.exec(value);
|
||||
if (!match) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let filePath = match[1].trim();
|
||||
|
||||
if (!path.isAbsolute(filePath)) {
|
||||
let dirName = path.dirname(this.path);
|
||||
filePath = path.resolve(dirName, filePath);
|
||||
}
|
||||
|
||||
return module.exports.getGlobalsForFile(filePath);
|
||||
},
|
||||
|
||||
ExpressionStatement(node, parents) {
|
||||
let isGlobal = helpers.getIsGlobalScope(parents);
|
||||
let names = helpers.convertExpressionToGlobals(node, isGlobal, this.root);
|
||||
return names.map(name => { return { name, writable: true }});
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Returns all globals for a given file. Recursively searches through
|
||||
* import-globals-from directives and also includes globals defined by
|
||||
* standard eslint directives.
|
||||
*
|
||||
* @param {String} path
|
||||
* The absolute path of the file to be parsed.
|
||||
*/
|
||||
getGlobalsForFile(path) {
|
||||
if (globalCache.has(path)) {
|
||||
return globalCache.get(path);
|
||||
}
|
||||
|
||||
let content = fs.readFileSync(path, "utf8");
|
||||
|
||||
// Parse the content into an AST
|
||||
let ast = helpers.getAST(content);
|
||||
|
||||
// Discover global declarations
|
||||
let scopeManager = escope.analyze(ast);
|
||||
let globalScope = scopeManager.acquire(ast);
|
||||
|
||||
let globals = Object.keys(globalScope.variables).map(v => ({
|
||||
name: globalScope.variables[v].name,
|
||||
writable: true,
|
||||
}));
|
||||
|
||||
// Walk over the AST to find any of our custom globals
|
||||
let handler = new GlobalsForNode(path);
|
||||
|
||||
helpers.walkAST(ast, (type, node, parents) => {
|
||||
// We have to discover any globals that ESLint would have defined through
|
||||
// comment directives
|
||||
if (type == "BlockComment") {
|
||||
let value = node.value.trim();
|
||||
let match = /^globals?\s+(.+)$/.exec(value);
|
||||
if (match) {
|
||||
let values = parseBooleanConfig(match[1].trim(), node);
|
||||
for (let name of Object.keys(values)) {
|
||||
globals.push({
|
||||
name,
|
||||
writable: values[name].value
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type in handler) {
|
||||
let newGlobals = handler[type](node, parents);
|
||||
globals.push.apply(globals, newGlobals);
|
||||
}
|
||||
});
|
||||
|
||||
globalCache.set(path, globals);
|
||||
|
||||
return globals;
|
||||
},
|
||||
|
||||
/**
|
||||
* Intended to be used as-is for an ESLint rule that parses for globals in
|
||||
* the current file and recurses through import-globals-from directives.
|
||||
*
|
||||
* @param {Object} context
|
||||
* The ESLint parsing context.
|
||||
*/
|
||||
getESLintGlobalParser(context) {
|
||||
let globalScope;
|
||||
|
||||
let parser = {
|
||||
Program(node) {
|
||||
globalScope = context.getScope();
|
||||
}
|
||||
};
|
||||
|
||||
// Install thin wrappers around GlobalsForNode
|
||||
let handler = new GlobalsForNode(helpers.getAbsoluteFilePath(context));
|
||||
|
||||
for (let type of Object.keys(GlobalsForNode.prototype)) {
|
||||
parser[type] = function(node) {
|
||||
let globals = handler[type](node, context.getAncestors());
|
||||
helpers.addGlobals(globals, globalScope);
|
||||
}
|
||||
}
|
||||
|
||||
return parser;
|
||||
}
|
||||
};
|
||||
524
tools/lint/eslint/eslint-plugin-mozilla/lib/helpers.js
Normal file
524
tools/lint/eslint/eslint-plugin-mozilla/lib/helpers.js
Normal file
|
|
@ -0,0 +1,524 @@
|
|||
/**
|
||||
* @fileoverview A collection of helper functions.
|
||||
* 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/.
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
var escope = require("escope");
|
||||
var espree = require("espree");
|
||||
var estraverse = require("estraverse");
|
||||
var path = require("path");
|
||||
var fs = require("fs");
|
||||
var ini = require("ini-parser");
|
||||
|
||||
var modules = null;
|
||||
var directoryManifests = new Map();
|
||||
|
||||
var definitions = [
|
||||
/^loader\.lazyGetter\(this, "(\w+)"/,
|
||||
/^loader\.lazyImporter\(this, "(\w+)"/,
|
||||
/^loader\.lazyServiceGetter\(this, "(\w+)"/,
|
||||
/^loader\.lazyRequireGetter\(this, "(\w+)"/,
|
||||
/^XPCOMUtils\.defineLazyGetter\(this, "(\w+)"/,
|
||||
/^XPCOMUtils\.defineLazyModuleGetter\(this, "(\w+)"/,
|
||||
/^XPCOMUtils\.defineLazyServiceGetter\(this, "(\w+)"/,
|
||||
/^XPCOMUtils\.defineConstant\(this, "(\w+)"/,
|
||||
/^DevToolsUtils\.defineLazyModuleGetter\(this, "(\w+)"/,
|
||||
/^DevToolsUtils\.defineLazyGetter\(this, "(\w+)"/,
|
||||
/^Object\.defineProperty\(this, "(\w+)"/,
|
||||
/^Reflect\.defineProperty\(this, "(\w+)"/,
|
||||
/^this\.__defineGetter__\("(\w+)"/,
|
||||
/^this\.(\w+) =/
|
||||
];
|
||||
|
||||
var imports = [
|
||||
/^(?:Cu|Components\.utils)\.import\(".*\/((.*?)\.jsm?)"(?:, this)?\)/,
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Gets the abstract syntax tree (AST) of the JavaScript source code contained
|
||||
* in sourceText.
|
||||
*
|
||||
* @param {String} sourceText
|
||||
* Text containing valid JavaScript.
|
||||
*
|
||||
* @return {Object}
|
||||
* The resulting AST.
|
||||
*/
|
||||
getAST: function(sourceText) {
|
||||
// Use a permissive config file to allow parsing of anything that Espree
|
||||
// can parse.
|
||||
var config = this.getPermissiveConfig();
|
||||
|
||||
return espree.parse(sourceText, config);
|
||||
},
|
||||
|
||||
/**
|
||||
* A simplistic conversion of some AST nodes to a standard string form.
|
||||
*
|
||||
* @param {Object} node
|
||||
* The AST node to convert.
|
||||
*
|
||||
* @return {String}
|
||||
* The JS source for the node.
|
||||
*/
|
||||
getASTSource: function(node) {
|
||||
switch (node.type) {
|
||||
case "MemberExpression":
|
||||
if (node.computed)
|
||||
throw new Error("getASTSource unsupported computed MemberExpression");
|
||||
return this.getASTSource(node.object) + "." + this.getASTSource(node.property);
|
||||
case "ThisExpression":
|
||||
return "this";
|
||||
case "Identifier":
|
||||
return node.name;
|
||||
case "Literal":
|
||||
return JSON.stringify(node.value);
|
||||
case "CallExpression":
|
||||
var args = node.arguments.map(a => this.getASTSource(a)).join(", ");
|
||||
return this.getASTSource(node.callee) + "(" + args + ")";
|
||||
case "ObjectExpression":
|
||||
return "{}";
|
||||
case "ExpressionStatement":
|
||||
return this.getASTSource(node.expression) + ";";
|
||||
case "FunctionExpression":
|
||||
return "function() {}";
|
||||
case "ArrowFunctionExpression":
|
||||
return "() => {}";
|
||||
case "AssignmentExpression":
|
||||
return this.getASTSource(node.left) + " = " + this.getASTSource(node.right);
|
||||
default:
|
||||
throw new Error("getASTSource unsupported node type: " + node.type);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This walks an AST in a manner similar to ESLint passing node and comment
|
||||
* events to the listener. The listener is expected to be a simple function
|
||||
* which accepts node type, node and parents arguments.
|
||||
*
|
||||
* @param {Object} ast
|
||||
* The AST to walk.
|
||||
* @param {Function} listener
|
||||
* A callback function to call for the nodes. Passed three arguments,
|
||||
* event type, node and an array of parent nodes for the current node.
|
||||
*/
|
||||
walkAST(ast, listener) {
|
||||
let parents = [];
|
||||
|
||||
let seenComments = new Set();
|
||||
function sendCommentEvents(comments) {
|
||||
if (!comments) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let comment of comments) {
|
||||
if (seenComments.has(comment)) {
|
||||
return;
|
||||
}
|
||||
seenComments.add(comment);
|
||||
|
||||
listener(comment.type + "Comment", comment, parents);
|
||||
}
|
||||
}
|
||||
|
||||
estraverse.traverse(ast, {
|
||||
enter(node, parent) {
|
||||
// Comments are held in node.comments for empty programs
|
||||
let leadingComments = node.leadingComments;
|
||||
if (node.type === "Program" && node.body.length == 0) {
|
||||
leadingComments = node.comments;
|
||||
}
|
||||
|
||||
sendCommentEvents(leadingComments);
|
||||
listener(node.type, node, parents);
|
||||
sendCommentEvents(node.trailingComments);
|
||||
|
||||
parents.push(node);
|
||||
},
|
||||
|
||||
leave(node, parent) {
|
||||
// TODO send comment exit events
|
||||
listener(node.type + ":exit", node, parents);
|
||||
|
||||
if (parents.length == 0) {
|
||||
throw new Error("Left more nodes than entered.");
|
||||
}
|
||||
parents.pop();
|
||||
}
|
||||
});
|
||||
if (parents.length) {
|
||||
throw new Error("Entered more nodes than left.");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Attempts to convert an ExpressionStatement to likely global variable
|
||||
* definitions.
|
||||
*
|
||||
* @param {Object} node
|
||||
* The AST node to convert.
|
||||
* @param {boolean} isGlobal
|
||||
* True if the current node is in the global scope.
|
||||
* @param {String} repository
|
||||
* The root of the repository.
|
||||
*
|
||||
* @return {Array}
|
||||
* An array of variable names defined.
|
||||
*/
|
||||
convertExpressionToGlobals: function(node, isGlobal, repository) {
|
||||
if (!modules) {
|
||||
modules = require(path.join(repository, "tools", "lint", "eslint", "modules.json"));
|
||||
}
|
||||
|
||||
try {
|
||||
var source = this.getASTSource(node);
|
||||
}
|
||||
catch (e) {
|
||||
return [];
|
||||
}
|
||||
|
||||
for (var reg of definitions) {
|
||||
var match = source.match(reg);
|
||||
if (match) {
|
||||
// Must be in the global scope
|
||||
if (!isGlobal) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [match[1]];
|
||||
}
|
||||
}
|
||||
|
||||
for (reg of imports) {
|
||||
var match = source.match(reg);
|
||||
if (match) {
|
||||
// The two argument form is only acceptable in the global scope
|
||||
if (node.expression.arguments.length > 1 && !isGlobal) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (match[1] in modules) {
|
||||
return modules[match[1]];
|
||||
}
|
||||
|
||||
return [match[2]];
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a variable to the current scope.
|
||||
* HACK: This relies on eslint internals so it could break at any time.
|
||||
*
|
||||
* @param {String} name
|
||||
* The variable name to add to the scope.
|
||||
* @param {ASTScope} scope
|
||||
* The scope to add to.
|
||||
* @param {boolean} writable
|
||||
* Whether the global can be overwritten.
|
||||
*/
|
||||
addVarToScope: function(name, scope, writable) {
|
||||
scope.__defineGeneric(name, scope.set, scope.variables, null, null);
|
||||
|
||||
let variable = scope.set.get(name);
|
||||
variable.eslintExplicitGlobal = false;
|
||||
variable.writeable = writable;
|
||||
|
||||
// Walk to the global scope which holds all undeclared variables.
|
||||
while (scope.type != "global") {
|
||||
scope = scope.upper;
|
||||
}
|
||||
|
||||
// "through" contains all references with no found definition.
|
||||
scope.through = scope.through.filter(function(reference) {
|
||||
if (reference.identifier.name != name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Links the variable and the reference.
|
||||
// And this reference is removed from `Scope#through`.
|
||||
reference.resolved = variable;
|
||||
variable.references.push(reference);
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a set of globals to a scope.
|
||||
*
|
||||
* @param {Array} globalVars
|
||||
* An array of global variable names.
|
||||
* @param {ASTScope} scope
|
||||
* The scope.
|
||||
*/
|
||||
addGlobals: function(globalVars, scope) {
|
||||
globalVars.forEach(v => this.addVarToScope(v.name, scope, v.writable));
|
||||
},
|
||||
|
||||
/**
|
||||
* To allow espree to parse almost any JavaScript we need as many features as
|
||||
* possible turned on. This method returns that config.
|
||||
*
|
||||
* @return {Object}
|
||||
* Espree compatible permissive config.
|
||||
*/
|
||||
getPermissiveConfig: function() {
|
||||
return {
|
||||
range: true,
|
||||
loc: true,
|
||||
comment: true,
|
||||
attachComment: true,
|
||||
ecmaVersion: 8,
|
||||
sourceType: "script",
|
||||
ecmaFeatures: {
|
||||
experimentalObjectRestSpread: true,
|
||||
globalReturn: true,
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether the context is the global scope.
|
||||
*
|
||||
* @param {Array} ancestors
|
||||
* The parents of the current node.
|
||||
*
|
||||
* @return {Boolean}
|
||||
* True or false
|
||||
*/
|
||||
getIsGlobalScope: function(ancestors) {
|
||||
for (let parent of ancestors) {
|
||||
if (parent.type == "FunctionExpression" ||
|
||||
parent.type == "FunctionDeclaration") {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether we might be in a test head file.
|
||||
*
|
||||
* @param {RuleContext} scope
|
||||
* You should pass this from within a rule
|
||||
* e.g. helpers.getIsHeadFile(this)
|
||||
*
|
||||
* @return {Boolean}
|
||||
* True or false
|
||||
*/
|
||||
getIsHeadFile: function(scope) {
|
||||
var pathAndFilename = this.cleanUpPath(scope.getFilename());
|
||||
|
||||
return /.*[\\/]head(_.+)?\.js$/.test(pathAndFilename);
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the head files for a potential test file
|
||||
*
|
||||
* @param {RuleContext} scope
|
||||
* You should pass this from within a rule
|
||||
* e.g. helpers.getIsHeadFile(this)
|
||||
*
|
||||
* @return {String[]}
|
||||
* Paths to head files to load for the test
|
||||
*/
|
||||
getTestHeadFiles: function(scope) {
|
||||
if (!this.getIsTest(scope)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let filepath = this.cleanUpPath(scope.getFilename());
|
||||
let dir = path.dirname(filepath);
|
||||
|
||||
let names = fs.readdirSync(dir)
|
||||
.filter(name => name.startsWith("head") && name.endsWith(".js"))
|
||||
.map(name => path.join(dir, name));
|
||||
return names;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets all the test manifest data for a directory
|
||||
*
|
||||
* @param {String} dir
|
||||
* The directory
|
||||
*
|
||||
* @return {Array}
|
||||
* An array of objects with file and manifest properties
|
||||
*/
|
||||
getManifestsForDirectory: function(dir) {
|
||||
if (directoryManifests.has(dir)) {
|
||||
return directoryManifests.get(dir);
|
||||
}
|
||||
|
||||
let manifests = [];
|
||||
|
||||
let names = fs.readdirSync(dir);
|
||||
for (let name of names) {
|
||||
if (!name.endsWith(".ini")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
let manifest = ini.parse(fs.readFileSync(path.join(dir, name), 'utf8'));
|
||||
|
||||
manifests.push({
|
||||
file: path.join(dir, name),
|
||||
manifest
|
||||
})
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
directoryManifests.set(dir, manifests);
|
||||
return manifests;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the manifest file a test is listed in
|
||||
*
|
||||
* @param {RuleContext} scope
|
||||
* You should pass this from within a rule
|
||||
* e.g. helpers.getIsHeadFile(this)
|
||||
*
|
||||
* @return {String}
|
||||
* The path to the test manifest file
|
||||
*/
|
||||
getTestManifest: function(scope) {
|
||||
let filepath = this.cleanUpPath(scope.getFilename());
|
||||
|
||||
let dir = path.dirname(filepath);
|
||||
let filename = path.basename(filepath);
|
||||
|
||||
for (let manifest of this.getManifestsForDirectory(dir)) {
|
||||
if (filename in manifest.manifest) {
|
||||
return manifest.file;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether we are in a test of some kind.
|
||||
*
|
||||
* @param {RuleContext} scope
|
||||
* You should pass this from within a rule
|
||||
* e.g. helpers.getIsTest(this)
|
||||
*
|
||||
* @return {Boolean}
|
||||
* True or false
|
||||
*/
|
||||
getIsTest: function(scope) {
|
||||
// Regardless of the manifest name being in a manifest means we're a test.
|
||||
let manifest = this.getTestManifest(scope);
|
||||
if (manifest) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !!this.getTestType(scope);
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the type of test or null if this isn't a test.
|
||||
*
|
||||
* @param {RuleContext} scope
|
||||
* You should pass this from within a rule
|
||||
* e.g. helpers.getIsHeadFile(this)
|
||||
*
|
||||
* @return {String or null}
|
||||
* Test type: xpcshell, browser, chrome, mochitest
|
||||
*/
|
||||
getTestType: function(scope) {
|
||||
let manifest = this.getTestManifest(scope);
|
||||
if (manifest) {
|
||||
let name = path.basename(manifest);
|
||||
for (let testType of ["browser", "xpcshell", "chrome", "mochitest"]) {
|
||||
if (name.startsWith(testType)) {
|
||||
return testType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let filepath = this.cleanUpPath(scope.getFilename());
|
||||
let filename = path.basename(filepath);
|
||||
|
||||
if (filename.startsWith("browser_")) {
|
||||
return "browser";
|
||||
}
|
||||
|
||||
if (filename.startsWith("test_")) {
|
||||
return "xpcshell";
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the root directory of the repository by walking up directories until
|
||||
* a .eslintignore file is found.
|
||||
* @param {String} fileName
|
||||
* The absolute path of a file in the repository
|
||||
*
|
||||
* @return {String} The absolute path of the repository directory
|
||||
*/
|
||||
getRootDir: function(fileName) {
|
||||
var dirName = path.dirname(fileName);
|
||||
|
||||
while (dirName && !fs.existsSync(path.join(dirName, ".eslintignore"))) {
|
||||
dirName = path.dirname(dirName);
|
||||
}
|
||||
|
||||
if (!dirName) {
|
||||
throw new Error("Unable to find root of repository");
|
||||
}
|
||||
|
||||
return dirName;
|
||||
},
|
||||
|
||||
/**
|
||||
* ESLint may be executed from various places: from mach, at the root of the
|
||||
* repository, or from a directory in the repository when, for instance,
|
||||
* executed by a text editor's plugin.
|
||||
* The value returned by context.getFileName() varies because of this.
|
||||
* This helper function makes sure to return an absolute file path for the
|
||||
* current context, by looking at process.cwd().
|
||||
* @param {Context} context
|
||||
* @return {String} The absolute path
|
||||
*/
|
||||
getAbsoluteFilePath: function(context) {
|
||||
var fileName = this.cleanUpPath(context.getFilename());
|
||||
var cwd = process.cwd();
|
||||
|
||||
if (path.isAbsolute(fileName)) {
|
||||
// Case 2: executed from the repo's root with mach:
|
||||
// fileName: /path/to/mozilla/repo/a/b/c/d.js
|
||||
// cwd: /path/to/mozilla/repo
|
||||
return fileName;
|
||||
} else if (path.basename(fileName) == fileName) {
|
||||
// Case 1b: executed from a nested directory, fileName is the base name
|
||||
// without any path info (happens in Atom with linter-eslint)
|
||||
return path.join(cwd, fileName);
|
||||
} else {
|
||||
// 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;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* When ESLint is run from SublimeText, paths retrieved from
|
||||
* context.getFileName contain leading and trailing double-quote characters.
|
||||
* These characters need to be removed.
|
||||
*/
|
||||
cleanUpPath: function(path) {
|
||||
return path.replace(/^"/, "").replace(/"$/, "");
|
||||
}
|
||||
};
|
||||
45
tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
Normal file
45
tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* @fileoverview A collection of rules that help enforce JavaScript coding
|
||||
* standard and avoid common errors in the Mozilla project.
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Plugin Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
processors: {
|
||||
".xml": require("../lib/processors/xbl-bindings"),
|
||||
},
|
||||
rules: {
|
||||
"balanced-listeners": require("../lib/rules/balanced-listeners"),
|
||||
"import-globals": require("../lib/rules/import-globals"),
|
||||
"import-headjs-globals": require("../lib/rules/import-headjs-globals"),
|
||||
"import-browserjs-globals": require("../lib/rules/import-browserjs-globals"),
|
||||
"mark-test-function-used": require("../lib/rules/mark-test-function-used"),
|
||||
"no-aArgs": require("../lib/rules/no-aArgs"),
|
||||
"no-cpows-in-tests": require("../lib/rules/no-cpows-in-tests"),
|
||||
"no-single-arg-cu-import": require("../lib/rules/no-single-arg-cu-import"),
|
||||
"reject-importGlobalProperties": require("../lib/rules/reject-importGlobalProperties"),
|
||||
"reject-some-requires": require("../lib/rules/reject-some-requires"),
|
||||
"var-only-at-top-level": require("../lib/rules/var-only-at-top-level")
|
||||
},
|
||||
rulesConfig: {
|
||||
"balanced-listeners": 0,
|
||||
"import-globals": 0,
|
||||
"import-headjs-globals": 0,
|
||||
"import-browserjs-globals": 0,
|
||||
"mark-test-function-used": 0,
|
||||
"no-aArgs": 0,
|
||||
"no-cpows-in-tests": 0,
|
||||
"no-single-arg-cu-import": 0,
|
||||
"reject-importGlobalProperties": 0,
|
||||
"reject-some-requires": 0,
|
||||
"var-only-at-top-level": 0
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,363 @@
|
|||
/**
|
||||
* @fileoverview Converts functions and handlers from XBL bindings into JS
|
||||
* functions
|
||||
*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const NS_XBL = "http://www.mozilla.org/xbl";
|
||||
|
||||
let sax = require("sax");
|
||||
|
||||
// Converts sax's error message to something that eslint will understand
|
||||
let errorRegex = /(.*)\nLine: (\d+)\nColumn: (\d+)\nChar: (.*)/
|
||||
function parseError(err) {
|
||||
let matches = err.message.match(errorRegex);
|
||||
if (!matches)
|
||||
return null;
|
||||
|
||||
return {
|
||||
fatal: true,
|
||||
message: matches[1],
|
||||
line: parseInt(matches[2]) + 1,
|
||||
column: parseInt(matches[3])
|
||||
}
|
||||
}
|
||||
|
||||
let entityRegex = /&[\w][\w-\.]*;/g;
|
||||
|
||||
// A simple sax listener that generates a tree of element information
|
||||
function XMLParser(parser) {
|
||||
this.parser = parser;
|
||||
parser.onopentag = this.onOpenTag.bind(this);
|
||||
parser.onclosetag = this.onCloseTag.bind(this);
|
||||
parser.ontext = this.onText.bind(this);
|
||||
parser.onopencdata = this.onOpenCDATA.bind(this);
|
||||
parser.oncdata = this.onCDATA.bind(this);
|
||||
parser.oncomment = this.onComment.bind(this);
|
||||
|
||||
this.document = {
|
||||
local: "#document",
|
||||
uri: null,
|
||||
children: [],
|
||||
comments: [],
|
||||
}
|
||||
this._currentNode = this.document;
|
||||
}
|
||||
|
||||
XMLParser.prototype = {
|
||||
parser: null,
|
||||
|
||||
onOpenTag: function(tag) {
|
||||
let node = {
|
||||
parentNode: this._currentNode,
|
||||
local: tag.local,
|
||||
namespace: tag.uri,
|
||||
attributes: {},
|
||||
children: [],
|
||||
comments: [],
|
||||
textContent: "",
|
||||
textLine: this.parser.line,
|
||||
textColumn: this.parser.column,
|
||||
textEndLine: this.parser.line
|
||||
}
|
||||
|
||||
for (let attr of Object.keys(tag.attributes)) {
|
||||
if (tag.attributes[attr].uri == "") {
|
||||
node.attributes[attr] = tag.attributes[attr].value;
|
||||
}
|
||||
}
|
||||
|
||||
this._currentNode.children.push(node);
|
||||
this._currentNode = node;
|
||||
},
|
||||
|
||||
onCloseTag: function(tagname) {
|
||||
this._currentNode.textEndLine = this.parser.line;
|
||||
this._currentNode = this._currentNode.parentNode;
|
||||
},
|
||||
|
||||
addText: function(text) {
|
||||
this._currentNode.textContent += text;
|
||||
},
|
||||
|
||||
onText: function(text) {
|
||||
// Replace entities with some valid JS token.
|
||||
this.addText(text.replace(entityRegex, "null"));
|
||||
},
|
||||
|
||||
onOpenCDATA: function() {
|
||||
// Turn the CDATA opening tag into whitespace for indent alignment
|
||||
this.addText(" ".repeat("<![CDATA[".length));
|
||||
},
|
||||
|
||||
onCDATA: function(text) {
|
||||
this.addText(text);
|
||||
},
|
||||
|
||||
onComment: function(text) {
|
||||
this._currentNode.comments.push(text);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const INDENT_LEVEL = 2;
|
||||
|
||||
function indent(count) {
|
||||
return " ".repeat(count * INDENT_LEVEL);
|
||||
}
|
||||
|
||||
// Stores any XML parse error
|
||||
let xmlParseError = null;
|
||||
|
||||
// Stores the lines of JS code generated from the XBL
|
||||
let scriptLines = [];
|
||||
// Stores a map from the synthetic line number to the real line number
|
||||
// and column offset.
|
||||
let lineMap = [];
|
||||
|
||||
function addSyntheticLine(line, linePos, addDisableLine) {
|
||||
lineMap[scriptLines.length] = { line: linePos, offset: null };
|
||||
scriptLines.push(line + (addDisableLine ? "" : " // eslint-disable-line"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds generated lines from an XBL node to the script to be passed back to eslint.
|
||||
*/
|
||||
function addNodeLines(node, reindent) {
|
||||
let lines = node.textContent.split("\n");
|
||||
let startLine = node.textLine;
|
||||
let startColumn = node.textColumn;
|
||||
|
||||
// The case where there are no whitespace lines before the first text is
|
||||
// treated differently for indentation
|
||||
let indentFirst = false;
|
||||
|
||||
// Strip off any preceeding whitespace only lines. These are often used to
|
||||
// format the XML and CDATA blocks.
|
||||
while (lines.length && lines[0].trim() == "") {
|
||||
indentFirst = true;
|
||||
startLine++;
|
||||
lines.shift();
|
||||
}
|
||||
|
||||
// Strip off any whitespace lines at the end. These are often used to line
|
||||
// up the closing tags
|
||||
while (lines.length && lines[lines.length - 1].trim() == "") {
|
||||
lines.pop();
|
||||
}
|
||||
|
||||
if (!indentFirst) {
|
||||
let firstLine = lines.shift();
|
||||
firstLine = " ".repeat(reindent * INDENT_LEVEL) + firstLine;
|
||||
// ESLint counts columns starting at 1 rather than 0
|
||||
lineMap[scriptLines.length] = { line: startLine, offset: reindent * INDENT_LEVEL - (startColumn - 1) };
|
||||
scriptLines.push(firstLine);
|
||||
startLine++;
|
||||
}
|
||||
|
||||
// Find the preceeding 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);
|
||||
// Find the smallest indent level in use
|
||||
let minIndent = Math.min.apply(null, indents);
|
||||
|
||||
for (let line of lines) {
|
||||
if (line.trim().length == 0) {
|
||||
// Don't offset lines that are only whitespace, the only possible JS error
|
||||
// is trailing whitespace and we want it to point at the right place
|
||||
lineMap[scriptLines.length] = { line: startLine, offset: 0 };
|
||||
} else {
|
||||
line = " ".repeat(reindent * INDENT_LEVEL) + line.substring(minIndent);
|
||||
lineMap[scriptLines.length] = { line: startLine, offset: reindent * INDENT_LEVEL - (minIndent - 1) };
|
||||
}
|
||||
|
||||
scriptLines.push(line);
|
||||
startLine++;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
preprocess: function(text, filename) {
|
||||
xmlParseError = null;
|
||||
scriptLines = [];
|
||||
lineMap = [];
|
||||
|
||||
// Non-strict allows us to ignore many errors from entities and
|
||||
// preprocessing at the expense of failing to report some XML errors.
|
||||
// Unfortunately it also throws away the case of tagnames and attributes
|
||||
let parser = sax.parser(false, {
|
||||
lowercase: true,
|
||||
xmlns: true,
|
||||
});
|
||||
|
||||
parser.onerror = function(err) {
|
||||
xmlParseError = parseError(err);
|
||||
}
|
||||
|
||||
let xp = new XMLParser(parser);
|
||||
parser.write(text);
|
||||
|
||||
// Sanity checks to make sure we're dealing with an XBL document
|
||||
let document = xp.document;
|
||||
if (document.children.length != 1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let bindings = document.children[0];
|
||||
if (bindings.local != "bindings" || bindings.namespace != NS_XBL) {
|
||||
return [];
|
||||
}
|
||||
|
||||
for (let comment of document.comments) {
|
||||
addSyntheticLine(`/*`, 0, true);
|
||||
for (let line of comment.split("\n")) {
|
||||
addSyntheticLine(`${line.trim()}`, 0, true);
|
||||
}
|
||||
addSyntheticLine(`*/`, 0, true);
|
||||
}
|
||||
|
||||
addSyntheticLine(`this.bindings = {`, bindings.textLine);
|
||||
|
||||
for (let binding of bindings.children) {
|
||||
if (binding.local != "binding" || binding.namespace != NS_XBL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
addSyntheticLine(indent(1) + `"${binding.attributes.id}": {`, binding.textLine);
|
||||
|
||||
for (let part of binding.children) {
|
||||
if (part.namespace != NS_XBL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (part.local == "implementation") {
|
||||
addSyntheticLine(indent(2) + `implementation: {`, part.textLine);
|
||||
} else if (part.local == "handlers") {
|
||||
addSyntheticLine(indent(2) + `handlers: [`, part.textLine);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let item of part.children) {
|
||||
if (item.namespace != NS_XBL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (item.local) {
|
||||
case "field": {
|
||||
// Fields are something like lazy getter functions
|
||||
|
||||
// Ignore empty fields
|
||||
if (item.textContent.trim().length == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
addSyntheticLine(indent(3) + `get ${item.attributes.name}() {`, item.textLine);
|
||||
addSyntheticLine(indent(4) + `return (`, item.textLine);
|
||||
|
||||
// Remove trailing semicolons, as we are adding our own
|
||||
item.textContent = item.textContent.replace(/;(?=\s*$)/, "");
|
||||
addNodeLines(item, 5);
|
||||
|
||||
addSyntheticLine(indent(4) + `);`, item.textLine);
|
||||
addSyntheticLine(indent(3) + `},`, item.textEndLine);
|
||||
break;
|
||||
}
|
||||
case "constructor":
|
||||
case "destructor": {
|
||||
// Constructors and destructors become function declarations
|
||||
addSyntheticLine(indent(3) + `${item.local}() {`, item.textLine);
|
||||
addNodeLines(item, 4);
|
||||
addSyntheticLine(indent(3) + `},`, item.textEndLine);
|
||||
break;
|
||||
}
|
||||
case "method": {
|
||||
// Methods become function declarations with the appropriate params
|
||||
|
||||
let params = item.children.filter(n => n.local == "parameter" && n.namespace == NS_XBL)
|
||||
.map(n => n.attributes.name)
|
||||
.join(", ");
|
||||
let body = item.children.filter(n => n.local == "body" && n.namespace == NS_XBL)[0];
|
||||
|
||||
addSyntheticLine(indent(3) + `${item.attributes.name}(${params}) {`, item.textLine);
|
||||
addNodeLines(body, 4);
|
||||
addSyntheticLine(indent(3) + `},`, item.textEndLine);
|
||||
break;
|
||||
}
|
||||
case "property": {
|
||||
// Properties become one or two function declarations
|
||||
for (let propdef of item.children) {
|
||||
if (propdef.namespace != NS_XBL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propdef.local == "setter") {
|
||||
addSyntheticLine(indent(3) + `set ${item.attributes.name}(val) {`, propdef.textLine);
|
||||
} else if (propdef.local == "getter") {
|
||||
addSyntheticLine(indent(3) + `get ${item.attributes.name}() {`, propdef.textLine);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
addNodeLines(propdef, 4);
|
||||
addSyntheticLine(indent(3) + `},`, propdef.textEndLine);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "handler": {
|
||||
// Handlers become a function declaration with an `event` parameter
|
||||
addSyntheticLine(indent(3) + `function(event) {`, item.textLine);
|
||||
addNodeLines(item, 4);
|
||||
addSyntheticLine(indent(3) + `},`, item.textEndLine);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
addSyntheticLine(indent(2) + (part.local == "implementation" ? `},` : `],`), part.textEndLine);
|
||||
}
|
||||
addSyntheticLine(indent(1) + `},`, binding.textEndLine);
|
||||
}
|
||||
addSyntheticLine(`};`, bindings.textEndLine);
|
||||
|
||||
let script = scriptLines.join("\n") + "\n";
|
||||
return [script];
|
||||
},
|
||||
|
||||
postprocess: function(messages, filename) {
|
||||
// If there was an XML parse error then just return that
|
||||
if (xmlParseError) {
|
||||
return [xmlParseError];
|
||||
}
|
||||
|
||||
// For every message from every script block update the line to point to the
|
||||
// correct place.
|
||||
let errors = [];
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
for (let message of messages[i]) {
|
||||
// ESLint indexes lines starting at 1 but our arrays start at 0
|
||||
let mapped = lineMap[message.line - 1];
|
||||
|
||||
message.line = mapped.line + 1;
|
||||
if (mapped.offset) {
|
||||
message.column -= mapped.offset;
|
||||
} else {
|
||||
message.column = NaN;
|
||||
}
|
||||
|
||||
errors.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* Based on npm coding standards at https://docs.npmjs.com/misc/coding-style.
|
||||
*
|
||||
* The places we differ from the npm coding style:
|
||||
* - Commas should be at the end of a line.
|
||||
* - Always use semicolons.
|
||||
* - Functions should not have whitespace before params.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
|
||||
"rules": {
|
||||
"brace-style": ["error", "1tbs"],
|
||||
"camelcase": "error",
|
||||
"comma-dangle": ["error", "never"],
|
||||
"comma-spacing": "error",
|
||||
"comma-style": ["error", "last"],
|
||||
"curly": ["error", "multi-line"],
|
||||
"handle-callback-err": ["error", "er"],
|
||||
"indent": ["error", 2, {"SwitchCase": 1}],
|
||||
"max-len": ["error", 80, "error"],
|
||||
"no-multiple-empty-lines": ["error", {"max": 1}],
|
||||
"no-undef": "error",
|
||||
"no-undef-init": "error",
|
||||
"no-unexpected-multiline": "error",
|
||||
"object-curly-spacing": "off",
|
||||
"one-var": ["error", "never"],
|
||||
"operator-linebreak": ["error", "after"],
|
||||
"semi": ["error", "always"],
|
||||
"space-before-blocks": "error",
|
||||
"space-before-function-paren": ["error", "never"],
|
||||
"keyword-spacing": "error",
|
||||
"strict": ["error", "global"],
|
||||
},
|
||||
|
||||
// Globals accessible within node modules.
|
||||
"globals": {
|
||||
"DTRACE_HTTP_CLIENT_REQUEST": true,
|
||||
"DTRACE_HTTP_CLIENT_RESPONSE": true,
|
||||
"DTRACE_HTTP_SERVER_REQUEST": true,
|
||||
"DTRACE_HTTP_SERVER_RESPONSE": true,
|
||||
"DTRACE_NET_SERVER_CONNECTION": true,
|
||||
"DTRACE_NET_STREAM_END": true,
|
||||
"Intl": true,
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
* @fileoverview Check that there's a removeEventListener for each
|
||||
* addEventListener and an off for each on.
|
||||
* Note that for now, this rule is rather simple in that it only checks that
|
||||
* for each event name there is both an add and remove listener. It doesn't
|
||||
* check that these are called on the right objects or with the same callback.
|
||||
*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
module.exports = function(context) {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
var DICTIONARY = {
|
||||
"addEventListener": "removeEventListener",
|
||||
"on": "off"
|
||||
};
|
||||
// Invert this dictionary to make it easy later.
|
||||
var INVERTED_DICTIONARY = {};
|
||||
for (var i in DICTIONARY) {
|
||||
INVERTED_DICTIONARY[DICTIONARY[i]] = i;
|
||||
}
|
||||
|
||||
// Collect the add/remove listeners in these 2 arrays.
|
||||
var addedListeners = [];
|
||||
var removedListeners = [];
|
||||
|
||||
function addAddedListener(node) {
|
||||
addedListeners.push({
|
||||
functionName: node.callee.property.name,
|
||||
type: node.arguments[0].value,
|
||||
node: node.callee.property,
|
||||
useCapture: node.arguments[2] ? node.arguments[2].value : null
|
||||
});
|
||||
}
|
||||
|
||||
function addRemovedListener(node) {
|
||||
removedListeners.push({
|
||||
functionName: node.callee.property.name,
|
||||
type: node.arguments[0].value,
|
||||
useCapture: node.arguments[2] ? node.arguments[2].value : null
|
||||
});
|
||||
}
|
||||
|
||||
function getUnbalancedListeners() {
|
||||
var unbalanced = [];
|
||||
|
||||
for (var j = 0; j < addedListeners.length; j++) {
|
||||
if (!hasRemovedListener(addedListeners[j])) {
|
||||
unbalanced.push(addedListeners[j]);
|
||||
}
|
||||
}
|
||||
addedListeners = removedListeners = [];
|
||||
|
||||
return unbalanced;
|
||||
}
|
||||
|
||||
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) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
CallExpression: function(node) {
|
||||
if (node.arguments.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.callee.type === "MemberExpression") {
|
||||
var listenerMethodName = node.callee.property.name;
|
||||
|
||||
if (DICTIONARY.hasOwnProperty(listenerMethodName)) {
|
||||
addAddedListener(node);
|
||||
} else if (INVERTED_DICTIONARY.hasOwnProperty(listenerMethodName)) {
|
||||
addRemovedListener(node);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"Program:exit": function() {
|
||||
getUnbalancedListeners().forEach(function(listener) {
|
||||
context.report(listener.node,
|
||||
"No corresponding '{{functionName}}({{type}})' was found.",
|
||||
{
|
||||
functionName: DICTIONARY[listener.functionName],
|
||||
type: listener.type
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* @fileoverview Import globals from browser.js.
|
||||
*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var helpers = require("../helpers");
|
||||
var globals = require("../globals");
|
||||
|
||||
const SCRIPTS = [
|
||||
//"browser/base/content/nsContextMenu.js",
|
||||
"toolkit/content/contentAreaUtils.js",
|
||||
"browser/components/places/content/editBookmarkOverlay.js",
|
||||
"toolkit/components/printing/content/printUtils.js",
|
||||
"toolkit/content/viewZoomOverlay.js",
|
||||
"browser/components/places/content/browserPlacesViews.js",
|
||||
"browser/base/content/browser.js",
|
||||
"browser/components/downloads/content/downloads.js",
|
||||
"browser/components/downloads/content/indicator.js",
|
||||
"browser/components/customizableui/content/panelUI.js",
|
||||
"toolkit/components/viewsource/content/viewSourceUtils.js",
|
||||
"browser/base/content/browser-addons.js",
|
||||
"browser/base/content/browser-ctrlTab.js",
|
||||
"browser/base/content/browser-customization.js",
|
||||
"browser/base/content/browser-devedition.js",
|
||||
"browser/base/content/browser-feeds.js",
|
||||
"browser/base/content/browser-fullScreenAndPointerLock.js",
|
||||
"browser/base/content/browser-fullZoom.js",
|
||||
"browser/base/content/browser-gestureSupport.js",
|
||||
"browser/base/content/browser-media.js",
|
||||
"browser/base/content/browser-places.js",
|
||||
"browser/base/content/browser-plugins.js",
|
||||
"browser/base/content/browser-refreshblocker.js",
|
||||
"browser/base/content/browser-safebrowsing.js",
|
||||
"browser/base/content/browser-sidebar.js",
|
||||
"browser/base/content/browser-social.js",
|
||||
"browser/base/content/browser-syncui.js",
|
||||
"browser/base/content/browser-tabsintitlebar.js",
|
||||
"browser/base/content/browser-thumbnails.js",
|
||||
"browser/base/content/browser-trackingprotection.js",
|
||||
"browser/base/content/browser-data-submission-info-bar.js",
|
||||
"browser/base/content/browser-fxaccounts.js"
|
||||
];
|
||||
|
||||
module.exports = function(context) {
|
||||
return {
|
||||
Program: function(node) {
|
||||
if (helpers.getTestType(this) != "browser" &&
|
||||
!helpers.getIsHeadFile(this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let filepath = helpers.getAbsoluteFilePath(context);
|
||||
let root = helpers.getRootDir(filepath);
|
||||
for (let script of SCRIPTS) {
|
||||
let fileName = path.join(root, script);
|
||||
try {
|
||||
let newGlobals = globals.getGlobalsForFile(fileName);
|
||||
helpers.addGlobals(newGlobals, context.getScope());
|
||||
} catch (e) {
|
||||
context.report(
|
||||
node,
|
||||
"Could not load globals from file {{filePath}}: {{error}}",
|
||||
{
|
||||
filePath: path.relative(root, fileName),
|
||||
error: e
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* @fileoverview Discovers all globals for the current file.
|
||||
*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
module.exports = require("../globals").getESLintGlobalParser;
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* @fileoverview Import globals from head.js and from any files that were
|
||||
* imported by head.js (as far as we can correctly resolve the path).
|
||||
*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var helpers = require("../helpers");
|
||||
var globals = require("../globals");
|
||||
|
||||
module.exports = function(context) {
|
||||
|
||||
function importHead(path, node) {
|
||||
try {
|
||||
let stats = fs.statSync(path);
|
||||
if (!stats.isFile()) {
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
let newGlobals = globals.getGlobalsForFile(path);
|
||||
helpers.addGlobals(newGlobals, context.getScope());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
Program: function(node) {
|
||||
let heads = helpers.getTestHeadFiles(this);
|
||||
for (let head of heads) {
|
||||
importHead(head, node);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* @fileoverview Simply marks `test` (the test method) or `run_test` as used when
|
||||
* in mochitests or xpcshell tests respectively. This avoids ESLint telling us
|
||||
* that the function is never called.
|
||||
*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
var helpers = require("../helpers");
|
||||
|
||||
module.exports = function(context) {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
Program: function() {
|
||||
if (helpers.getTestType(this) == "browser") {
|
||||
context.markVariableAsUsed("test");
|
||||
return;
|
||||
}
|
||||
|
||||
if (helpers.getTestType(this) == "xpcshell") {
|
||||
context.markVariableAsUsed("run_test");
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* @fileoverview warns against using hungarian notation in function arguments
|
||||
* (i.e. aArg).
|
||||
*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
module.exports = function(context) {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function isPrefixed(name) {
|
||||
return name.length >= 2 && /^a[A-Z]/.test(name);
|
||||
}
|
||||
|
||||
function deHungarianize(name) {
|
||||
return name.substring(1, 2).toLowerCase() +
|
||||
name.substring(2, name.length);
|
||||
}
|
||||
|
||||
function checkFunction(node) {
|
||||
for (var i = 0; i < node.params.length; i++) {
|
||||
var param = node.params[i];
|
||||
if (param.name && isPrefixed(param.name)) {
|
||||
var errorObj = {
|
||||
name: param.name,
|
||||
suggestion: deHungarianize(param.name)
|
||||
};
|
||||
context.report(param,
|
||||
"Parameter '{{name}}' uses Hungarian Notation, " +
|
||||
"consider using '{{suggestion}}' instead.",
|
||||
errorObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
"FunctionDeclaration": checkFunction,
|
||||
"ArrowFunctionExpression": checkFunction,
|
||||
"FunctionExpression": checkFunction
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
/**
|
||||
* @fileoverview Prevent access to CPOWs in browser mochitests.
|
||||
*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
var helpers = require("../helpers");
|
||||
|
||||
var cpows = [
|
||||
/^gBrowser\.contentWindow/,
|
||||
/^gBrowser\.contentDocument/,
|
||||
/^gBrowser\.selectedBrowser.contentWindow/,
|
||||
/^browser\.contentDocument/,
|
||||
/^window\.content/
|
||||
];
|
||||
|
||||
var isInContentTask = false;
|
||||
|
||||
module.exports = function(context) {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function showError(node, identifier) {
|
||||
if (isInContentTask) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.report({
|
||||
node: node,
|
||||
message: identifier +
|
||||
" is a possible Cross Process Object Wrapper (CPOW)."
|
||||
});
|
||||
}
|
||||
|
||||
function isContentTask(node) {
|
||||
return node &&
|
||||
node.type === "MemberExpression" &&
|
||||
node.property.type === "Identifier" &&
|
||||
node.property.name === "spawn" &&
|
||||
node.object.type === "Identifier" &&
|
||||
node.object.name === "ContentTask";
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
CallExpression: function(node) {
|
||||
if (isContentTask(node.callee)) {
|
||||
isInContentTask = true;
|
||||
}
|
||||
},
|
||||
|
||||
"CallExpression:exit": function(node) {
|
||||
if (isContentTask(node.callee)) {
|
||||
isInContentTask = false;
|
||||
}
|
||||
},
|
||||
|
||||
MemberExpression: function(node) {
|
||||
if (helpers.getTestType(this) != "browser") {
|
||||
return;
|
||||
}
|
||||
|
||||
var expression = context.getSource(node);
|
||||
|
||||
// Only report a single CPOW error per node -- so if checking
|
||||
// |cpows| reports one, don't report another below.
|
||||
var someCpowFound = cpows.some(function(cpow) {
|
||||
if (cpow.test(expression)) {
|
||||
showError(node, expression);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (!someCpowFound && helpers.getIsGlobalScope(context.getAncestors())) {
|
||||
if (/^content\./.test(expression)) {
|
||||
showError(node, expression);
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Identifier: function(node) {
|
||||
if (helpers.getTestType(this) != "browser") {
|
||||
return;
|
||||
}
|
||||
|
||||
var expression = context.getSource(node);
|
||||
if (expression == "content" || /^content\./.test(expression)) {
|
||||
if (node.parent.type === "MemberExpression" &&
|
||||
node.parent.object &&
|
||||
node.parent.object.type === "Identifier" &&
|
||||
node.parent.object.name != "content") {
|
||||
return;
|
||||
}
|
||||
showError(node, expression);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* @fileoverview Reject use of single argument Cu.import
|
||||
*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
var helpers = require("../helpers");
|
||||
|
||||
module.exports = function(context) {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
"CallExpression": function(node) {
|
||||
if (node.callee.type === "MemberExpression") {
|
||||
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 === "import" &&
|
||||
node.arguments.length === 1) {
|
||||
context.report(node, "Single argument Cu.import exposes new " +
|
||||
"globals to all modules");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* @fileoverview Reject use of Cu.importGlobalProperties
|
||||
*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
var helpers = require("../helpers");
|
||||
|
||||
module.exports = function(context) {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
"CallExpression": function(node) {
|
||||
if (node.callee.type === "MemberExpression") {
|
||||
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") {
|
||||
context.report(node, "Unexpected call to Cu.importGlobalProperties");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* @fileoverview Reject some uses of require.
|
||||
*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
module.exports = function(context) {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
if (typeof(context.options[0]) !== "string") {
|
||||
throw new Error("reject-some-requires expects a regexp");
|
||||
}
|
||||
const RX = new RegExp(context.options[0]);
|
||||
|
||||
const checkPath = function(node, path) {
|
||||
if (RX.test(path)) {
|
||||
context.report(node, `require(${path}) is not allowed`);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
"CallExpression": function(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") {
|
||||
checkPath(node, node.arguments[2].value);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* @fileoverview Marks all var declarations that are not at the top level
|
||||
* invalid.
|
||||
*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
var helpers = require("../helpers");
|
||||
|
||||
module.exports = function(context) {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
"VariableDeclaration": function(node) {
|
||||
if (node.kind === "var") {
|
||||
if (helpers.getIsGlobalScope(context.getAncestors())) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.report(node, "Unexpected var, use let or const instead.");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
29
tools/lint/eslint/eslint-plugin-mozilla/package.json
Normal file
29
tools/lint/eslint/eslint-plugin-mozilla/package.json
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "eslint-plugin-mozilla",
|
||||
"version": "0.2.5",
|
||||
"description": "A collection of rules that help enforce JavaScript coding standard in the Mozilla project.",
|
||||
"keywords": [
|
||||
"eslint",
|
||||
"eslintplugin",
|
||||
"eslint-plugin",
|
||||
"mozilla",
|
||||
"firefox"
|
||||
],
|
||||
"bugs": {
|
||||
"url": "https://bugzilla.mozilla.org/enter_bug.cgi?product=Firefox&component=Developer%20Tools"
|
||||
},
|
||||
"homepage": "https://bugzilla.mozilla.org/show_bug.cgi?id=1203520",
|
||||
"author": "Mike Ratcliffe",
|
||||
"main": "lib/index.js",
|
||||
"dependencies": {
|
||||
"escope": "^3.6.0",
|
||||
"espree": "^3.2.0",
|
||||
"estraverse": "^4.2.0",
|
||||
"ini-parser": "^0.0.2",
|
||||
"sax": "^1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"license": "MPL-2.0"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue