lazy-loading-rule-map.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /**
  2. * @fileoverview `Map` to load rules lazily.
  3. * @author Toru Nagashima <https://github.com/mysticatea>
  4. */
  5. "use strict";
  6. const debug = require("debug")("eslint:rules");
  7. /** @typedef {import("../../types").Rule.RuleModule} Rule */
  8. /**
  9. * The `Map` object that loads each rule when it's accessed.
  10. * @example
  11. * const rules = new LazyLoadingRuleMap([
  12. * ["eqeqeq", () => require("eqeqeq")],
  13. * ["semi", () => require("semi")],
  14. * ["no-unused-vars", () => require("no-unused-vars")]
  15. * ]);
  16. *
  17. * rules.get("semi"); // call `() => require("semi")` here.
  18. *
  19. * @extends {Map<string, Rule>}
  20. */
  21. class LazyLoadingRuleMap extends Map {
  22. /**
  23. * Initialize this map.
  24. * @param {Array<[string, function(): Rule]>} loaders The rule loaders.
  25. */
  26. constructor(loaders) {
  27. let remaining = loaders.length;
  28. super(
  29. debug.enabled
  30. ? loaders.map(([ruleId, load]) => {
  31. let cache = null;
  32. return [
  33. ruleId,
  34. () => {
  35. if (!cache) {
  36. debug(
  37. "Loading rule %o (remaining=%d)",
  38. ruleId,
  39. --remaining,
  40. );
  41. cache = load();
  42. }
  43. return cache;
  44. },
  45. ];
  46. })
  47. : loaders,
  48. );
  49. // `super(...iterable)` uses `this.set()`, so disable it here.
  50. Object.defineProperty(LazyLoadingRuleMap.prototype, "set", {
  51. configurable: true,
  52. value: void 0,
  53. });
  54. }
  55. /**
  56. * Get a rule.
  57. * Each rule will be loaded on the first access.
  58. * @param {string} ruleId The rule ID to get.
  59. * @returns {Rule|undefined} The rule.
  60. */
  61. get(ruleId) {
  62. const load = super.get(ruleId);
  63. return load && load();
  64. }
  65. /**
  66. * Iterate rules.
  67. * @returns {IterableIterator<Rule>} Rules.
  68. */
  69. *values() {
  70. for (const load of super.values()) {
  71. yield load();
  72. }
  73. }
  74. /**
  75. * Iterate rules.
  76. * @returns {IterableIterator<[string, Rule]>} Rules.
  77. */
  78. *entries() {
  79. for (const [ruleId, load] of super.entries()) {
  80. yield [ruleId, load()];
  81. }
  82. }
  83. /**
  84. * Call a function with each rule.
  85. * @param {Function} callbackFn The callback function.
  86. * @param {any} [thisArg] The object to pass to `this` of the callback function.
  87. * @returns {void}
  88. */
  89. forEach(callbackFn, thisArg) {
  90. for (const [ruleId, load] of super.entries()) {
  91. callbackFn.call(thisArg, load(), ruleId, this);
  92. }
  93. }
  94. }
  95. // Forbid mutation.
  96. Object.defineProperties(LazyLoadingRuleMap.prototype, {
  97. clear: { configurable: true, value: void 0 },
  98. delete: { configurable: true, value: void 0 },
  99. [Symbol.iterator]: {
  100. configurable: true,
  101. writable: true,
  102. value: LazyLoadingRuleMap.prototype.entries,
  103. },
  104. });
  105. module.exports = { LazyLoadingRuleMap };