Comparing version 2.2.2 to 2.3.0
@@ -1,1 +0,1 @@ | ||
!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(n=n||self).efrt=t()}(this,function(){"use strict";const n="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",t=n.split("").reduce(function(n,t,e){return n[t]=e,n},{});var e=function(n){if(void 0!==t[n])return t[n];let e=0,o=1,s=36,r=1;for(;o<n.length;e+=s,o++,s*=36);for(let t=n.length-1;t>=0;t--,r*=36){let o=n.charCodeAt(t)-48;o>10&&(o-=7),e+=o*r}return e};const o=function(n,t,o){const s=e(t);return s<n.symCount?n.syms[s]:o+s+1-n.symCount};var s=function(n){const t={nodes:n.split(";"),syms:[],symCount:0};return n.match(":")&&function(n){const t=new RegExp("([0-9A-Z]+):([0-9A-Z]+)");for(let o=0;o<n.nodes.length;o++){const s=t.exec(n.nodes[o]);if(!s){n.symCount=o;break}n.syms[e(s[1])]=e(s[2])}n.nodes=n.nodes.slice(n.symCount,n.nodes.length)}(t),function(n){const t=[],e=(s,r)=>{let c=n.nodes[s];"!"===c[0]&&(t.push(r),c=c.slice(1));const u=c.split(/([A-Z0-9,]+)/g);for(let c=0;c<u.length;c+=2){const i=u[c],f=u[c+1];if(!i)continue;const l=r+i;if(","===f||void 0===f){t.push(l);continue}const d=o(n,f,s);e(d,l)}};return e(0,""),t}(t)};return function(n){const t=n.split("|").reduce((n,t)=>{const e=t.split("¦");return n[e[0]]=e[1],n},{}),e={};return Object.keys(t).forEach(function(n){const o=s(t[n]);"true"===n&&(n=!0);for(let t=0;t<o.length;t++){const s=o[t];!0===e.hasOwnProperty(s)?!1===Array.isArray(e[s])?e[s]=[e[s],n]:e[s].push(n):e[s]=n}}),e}}); | ||
!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(n="undefined"!=typeof globalThis?globalThis:n||self).efrt=e()}(this,(function(){"use strict";var n=36,e="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",r=e.split("").reduce((function(n,e,r){return n[e]=r,n}),{}),t=function(e){if(void 0!==r[e])return r[e];for(var t=0,o=1,s=n,u=1;o<e.length;t+=s,o++,s*=n);for(var i=e.length-1;i>=0;i--,u*=n){var f=e.charCodeAt(i)-48;f>10&&(f-=7),t+=f*u}return t},o=function(n,e,r){var o=t(e);return o<n.symCount?n.syms[o]:r+o+1-n.symCount},s=function(n){var e={nodes:n.split(";"),syms:[],symCount:0};return n.match(":")&&function(n){for(var e=new RegExp("([0-9A-Z]+):([0-9A-Z]+)"),r=0;r<n.nodes.length;r++){var o=e.exec(n.nodes[r]);if(!o){n.symCount=r;break}n.syms[t(o[1])]=t(o[2])}n.nodes=n.nodes.slice(n.symCount,n.nodes.length)}(e),function(n){var e=[];return function r(t,s){var u=n.nodes[t];"!"===u[0]&&(e.push(s),u=u.slice(1));for(var i=u.split(/([A-Z0-9,]+)/g),f=0;f<i.length;f+=2){var a=i[f],c=i[f+1];if(a){var d=s+a;","!==c&&void 0!==c?r(o(n,c,t),d):e.push(d)}}}(0,""),e}(e)};return function(n){var e=n.split("|").reduce((function(n,e){var r=e.split("¦");return n[r[0]]=r[1],n}),{}),r={};return Object.keys(e).forEach((function(n){var t=s(e[n]);"true"===n&&(n=!0);for(var o=0;o<t.length;o++){var u=t[o];!0===r.hasOwnProperty(u)?!1===Array.isArray(r[u])?r[u]=[r[u],n]:r[u].push(n):r[u]=n}})),r}})); |
1367
builds/efrt.js
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global = global || self, global.efrt = factory()); | ||
}(this, function () { 'use strict'; | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | ||
typeof define === 'function' && define.amd ? define(['exports'], factory) : | ||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.efrt = {})); | ||
}(this, (function (exports) { 'use strict'; | ||
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; | ||
const commonPrefix = function (w1, w2) { | ||
let len = Math.min(w1.length, w2.length); | ||
while (len > 0) { | ||
const prefix = w1.slice(0, len); | ||
if (prefix === w2.slice(0, len)) { | ||
return prefix | ||
} | ||
len -= 1; | ||
} | ||
return '' | ||
}; | ||
function createCommonjsModule(fn, module) { | ||
return module = { exports: {} }, fn(module, module.exports), module.exports; | ||
} | ||
/* Sort elements and remove duplicates from array (modified in place) */ | ||
const unique = function (a) { | ||
a.sort(); | ||
for (let i = 1; i < a.length; i++) { | ||
if (a[i - 1] === a[i]) { | ||
a.splice(i, 1); | ||
} | ||
} | ||
}; | ||
const commonPrefix = function(w1, w2) { | ||
let len = Math.min(w1.length, w2.length); | ||
while (len > 0) { | ||
const prefix = w1.slice(0, len); | ||
if (prefix === w2.slice(0, len)) { | ||
return prefix | ||
} | ||
len -= 1; | ||
} | ||
return '' | ||
}; | ||
var fns = { | ||
commonPrefix, | ||
unique | ||
}; | ||
/* Sort elements and remove duplicates from array (modified in place) */ | ||
const unique = function(a) { | ||
a.sort(); | ||
for (let i = 1; i < a.length; i++) { | ||
if (a[i - 1] === a[i]) { | ||
a.splice(i, 1); | ||
} | ||
} | ||
}; | ||
const Histogram = function () { | ||
this.counts = {}; | ||
}; | ||
var fns = { | ||
commonPrefix: commonPrefix, | ||
unique: unique | ||
}; | ||
const methods$1 = { | ||
init: function (sym) { | ||
if (this.counts[sym] === undefined) { | ||
this.counts[sym] = 0; | ||
} | ||
}, | ||
add: function (sym, n) { | ||
if (n === undefined) { | ||
n = 1; | ||
} | ||
this.init(sym); | ||
this.counts[sym] += n; | ||
}, | ||
countOf: function (sym) { | ||
this.init(sym); | ||
return this.counts[sym] | ||
}, | ||
highest: function (top) { | ||
let sorted = []; | ||
const keys = Object.keys(this.counts); | ||
for (let i = 0; i < keys.length; i++) { | ||
const sym = keys[i]; | ||
sorted.push([sym, this.counts[sym]]); | ||
} | ||
sorted.sort(function (a, b) { | ||
return b[1] - a[1] | ||
}); | ||
if (top) { | ||
sorted = sorted.slice(0, top); | ||
} | ||
return sorted | ||
} | ||
}; | ||
const Histogram = function() { | ||
this.counts = {}; | ||
}; | ||
Object.keys(methods$1).forEach(function (k) { | ||
Histogram.prototype[k] = methods$1[k]; | ||
}); | ||
const methods = { | ||
init: function(sym) { | ||
if (this.counts[sym] === undefined) { | ||
this.counts[sym] = 0; | ||
} | ||
}, | ||
add: function(sym, n) { | ||
if (n === undefined) { | ||
n = 1; | ||
} | ||
this.init(sym); | ||
this.counts[sym] += n; | ||
}, | ||
countOf: function(sym) { | ||
this.init(sym); | ||
return this.counts[sym] | ||
}, | ||
highest: function(top) { | ||
let sorted = []; | ||
const keys = Object.keys(this.counts); | ||
for (let i = 0; i < keys.length; i++) { | ||
const sym = keys[i]; | ||
sorted.push([sym, this.counts[sym]]); | ||
} | ||
sorted.sort(function(a, b) { | ||
return b[1] - a[1] | ||
}); | ||
if (top) { | ||
sorted = sorted.slice(0, top); | ||
} | ||
return sorted | ||
} | ||
}; | ||
Object.keys(methods).forEach(function(k) { | ||
Histogram.prototype[k] = methods[k]; | ||
}); | ||
var histogram = Histogram; | ||
const BASE = 36; | ||
const seq = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; | ||
const BASE = 36; | ||
const cache = seq.split('').reduce(function (h, c, i) { | ||
h[c] = i; | ||
return h | ||
}, {}); | ||
const seq = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; | ||
const cache = seq.split('').reduce(function(h, c, i) { | ||
h[c] = i; | ||
return h | ||
}, {}); | ||
// 0, 1, 2, ..., A, B, C, ..., 00, 01, ... AA, AB, AC, ..., AAA, AAB, ... | ||
const toAlphaCode = function (n) { | ||
if (seq[n] !== undefined) { | ||
return seq[n] | ||
} | ||
let places = 1; | ||
let range = BASE; | ||
let s = ''; | ||
for (; n >= range; n -= range, places++, range *= BASE) {} | ||
while (places--) { | ||
const d = n % BASE; | ||
s = String.fromCharCode((d < 10 ? 48 : 55) + d) + s; | ||
n = (n - d) / BASE; | ||
} | ||
return s | ||
}; | ||
// 0, 1, 2, ..., A, B, C, ..., 00, 01, ... AA, AB, AC, ..., AAA, AAB, ... | ||
const toAlphaCode = function(n) { | ||
if (seq[n] !== undefined) { | ||
return seq[n] | ||
} | ||
let places = 1; | ||
let range = BASE; | ||
let s = ''; | ||
const fromAlphaCode = function (s) { | ||
if (cache[s] !== undefined) { | ||
return cache[s] | ||
} | ||
let n = 0; | ||
let places = 1; | ||
let range = BASE; | ||
let pow = 1; | ||
for (; places < s.length; n += range, places++, range *= BASE) {} | ||
for (let i = s.length - 1; i >= 0; i--, pow *= BASE) { | ||
let d = s.charCodeAt(i) - 48; | ||
if (d > 10) { | ||
d -= 7; | ||
} | ||
n += d * pow; | ||
} | ||
return n | ||
}; | ||
for (; n >= range; n -= range, places++, range *= BASE) {} | ||
while (places--) { | ||
const d = n % BASE; | ||
s = String.fromCharCode((d < 10 ? 48 : 55) + d) + s; | ||
n = (n - d) / BASE; | ||
} | ||
return s | ||
}; | ||
var encoding = { | ||
toAlphaCode, | ||
fromAlphaCode | ||
}; | ||
const fromAlphaCode = function(s) { | ||
if (cache[s] !== undefined) { | ||
return cache[s] | ||
} | ||
let n = 0; | ||
let places = 1; | ||
let range = BASE; | ||
let pow = 1; | ||
const config = { | ||
NODE_SEP: ';', | ||
KEY_VAL: ':', | ||
STRING_SEP: ',', | ||
TERMINAL_PREFIX: '!', | ||
BASE: 36 | ||
}; | ||
// Return packed representation of Trie as a string. | ||
// Return packed representation of Trie as a string. | ||
// | ||
// Each node of the Trie is output on a single line. | ||
// | ||
// For example Trie("the them there thesis this"): | ||
// { | ||
// "th": { | ||
// "is": 1, | ||
// "e": { | ||
// "": 1, | ||
// "m": 1, | ||
// "re": 1, | ||
// "sis": 1 | ||
// } | ||
// } | ||
// } | ||
// | ||
// Would be reperesented as: | ||
// | ||
// th0 | ||
// e0is | ||
// !m,re,sis | ||
// | ||
// The line begins with a '!' iff it is a terminal node of the Trie. | ||
// For each string property in a node, the string is listed, along | ||
// with a (relative!) line number of the node that string references. | ||
// Terminal strings (those without child node references) are | ||
// separated by ',' characters. | ||
const nodeLine = function (self, node) { | ||
let line = '', | ||
sep = ''; | ||
if (self.isTerminal(node)) { | ||
line += config.TERMINAL_PREFIX; | ||
} | ||
const props = self.nodeProps(node); | ||
for (let i = 0; i < props.length; i++) { | ||
const prop = props[i]; | ||
if (typeof node[prop] === 'number') { | ||
line += sep + prop; | ||
sep = config.STRING_SEP; | ||
continue | ||
} | ||
if (self.syms[node[prop]._n]) { | ||
line += sep + prop + self.syms[node[prop]._n]; | ||
sep = ''; | ||
continue | ||
} | ||
let ref = encoding.toAlphaCode(node._n - node[prop]._n - 1 + self.symCount); | ||
// Large reference to smaller string suffix -> duplicate suffix | ||
if (node[prop]._g && ref.length >= node[prop]._g.length && node[node[prop]._g] === 1) { | ||
ref = node[prop]._g; | ||
line += sep + prop + ref; | ||
sep = config.STRING_SEP; | ||
continue | ||
} | ||
line += sep + prop + ref; | ||
sep = ''; | ||
} | ||
return line | ||
}; | ||
for (; places < s.length; n += range, places++, range *= BASE) {} | ||
for (let i = s.length - 1; i >= 0; i--, pow *= BASE) { | ||
let d = s.charCodeAt(i) - 48; | ||
if (d > 10) { | ||
d -= 7; | ||
} | ||
n += d * pow; | ||
} | ||
return n | ||
}; | ||
const analyzeRefs = function (self, node) { | ||
if (self.visited(node)) { | ||
return | ||
} | ||
const props = self.nodeProps(node, true); | ||
for (let i = 0; i < props.length; i++) { | ||
const prop = props[i]; | ||
const ref = node._n - node[prop]._n - 1; | ||
// Count the number of single-character relative refs | ||
if (ref < config.BASE) { | ||
self.histRel.add(ref); | ||
} | ||
// Count the number of characters saved by converting an absolute | ||
// reference to a one-character symbol. | ||
self.histAbs.add(node[prop]._n, encoding.toAlphaCode(ref).length - 1); | ||
analyzeRefs(self, node[prop]); | ||
} | ||
}; | ||
var encoding = { | ||
toAlphaCode: toAlphaCode, | ||
fromAlphaCode: fromAlphaCode | ||
}; | ||
const symbolCount = function (self) { | ||
self.histAbs = self.histAbs.highest(config.BASE); | ||
const savings = []; | ||
savings[-1] = 0; | ||
let best = 0, | ||
sCount = 0; | ||
const defSize = 3 + encoding.toAlphaCode(self.nodeCount).length; | ||
for (let sym = 0; sym < config.BASE; sym++) { | ||
if (self.histAbs[sym] === undefined) { | ||
break | ||
} | ||
savings[sym] = | ||
self.histAbs[sym][1] - | ||
defSize - | ||
self.histRel.countOf(config.BASE - sym - 1) + | ||
savings[sym - 1]; | ||
if (savings[sym] >= best) { | ||
best = savings[sym]; | ||
sCount = sym + 1; | ||
} | ||
} | ||
return sCount | ||
}; | ||
const config = { | ||
NODE_SEP: ';', | ||
KEY_VAL: ':', | ||
STRING_SEP: ',', | ||
TERMINAL_PREFIX: '!', | ||
BASE: 36 | ||
}; | ||
const numberNodes = function (self, node) { | ||
// Topological sort into nodes array | ||
if (node._n !== undefined) { | ||
return | ||
} | ||
const props = self.nodeProps(node, true); | ||
for (let i = 0; i < props.length; i++) { | ||
numberNodes(self, node[props[i]]); //recursive | ||
} | ||
node._n = self.pos++; | ||
self.nodes.unshift(node); | ||
}; | ||
// Return packed representation of Trie as a string. | ||
const pack$1 = function (self) { | ||
self.nodes = []; | ||
self.nodeCount = 0; | ||
self.syms = {}; | ||
self.symCount = 0; | ||
self.pos = 0; | ||
// Make sure we've combined all the common suffixes | ||
self.optimize(); | ||
self.histAbs = new Histogram(); | ||
self.histRel = new Histogram(); | ||
numberNodes(self, self.root); | ||
self.nodeCount = self.nodes.length; | ||
self.prepDFS(); | ||
analyzeRefs(self, self.root); | ||
self.symCount = symbolCount(self); | ||
for (let sym = 0; sym < self.symCount; sym++) { | ||
self.syms[self.histAbs[sym][0]] = encoding.toAlphaCode(sym); | ||
} | ||
for (let i = 0; i < self.nodeCount; i++) { | ||
self.nodes[i] = nodeLine(self, self.nodes[i]); | ||
} | ||
// Prepend symbols | ||
for (let sym = self.symCount - 1; sym >= 0; sym--) { | ||
self.nodes.unshift( | ||
encoding.toAlphaCode(sym) + | ||
config.KEY_VAL + | ||
encoding.toAlphaCode(self.nodeCount - self.histAbs[sym][0] - 1) | ||
); | ||
} | ||
return self.nodes.join(config.NODE_SEP) | ||
}; | ||
// Return packed representation of Trie as a string. | ||
// | ||
// Each node of the Trie is output on a single line. | ||
// | ||
// For example Trie("the them there thesis this"): | ||
// { | ||
// "th": { | ||
// "is": 1, | ||
// "e": { | ||
// "": 1, | ||
// "m": 1, | ||
// "re": 1, | ||
// "sis": 1 | ||
// } | ||
// } | ||
// } | ||
// | ||
// Would be reperesented as: | ||
// | ||
// th0 | ||
// e0is | ||
// !m,re,sis | ||
// | ||
// The line begins with a '!' iff it is a terminal node of the Trie. | ||
// For each string property in a node, the string is listed, along | ||
// with a (relative!) line number of the node that string references. | ||
// Terminal strings (those without child node references) are | ||
// separated by ',' characters. | ||
const NOT_ALLOWED = new RegExp('[0-9A-Z,;!:|¦]'); //characters banned from entering the trie | ||
const nodeLine = function(self, node) { | ||
let line = '', | ||
sep = ''; | ||
const methods = { | ||
// Insert words from one big string, or from an array. | ||
insertWords: function (words) { | ||
if (words === undefined) { | ||
return | ||
} | ||
if (typeof words === 'string') { | ||
words = words.split(/[^a-zA-Z]+/); | ||
} | ||
for (let i = 0; i < words.length; i++) { | ||
words[i] = words[i].toLowerCase(); | ||
} | ||
fns.unique(words); | ||
for (let i = 0; i < words.length; i++) { | ||
if (words[i].match(NOT_ALLOWED) === null) { | ||
this.insert(words[i]); | ||
} | ||
} | ||
}, | ||
if (self.isTerminal(node)) { | ||
line += config.TERMINAL_PREFIX; | ||
} | ||
insert: function (word) { | ||
this._insert(word, this.root); | ||
const lastWord = this.lastWord; | ||
this.lastWord = word; | ||
const props = self.nodeProps(node); | ||
for (let i = 0; i < props.length; i++) { | ||
const prop = props[i]; | ||
if (typeof node[prop] === 'number') { | ||
line += sep + prop; | ||
sep = config.STRING_SEP; | ||
continue | ||
} | ||
if (self.syms[node[prop]._n]) { | ||
line += sep + prop + self.syms[node[prop]._n]; | ||
sep = ''; | ||
continue | ||
} | ||
let ref = encoding.toAlphaCode(node._n - node[prop]._n - 1 + self.symCount); | ||
// Large reference to smaller string suffix -> duplicate suffix | ||
if (node[prop]._g && ref.length >= node[prop]._g.length && node[node[prop]._g] === 1) { | ||
ref = node[prop]._g; | ||
line += sep + prop + ref; | ||
sep = config.STRING_SEP; | ||
continue | ||
} | ||
line += sep + prop + ref; | ||
sep = ''; | ||
} | ||
return line | ||
}; | ||
const prefix = fns.commonPrefix(word, lastWord); | ||
if (prefix === lastWord) { | ||
return | ||
} | ||
const analyzeRefs = function(self, node) { | ||
if (self.visited(node)) { | ||
return | ||
} | ||
const props = self.nodeProps(node, true); | ||
for (let i = 0; i < props.length; i++) { | ||
const prop = props[i]; | ||
const ref = node._n - node[prop]._n - 1; | ||
// Count the number of single-character relative refs | ||
if (ref < config.BASE) { | ||
self.histRel.add(ref); | ||
} | ||
// Count the number of characters saved by converting an absolute | ||
// reference to a one-character symbol. | ||
self.histAbs.add(node[prop]._n, encoding.toAlphaCode(ref).length - 1); | ||
analyzeRefs(self, node[prop]); | ||
} | ||
}; | ||
const freeze = this.uniqueNode(lastWord, word, this.root); | ||
if (freeze) { | ||
this.combineSuffixNode(freeze); | ||
} | ||
}, | ||
const symbolCount = function(self) { | ||
self.histAbs = self.histAbs.highest(config.BASE); | ||
const savings = []; | ||
savings[-1] = 0; | ||
let best = 0, | ||
sCount = 0; | ||
const defSize = 3 + encoding.toAlphaCode(self.nodeCount).length; | ||
for (let sym = 0; sym < config.BASE; sym++) { | ||
if (self.histAbs[sym] === undefined) { | ||
break | ||
} | ||
savings[sym] = | ||
self.histAbs[sym][1] - | ||
defSize - | ||
self.histRel.countOf(config.BASE - sym - 1) + | ||
savings[sym - 1]; | ||
if (savings[sym] >= best) { | ||
best = savings[sym]; | ||
sCount = sym + 1; | ||
} | ||
} | ||
return sCount | ||
}; | ||
_insert: function (word, node) { | ||
let prefix, next; | ||
const numberNodes = function(self, node) { | ||
// Topological sort into nodes array | ||
if (node._n !== undefined) { | ||
return | ||
} | ||
const props = self.nodeProps(node, true); | ||
for (let i = 0; i < props.length; i++) { | ||
numberNodes(self, node[props[i]]); //recursive | ||
} | ||
node._n = self.pos++; | ||
self.nodes.unshift(node); | ||
}; | ||
// Duplicate word entry - ignore | ||
if (word.length === 0) { | ||
return | ||
} | ||
const pack = function(self) { | ||
self.nodes = []; | ||
self.nodeCount = 0; | ||
self.syms = {}; | ||
self.symCount = 0; | ||
self.pos = 0; | ||
// Make sure we've combined all the common suffixes | ||
self.optimize(); | ||
// Do any existing props share a common prefix? | ||
const keys = Object.keys(node); | ||
for (let i = 0; i < keys.length; i++) { | ||
const prop = keys[i]; | ||
prefix = fns.commonPrefix(word, prop); | ||
if (prefix.length === 0) { | ||
continue | ||
} | ||
// Prop is a proper prefix - recurse to child node | ||
if (prop === prefix && typeof node[prop] === 'object') { | ||
this._insert(word.slice(prefix.length), node[prop]); | ||
return | ||
} | ||
// Duplicate terminal string - ignore | ||
if (prop === word && typeof node[prop] === 'number') { | ||
return | ||
} | ||
next = {}; | ||
next[prop.slice(prefix.length)] = node[prop]; | ||
this.addTerminal(next, (word = word.slice(prefix.length))); | ||
delete node[prop]; | ||
node[prefix] = next; | ||
this.wordCount++; | ||
return | ||
} | ||
self.histAbs = new histogram(); | ||
self.histRel = new histogram(); | ||
// No shared prefix. Enter the word here as a terminal string. | ||
this.addTerminal(node, word); | ||
this.wordCount++; | ||
}, | ||
numberNodes(self, self.root); | ||
self.nodeCount = self.nodes.length; | ||
// Add a terminal string to node. | ||
// If 2 characters or less, just add with value == 1. | ||
// If more than 2 characters, point to shared node | ||
// Note - don't prematurely share suffixes - these | ||
// terminals may become split and joined with other | ||
// nodes in this part of the tree. | ||
addTerminal: function (node, prop) { | ||
if (prop.length <= 1) { | ||
node[prop] = 1; | ||
return | ||
} | ||
const next = {}; | ||
node[prop[0]] = next; | ||
this.addTerminal(next, prop.slice(1)); | ||
}, | ||
self.prepDFS(); | ||
analyzeRefs(self, self.root); | ||
self.symCount = symbolCount(self); | ||
for (let sym = 0; sym < self.symCount; sym++) { | ||
self.syms[self.histAbs[sym][0]] = encoding.toAlphaCode(sym); | ||
} | ||
for (let i = 0; i < self.nodeCount; i++) { | ||
self.nodes[i] = nodeLine(self, self.nodes[i]); | ||
} | ||
// Prepend symbols | ||
for (let sym = self.symCount - 1; sym >= 0; sym--) { | ||
self.nodes.unshift( | ||
encoding.toAlphaCode(sym) + | ||
config.KEY_VAL + | ||
encoding.toAlphaCode(self.nodeCount - self.histAbs[sym][0] - 1) | ||
); | ||
} | ||
// Well ordered list of properties in a node (string or object properties) | ||
// Use nodesOnly==true to return only properties of child nodes (not | ||
// terminal strings. | ||
nodeProps: function (node, nodesOnly) { | ||
const props = []; | ||
for (const prop in node) { | ||
if (prop !== '' && prop[0] !== '_') { | ||
if (!nodesOnly || typeof node[prop] === 'object') { | ||
props.push(prop); | ||
} | ||
} | ||
} | ||
props.sort(); | ||
return props | ||
}, | ||
return self.nodes.join(config.NODE_SEP) | ||
}; | ||
optimize: function () { | ||
this.combineSuffixNode(this.root); | ||
this.prepDFS(); | ||
this.countDegree(this.root); | ||
this.prepDFS(); | ||
this.collapseChains(this.root); | ||
}, | ||
var pack_1 = pack; | ||
// Convert Trie to a DAWG by sharing identical nodes | ||
combineSuffixNode: function (node) { | ||
// Frozen node - can't change. | ||
if (node._c) { | ||
return node | ||
} | ||
// Make sure all children are combined and generate unique node | ||
// signature for this node. | ||
let sig = []; | ||
if (this.isTerminal(node)) { | ||
sig.push('!'); | ||
} | ||
const props = this.nodeProps(node); | ||
for (let i = 0; i < props.length; i++) { | ||
const prop = props[i]; | ||
if (typeof node[prop] === 'object') { | ||
node[prop] = this.combineSuffixNode(node[prop]); | ||
sig.push(prop); | ||
sig.push(node[prop]._c); | ||
} else { | ||
sig.push(prop); | ||
} | ||
} | ||
sig = sig.join('-'); | ||
const NOT_ALLOWED = new RegExp('[0-9A-Z,;!:|¦]'); //characters banned from entering the trie | ||
const shared = this.suffixes[sig]; | ||
if (shared) { | ||
return shared | ||
} | ||
this.suffixes[sig] = node; | ||
node._c = this.cNext++; | ||
return node | ||
}, | ||
var methods$1 = { | ||
// Insert words from one big string, or from an array. | ||
insertWords: function(words) { | ||
if (words === undefined) { | ||
return | ||
} | ||
if (typeof words === 'string') { | ||
words = words.split(/[^a-zA-Z]+/); | ||
} | ||
for (let i = 0; i < words.length; i++) { | ||
words[i] = words[i].toLowerCase(); | ||
} | ||
fns.unique(words); | ||
for (let i = 0; i < words.length; i++) { | ||
if (words[i].match(NOT_ALLOWED) === null) { | ||
this.insert(words[i]); | ||
} | ||
} | ||
}, | ||
prepDFS: function () { | ||
this.vCur++; | ||
}, | ||
insert: function(word) { | ||
this._insert(word, this.root); | ||
const lastWord = this.lastWord; | ||
this.lastWord = word; | ||
visited: function (node) { | ||
if (node._v === this.vCur) { | ||
return true | ||
} | ||
node._v = this.vCur; | ||
return false | ||
}, | ||
const prefix = fns.commonPrefix(word, lastWord); | ||
if (prefix === lastWord) { | ||
return | ||
} | ||
countDegree: function (node) { | ||
if (node._d === undefined) { | ||
node._d = 0; | ||
} | ||
node._d++; | ||
if (this.visited(node)) { | ||
return | ||
} | ||
const props = this.nodeProps(node, true); | ||
for (let i = 0; i < props.length; i++) { | ||
this.countDegree(node[props[i]]); | ||
} | ||
}, | ||
const freeze = this.uniqueNode(lastWord, word, this.root); | ||
if (freeze) { | ||
this.combineSuffixNode(freeze); | ||
} | ||
}, | ||
// Remove intermediate singleton nodes by hoisting into their parent | ||
collapseChains: function (node) { | ||
let prop, props, child, i; | ||
if (this.visited(node)) { | ||
return | ||
} | ||
props = this.nodeProps(node); | ||
for (i = 0; i < props.length; i++) { | ||
prop = props[i]; | ||
child = node[prop]; | ||
if (typeof child !== 'object') { | ||
continue | ||
} | ||
this.collapseChains(child); | ||
// Hoist the singleton child's single property to the parent | ||
if (child._g !== undefined && (child._d === 1 || child._g.length === 1)) { | ||
delete node[prop]; | ||
prop += child._g; | ||
node[prop] = child[child._g]; | ||
} | ||
} | ||
// Identify singleton nodes | ||
if (props.length === 1 && !this.isTerminal(node)) { | ||
node._g = prop; | ||
} | ||
}, | ||
_insert: function(word, node) { | ||
let prefix, next; | ||
isTerminal: function (node) { | ||
return !!node[''] | ||
}, | ||
// Duplicate word entry - ignore | ||
if (word.length === 0) { | ||
return | ||
} | ||
// Find highest node in Trie that is on the path to word | ||
// and that is NOT on the path to other. | ||
uniqueNode: function (word, other, node) { | ||
const props = this.nodeProps(node, true); | ||
for (let i = 0; i < props.length; i++) { | ||
const prop = props[i]; | ||
if (prop === word.slice(0, prop.length)) { | ||
if (prop !== other.slice(0, prop.length)) { | ||
return node[prop] | ||
} | ||
return this.uniqueNode(word.slice(prop.length), other.slice(prop.length), node[prop]) | ||
} | ||
} | ||
return undefined | ||
}, | ||
// Do any existing props share a common prefix? | ||
const keys = Object.keys(node); | ||
for (let i = 0; i < keys.length; i++) { | ||
const prop = keys[i]; | ||
prefix = fns.commonPrefix(word, prop); | ||
if (prefix.length === 0) { | ||
continue | ||
} | ||
// Prop is a proper prefix - recurse to child node | ||
if (prop === prefix && typeof node[prop] === 'object') { | ||
this._insert(word.slice(prefix.length), node[prop]); | ||
return | ||
} | ||
// Duplicate terminal string - ignore | ||
if (prop === word && typeof node[prop] === 'number') { | ||
return | ||
} | ||
next = {}; | ||
next[prop.slice(prefix.length)] = node[prop]; | ||
this.addTerminal(next, word = word.slice(prefix.length)); | ||
delete node[prop]; | ||
node[prefix] = next; | ||
this.wordCount++; | ||
return | ||
} | ||
pack: function () { | ||
return pack$1(this) | ||
} | ||
}; | ||
// No shared prefix. Enter the word here as a terminal string. | ||
this.addTerminal(node, word); | ||
this.wordCount++; | ||
}, | ||
/* | ||
A JavaScript implementation of a Trie search datastructure. | ||
Each node of the Trie is an Object that can contain the following properties: | ||
'' - If present (with value == 1), the node is a Terminal Node - the prefix | ||
leading to this node is a word in the dictionary. | ||
numeric properties (value == 1) - the property name is a terminal string | ||
so that the prefix + string is a word in the dictionary. | ||
Object properties - the property name is one or more characters to be consumed | ||
from the prefix of the test string, with the remainder to be checked in | ||
the child node. | ||
'_c': A unique name for the node (starting from 1), used in combining Suffixes. | ||
'_n': Created when packing the Trie, the sequential node number | ||
(in pre-order traversal). | ||
'_d': The number of times a node is shared (it's in-degree from other nodes). | ||
'_v': Visited in DFS. | ||
'_g': For singleton nodes, the name of it's single property. | ||
*/ | ||
const Trie = function (words) { | ||
this.root = {}; | ||
this.lastWord = ''; | ||
this.suffixes = {}; | ||
this.suffixCounts = {}; | ||
this.cNext = 1; | ||
this.wordCount = 0; | ||
this.insertWords(words); | ||
this.vCur = 0; | ||
}; | ||
// Add a terminal string to node. | ||
// If 2 characters or less, just add with value == 1. | ||
// If more than 2 characters, point to shared node | ||
// Note - don't prematurely share suffixes - these | ||
// terminals may become split and joined with other | ||
// nodes in this part of the tree. | ||
addTerminal: function(node, prop) { | ||
if (prop.length <= 1) { | ||
node[prop] = 1; | ||
return | ||
} | ||
const next = {}; | ||
node[prop[0]] = next; | ||
this.addTerminal(next, prop.slice(1)); | ||
}, | ||
Object.keys(methods).forEach(function (k) { | ||
Trie.prototype[k] = methods[k]; | ||
}); | ||
// Well ordered list of properties in a node (string or object properties) | ||
// Use nodesOnly==true to return only properties of child nodes (not | ||
// terminal strings. | ||
nodeProps: function(node, nodesOnly) { | ||
const props = []; | ||
for (const prop in node) { | ||
if (prop !== '' && prop[0] !== '_') { | ||
if (!nodesOnly || typeof node[prop] === 'object') { | ||
props.push(prop); | ||
} | ||
} | ||
} | ||
props.sort(); | ||
return props | ||
}, | ||
const isArray = function (input) { | ||
return Object.prototype.toString.call(input) === '[object Array]' | ||
}; | ||
optimize: function() { | ||
this.combineSuffixNode(this.root); | ||
this.prepDFS(); | ||
this.countDegree(this.root); | ||
this.prepDFS(); | ||
this.collapseChains(this.root); | ||
}, | ||
const handleFormats = function (input) { | ||
//null | ||
if (input === null || input === undefined) { | ||
return {} | ||
} | ||
//string | ||
if (typeof input === 'string') { | ||
return input.split(/ +/g).reduce(function (h, str) { | ||
h[str] = true; | ||
return h | ||
}, {}) | ||
} | ||
//array | ||
if (isArray(input)) { | ||
return input.reduce(function (h, str) { | ||
h[str] = true; | ||
return h | ||
}, {}) | ||
} | ||
//object | ||
return input | ||
}; | ||
// Convert Trie to a DAWG by sharing identical nodes | ||
combineSuffixNode: function(node) { | ||
// Frozen node - can't change. | ||
if (node._c) { | ||
return node | ||
} | ||
// Make sure all children are combined and generate unique node | ||
// signature for this node. | ||
let sig = []; | ||
if (this.isTerminal(node)) { | ||
sig.push('!'); | ||
} | ||
const props = this.nodeProps(node); | ||
for (let i = 0; i < props.length; i++) { | ||
const prop = props[i]; | ||
if (typeof node[prop] === 'object') { | ||
node[prop] = this.combineSuffixNode(node[prop]); | ||
sig.push(prop); | ||
sig.push(node[prop]._c); | ||
} else { | ||
sig.push(prop); | ||
} | ||
} | ||
sig = sig.join('-'); | ||
//turn an array into a compressed string | ||
const pack = function (obj) { | ||
obj = handleFormats(obj); | ||
//pivot into categories: | ||
const flat = Object.keys(obj).reduce(function (h, k) { | ||
const val = obj[k]; | ||
//array version- | ||
//put it in several buckets | ||
if (isArray(val)) { | ||
for (let i = 0; i < val.length; i++) { | ||
h[val[i]] = h[val[i]] || []; | ||
h[val[i]].push(k); | ||
} | ||
return h | ||
} | ||
//normal string/boolean version | ||
if (h.hasOwnProperty(val) === false) { | ||
//basically h[val]=[] - support reserved words | ||
Object.defineProperty(h, val, { | ||
writable: true, | ||
enumerable: true, | ||
configurable: true, | ||
value: [] | ||
}); | ||
} | ||
h[val].push(k); | ||
return h | ||
}, {}); | ||
//pack each into a compressed string | ||
Object.keys(flat).forEach(function (k) { | ||
const t = new Trie(flat[k]); | ||
flat[k] = t.pack(); | ||
}); | ||
const shared = this.suffixes[sig]; | ||
if (shared) { | ||
return shared | ||
} | ||
this.suffixes[sig] = node; | ||
node._c = this.cNext++; | ||
return node | ||
}, | ||
return Object.keys(flat) | ||
.map((k) => { | ||
return k + '¦' + flat[k] | ||
}) | ||
.join('|') | ||
}; | ||
prepDFS: function() { | ||
this.vCur++; | ||
}, | ||
const symbols = function (t) { | ||
//... process these lines | ||
const reSymbol = new RegExp('([0-9A-Z]+):([0-9A-Z]+)'); | ||
for (let i = 0; i < t.nodes.length; i++) { | ||
const m = reSymbol.exec(t.nodes[i]); | ||
if (!m) { | ||
t.symCount = i; | ||
break | ||
} | ||
t.syms[encoding.fromAlphaCode(m[1])] = encoding.fromAlphaCode(m[2]); | ||
} | ||
//remove from main node list | ||
t.nodes = t.nodes.slice(t.symCount, t.nodes.length); | ||
}; | ||
visited: function(node) { | ||
if (node._v === this.vCur) { | ||
return true | ||
} | ||
node._v = this.vCur; | ||
return false | ||
}, | ||
// References are either absolute (symbol) or relative (1 - based) | ||
const indexFromRef = function (trie, ref, index) { | ||
const dnode = encoding.fromAlphaCode(ref); | ||
if (dnode < trie.symCount) { | ||
return trie.syms[dnode] | ||
} | ||
return index + dnode + 1 - trie.symCount | ||
}; | ||
countDegree: function(node) { | ||
if (node._d === undefined) { | ||
node._d = 0; | ||
} | ||
node._d++; | ||
if (this.visited(node)) { | ||
return | ||
} | ||
const props = this.nodeProps(node, true); | ||
for (let i = 0; i < props.length; i++) { | ||
this.countDegree(node[props[i]]); | ||
} | ||
}, | ||
const toArray = function (trie) { | ||
const all = []; | ||
const crawl = (index, pref) => { | ||
let node = trie.nodes[index]; | ||
if (node[0] === '!') { | ||
all.push(pref); | ||
node = node.slice(1); //ok, we tried. remove it. | ||
} | ||
const matches = node.split(/([A-Z0-9,]+)/g); | ||
for (let i = 0; i < matches.length; i += 2) { | ||
const str = matches[i]; | ||
const ref = matches[i + 1]; | ||
if (!str) { | ||
continue | ||
} | ||
const have = pref + str; | ||
//branch's end | ||
if (ref === ',' || ref === undefined) { | ||
all.push(have); | ||
continue | ||
} | ||
const newIndex = indexFromRef(trie, ref, index); | ||
crawl(newIndex, have); | ||
} | ||
}; | ||
crawl(0, ''); | ||
return all | ||
}; | ||
// Remove intermediate singleton nodes by hoisting into their parent | ||
collapseChains: function(node) { | ||
let prop, props, child, i; | ||
if (this.visited(node)) { | ||
return | ||
} | ||
props = this.nodeProps(node); | ||
for (i = 0; i < props.length; i++) { | ||
prop = props[i]; | ||
child = node[prop]; | ||
if (typeof child !== 'object') { | ||
continue | ||
} | ||
this.collapseChains(child); | ||
// Hoist the singleton child's single property to the parent | ||
if (child._g !== undefined && (child._d === 1 || child._g.length === 1)) { | ||
delete node[prop]; | ||
prop += child._g; | ||
node[prop] = child[child._g]; | ||
} | ||
} | ||
// Identify singleton nodes | ||
if (props.length === 1 && !this.isTerminal(node)) { | ||
node._g = prop; | ||
} | ||
}, | ||
//PackedTrie - Trie traversal of the Trie packed-string representation. | ||
const unpack$1 = function (str) { | ||
const trie = { | ||
nodes: str.split(';'), | ||
syms: [], | ||
symCount: 0 | ||
}; | ||
//process symbols, if they have them | ||
if (str.match(':')) { | ||
symbols(trie); | ||
} | ||
return toArray(trie) | ||
}; | ||
isTerminal: function(node) { | ||
return !!node[''] | ||
}, | ||
const unpack = function (str) { | ||
//turn the weird string into a key-value object again | ||
const obj = str.split('|').reduce((h, s) => { | ||
const arr = s.split('¦'); | ||
h[arr[0]] = arr[1]; | ||
return h | ||
}, {}); | ||
const all = {}; | ||
Object.keys(obj).forEach(function (cat) { | ||
const arr = unpack$1(obj[cat]); | ||
//special case, for botched-boolean | ||
if (cat === 'true') { | ||
cat = true; | ||
} | ||
for (let i = 0; i < arr.length; i++) { | ||
const k = arr[i]; | ||
if (all.hasOwnProperty(k) === true) { | ||
if (Array.isArray(all[k]) === false) { | ||
all[k] = [all[k], cat]; | ||
} else { | ||
all[k].push(cat); | ||
} | ||
} else { | ||
all[k] = cat; | ||
} | ||
} | ||
}); | ||
return all | ||
}; | ||
// Find highest node in Trie that is on the path to word | ||
// and that is NOT on the path to other. | ||
uniqueNode: function(word, other, node) { | ||
const props = this.nodeProps(node, true); | ||
for (let i = 0; i < props.length; i++) { | ||
const prop = props[i]; | ||
if (prop === word.slice(0, prop.length)) { | ||
if (prop !== other.slice(0, prop.length)) { | ||
return node[prop] | ||
} | ||
return this.uniqueNode(word.slice(prop.length), other.slice(prop.length), node[prop]) | ||
} | ||
} | ||
return undefined | ||
}, | ||
var _version = '2.3.0'; | ||
pack: function() { | ||
return pack_1(this) | ||
} | ||
}; | ||
exports.pack = pack; | ||
exports.unpack = unpack; | ||
exports.version = _version; | ||
/* | ||
A JavaScript implementation of a Trie search datastructure. | ||
Each node of the Trie is an Object that can contain the following properties: | ||
'' - If present (with value == 1), the node is a Terminal Node - the prefix | ||
leading to this node is a word in the dictionary. | ||
numeric properties (value == 1) - the property name is a terminal string | ||
so that the prefix + string is a word in the dictionary. | ||
Object properties - the property name is one or more characters to be consumed | ||
from the prefix of the test string, with the remainder to be checked in | ||
the child node. | ||
'_c': A unique name for the node (starting from 1), used in combining Suffixes. | ||
'_n': Created when packing the Trie, the sequential node number | ||
(in pre-order traversal). | ||
'_d': The number of times a node is shared (it's in-degree from other nodes). | ||
'_v': Visited in DFS. | ||
'_g': For singleton nodes, the name of it's single property. | ||
*/ | ||
const Trie = function(words) { | ||
this.root = {}; | ||
this.lastWord = ''; | ||
this.suffixes = {}; | ||
this.suffixCounts = {}; | ||
this.cNext = 1; | ||
this.wordCount = 0; | ||
this.insertWords(words); | ||
this.vCur = 0; | ||
}; | ||
Object.keys(methods$1).forEach(function(k) { | ||
Trie.prototype[k] = methods$1[k]; | ||
}); | ||
var trie = Trie; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
const isArray = function(input) { | ||
return Object.prototype.toString.call(input) === '[object Array]' | ||
}; | ||
const handleFormats = function(input) { | ||
//null | ||
if (input === null || input === undefined) { | ||
return {} | ||
} | ||
//string | ||
if (typeof input === 'string') { | ||
return input.split(/ +/g).reduce(function(h, str) { | ||
h[str] = true; | ||
return h | ||
}, {}) | ||
} | ||
//array | ||
if (isArray(input)) { | ||
return input.reduce(function(h, str) { | ||
h[str] = true; | ||
return h | ||
}, {}) | ||
} | ||
//object | ||
return input | ||
}; | ||
//turn an array into a compressed string | ||
const pack$1 = function(obj) { | ||
obj = handleFormats(obj); | ||
//pivot into categories: | ||
const flat = Object.keys(obj).reduce(function(h, k) { | ||
const val = obj[k]; | ||
//array version- | ||
//put it in several buckets | ||
if (isArray(val)) { | ||
for (let i = 0; i < val.length; i++) { | ||
h[val[i]] = h[val[i]] || []; | ||
h[val[i]].push(k); | ||
} | ||
return h | ||
} | ||
//normal string/boolean version | ||
if (h.hasOwnProperty(val) === false) { | ||
//basically h[val]=[] - support reserved words | ||
Object.defineProperty(h, val, { | ||
writable: true, | ||
enumerable: true, | ||
configurable: true, | ||
value: [] | ||
}); | ||
} | ||
h[val].push(k); | ||
return h | ||
}, {}); | ||
//pack each into a compressed string | ||
Object.keys(flat).forEach(function(k) { | ||
const t = new trie(flat[k]); | ||
flat[k] = t.pack(); | ||
}); | ||
// flat = JSON.stringify(flat, null, 0); | ||
return Object.keys(flat) | ||
.map(k => { | ||
return k + '¦' + flat[k] | ||
}) | ||
.join('|') | ||
// return flat; | ||
}; | ||
var pack_1$1 = pack$1; | ||
//the symbols are at the top of the array. | ||
var symbols = function(t) { | ||
//... process these lines | ||
const reSymbol = new RegExp('([0-9A-Z]+):([0-9A-Z]+)'); | ||
for (let i = 0; i < t.nodes.length; i++) { | ||
const m = reSymbol.exec(t.nodes[i]); | ||
if (!m) { | ||
t.symCount = i; | ||
break | ||
} | ||
t.syms[encoding.fromAlphaCode(m[1])] = encoding.fromAlphaCode(m[2]); | ||
} | ||
//remove from main node list | ||
t.nodes = t.nodes.slice(t.symCount, t.nodes.length); | ||
}; | ||
// References are either absolute (symbol) or relative (1 - based) | ||
const indexFromRef = function(trie, ref, index) { | ||
const dnode = encoding.fromAlphaCode(ref); | ||
if (dnode < trie.symCount) { | ||
return trie.syms[dnode] | ||
} | ||
return index + dnode + 1 - trie.symCount | ||
}; | ||
const toArray = function(trie) { | ||
const all = []; | ||
const crawl = (index, pref) => { | ||
let node = trie.nodes[index]; | ||
if (node[0] === '!') { | ||
all.push(pref); | ||
node = node.slice(1); //ok, we tried. remove it. | ||
} | ||
const matches = node.split(/([A-Z0-9,]+)/g); | ||
for (let i = 0; i < matches.length; i += 2) { | ||
const str = matches[i]; | ||
const ref = matches[i + 1]; | ||
if (!str) { | ||
continue | ||
} | ||
const have = pref + str; | ||
//branch's end | ||
if (ref === ',' || ref === undefined) { | ||
all.push(have); | ||
continue | ||
} | ||
const newIndex = indexFromRef(trie, ref, index); | ||
crawl(newIndex, have); | ||
} | ||
}; | ||
crawl(0, ''); | ||
return all | ||
}; | ||
//PackedTrie - Trie traversal of the Trie packed-string representation. | ||
const unpack = function(str) { | ||
const trie = { | ||
nodes: str.split(';'), //that's all ;)! | ||
syms: [], | ||
symCount: 0 | ||
}; | ||
//process symbols, if they have them | ||
if (str.match(':')) { | ||
symbols(trie); | ||
} | ||
return toArray(trie) | ||
}; | ||
var unpack_1 = unpack; | ||
var unpack_1$1 = function(str) { | ||
//turn the weird string into a key-value object again | ||
const obj = str.split('|').reduce((h, s) => { | ||
const arr = s.split('¦'); | ||
h[arr[0]] = arr[1]; | ||
return h | ||
}, {}); | ||
const all = {}; | ||
Object.keys(obj).forEach(function(cat) { | ||
const arr = unpack_1(obj[cat]); | ||
//special case, for botched-boolean | ||
if (cat === 'true') { | ||
cat = true; | ||
} | ||
for (let i = 0; i < arr.length; i++) { | ||
const k = arr[i]; | ||
if (all.hasOwnProperty(k) === true) { | ||
if (Array.isArray(all[k]) === false) { | ||
all[k] = [all[k], cat]; | ||
} else { | ||
all[k].push(cat); | ||
} | ||
} else { | ||
all[k] = cat; | ||
} | ||
} | ||
}); | ||
return all | ||
}; | ||
var src = createCommonjsModule(function (module) { | ||
const efrt = { | ||
pack: pack_1$1, | ||
unpack: unpack_1$1 | ||
}; | ||
//and then all-the-exports... | ||
if (typeof self !== 'undefined') { | ||
self.efrt = efrt; // Web Worker | ||
} else if (typeof window !== 'undefined') { | ||
window.efrt = efrt; // Browser | ||
} else if (typeof commonjsGlobal !== 'undefined') { | ||
commonjsGlobal.efrt = efrt; // NodeJS | ||
} | ||
//then for some reason, do this too! | ||
{ | ||
module.exports = efrt; | ||
} | ||
}); | ||
return src; | ||
})); | ||
}))); |
@@ -1,2 +0,1 @@ | ||
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(t=t||self).efrt=n()}(this,function(){"use strict";var t="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var n=function(t,n){let e=Math.min(t.length,n.length);for(;e>0;){const o=t.slice(0,e);if(o===n.slice(0,e))return o;e-=1}return""},e=function(t){t.sort();for(let n=1;n<t.length;n++)t[n-1]===t[n]&&t.splice(n,1)};const o=function(){this.counts={}},s={init:function(t){void 0===this.counts[t]&&(this.counts[t]=0)},add:function(t,n){void 0===n&&(n=1),this.init(t),this.counts[t]+=n},countOf:function(t){return this.init(t),this.counts[t]},highest:function(t){let n=[];const e=Object.keys(this.counts);for(let t=0;t<e.length;t++){const o=e[t];n.push([o,this.counts[o]])}return n.sort(function(t,n){return n[1]-t[1]}),t&&(n=n.slice(0,t)),n}};Object.keys(s).forEach(function(t){o.prototype[t]=s[t]});var i=o;const r="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",u=r.split("").reduce(function(t,n,e){return t[n]=e,t},{});var c=function(t){if(void 0!==r[t])return r[t];let n=1,e=36,o="";for(;t>=e;t-=e,n++,e*=36);for(;n--;){const n=t%36;o=String.fromCharCode((n<10?48:55)+n)+o,t=(t-n)/36}return o},f=function(t){if(void 0!==u[t])return u[t];let n=0,e=1,o=36,s=1;for(;e<t.length;n+=o,e++,o*=36);for(let e=t.length-1;e>=0;e--,s*=36){let o=t.charCodeAt(e)-48;o>10&&(o-=7),n+=o*s}return n};const h=";",l=":",d=",",p="!",a=36,g=function(t,n){let e="",o="";t.isTerminal(n)&&(e+=p);const s=t.nodeProps(n);for(let i=0;i<s.length;i++){const r=s[i];if("number"==typeof n[r]){e+=o+r,o=d;continue}if(t.syms[n[r]._n]){e+=o+r+t.syms[n[r]._n],o="";continue}let u=c(n._n-n[r]._n-1+t.symCount);n[r]._g&&u.length>=n[r]._g.length&&1===n[n[r]._g]?(e+=o+r+(u=n[r]._g),o=d):(e+=o+r+u,o="")}return e},y=function(t,n){if(t.visited(n))return;const e=t.nodeProps(n,!0);for(let o=0;o<e.length;o++){const s=e[o],i=n._n-n[s]._n-1;i<a&&t.histRel.add(i),t.histAbs.add(n[s]._n,c(i).length-1),y(t,n[s])}},m=function(t,n){if(void 0!==n._n)return;const e=t.nodeProps(n,!0);for(let o=0;o<e.length;o++)m(t,n[e[o]]);n._n=t.pos++,t.nodes.unshift(n)};var b=function(t){t.nodes=[],t.nodeCount=0,t.syms={},t.symCount=0,t.pos=0,t.optimize(),t.histAbs=new i,t.histRel=new i,m(t,t.root),t.nodeCount=t.nodes.length,t.prepDFS(),y(t,t.root),t.symCount=function(t){t.histAbs=t.histAbs.highest(a);const n=[];n[-1]=0;let e=0,o=0;const s=3+c(t.nodeCount).length;for(let i=0;i<a&&void 0!==t.histAbs[i];i++)n[i]=t.histAbs[i][1]-s-t.histRel.countOf(a-i-1)+n[i-1],n[i]>=e&&(e=n[i],o=i+1);return o}(t);for(let n=0;n<t.symCount;n++)t.syms[t.histAbs[n][0]]=c(n);for(let n=0;n<t.nodeCount;n++)t.nodes[n]=g(t,t.nodes[n]);for(let n=t.symCount-1;n>=0;n--)t.nodes.unshift(c(n)+l+c(t.nodeCount-t.histAbs[n][0]-1));return t.nodes.join(h)};const v=new RegExp("[0-9A-Z,;!:|¦]");var C={insertWords:function(t){if(void 0!==t){"string"==typeof t&&(t=t.split(/[^a-zA-Z]+/));for(let n=0;n<t.length;n++)t[n]=t[n].toLowerCase();e(t);for(let n=0;n<t.length;n++)null===t[n].match(v)&&this.insert(t[n])}},insert:function(t){this._insert(t,this.root);const e=this.lastWord;if(this.lastWord=t,n(t,e)===e)return;const o=this.uniqueNode(e,t,this.root);o&&this.combineSuffixNode(o)},_insert:function(t,e){let o,s;if(0===t.length)return;const i=Object.keys(e);for(let r=0;r<i.length;r++){const u=i[r];if(0!==(o=n(t,u)).length){if(u===o&&"object"==typeof e[u])return void this._insert(t.slice(o.length),e[u]);if(u===t&&"number"==typeof e[u])return;return(s={})[u.slice(o.length)]=e[u],this.addTerminal(s,t=t.slice(o.length)),delete e[u],e[o]=s,void this.wordCount++}}this.addTerminal(e,t),this.wordCount++},addTerminal:function(t,n){if(n.length<=1)return void(t[n]=1);const e={};t[n[0]]=e,this.addTerminal(e,n.slice(1))},nodeProps:function(t,n){const e=[];for(const o in t)""!==o&&"_"!==o[0]&&(n&&"object"!=typeof t[o]||e.push(o));return e.sort(),e},optimize:function(){this.combineSuffixNode(this.root),this.prepDFS(),this.countDegree(this.root),this.prepDFS(),this.collapseChains(this.root)},combineSuffixNode:function(t){if(t._c)return t;let n=[];this.isTerminal(t)&&n.push("!");const e=this.nodeProps(t);for(let o=0;o<e.length;o++){const s=e[o];"object"==typeof t[s]?(t[s]=this.combineSuffixNode(t[s]),n.push(s),n.push(t[s]._c)):n.push(s)}n=n.join("-");const o=this.suffixes[n];return o||(this.suffixes[n]=t,t._c=this.cNext++,t)},prepDFS:function(){this.vCur++},visited:function(t){return t._v===this.vCur||(t._v=this.vCur,!1)},countDegree:function(t){if(void 0===t._d&&(t._d=0),t._d++,this.visited(t))return;const n=this.nodeProps(t,!0);for(let e=0;e<n.length;e++)this.countDegree(t[n[e]])},collapseChains:function(t){let n,e,o,s;if(!this.visited(t)){for(e=this.nodeProps(t),s=0;s<e.length;s++)"object"==typeof(o=t[n=e[s]])&&(this.collapseChains(o),void 0===o._g||1!==o._d&&1!==o._g.length||(delete t[n],t[n+=o._g]=o[o._g]));1!==e.length||this.isTerminal(t)||(t._g=n)}},isTerminal:function(t){return!!t[""]},uniqueNode:function(t,n,e){const o=this.nodeProps(e,!0);for(let s=0;s<o.length;s++){const i=o[s];if(i===t.slice(0,i.length))return i!==n.slice(0,i.length)?e[i]:this.uniqueNode(t.slice(i.length),n.slice(i.length),e[i])}},pack:function(){return b(this)}};const _=function(t){this.root={},this.lastWord="",this.suffixes={},this.suffixCounts={},this.cNext=1,this.wordCount=0,this.insertWords(t),this.vCur=0};Object.keys(C).forEach(function(t){_.prototype[t]=C[t]});var w=_;const j=function(t){return"[object Array]"===Object.prototype.toString.call(t)};var x=function(t){var n;t=null==(n=t)?{}:"string"==typeof n?n.split(/ +/g).reduce(function(t,n){return t[n]=!0,t},{}):j(n)?n.reduce(function(t,n){return t[n]=!0,t},{}):n;const e=Object.keys(t).reduce(function(n,e){const o=t[e];if(j(o)){for(let t=0;t<o.length;t++)n[o[t]]=n[o[t]]||[],n[o[t]].push(e);return n}return!1===n.hasOwnProperty(o)&&Object.defineProperty(n,o,{writable:!0,enumerable:!0,configurable:!0,value:[]}),n[o].push(e),n},{});return Object.keys(e).forEach(function(t){const n=new w(e[t]);e[t]=n.pack()}),Object.keys(e).map(t=>t+"¦"+e[t]).join("|")};const A=function(t,n,e){const o=f(n);return o<t.symCount?t.syms[o]:e+o+1-t.symCount};var O=function(t){const n={nodes:t.split(";"),syms:[],symCount:0};return t.match(":")&&function(t){const n=new RegExp("([0-9A-Z]+):([0-9A-Z]+)");for(let e=0;e<t.nodes.length;e++){const o=n.exec(t.nodes[e]);if(!o){t.symCount=e;break}t.syms[f(o[1])]=f(o[2])}t.nodes=t.nodes.slice(t.symCount,t.nodes.length)}(n),function(t){const n=[],e=(o,s)=>{let i=t.nodes[o];"!"===i[0]&&(n.push(s),i=i.slice(1));const r=i.split(/([A-Z0-9,]+)/g);for(let i=0;i<r.length;i+=2){const u=r[i],c=r[i+1];if(!u)continue;const f=s+u;if(","===c||void 0===c){n.push(f);continue}const h=A(t,c,o);e(h,f)}};return e(0,""),n}(n)},k=function(t){const n=t.split("|").reduce((t,n)=>{const e=n.split("¦");return t[e[0]]=e[1],t},{}),e={};return Object.keys(n).forEach(function(t){const o=O(n[t]);"true"===t&&(t=!0);for(let n=0;n<o.length;n++){const s=o[n];!0===e.hasOwnProperty(s)?!1===Array.isArray(e[s])?e[s]=[e[s],t]:e[s].push(t):e[s]=t}}),e};return function(t,n){return t(n={exports:{}},n.exports),n.exports}(function(n){const e={pack:x,unpack:k};"undefined"!=typeof self?self.efrt=e:"undefined"!=typeof window?window.efrt=e:void 0!==t&&(t.efrt=e),n.exports=e})}); | ||
//# sourceMappingURL=efrt.min.js.map | ||
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).efrt={})}(this,(function(t){"use strict";function n(t){return(n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var e=function(t,n){for(var e=Math.min(t.length,n.length);e>0;){var r=t.slice(0,e);if(r===n.slice(0,e))return r;e-=1}return""},r=function(t){t.sort();for(var n=1;n<t.length;n++)t[n-1]===t[n]&&t.splice(n,1)},o=function(){this.counts={}},i={init:function(t){void 0===this.counts[t]&&(this.counts[t]=0)},add:function(t,n){void 0===n&&(n=1),this.init(t),this.counts[t]+=n},countOf:function(t){return this.init(t),this.counts[t]},highest:function(t){for(var n=[],e=Object.keys(this.counts),r=0;r<e.length;r++){var o=e[r];n.push([o,this.counts[o]])}return n.sort((function(t,n){return n[1]-t[1]})),t&&(n=n.slice(0,t)),n}};Object.keys(i).forEach((function(t){o.prototype[t]=i[t]}));var s=36,u="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",f=u.split("").reduce((function(t,n,e){return t[n]=e,t}),{}),h=function(t){if(void 0!==u[t])return u[t];for(var n=1,e=s,r="";t>=e;t-=e,n++,e*=s);for(;n--;){var o=t%s;r=String.fromCharCode((o<10?48:55)+o)+r,t=(t-o)/s}return r},c=function(t){if(void 0!==f[t])return f[t];for(var n=0,e=1,r=s,o=1;e<t.length;n+=r,e++,r*=s);for(var i=t.length-1;i>=0;i--,o*=s){var u=t.charCodeAt(i)-48;u>10&&(u-=7),n+=u*o}return n},a=";",l=":",d=",",v="!",p=36,g=function(t,n){var e="",r="";t.isTerminal(n)&&(e+=v);for(var o=t.nodeProps(n),i=0;i<o.length;i++){var s=o[i];if("number"!=typeof n[s])if(t.syms[n[s]._n])e+=r+s+t.syms[n[s]._n],r="";else{var u=h(n._n-n[s]._n-1+t.symCount);n[s]._g&&u.length>=n[s]._g.length&&1===n[n[s]._g]?(e+=r+s+(u=n[s]._g),r=d):(e+=r+s+u,r="")}else e+=r+s,r=d}return e},y=function t(n,e){if(!n.visited(e))for(var r=n.nodeProps(e,!0),o=0;o<r.length;o++){var i=r[o],s=e._n-e[i]._n-1;s<p&&n.histRel.add(s),n.histAbs.add(e[i]._n,h(s).length-1),t(n,e[i])}},m=function t(n,e){if(void 0===e._n){for(var r=n.nodeProps(e,!0),o=0;o<r.length;o++)t(n,e[r[o]]);e._n=n.pos++,n.nodes.unshift(e)}},b=function(t){t.nodes=[],t.nodeCount=0,t.syms={},t.symCount=0,t.pos=0,t.optimize(),t.histAbs=new o,t.histRel=new o,m(t,t.root),t.nodeCount=t.nodes.length,t.prepDFS(),y(t,t.root),t.symCount=function(t){t.histAbs=t.histAbs.highest(p);var n=[];n[-1]=0;for(var e=0,r=0,o=3+h(t.nodeCount).length,i=0;i<p&&void 0!==t.histAbs[i];i++)n[i]=t.histAbs[i][1]-o-t.histRel.countOf(p-i-1)+n[i-1],n[i]>=e&&(e=n[i],r=i+1);return r}(t);for(var n=0;n<t.symCount;n++)t.syms[t.histAbs[n][0]]=h(n);for(var e=0;e<t.nodeCount;e++)t.nodes[e]=g(t,t.nodes[e]);for(var r=t.symCount-1;r>=0;r--)t.nodes.unshift(h(r)+l+h(t.nodeCount-t.histAbs[r][0]-1));return t.nodes.join(a)},_=new RegExp("[0-9A-Z,;!:|¦]"),C={insertWords:function(t){if(void 0!==t){"string"==typeof t&&(t=t.split(/[^a-zA-Z]+/));for(var n=0;n<t.length;n++)t[n]=t[n].toLowerCase();r(t);for(var e=0;e<t.length;e++)null===t[e].match(_)&&this.insert(t[e])}},insert:function(t){this._insert(t,this.root);var n=this.lastWord;if(this.lastWord=t,e(t,n)!==n){var r=this.uniqueNode(n,t,this.root);r&&this.combineSuffixNode(r)}},_insert:function(t,r){var o,i;if(0!==t.length){for(var s=Object.keys(r),u=0;u<s.length;u++){var f=s[u];if(0!==(o=e(t,f)).length){if(f===o&&"object"===n(r[f]))return void this._insert(t.slice(o.length),r[f]);if(f===t&&"number"==typeof r[f])return;return(i={})[f.slice(o.length)]=r[f],this.addTerminal(i,t=t.slice(o.length)),delete r[f],r[o]=i,void this.wordCount++}}this.addTerminal(r,t),this.wordCount++}},addTerminal:function(t,n){if(n.length<=1)t[n]=1;else{var e={};t[n[0]]=e,this.addTerminal(e,n.slice(1))}},nodeProps:function(t,e){var r=[];for(var o in t)""!==o&&"_"!==o[0]&&(e&&"object"!==n(t[o])||r.push(o));return r.sort(),r},optimize:function(){this.combineSuffixNode(this.root),this.prepDFS(),this.countDegree(this.root),this.prepDFS(),this.collapseChains(this.root)},combineSuffixNode:function(t){if(t._c)return t;var e=[];this.isTerminal(t)&&e.push("!");for(var r=this.nodeProps(t),o=0;o<r.length;o++){var i=r[o];"object"===n(t[i])?(t[i]=this.combineSuffixNode(t[i]),e.push(i),e.push(t[i]._c)):e.push(i)}e=e.join("-");var s=this.suffixes[e];return s||(this.suffixes[e]=t,t._c=this.cNext++,t)},prepDFS:function(){this.vCur++},visited:function(t){return t._v===this.vCur||(t._v=this.vCur,!1)},countDegree:function(t){if(void 0===t._d&&(t._d=0),t._d++,!this.visited(t))for(var n=this.nodeProps(t,!0),e=0;e<n.length;e++)this.countDegree(t[n[e]])},collapseChains:function(t){var e,r,o,i;if(!this.visited(t)){for(r=this.nodeProps(t),i=0;i<r.length;i++)"object"===n(o=t[e=r[i]])&&(this.collapseChains(o),void 0===o._g||1!==o._d&&1!==o._g.length||(delete t[e],t[e+=o._g]=o[o._g]));1!==r.length||this.isTerminal(t)||(t._g=e)}},isTerminal:function(t){return!!t[""]},uniqueNode:function(t,n,e){for(var r=this.nodeProps(e,!0),o=0;o<r.length;o++){var i=r[o];if(i===t.slice(0,i.length))return i!==n.slice(0,i.length)?e[i]:this.uniqueNode(t.slice(i.length),n.slice(i.length),e[i])}},pack:function(){return b(this)}},j=function(t){this.root={},this.lastWord="",this.suffixes={},this.suffixCounts={},this.cNext=1,this.wordCount=0,this.insertWords(t),this.vCur=0};Object.keys(C).forEach((function(t){j.prototype[t]=C[t]}));var A=function(t){return"[object Array]"===Object.prototype.toString.call(t)},x=function(t,n,e){var r=c(n);return r<t.symCount?t.syms[r]:e+r+1-t.symCount},O=function(t){var n={nodes:t.split(";"),syms:[],symCount:0};return t.match(":")&&function(t){for(var n=new RegExp("([0-9A-Z]+):([0-9A-Z]+)"),e=0;e<t.nodes.length;e++){var r=n.exec(t.nodes[e]);if(!r){t.symCount=e;break}t.syms[c(r[1])]=c(r[2])}t.nodes=t.nodes.slice(t.symCount,t.nodes.length)}(n),function(t){var n=[];return function e(r,o){var i=t.nodes[r];"!"===i[0]&&(n.push(o),i=i.slice(1));for(var s=i.split(/([A-Z0-9,]+)/g),u=0;u<s.length;u+=2){var f=s[u],h=s[u+1];if(f){var c=o+f;","!==h&&void 0!==h?e(x(t,h,r),c):n.push(c)}}}(0,""),n}(n)};t.pack=function(t){var n;t=null==(n=t)?{}:"string"==typeof n?n.split(/ +/g).reduce((function(t,n){return t[n]=!0,t}),{}):A(n)?n.reduce((function(t,n){return t[n]=!0,t}),{}):n;var e=Object.keys(t).reduce((function(n,e){var r=t[e];if(A(r)){for(var o=0;o<r.length;o++)n[r[o]]=n[r[o]]||[],n[r[o]].push(e);return n}return!1===n.hasOwnProperty(r)&&Object.defineProperty(n,r,{writable:!0,enumerable:!0,configurable:!0,value:[]}),n[r].push(e),n}),{});return Object.keys(e).forEach((function(t){var n=new j(e[t]);e[t]=n.pack()})),Object.keys(e).map((function(t){return t+"¦"+e[t]})).join("|")},t.unpack=function(t){var n=t.split("|").reduce((function(t,n){var e=n.split("¦");return t[e[0]]=e[1],t}),{}),e={};return Object.keys(n).forEach((function(t){var r=O(n[t]);"true"===t&&(t=!0);for(var o=0;o<r.length;o++){var i=r[o];!0===e.hasOwnProperty(i)?!1===Array.isArray(e[i])?e[i]=[e[i],t]:e[i].push(t):e[i]=t}})),e},t.version="2.3.0",Object.defineProperty(t,"__esModule",{value:!0})})); |
@@ -1,8 +0,17 @@ | ||
## 1.0.0 | ||
### 1.1.0 | ||
* adds support for object inputs, instead of just arrays | ||
## 2.3.0 [June 2021] | ||
- support es modules exports | ||
- remove mapfile | ||
- update deps | ||
## 2.0.0 | ||
pack now returns a flat string, instead of an object. This avoids all the quoting/encoding and stuff the JSON was doing. Breaking-change. | ||
### 1.1.1 | ||
fixes reserved-word issue in firefox for 'watch' | ||
## 2.0.0 | ||
pack now returns a flat string, instead of an object. This avoids all the quoting/encoding and stuff the JSON was doing. Breaking-change. | ||
### 1.1.0 | ||
- adds support for object inputs, instead of just arrays |
{ | ||
"name": "efrt", | ||
"description": "neato compression of key-value data", | ||
"version": "2.2.2", | ||
"version": "2.3.0", | ||
"main": "./builds/efrt.js", | ||
"unpkg": "./builds/efrt.min.js", | ||
"module": "./builds/efrt.mjs", | ||
"type": "module", | ||
"sideEffects": false, | ||
"exports": { | ||
".": { | ||
"require": "./builds/efrt.js", | ||
"import": "./builds/efrt.mjs", | ||
"default": "./builds/efrt.js" | ||
}, | ||
"./unpack": { | ||
"import": "./builds/efrt-unpack.mjs", | ||
"default": "./builds/efrt-unpack.min.js" | ||
} | ||
}, | ||
"author": "Spencer Kelly <spencermountain@gmail.com> (http://spencermounta.in)", | ||
@@ -12,6 +27,5 @@ "repository": { | ||
"scripts": { | ||
"build": "rollup -c && node ./scripts/filesize.js", | ||
"filesize": "node ./scripts/filesize.js", | ||
"test": "tape \"./tests/*.test.js\" | tap-dancer", | ||
"testb": "TESTENV=prod tape \"./tests/*.test.js\" | tap-dancer", | ||
"build": "node ./scripts/version.js && rollup -c ", | ||
"test": "tape-es \"./tests/*.test.js\" | tap-dancer", | ||
"testb": "TESTENV=prod tape-es \"./tests/*.test.js\" | tap-dancer", | ||
"watch": "amble ./scratch" | ||
@@ -29,16 +43,14 @@ }, | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"@babel/core": "7.5.5", | ||
"@babel/preset-env": "7.5.5", | ||
"amble": "0.0.7", | ||
"@babel/core": "7.14.6", | ||
"@babel/preset-env": "7.14.7", | ||
"amble": "1.3.0", | ||
"rollup": "2.52.4", | ||
"rollup-plugin-babel": "^4.3.3", | ||
"rollup-plugin-commonjs": "10.0.1", | ||
"rollup-plugin-json": "^4.0.0", | ||
"rollup-plugin-node-resolve": "5.2.0", | ||
"rollup-plugin-terser": "5.1.1", | ||
"tap-dancer": "^0.2.0", | ||
"tape": "4.11.0" | ||
"rollup-plugin-terser": "7.0.2", | ||
"tap-dancer": "0.3.2", | ||
"tape": "^5.2.2", | ||
"tape-es": "^1.2.15" | ||
}, | ||
"license": "MIT" | ||
} |
@@ -23,2 +23,3 @@ <div align="center"> | ||
if your data looks like this: | ||
```js | ||
@@ -34,13 +35,19 @@ var data = { | ||
banffshire: 'Scotland' | ||
}; | ||
} | ||
``` | ||
you can compress it like this: | ||
```js | ||
var str = efrt.pack(data); | ||
import { pack } from 'efrt' | ||
var str = pack(data) | ||
//'England:b0che1;ambridge0edford0uckingham0;shire|Scotland:a0banff1;berdeen0rgyll0yr0;shire' | ||
``` | ||
then \_very!\_ quickly flip it back into: | ||
```js | ||
var obj = efrt.unpack(str); | ||
obj['bedfordshire'];//'England' | ||
import { unpack } from 'efrt' | ||
var obj = unpack(str) | ||
obj['bedfordshire'] //'England' | ||
``` | ||
@@ -50,5 +57,5 @@ | ||
**efrt** packs category-type data into a *[very compressed prefix trie](https://en.wikipedia.org/wiki/Trie)* format, so that redundancies in the data are shared, and nothing is repeated. | ||
**efrt** packs category-type data into a _[very compressed prefix trie](https://en.wikipedia.org/wiki/Trie)_ format, so that redundancies in the data are shared, and nothing is repeated. | ||
By doing this clever-stuff ahead-of-time, **efrt** lets you ship *much more* data to the client-side, without hassle or overhead. | ||
By doing this clever-stuff ahead-of-time, **efrt** lets you ship _much more_ data to the client-side, without hassle or overhead. | ||
@@ -58,6 +65,7 @@ The whole library is **8kb**, the unpack half is barely **2kb**. | ||
it is based on: | ||
* 😍 [tamper](https://nytimes.github.io/tamper/) by the [NYTimes](https://github.com/NYTimes/) | ||
* 💝 [lookups](https://github.com/mckoss/lookups) by [Mike Koss](https://github.com/mckoss), | ||
* 💓 [bits.js](http://stevehanov.ca/blog/index.php?id=120) by [Steve Hanov](https://twitter.com/smhanov) | ||
- 😍 [tamper](https://nytimes.github.io/tamper/) by the [NYTimes](https://github.com/NYTimes/) | ||
- 💝 [lookups](https://github.com/mckoss/lookups) by [Mike Koss](https://github.com/mckoss), | ||
- 💓 [bits.js](http://stevehanov.ca/blog/index.php?id=120) by [Steve Hanov](https://twitter.com/smhanov) | ||
<a href="https://monolithpl.github.io/trie-compiler/">Benchmarks!</a> | ||
@@ -73,9 +81,9 @@ | ||
* get a js object into very compact form | ||
* reduce filesize/bandwidth a bunch | ||
* ensure the unpacking time is negligible | ||
* keep word-lookups on critical-path | ||
- get a js object into very compact form | ||
- reduce filesize/bandwidth a bunch | ||
- ensure the unpacking time is negligible | ||
- keep word-lookups on critical-path | ||
```js | ||
var efrt = require('efrt') | ||
import { pack, unpack } from 'efrt' // const {pack, unpack} = require('efrt') | ||
@@ -89,7 +97,7 @@ var foods = { | ||
pepper: 'vegetable' | ||
}; | ||
var str = efrt.pack(foods); | ||
} | ||
var str = pack(foods) | ||
//'{"fruit":"bl0straw1tomato;ack0ue0;berry","vegetable":"cucumb0pepp0tomato;er"}' | ||
var obj=efrt.unpack(str) | ||
var obj = unpack(str) | ||
console.log(obj.tomato) | ||
@@ -120,5 +128,5 @@ //['fruit', 'vegetable'] | ||
] | ||
const packd = efrt.pack(data) | ||
const packd = pack(data) | ||
// true¦a6dec4febr3j1ma0nov4octo5sept4;rch,y;an1u0;ly,ne;uary;em0;ber;pril,ugust | ||
const sameArray = Object.keys(efrt.unpack(packd)) | ||
const sameArray = Object.keys(unpack(packd)) | ||
// same thing ! | ||
@@ -128,3 +136,5 @@ ``` | ||
## Reserved characters | ||
the keys of the object are normalized. Spaces/unicode are good, but numbers, case-sensitivity, and *some punctuation* (semicolon, comma, exclamation-mark) are not (yet) supported. | ||
the keys of the object are normalized. Spaces/unicode are good, but numbers, case-sensitivity, and _some punctuation_ (semicolon, comma, exclamation-mark) are not (yet) supported. | ||
```js | ||
@@ -134,10 +144,12 @@ specialChars = new RegExp('[0-9A-Z,;!:|¦]') | ||
*efrt* is built-for, and used heavily in [compromise](https://github.com/nlp-compromise/compromise), to expand the amount of data it can ship onto the client-side. | ||
_efrt_ is built-for, and used heavily in [compromise](https://github.com/nlp-compromise/compromise), to expand the amount of data it can ship onto the client-side. | ||
If you find another use for efrt, please [drop us a line](mailto:spencermountain@gmail.com)🎈 | ||
## Performance | ||
*efrt* is tuned to be very quick to unzip. It is O(1) to lookup. Packing-up the data is the slowest part, which is usually fine: | ||
_efrt_ is tuned to be very quick to unzip. It is O(1) to lookup. Packing-up the data is the slowest part, which is usually fine: | ||
```js | ||
var compressed = efrt.pack(skateboarders);//1k words (on a macbook) | ||
var trie = efrt.unpack(compressed) | ||
var compressed = pack(skateboarders) //1k words (on a macbook) | ||
var trie = unpack(compressed) | ||
// unpacking-step: 5.1ms | ||
@@ -150,22 +162,27 @@ | ||
## Size | ||
`efrt` will pack filesize down as much as possible, depending upon the redundancy of the prefixes/suffixes in the words, and the size of the list. | ||
* list of countries - `1.5k -> 0.8k` *(46% compressed)* | ||
* all adverbs in wordnet - `58k -> 24k` *(58% compressed)* | ||
* all adjectives in wordnet - `265k -> 99k` *(62% compressed)* | ||
* all nouns in wordnet - `1,775k -> 692k` *(61% compressed)* | ||
- list of countries - `1.5k -> 0.8k` _(46% compressed)_ | ||
- all adverbs in wordnet - `58k -> 24k` _(58% compressed)_ | ||
- all adjectives in wordnet - `265k -> 99k` _(62% compressed)_ | ||
- all nouns in wordnet - `1,775k -> 692k` _(61% compressed)_ | ||
but there are some things to consider: | ||
* bigger files compress further (see [🎈 birthday problem](https://en.wikipedia.org/wiki/Birthday_problem)) | ||
* using efrt will reduce gains from gzip compression, which most webservers quietly use | ||
* english is more suffix-redundant than prefix-redundant, so non-english words may benefit from other styles | ||
- bigger files compress further (see [🎈 birthday problem](https://en.wikipedia.org/wiki/Birthday_problem)) | ||
- using efrt will reduce gains from gzip compression, which most webservers quietly use | ||
- english is more suffix-redundant than prefix-redundant, so non-english words may benefit from other styles | ||
Assuming your data has a low _category-to-data ratio_, you will hit-breakeven with at about 250 keys. If your data is in the thousands, you can very be confident about saving your users some considerable bandwidth. | ||
## Use | ||
**IE9+** | ||
```html | ||
<script src="https://unpkg.com/efrt@latest/builds/efrt.min.js"></script> | ||
<script> | ||
var smaller=efrt.pack(['larry','curly','moe']) | ||
var trie=efrt.unpack(smaller) | ||
var smaller = efrt.pack(['larry', 'curly', 'moe']) | ||
var trie = efrt.unpack(smaller) | ||
console.log(trie['moe']) | ||
@@ -175,11 +192,13 @@ </script> | ||
if you're doing the second step in the client, you can load just the unpack-half of the library(~3k): | ||
if you're doing the second step in the client, you can load just the CJS unpack-half of the library(~3k): | ||
```bash | ||
npm install efrt-unpack | ||
``` | ||
```html | ||
<script src="https://unpkg.com/efrt@latest/builds/efrt-unpack.min.js"></script> | ||
<script> | ||
var trie=unpack(compressedStuff); | ||
trie.hasOwnProperty('miles davis'); | ||
var trie = unpack(compressedStuff) | ||
trie.hasOwnProperty('miles davis') | ||
</script> | ||
@@ -186,0 +205,0 @@ ``` |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
9
199
Yes
45327
730