| 'use strict'; | 
|   | 
| 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; | 
|     } | 
| }; |