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