diff options
Diffstat (limited to 'tools/lint/eslint')
23 files changed, 3245 insertions, 0 deletions
diff --git a/tools/lint/eslint/eslint-plugin-mozilla/LICENSE b/tools/lint/eslint/eslint-plugin-mozilla/LICENSE new file mode 100644 index 000000000..e87a115e4 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/LICENSE @@ -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. + diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/globals.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/globals.js new file mode 100644 index 000000000..acbfa0684 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/globals.js @@ -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; + } +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/helpers.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/helpers.js new file mode 100644 index 000000000..50e00ab97 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/helpers.js @@ -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(/"$/, ""); + } +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js new file mode 100644 index 000000000..e1f694c36 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js @@ -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 + } +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/processors/xbl-bindings.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/processors/xbl-bindings.js new file mode 100644 index 000000000..dc09550f2 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/processors/xbl-bindings.js @@ -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; + } +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/.eslintrc.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/.eslintrc.js new file mode 100644 index 000000000..505a3ea82 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/.eslintrc.js @@ -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, + }, +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/balanced-listeners.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/balanced-listeners.js new file mode 100644 index 000000000..c658a6b44 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/balanced-listeners.js @@ -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
+ });
+ });
+ }
+ };
+};
diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-browserjs-globals.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-browserjs-globals.js new file mode 100644 index 000000000..313af2d71 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-browserjs-globals.js @@ -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 + } + ); + } + } + } + }; +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-globals.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-globals.js new file mode 100644 index 000000000..053a9e702 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-globals.js @@ -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; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-headjs-globals.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-headjs-globals.js new file mode 100644 index 000000000..783642f58 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-headjs-globals.js @@ -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); + } + } + }; +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/mark-test-function-used.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/mark-test-function-used.js new file mode 100644 index 000000000..b2e8ec294 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/mark-test-function-used.js @@ -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; + } + } + }; +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-aArgs.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-aArgs.js new file mode 100644 index 000000000..267f6836f --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-aArgs.js @@ -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
+ };
+};
diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-cpows-in-tests.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-cpows-in-tests.js new file mode 100644 index 000000000..415cb2fc9 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-cpows-in-tests.js @@ -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; + } + } + }; +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-single-arg-cu-import.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-single-arg-cu-import.js new file mode 100644 index 000000000..b295f3555 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-single-arg-cu-import.js @@ -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"); + } + } + } + }; +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-importGlobalProperties.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-importGlobalProperties.js new file mode 100644 index 000000000..0661c91d4 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-importGlobalProperties.js @@ -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"); + } + } + } + }; +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-some-requires.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-some-requires.js new file mode 100644 index 000000000..746f98a1f --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-some-requires.js @@ -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); + } + } + }; +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/var-only-at-top-level.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/var-only-at-top-level.js new file mode 100644 index 000000000..a1e14e166 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/var-only-at-top-level.js @@ -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."); + } + } + }; +}; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/package.json b/tools/lint/eslint/eslint-plugin-mozilla/package.json new file mode 100644 index 000000000..2f4a85172 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/package.json @@ -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" +} diff --git a/tools/lint/eslint/manifest.tt b/tools/lint/eslint/manifest.tt new file mode 100644 index 000000000..c98f6455f --- /dev/null +++ b/tools/lint/eslint/manifest.tt @@ -0,0 +1,9 @@ +[ +{ +"size": 2768586, +"visibility": "public", +"digest": "1b9a7c5b1ca8d7d2aeb803055129d1cb0fa0d17b90dd3cf852ea77d86d1b1d9d09f34007a71908074afef9ce1ab87972a5cf16a36952e1a6159f7abfc6fa15b3", +"algorithm": "sha512", +"filename": "eslint.tar.gz" +} +] diff --git a/tools/lint/eslint/modules.json b/tools/lint/eslint/modules.json new file mode 100644 index 000000000..34ebfc6c1 --- /dev/null +++ b/tools/lint/eslint/modules.json @@ -0,0 +1,247 @@ +{ + "AboutHome.jsm": ["AboutHomeUtils", "AboutHome"], + "AddonLogging.jsm": ["LogManager"], + "AddonManager.jsm": ["AddonManager", "AddonManagerPrivate"], + "addons.js": ["AddonsEngine", "AddonValidator"], + "addons.jsm": ["Addon", "STATE_ENABLED", "STATE_DISABLED"], + "addonsreconciler.js": ["AddonsReconciler", "CHANGE_INSTALLED", "CHANGE_UNINSTALLED", "CHANGE_ENABLED", "CHANGE_DISABLED"], + "AddonTestUtils.jsm": ["AddonTestUtils", "MockAsyncShutdown"], + "addonutils.js": ["AddonUtils"], + "ajv-4.1.1.js": ["Ajv"], + "AlertsHelper.jsm": [], + "AppData.jsm": ["makeFakeAppDir"], + "AppInfo.jsm": ["newAppInfo", "getAppInfo", "updateAppInfo"], + "AppsServiceChild.jsm": ["DOMApplicationRegistry", "WrappedManifestCache"], + "arrays.js": ["inArray", "getSet", "indexOf", "remove", "rindexOf", "compare"], + "assertions.js": ["Assert", "Expect"], + "async.js": ["Async"], + "AsyncSpellCheckTestHelper.jsm": ["onSpellCheck"], + "Battery.jsm": ["GetBattery", "Battery"], + "blocklist-clients.js": ["AddonBlocklistClient", "GfxBlocklistClient", "OneCRLBlocklistClient", "PluginBlocklistClient", "FILENAME_ADDONS_JSON", "FILENAME_GFX_JSON", "FILENAME_PLUGINS_JSON"], + "blocklist-updater.js": ["checkVersions", "addTestBlocklistClient"], + "bogus_element_type.jsm": [], + "bookmark_validator.js": ["BookmarkValidator", "BookmarkProblemData"], + "bookmarks.js": ["BookmarksEngine", "PlacesItem", "Bookmark", "BookmarkFolder", "BookmarkQuery", "Livemark", "BookmarkSeparator"], + "bookmarks.jsm": ["PlacesItem", "Bookmark", "Separator", "Livemark", "BookmarkFolder", "DumpBookmarks"], + "BootstrapMonitor.jsm": ["monitor"], + "browser-loader.js": ["BrowserLoader"], + "browserid_identity.js": ["BrowserIDManager", "AuthenticationError"], + "CertUtils.jsm": ["BadCertHandler", "checkCert", "readCertPrefs", "validateCert"], + "clients.js": ["ClientEngine", "ClientsRec"], + "CloudSyncAdapters.jsm": ["Adapters"], + "CloudSyncBookmarks.jsm": ["Bookmarks"], + "CloudSyncBookmarksFolderCache.jsm": ["FolderCache"], + "CloudSyncEventSource.jsm": ["EventSource"], + "CloudSyncLocal.jsm": ["Local"], + "CloudSyncPlacesWrapper.jsm": ["PlacesWrapper"], + "CloudSyncTabs.jsm": ["Tabs"], + "cluster.js": ["ClusterManager"], + "collection_validator.js": ["CollectionValidator", "CollectionProblemData"], + "Console.jsm": ["console", "ConsoleAPI"], + "Constants.jsm": ["Roles", "Events", "Relations", "Filters", "States", "Prefilters"], + "ContactDB.jsm": ["ContactDB", "DB_NAME", "STORE_NAME", "SAVED_GETALL_STORE_NAME", "REVISION_STORE", "DB_VERSION"], + "content-server.jsm": ["init"], + "content.jsm": ["registerContentFrame"], + "ContentCrashHandlers.jsm": ["TabCrashHandler", "PluginCrashReporter", "UnsubmittedCrashHandler"], + "ContentObservers.jsm": [], + "ContentPrefUtils.jsm": ["ContentPref", "cbHandleResult", "cbHandleError", "cbHandleCompletion", "safeCallback"], + "controller.js": ["MozMillController", "globalEventRegistry", "sleep", "windowMap"], + "cookies.js": ["Cookies"], + "CoverageUtils.jsm": ["CoverageCollector"], + "CrashManagerTest.jsm": ["configureLogging", "getManager", "sleep", "TestingCrashManager"], + "dbg-client.jsm": ["DebuggerTransport", "DebuggerClient", "RootClient", "LongStringClient", "EnvironmentClient", "ObjectClient"], + "dbg-server.jsm": ["DebuggerServer", "ActorPool", "OriginalLocation"], + "debug.js": ["NS_ASSERT"], + "declined.js": ["DeclinedEngines"], + "dispatcher.js": ["Dispatcher"], + "distribution.js": ["DistributionCustomizer"], + "DNSTypes.jsm": ["DNS_QUERY_RESPONSE_CODES", "DNS_AUTHORITATIVE_ANSWER_CODES", "DNS_CLASS_CODES", "DNS_RECORD_TYPES"], + "dom.js": ["getAttributes"], + "DOMRequestHelper.jsm": ["DOMRequestIpcHelper"], + "DownloadCore.jsm": ["Download", "DownloadSource", "DownloadTarget", "DownloadError", "DownloadSaver", "DownloadCopySaver", "DownloadLegacySaver", "DownloadPDFSaver"], + "DownloadList.jsm": ["DownloadList", "DownloadCombinedList", "DownloadSummary"], + "E10SAddonsRollout.jsm": ["isAddonPartOfE10SRollout"], + "elementslib.js": ["ID", "Link", "XPath", "Selector", "Name", "Anon", "AnonXPath", "Lookup", "_byID", "_byName", "_byAttrib", "_byAnonAttrib"], + "engines.js": ["EngineManager", "Engine", "SyncEngine", "Tracker", "Store", "Changeset"], + "enginesync.js": ["EngineSynchronizer"], + "errors.js": ["BaseError", "ApplicationQuitError", "AssertionError", "TimeoutError"], + "evaluate.js": ["evaluate", "sandbox", "Sandboxes"], + "event-emitter.js": ["EventEmitter"], + "EventUtils.js": ["disableNonTestMouseEvents", "sendMouseEvent", "sendChar", "sendString", "sendKey", "synthesizeMouse", "synthesizeTouch", "synthesizeMouseAtPoint", "synthesizeTouchAtPoint", "synthesizeMouseAtCenter", "synthesizeTouchAtCenter", "synthesizeWheel", "synthesizeKey", "synthesizeMouseExpectEvent", "synthesizeKeyExpectEvent", "synthesizeText", "synthesizeComposition", "synthesizeQuerySelectedText"], + "Extension.jsm": ["Extension", "ExtensionData"], + "ExtensionAPI.jsm": ["ExtensionAPI", "ExtensionAPIs"], + "ExtensionXPCShellUtils.jsm": ["ExtensionTestUtils"], + "fakeservices.js": ["FakeCryptoService", "FakeFilesystemService", "FakeGUIDService", "fakeSHA256HMAC"], + "file_expandosharing.jsm": ["checkFromJSM"], + "file_stringencoding.jsm": ["checkFromJSM"], + "file_url.jsm": ["checkFromJSM"], + "file_worker_url.jsm": ["checkFromJSM"], + "Finder.jsm": ["Finder", "GetClipboardSearchString"], + "FormAutofillContent.jsm": ["FormAutofillHandler"], + "forms.js": ["FormEngine", "FormRec", "FormValidator"], + "forms.jsm": ["FormData"], + "frame.js": ["Collector", "Runner", "events", "runTestFile", "log", "timers", "persisted", "shutdownApplication"], + "FrameScriptManager.jsm": ["getNewLoaderID"], + "fxa_utils.js": ["initializeIdentityWithTokenServerResponse"], + "fxaccounts.jsm": ["Authentication"], + "FxAccounts.jsm": ["fxAccounts", "FxAccounts"], + "FxAccountsOAuthGrantClient.jsm": ["FxAccountsOAuthGrantClient", "FxAccountsOAuthGrantClientError"], + "FxAccountsProfileClient.jsm": ["FxAccountsProfileClient", "FxAccountsProfileClientError"], + "FxAccountsPush.js": ["FxAccountsPushService"], + "FxAccountsStorage.jsm": ["FxAccountsStorageManagerCanStoreField", "FxAccountsStorageManager"], + "FxAccountsWebChannel.jsm": ["EnsureFxAccountsWebChannel"], + "FxaMigrator.jsm": ["fxaMigrator"], + "gDevTools.jsm": ["gDevTools", "gDevToolsBrowser"], + "gDevTools.jsm": ["gDevTools", "gDevToolsBrowser"], + "Geometry.jsm": ["Point", "Rect"], + "Gestures.jsm": ["GestureSettings", "GestureTracker"], + "GMPInstallManager.jsm": ["GMPInstallManager", "GMPExtractor", "GMPDownloader", "GMPAddon"], + "GMPProvider.jsm": [], + "GMPUtils.jsm": ["EME_ADOBE_ID", "GMP_PLUGIN_IDS", "GMPPrefs", "GMPUtils", "OPEN_H264_ID", "WIDEVINE_ID"], + "hawkclient.js": ["HawkClient"], + "hawkrequest.js": ["HAWKAuthenticatedRESTRequest", "deriveHawkCredentials"], + "HelperApps.jsm": ["App", "HelperApps"], + "history.js": ["HistoryEngine", "HistoryRec"], + "history.jsm": ["HistoryEntry", "DumpHistory"], + "Http.jsm": ["httpRequest", "percentEncode"], + "httpd.js": ["HTTP_400", "HTTP_401", "HTTP_402", "HTTP_403", "HTTP_404", "HTTP_405", "HTTP_406", "HTTP_407", "HTTP_408", "HTTP_409", "HTTP_410", "HTTP_411", "HTTP_412", "HTTP_413", "HTTP_414", "HTTP_415", "HTTP_417", "HTTP_500", "HTTP_501", "HTTP_502", "HTTP_503", "HTTP_504", "HTTP_505", "HttpError", "HttpServer"], + "identity.js": ["IdentityManager"], + "Identity.jsm": ["IdentityService"], + "IdentityUtils.jsm": ["checkDeprecated", "checkRenamed", "getRandomId", "objectCopy", "makeMessageObject"], + "import_module.jsm": ["MODULE_IMPORTED", "MODULE_URI", "SUBMODULE_IMPORTED", "same_scope", "SUBMODULE_IMPORTED_TO_SCOPE"], + "import_sub_module.jsm": ["SUBMODULE_IMPORTED", "test_obj"], + "InlineSpellChecker.jsm": ["InlineSpellChecker", "SpellCheckHelper"], + "JNI.jsm": ["JNI", "android_log"], + "jpakeclient.js": ["JPAKEClient", "SendCredentialsController"], + "Jsbeautify.jsm": ["jsBeautify"], + "jsdebugger.jsm": ["addDebuggerToGlobal"], + "json2.js": ["JSON"], + "keys.js": ["BulkKeyBundle", "SyncKeyBundle"], + "KeyValueParser.jsm": ["parseKeyValuePairsFromLines", "parseKeyValuePairs", "parseKeyValuePairsFromFile"], + "kinto-http-client.js": ["KintoHttpClient"], + "kinto-offline-client.js": ["loadKinto"], + "loader-plugin-raw.jsm": ["requireRawId"], + "loader.js": ["WorkerDebuggerLoader", "worker"], + "Loader.jsm": ["DevToolsLoader", "devtools", "BuiltinProvider", "require", "loader"], + "logger.jsm": ["Logger"], + "logging.js": ["getTestLogger", "initTestLogging"], + "LoginManagerContent.jsm": ["LoginManagerContent", "LoginFormFactory", "UserAutoCompleteResult"], + "LoginRecipes.jsm": ["LoginRecipesContent", "LoginRecipesParent"], + "logmanager.js": ["LogManager"], + "LogUtils.jsm": ["Logger"], + "lz4.js": ["Lz4"], + "lz4_internal.js": ["Primitives"], + "main.js": ["Weave"], + "MatchPattern.jsm": ["MatchPattern", "MatchGlobs", "MatchURLFilters"], + "mcc_iso3166_table.jsm": ["MCC_ISO3166_TABLE"], + "message.js": ["Command", "Message", "MessageOrigin", "Response"], + "Messaging.jsm": ["sendMessageToJava", "Messaging"], + "microformat-shiv.js": ["Microformats"], + "MigrationUtils.jsm": ["MigrationUtils", "MigratorPrototype"], + "MinimalIdentity.jsm": ["IdentityService"], + "mozelement.js": ["Elem", "Selector", "ID", "Link", "XPath", "Name", "Lookup", "MozMillElement", "MozMillCheckBox", "MozMillRadio", "MozMillDropList", "MozMillTextBox", "subclasses"], + "mozmill.js": ["controller", "utils", "elementslib", "os", "getBrowserController", "newBrowserController", "getAddonsController", "getPreferencesController", "newMail3PaneController", "getMail3PaneController", "wm", "platform", "getAddrbkController", "getMsgComposeController", "getDownloadsController", "Application", "findElement", "getPlacesController", "isMac", "isLinux", "isWindows", "firePythonCallback", "getAddons"], + "msgbroker.js": ["addListener", "addObject", "removeListener", "sendMessage", "log", "pass", "fail"], + "MulticastDNSAndroid.jsm": ["MulticastDNS"], + "NativeMessaging.jsm": ["HostManifestManager", "NativeApp"], + "NetworkPrioritizer.jsm": ["trackBrowserWindow"], + "NotificationDB.jsm": [], + "nsFormAutoCompleteResult.jsm": ["FormAutoCompleteResult"], + "objects.js": ["getLength"], + "observers.js": ["Observers"], + "offlineAppCache.jsm": ["OfflineAppCacheHelper"], + "OrientationChangeHandler.jsm": [], + "os.js": ["listDirectory", "getFileForPath", "abspath", "getPlatform"], + "osfile.jsm": ["OS"], + "osfile_async_front.jsm": ["OS"], + "osfile_native.jsm": ["read"], + "osfile_shared_allthreads.jsm": ["LOG", "clone", "Config", "Constants", "Type", "HollowStructure", "OSError", "Library", "declareFFI", "declareLazy", "declareLazyFFI", "normalizeBufferArgs", "projectValue", "isArrayBuffer", "isTypedArray", "defineLazyGetter", "OS"], + "osfile_unix_allthreads.jsm": ["declareFFI", "libc", "Error", "AbstractInfo", "AbstractEntry", "Type", "POS_START", "POS_CURRENT", "POS_END"], + "osfile_win_allthreads.jsm": ["declareFFI", "libc", "Error", "AbstractInfo", "AbstractEntry", "Type", "POS_START", "POS_CURRENT", "POS_END"], + "ospath_unix.jsm": ["basename", "dirname", "join", "normalize", "split", "toFileURI", "fromFileURI"], + "ospath_win.jsm": ["basename", "dirname", "join", "normalize", "split", "winGetDrive", "winIsAbsolute", "toFileURI", "fromFileURI"], + "OutputGenerator.jsm": ["UtteranceGenerator", "BrailleGenerator"], + "PageMenu.jsm": ["PageMenuParent", "PageMenuChild"], + "PageThumbs.jsm": ["PageThumbs", "PageThumbsStorage"], + "Parser.jsm": ["Parser", "ParserHelpers", "SyntaxTreeVisitor"], + "parsingTestHelpers.jsm": ["generateURIsFromDirTree"], + "passwords.js": ["PasswordEngine", "LoginRec", "PasswordValidator"], + "passwords.jsm": ["Password", "DumpPasswords"], + "PdfJsNetwork.jsm": ["NetworkManager"], + "PermissionSettings.jsm": ["PermissionSettingsModule"], + "PermissionsTable.jsm": ["PermissionsTable", "PermissionsReverseTable", "expandPermissions", "appendAccessToPermName", "isExplicitInPermissionsTable", "AllPossiblePermissions"], + "PhoneNumberMetaData.jsm": ["PHONE_NUMBER_META_DATA"], + "PlacesUtils.jsm": ["PlacesUtils", "PlacesAggregatedTransaction", "PlacesCreateFolderTransaction", "PlacesCreateBookmarkTransaction", "PlacesCreateSeparatorTransaction", "PlacesCreateLivemarkTransaction", "PlacesMoveItemTransaction", "PlacesRemoveItemTransaction", "PlacesEditItemTitleTransaction", "PlacesEditBookmarkURITransaction", "PlacesSetItemAnnotationTransaction", "PlacesSetPageAnnotationTransaction", "PlacesEditBookmarkKeywordTransaction", "PlacesEditBookmarkPostDataTransaction", "PlacesEditItemDateAddedTransaction", "PlacesEditItemLastModifiedTransaction", "PlacesSortFolderByNameTransaction", "PlacesTagURITransaction", "PlacesUntagURITransaction"], + "PluginProvider.jsm": [], + "PointerAdapter.jsm": ["PointerRelay", "PointerAdapter"], + "policies.js": ["ErrorHandler", "SyncScheduler"], + "prefs.js": ["PrefsEngine", "PrefRec"], + "prefs.jsm": ["Preference"], + "PresentationDeviceInfoManager.jsm": ["PresentationDeviceInfoService"], + "PromiseWorker.jsm": ["BasePromiseWorker"], + "PushCrypto.jsm": ["PushCrypto", "concatArray"], + "quit.js": ["goQuitApplication"], + "record.js": ["WBORecord", "RecordManager", "CryptoWrapper", "CollectionKeyManager", "Collection"], + "recursive_importA.jsm": ["foo", "bar"], + "recursive_importB.jsm": ["baz", "qux"], + "reflect.jsm": ["Reflect"], + "RemoteFinder.jsm": ["RemoteFinder", "RemoteFinderListener"], + "RemotePageManager.jsm": ["RemotePages", "RemotePageManager", "PageListener"], + "RemoteWebProgress.jsm": ["RemoteWebProgressManager"], + "resource.js": ["AsyncResource", "Resource"], + "responsivedesign.jsm": ["ResponsiveUIManager"], + "rest.js": ["RESTRequest", "RESTResponse", "TokenAuthenticatedRESTRequest", "SyncStorageRequest"], + "rotaryengine.js": ["RotaryEngine", "RotaryRecord", "RotaryStore", "RotaryTracker"], + "RTCStatsReport.jsm": ["convertToRTCStatsReport"], + "scratchpad-manager.jsm": ["ScratchpadManager"], + "server.js": ["MarionetteServer"], + "service.js": ["Service"], + "SettingsDB.jsm": ["SettingsDB", "SETTINGSDB_NAME", "SETTINGSSTORE_NAME"], + "SharedPromptUtils.jsm": ["PromptUtils", "EnableDelayHelper"], + "ShutdownLeaksCollector.jsm": ["ContentCollector"], + "SignInToWebsite.jsm": ["SignInToWebsiteController"], + "Social.jsm": ["Social", "OpenGraphBuilder", "DynamicResizeWatcher", "sizeSocialPanelToContent"], + "SpecialPowersObserver.jsm": ["SpecialPowersObserver", "SpecialPowersObserverFactory"], + "stack.js": ["findCallerFrame"], + "StateMachineHelper.jsm": ["State", "CommandType"], + "status.js": ["Status"], + "storageserver.js": ["ServerBSO", "StorageServerCallback", "StorageServerCollection", "StorageServer", "storageServerForUsers"], + "stringbundle.js": ["StringBundle"], + "strings.js": ["trim", "vslice"], + "StructuredLog.jsm": ["StructuredLogger", "StructuredFormatter"], + "StyleEditorUtil.jsm": ["getString", "assert", "log", "text", "wire", "showFilePicker"], + "subprocess_common.jsm": ["BaseProcess", "PromiseWorker", "SubprocessConstants"], + "subprocess_unix.jsm": ["SubprocessImpl"], + "subprocess_win.jsm": ["SubprocessImpl"], + "sync.jsm": ["Authentication"], + "tabs.js": ["TabEngine", "TabSetRecord"], + "tabs.jsm": ["BrowserTabs"], + "tcpsocket_test.jsm": ["createSocket", "createServer", "enablePrefsAndPermissions", "socketCompartmentInstanceOfArrayBuffer"], + "telemetry.js": ["SyncTelemetry"], + "test.jsm": ["Foo"], + "test2.jsm": ["Bar"], + "test_bug883784.jsm": ["Test"], + "Timer.jsm": ["setTimeout", "clearTimeout", "setInterval", "clearInterval"], + "tokenserverclient.js": ["TokenServerClient", "TokenServerClientError", "TokenServerClientNetworkError", "TokenServerClientServerError"], + "ToolboxProcess.jsm": ["BrowserToolboxProcess"], + "tps.jsm": ["ACTIONS", "TPS"], + "Translation.jsm": ["Translation", "TranslationTelemetry"], + "Traversal.jsm": ["TraversalRules", "TraversalHelper"], + "UpdateTelemetry.jsm": ["AUSTLMY"], + "userapi.js": ["UserAPI10Client"], + "util.js": ["getChromeWindow", "XPCOMUtils", "Services", "Utils", "Async", "Svc", "Str"], + "utils.js": ["applicationName", "assert", "Copy", "getBrowserObject", "getChromeWindow", "getWindows", "getWindowByTitle", "getWindowByType", "getWindowId", "getMethodInWindows", "getPreference", "saveDataURL", "setPreference", "sleep", "startTimer", "stopTimer", "takeScreenshot", "unwrapNode", "waitFor", "btoa", "encryptPayload", "isConfiguredWithLegacyIdentity", "ensureLegacyIdentityManager", "setBasicCredentials", "makeIdentityConfig", "makeFxAccountsInternalMock", "configureFxAccountIdentity", "configureIdentity", "SyncTestingInfrastructure", "waitForZeroTimer", "Promise", "add_identity_test", "MockFxaStorageManager", "AccountState", "sumHistogram", "CommonUtils", "CryptoUtils", "TestingUtils"], + "Utils.jsm": ["Utils", "Logger", "PivotContext", "PrefCache", "SettingCache"], + "VariablesView.jsm": ["VariablesView", "escapeHTML"], + "VariablesViewController.jsm": ["VariablesViewController", "StackFrameUtils"], + "version.jsm": ["VERSION"], + "vtt.jsm": ["WebVTT"], + "WebChannel.jsm": ["WebChannel", "WebChannelBroker"], + "WindowDraggingUtils.jsm": ["WindowDraggingElement"], + "windows.js": ["init", "map"], + "windows.jsm": ["BrowserWindows"], + "WindowsJumpLists.jsm": ["WinTaskbarJumpList"], + "WindowsPreviewPerTab.jsm": ["AeroPeek"], + "withs.js": ["startsWith", "endsWith"], + "xul-app.jsm": ["XulApp"] +} diff --git a/tools/lint/eslint/npm-shrinkwrap.json b/tools/lint/eslint/npm-shrinkwrap.json new file mode 100644 index 000000000..4421c4cd3 --- /dev/null +++ b/tools/lint/eslint/npm-shrinkwrap.json @@ -0,0 +1,718 @@ +{ + "name": "mach-eslint", + "dependencies": { + "acorn": { + "version": "4.0.3", + "from": "acorn@>=4.0.1 <5.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.3.tgz" + }, + "acorn-jsx": { + "version": "3.0.1", + "from": "acorn-jsx@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "dependencies": { + "acorn": { + "version": "3.3.0", + "from": "acorn@>=3.0.4 <4.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz" + } + } + }, + "ajv": { + "version": "4.8.2", + "from": "ajv@>=4.7.0 <5.0.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.8.2.tgz" + }, + "ajv-keywords": { + "version": "1.1.1", + "from": "ajv-keywords@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.1.1.tgz" + }, + "ansi-escapes": { + "version": "1.4.0", + "from": "ansi-escapes@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz" + }, + "ansi-regex": { + "version": "2.0.0", + "from": "ansi-regex@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + }, + "ansi-styles": { + "version": "2.2.1", + "from": "ansi-styles@>=2.2.1 <3.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz" + }, + "argparse": { + "version": "1.0.9", + "from": "argparse@>=1.0.7 <2.0.0", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz" + }, + "array-union": { + "version": "1.0.2", + "from": "array-union@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz" + }, + "array-uniq": { + "version": "1.0.3", + "from": "array-uniq@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz" + }, + "arrify": { + "version": "1.0.1", + "from": "arrify@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz" + }, + "balanced-match": { + "version": "0.4.2", + "from": "balanced-match@>=0.4.1 <0.5.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz" + }, + "brace-expansion": { + "version": "1.1.6", + "from": "brace-expansion@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz" + }, + "caller-path": { + "version": "0.1.0", + "from": "caller-path@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz" + }, + "callsites": { + "version": "0.2.0", + "from": "callsites@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz" + }, + "chalk": { + "version": "1.1.3", + "from": "chalk@>=1.1.3 <2.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz" + }, + "circular-json": { + "version": "0.3.1", + "from": "circular-json@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz" + }, + "cli-cursor": { + "version": "1.0.2", + "from": "cli-cursor@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz" + }, + "cli-width": { + "version": "2.1.0", + "from": "cli-width@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz" + }, + "co": { + "version": "4.6.0", + "from": "co@>=4.6.0 <5.0.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz" + }, + "code-point-at": { + "version": "1.1.0", + "from": "code-point-at@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz" + }, + "concat-map": { + "version": "0.0.1", + "from": "concat-map@0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + }, + "concat-stream": { + "version": "1.5.2", + "from": "concat-stream@>=1.4.6 <2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz" + }, + "core-util-is": { + "version": "1.0.2", + "from": "core-util-is@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" + }, + "d": { + "version": "0.1.1", + "from": "d@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz" + }, + "debug": { + "version": "2.3.0", + "from": "debug@>=2.1.1 <3.0.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.0.tgz" + }, + "deep-is": { + "version": "0.1.3", + "from": "deep-is@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" + }, + "del": { + "version": "2.2.2", + "from": "del@>=2.0.2 <3.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz" + }, + "doctrine": { + "version": "1.5.0", + "from": "doctrine@>=1.2.2 <2.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz" + }, + "dom-serializer": { + "version": "0.1.0", + "from": "dom-serializer@>=0.0.0 <1.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "from": "domelementtype@>=1.1.1 <1.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz" + } + } + }, + "domelementtype": { + "version": "1.3.0", + "from": "domelementtype@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz" + }, + "domhandler": { + "version": "2.3.0", + "from": "domhandler@>=2.3.0 <3.0.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz" + }, + "domutils": { + "version": "1.5.1", + "from": "domutils@>=1.5.1 <2.0.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz" + }, + "entities": { + "version": "1.1.1", + "from": "entities@>=1.1.1 <2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz" + }, + "es5-ext": { + "version": "0.10.12", + "from": "es5-ext@>=0.10.11 <0.11.0", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.12.tgz" + }, + "es6-iterator": { + "version": "2.0.0", + "from": "es6-iterator@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.0.tgz" + }, + "es6-map": { + "version": "0.1.4", + "from": "es6-map@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.4.tgz" + }, + "es6-set": { + "version": "0.1.4", + "from": "es6-set@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.4.tgz" + }, + "es6-symbol": { + "version": "3.1.0", + "from": "es6-symbol@>=3.1.0 <3.2.0", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.0.tgz" + }, + "es6-weak-map": { + "version": "2.0.1", + "from": "es6-weak-map@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.1.tgz" + }, + "escape-string-regexp": { + "version": "1.0.5", + "from": "escape-string-regexp@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + }, + "escope": { + "version": "3.6.0", + "from": "escope@>=3.6.0 <4.0.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz" + }, + "eslint": { + "version": "3.8.1", + "from": "eslint@3.8.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.8.1.tgz" + }, + "eslint-plugin-html": { + "version": "1.5.2", + "from": "eslint-plugin-html@1.5.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-1.5.2.tgz" + }, + "eslint-plugin-react": { + "version": "4.2.3", + "from": "eslint-plugin-react@4.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-4.2.3.tgz" + }, + "espree": { + "version": "3.3.2", + "from": "espree@>=3.2.0 <4.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.3.2.tgz" + }, + "esprima": { + "version": "2.7.3", + "from": "esprima@>=2.6.0 <3.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz" + }, + "esrecurse": { + "version": "4.1.0", + "from": "esrecurse@>=4.1.0 <5.0.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz", + "dependencies": { + "estraverse": { + "version": "4.1.1", + "from": "estraverse@>=4.1.0 <4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz" + } + } + }, + "estraverse": { + "version": "4.2.0", + "from": "estraverse@>=4.2.0 <5.0.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz" + }, + "esutils": { + "version": "2.0.2", + "from": "esutils@>=2.0.2 <3.0.0", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz" + }, + "event-emitter": { + "version": "0.3.4", + "from": "event-emitter@>=0.3.4 <0.4.0", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.4.tgz" + }, + "exit-hook": { + "version": "1.1.1", + "from": "exit-hook@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz" + }, + "fast-levenshtein": { + "version": "2.0.5", + "from": "fast-levenshtein@>=2.0.4 <2.1.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.5.tgz" + }, + "figures": { + "version": "1.7.0", + "from": "figures@>=1.3.5 <2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz" + }, + "file-entry-cache": { + "version": "2.0.0", + "from": "file-entry-cache@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz" + }, + "flat-cache": { + "version": "1.2.1", + "from": "flat-cache@>=1.2.1 <2.0.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.1.tgz" + }, + "fs.realpath": { + "version": "1.0.0", + "from": "fs.realpath@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + }, + "generate-function": { + "version": "2.0.0", + "from": "generate-function@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz" + }, + "generate-object-property": { + "version": "1.2.0", + "from": "generate-object-property@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz" + }, + "glob": { + "version": "7.1.1", + "from": "glob@>=7.0.3 <8.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz" + }, + "globals": { + "version": "9.12.0", + "from": "globals@>=9.2.0 <10.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.12.0.tgz" + }, + "globby": { + "version": "5.0.0", + "from": "globby@>=5.0.0 <6.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz" + }, + "graceful-fs": { + "version": "4.1.10", + "from": "graceful-fs@>=4.1.2 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.10.tgz" + }, + "has-ansi": { + "version": "2.0.0", + "from": "has-ansi@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz" + }, + "htmlparser2": { + "version": "3.9.2", + "from": "htmlparser2@>=3.8.2 <4.0.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz" + }, + "ignore": { + "version": "3.2.0", + "from": "ignore@>=3.1.5 <4.0.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.2.0.tgz" + }, + "imurmurhash": { + "version": "0.1.4", + "from": "imurmurhash@>=0.1.4 <0.2.0", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + }, + "inflight": { + "version": "1.0.6", + "from": "inflight@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + }, + "inherits": { + "version": "2.0.3", + "from": "inherits@>=2.0.1 <2.1.0", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz" + }, + "ini-parser": { + "version": "0.0.2", + "from": "ini-parser@>=0.0.2 <0.0.3", + "resolved": "https://registry.npmjs.org/ini-parser/-/ini-parser-0.0.2.tgz" + }, + "inquirer": { + "version": "0.12.0", + "from": "inquirer@>=0.12.0 <0.13.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "from": "is-fullwidth-code-point@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz" + }, + "is-my-json-valid": { + "version": "2.15.0", + "from": "is-my-json-valid@>=2.10.0 <3.0.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz" + }, + "is-path-cwd": { + "version": "1.0.0", + "from": "is-path-cwd@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz" + }, + "is-path-in-cwd": { + "version": "1.0.0", + "from": "is-path-in-cwd@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz" + }, + "is-path-inside": { + "version": "1.0.0", + "from": "is-path-inside@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz" + }, + "is-property": { + "version": "1.0.2", + "from": "is-property@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz" + }, + "is-resolvable": { + "version": "1.0.0", + "from": "is-resolvable@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz" + }, + "isarray": { + "version": "1.0.0", + "from": "isarray@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + }, + "js-yaml": { + "version": "3.6.1", + "from": "js-yaml@>=3.5.1 <4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz" + }, + "json-stable-stringify": { + "version": "1.0.1", + "from": "json-stable-stringify@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz" + }, + "jsonify": { + "version": "0.0.0", + "from": "jsonify@>=0.0.0 <0.1.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz" + }, + "jsonpointer": { + "version": "4.0.0", + "from": "jsonpointer@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.0.tgz" + }, + "levn": { + "version": "0.3.0", + "from": "levn@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" + }, + "lodash": { + "version": "4.16.6", + "from": "lodash@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.6.tgz" + }, + "minimatch": { + "version": "3.0.3", + "from": "minimatch@>=3.0.2 <4.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz" + }, + "minimist": { + "version": "0.0.8", + "from": "minimist@0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" + }, + "mkdirp": { + "version": "0.5.1", + "from": "mkdirp@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz" + }, + "ms": { + "version": "0.7.2", + "from": "ms@0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz" + }, + "mute-stream": { + "version": "0.0.5", + "from": "mute-stream@0.0.5", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz" + }, + "natural-compare": { + "version": "1.4.0", + "from": "natural-compare@>=1.4.0 <2.0.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + }, + "number-is-nan": { + "version": "1.0.1", + "from": "number-is-nan@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" + }, + "object-assign": { + "version": "4.1.0", + "from": "object-assign@>=4.0.1 <5.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz" + }, + "once": { + "version": "1.4.0", + "from": "once@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + }, + "onetime": { + "version": "1.1.0", + "from": "onetime@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz" + }, + "optionator": { + "version": "0.8.2", + "from": "optionator@>=0.8.2 <0.9.0", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz" + }, + "os-homedir": { + "version": "1.0.2", + "from": "os-homedir@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz" + }, + "path-is-absolute": { + "version": "1.0.1", + "from": "path-is-absolute@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + }, + "path-is-inside": { + "version": "1.0.2", + "from": "path-is-inside@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz" + }, + "pify": { + "version": "2.3.0", + "from": "pify@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" + }, + "pinkie": { + "version": "2.0.4", + "from": "pinkie@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" + }, + "pinkie-promise": { + "version": "2.0.1", + "from": "pinkie-promise@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" + }, + "pluralize": { + "version": "1.2.1", + "from": "pluralize@>=1.2.1 <2.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz" + }, + "prelude-ls": { + "version": "1.1.2", + "from": "prelude-ls@>=1.1.2 <1.2.0", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" + }, + "process-nextick-args": { + "version": "1.0.7", + "from": "process-nextick-args@>=1.0.6 <1.1.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz" + }, + "progress": { + "version": "1.1.8", + "from": "progress@>=1.1.8 <2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz" + }, + "readable-stream": { + "version": "2.0.6", + "from": "readable-stream@>=2.0.0 <2.1.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz" + }, + "readline2": { + "version": "1.0.1", + "from": "readline2@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz" + }, + "require-uncached": { + "version": "1.0.3", + "from": "require-uncached@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz" + }, + "resolve-from": { + "version": "1.0.1", + "from": "resolve-from@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz" + }, + "restore-cursor": { + "version": "1.0.1", + "from": "restore-cursor@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz" + }, + "rimraf": { + "version": "2.5.4", + "from": "rimraf@>=2.2.8 <3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz" + }, + "run-async": { + "version": "0.1.0", + "from": "run-async@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz" + }, + "rx-lite": { + "version": "3.1.2", + "from": "rx-lite@>=3.1.2 <4.0.0", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz" + }, + "sax": { + "version": "1.2.1", + "from": "sax@>=1.1.4 <2.0.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz" + }, + "shelljs": { + "version": "0.6.1", + "from": "shelljs@>=0.6.0 <0.7.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.6.1.tgz" + }, + "slice-ansi": { + "version": "0.0.4", + "from": "slice-ansi@0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz" + }, + "sprintf-js": { + "version": "1.0.3", + "from": "sprintf-js@>=1.0.2 <1.1.0", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + }, + "string_decoder": { + "version": "0.10.31", + "from": "string_decoder@>=0.10.0 <0.11.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + }, + "string-width": { + "version": "1.0.2", + "from": "string-width@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" + }, + "strip-ansi": { + "version": "3.0.1", + "from": "strip-ansi@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" + }, + "strip-bom": { + "version": "3.0.0", + "from": "strip-bom@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" + }, + "strip-json-comments": { + "version": "1.0.4", + "from": "strip-json-comments@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz" + }, + "supports-color": { + "version": "2.0.0", + "from": "supports-color@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" + }, + "table": { + "version": "3.8.3", + "from": "table@>=3.7.8 <4.0.0", + "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "from": "is-fullwidth-code-point@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz" + }, + "string-width": { + "version": "2.0.0", + "from": "string-width@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz" + } + } + }, + "text-table": { + "version": "0.2.0", + "from": "text-table@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + }, + "through": { + "version": "2.3.8", + "from": "through@>=2.3.6 <3.0.0", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + }, + "tryit": { + "version": "1.0.3", + "from": "tryit@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz" + }, + "type-check": { + "version": "0.3.2", + "from": "type-check@>=0.3.2 <0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" + }, + "typedarray": { + "version": "0.0.6", + "from": "typedarray@>=0.0.5 <0.1.0", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" + }, + "user-home": { + "version": "2.0.0", + "from": "user-home@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz" + }, + "util-deprecate": { + "version": "1.0.2", + "from": "util-deprecate@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + }, + "wordwrap": { + "version": "1.0.0", + "from": "wordwrap@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" + }, + "wrappy": { + "version": "1.0.2", + "from": "wrappy@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + }, + "write": { + "version": "0.2.1", + "from": "write@>=0.2.1 <0.3.0", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz" + }, + "xtend": { + "version": "4.0.1", + "from": "xtend@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + } + } +} diff --git a/tools/lint/eslint/package.json b/tools/lint/eslint/package.json new file mode 100644 index 000000000..9c0a8f803 --- /dev/null +++ b/tools/lint/eslint/package.json @@ -0,0 +1,16 @@ +{ + "name": "mach-eslint", + "description": "ESLint and external plugins for use with mach", + "repository": {}, + "license": "MPL-2.0", + "dependencies": { + "eslint": "3.8.1", + "eslint-plugin-html": "1.5.2", + "eslint-plugin-react": "4.2.3", + "escope": "^3.6.0", + "espree": "^3.2.0", + "estraverse": "^4.2.0", + "ini-parser": "^0.0.2", + "sax": "^1.1.4" + } +} diff --git a/tools/lint/eslint/update b/tools/lint/eslint/update new file mode 100755 index 000000000..477584236 --- /dev/null +++ b/tools/lint/eslint/update @@ -0,0 +1,70 @@ +#!/bin/sh +# Force the scripts working directory to be projdir/tools/lint/eslint. +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd $DIR + +echo "To complete this script you will need the following tokens from https://api.pub.build.mozilla.org/tokenauth/" +echo " - tooltool.upload.public" +echo " - tooltool.download.public" +echo "" +read -p "Are these tokens visible at the above URL (y/n)?" choice +case "$choice" in + y|Y ) + echo "" + echo "1. Go to https://api.pub.build.mozilla.org/" + echo "2. Log in using your Mozilla LDAP account." + echo "3. Click on \"Tokens.\"" + echo "4. Issue a user token with the permissions tooltool.upload.public and tooltool.download.public." + echo "" + echo "When you click issue you will be presented with a long string. Paste the string into a temporary file called ~/.tooltool-token." + echo "" + read -rsp $'Press any key to continue...\n' -n 1 + ;; + n|N ) + echo "" + echo "You will need to contact somebody that has these permissions... people most likely to have these permissions are members of the releng, ateam, a sheriff, mratcliffe, or jryans" + exit 1 + ;; + * ) + echo "" + echo "Invalid input." + continue + ;; +esac + +echo "" +echo "Removing node_modules and npm_shrinkwrap.json..." +rm -rf node_modules/ +rm npm-shrinkwrap.json + +echo "Installing eslint and external plugins..." +# ESLint and all _external_ plugins are listed in this directory's package.json, +# so a regular `npm install` will install them at the specified versions. +# The in-tree eslint-plugin-mozilla is kept out of this tooltool archive on +# purpose so that it can be changed by any developer without requiring tooltool +# access to make changes. +npm install + +echo "Creating npm shrinkwrap..." +npm shrinkwrap + +echo "Creating eslint.tar.gz..." +tar cvfz eslint.tar.gz node_modules + +echo "Downloading tooltool..." +wget https://raw.githubusercontent.com/mozilla/build-tooltool/master/tooltool.py +chmod +x tooltool.py + +echo "Adding eslint.tar.gz to tooltool..." +rm manifest.tt +./tooltool.py add --visibility public eslint.tar.gz + +echo "Uploading eslint.tar.gz to tooltool..." +./tooltool.py upload --authentication-file=~/.tooltool-token --message "node_modules folder update for tools/lint/eslint" + +echo "Cleaning up..." +rm eslint.tar.gz +rm tooltool.py + +echo "" +echo "Update complete, please commit and check in your changes." |