From 642df0bd9b37d86f9eb591e6932ceffa781fb7b8 Mon Sep 17 00:00:00 2001 From: Chris Thielen Date: Thu, 16 Feb 2017 19:29:54 -0600 Subject: [PATCH] feat(decorators): Add state, resolve and resolve data decorators --- src/decorators/index.ts | 3 +++ src/decorators/resolve.ts | 40 +++++++++++++++++++++++++++++++++++ src/decorators/resolveData.ts | 18 ++++++++++++++++ src/decorators/state.ts | 8 +++++++ src/index.ts | 1 + 5 files changed, 70 insertions(+) create mode 100644 src/decorators/index.ts create mode 100644 src/decorators/resolve.ts create mode 100644 src/decorators/resolveData.ts create mode 100644 src/decorators/state.ts diff --git a/src/decorators/index.ts b/src/decorators/index.ts new file mode 100644 index 00000000..5a093ac1 --- /dev/null +++ b/src/decorators/index.ts @@ -0,0 +1,3 @@ +export * from "./resolveData"; +export * from "./resolve"; +export * from "./state"; diff --git a/src/decorators/resolve.ts b/src/decorators/resolve.ts new file mode 100644 index 00000000..a3c991fe --- /dev/null +++ b/src/decorators/resolve.ts @@ -0,0 +1,40 @@ +/** + * An ES7 decorator which maps resolve data to a component. + * + * Add this decorator to a property of your component. + * The decorator marks the component's property to receive resolve data. + * + * When resolve data of the same name (token) is found, + * the resolve data will be assigned to the component's property. + * + * #### Example: + * + * The component's properties receive resolve data from the state definition. + * ```js + * @Component({ selector: 'foo' }) + * export class FooComponent { + * @Resolve() resolveToken1; + * @Resolve('resolveToken2') prop2; + * @Input() @Resolve() resolveToken3; + * } + * + * const fooState = { + * name: 'foo', + * component: FooComponent, + * resolve: [ + * { token: 'resolveToken1', deps: [], resolveFn: resolve1Fn }, + * { token: 'resolveToken2', deps: [], resolveFn: resolve2Fn }, + * { token: 'resolveToken3', deps: [], resolveFn: resolve3Fn }, + * ] + * } + * ``` + * + * @param token The resolve token to bind to this property + * (if omitted, the property name is used as the token) + */ +export function Resolve(token?: string): PropertyDecorator { + return function(target, property) { + const inputs = target['$inputs'] = target['$inputs'] || {}; + inputs[token] = property; + }; +} \ No newline at end of file diff --git a/src/decorators/resolveData.ts b/src/decorators/resolveData.ts new file mode 100644 index 00000000..1e2d2727 --- /dev/null +++ b/src/decorators/resolveData.ts @@ -0,0 +1,18 @@ +import { StateDeclaration } from '../state/interface'; +import { isArray } from '../common/predicates'; + +export function ResolveData(resolveConfig: { token?: string, deps?: any[] }): PropertyDecorator { + resolveConfig = resolveConfig || {}; + + return function(target: StateDeclaration, property) { + const resolve = target.resolve = target.resolve || []; + const token = resolveConfig.token || property; + const deps = resolveConfig.deps || []; + + if (!isArray(resolve)) { + throw new Error(`@ResolveData() only supports array style resolve: state: '${target.name}', resolve: ${property}, token: ${token}.`) + } + + resolve.push({ token, deps, resolveFn: target[property] }); + }; +} diff --git a/src/decorators/state.ts b/src/decorators/state.ts new file mode 100644 index 00000000..c9d441c9 --- /dev/null +++ b/src/decorators/state.ts @@ -0,0 +1,8 @@ +import { isString } from '../common/predicates'; + +export function State(stateName?: string): ClassDecorator { + return function(targetClass: { new(...args: any[]): T }) { + if (isString(stateName)) targetClass.prototype.name = stateName; + targetClass['__uiRouterState'] = true; + }; +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 634f9861..1c962282 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,7 @@ export * from "./state/index"; export * from "./transition/index"; export * from "./url/index"; export * from "./view/index"; +export * from "./decorators/index"; export * from "./globals"; export * from "./router";