reject-eager-module-in-lazy-getter.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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 isString(node) {
  12. return node.type === "Literal" && typeof node.value === "string";
  13. }
  14. function isEagerModule(resourceURI) {
  15. return [
  16. "resource://gre/modules/Services",
  17. "resource://gre/modules/XPCOMUtils",
  18. "resource://gre/modules/AppConstants",
  19. ].includes(resourceURI.replace(/(\.jsm|\.jsm\.js|\.js|\.sys\.mjs)$/, ""));
  20. }
  21. function checkEagerModule(context, node, resourceURI) {
  22. if (!isEagerModule(resourceURI)) {
  23. return;
  24. }
  25. context.report({
  26. node,
  27. messageId: "eagerModule",
  28. data: { uri: resourceURI },
  29. });
  30. }
  31. module.exports = {
  32. meta: {
  33. docs: {
  34. url:
  35. "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-eager-module-in-lazy-getter.html",
  36. },
  37. messages: {
  38. eagerModule:
  39. 'Module "{{uri}}" is known to be loaded early in the startup process, and should be loaded eagerly, instead of defining a lazy getter.',
  40. },
  41. type: "problem",
  42. },
  43. create(context) {
  44. return {
  45. CallExpression(node) {
  46. if (node.callee.type !== "MemberExpression") {
  47. return;
  48. }
  49. let callerSource;
  50. try {
  51. callerSource = helpers.getASTSource(node.callee);
  52. } catch (e) {
  53. return;
  54. }
  55. if (
  56. callerSource === "XPCOMUtils.defineLazyModuleGetter" ||
  57. callerSource === "ChromeUtils.defineModuleGetter"
  58. ) {
  59. if (node.arguments.length < 3) {
  60. return;
  61. }
  62. const resourceURINode = node.arguments[2];
  63. if (!isString(resourceURINode)) {
  64. return;
  65. }
  66. checkEagerModule(context, node, resourceURINode.value);
  67. } else if (
  68. callerSource === "XPCOMUtils.defineLazyModuleGetters" ||
  69. callerSource === "ChromeUtils.defineESModuleGetters"
  70. ) {
  71. if (node.arguments.length < 2) {
  72. return;
  73. }
  74. const obj = node.arguments[1];
  75. if (obj.type !== "ObjectExpression") {
  76. return;
  77. }
  78. for (let prop of obj.properties) {
  79. if (prop.type !== "Property") {
  80. continue;
  81. }
  82. if (prop.kind !== "init") {
  83. continue;
  84. }
  85. const resourceURINode = prop.value;
  86. if (!isString(resourceURINode)) {
  87. continue;
  88. }
  89. checkEagerModule(context, node, resourceURINode.value);
  90. }
  91. }
  92. },
  93. };
  94. },
  95. };