Created
July 21, 2021 08:54
-
-
Save koresar/aa4cad04453d5b307f8ed4f6e0b932d4 to your computer and use it in GitHub Desktop.
Protect JS object properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const HasProtectedAccessor = stampit({ | |
// stamp configuration | |
deepConf: { | |
// collect all the property names to protect | |
protectedProperties: {} | |
}, | |
statics: { | |
// API of the stamp | |
protectProperty(names) { | |
// will deep merge the base objects with `names` | |
return this.deepConf({ protectedProperties: names }); | |
} | |
}, | |
init(keyValueMap, { stamp }) { | |
// The properties to protect | |
let { protectedProperties } = stamp.compose.deepConfiguration || {}; | |
// The closured map of protector functions | |
const protectors = new Map(Object.entries(protectedProperties) | |
.filter(([key, value]) => typeof value === "function")); | |
// The closured map of protected values | |
const map = new Map(); | |
for (const key of protectors.keys()) map.set(key, undefined); | |
for (const name of map.keys()) { | |
// Using JS getters and setters to protect properties | |
Object.defineProperty(this, name, { | |
get () { return map.get(name); }, | |
set (value) { | |
if (protectors.get(name)(value, name)) | |
map.set(name, value); | |
} | |
}); | |
} | |
// Initialise this object instance with the configured values | |
for (const [key, value] of Object.entries(keyValueMap)) { | |
if (map.has(key)) this[key] = value; | |
} | |
} | |
}); | |
const _ = require("lodash"); | |
const TestAccessors = stampit( | |
HasProtectedAccessor.protectProperty({ | |
fullName: v => v === undefined || _.isString(v), | |
address: _.isArray, | |
}), | |
{ name: "TestAccessors" } | |
); | |
const instance1 = TestAccessors({ fullName: "John Johnson", address: [] }); | |
t.strictEqual(instance1.fullName, "John Johnson"); | |
t.deepEqual(instance1.address, []); | |
const instance2 = TestAccessors({ fullName: ["array"], address: "oops" }); // WILL NOT SET | |
t.strictEqual(instance2.fullName, undefined); | |
t.strictEqual(instance2.address, undefined); | |
instance2.fullName = function () {}; // WILL NOT SET | |
t.strictEqual(instance2.fullName, undefined); | |
instance2.address = { NotAnArray: 111 }; // WILL NOT SET | |
t.strictEqual(instance2.address, undefined); | |
instance2.fullName = "Andrew Anderson"; | |
t.strictEqual(instance2.fullName, "Andrew Anderson"); | |
instance2.address = ["111 Acme St", "London"]; | |
t.deepEqual(instance2.address, ["111 Acme St", "London"]); | |
instance2.fullName = undefined; | |
t.strictEqual(instance2.fullName, undefined); | |
instance2.address = undefined; // WILL NOT SET | |
t.deepEqual(instance2.address, ["111 Acme St", "London"]); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment