Greasy Fork is available in English.

Matcher

match value with cache.

Tätä skriptiä ei tulisi asentaa suoraan. Se on kirjasto muita skriptejä varten sisällytettäväksi metadirektiivillä // @require https://greasyfork.org/scripts/32050-matcher/code/Matcher.js?version=210131.

// ==UserScript==
// @name               Matcher
// @namespace          https://github.com/cologler/
// @version            0.2
// @description        match value with cache.
// @author             cologler
// @grant              none
// ==/UserScript==

// just let type script work.
(function() { function require(){}; require("greasemonkey"); })();

class MatchRules {
    constructor(cacheSize) {
        Object.defineProperty(this, 'cacheSize', {
            get: () => cacheSize
        });
        this._cacheTrue = null;
        this._cacheFalse = null;
        this._cacheQueue = null;
        if (this.cacheSize > 0) {
            this._cacheTrue = new Set();
            this._cacheFalse = new Set();
            this._cacheQueue = [];
        }
        this._rules = [];
    }

    addRule(rule) {
        if (!this.isRule(rule)) {
            throw 'TypeError';
        }
        this._rules.push(rule);
        if (this._cacheFalse !== null) {
            this._cacheFalse.clear();
        }
    }

    removeRule(rule) {
        if (this.isRule(rule) && this.onRemoveRule(rule)) {
            if (this._cacheTrue !== null) {
                this._cacheTrue.clear()
            }
            return true;
        }
        return false;
    }

    onRemoveRule(rule) {
        let index = this._rules.indexOf(rule);
        if (index >= 0) {
            delete this._rules[index];
            return true;
        }
        return false;
    }

    isRule(rule) {
        throw 'NotImplementedError';
    }

    test(value) {
        let self = this;

        if (this.cacheSize > 0) {
            if (this._cacheTrue.has(value)) {
                return true;
            } else if (this._cacheFalse.has(value)) {
                return false;
            }
        }

        let result = this._rules.map(z => self.onTestRule(z, value)).some(z => z);

        if (this.cacheSize > 0) {
            this._cacheQueue.push(value);
            if (this._cacheQueue.length > this.cacheSize) {
                let first = this._cacheQueue.shift();
                this._cacheTrue.delete(first);
                this._cacheFalse.delete(first);
            }
            (result ? this._cacheTrue : this._cacheFalse).add(value);
        }

        return result;
    }

    onTestRule(rule, value) {
        throw 'NotImplementedError';
    }
}

class TextMatchRules extends MatchRules {
    isRule(rule) {
        return typeof rule === 'string';
    }

    onTestRule(rule, value) {
        return rule === value;
    }
}

class TextContainsMatchRules extends TextMatchRules {
    onTestRule(rule, value) {
        return value.indexOf(rule);
    }
}

class RegExpMatchRules extends MatchRules {
    isRule(rule) {
        return rule instanceof RegExp;
    }

    onTestRule(rule, value) {
        return rule.test(value);
    }

    onRemoveRule(rule) {
        let index = this._rules.map(z => z.toString()).indexOf(rule.toString());
        if (index >= 0) {
            delete this._rules[index];
            return true;
        }
        return false;
    }
}

class Matcher {
    constructor() {
        this._rules = [];
    }

    addRulesProvider(rulesProvider) {
        if (!rulesProvider instanceof MatchRules) {
            throw 'TypeError';
        }
        this._rules.push(rulesProvider);
    }

    addRule(rule) {
        for (var index = 0; index < this._rules.length; index++) {
            let rules = this._rules[index];
            if (rules.isRule(rule)) {
                rules.addRule(rule);
                return true;
            }
        }
        return false;
    }

    removeRule(rule) {
        for (var index = 0; index < this._rules.length; index++) {
            let rules = this._rules[index];
            if (rules.removeRule(rule)) {
                return true;
            }
        }
        return false;
    }

    test(value) {
        let self = this;
        return this._rules.map(z => z.test(value)).some(z => z);
    }
}

class KeywordMatcher extends Matcher {
    constructor(cacheSize) {
        super();
        this.addRulesProvider(new TextContainsMatchRules(cacheSize));
        this.addRulesProvider(new RegExpMatchRules(cacheSize));
    }
}