'use strict'; function Sorter() { } Sorter.prototype.sort = function(tokens, fromIndex) { fromIndex = fromIndex || 0; for (var i = 0, len = this.keys.length; i < len; i++) { var key = this.keys[i]; var token = key.slice(1); var index = tokens.indexOf(token, fromIndex); if (index !== -1) { do { if (index !== fromIndex) { tokens.splice(index, 1); tokens.splice(fromIndex, 0, token); } fromIndex++; } while ((index = tokens.indexOf(token, fromIndex)) !== -1); return this[key].sort(tokens, fromIndex); } } return tokens; }; function TokenChain() { } TokenChain.prototype = { add: function(tokens) { var self = this; tokens.forEach(function(token) { var key = '$' + token; if (!self[key]) { self[key] = []; self[key].processed = 0; } self[key].push(tokens); }); }, createSorter: function() { var self = this; var sorter = new Sorter(); sorter.keys = Object.keys(self).sort(function(j, k) { var m = self[j].length; var n = self[k].length; return m < n ? 1 : m > n ? -1 : j < k ? -1 : j > k ? 1 : 0; }).filter(function(key) { if (self[key].processed < self[key].length) { var token = key.slice(1); var chain = new TokenChain(); self[key].forEach(function(tokens) { var index; while ((index = tokens.indexOf(token)) !== -1) { tokens.splice(index, 1); } tokens.forEach(function(token) { self['$' + token].processed++; }); chain.add(tokens.slice(0)); }); sorter[key] = chain.createSorter(); return true; } return false; }); return sorter; } }; module.exports = TokenChain;