es6-class-privates
Version:
Provides a method of converting underscored pseudo-private class members into truly private class members
128 lines (101 loc) • 3.99 kB
JavaScript
;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var config = {
privatePrefix: '_',
protectedPrefix: '$',
dropPrefix: true
};
var findConfigErrors = function findConfigErrors(newConfig) {
var validPrefixTypes = ['string', 'undefined'];
var validDropPrefixTypes = ['boolean', 'undefined'];
var prefixProps = ['privatePrefix', 'protectedPrefix'];
var errors = [];
// Config must be a valid object
if ((typeof newConfig === 'undefined' ? 'undefined' : _typeof(newConfig)) !== 'object') {
errors.push('Configuration must be an object');
return errors;
}
prefixProps.forEach(function (prop) {
// Check prefix types
if (!validPrefixTypes.includes(_typeof(newConfig[prop]))) {
errors.push(prop + ' must be a string if provided');
}
// Prefixes may not be blank strings
if (newConfig[prop] === '') {
errors.push('Invalid prefix for ' + prop + ': Prefix may not be a blank string');
}
});
// Prefixes may not be the same
var priv = newConfig.privatePrefix;
var prot = newConfig.protectedPrefix;
if (priv && prot && priv === prot) {
errors.push('Invalid prefixes: Prefixes may not be the same');
}
if (priv && !prot && priv === config.protectedPrefix) {
errors.push('Invalid prefixes: Prefixes may not be the same');
}
if (prot && !priv && prot === config.privatedPrefix) {
errors.push('Invalid prefixes: Prefixes may not be the same');
}
// Drop prefix flag must be boolean or undefined
if (!validDropPrefixTypes.includes(_typeof(newConfig.dropPrefix))) {
errors.push('Invalid dropPrefix flag: Must be boolean or undefined');
}
return errors;
};
var formatErrors = function formatErrors(errors) {
return 'Invalid configuration - ' + errors.join('; ') + '.';
};
var makeMine = function makeMine() {
var newConfig = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var errors = findConfigErrors(newConfig);
if (errors.length > 0) throw new Error(formatErrors(errors));
var localConfig = Object.assign({}, config, newConfig);
var restrictTo = function restrictTo(accessor) {
return function (constructor) {
var propNames = Object.getOwnPropertyNames(constructor.prototype);
propNames.forEach(function (name) {
var prop = constructor.prototype[name];
// Skip non-methods and constructor
if (!(prop instanceof Function) || prop === constructor) return;
// Handle private methods
if (name.indexOf(localConfig.privatePrefix) === 0) {
var newName = localConfig.dropPrefix ? name.substr(1) : name;
accessor(constructor)[newName] = prop;
delete constructor.prototype[name];
}
});
return constructor;
};
};
var bindAllTo = function bindAllTo(accessor) {
return function (instance) {
var constructor = Object.getPrototypeOf(instance).constructor;
var propMap = accessor(constructor);
Object.keys(propMap).forEach(function (name) {
var prop = propMap[name];
// Skip non-methods
if (!(prop instanceof Function)) return;
accessor(instance)[name] = prop.bind(instance);
});
return instance;
};
};
var map = new WeakMap();
var accessor = function accessor(object) {
if (!map.has(object)) map.set(object, {});
return map.get(object);
};
accessor.restrict = restrictTo(accessor);
accessor.bindAllTo = bindAllTo(accessor);
return accessor;
};
var configure = function configure(newConfig) {
var errors = findConfigErrors(newConfig);
if (errors.length > 0) throw new Error(errors);
config = Object.assign({}, config, newConfig);
};
module.exports = {
makeMine: makeMine,
configure: configure
};