import * as I from 'immutable'; import {compose} from '@avocado/core'; import {EventEmitter} from '@avocado/mixins'; import {Resource} from '@avocado/resource'; import {Traits} from './traits'; // Cache builtins to avoid HasProperty const entityBuiltins = [ '$$events', '$$namespaces', '_instanceUuid', '_traits', '_uri', '_uuid', 'addListener', 'addTrait', 'addTraits', 'allTraitInstances', 'allTraitTypes', 'emit', 'fromJSON', 'is', 'hydrate', 'instanceUuid', 'invokeHook', 'invokeHookFlat', 'lookupEmitListeners', 'off', 'offSingleEvent', 'on', '_on', 'once', 'onSingleEvent', 'patchState', 'regenerateUuid', 'removeAllTraits', 'removeEventListenersFor', 'removeListener', 'removeTrait', 'removeTraits', 'state', 'tick', 'toJSON', 'uuid', 'uri', ]; const entityBuiltinsMap = new Map(); for (const entityBuiltin of entityBuiltins) { entityBuiltinsMap.set(entityBuiltin, true); } class TraitProxy { has(entity, property, receiver) { const isBuiltin = entityBuiltinsMap.get(property); if (isBuiltin) { return true; } else { return entity._traits.hasProperty(property); } } get(entity, property, receiver) { const isBuiltin = entityBuiltinsMap.get(property); if (isBuiltin) { return entity[property]; } else { return entity._traits.getProperty(property); } } set(entity, property, value, receiver) { const isBuiltin = entityBuiltinsMap.get(property); if (isBuiltin) { entity[property] = value; return true; } return entity._traits.setProperty(property, value, receiver); } } const decorate = compose( EventEmitter, ); class Entity extends decorate(Resource) { constructor() { super(); this._traits = new Traits(createProxy(this)); } addTrait(type, trait) { this._traits.addTrait(type, trait); } addTraits(traits) { for (const type in traits) { this._traits.addTrait(type, traits[type]); } } allTraitInstances() { return this._traits.allInstances(); } allTraitTypes() { return this._traits.allTypes(); } fromJSON(json) { super.fromJSON(json); this._traits.fromJSON(json.traits); return this; } is(type) { return this._traits.hasTrait(type); } hydrate() { return this._traits.hydrate(); } invokeHook(hook, ...args) { return this._traits.invokeHook(hook, ...args); } invokeHookFlat(hook, ...args) { return this._traits.invokeHookFlat(hook, ...args); } patchState(patch) { this._traits.patchState(patch); } removeAllTraits() { const types = this._traits.allTypes(); this.removeTraits(types); } removeTrait(type) { this._traits.removeTrait(type); } removeTraits(types) { types.forEach((type) => this.removeTrait(type)); } get state() { return this._traits.state; } tick(elapsed) { if (this.isTicking) { this._traits.tick(elapsed); } } toJSON() { return { ...super.toJSON(), traits: this._traits.toJSON(), } } } export function create() { return createProxy(new Entity()); } export function createProxy(entity) { return new Proxy(entity, new TraitProxy()); } export {EntityList} from './list'; export { hasTrait, lookupTrait, registerTrait, } from './trait-registry'; export {StateProperty, Trait} from './trait';