"use strict"; const util = require("util"); const errors = require("../errors"); const createWrapper = require("../util/function-wrapper"); const getValueType = require("../util/get-value-type"); let proto = { _source: null, description: null, size: 0, add: null, [Symbol.iterator]: createWrapper(Symbol.iterator), [util.inspect.custom]: function () { return this.valueOf(); }, clear: function () { this._source.clear(); this.size = 0; }, entries: createWrapper("entries"), forEach: createWrapper("forEach"), /* FIXME: Prevent mutation from the third argument to forEach (which is the original set); maybe also needed for Map? */ has: createWrapper("has"), keys: createWrapper("keys"), values: createWrapper("values"), toString: createWrapper("toString"), valueOf: createWrapper("valueOf"), delete: function (value) { let deleted = this._source.delete(value); this.size = this._source.size; if (deleted === false) { throw new errors.ValidationError("Tried to delete non-existent value from guarded set", { value: value, set: this._source }); } } }; module.exports = function createGuardedSet(set, guard, _, parent) { function generateSetSignatureError() { let wantedSignature = { _guardedCollectionType: "set", _itemType: guard._rule }; return new errors.ValidationError(`Expected a Set or ${getValueType(wantedSignature)}, got ${getValueType(set)} instead`); } if (set._guardedCollectionType === "set") { if (guard === set._itemType) { return set; } else { throw generateSetSignatureError(); } } else if (set instanceof Set) { function check(value) { let guardResult = guard.call(parent, value); if (guardResult === true) { return true; } else { throw guardResult; } } for (let value of set.values()) { check(value); } return Object.assign(Object.create(proto), { _source: set, _guardedCollectionType: "set", _itemType: guard, add: function (value) { if (check(value) === true) { this._source.add(value); this.size = this._source.size; } } }); } else { throw generateSetSignatureError(); } };