• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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