runtime-branding
Version:
Runtime Branding API for TypeScript
95 lines • 2.95 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const brand = Symbol();
// TODO: do we need a global branding map?
/**
* Creates a new brand, identified by the provided branding object.
*
* @param brandObject An object that represents the brand. The shape of this object should be unique, and symbols may be used as unique keys.
* @param callback An optional callback with variable arguments which is invoked during object branding
*/
function createBranding(brandObject, callback) {
const brandedObjects = new WeakSet();
function has(obj) {
return brandedObjects.has(obj);
}
function assert(obj) {
if (!brandedObjects.has(obj)) {
throw new Error("Object not branded.");
}
}
function branding(obj) {
if (has(obj)) {
throw new Error("Object already branded.");
}
brandedObjects.add(obj);
if (callback) {
try {
callback(obj, brandObject);
}
catch (e) {
brandedObjects.delete(obj);
throw e;
}
}
return obj;
}
function refine(newBrand, newCallback) {
const b = Object.assign({}, newBrand, brandObject);
const refinedBranding = createBranding(b, newCallback);
return merge(refinedBranding);
}
function merge(branding1) {
return mixin(branding, branding1);
}
function generic() {
return branding;
}
branding.has = has; // TODO: maybe all these should be built separately, then Object.assigned to branding()
branding.assert = assert;
branding.refine = refine;
branding.merge = merge;
branding.generic = generic;
branding[brand] = brandObject;
return branding;
}
exports.createBranding = createBranding;
/**
* Mixes two different brandings in a single one.
*
* @param fn1 The first branding function
* @param fn2 The second branding function
*/
function mixin(fn1, fn2) {
function has(obj) {
return fn1.has(obj) && fn2.has(obj);
}
function assert(obj) {
fn1.assert(obj);
fn2.assert(obj);
}
function branding(obj) {
fn1(obj);
fn2(obj);
return obj;
}
function refine(newBrand, callback) {
const b = Object.assign({}, newBrand, fn1[brand], fn2[brand]);
return createBranding(b, callback);
}
function merge(branding1) {
return mixin(branding, branding1);
}
function generic() {
return branding;
}
const newBrand = Object.assign({}, fn1[brand], fn2[brand]);
branding.has = has;
branding.assert = assert;
branding.refine = refine;
branding.merge = merge;
branding.generic = generic;
branding[brand] = newBrand;
return branding;
}
//# sourceMappingURL=index.js.map