Spaces:
Sleeping
Sleeping
| ; | |
| const Ref = require('./ref'); | |
| const internals = {}; | |
| internals.extendedCheckForValue = function (value, insensitive) { | |
| const valueType = typeof value; | |
| if (valueType === 'object') { | |
| if (value instanceof Date) { | |
| return (item) => { | |
| return item instanceof Date && value.getTime() === item.getTime(); | |
| }; | |
| } | |
| if (Buffer.isBuffer(value)) { | |
| return (item) => { | |
| return Buffer.isBuffer(item) && value.length === item.length && value.toString('binary') === item.toString('binary'); | |
| }; | |
| } | |
| } | |
| else if (insensitive && valueType === 'string') { | |
| const lowercaseValue = value.toLowerCase(); | |
| return (item) => { | |
| return typeof item === 'string' && lowercaseValue === item.toLowerCase(); | |
| }; | |
| } | |
| return null; | |
| }; | |
| module.exports = class InternalSet { | |
| constructor(from) { | |
| this._set = new Set(from); | |
| this._hasRef = false; | |
| } | |
| add(value, refs) { | |
| const isRef = Ref.isRef(value); | |
| if (!isRef && this.has(value, null, null, false)) { | |
| return this; | |
| } | |
| if (refs !== undefined) { // If it's a merge, we don't have any refs | |
| Ref.push(refs, value); | |
| } | |
| this._set.add(value); | |
| this._hasRef |= isRef; | |
| return this; | |
| } | |
| merge(add, remove) { | |
| for (const item of add._set) { | |
| this.add(item); | |
| } | |
| for (const item of remove._set) { | |
| this.remove(item); | |
| } | |
| return this; | |
| } | |
| remove(value) { | |
| this._set.delete(value); | |
| return this; | |
| } | |
| has(value, state, options, insensitive) { | |
| return !!this.get(value, state, options, insensitive); | |
| } | |
| get(value, state, options, insensitive) { | |
| if (!this._set.size) { | |
| return false; | |
| } | |
| const hasValue = this._set.has(value); | |
| if (hasValue) { | |
| return { value }; | |
| } | |
| const extendedCheck = internals.extendedCheckForValue(value, insensitive); | |
| if (!extendedCheck) { | |
| if (state && this._hasRef) { | |
| for (let item of this._set) { | |
| if (Ref.isRef(item)) { | |
| item = [].concat(item(state.reference || state.parent, options)); | |
| const found = item.indexOf(value); | |
| if (found >= 0) { | |
| return { value: item[found] }; | |
| } | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| return this._has(value, state, options, extendedCheck); | |
| } | |
| _has(value, state, options, check) { | |
| const checkRef = !!(state && this._hasRef); | |
| const isReallyEqual = function (item) { | |
| if (value === item) { | |
| return true; | |
| } | |
| return check(item); | |
| }; | |
| for (let item of this._set) { | |
| if (checkRef && Ref.isRef(item)) { // Only resolve references if there is a state, otherwise it's a merge | |
| item = item(state.reference || state.parent, options); | |
| if (Array.isArray(item)) { | |
| const found = item.findIndex(isReallyEqual); | |
| if (found >= 0) { | |
| return { | |
| value: item[found] | |
| }; | |
| } | |
| continue; | |
| } | |
| } | |
| if (isReallyEqual(item)) { | |
| return { | |
| value: item | |
| }; | |
| } | |
| } | |
| return false; | |
| } | |
| values(options) { | |
| if (options && options.stripUndefined) { | |
| const values = []; | |
| for (const item of this._set) { | |
| if (item !== undefined) { | |
| values.push(item); | |
| } | |
| } | |
| return values; | |
| } | |
| return Array.from(this._set); | |
| } | |
| slice() { | |
| const set = new InternalSet(this._set); | |
| set._hasRef = this._hasRef; | |
| return set; | |
| } | |
| concat(source) { | |
| const set = new InternalSet([...this._set, ...source._set]); | |
| set._hasRef = !!(this._hasRef | source._hasRef); | |
| return set; | |
| } | |
| }; | |