avocado-old/packages/mixins/property.js
2019-03-18 19:57:31 -05:00

83 lines
1.8 KiB
JavaScript

export function PropertyMixin(key, meta = {}) {
if (!meta || 'object' !== typeof meta) {
throw new TypeError(
`Expected meta for Property(${
key
}) to be object. ${
JSON.stringify(meta)
} given.`
);
}
return (Superclass) => {
if (Superclass.prototype[key]) {
throw new TypeError(`can't redefine Avocado property "${key}"`);
}
if ('identity' === meta.transformProperty) {
meta.transformProperty = (key) => key;
}
else if (!meta.transformProperty) {
meta.transformProperty = (key) => `${key}_PRIVATE_PROPERTY`;
}
meta.emit = meta.emit || function(...args) {
if (this.emit) {
this.emit(...args);
}
}
meta.eq = meta.eq || function (l, r) {
return l === r;
}
meta.get = meta.get || function(value) {
return this[meta.transformProperty(key)];
}
meta.set = meta.set || function(value) {
this[meta.transformProperty(key)] = value;
}
let metaDefault;
if (null === meta.default) {
metaDefault = null;
}
else if (undefined === meta.default) {
metaDefault = undefined;
}
else {
metaDefault = JSON.parse(JSON.stringify(meta.default));
}
class Property extends Superclass {
constructor(...args) {
super(...args);
if (undefined !== metaDefault) {
meta.set.call(this, metaDefault);
}
}
}
Object.defineProperty(Property.prototype, key, {
enumerable: true,
get: function() {
return meta.get.call(this);
},
set: function (value) {
const old = meta.get.call(this);
meta.set.call(this, value);
if (meta.track && meta.emit && !meta.eq.call(this, old, value)) {
meta.emit.call(this, `${key}Changed`, old, value);
}
},
});
return Property;
}
}