diff options
Diffstat (limited to 'tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-mixing-eager-and-lazy.js')
-rw-r--r-- | tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-mixing-eager-and-lazy.js | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-mixing-eager-and-lazy.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-mixing-eager-and-lazy.js new file mode 100644 index 0000000000..0d158731ea --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-mixing-eager-and-lazy.js @@ -0,0 +1,153 @@ +/** + * @fileoverview Reject use of lazy getters for modules that's loaded early in + * the startup process and not necessarily be lazy. + * + * 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 helpers = require("../helpers"); + +function isIdentifier(node, id) { + return node.type === "Identifier" && node.name === id; +} + +function isString(node) { + return node.type === "Literal" && typeof node.value === "string"; +} + +function checkMixed(loadedModules, context, node, type, resourceURI) { + if (!loadedModules.has(resourceURI)) { + loadedModules.set(resourceURI, type); + } + + if (loadedModules.get(resourceURI) === type) { + return; + } + + context.report({ + node, + messageId: "mixedEagerAndLazy", + data: { uri: resourceURI }, + }); +} + +module.exports = { + meta: { + docs: { + url: + "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-mixed-eager-and-lazy.html", + }, + messages: { + mixedEagerAndLazy: + 'Module "{{uri}}" is loaded eagerly, and should not be used for lazy getter.', + }, + type: "problem", + }, + + create(context) { + const loadedModules = new Map(); + + return { + ImportDeclaration(node) { + const resourceURI = node.source.value; + checkMixed(loadedModules, context, node, "eager", resourceURI); + }, + CallExpression(node) { + if (node.callee.type !== "MemberExpression") { + return; + } + + let callerSource; + try { + callerSource = helpers.getASTSource(node.callee); + } catch (e) { + return; + } + + if ( + (callerSource === "ChromeUtils.import" || + callerSource === "ChromeUtils.importESModule") && + helpers.getIsTopLevelAndUnconditionallyExecuted( + context.getAncestors() + ) + ) { + if (node.arguments.length < 1) { + return; + } + const resourceURINode = node.arguments[0]; + if (!isString(resourceURINode)) { + return; + } + checkMixed( + loadedModules, + context, + node, + "eager", + resourceURINode.value + ); + } + + if ( + callerSource === "XPCOMUtils.defineLazyModuleGetter" || + callerSource === "ChromeUtils.defineModuleGetter" + ) { + if (node.arguments.length < 3) { + return; + } + if (!isIdentifier(node.arguments[0], "lazy")) { + return; + } + + const resourceURINode = node.arguments[2]; + if (!isString(resourceURINode)) { + return; + } + checkMixed( + loadedModules, + context, + node, + "lazy", + resourceURINode.value + ); + } else if ( + callerSource === "XPCOMUtils.defineLazyModuleGetters" || + callerSource === "ChromeUtils.defineESModuleGetters" + ) { + if (node.arguments.length < 2) { + return; + } + if (!isIdentifier(node.arguments[0], "lazy")) { + return; + } + + const obj = node.arguments[1]; + if (obj.type !== "ObjectExpression") { + return; + } + for (let prop of obj.properties) { + if (prop.type !== "Property") { + continue; + } + if (prop.kind !== "init") { + continue; + } + const resourceURINode = prop.value; + if (!isString(resourceURINode)) { + continue; + } + checkMixed( + loadedModules, + context, + node, + "lazy", + resourceURINode.value + ); + } + } + }, + }; + }, +}; |