mirror of
https://github.com/nextcloud/nextcloud.com.git
synced 2026-01-28 14:01:36 +00:00
274 lines
5.3 KiB
JavaScript
274 lines
5.3 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Ruler is a helper class for building responsibility chains from
|
|
* parse rules. It allows:
|
|
*
|
|
* - easy stack rules chains
|
|
* - getting main chain and named chains content (as arrays of functions)
|
|
*
|
|
* Helper methods, should not be used directly.
|
|
* @api private
|
|
*/
|
|
|
|
function Ruler() {
|
|
// List of added rules. Each element is:
|
|
//
|
|
// { name: XXX,
|
|
// enabled: Boolean,
|
|
// fn: Function(),
|
|
// alt: [ name2, name3 ] }
|
|
//
|
|
this.__rules__ = [];
|
|
|
|
// Cached rule chains.
|
|
//
|
|
// First level - chain name, '' for default.
|
|
// Second level - digital anchor for fast filtering by charcodes.
|
|
//
|
|
this.__cache__ = null;
|
|
}
|
|
|
|
/**
|
|
* Find the index of a rule by `name`.
|
|
*
|
|
* @param {String} `name`
|
|
* @return {Number} Index of the given `name`
|
|
* @api private
|
|
*/
|
|
|
|
Ruler.prototype.__find__ = function (name) {
|
|
var len = this.__rules__.length;
|
|
var i = -1;
|
|
|
|
while (len--) {
|
|
if (this.__rules__[++i].name === name) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
};
|
|
|
|
/**
|
|
* Build the rules lookup cache
|
|
*
|
|
* @api private
|
|
*/
|
|
|
|
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);
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Ruler public methods
|
|
* ------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* Replace rule function
|
|
*
|
|
* @param {String} `name` Rule name
|
|
* @param {Function `fn`
|
|
* @param {Object} `options`
|
|
* @api private
|
|
*/
|
|
|
|
Ruler.prototype.at = function (name, fn, options) {
|
|
var idx = this.__find__(name);
|
|
var opt = options || {};
|
|
|
|
if (idx === -1) {
|
|
throw new Error('Parser rule not found: ' + name);
|
|
}
|
|
|
|
this.__rules__[idx].fn = fn;
|
|
this.__rules__[idx].alt = opt.alt || [];
|
|
this.__cache__ = null;
|
|
};
|
|
|
|
/**
|
|
* Add a rule to the chain before given the `ruleName`.
|
|
*
|
|
* @param {String} `beforeName`
|
|
* @param {String} `ruleName`
|
|
* @param {Function} `fn`
|
|
* @param {Object} `options`
|
|
* @api private
|
|
*/
|
|
|
|
Ruler.prototype.before = function (beforeName, ruleName, fn, options) {
|
|
var idx = this.__find__(beforeName);
|
|
var opt = options || {};
|
|
|
|
if (idx === -1) {
|
|
throw new Error('Parser rule not found: ' + beforeName);
|
|
}
|
|
|
|
this.__rules__.splice(idx, 0, {
|
|
name: ruleName,
|
|
enabled: true,
|
|
fn: fn,
|
|
alt: opt.alt || []
|
|
});
|
|
|
|
this.__cache__ = null;
|
|
};
|
|
|
|
/**
|
|
* Add a rule to the chain after the given `ruleName`.
|
|
*
|
|
* @param {String} `afterName`
|
|
* @param {String} `ruleName`
|
|
* @param {Function} `fn`
|
|
* @param {Object} `options`
|
|
* @api private
|
|
*/
|
|
|
|
Ruler.prototype.after = function (afterName, ruleName, fn, options) {
|
|
var idx = this.__find__(afterName);
|
|
var opt = options || {};
|
|
|
|
if (idx === -1) {
|
|
throw new Error('Parser rule not found: ' + afterName);
|
|
}
|
|
|
|
this.__rules__.splice(idx + 1, 0, {
|
|
name: ruleName,
|
|
enabled: true,
|
|
fn: fn,
|
|
alt: opt.alt || []
|
|
});
|
|
|
|
this.__cache__ = null;
|
|
};
|
|
|
|
/**
|
|
* Add a rule to the end of chain.
|
|
*
|
|
* @param {String} `ruleName`
|
|
* @param {Function} `fn`
|
|
* @param {Object} `options`
|
|
* @return {String}
|
|
*/
|
|
|
|
Ruler.prototype.push = function (ruleName, fn, options) {
|
|
var opt = options || {};
|
|
|
|
this.__rules__.push({
|
|
name: ruleName,
|
|
enabled: true,
|
|
fn: fn,
|
|
alt: opt.alt || []
|
|
});
|
|
|
|
this.__cache__ = null;
|
|
};
|
|
|
|
/**
|
|
* Enable a rule or list of rules.
|
|
*
|
|
* @param {String|Array} `list` Name or array of rule names to enable
|
|
* @param {Boolean} `strict` If `true`, all non listed rules will be disabled.
|
|
* @api private
|
|
*/
|
|
|
|
Ruler.prototype.enable = function (list, strict) {
|
|
list = !Array.isArray(list)
|
|
? [ list ]
|
|
: list;
|
|
|
|
// In strict mode disable all existing rules first
|
|
if (strict) {
|
|
this.__rules__.forEach(function (rule) {
|
|
rule.enabled = false;
|
|
});
|
|
}
|
|
|
|
// Search by name and enable
|
|
list.forEach(function (name) {
|
|
var idx = this.__find__(name);
|
|
if (idx < 0) {
|
|
throw new Error('Rules manager: invalid rule name ' + name);
|
|
}
|
|
this.__rules__[idx].enabled = true;
|
|
}, this);
|
|
|
|
this.__cache__ = null;
|
|
};
|
|
|
|
|
|
/**
|
|
* Disable a rule or list of rules.
|
|
*
|
|
* @param {String|Array} `list` Name or array of rule names to disable
|
|
* @api private
|
|
*/
|
|
|
|
Ruler.prototype.disable = function (list) {
|
|
list = !Array.isArray(list)
|
|
? [ list ]
|
|
: list;
|
|
|
|
// Search by name and disable
|
|
list.forEach(function (name) {
|
|
var idx = this.__find__(name);
|
|
if (idx < 0) {
|
|
throw new Error('Rules manager: invalid rule name ' + name);
|
|
}
|
|
this.__rules__[idx].enabled = false;
|
|
}, this);
|
|
|
|
this.__cache__ = null;
|
|
};
|
|
|
|
/**
|
|
* Get a rules list as an array of functions.
|
|
*
|
|
* @param {String} `chainName`
|
|
* @return {Object}
|
|
* @api private
|
|
*/
|
|
|
|
Ruler.prototype.getRules = function (chainName) {
|
|
if (this.__cache__ === null) {
|
|
this.__compile__();
|
|
}
|
|
return this.__cache__[chainName] || [];
|
|
};
|
|
|
|
/**
|
|
* Expose `Ruler`
|
|
*/
|
|
|
|
module.exports = Ruler;
|