You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
2.3 KiB
JavaScript

"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,
set: null,
size: 0,
[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"),
get: createWrapper("get"),
has: createWrapper("has"),
keys: createWrapper("keys"),
values: createWrapper("values"),
toString: createWrapper("toString"),
valueOf: createWrapper("valueOf"),
delete: function (key) {
let deleted = this._source.delete(key);
this.size = this._source.size;
if (deleted === false) {
throw new errors.ValidationError("Tried to delete non-existent key from guarded map", {
key: key,
nap: this._source
});
}
}
};
module.exports = function createGuardedMap(map, valueGuard, keyGuard, parent) {
function generateMapSignatureError() {
let wantedSignature = {
_guardedCollectionType: "map",
_keyType: keyGuard._rule,
_itemType: valueGuard._rule
};
return new errors.ValidationError(`Expected a Map or ${getValueType(wantedSignature)}, got ${getValueType(map)} instead`);
}
if (map._guardedCollectionType === "map") {
if (keyGuard === map._keyType && valueGuard === map._itemType) {
return map;
} else {
throw generateMapSignatureError();
}
} else if (map instanceof Map) {
function check(key, value) {
let keyGuardResult = keyGuard.call(parent, key);
let valueGuardResult = valueGuard.call(parent, value);
if (keyGuardResult === true && valueGuardResult === true) {
return true;
} else if (keyGuardResult !== true) {
throw keyGuardResult;
} else {
throw valueGuardResult;
}
}
for (let [key, value] of map.entries()) {
check(key, value);
}
return Object.assign(Object.create(proto), {
_source: map,
_guardedCollectionType: "map",
_itemType: valueGuard,
_keyType: keyGuard,
set: function (key, value) {
if (check(key, value) === true) {
this._source.set(key, value);
this.size = this._source.size;
}
}
});
} else {
throw generateMapSignatureError();
}
};