terriajs
Version:
Geospatial data visualization platform.
69 lines (60 loc) • 2.22 kB
text/typescript
import { computed } from "mobx";
import ModelTraits from "../../Traits/ModelTraits";
import Stratified from "../../Traits/Stratified";
import TraitsConstructor from "../../Traits/TraitsConstructor";
import ModelPropertiesFromTraits from "./ModelPropertiesFromTraits";
/**
* Adds a set of traits to a model. The values of the traits will be derived
* from the model's strata.
* @param model The model class or instance.
* @param Traits The traits class.
* @returns The original model, now modified to add the added traits.
*/
export default function addModelStrataView<
T extends TraitsConstructor<ModelTraits>
>(
/* TODO: Use a more specific type than "Function". */
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
model: Stratified<InstanceType<T>> | Function,
Traits: T
): ModelPropertiesFromTraits<InstanceType<T>>;
export default function addModelStrataView<
T extends TraitsConstructor<ModelTraits>
>(model: any, Traits: T): ModelPropertiesFromTraits<InstanceType<T>> {
const traits = Traits.traits;
const decorators: { [id: string]: PropertyDecorator } = {};
const propertyTarget = typeof model === "function" ? model.prototype : model;
const traitsInstance: any = new Traits();
Object.keys(traits).forEach((traitName) => {
const trait = traits[traitName];
const defaultValue = traitsInstance[traitName];
Object.defineProperty(propertyTarget, traitName, {
get: function () {
const value = trait.getValue(this);
return value === undefined ? defaultValue : value;
},
enumerable: true,
configurable: true
});
decorators[traitName] = trait.decoratorForFlattened || computed;
});
decorate(model, decorators);
return model;
}
/**
* Decorate the target class.
*
* Note that we assume that the class constructor calls `makeObservable(this)`
* to correctly setup the mobx properties.
*
* @param target Target class to decorate
* @param decorators Properties of the class that must be decorated
*/
function decorate(
target: any,
decorators: { [id: string]: PropertyDecorator }
) {
Object.entries(decorators).forEach(([prop, decorator]) => {
decorator(target.prototype, prop);
});
}