UNPKG

cs-element

Version:

Advanced reactive data management library with state machines, blueprints, persistence, compression, networking, and multithreading support

1,760 lines (1,473 loc) 985 kB
'use strict'; var require$$0 = require('url'); var require$$0$1 = require('util'); var fs = require('fs-extra'); var path = require('path'); var cron = require('node-cron'); var archiver = require('archiver'); var extract = require('extract-zip'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs); var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path); var cron__namespace = /*#__PURE__*/_interopNamespaceDefault(cron); function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var eventemitter3 = {exports: {}}; (function (module) { var has = Object.prototype.hasOwnProperty , prefix = '~'; /** * Constructor to create a storage for our `EE` objects. * An `Events` instance is a plain object whose properties are event names. * * @constructor * @private */ function Events() {} // // We try to not inherit from `Object.prototype`. In some engines creating an // instance in this way is faster than calling `Object.create(null)` directly. // If `Object.create(null)` is not supported we prefix the event names with a // character to make sure that the built-in object properties are not // overridden or used as an attack vector. // if (Object.create) { Events.prototype = Object.create(null); // // This hack is needed because the `__proto__` property is still inherited in // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5. // if (!new Events().__proto__) prefix = false; } /** * Representation of a single event listener. * * @param {Function} fn The listener function. * @param {*} context The context to invoke the listener with. * @param {Boolean} [once=false] Specify if the listener is a one-time listener. * @constructor * @private */ function EE(fn, context, once) { this.fn = fn; this.context = context; this.once = once || false; } /** * Add a listener for a given event. * * @param {EventEmitter} emitter Reference to the `EventEmitter` instance. * @param {(String|Symbol)} event The event name. * @param {Function} fn The listener function. * @param {*} context The context to invoke the listener with. * @param {Boolean} once Specify if the listener is a one-time listener. * @returns {EventEmitter} * @private */ function addListener(emitter, event, fn, context, once) { if (typeof fn !== 'function') { throw new TypeError('The listener must be a function'); } var listener = new EE(fn, context || emitter, once) , evt = prefix ? prefix + event : event; if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++; else if (!emitter._events[evt].fn) emitter._events[evt].push(listener); else emitter._events[evt] = [emitter._events[evt], listener]; return emitter; } /** * Clear event by name. * * @param {EventEmitter} emitter Reference to the `EventEmitter` instance. * @param {(String|Symbol)} evt The Event name. * @private */ function clearEvent(emitter, evt) { if (--emitter._eventsCount === 0) emitter._events = new Events(); else delete emitter._events[evt]; } /** * Minimal `EventEmitter` interface that is molded against the Node.js * `EventEmitter` interface. * * @constructor * @public */ function EventEmitter() { this._events = new Events(); this._eventsCount = 0; } /** * Return an array listing the events for which the emitter has registered * listeners. * * @returns {Array} * @public */ EventEmitter.prototype.eventNames = function eventNames() { var names = [] , events , name; if (this._eventsCount === 0) return names; for (name in (events = this._events)) { if (has.call(events, name)) names.push(prefix ? name.slice(1) : name); } if (Object.getOwnPropertySymbols) { return names.concat(Object.getOwnPropertySymbols(events)); } return names; }; /** * Return the listeners registered for a given event. * * @param {(String|Symbol)} event The event name. * @returns {Array} The registered listeners. * @public */ EventEmitter.prototype.listeners = function listeners(event) { var evt = prefix ? prefix + event : event , handlers = this._events[evt]; if (!handlers) return []; if (handlers.fn) return [handlers.fn]; for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) { ee[i] = handlers[i].fn; } return ee; }; /** * Return the number of listeners listening to a given event. * * @param {(String|Symbol)} event The event name. * @returns {Number} The number of listeners. * @public */ EventEmitter.prototype.listenerCount = function listenerCount(event) { var evt = prefix ? prefix + event : event , listeners = this._events[evt]; if (!listeners) return 0; if (listeners.fn) return 1; return listeners.length; }; /** * Calls each of the listeners registered for a given event. * * @param {(String|Symbol)} event The event name. * @returns {Boolean} `true` if the event had listeners, else `false`. * @public */ EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) { var evt = prefix ? prefix + event : event; if (!this._events[evt]) return false; var listeners = this._events[evt] , len = arguments.length , args , i; if (listeners.fn) { if (listeners.once) this.removeListener(event, listeners.fn, undefined, true); switch (len) { case 1: return listeners.fn.call(listeners.context), true; case 2: return listeners.fn.call(listeners.context, a1), true; case 3: return listeners.fn.call(listeners.context, a1, a2), true; case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true; case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true; case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true; } for (i = 1, args = new Array(len -1); i < len; i++) { args[i - 1] = arguments[i]; } listeners.fn.apply(listeners.context, args); } else { var length = listeners.length , j; for (i = 0; i < length; i++) { if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true); switch (len) { case 1: listeners[i].fn.call(listeners[i].context); break; case 2: listeners[i].fn.call(listeners[i].context, a1); break; case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break; case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break; default: if (!args) for (j = 1, args = new Array(len -1); j < len; j++) { args[j - 1] = arguments[j]; } listeners[i].fn.apply(listeners[i].context, args); } } } return true; }; /** * Add a listener for a given event. * * @param {(String|Symbol)} event The event name. * @param {Function} fn The listener function. * @param {*} [context=this] The context to invoke the listener with. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.on = function on(event, fn, context) { return addListener(this, event, fn, context, false); }; /** * Add a one-time listener for a given event. * * @param {(String|Symbol)} event The event name. * @param {Function} fn The listener function. * @param {*} [context=this] The context to invoke the listener with. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.once = function once(event, fn, context) { return addListener(this, event, fn, context, true); }; /** * Remove the listeners of a given event. * * @param {(String|Symbol)} event The event name. * @param {Function} fn Only remove the listeners that match this function. * @param {*} context Only remove the listeners that have this context. * @param {Boolean} once Only remove one-time listeners. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) { var evt = prefix ? prefix + event : event; if (!this._events[evt]) return this; if (!fn) { clearEvent(this, evt); return this; } var listeners = this._events[evt]; if (listeners.fn) { if ( listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context) ) { clearEvent(this, evt); } } else { for (var i = 0, events = [], length = listeners.length; i < length; i++) { if ( listeners[i].fn !== fn || (once && !listeners[i].once) || (context && listeners[i].context !== context) ) { events.push(listeners[i]); } } // // Reset the array, or remove it completely if we have no more listeners. // if (events.length) this._events[evt] = events.length === 1 ? events[0] : events; else clearEvent(this, evt); } return this; }; /** * Remove all listeners, or those of the specified event. * * @param {(String|Symbol)} [event] The event name. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) { var evt; if (event) { evt = prefix ? prefix + event : event; if (this._events[evt]) clearEvent(this, evt); } else { this._events = new Events(); this._eventsCount = 0; } return this; }; // // Alias methods names because people roll like that. // EventEmitter.prototype.off = EventEmitter.prototype.removeListener; EventEmitter.prototype.addListener = EventEmitter.prototype.on; // // Expose the prefix. // EventEmitter.prefixed = prefix; // // Allow `EventEmitter` to be imported as module namespace. // EventEmitter.EventEmitter = EventEmitter; // // Expose the module. // { module.exports = EventEmitter; } } (eventemitter3)); var eventemitter3Exports = eventemitter3.exports; var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports); /** * Основные типы и интерфейсы для библиотеки CSElement */ /** * Типы событий элемента */ var ElementEventType; (function (ElementEventType) { ElementEventType["ElementAdded"] = "element:added"; ElementEventType["ElementRemoved"] = "element:removed"; ElementEventType["DataChanged"] = "data:changed"; ElementEventType["OwnerChanged"] = "owner:changed"; ElementEventType["Locked"] = "locked"; ElementEventType["Unlocked"] = "unlocked"; })(ElementEventType || (ElementEventType = {})); /** * Генерация уникального идентификатора */ function generateId() { return `cs_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } var jspath$1 = {exports: {}}; (function (module) { /** * JSPath * * Copyright (c) 2012 Filatov Dmitry (dfilatov@yandex-team.ru) * With parts by Marat Dulin (mdevils@gmail.com) * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * * @version 0.4.0 */ (function() { var SYNTAX = { PATH : 1, SELECTOR : 2, OBJ_PRED : 3, POS_PRED : 4, LOGICAL_EXPR : 5, COMPARISON_EXPR : 6, MATH_EXPR : 7, CONCAT_EXPR : 8, UNARY_EXPR : 9, POS_EXPR : 10, LITERAL : 11 }; // parser var parse = (function() { var TOKEN = { ID : 1, NUM : 2, STR : 3, BOOL : 4, NULL : 5, PUNCT : 6, EOP : 7 }, MESSAGES = { UNEXP_TOKEN : 'Unexpected token "%0"', UNEXP_EOP : 'Unexpected end of path' }; var path, idx, buf, len; function parse(_path) { path = _path.split(''); idx = 0; buf = null; len = path.length; var res = parsePathConcatExpr(), token = lex(); if(token.type !== TOKEN.EOP) { throwUnexpected(token); } return res; } function parsePathConcatExpr() { var expr = parsePathConcatPartExpr(), operands; while(match('|')) { lex(); (operands || (operands = [expr])).push(parsePathConcatPartExpr()); } return operands? { type : SYNTAX.CONCAT_EXPR, args : operands } : expr; } function parsePathConcatPartExpr() { return match('(')? parsePathGroupExpr() : parsePath(); } function parsePathGroupExpr() { expect('('); var expr = parsePathConcatExpr(); expect(')'); var parts = [], part; while((part = parsePredicate())) { parts.push(part); } if(!parts.length) { return expr; } else if(expr.type === SYNTAX.PATH) { expr.parts = expr.parts.concat(parts); return expr; } parts.unshift(expr); return { type : SYNTAX.PATH, parts : parts }; } function parsePredicate() { if(match('[')) { return parsePosPredicate(); } if(match('{')) { return parseObjectPredicate(); } if(match('(')) { return parsePathGroupExpr(); } } function parsePath() { if(!matchPath()) { throwUnexpected(lex()); } var fromRoot = false, subst; if(match('^')) { lex(); fromRoot = true; } else if(matchSubst()) { subst = lex().val.substr(1); } var parts = [], part; while((part = parsePathPart())) { parts.push(part); } return { type : SYNTAX.PATH, fromRoot : fromRoot, subst : subst, parts : parts }; } function parsePathPart() { return matchSelector()? parseSelector() : parsePredicate(); } function parseSelector() { var selector = lex().val, token = lookahead(), prop; if(match('*') || token.type === TOKEN.ID || token.type === TOKEN.STR) { prop = lex().val; } return { type : SYNTAX.SELECTOR, selector : selector, prop : prop }; } function parsePosPredicate() { expect('['); var expr = parsePosExpr(); expect(']'); return { type : SYNTAX.POS_PRED, arg : expr }; } function parseObjectPredicate() { expect('{'); var expr = parseLogicalORExpr(); expect('}'); return { type : SYNTAX.OBJ_PRED, arg : expr }; } function parseLogicalORExpr() { var expr = parseLogicalANDExpr(), operands; while(match('||')) { lex(); (operands || (operands = [expr])).push(parseLogicalANDExpr()); } return operands? { type : SYNTAX.LOGICAL_EXPR, op : '||', args : operands } : expr; } function parseLogicalANDExpr() { var expr = parseEqualityExpr(), operands; while(match('&&')) { lex(); (operands || (operands = [expr])).push(parseEqualityExpr()); } return operands? { type : SYNTAX.LOGICAL_EXPR, op : '&&', args : operands } : expr; } function parseEqualityExpr() { var expr = parseRelationalExpr(); while( match('==') || match('!=') || match('===') || match('!==') || match('^==') || match('==^') ||match('^=') || match('=^') || match('$==') || match('==$') || match('$=') || match('=$') || match('*==') || match('==*')|| match('*=') || match('=*') ) { expr = { type : SYNTAX.COMPARISON_EXPR, op : lex().val, args : [expr, parseEqualityExpr()] }; } return expr; } function parseRelationalExpr() { var expr = parseAdditiveExpr(); while(match('<') || match('>') || match('<=') || match('>=')) { expr = { type : SYNTAX.COMPARISON_EXPR, op : lex().val, args : [expr, parseRelationalExpr()] }; } return expr; } function parseAdditiveExpr() { var expr = parseMultiplicativeExpr(); while(match('+') || match('-')) { expr = { type : SYNTAX.MATH_EXPR, op : lex().val, args : [expr, parseMultiplicativeExpr()] }; } return expr; } function parseMultiplicativeExpr() { var expr = parseUnaryExpr(); while(match('*') || match('/') || match('%')) { expr = { type : SYNTAX.MATH_EXPR, op : lex().val, args : [expr, parseMultiplicativeExpr()] }; } return expr; } function parsePosExpr() { if(match(':')) { lex(); return { type : SYNTAX.POS_EXPR, toIdx : parseUnaryExpr() }; } var fromExpr = parseUnaryExpr(); if(match(':')) { lex(); if(match(']')) { return { type : SYNTAX.POS_EXPR, fromIdx : fromExpr }; } return { type : SYNTAX.POS_EXPR, fromIdx : fromExpr, toIdx : parseUnaryExpr() }; } return { type : SYNTAX.POS_EXPR, idx : fromExpr }; } function parseUnaryExpr() { if(match('!') || match('-')) { return { type : SYNTAX.UNARY_EXPR, op : lex().val, arg : parseUnaryExpr() }; } return parsePrimaryExpr(); } function parsePrimaryExpr() { var token = lookahead(), type = token.type; if(type === TOKEN.STR || type === TOKEN.NUM || type === TOKEN.BOOL || type === TOKEN.NULL) { return { type : SYNTAX.LITERAL, val : lex().val }; } if(matchPath()) { return parsePath(); } if(match('(')) { return parseGroupExpr(); } return throwUnexpected(lex()); } function parseGroupExpr() { expect('('); var expr = parseLogicalORExpr(); expect(')'); return expr; } function match(val) { var token = lookahead(); return token.type === TOKEN.PUNCT && token.val === val; } function matchPath() { return matchSelector() || matchSubst() || match('^'); } function matchSelector() { var token = lookahead(); if(token.type === TOKEN.PUNCT) { var val = token.val; return val === '.' || val === '..'; } return false; } function matchSubst() { var token = lookahead(); return token.type === TOKEN.ID && token.val[0] === '$'; } function expect(val) { var token = lex(); if(token.type !== TOKEN.PUNCT || token.val !== val) { throwUnexpected(token); } } function lookahead() { if(buf !== null) { return buf; } var pos = idx; buf = advance(); idx = pos; return buf; } function advance() { while(isWhiteSpace(path[idx])) { ++idx; } if(idx >= len) { return { type : TOKEN.EOP, range : [idx, idx] }; } var token = scanPunctuator(); if(token || (token = scanId()) || (token = scanString()) || (token = scanNumeric())) { return token; } token = { range : [idx, idx] }; idx >= len? token.type = TOKEN.EOP : token.val = path[idx]; throwUnexpected(token); } function lex() { var token; if(buf) { idx = buf.range[1]; token = buf; buf = null; return token; } return advance(); } function isDigit(ch) { return '0123456789'.indexOf(ch) >= 0; } function isWhiteSpace(ch) { return ' \r\n\t'.indexOf(ch) > -1; } function isIdStart(ch) { return ch === '$' || ch === '@' || ch === '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); } function isIdPart(ch) { return isIdStart(ch) || (ch >= '0' && ch <= '9'); } function scanId() { var ch = path[idx]; if(!isIdStart(ch)) { return; } var start = idx, id = ch; while(++idx < len) { ch = path[idx]; if(!isIdPart(ch)) { break; } id += ch; } switch(id) { case 'true': case 'false': return { type : TOKEN.BOOL, val : id === 'true', range : [start, idx] }; case 'null': return { type : TOKEN.NULL, val : null, range : [start, idx] }; default: return { type : TOKEN.ID, val : id, range : [start, idx] }; } } function scanString() { if(path[idx] !== '"' && path[idx] !== '\'') { return; } var orig = path[idx], start = ++idx, str = '', eosFound = false, ch; while(idx < len) { ch = path[idx++]; if(ch === '\\') { ch = path[idx++]; } else if((ch === '"' || ch === '\'') && ch === orig) { eosFound = true; break; } str += ch; } if(eosFound) { return { type : TOKEN.STR, val : str, range : [start, idx] }; } } function scanNumeric() { var start = idx, ch = path[idx], isFloat = ch === '.'; if(isFloat || isDigit(ch)) { var num = ch; while(++idx < len) { ch = path[idx]; if(ch === '.') { if(isFloat) { return; } isFloat = true; } else if(!isDigit(ch)) { break; } num += ch; } return { type : TOKEN.NUM, val : isFloat? parseFloat(num) : parseInt(num, 10), range : [start, idx] }; } } function scanPunctuator() { var start = idx, ch1 = path[idx], ch2 = path[idx + 1]; if(ch1 === '.') { if(isDigit(ch2)) { return; } return path[++idx] === '.'? { type : TOKEN.PUNCT, val : '..', range : [start, ++idx] } : { type : TOKEN.PUNCT, val : '.', range : [start, idx] }; } if(ch2 === '=') { var ch3 = path[idx + 2]; if(ch3 === '=') { if('=!^$*'.indexOf(ch1) >= 0) { return { type : TOKEN.PUNCT, val : ch1 + ch2 + ch3, range : [start, idx += 3] }; } } else if('^$*'.indexOf(ch3) >= 0) { if(ch1 === '=') { return { type : TOKEN.PUNCT, val : ch1 + ch2 + ch3, range : [start, idx += 3] }; } } else if('=!^$*><'.indexOf(ch1) >= 0) { return { type : TOKEN.PUNCT, val : ch1 + ch2, range : [start, idx += 2] }; } } else if(ch1 === '=' && '^$*'.indexOf(ch2) >= 0) { return { type : TOKEN.PUNCT, val : ch1 + ch2, range : [start, idx += 2] }; } if(ch1 === ch2 && (ch1 === '|' || ch1 === '&')) { return { type : TOKEN.PUNCT, val : ch1 + ch2, range : [start, idx += 2] }; } if(':{}()[]^+-*/%!><|'.indexOf(ch1) >= 0) { return { type : TOKEN.PUNCT, val : ch1, range : [start, ++idx] }; } } function throwUnexpected(token) { if(token.type === TOKEN.EOP) { throwError(token, MESSAGES.UNEXP_EOP); } throwError(token, MESSAGES.UNEXP_TOKEN, token.val); } function throwError(token, messageFormat) { var args = Array.prototype.slice.call(arguments, 2), msg = messageFormat.replace( /%(\d)/g, function(_, idx) { return args[idx] || ''; }), error = new Error(msg); error.column = token.range[0]; throw error; } return parse; })(); // translator var translate = (function() { var body, vars, lastVarId, unusedVars; function acquireVar() { if(unusedVars.length) { return unusedVars.shift(); } var varName = 'v' + ++lastVarId; vars.push(varName); return varName; } function releaseVars() { var args = arguments, i = args.length; while(i--) { unusedVars.push(args[i]); } } function translate(ast) { body = []; vars = ['res']; lastVarId = 0; unusedVars = []; translateExpr(ast, 'res', 'data'); body.unshift( 'var ', Array.isArray? 'isArr = Array.isArray' : 'toStr = Object.prototype.toString, isArr = function(o) { return toStr.call(o) === "[object Array]"; }', ', concat = Array.prototype.concat', ',', vars.join(','), ';'); if(ast.type === SYNTAX.PATH) { var lastPart = ast.parts[ast.parts.length - 1]; if(lastPart && lastPart.type === SYNTAX.POS_PRED && 'idx' in lastPart.arg) { body.push('res = res[0];'); } } body.push('return res;'); return body.join(''); } function translatePath(path, dest, ctx) { var parts = path.parts, i = 0, len = parts.length; body.push( dest, '=', path.fromRoot? 'data' : path.subst? 'subst.' + path.subst : ctx, ';', 'isArr(' + dest + ') || (' + dest + ' = [' + dest + ']);'); while(i < len) { var item = parts[i++]; switch(item.type) { case SYNTAX.SELECTOR: item.selector === '..'? translateDescendantSelector(item, dest, dest) : translateSelector(item, dest, dest); break; case SYNTAX.OBJ_PRED: translateObjectPredicate(item, dest, dest); break; case SYNTAX.POS_PRED: translatePosPredicate(item, dest, dest); break; case SYNTAX.CONCAT_EXPR: translateConcatExpr(item, dest, dest); break; } } } function translateSelector(sel, dest, ctx) { if(sel.prop) { var propStr = escapeStr(sel.prop), res = acquireVar(), i = acquireVar(), len = acquireVar(), curCtx = acquireVar(), j = acquireVar(), val = acquireVar(), tmpArr = acquireVar(); body.push( res, '= [];', i, '= 0;', len, '=', ctx, '.length;', tmpArr, '= [];', 'while(', i, '<', len, ') {', curCtx, '=', ctx, '[', i, '++];', 'if(', curCtx, '!= null) {'); if(sel.prop === '*') { body.push( 'if(typeof ', curCtx, '=== "object") {', 'if(isArr(', curCtx, ')) {', res, '=', res, '.concat(', curCtx, ');', '}', 'else {', 'for(', j, ' in ', curCtx, ') {', 'if(', curCtx, '.hasOwnProperty(', j, ')) {', val, '=', curCtx, '[', j, '];'); inlineAppendToArray(res, val); body.push( '}', '}', '}', '}'); } else { body.push( val, '=', curCtx, '[', propStr, '];'); inlineAppendToArray(res, val, tmpArr, len); } body.push( '}', '}', dest, '=', len, '> 1 &&', tmpArr, '.length?', tmpArr, '.length > 1?', 'concat.apply(', res, ',', tmpArr, ') :', res, '.concat(', tmpArr, '[0]) :', res, ';'); releaseVars(res, i, len, curCtx, j, val, tmpArr); } } function translateDescendantSelector(sel, dest, baseCtx) { var prop = sel.prop, ctx = acquireVar(), curCtx = acquireVar(), childCtxs = acquireVar(), i = acquireVar(), j = acquireVar(), val = acquireVar(), len = acquireVar(), res = acquireVar(); body.push( ctx, '=', baseCtx, '.slice(),', res, '= [];', 'while(', ctx, '.length) {', curCtx, '=', ctx, '.shift();'); prop? body.push( 'if(typeof ', curCtx, '=== "object" &&', curCtx, ') {') : body.push( 'if(typeof ', curCtx, '!= null) {'); body.push( childCtxs, '= [];', 'if(isArr(', curCtx, ')) {', i, '= 0,', len, '=', curCtx, '.length;', 'while(', i, '<', len, ') {', val, '=', curCtx, '[', i, '++];'); prop && body.push( 'if(typeof ', val, '=== "object") {'); inlineAppendToArray(childCtxs, val); prop && body.push( '}'); body.push( '}', '}', 'else {'); if(prop) { if(prop !== '*') { body.push( val, '=', curCtx, '["' + prop + '"];'); inlineAppendToArray(res, val); } } else { inlineAppendToArray(res, curCtx); body.push( 'if(typeof ', curCtx, '=== "object") {'); } body.push( 'for(', j, ' in ', curCtx, ') {', 'if(', curCtx, '.hasOwnProperty(', j, ')) {', val, '=', curCtx, '[', j, '];'); inlineAppendToArray(childCtxs, val); prop === '*' && inlineAppendToArray(res, val); body.push( '}', '}'); prop || body.push( '}'); body.push( '}', childCtxs, '.length &&', ctx, '.unshift.apply(', ctx, ',', childCtxs, ');', '}', '}', dest, '=', res, ';'); releaseVars(ctx, curCtx, childCtxs, i, j, val, len, res); } function translateObjectPredicate(expr, dest, ctx) { var resVar = acquireVar(), i = acquireVar(), len = acquireVar(), cond = acquireVar(), curItem = acquireVar(); body.push( resVar, '= [];', i, '= 0;', len, '=', ctx, '.length;', 'while(', i, '<', len, ') {', curItem, '=', ctx, '[', i, '++];'); translateExpr(expr.arg, cond, curItem); body.push( convertToBool(expr.arg, cond), '&&', resVar, '.push(', curItem, ');', '}', dest, '=', resVar, ';'); releaseVars(resVar, i, len, curItem, cond); } function translatePosPredicate(item, dest, ctx) { var arrayExpr = item.arg, fromIdx, toIdx; if(arrayExpr.idx) { var idx = acquireVar(); translateExpr(arrayExpr.idx, idx, ctx); body.push( idx, '< 0 && (', idx, '=', ctx, '.length +', idx, ');', dest, '=', ctx, '[', idx, '] == null? [] : [', ctx, '[', idx, ']];'); releaseVars(idx); return false; } else if(arrayExpr.fromIdx) { if(arrayExpr.toIdx) { translateExpr(arrayExpr.fromIdx, fromIdx = acquireVar(), ctx); translateExpr(arrayExpr.toIdx, toIdx = acquireVar(), ctx); body.push(dest, '=', ctx, '.slice(', fromIdx, ',', toIdx, ');'); releaseVars(fromIdx, toIdx); } else { translateExpr(arrayExpr.fromIdx, fromIdx = acquireVar(), ctx); body.push(dest, '=', ctx, '.slice(', fromIdx, ');'); releaseVars(fromIdx); } } else { translateExpr(arrayExpr.toIdx, toIdx = acquireVar(), ctx); body.push(dest, '=', ctx, '.slice(0,', toIdx, ');'); releaseVars(toIdx); } } function translateExpr(expr, dest, ctx) { switch(expr.type) { case SYNTAX.PATH: translatePath(expr, dest, ctx); break; case SYNTAX.CONCAT_EXPR: translateConcatExpr(expr, dest, ctx); break; case SYNTAX.COMPARISON_EXPR: translateComparisonExpr(expr, dest, ctx); break; case SYNTAX.MATH_EXPR: translateMathExpr(expr, dest, ctx); break; case SYNTAX.LOGICAL_EXPR: translateLogicalExpr(expr, dest, ctx); break; case SYNTAX.UNARY_EXPR: translateUnaryExpr(expr, dest, ctx); break; case SYNTAX.LITERAL: body.push(dest, '='); translateLiteral(expr.val); body.push(';'); break; } } function translateLiteral(val) { body.push(typeof val === 'string'? escapeStr(val) : val === null? 'null' : val); } function translateComparisonExpr(expr, dest, ctx) { var val1 = acquireVar(), val2 = acquireVar(), isVal1Array = acquireVar(), isVal2Array = acquireVar(), i = acquireVar(), j = acquireVar(), len1 = acquireVar(), len2 = acquireVar(), leftArg = expr.args[0], rightArg = expr.args[1]; body.push(dest, '= false;'); translateExpr(leftArg, val1, ctx); translateExpr(rightArg, val2, ctx); var isLeftArgPath = leftArg.type === SYNTAX.PATH, isRightArgLiteral = rightArg.type === SYNTAX.LITERAL; body.push(isVal1Array, '='); isLeftArgPath? body.push('true;') : body.push('isArr(', val1, ');'); body.push(isVal2Array, '='); isRightArgLiteral? body.push('false;') : body.push('isArr(', val2, ');'); body.push( 'if('); isLeftArgPath || body.push(isVal1Array, '&&'); body.push(val1, '.length === 1) {', val1, '=', val1, '[0];', isVal1Array, '= false;', '}'); isRightArgLiteral || body.push( 'if(', isVal2Array, '&&', val2, '.length === 1) {', val2, '=', val2, '[0];', isVal2Array, '= false;', '}'); body.push(i, '= 0;', 'if(', isVal1Array, ') {', len1, '=', val1, '.length;'); if(!isRightArgLiteral) { body.push( 'if(', isVal2Array, ') {', len2, '=', val2, '.length;', 'while(', i, '<', len1, '&& !', dest, ') {', j, '= 0;', 'while(', j, '<', len2, ') {'); writeCondition(expr.op, [val1, '[', i, ']'].join(''), [val2, '[', j, ']'].join('')); body.push( dest, '= true;', 'break;', '}', '++', j, ';', '}', '++', i, ';', '}', '}', 'else {'); } body.push( 'while(', i, '<', len1, ') {'); writeCondition(expr.op, [val1, '[', i, ']'].join(''), val2); body.push( dest, '= true;', 'break;', '}', '++', i, ';', '}'); isRightArgLiteral || body.push( '}'); body.push( '}'); if(!isRightArgLiteral) { body.push( 'else if(', isVal2Array,') {', len2, '=', val2, '.length;', 'while(', i, '<', len2, ') {'); writeCondition(expr.op, val1, [val2, '[', i, ']'].join('')); body.push( dest, '= true;', 'break;', '}', '++', i, ';', '}', '}'); } body.push( 'else {', dest, '=', binaryOperators[expr.op](val1, val2), ';', '}'); releaseVars(val1, val2, isVal1Array, isVal2Array, i, j, len1, len2); } function writeCondition(op, val1Expr, val2Expr) { body.push('if(', binaryOperators[op](val1Expr, val2Expr), ') {'); } function translateLogicalExpr(expr, dest, ctx) { var conditionVars = [], args = expr.args, len = args.length, i = 0, val; body.push(dest, '= false;'); switch(expr.op) { case '&&': while(i < len) { conditionVars.push(val = acquireVar()); translateExpr(args[i], val, ctx); body.push('if(', convertToBool(args[i++], val), ') {'); } body.push(dest, '= true;'); break; case '||': while(i < len) { conditionVars.push(val = acquireVar()); translateExpr(args[i], val, ctx); body.push( 'if(', convertToBool(args[i], val), ') {', dest, '= true;', '}'); if(i++ + 1 < len) { body.push('else {'); } } --len; break; } while(len--) { body.push('}'); } releaseVars.apply(null, conditionVars); } function translateMathExpr(expr, dest, ctx) { var val1 = acquireVar(), val2 = acquireVar(), args = expr.args; translateExpr(args[0], val1, ctx); translateExpr(args[1], val2, ctx); body.push( dest, '=', binaryOperators[expr.op]( convertToSingleValue(args[0], val1), convertToSingleValue(args[1], val2)), ';'); releaseVars(val1, val2); } function translateUnaryExpr(expr, dest, ctx) { var val = acquireVar(), arg = expr.arg; translateExpr(arg, val, ctx); switch(expr.op) { case '!': body.push(dest, '= !', convertToBool(arg, val) + ';'); break; case '-': body.push(dest, '= -', convertToSingleValue(arg, val) + ';'); break; } releaseVars(val); } function translateConcatExpr(expr, dest, ctx) { var argVars = [], args = expr.args, len = args.length, i = 0; while(i < len) { argVars.push(acquireVar()); translateExpr(args[i], argVars[i++], ctx); } body.push(dest, '= concat.call(', argVars.join(','), ');'); releaseVars.apply(null, argVars); } function escapeStr(s) { return '\'' + s.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + '\''; } function inlineAppendToArray(res, val, tmpArr, len) { body.push( 'if(typeof ', val, '!== "undefined") {', 'if(isArr(', val, ')) {'); if(tmpArr) { body.push( len, '> 1?'); inlinePushToArray(tmpArr, val); body.push( ':'); } body.push( res, '=', res, '.length?', res, '.concat(', val, ') :', val, '.slice()', ';', '}', 'else {'); tmpArr && body.push( 'if(', tmpArr, '.length) {', res, '= concat.apply(', res, ',', tmpArr, ');', tmpArr, '= [];', '}'); inlinePushToArray(res, val); body.push(';', '}', '}'); } function inlinePushToArray(res, val) { body.push(res, '.length?', res, '.push(', val, ') :', res, '[0] =', val); } function convertToBool(arg, varName) { switch(arg.type) { case SYNTAX.LOGICAL_EXPR: return varName; case SYNTAX.LITERAL: return '!!' + varName; case SYNTAX.PATH: return varName + '.length > 0'; default: return ['(typeof ', varName, '=== "boolean"?', varName, ':', 'isArr(', varName, ')?', varName, '.length > 0 : !!', varName, ')'].join(''); } } function convertToSingleValue(arg, varName) { switch(arg.type) { case SYNTAX.LITERAL: return varName; case SYNTAX.PATH: return varName + '[0]'; default: return ['(isArr(', varName, ')?', varName, '[0] : ', varName, ')'].join(''); } } function startsWithStrict(val1, val2) { return ['typeof ', val1, '=== "string" && typeof ', val2, '=== "string" &&', val1, '.indexOf(', val2, ') === 0'].join(''); } function startsWith(val1, val2) { return [val1, '!= null &&', val2, '!= null &&', val1, '.toString().toLowerCase().indexOf(', val2, '.toString().toLowerCase()) === 0'].join(''); } function endsWithStrict(val1, val2) { return ['typeof ', val1, '=== "string" && typeof ', val2, '=== "string" &&', val1, '.length >=', val2, '.length &&', val1, '.lastIndexOf(', val2, ') ===', val1, '.length -', val2, '.length'].join(''); } function endsWith(val1, val2) { return [val1, '!= null &&', val2, '!= null &&', '(', val1, '=', val1, '.toString()).length >=', '(', val2, '=', val2, '.toString()).length &&', '(', val1, '.toLowerCase()).lastIndexOf(', '(', val2, '.toLowerCase())) ===', val1, '.length -', val2, '.length'].join(''); } function containsStrict(val1, val2) { return ['typeof ', val1, '=== "string" && typeof ', val2, '=== "string" &&', val1, '.indexOf(', val2, ') > -1'].join(''); } function contains(val1, val2) { return [val1, '!= null && ', val2, '!= null &&', val1, '.toString().toLowerCase().indexOf(', val2, '.toString().toLowerCase()) > -1'].join(''); } var binaryOperators = { '===' : function(val1, val2) { return val1 + '===' + val2; }, '==' : function(val1, val2) { return ['typeof ', val1, '=== "string" && typeof ', val2, '=== "string"?', val1, '.toLowerCase() ===', val2, '.toLowerCase() :' + val1, '==', val2].join(''); }, '>=' : function(val1, val2) { return val1 + '>=' + val2; }, '>' : function(val1, val2) { return val1 + '>' + val2; }, '<=' : function(val1, val2) { return val1 + '<=' + val2; }, '<' : function(val1, val2) { return val1 + '<' + val2; }, '!==' : function(val1, val2) { return val1 + '!==' + val2; }, '!=' : function(val1, val2) { return val1 + '!=' + val2; }, '^==' : startsWithStrict, '==^' : function(val1, val2) { return startsWithStrict(val2, val1); }, '^=' : startsWith, '=^' : function(val1, val2) { return startsWith(val2, val1); }, '$==' : endsWithStrict, '==$' : function(val1, val2) { return endsWithStrict(val2, val1); }, '$=' : endsWith, '=$' : function(val1, val2) { return endsWith(val2, val1); }, '*==' : containsStrict, '==*' : function(val1, val2) { return containsStrict(val2, val1); }, '=*' : function(val1, val2) { return contains(val2, val1); }, '*=' : contains, '+' : function(val1, val2) { return val1 + '+' + val2; }, '-' : function(val1, val2) { return val1 + '-' + val2; }, '*' : function(val1, val2) { return val1 + '*' + val2; }, '/' : function(val1, val2) { return val1 + '/' + val2; }, '%' : function(val1, val2) { return val1 + '%' + val2; } }; return translate; })(); function compile(path) { return Function('data,subst', translate(parse(path))); } var cache = {}, cacheKeys = [], params = { cacheSize : 100 }, setParamsHooks = { cacheSize : function(oldVal, newVal) { if(newVal < oldVal && cacheKeys.length > newVal) { var removedKeys = cacheKeys.splice(0, cacheKeys.l