@serenityjs/plugins 0.2.3-beta-20240522190240 → 0.2.3-beta-20240522233103

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Logger } from '@serenityjs/logger';
2
+ import Emitter from '@serenityjs/emitter';
2
3
 
3
4
  /**
4
5
  * Represents a base plugin that can be loaded into the Serenity server.
@@ -29,17 +30,26 @@ declare abstract class BasePlugin<T = unknown> {
29
30
  shutdown(): void;
30
31
  }
31
32
 
33
+ interface PluginPackage {
34
+ name: string;
35
+ version: string;
36
+ main: string;
37
+ development: boolean;
38
+ scripts: {
39
+ build: string;
40
+ };
41
+ }
32
42
  interface Plugin {
33
43
  instance: BasePlugin;
34
- package: Record<string, unknown>;
44
+ typescript: boolean;
45
+ package: PluginPackage;
46
+ path: string;
35
47
  plugin: unknown;
36
48
  }
37
- interface tsconfig {
38
- compilerOptions: {
39
- outDir: string;
40
- };
49
+ interface PluginEvents {
50
+ register: [Plugin];
41
51
  }
42
- declare class Plugins<T> {
52
+ declare class Plugins<T> extends Emitter<PluginEvents> {
43
53
  /**
44
54
  * The serenity instance.
45
55
  */
@@ -53,18 +63,34 @@ declare class Plugins<T> {
53
63
  */
54
64
  readonly path: string;
55
65
  /**
56
- * The plugins map.
66
+ * A collection registry of all plugins.
57
67
  */
58
- readonly plugins: Map<string, Plugin>;
68
+ readonly entries: Map<string, Plugin>;
59
69
  /**
60
70
  * Constructs a new plugins instance.
61
71
  *
62
72
  * @param serenity - The serenity instance.
63
73
  */
64
74
  constructor(serenity: T, path: string, enabled?: boolean);
65
- loadNew(): Promise<void>;
66
- validatePackage(path: string, pack: Record<string, unknown>): boolean;
67
- validateTsconfig(path: string, tsconfig: tsconfig): boolean;
75
+ /**
76
+ * Get a plugin from the plugins map.
77
+ *
78
+ * @param name - The name of the plugin.
79
+ * @param version - The version of the plugin.
80
+ * @returns The plugin instance.
81
+ */
82
+ get<T = BasePlugin>(name: string, version?: string): T;
83
+ /**
84
+ * Get all the plugins from the plugins map.
85
+ */
86
+ getAll(): Array<BasePlugin>;
87
+ reload(name: string): void;
88
+ /**
89
+ * Start loading the plugins.
90
+ */
91
+ private start;
92
+ private validatePackage;
93
+ private validateTsconfig;
68
94
  }
69
95
 
70
96
  export { BasePlugin, Plugins };
package/dist/index.js CHANGED
@@ -74,7 +74,8 @@ var import_node_fs = require("fs");
74
74
  var import_node_path = require("path");
75
75
  var import_node_process = __toESM(require("process"));
76
76
  var import_logger = require("@serenityjs/logger");
77
- var Plugins = class {
77
+ var import_emitter = __toESM(require("@serenityjs/emitter"));
78
+ var Plugins = class extends import_emitter.default {
78
79
  /**
79
80
  * The serenity instance.
80
81
  */
@@ -88,28 +89,100 @@ var Plugins = class {
88
89
  */
89
90
  path;
90
91
  /**
91
- * The plugins map.
92
+ * A collection registry of all plugins.
92
93
  */
93
- plugins;
94
+ entries;
94
95
  /**
95
96
  * Constructs a new plugins instance.
96
97
  *
97
98
  * @param serenity - The serenity instance.
98
99
  */
99
100
  constructor(serenity, path, enabled = true) {
101
+ super();
100
102
  this.serenity = serenity;
101
103
  this.logger = new import_logger.Logger("Plugins", import_logger.LoggerColors.CyanBright);
102
104
  this.path = (0, import_node_path.resolve)(import_node_process.default.cwd(), path);
103
- this.plugins = /* @__PURE__ */ new Map();
105
+ this.entries = /* @__PURE__ */ new Map();
104
106
  if (enabled) {
105
107
  if (!(0, import_node_fs.existsSync)(this.path)) {
106
108
  (0, import_node_fs.mkdirSync)(this.path);
107
109
  this.logger.success(`Created plugins folder at "${this.path}"`);
108
110
  }
109
- void this.loadNew();
111
+ this.logger.info(`Attempting to load plugins from "${this.path}"`);
112
+ void this.start();
110
113
  }
111
114
  }
112
- async loadNew() {
115
+ /**
116
+ * Get a plugin from the plugins map.
117
+ *
118
+ * @param name - The name of the plugin.
119
+ * @param version - The version of the plugin.
120
+ * @returns The plugin instance.
121
+ */
122
+ get(name, version) {
123
+ const filtered = [...this.entries.values()].filter((plugin2) => {
124
+ return plugin2.package.name === name;
125
+ });
126
+ const plugin = filtered.find((plugin2) => {
127
+ return version ? plugin2.package.version === version : filtered[0];
128
+ });
129
+ if (!plugin) {
130
+ throw new Error(
131
+ `Plugin "${name}" with version "${version}" does not exist.`
132
+ );
133
+ }
134
+ return plugin.instance;
135
+ }
136
+ /**
137
+ * Get all the plugins from the plugins map.
138
+ */
139
+ getAll() {
140
+ const plugins = [...this.entries.values()].map((plugin) => {
141
+ return plugin.instance;
142
+ });
143
+ return plugins;
144
+ }
145
+ reload(name) {
146
+ const plugin = this.entries.get(name);
147
+ if (!plugin) {
148
+ throw new Error(`Plugin "${name}" does not exist.`);
149
+ }
150
+ plugin.instance.shutdown();
151
+ if (plugin.typescript) {
152
+ try {
153
+ if (plugin.package.scripts.build) {
154
+ (0, import_node_child_process.execSync)("npm run build", { cwd: plugin.path });
155
+ } else {
156
+ (0, import_node_child_process.execSync)("tsc", { cwd: plugin.path });
157
+ }
158
+ } catch (reason) {
159
+ this.logger.error(
160
+ `Failed to compile plugin "${name}" before reloading.`,
161
+ reason
162
+ );
163
+ return;
164
+ }
165
+ }
166
+ const path = require.resolve(plugin.path);
167
+ if (path) {
168
+ delete require.cache[path];
169
+ }
170
+ const pluginMain = require(`${(0, import_node_path.resolve)(plugin.path, plugin.package.main)}`);
171
+ if (!pluginMain.default) {
172
+ throw new Error(`Plugin "${name}" does not have a default export.`);
173
+ }
174
+ const pluginInstance = new pluginMain.default(
175
+ this.serenity,
176
+ new import_logger.Logger(`${name}@${plugin.package.version}`, import_logger.LoggerColors.Blue)
177
+ );
178
+ plugin.instance = pluginInstance;
179
+ this.emit("register", plugin);
180
+ this.logger.success(`Reloaded plugin "${name}".`);
181
+ }
182
+ /**
183
+ * Start loading the plugins.
184
+ */
185
+ async start() {
113
186
  const files = (0, import_node_fs.readdirSync)(this.path, { withFileTypes: true });
114
187
  for (const file of files) {
115
188
  if (!file.isDirectory())
@@ -134,7 +207,7 @@ var Plugins = class {
134
207
  );
135
208
  if (!needModules) {
136
209
  try {
137
- (0, import_node_child_process.execSync)("npm install", { cwd: (0, import_node_path.resolve)(file.path, file.name) });
210
+ (0, import_node_child_process.execSync)("npm install", { cwd: import_node_process.default.cwd() });
138
211
  } catch (reason) {
139
212
  this.logger.error(
140
213
  `Failed to install node_modules for plugin "${file.name}".`,
@@ -171,14 +244,22 @@ var Plugins = class {
171
244
  }
172
245
  }
173
246
  try {
174
- const plugin = await import(`file://${(0, import_node_path.resolve)(file.path, file.name, pack.main)}`);
247
+ const plugin = require(`${(0, import_node_path.resolve)(file.path, file.name, pack.main)}`);
175
248
  if (!plugin.default)
176
249
  continue;
177
250
  const instance = new plugin.default(
178
251
  this.serenity,
179
252
  new import_logger.Logger(`${file.name}@${pack.version}`, import_logger.LoggerColors.Blue)
180
253
  );
181
- this.plugins.set(file.name, { instance, package: pack, plugin });
254
+ const pluginEntry = {
255
+ instance,
256
+ typescript: Boolean(typescript),
257
+ package: pack,
258
+ path: (0, import_node_path.resolve)(file.path, file.name),
259
+ plugin
260
+ };
261
+ this.entries.set(file.name, pluginEntry);
262
+ this.emit("register", pluginEntry);
182
263
  } catch (reason) {
183
264
  this.logger.error(`Failed to import plugin "${file.name}".`, reason);
184
265
  continue;
@@ -203,9 +284,9 @@ var Plugins = class {
203
284
  `Plugin package.json "${path}" does not contain a "type" property.`
204
285
  );
205
286
  return false;
206
- } else if (pack.type !== "module") {
287
+ } else if (pack.type !== "commonjs") {
207
288
  this.logger.error(
208
- `Plugin package.json "${path}" type is not set to "module".`
289
+ `Plugin package.json "${path}" type is not set to "commonjs".`
209
290
  );
210
291
  return false;
211
292
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serenityjs/plugins",
3
- "version": "0.2.3-beta-20240522190240",
3
+ "version": "0.2.3-beta-20240522233103",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "repository": "https://github.com/SerenityJS/serenity",
@@ -18,9 +18,9 @@
18
18
  "preset": "@serenityjs/jest-presets/jest/node"
19
19
  },
20
20
  "devDependencies": {
21
- "@serenityjs/eslint-config": "0.2.3-beta-20240522190240",
22
- "@serenityjs/jest-presets": "0.2.3-beta-20240522190240",
23
- "@serenityjs/typescript-config": "0.2.3-beta-20240522190240",
21
+ "@serenityjs/eslint-config": "0.2.3-beta-20240522233103",
22
+ "@serenityjs/jest-presets": "0.2.3-beta-20240522233103",
23
+ "@serenityjs/typescript-config": "0.2.3-beta-20240522233103",
24
24
  "@types/jest": "^29.5.12",
25
25
  "@types/node": "^20.11.24",
26
26
  "jest": "^29.7.0",
@@ -28,6 +28,7 @@
28
28
  "typescript": "^5.4.2"
29
29
  },
30
30
  "dependencies": {
31
- "@serenityjs/logger": "0.2.3-beta-20240522190240"
31
+ "@serenityjs/emitter": "0.2.3-beta-20240522233103",
32
+ "@serenityjs/logger": "0.2.3-beta-20240522233103"
32
33
  }
33
34
  }