Skip to content

Commit aa6c39d

Browse files
authored
fix: support plugins that return an empty object (#15)
BREAKING CHANGE: `.plugin([plugin1, plugin2])` is now `.plugin(plugin1, plugin2)` (compare octokit/core.js#53, thanks @wolfy1339)
1 parent ef6406e commit aa6c39d

File tree

6 files changed

+44
-30
lines changed

6 files changed

+44
-30
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ jobs:
1111
build:
1212
runs-on: ubuntu-latest
1313
steps:
14-
- uses: actions/checkout@master
15-
- uses: actions/setup-node@v1
16-
with:
17-
node-version: 12
14+
- uses: actions/checkout@v2
15+
- uses: actions/setup-node@v2
1816
- run: npm ci
1917
- run: npm run build

.github/workflows/release.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@ jobs:
99
name: release
1010
runs-on: ubuntu-latest
1111
steps:
12-
- uses: actions/checkout@master
13-
- uses: actions/setup-node@v1
14-
with:
15-
node-version: "12.x"
12+
- uses: actions/checkout@v2
13+
- uses: actions/setup-node@v2
1614
- run: npm ci
1715
- run: npm run build
1816
- run: npx semantic-release

.github/workflows/test.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ jobs:
1111
test:
1212
runs-on: ubuntu-latest
1313
steps:
14-
- uses: actions/checkout@master
15-
- uses: actions/setup-node@v1
16-
with:
17-
node-version: 12
14+
- uses: actions/checkout@v2
15+
- uses: actions/setup-node@v2
1816
- run: npm ci
1917
- run: npm test

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,21 @@ import { Base } from "javascript-plugin-architecture-with-typescript-definitions
1515

1616
function myFooPlugin(instance: Base) {
1717
return {
18-
foo: () => "foo"
18+
foo: () => "foo",
1919
};
2020
}
2121

2222
function myBarPlugin(instance: Base) {
2323
return {
24-
bar: () => "bar"
24+
bar: () => "bar",
2525
};
2626
}
2727

2828
const FooTest = Base.plugin(myFooPlugin);
2929
const fooTest = new FooTest();
3030
fooTest.foo(); // has full TypeScript intellisense
3131

32-
const FooBarTest = Base.plugin([myFooPlugin, myBarPlugin]);
32+
const FooBarTest = Base.plugin(myFooPlugin, myBarPlugin);
3333
const fooBarTest = new FooBarTest();
3434
fooBarTest.foo(); // has full TypeScript intellisense
3535
fooBarTest.bar(); // has full TypeScript intellisense

src/index.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ type Constructor<T> = new (...args: any[]) => T;
1313
* @author https://stackoverflow.com/users/2887218/jcalz
1414
* @see https://stackoverflow.com/a/50375286/10325032
1515
*/
16-
type UnionToIntersection<Union> = (Union extends any
17-
? (argument: Union) => void
18-
: never) extends (argument: infer Intersection) => void // tslint:disable-line: no-unused
16+
type UnionToIntersection<Union> = (
17+
Union extends any ? (argument: Union) => void : never
18+
) extends (argument: infer Intersection) => void // tslint:disable-line: no-unused
1919
? Intersection
2020
: never;
2121

@@ -31,16 +31,23 @@ export class Base {
3131
static plugins: TestPlugin[] = [];
3232
static plugin<
3333
S extends Constructor<any> & { plugins: any[] },
34-
T extends TestPlugin | TestPlugin[]
35-
>(this: S, plugin: T) {
34+
T1 extends TestPlugin,
35+
T2 extends TestPlugin[]
36+
>(this: S, plugin1: T1, ...additionalPlugins: T2) {
3637
const currentPlugins = this.plugins;
38+
let newPlugins: (TestPlugin | undefined)[] = [
39+
plugin1,
40+
...additionalPlugins,
41+
];
3742

3843
const BaseWithPlugins = class extends this {
39-
static plugins = currentPlugins.concat(plugin);
44+
static plugins = currentPlugins.concat(
45+
newPlugins.filter((plugin) => !currentPlugins.includes(plugin))
46+
);
4047
};
4148

42-
type Extension = ReturnTypeOf<T>;
43-
return BaseWithPlugins as typeof BaseWithPlugins & Constructor<Extension>;
49+
return BaseWithPlugins as typeof BaseWithPlugins &
50+
Constructor<UnionToIntersection<ReturnTypeOf<T1> & ReturnTypeOf<T2>>>;
4451
}
4552

4653
static defaults<S extends Constructor<any>>(this: S, defaults: Options) {
@@ -59,7 +66,7 @@ export class Base {
5966
// apply plugins
6067
// https://stackoverflow.com/a/16345172
6168
const classConstructor = this.constructor as typeof Base;
62-
classConstructor.plugins.forEach(plugin => {
69+
classConstructor.plugins.forEach((plugin) => {
6370
Object.assign(this, plugin(this, options));
6471
});
6572
}

test.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,38 @@ const fooPlugin = (test: Base) => {
44
console.log("plugin evalutes");
55

66
return {
7-
foo: () => "foo"
7+
foo: () => "foo",
88
};
99
};
1010
const barPlugin = (test: Base) => {
1111
console.log("plugin evalutes");
1212

1313
return {
14-
bar: () => "bar"
14+
bar: () => "bar",
1515
};
1616
};
17+
const pluginWithEmptyObjectReturn = (test: Base) => {
18+
return {};
19+
};
1720

1821
describe("Base", () => {
1922
it(".plugin(fooPlugin)", () => {
2023
const FooTest = Base.plugin(fooPlugin);
2124
const fooTest = new FooTest();
2225
expect(fooTest.foo()).toEqual("foo");
2326
});
24-
it(".plugin([fooPlugin, barPlugin])", () => {
25-
const FooBarTest = Base.plugin([fooPlugin, barPlugin]);
27+
it(".plugin(fooPlugin, barPlugin)", () => {
28+
const FooBarTest = Base.plugin(fooPlugin, barPlugin);
29+
const fooBarTest = new FooBarTest();
30+
expect(fooBarTest.foo()).toEqual("foo");
31+
expect(fooBarTest.bar()).toEqual("bar");
32+
});
33+
it(".plugin(fooPlugin, barPlugin, pluginWithVoidReturn)", () => {
34+
const FooBarTest = Base.plugin(
35+
fooPlugin,
36+
barPlugin,
37+
pluginWithEmptyObjectReturn
38+
);
2639
const fooBarTest = new FooBarTest();
2740
expect(fooBarTest.foo()).toEqual("foo");
2841
expect(fooBarTest.bar()).toEqual("bar");
@@ -43,10 +56,10 @@ describe("Base", () => {
4356

4457
it(".plugin().defaults()", () => {
4558
const BaseWithPluginAndDefaults = Base.plugin(fooPlugin).defaults({
46-
baz: "daz"
59+
baz: "daz",
4760
});
4861
const BaseWithDefaultsAndPlugin = Base.defaults({
49-
baz: "daz"
62+
baz: "daz",
5063
}).plugin(fooPlugin);
5164

5265
const instance1 = new BaseWithPluginAndDefaults();

0 commit comments

Comments
 (0)