|
5 | 5 | [](https://www.npmjs.com/package/javascript-plugin-architecture-with-typescript-definitions)
|
6 | 6 | [](https://github.com/gr2m/javascript-plugin-architecture-with-typescript-definitions/actions/workflows/test.yml)
|
7 | 7 |
|
8 |
| -The goal of this repository is to provide a template of a simple plugin Architecture which allows plugins to be created and authored as separate npm modules and shared as official or 3rd party plugins. It also permits the plugins to extend the types for the constructor options. |
| 8 | +The goal of this repository is to provide a template for a simple plugin Architecture which allows plugin authors to extend the base API as well as extend its constructor options. A custom class can be composed of the core Base class, a set of plugins and default options and distributed as new package, with full TypeScript for added APIs and constructor options. |
9 | 9 |
|
10 | 10 | ## Usage
|
11 | 11 |
|
12 |
| -[Try it in TypeScript's playground editor](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgIQIYGcCmcC+cBmUEIcARAFaoBuGAxlMGDALRgA2ArgObAB2zqKLQAWwGJlowOUTMwDuY4cxgBPMJnT1GLACaZ8fMcAi90pANwAoS-g69Jx3nBAqAYhAgAFTj14AKPnQYVHtMAC4UDEwASkRLODgZKSgnBHiEgg8Iv1iAXgA+MnwPUgAadJwrHGtbexhHZxU0KG9uPgDTYNCItCxYtISk6VT0hIAjQWy8wtIJqDKKqpq7BxM4DCxYAGUYBl4uP3QOMfIJGAigva5+6staEyC4dwgAFQ14XMisADoFGGFWr50H4ANouZ6AvgAXWiVnunUyr3ecE+vEwcieHjeQRyVg2mG2uz4B2KSKC31JOVh1nhj2ezWxHy+mF+ikhplB4I87NKjWa7JhcIe8FJDORqPRmIgYpx1PxhKuflFgkZFI8VLx6E2MB2iuVUFVcw1QA) |
| 12 | +[Try it in TypeScript's playground editor](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgIQIYGcCmcC+cBmUEIcARAFaoBuGAxlMGDALRgA2ArgObAB2zqKLQAWwGJlowOUTMwDuY4cxgBPMJnT1GLACaZ8fMcAi90pANwAoS3tptB2EBB0c22CtToMmrTj36CImISUjLyispqGlo+ega8RiZmiJZwcLyoIBpgqLTYaFgpaWl84lD4udgA8kzGpkXFafgQEABccOgwDLxcVo04qbiWA5b4HLySdXAgKgBiLQAKfnwAFHydqBOY7QWYADRwELVJOxiYAHQ1MHXoAJQNMqG8DU0t7Sv3ALwAfIfHpudmhA4AAfEFkABGglIe0GOCsIzGE2uJmmKjQUCW3FW6xgmzypyw9wQg0e0meJMaUKg7y+v1I1JhcIR1loSXgAFl0Wc4J8UGdzgoYMIsf50CsANozeYQUV8A4zDFy3gAXVugsUABF9KhXDBxZSCG9IdDYThblZLGzTPBFTy+bxMHI4FzdiskED2gzUAAvUi4C2WO1YQEtD7mOAAekjHS6fC4Qe5Iep4ajMc63QTQA) |
| 13 | + |
| 14 | +### Export new class `MyBase` with two plugins and default options: |
13 | 15 |
|
14 | 16 | ```ts
|
| 17 | +// import the Base class |
15 | 18 | import { Base } from "javascript-plugin-architecture-with-typescript-definitions";
|
16 | 19 |
|
17 |
| -function myFooPlugin(instance: Base) { |
18 |
| - return { |
19 |
| - foo: () => "foo", |
20 |
| - }; |
21 |
| -} |
| 20 | +// import a set of plugins |
| 21 | +import { myFooPlugin } from "@example/my-foo-plugin"; |
| 22 | +import { myBarPlugin } from "./my-bar-plugin"; |
22 | 23 |
|
23 |
| -function myBarPlugin(instance: Base) { |
24 |
| - return { |
25 |
| - bar: () => "bar", |
26 |
| - }; |
27 |
| -} |
| 24 | +export const MyBase = Base.withPlugins([myFooPlugin, myBarPlugin]).withDefaults( |
| 25 | + { |
| 26 | + foo: "bar", |
| 27 | + } |
| 28 | +); |
| 29 | +``` |
28 | 30 |
|
29 |
| -const FooTest = Base.withPlugins([myFooPlugin]); |
30 |
| -const fooTest = new FooTest(); |
31 |
| -fooTest.foo(); // has full TypeScript intellisense |
| 31 | +When importing `MyBase` and instantiating it, the `MyBase` constructor has type support for the new optional `foo` option as well as the `.foo()` and `.bar()` methods addded by the respective plugins. |
32 | 32 |
|
33 |
| -const FooBarTest = Base.withPlugins([myFooPlugin, myBarPlugin]); |
34 |
| -const fooBarTest = new FooBarTest(); |
35 |
| -fooBarTest.foo(); // has full TypeScript intellisense |
36 |
| -fooBarTest.bar(); // has full TypeScript intellisense |
| 33 | +```ts |
| 34 | +import { MyBase } from "@example/my-base"; |
| 35 | + |
| 36 | +const myBase = new MyBase({ |
| 37 | + // has full TypeScript intellisense |
| 38 | + foo: "bar", |
| 39 | +}); |
| 40 | +myBase.foo(); // has full TypeScript intellisense |
| 41 | +myBase.bar(); // has full TypeScript intellisense |
37 | 42 | ```
|
38 | 43 |
|
39 |
| -The constructor accepts an optional `options` object which is passed to the plugins as second argument and stored in `instance.options`. Default options can be set using `Base.withDefaults(options)`. |
| 44 | +### Create plugin which extends the API as well as the constructor options type |
40 | 45 |
|
41 | 46 | ```js
|
42 |
| -const BaseWithOptions = Base.withDefaults({ foo: "bar" }); |
43 |
| -const instance = new BaseWithOptions(); |
44 |
| -instance.options; // {foo: 'bar'} |
45 |
| -``` |
46 |
| - |
47 |
| -Note that in for TypeScript to recognize the new option, you have to extend the `Base.Option` intererface. |
| 47 | +import { Base } from "javascript-plugin-architecture-with-typescript-definitions"; |
48 | 48 |
|
49 |
| -```ts |
50 | 49 | declare module "javascript-plugin-architecture-with-typescript-definitions" {
|
51 | 50 | namespace Base {
|
52 | 51 | interface Options {
|
53 |
| - foo: string; |
| 52 | + foo?: string; |
54 | 53 | }
|
55 | 54 | }
|
56 | 55 | }
|
| 56 | + |
| 57 | +export function myFooPlugin(base: Base, options: Base.options) { |
| 58 | + return { |
| 59 | + foo() => options.foo || "bar", |
| 60 | + } |
| 61 | +} |
57 | 62 | ```
|
58 | 63 |
|
59 |
| -See also the [`required-options` example](examples/required-options). |
| 64 | +## API |
| 65 | + |
| 66 | +### static `.withPlugins(plugins)` |
| 67 | + |
| 68 | +Returns a new class with `.plugins` added to parent classes `.plugins` array. All plugins will be applied to instances. |
| 69 | + |
| 70 | +### static `.withDefaults(options)` |
60 | 71 |
|
61 |
| -The `Base` class also has two static properties |
| 72 | +Returns a new class with `.defaults` merged with the parent classes `.defaults` object. The defaults are applied to the options passed to the constructor when instantiated. |
62 | 73 |
|
63 |
| -- `.defaults`: the default options for all instances |
64 |
| -- `.plugins`: the list of plugins applied to all instances |
| 74 | +### static `.plugins` |
65 | 75 |
|
66 |
| -When creating a new class with `.withPlugins()` and `.defaults()`, the static properties of the returned class are set accordingly. |
| 76 | +`Base.plugins` is an empty array by default. It is extended on derived classes using `.withPlugins(plugins)`. |
| 77 | + |
| 78 | +### static `.defaults` |
| 79 | + |
| 80 | +`Base.defaults` is an empty object by default. It is extended on derived classes using `.withDefaults(plugins)`. |
| 81 | + |
| 82 | +### Constructor |
| 83 | + |
| 84 | +The constructor accepts one argument which is optional by default |
| 85 | + |
| 86 | +```ts |
| 87 | +new Base(options); |
| 88 | +``` |
| 89 | + |
| 90 | +If the `Base.Options` interface has been extended with required keys, then the `options` argument becomes required, and all required `Base.Options` keys must be set. |
| 91 | + |
| 92 | +### `.options` |
| 93 | + |
| 94 | +The `.options` key is set on all instances. It's merged from from the constructor's `.defaults` object and the options passed to the constructor |
67 | 95 |
|
68 | 96 | ```js
|
69 |
| -const MyBase = Base.withDefaults({ foo: "bar" }); |
| 97 | +const BaseWithOptions = Base.withDefaults({ foo: "bar" }); |
| 98 | +const instance = new BaseWithOptions(); |
| 99 | +instance.options; // {foo: 'bar'} |
| 100 | +``` |
| 101 | + |
| 102 | +Note that in for TypeScript to recognize the new option, you have to extend the `Base.Option` intererface. |
| 103 | + |
| 104 | +### Other instance propreties and methods |
| 105 | + |
| 106 | +Instance properties and methods can be added using plugins. Example: |
| 107 | + |
| 108 | +```ts |
| 109 | +function myPlugin(base: Base, options: Base.options) { |
| 110 | + return { |
| 111 | + myMethod() { |
| 112 | + /* do something here */ |
| 113 | + }, |
| 114 | + myProperty: "", // set to something useful |
| 115 | + }; |
| 116 | +} |
| 117 | +const MyBase = Base.plugins([myPlugin]); |
| 118 | +const myBase = new MyBase(); |
| 119 | + |
| 120 | +// this method and property is now set |
| 121 | +myBase.myMethod(); |
| 122 | +myBase.myProperty; |
70 | 123 | ```
|
71 | 124 |
|
72 | 125 | ### Defaults
|
|
0 commit comments