Home Reference Source

src/store.js

import angular from 'angular';

import {Annotation} from './annotation';
import {Annotations} from './annotations';
import {EventEmitter as eventEmitterDecorator} from './behaviors/event-emitter';

import {addStaticGetterObjectMember, addStaticGetter} from './utils';

export class StoreAnnotation extends Annotation {
  get serviceName() {
    const name = this.name;
    return `${name[0].toUpperCase()}${name.slice(1)}Store`;
  }

  getInjectionTokens() {
    return [
      'LuxyFlux',
      'LuxyFluxStore',
      'ApplicationDispatcher'
    ].concat(super.getInjectionTokens());
  }

  get factoryFn() {
    const TargetCls = this.targetCls;
    const annotation = this;

    return function(LuxyFlux, LuxyFluxStore, ApplicationDispatcher) {
      const injected = Array.from(arguments).slice(3);
      const instance = new TargetCls(...injected);

      annotation.applyInjectionBindings(instance, injected);
      annotation.applyDecorators(instance);

      return LuxyFlux.createStore({
        name: `store.${annotation.name}`,
        dispatcher: ApplicationDispatcher,
        handlers: TargetCls.handlers,
        decorate: instance
      }, LuxyFluxStore);
    };
  }

  get module() {
    if (!this._module) {
      this._module = angular.module(
        `stores.${this.name}`,
        this.dependencies
      );

      this._module.factory(
        this.serviceName,
        this.getInjectionTokens().concat([this.factoryFn])
      );

      this.configure(this._module);
    }
    return this._module;
  }
}

export function Store(config) {
  return cls => {
    // Decorate a store with the EventEmitterBehavior
    eventEmitterDecorator()(cls);

    let storeName;
    const isConfigObject = angular.isObject(config);

    if (isConfigObject && config.name) {
      storeName = config.name;
    } else if (angular.isString(config)) {
      storeName = config;
    } else {
      const clsName = cls.name.replace(/store$/i, '');
      storeName = `${clsName[0].toLowerCase()}${clsName.slice(1)}`;
    }

    addStaticGetter(cls, 'annotation', () => Annotations.getStore(storeName, cls));
  };
}

export function Handlers(handlers) {
  return cls => {
    Object.keys(handlers).forEach(actionName => {
      const handlerName = handlers[actionName];
      addStaticGetterObjectMember(cls, 'handlers', actionName, handlerName);
    });
  };
}

export function Handler(actionName, override = true) {
  return (cls, handlerName) => {
    let action = actionName;
    if (!action) {
      action = handlerName
        .replace(/^on([A-Z])/, (match, first) => first.toLowerCase())
        .replace(/([A-Z])/g, '_$1').toUpperCase();
    }
    addStaticGetterObjectMember(cls.constructor, 'handlers', action, handlerName, override);
  };
}

export default StoreAnnotation;