Skip to content

Commit

Permalink
frint: Expose class methods on the app instance level (#431)
Browse files Browse the repository at this point in the history
* Expose class methods on the app instance level

* Update documentation

* Fix linting errors

* Don't overwrite app fields with options methods

* Remove `app.getMethods` method

* Rename App index signature
  • Loading branch information
rbardini authored Jul 13, 2018
1 parent abb7964 commit 0a89cc1
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 1 deletion.
1 change: 1 addition & 0 deletions packages/frint/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ The base App class.

1. `options` (`Object`)
* `options.name`: (`String` [required]): Name of your App.
* `options.methods`: (`Object` [optional]): Object with the methods your App exposes on the instance level.
* `options.initialize`: (`Function` [optional]): Called when App is constructed.
* `options.beforeDestroy`: (`Function` [optional]): Called when App is about to be destroyed.
* `options.providers`: (`Array` [optional]): Array of provider objects.
Expand Down
29 changes: 28 additions & 1 deletion packages/frint/src/App.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,41 @@ describe('frint › App', () => {
}).to.throw(/Must provide `name` in options/);
});

it('gets option value', () => {
it('gets name option value', () => {
const app = new App({
name: 'MyApp',
});

expect(app.getName()).to.equal('MyApp');
});

it('exposes methods as class properties', () => {
const methods = {
foo() { return 'foo'; },
};

const app = new App({
name: 'MyApp',
methods,
});

expect(app.foo()).to.equal('foo');
});

it('does not overwrite app properties or methods with options methods', () => {
const methods = {
// tslint:disable-next-line:no-empty
getName() {},
};

expect(() => (
new App({
name: 'MyApp',
methods,
})
)).to.throw(/Cannot overwrite app's `getName` property or method with options method/);
});

it('gets parent and root app', () => {
const rootApp = new App({
name: 'RootApp',
Expand Down
20 changes: 20 additions & 0 deletions packages/frint/src/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ function makeInstanceKey(region = null, regionKey = null, multi = false) {
return key;
}

export interface Methods {
[key: string]: () => any;
}

export interface ProviderNames {
component: string;
container: string;
Expand Down Expand Up @@ -75,6 +79,7 @@ export interface AppRegistration {

export interface AppOptions {
name?: string;
methods?: Methods;
parentApp?: App;
providers?: FrintProvider[];
providerNames?: ProviderNames;
Expand All @@ -88,6 +93,7 @@ export interface AppClass {
}

export class App {
[method: string]: any;
public container: Container;
private options: AppOptions;
private _appsCollection: AppRegistration[];
Expand All @@ -96,6 +102,7 @@ export class App {
constructor(opts: AppOptions) {
this.options = {
name: null,
methods: {},
parentApp: null,
providers: [],

Expand All @@ -116,6 +123,19 @@ export class App {
throw new Error('Must provide `name` in options');
}

// expose methods as class properties
Object.keys(this.options.methods).forEach(methodName => {
const method = this.options.methods[methodName];

if (typeof method === 'function') {
if (this[methodName] !== undefined) {
throw new Error(`Cannot overwrite app's \`${methodName}\` property or method with options method.`);
}

this[methodName] = method.bind(this);
}
});

// children - create Observable if root
this._appsCollection = [];
this._apps$ = new BehaviorSubject(this._appsCollection);
Expand Down

0 comments on commit 0a89cc1

Please sign in to comment.