UNPKG

plywood

Version:
458 lines (457 loc) 16.2 kB
import { Timezone } from 'chronoshift'; import * as hasOwnProp from 'has-own-prop'; import { generalEqual } from 'immutable-class'; import { getValueType, valueFromJS, valueToJS } from './common'; import { NumberRange } from './numberRange'; import { Range } from './range'; import { StringRange } from './stringRange'; import { TimeRange } from './timeRange'; function dateString(date) { return date.toISOString(); } function stringKeyFn(value) { if (value === null) { return '__NULL_KEY_HASH_INTERNAL_USE_ONLY__'; } return String(value); } function arrayFromJS(xs, setType) { return xs.map(function (x) { return valueFromJS(x, setType); }); } var typeUpgrades = { NUMBER: 'NUMBER_RANGE', TIME: 'TIME_RANGE', STRING: 'STRING_RANGE', }; var Set = (function () { function Set(parameters) { var setType = parameters.setType; this.setType = setType; var keyFn = setType === 'TIME' ? dateString : stringKeyFn; this.keyFn = keyFn; var elements = parameters.elements; var newElements = null; var hash = Object.create(null); for (var i = 0; i < elements.length; i++) { var element = elements[i]; var key = keyFn(element); if (hasOwnProp(hash, key)) { if (!newElements) newElements = elements.slice(0, i); } else { hash[key] = element; if (newElements) newElements.push(element); } } if (newElements) { elements = newElements; } this.elements = elements; this.hash = hash; } Set.unifyElements = function (elements) { var newElements = Object.create(null); for (var _i = 0, elements_1 = elements; _i < elements_1.length; _i++) { var accumulator = elements_1[_i]; var newElementsKeys_2 = Object.keys(newElements); for (var _a = 0, newElementsKeys_1 = newElementsKeys_2; _a < newElementsKeys_1.length; _a++) { var newElementsKey = newElementsKeys_1[_a]; var newElement = newElements[newElementsKey]; var unionElement = accumulator.union(newElement); if (unionElement) { accumulator = unionElement; delete newElements[newElementsKey]; } } if (accumulator) { newElements[accumulator.toString()] = accumulator; } } var newElementsKeys = Object.keys(newElements); return newElementsKeys.length < elements.length ? newElementsKeys.map(function (k) { return newElements[k]; }) : elements; }; Set.intersectElements = function (elements1, elements2) { var newElements = []; for (var _i = 0, elements1_1 = elements1; _i < elements1_1.length; _i++) { var element1 = elements1_1[_i]; for (var _a = 0, elements2_1 = elements2; _a < elements2_1.length; _a++) { var element2 = elements2_1[_a]; var intersect = element1.intersect(element2); if (intersect) newElements.push(intersect); } } return newElements; }; Set.isSet = function (candidate) { return candidate instanceof Set; }; Set.isAtomicType = function (type) { return type && type !== 'NULL' && type.indexOf('SET/') === -1; }; Set.isSetType = function (type) { return type && type.indexOf('SET/') === 0; }; Set.wrapSetType = function (type) { if (!type) return null; return Set.isSetType(type) ? type : ('SET/' + type); }; Set.unwrapSetType = function (type) { if (!type) return null; return Set.isSetType(type) ? type.substr(4) : type; }; Set.cartesianProductOf = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return args.reduce(function (a, b) { return [].concat.apply([], a.map(function (x) { return b.map(function (y) { return x.concat([y]); }); })); }, [[]]); }; Set.crossBinary = function (as, bs, fn) { if (as instanceof Set || bs instanceof Set) { var aElements = as instanceof Set ? as.elements : [as]; var bElements = bs instanceof Set ? bs.elements : [bs]; var cp = Set.cartesianProductOf(aElements, bElements); return Set.fromJS(cp.map(function (v) { return fn(v[0], v[1]); })); } else { return fn(as, bs); } }; Set.crossBinaryBoolean = function (as, bs, fn) { if (as instanceof Set || bs instanceof Set) { var aElements = as instanceof Set ? as.elements : [as]; var bElements = bs instanceof Set ? bs.elements : [bs]; var cp = Set.cartesianProductOf(aElements, bElements); return cp.some(function (v) { return fn(v[0], v[1]); }); } else { return fn(as, bs); } }; Set.crossUnary = function (as, fn) { if (as instanceof Set) { var aElements = as instanceof Set ? as.elements : [as]; return Set.fromJS(aElements.map(function (a) { return fn(a); })); } else { return fn(as); } }; Set.crossUnaryBoolean = function (as, fn) { if (as instanceof Set) { var aElements = as instanceof Set ? as.elements : [as]; return aElements.some(function (a) { return fn(a); }); } else { return fn(as); } }; Set.convertToSet = function (thing) { var thingType = getValueType(thing); if (Set.isSetType(thingType)) return thing; return Set.fromJS({ setType: thingType, elements: [thing] }); }; Set.unionCover = function (a, b) { var aSet = Set.convertToSet(a); var bSet = Set.convertToSet(b); var aSetType = aSet.setType; var bSetType = bSet.setType; if (typeUpgrades[aSetType] === bSetType) { aSet = aSet.upgradeType(); } else if (typeUpgrades[bSetType] === aSetType) { bSet = bSet.upgradeType(); } else if (aSetType !== bSetType) { return null; } return aSet.union(bSet).simplifyCover(); }; Set.intersectCover = function (a, b) { var aSet = Set.convertToSet(a); var bSet = Set.convertToSet(b); var aSetType = aSet.setType; var bSetType = bSet.setType; if (typeUpgrades[aSetType] === bSetType) { aSet = aSet.upgradeType(); } else if (typeUpgrades[bSetType] === aSetType) { bSet = bSet.upgradeType(); } else if (aSetType !== bSetType) { return null; } return aSet.intersect(bSet).simplifyCover(); }; Set.fromPlywoodValue = function (pv) { return pv instanceof Set ? pv : Set.fromJS([pv]); }; Set.fromJS = function (parameters) { if (Array.isArray(parameters)) { parameters = { elements: parameters }; } if (typeof parameters !== 'object') { throw new Error('unrecognizable set'); } var setType = parameters.setType; var elements = parameters.elements; if (!setType) { setType = getValueType(elements.length ? elements[0] : null); if (setType === 'NULL' && elements.length > 1) setType = getValueType(elements[1]); } return new Set({ setType: setType, elements: arrayFromJS(elements, setType), }); }; Set.prototype.valueOf = function () { return { setType: this.setType, elements: this.elements, }; }; Set.prototype.toJS = function () { return { setType: this.setType, elements: this.elements.map(valueToJS), }; }; Set.prototype.toJSON = function () { return this.toJS(); }; Set.prototype.toString = function (tz) { var setType = this.setType; var stringFn = null; if (setType === 'NULL') return 'null'; if (setType === 'TIME_RANGE') { stringFn = function (e) { return (e ? e.toString(tz) : 'null'); }; } else if (setType === 'TIME') { stringFn = function (e) { return (e ? Timezone.formatDateWithTimezone(e, tz) : 'null'); }; } else { stringFn = String; } return "".concat(this.elements.map(stringFn).join(', ')); }; Set.prototype.equals = function (other) { return (other instanceof Set && this.setType === other.setType && this.elements.length === other.elements.length && this.elements.slice().sort().join('') === other.elements.slice().sort().join('')); }; Set.prototype.changeSetType = function (setType) { if (this.setType === setType) return this; var value = this.valueOf(); value.setType = setType; return new Set(value); }; Set.prototype.changeElements = function (elements) { if (this.elements === elements) return this; var value = this.valueOf(); value.elements = elements; return new Set(value); }; Set.prototype.cardinality = function () { return this.size(); }; Set.prototype.size = function () { return this.elements.length; }; Set.prototype.empty = function () { return this.elements.length === 0; }; Set.prototype.isNullSet = function () { return this.setType === 'NULL'; }; Set.prototype.unifyElements = function () { return Range.isRangeType(this.setType) ? this.changeElements(Set.unifyElements(this.elements)) : this; }; Set.prototype.simplifyCover = function () { var simpleSet = this.unifyElements().downgradeType(); var simpleSetElements = simpleSet.elements; return simpleSetElements.length === 1 ? simpleSetElements[0] : simpleSet; }; Set.prototype.getType = function () { return ('SET/' + this.setType); }; Set.prototype.upgradeType = function () { if (this.setType === 'NUMBER') { return Set.fromJS({ setType: 'NUMBER_RANGE', elements: this.elements.map(NumberRange.fromNumber), }); } else if (this.setType === 'TIME') { return Set.fromJS({ setType: 'TIME_RANGE', elements: this.elements.map(TimeRange.fromTime), }); } else if (this.setType === 'STRING') { return Set.fromJS({ setType: 'STRING_RANGE', elements: this.elements.map(StringRange.fromString), }); } else { return this; } }; Set.prototype.downgradeType = function () { if (!Range.isRangeType(this.setType)) return this; var elements = this.elements; var simpleElements = []; for (var _i = 0, elements_2 = elements; _i < elements_2.length; _i++) { var element = elements_2[_i]; if (element.degenerate()) { simpleElements.push(element.start); } else { return this; } } return Set.fromJS(simpleElements); }; Set.prototype.extent = function () { var setType = this.setType; if (hasOwnProp(typeUpgrades, setType)) { return this.upgradeType().extent(); } if (!Range.isRangeType(setType)) return null; var elements = this.elements; var extent = elements[0] || null; for (var i = 1; i < elements.length; i++) { extent = extent.extend(elements[i]); } return extent; }; Set.prototype.union = function (other) { if (this.empty()) return other; if (other.empty()) return this; var ret = this; if (this.setType !== other.setType) { if (this.setType === 'NULL') { ret = ret.changeSetType(other.setType); } else if (other.setType !== 'NULL') { throw new TypeError('can not union sets of different types'); } } return ret.changeElements(ret.elements.concat(other.elements)).unifyElements(); }; Set.prototype.intersect = function (other) { if (this.empty() || other.empty()) return Set.EMPTY; var setType = this.setType; if (this.setType !== other.setType) { throw new TypeError('can not intersect sets of different types'); } var thisElements = this.elements; var newElements; if (setType === 'NUMBER_RANGE' || setType === 'TIME_RANGE' || setType === 'STRING_RANGE') { var otherElements = other.elements; newElements = Set.intersectElements(thisElements, otherElements); } else { newElements = []; for (var _i = 0, thisElements_1 = thisElements; _i < thisElements_1.length; _i++) { var el = thisElements_1[_i]; if (!other.contains(el)) continue; newElements.push(el); } } return this.changeElements(newElements); }; Set.prototype.overlap = function (other) { if (this.empty() || other.empty()) return false; if (this.setType !== other.setType) { throw new TypeError('can determine overlap sets of different types'); } var thisElements = this.elements; for (var _i = 0, thisElements_2 = thisElements; _i < thisElements_2.length; _i++) { var el = thisElements_2[_i]; if (!other.contains(el)) continue; return true; } return false; }; Set.prototype.has = function (value) { var key = this.keyFn(value); return hasOwnProp(this.hash, key) && generalEqual(this.hash[key], value); }; Set.prototype.contains = function (value) { var _this = this; if (value instanceof Set) { return value.elements.every(function (element) { return _this.contains(element); }); } if (Range.isRangeType(this.setType)) { if (value instanceof Range && this.has(value)) return true; return this.elements.some(function (element) { return element.contains(value); }); } else { return this.has(value); } }; Set.prototype.add = function (value) { var setType = this.setType; var valueType = getValueType(value); if (setType === 'NULL') setType = valueType; if (valueType !== 'NULL' && setType !== valueType) throw new Error('value type must match'); if (this.contains(value)) return this; return new Set({ setType: setType, elements: this.elements.concat([value]), }); }; Set.prototype.remove = function (value) { if (!this.contains(value)) return this; var keyFn = this.keyFn; var key = keyFn(value); var newElements = this.elements.filter(function (element) { return keyFn(element) !== key; }); return new Set({ setType: getValueType(newElements.length ? newElements[0] : null), elements: newElements, }); }; Set.prototype.toggle = function (value) { return this.contains(value) ? this.remove(value) : this.add(value); }; Set.type = 'SET'; return Set; }()); export { Set }; var check = Set; Set.EMPTY = Set.fromJS([]);