trieste
Version:
Trie generator.
338 lines (293 loc) • 7.52 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = global || self, global.trieste = factory());
}(this, function () { 'use strict';
/**
* Adds string to trie (via object mutation).
*
* @param {string|Object} string
* @param {Object} trie
* @param {Object} options
* @param {string} options.endKey
* @param {*} options.endValue
* @param {*} [endValue]
*/
function add(string, trie, options, endValue) {
if (string instanceof Object) {
for (var key in string) {
add(key, trie, options, string[key]);
}
return;
}
if (!string || typeof string !== 'string') {
return;
}
var endKey = options.endKey;
endValue = arguments.length === 4 ? endValue : options.endValue;
var node = trie;
var letters = string.split('');
for (
var i = 0,
lettersLength = letters.length,
lettersLastIndex = lettersLength - 1;
i < lettersLength;
i++
) {
var letter = letters[i];
// use node with key if it exists; otherwise, create empty node
node[letter] = node[letter] || {};
// update current node
node = node[letter];
// last node of current string
if (lettersLastIndex === i) {
node[endKey] = endValue;
}
}
}
var add_1 = add;
/**
* The default end of string marker and value.
*
* The key `$$` ensures uniqueness since it has a length of 2.
* The value `1` is a boolean integer of 1 byte.
*/
var constants = {
END_KEY: '$$',
END_VALUE: 1
};
/**
* Checks if trie contains a string.
*
* @param {string} string
* @param {Object} trie
* @param {Object} options
* @param {string} options.endKey
* @return {boolean}
*/
function contains(string, trie, options) {
if (!string || typeof string !== 'string') {
return false;
}
var endKey = options.endKey;
var letters = string.split('');
var node = trie;
for (var i = 0, len = letters.length, lastIndex = len - 1; i < len; i++) {
var key = letters[i];
if (!node.hasOwnProperty(key)) {
return false;
}
node = node[key];
if (lastIndex === i) {
return node.hasOwnProperty(endKey);
}
}
}
var contains_1 = contains;
/**
* Gets end of string value from trie.
*
* @param {string} string
* @param {Object} trie
* @param {Object} options
* @param {string} options.endKey
* @return {*}
*/
function get(string, trie, options) {
if (!string || typeof string !== 'string') {
return;
}
var endKey = options.endKey;
var letters = string.split('');
var node = trie;
for (var i = 0, len = letters.length, lastIndex = len - 1; i < len; i++) {
var key = letters[i];
if (!node.hasOwnProperty(key)) {
return;
}
node = node[key];
if (lastIndex === i && node.hasOwnProperty(endKey)) {
return node[endKey];
}
}
}
var get_1 = get;
var assign = Object.assign;
if (typeof assign !== 'function') {
/**
* Polyfills `Object.assign`.
*
* @see {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign}
*
* @param {Object} target
* @param {...Object} [source]
* @return {Object}
*/
assign = function(target, source) {
if (target === undefined || target === null) {
throw new TypeError('Cannot convert undefined or null to object');
}
for (var i = 1, len = arguments.length; i < len; i++) {
if (i !== 1) {
source = arguments[i];
}
if (source instanceof Object) {
for (var key in source) {
target[key] = source[key];
}
}
}
return target;
};
}
/**
* Invokes function with arguments and data.
*
* @param {Function} func
* @param {Array} args
* @param {Object} data
* @param {Object} options
*/
function invoke(func, args, data, options) {
var argsLen = args.length;
if (argsLen) {
for (var i = 0; i < argsLen; i++) {
func(args[i], data, options);
}
}
}
/**
* Checks if object is empty.
*
* @param {Object} object
* @return {boolean}
*/
function isObjectEmpty(object) {
for (var key in object) {
/* istanbul ignore else */
if (object.hasOwnProperty(key)) {
return false;
}
}
return true;
}
var utilities = {
assign: assign,
invoke: invoke,
isObjectEmpty: isObjectEmpty
};
var isObjectEmpty$1 = utilities.isObjectEmpty;
/**
* Removes string from trie (through object mutation).
*
* @param {string} string
* @param {Object} trie
* @param {Object} options
* @param {string} options.endKey
*/
function remove(string, trie, options) {
if (!string || typeof string !== 'string') {
return;
}
var endKey = options.endKey;
var letters = string.split('');
var node = trie;
var nodes = [node];
for (var i = 0, len = letters.length, lastIndex = len - 1; i < len; i++) {
var key = letters[i];
if (!node.hasOwnProperty(key)) {
return;
}
node = node[key];
if (lastIndex === i && node.hasOwnProperty(endKey)) {
delete node[endKey];
// clean up empty nodes like `{ a: {} }`
while (isObjectEmpty$1(node)) {
if (nodes.length) {
// parent node
node = nodes.pop();
// delete empty property
delete node[letters[nodes.length]];
} else {
break;
}
}
}
// keep track of traversed nodes
nodes.push(node);
}
}
var remove_1 = remove;
var assign$1 = utilities.assign;
var invoke$1 = utilities.invoke;
/**
* Constructs a trie.
*
* @constructor
* @param {Object} [options]
* @param {string} [options.endKey='$$']
* @param {number} [options.endValue=1]
*/
function Trie(options) {
this.options = assign$1(
{
endKey: constants.END_KEY,
endValue: constants.END_VALUE
},
options
);
this.data = {};
}
/**
* Adds string(s) to trie.
*
* @param {...string}
* @return {this}
*/
Trie.prototype.add = function() {
invoke$1(add_1, arguments, this.data, this.options);
return this;
};
/**
* Checks if trie contains a string.
*
* @param {string} string
* @return {boolean}
*/
Trie.prototype.contains = function(string) {
return contains_1(string, this.data, this.options);
};
/**
* Gets end of string value from trie.
*
* @param {string} string
* @return {*}
*/
Trie.prototype.get = function(string) {
return get_1(string, this.data, this.options);
};
/**
* Removes string(s) from trie.
*
* @param {...string}
* @return {this}
*/
Trie.prototype.remove = function() {
invoke$1(remove_1, arguments, this.data, this.options);
return this;
};
var trie = Trie;
/**
* Instantiates a trie.
*
* @param {Object} [options]
* @param {string} [options.endKey='$$']
* @param {number} [options.endValue=1]
* @return {Trie}
*/
function trieste(options) {
return new trie(options);
}
var trieste_1 = trieste;
return trieste_1;
}));