src/utilities/ClassUtility.js
import { stringToCamel, stringToSnake } from './FormatUtility';
/**
* Support for mixin-style inheritance by extending from expressions yielding function objects.
*
* @param {Class} baseClass - The base class
* @param {Class[]} mixins - The classes in which to mixin
* @see http://es6-features.org/#ClassInheritanceFromExpressions
*
* @example
* class Colored {
* initializer () { this._color = "white"; }
* get color () { return this._color; }
* set color (v) { this._color = v; }
* }
*
* class ZCoord {
* initializer () { this._z = 0; }
* get z () { return this._z; }
* set z (v) { this._z = v; }
* }
*
* class Shape {
* constructor (x, y) { this._x = x; this._y = y; }
* get x () { return this._x; }
* set x (v) { this._x = v; }
* get y () { return this._y; }
* set y (v) { this._y = v; }
* }
*
* class Rectangle extends aggregation(Shape, Colored, ZCoord) {}
*
* var rect = new Rectangle(7, 42);
* rect.z = 1000;
* rect.color = "red";
* console.log(rect.x, rect.y, rect.z, rect.color);
*/
const aggregate = (baseClass, ...mixins) => {
const base = class _Combined extends baseClass {
constructor(...args) {
super(...args);
mixins.forEach((mixin) => {
mixin.prototype.initializer.call(this);
});
}
};
const copyProps = (target, source) => {
Object.getOwnPropertyNames(source)
.concat(Object.getOwnPropertySymbols(source))
.forEach((prop) => {
if (prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/)) { return; }
Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop));
});
};
mixins.forEach((mixin) => {
copyProps(base.prototype, mixin.prototype);
copyProps(base, mixin);
});
return base;
};
/**
* Updates field names from the current case to snake case
*
* @param {Object} obj - Object in which to update field names
* @return {Object} - Object with fields in snake case
*/
function fieldsToCamel(obj) {
if (obj === null || obj === undefined) {
return obj;
}
Object.keys(obj).forEach((oldKey) => {
const newKey = stringToCamel(oldKey);
obj[newKey] = (typeof (obj[oldKey]) === 'object') ? fieldsToCamel(obj[oldKey]) : obj[oldKey];
if (newKey !== oldKey) {
delete obj[oldKey];
}
});
return obj;
}
/**
* Updates field names from the current case to snake case
*
* @param {Object} obj - Object in which to update field names
* @return {Object} - Object with fields in snake case
*/
function fieldsToSnake(obj) {
if (obj === null || obj === undefined) {
return obj;
}
Object.keys(obj).forEach((oldKey) => {
const newKey = stringToSnake(oldKey);
obj[newKey] = (typeof (obj[oldKey]) === 'object') ? fieldsToSnake(obj[oldKey]) : obj[oldKey];
if (newKey !== oldKey) {
delete obj[oldKey];
}
});
return obj;
}
function toJsonApiStub(obj) {
let stub;
if (obj) {
if (Array.isArray(obj)) {
stub = [];
obj.forEach(o => stub.push(toJsonApiStub(o)));
} else if (obj.id && obj.type) {
stub = { id: obj.id, type: obj.type };
} else {
stub = null;
}
} else if (obj === null) {
stub = null;
}
return stub;
}
export {
aggregate,
fieldsToCamel,
fieldsToSnake,
toJsonApiStub,
};