reject-mixing-eager-and-lazy.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /**
  2. * @fileoverview Reject use of lazy getters for modules that's loaded early in
  3. * the startup process and not necessarily be lazy.
  4. *
  5. * This Source Code Form is subject to the terms of the Mozilla Public
  6. * License, v. 2.0. If a copy of the MPL was not distributed with this
  7. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  8. */
  9. "use strict";
  10. const helpers = require("../helpers");
  11. function isIdentifier(node, id) {
  12. return node.type === "Identifier" && node.name === id;
  13. }
  14. function isString(node) {
  15. return node.type === "Literal" && typeof node.value === "string";
  16. }
  17. function checkMixed(loadedModules, context, node, type, resourceURI) {
  18. if (!loadedModules.has(resourceURI)) {
  19. loadedModules.set(resourceURI, type);
  20. }
  21. if (loadedModules.get(resourceURI) === type) {
  22. return;
  23. }
  24. context.report({
  25. node,
  26. messageId: "mixedEagerAndLazy",
  27. data: { uri: resourceURI },
  28. });
  29. }
  30. module.exports = {
  31. meta: {
  32. docs: {
  33. url:
  34. "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",
  35. },
  36. messages: {
  37. mixedEagerAndLazy:
  38. 'Module "{{uri}}" is loaded eagerly, and should not be used for lazy getter.',
  39. },
  40. type: "problem",
  41. },
  42. create(context) {
  43. const loadedModules = new Map();
  44. return {
  45. ImportDeclaration(node) {
  46. const resourceURI = node.source.value;
  47. checkMixed(loadedModules, context, node, "eager", resourceURI);
  48. },
  49. CallExpression(node) {
  50. if (node.callee.type !== "MemberExpression") {
  51. return;
  52. }
  53. let callerSource;
  54. try {
  55. callerSource = helpers.getASTSource(node.callee);
  56. } catch (e) {
  57. return;
  58. }
  59. if (
  60. (callerSource === "ChromeUtils.import" ||
  61. callerSource === "ChromeUtils.importESModule") &&
  62. helpers.getIsTopLevelAndUnconditionallyExecuted(
  63. context.getAncestors()
  64. )
  65. ) {
  66. if (node.arguments.length < 1) {
  67. return;
  68. }
  69. const resourceURINode = node.arguments[0];
  70. if (!isString(resourceURINode)) {
  71. return;
  72. }
  73. checkMixed(
  74. loadedModules,
  75. context,
  76. node,
  77. "eager",
  78. resourceURINode.value
  79. );
  80. }
  81. if (
  82. callerSource === "XPCOMUtils.defineLazyModuleGetter" ||
  83. callerSource === "ChromeUtils.defineModuleGetter"
  84. ) {
  85. if (node.arguments.length < 3) {
  86. return;
  87. }
  88. if (!isIdentifier(node.arguments[0], "lazy")) {
  89. return;
  90. }
  91. const resourceURINode = node.arguments[2];
  92. if (!isString(resourceURINode)) {
  93. return;
  94. }
  95. checkMixed(
  96. loadedModules,
  97. context,
  98. node,
  99. "lazy",
  100. resourceURINode.value
  101. );
  102. } else if (
  103. callerSource === "XPCOMUtils.defineLazyModuleGetters" ||
  104. callerSource === "ChromeUtils.defineESModuleGetters"
  105. ) {
  106. if (node.arguments.length < 2) {
  107. return;
  108. }
  109. if (!isIdentifier(node.arguments[0], "lazy")) {
  110. return;
  111. }
  112. const obj = node.arguments[1];
  113. if (obj.type !== "ObjectExpression") {
  114. return;
  115. }
  116. for (let prop of obj.properties) {
  117. if (prop.type !== "Property") {
  118. continue;
  119. }
  120. if (prop.kind !== "init") {
  121. continue;
  122. }
  123. const resourceURINode = prop.value;
  124. if (!isString(resourceURINode)) {
  125. continue;
  126. }
  127. checkMixed(
  128. loadedModules,
  129. context,
  130. node,
  131. "lazy",
  132. resourceURINode.value
  133. );
  134. }
  135. }
  136. },
  137. };
  138. },
  139. };