UNPKG

json-query

Version:

Retrieves values from JSON objects for data binding. Offers params, nested queries, deep queries, custom reduce/filter functions and simple boolean logic. Browserify compatible.

190 lines (156 loc) 4.42 kB
module.exports = State function State(options, params, handleQuery){ options = options || {} //this.options = options this.handleQuery = handleQuery this.options = options this.locals = this.options.locals || {} this.globals = this.options.globals || {} this.rootContext = firstNonNull(options.data, options.rootContext, options.context, options.source) this.parent = options.parent this.override = options.override this.filters = options.filters || {} this.params = params || options.params || [] this.context = firstNonNull(options.currentItem, options.context, options.source) this.currentItem = firstNonNull(this.context, options.rootContext, options.data) this.currentKey = null this.currentReferences = [] this.currentParents = [] } State.prototype = { // current manipulation setCurrent: function(key, value){ if (this.currentItem || this.currentKey || this.currentParents.length>0){ this.currentParents.push({key: this.currentKey, value: this.currentItem}) } this.currentItem = value this.currentKey = key }, resetCurrent: function(){ this.currentItem = null this.currentKey = null this.currentParents = [] }, force: function(def){ var parent = this.currentParents[this.currentParents.length-1] if (!this.currentItem && parent && (this.currentKey != null)){ this.currentItem = def || {} parent.value[this.currentKey] = this.currentItem } return !!this.currentItem }, getLocal: function(localName){ if (~localName.indexOf('/')){ var result = null var parts = localName.split('/') for (var i=0;i<parts.length;i++){ var part = parts[i] if (i == 0){ result = this.locals[part] } else if (result && result[part]){ result = result[part] } } return result } else { return this.locals[localName] } }, getGlobal: function(globalName){ if (~globalName.indexOf('/')){ var result = null var parts = globalName.split('/') for (var i=0;i<parts.length;i++){ var part = parts[i] if (i == 0){ result = this.globals[part] } else if (result && result[part]){ result = result[part] } } return result } else { return this.globals[globalName] } }, getFilter: function(filterName){ if (~filterName.indexOf('/')){ var result = null var filterParts = filterName.split('/') for (var i=0;i<filterParts.length;i++){ var part = filterParts[i] if (i == 0){ result = this.filters[part] } else if (result && result[part]){ result = result[part] } } return result } else { return this.filters[filterName] } }, addReferences: function(references){ if (references){ references.forEach(this.addReference, this) } }, addReference: function(ref){ if (ref instanceof Object && !~this.currentReferences.indexOf(ref)){ this.currentReferences.push(ref) } }, // helper functions getValues: function(values, callback){ return values.map(this.getValue, this) }, getValue: function (value) { return this.getValueFrom(value, null) }, getValueFrom: function (value, item) { if (value._param != null){ return this.params[value._param] } else if (value._sub){ var options = copy(this.options) options.force = null options.currentItem = item var result = this.handleQuery(value._sub, options, this.params) this.addReferences(result.references) return result.value } else { return value } }, deepQuery: function(source, tokens, options, callback){ var keys = Object.keys(source) for (var key in source){ if (key in source){ var options = copy(this.options) options.currentItem = source[key] var result = this.handleQuery(tokens, options, this.params) if (result.value){ return result } } } return null } } function firstNonNull(args){ for (var i=0;i<arguments.length;i++){ if (arguments[i] != null){ return arguments[i] } } } function copy(obj){ var result = {} if (obj){ for (var key in obj){ if (key in obj){ result[key] = obj[key] } } } return result }