| /** | |
|  * @fileoverview `Map` to load rules lazily. | |
|  * @author Toru Nagashima <https://github.com/mysticatea> | |
|  */ | |
| "use strict"; | |
| 
 | |
| const debug = require("debug")("eslint:rules"); | |
| 
 | |
| /** @typedef {import("./types").Rule} Rule */ | |
| 
 | |
| /** | |
|  * The `Map` object that loads each rule when it's accessed. | |
|  * @example | |
|  * const rules = new LazyLoadingRuleMap([ | |
|  *     ["eqeqeq", () => require("eqeqeq")], | |
|  *     ["semi", () => require("semi")], | |
|  *     ["no-unused-vars", () => require("no-unused-vars")] | |
|  * ]); | |
|  * | |
|  * rules.get("semi"); // call `() => require("semi")` here. | |
|  * | |
|  * @extends {Map<string, () => Rule>} | |
|  */ | |
| class LazyLoadingRuleMap extends Map { | |
| 
 | |
|     /** | |
|      * Initialize this map. | |
|      * @param {Array<[string, function(): Rule]>} loaders The rule loaders. | |
|      */ | |
|     constructor(loaders) { | |
|         let remaining = loaders.length; | |
| 
 | |
|         super( | |
|             debug.enabled | |
|                 ? loaders.map(([ruleId, load]) => { | |
|                     let cache = null; | |
| 
 | |
|                     return [ | |
|                         ruleId, | |
|                         () => { | |
|                             if (!cache) { | |
|                                 debug("Loading rule %o (remaining=%d)", ruleId, --remaining); | |
|                                 cache = load(); | |
|                             } | |
|                             return cache; | |
|                         } | |
|                     ]; | |
|                 }) | |
|                 : loaders | |
|         ); | |
| 
 | |
|         // `super(...iterable)` uses `this.set()`, so disable it here. | |
|         Object.defineProperty(LazyLoadingRuleMap.prototype, "set", { | |
|             configurable: true, | |
|             value: void 0 | |
|         }); | |
|     } | |
| 
 | |
|     /** | |
|      * Get a rule. | |
|      * Each rule will be loaded on the first access. | |
|      * @param {string} ruleId The rule ID to get. | |
|      * @returns {Rule|undefined} The rule. | |
|      */ | |
|     get(ruleId) { | |
|         const load = super.get(ruleId); | |
| 
 | |
|         return load && load(); | |
|     } | |
| 
 | |
|     /** | |
|      * Iterate rules. | |
|      * @returns {IterableIterator<Rule>} Rules. | |
|      */ | |
|     *values() { | |
|         for (const load of super.values()) { | |
|             yield load(); | |
|         } | |
|     } | |
| 
 | |
|     /** | |
|      * Iterate rules. | |
|      * @returns {IterableIterator<[string, Rule]>} Rules. | |
|      */ | |
|     *entries() { | |
|         for (const [ruleId, load] of super.entries()) { | |
|             yield [ruleId, load()]; | |
|         } | |
|     } | |
| 
 | |
|     /** | |
|      * Call a function with each rule. | |
|      * @param {Function} callbackFn The callback function. | |
|      * @param {any} [thisArg] The object to pass to `this` of the callback function. | |
|      * @returns {void} | |
|      */ | |
|     forEach(callbackFn, thisArg) { | |
|         for (const [ruleId, load] of super.entries()) { | |
|             callbackFn.call(thisArg, load(), ruleId, this); | |
|         } | |
|     } | |
| } | |
| 
 | |
| // Forbid mutation. | |
| Object.defineProperties(LazyLoadingRuleMap.prototype, { | |
|     clear: { configurable: true, value: void 0 }, | |
|     delete: { configurable: true, value: void 0 }, | |
|     [Symbol.iterator]: { | |
|         configurable: true, | |
|         writable: true, | |
|         value: LazyLoadingRuleMap.prototype.entries | |
|     } | |
| }); | |
| 
 | |
| module.exports = { LazyLoadingRuleMap };
 |