diff --git a/lib/ruler.js b/lib/ruler.js index 5862655..7c54106 100644 --- a/lib/ruler.js +++ b/lib/ruler.js @@ -19,22 +19,25 @@ function Ruler() { // alt: [ name2, name3 ] // } // - this.rules = []; + this.__rules__ = []; // Cached rule chains. // // First level - chain name, '' for default. // Second level - diginal anchor for fast filtering by charcodes. // - this.cache = null; + this.__cache__ = null; } +//////////////////////////////////////////////////////////////////////////////// +// Helper methods, should not be used directly + // Find rule index by name // -Ruler.prototype.find = function (name) { - for (var i = 0; i < this.rules.length; i++) { - if (this.rules[i].name === name) { +Ruler.prototype.__find__ = function (name) { + for (var i = 0; i < this.__rules__.length; i++) { + if (this.__rules__[i].name === name) { return i; } } @@ -42,55 +45,91 @@ Ruler.prototype.find = function (name) { }; +// Build rules lookup cache +// +Ruler.prototype.__compile__ = function () { + var self = this; + var chains = [ '' ]; + + // collect unique names + self.__rules__.forEach(function (rule) { + if (!rule.enabled) { return; } + + rule.alt.forEach(function (altName) { + if (chains.indexOf(altName) < 0) { + chains.push(altName); + } + }); + }); + + self.__cache__ = {}; + + chains.forEach(function (chain) { + self.__cache__[chain] = []; + self.__rules__.forEach(function (rule) { + if (!rule.enabled) { return; } + + if (chain && rule.alt.indexOf(chain) < 0) { return; } + + self.__cache__[chain].push(rule.fn); + }); + }); +}; + + +//////////////////////////////////////////////////////////////////////////////// +// Public methods + + // Replace rule function // Ruler.prototype.at = function (name, fn, options) { - var index = this.find(name); + var index = this.__find__(name); var opt = options || {}; if (index === -1) { throw new Error('Parser rule not found: ' + name); } - this.rules[index].fn = fn; - this.rules[index].alt = opt.alt || []; - this.cache = null; + this.__rules__[index].fn = fn; + this.__rules__[index].alt = opt.alt || []; + this.__cache__ = null; }; // Add rule to chain before one with given name. // Ruler.prototype.before = function (beforeName, ruleName, fn, options) { - var index = this.find(beforeName); + var index = this.__find__(beforeName); var opt = options || {}; if (index === -1) { throw new Error('Parser rule not found: ' + beforeName); } - this.rules.splice(index, 0, { + this.__rules__.splice(index, 0, { name: ruleName, enabled: true, fn: fn, alt: opt.alt || [] }); - this.cache = null; + this.__cache__ = null; }; // Add rule to chain after one with given name. // Ruler.prototype.after = function (afterName, ruleName, fn, options) { - var index = this.find(afterName); + var index = this.__find__(afterName); var opt = options || {}; if (index === -1) { throw new Error('Parser rule not found: ' + afterName); } - this.rules.splice(index + 1, 0, { + this.__rules__.splice(index + 1, 0, { name: ruleName, enabled: true, fn: fn, alt: opt.alt || [] }); - this.cache = null; + this.__cache__ = null; }; // Add rule to the end of chain. @@ -98,14 +137,14 @@ Ruler.prototype.after = function (afterName, ruleName, fn, options) { Ruler.prototype.push = function (ruleName, fn, options) { var opt = options || {}; - this.rules.push({ + this.__rules__.push({ name: ruleName, enabled: true, fn: fn, alt: opt.alt || [] }); - this.cache = null; + this.__cache__ = null; }; @@ -119,21 +158,21 @@ Ruler.prototype.enable = function (list, strict) { // In strict mode disable all existing rules first if (strict) { - this.rules.forEach(function (rule) { + this.__rules__.forEach(function (rule) { rule.enabled = false; }); } // Search by name and enable list.forEach(function (name) { - var idx = this.find(name); + var idx = this.__find__(name); if (idx < 0) { throw new Error('Rules manager: invalid rule name ' + name); } - this.rules[idx].enabled = true; + this.__rules__[idx].enabled = true; }, this); - this.cache = null; + this.__cache__ = null; }; @@ -146,57 +185,25 @@ Ruler.prototype.disable = function (list) { // Search by name and disable list.forEach(function (name) { - var idx = this.find(name); + var idx = this.__find__(name); if (idx < 0) { throw new Error('Rules manager: invalid rule name ' + name); } - this.rules[idx].enabled = false; + this.__rules__[idx].enabled = false; }, this); - this.cache = null; -}; - - -// Build rules lookup cache -// -Ruler.prototype.compile = function () { - var self = this; - var chains = [ '' ]; - - // collect unique names - self.rules.forEach(function (rule) { - if (!rule.enabled) { return; } - - rule.alt.forEach(function (altName) { - if (chains.indexOf(altName) < 0) { - chains.push(altName); - } - }); - }); - - self.cache = {}; - - chains.forEach(function (chain) { - self.cache[chain] = []; - self.rules.forEach(function (rule) { - if (!rule.enabled) { return; } - - if (chain && rule.alt.indexOf(chain) < 0) { return; } - - self.cache[chain].push(rule.fn); - }); - }); + this.__cache__ = null; }; // Get rules list as array of functions. // Ruler.prototype.getRules = function (chainName) { - if (this.cache === null) { - this.compile(); + if (this.__cache__ === null) { + this.__compile__(); } - return this.cache[chainName]; + return this.__cache__[chainName]; }; module.exports = Ruler;