jtcsv 2.2.8 → 3.1.0
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/README.md +204 -115
- package/bin/jtcsv.ts +2612 -0
- package/browser.d.ts +142 -0
- package/dist/benchmark.js +446 -0
- package/dist/benchmark.js.map +1 -0
- package/dist/bin/jtcsv.js +1940 -0
- package/dist/bin/jtcsv.js.map +1 -0
- package/dist/csv-to-json.js +1262 -0
- package/dist/csv-to-json.js.map +1 -0
- package/dist/errors.js +291 -0
- package/dist/errors.js.map +1 -0
- package/dist/eslint.config.js +147 -0
- package/dist/eslint.config.js.map +1 -0
- package/dist/index-core.js +95 -0
- package/dist/index-core.js.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/json-save.js +229 -0
- package/dist/json-save.js.map +1 -0
- package/dist/json-to-csv.js +576 -0
- package/dist/json-to-csv.js.map +1 -0
- package/dist/jtcsv-core.cjs.js +1736 -0
- package/dist/jtcsv-core.cjs.js.map +1 -0
- package/dist/jtcsv-core.esm.js +1708 -0
- package/dist/jtcsv-core.esm.js.map +1 -0
- package/dist/jtcsv-core.umd.js +1742 -0
- package/dist/jtcsv-core.umd.js.map +1 -0
- package/dist/jtcsv-full.cjs.js +2241 -0
- package/dist/jtcsv-full.cjs.js.map +1 -0
- package/dist/jtcsv-full.esm.js +2209 -0
- package/dist/jtcsv-full.esm.js.map +1 -0
- package/dist/jtcsv-full.umd.js +2247 -0
- package/dist/jtcsv-full.umd.js.map +1 -0
- package/dist/jtcsv-workers.esm.js +768 -0
- package/dist/jtcsv-workers.esm.js.map +1 -0
- package/dist/jtcsv-workers.umd.js +782 -0
- package/dist/jtcsv-workers.umd.js.map +1 -0
- package/dist/jtcsv.cjs.js +1996 -2048
- package/dist/jtcsv.cjs.js.map +1 -1
- package/dist/jtcsv.esm.js +1992 -2048
- package/dist/jtcsv.esm.js.map +1 -1
- package/dist/jtcsv.umd.js +2157 -2209
- package/dist/jtcsv.umd.js.map +1 -1
- package/dist/plugins/express-middleware/index.js +350 -0
- package/dist/plugins/express-middleware/index.js.map +1 -0
- package/dist/plugins/fastify-plugin/index.js +315 -0
- package/dist/plugins/fastify-plugin/index.js.map +1 -0
- package/dist/plugins/hono/index.js +111 -0
- package/dist/plugins/hono/index.js.map +1 -0
- package/dist/plugins/nestjs/index.js +112 -0
- package/dist/plugins/nestjs/index.js.map +1 -0
- package/dist/plugins/nuxt/index.js +53 -0
- package/dist/plugins/nuxt/index.js.map +1 -0
- package/dist/plugins/remix/index.js +133 -0
- package/dist/plugins/remix/index.js.map +1 -0
- package/dist/plugins/sveltekit/index.js +155 -0
- package/dist/plugins/sveltekit/index.js.map +1 -0
- package/dist/plugins/trpc/index.js +136 -0
- package/dist/plugins/trpc/index.js.map +1 -0
- package/dist/run-demo.js +49 -0
- package/dist/run-demo.js.map +1 -0
- package/dist/src/browser/browser-functions.js +193 -0
- package/dist/src/browser/browser-functions.js.map +1 -0
- package/dist/src/browser/core.js +123 -0
- package/dist/src/browser/core.js.map +1 -0
- package/dist/src/browser/csv-to-json-browser.js +353 -0
- package/dist/src/browser/csv-to-json-browser.js.map +1 -0
- package/dist/src/browser/errors-browser.js +219 -0
- package/dist/src/browser/errors-browser.js.map +1 -0
- package/dist/src/browser/extensions/plugins.js +106 -0
- package/dist/src/browser/extensions/plugins.js.map +1 -0
- package/dist/src/browser/extensions/workers.js +66 -0
- package/dist/src/browser/extensions/workers.js.map +1 -0
- package/dist/src/browser/index.js +140 -0
- package/dist/src/browser/index.js.map +1 -0
- package/dist/src/browser/json-to-csv-browser.js +225 -0
- package/dist/src/browser/json-to-csv-browser.js.map +1 -0
- package/dist/src/browser/streams.js +340 -0
- package/dist/src/browser/streams.js.map +1 -0
- package/dist/src/browser/workers/csv-parser.worker.js +264 -0
- package/dist/src/browser/workers/csv-parser.worker.js.map +1 -0
- package/dist/src/browser/workers/worker-pool.js +338 -0
- package/dist/src/browser/workers/worker-pool.js.map +1 -0
- package/dist/src/core/delimiter-cache.js +196 -0
- package/dist/src/core/delimiter-cache.js.map +1 -0
- package/dist/src/core/node-optimizations.js +279 -0
- package/dist/src/core/node-optimizations.js.map +1 -0
- package/dist/src/core/plugin-system.js +399 -0
- package/dist/src/core/plugin-system.js.map +1 -0
- package/dist/src/core/transform-hooks.js +348 -0
- package/dist/src/core/transform-hooks.js.map +1 -0
- package/dist/src/engines/fast-path-engine-new.js +262 -0
- package/dist/src/engines/fast-path-engine-new.js.map +1 -0
- package/dist/src/engines/fast-path-engine.js +671 -0
- package/dist/src/engines/fast-path-engine.js.map +1 -0
- package/dist/src/errors.js +18 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/formats/ndjson-parser.js +332 -0
- package/dist/src/formats/ndjson-parser.js.map +1 -0
- package/dist/src/formats/tsv-parser.js +230 -0
- package/dist/src/formats/tsv-parser.js.map +1 -0
- package/dist/src/index-with-plugins.js +259 -0
- package/dist/src/index-with-plugins.js.map +1 -0
- package/dist/src/types/index.js +3 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/utils/bom-utils.js +267 -0
- package/dist/src/utils/bom-utils.js.map +1 -0
- package/dist/src/utils/encoding-support.js +77 -0
- package/dist/src/utils/encoding-support.js.map +1 -0
- package/dist/src/utils/schema-validator.js +609 -0
- package/dist/src/utils/schema-validator.js.map +1 -0
- package/dist/src/utils/transform-loader.js +281 -0
- package/dist/src/utils/transform-loader.js.map +1 -0
- package/dist/src/utils/validators.js +40 -0
- package/dist/src/utils/validators.js.map +1 -0
- package/dist/src/utils/zod-adapter.js +144 -0
- package/dist/src/utils/zod-adapter.js.map +1 -0
- package/dist/src/web-server/index.js +648 -0
- package/dist/src/web-server/index.js.map +1 -0
- package/dist/src/workers/csv-multithreaded.js +211 -0
- package/dist/src/workers/csv-multithreaded.js.map +1 -0
- package/dist/src/workers/csv-parser.worker.js +179 -0
- package/dist/src/workers/csv-parser.worker.js.map +1 -0
- package/dist/src/workers/worker-pool.js +228 -0
- package/dist/src/workers/worker-pool.js.map +1 -0
- package/dist/stream-csv-to-json.js +665 -0
- package/dist/stream-csv-to-json.js.map +1 -0
- package/dist/stream-json-to-csv.js +389 -0
- package/dist/stream-json-to-csv.js.map +1 -0
- package/examples/advanced/conditional-transformations.ts +446 -0
- package/examples/advanced/csv-parser.worker.ts +89 -0
- package/examples/advanced/nested-objects-example.ts +306 -0
- package/examples/advanced/performance-optimization.ts +504 -0
- package/examples/advanced/run-demo-server.ts +116 -0
- package/examples/advanced/web-worker-usage.html +874 -0
- package/examples/async-multithreaded-example.ts +335 -0
- package/examples/cli-advanced-usage.md +290 -0
- package/examples/{cli-batch-processing.js → cli-batch-processing.ts} +38 -38
- package/examples/{cli-tool.js → cli-tool.ts} +5 -8
- package/examples/{error-handling.js → error-handling.ts} +356 -324
- package/examples/{express-api.js → express-api.ts} +161 -164
- package/examples/{large-dataset-example.js → large-dataset-example.ts} +201 -182
- package/examples/{ndjson-processing.js → ndjson-processing.ts} +456 -434
- package/examples/{plugin-excel-exporter.js → plugin-excel-exporter.ts} +6 -7
- package/examples/react-integration.tsx +637 -0
- package/examples/{schema-validation.js → schema-validation.ts} +2 -2
- package/examples/simple-usage.ts +194 -0
- package/examples/{streaming-example.js → streaming-example.ts} +12 -12
- package/index.d.ts +187 -18
- package/package.json +75 -81
- package/plugins.d.ts +37 -0
- package/schema.d.ts +103 -0
- package/src/browser/browser-functions.ts +402 -0
- package/src/browser/core.ts +152 -0
- package/src/browser/csv-to-json-browser.d.ts +3 -0
- package/src/browser/csv-to-json-browser.ts +494 -0
- package/src/browser/{errors-browser.js → errors-browser.ts} +305 -197
- package/src/browser/extensions/plugins.ts +93 -0
- package/src/browser/extensions/workers.ts +39 -0
- package/src/browser/globals.d.ts +5 -0
- package/src/browser/index.ts +192 -0
- package/src/browser/json-to-csv-browser.d.ts +3 -0
- package/src/browser/json-to-csv-browser.ts +338 -0
- package/src/browser/streams.ts +403 -0
- package/src/browser/workers/{csv-parser.worker.js → csv-parser.worker.ts} +3 -3
- package/src/browser/workers/{worker-pool.js → worker-pool.ts} +51 -30
- package/src/core/delimiter-cache.ts +320 -0
- package/src/core/{node-optimizations.js → node-optimizations.ts} +448 -407
- package/src/core/plugin-system.ts +588 -0
- package/src/core/transform-hooks.ts +566 -0
- package/src/engines/{fast-path-engine-new.js → fast-path-engine-new.ts} +11 -2
- package/src/engines/{fast-path-engine.js → fast-path-engine.ts} +79 -53
- package/src/errors.ts +1 -0
- package/src/formats/{ndjson-parser.js → ndjson-parser.ts} +24 -16
- package/src/formats/{tsv-parser.js → tsv-parser.ts} +18 -17
- package/src/{index-with-plugins.js → index-with-plugins.ts} +381 -357
- package/src/types/index.ts +275 -0
- package/src/utils/bom-utils.ts +373 -0
- package/src/utils/encoding-support.ts +155 -0
- package/src/utils/{schema-validator.js → schema-validator.ts} +814 -589
- package/src/utils/transform-loader.ts +389 -0
- package/src/utils/validators.ts +35 -0
- package/src/utils/zod-adapter.ts +280 -0
- package/src/web-server/{index.js → index.ts} +19 -19
- package/src/workers/csv-multithreaded.ts +310 -0
- package/src/workers/csv-parser.worker.ts +227 -0
- package/src/workers/worker-pool.ts +409 -0
- package/bin/jtcsv.js +0 -2462
- package/csv-to-json.js +0 -688
- package/errors.js +0 -208
- package/examples/simple-usage.js +0 -282
- package/index.js +0 -68
- package/json-save.js +0 -254
- package/json-to-csv.js +0 -526
- package/plugins/README.md +0 -91
- package/plugins/express-middleware/README.md +0 -64
- package/plugins/express-middleware/example.js +0 -136
- package/plugins/express-middleware/index.d.ts +0 -114
- package/plugins/express-middleware/index.js +0 -360
- package/plugins/express-middleware/package.json +0 -52
- package/plugins/fastify-plugin/index.js +0 -406
- package/plugins/fastify-plugin/package.json +0 -55
- package/plugins/hono/README.md +0 -28
- package/plugins/hono/index.d.ts +0 -12
- package/plugins/hono/index.js +0 -36
- package/plugins/hono/package.json +0 -35
- package/plugins/nestjs/README.md +0 -35
- package/plugins/nestjs/index.d.ts +0 -25
- package/plugins/nestjs/index.js +0 -77
- package/plugins/nestjs/package.json +0 -37
- package/plugins/nextjs-api/README.md +0 -57
- package/plugins/nextjs-api/examples/ConverterComponent.jsx +0 -386
- package/plugins/nextjs-api/examples/api-convert.js +0 -69
- package/plugins/nextjs-api/index.js +0 -387
- package/plugins/nextjs-api/package.json +0 -63
- package/plugins/nextjs-api/route.js +0 -371
- package/plugins/nuxt/README.md +0 -24
- package/plugins/nuxt/index.js +0 -21
- package/plugins/nuxt/package.json +0 -35
- package/plugins/nuxt/runtime/composables/useJtcsv.js +0 -6
- package/plugins/nuxt/runtime/plugin.js +0 -6
- package/plugins/remix/README.md +0 -26
- package/plugins/remix/index.d.ts +0 -16
- package/plugins/remix/index.js +0 -62
- package/plugins/remix/package.json +0 -35
- package/plugins/sveltekit/README.md +0 -28
- package/plugins/sveltekit/index.d.ts +0 -17
- package/plugins/sveltekit/index.js +0 -54
- package/plugins/sveltekit/package.json +0 -33
- package/plugins/trpc/README.md +0 -25
- package/plugins/trpc/index.d.ts +0 -7
- package/plugins/trpc/index.js +0 -32
- package/plugins/trpc/package.json +0 -34
- package/src/browser/browser-functions.js +0 -219
- package/src/browser/csv-to-json-browser.js +0 -700
- package/src/browser/index.js +0 -113
- package/src/browser/json-to-csv-browser.js +0 -309
- package/src/browser/streams.js +0 -393
- package/src/core/delimiter-cache.js +0 -186
- package/src/core/plugin-system.js +0 -476
- package/src/core/transform-hooks.js +0 -350
- package/src/errors.js +0 -26
- package/src/utils/transform-loader.js +0 -205
- package/stream-csv-to-json.js +0 -542
- package/stream-json-to-csv.js +0 -464
- /package/examples/{web-workers-advanced.js → web-workers-advanced.ts} +0 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PluginManager = void 0;
|
|
4
|
+
exports.getGlobalPluginManager = getGlobalPluginManager;
|
|
5
|
+
exports.getGlobalPluginManagerAsync = getGlobalPluginManagerAsync;
|
|
6
|
+
const SLOW_HOOK_THRESHOLD_MS = 100;
|
|
7
|
+
class PluginManager {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.plugins = new Map();
|
|
10
|
+
this.hooks = new Map();
|
|
11
|
+
this.middlewares = [];
|
|
12
|
+
this.context = {};
|
|
13
|
+
this.stats = {
|
|
14
|
+
pluginLoads: 0,
|
|
15
|
+
hookExecutions: 0,
|
|
16
|
+
middlewareExecutions: 0
|
|
17
|
+
};
|
|
18
|
+
this._registerDefaultHooks();
|
|
19
|
+
}
|
|
20
|
+
use(name, plugin) {
|
|
21
|
+
this.registerPlugin(name, plugin);
|
|
22
|
+
}
|
|
23
|
+
_registerDefaultHooks() {
|
|
24
|
+
const defaultHooks = [
|
|
25
|
+
'before:csvToJson',
|
|
26
|
+
'after:csvToJson',
|
|
27
|
+
'before:jsonToCsv',
|
|
28
|
+
'after:jsonToCsv',
|
|
29
|
+
'before:parse',
|
|
30
|
+
'after:parse',
|
|
31
|
+
'before:serialize',
|
|
32
|
+
'after:serialize',
|
|
33
|
+
'error',
|
|
34
|
+
'validation',
|
|
35
|
+
'transformation'
|
|
36
|
+
];
|
|
37
|
+
defaultHooks.forEach(hook => {
|
|
38
|
+
this.hooks.set(hook, []);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
registerPlugin(name, plugin) {
|
|
42
|
+
if (!plugin || typeof plugin !== 'object' || !plugin.name || !plugin.version) {
|
|
43
|
+
throw new Error('Plugin должен иметь name и version');
|
|
44
|
+
}
|
|
45
|
+
if (this.plugins.has(name)) {
|
|
46
|
+
throw new Error(`Plugin "${name}" уже зарегистрирован`);
|
|
47
|
+
}
|
|
48
|
+
if (plugin.hooks && (typeof plugin.hooks !== 'object' || Array.isArray(plugin.hooks))) {
|
|
49
|
+
throw new Error('hooks must be an object');
|
|
50
|
+
}
|
|
51
|
+
if (plugin.hooks) {
|
|
52
|
+
for (const [hookName, handler] of Object.entries(plugin.hooks)) {
|
|
53
|
+
if (typeof handler !== 'function') {
|
|
54
|
+
throw new Error(`Hook handler for "${hookName}" must be a function`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (plugin.middlewares && !Array.isArray(plugin.middlewares)) {
|
|
59
|
+
throw new Error('middlewares must be an array');
|
|
60
|
+
}
|
|
61
|
+
if (plugin.middlewares) {
|
|
62
|
+
plugin.middlewares.forEach((middleware, index) => {
|
|
63
|
+
if (typeof middleware !== 'function') {
|
|
64
|
+
throw new Error(`Middleware ${index} must be a function`);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const record = {
|
|
69
|
+
id: name,
|
|
70
|
+
enabled: true,
|
|
71
|
+
...plugin
|
|
72
|
+
};
|
|
73
|
+
this.plugins.set(name, record);
|
|
74
|
+
this.stats.pluginLoads++;
|
|
75
|
+
if (plugin.hooks) {
|
|
76
|
+
Object.entries(plugin.hooks).forEach(([hookName, handler]) => {
|
|
77
|
+
this.registerHook(hookName, handler, name);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (plugin.middlewares) {
|
|
81
|
+
plugin.middlewares.forEach(middleware => {
|
|
82
|
+
this.registerMiddleware(middleware, name);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (plugin.init) {
|
|
86
|
+
plugin.init(this);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
registerHook(hookName, handler, pluginName) {
|
|
90
|
+
if (typeof handler != 'function') {
|
|
91
|
+
throw new Error('Hook handler must be a function');
|
|
92
|
+
}
|
|
93
|
+
if (!this.hooks.has(hookName)) {
|
|
94
|
+
this.hooks.set(hookName, []);
|
|
95
|
+
}
|
|
96
|
+
const handlers = this.hooks.get(hookName);
|
|
97
|
+
handlers.push({
|
|
98
|
+
handler,
|
|
99
|
+
pluginName,
|
|
100
|
+
executionCount: 0
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
registerMiddleware(middleware, pluginName) {
|
|
104
|
+
if (typeof middleware !== 'function') {
|
|
105
|
+
throw new Error('Middleware must be a function');
|
|
106
|
+
}
|
|
107
|
+
this.middlewares.push({
|
|
108
|
+
handler: middleware,
|
|
109
|
+
pluginName,
|
|
110
|
+
executionCount: 0
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
_isPluginEnabled(pluginName) {
|
|
114
|
+
if (!pluginName) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
const plugin = this.plugins.get(pluginName);
|
|
118
|
+
if (!plugin) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
return plugin.enabled !== false;
|
|
122
|
+
}
|
|
123
|
+
_runErrorHooks(error, context) {
|
|
124
|
+
const errorHandlers = this.hooks.get('error');
|
|
125
|
+
if (!errorHandlers || errorHandlers.length == 0) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
for (const handlerEntry of errorHandlers) {
|
|
129
|
+
try {
|
|
130
|
+
handlerEntry.handler(error, context);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async executeHook(hookName, data, context = {}) {
|
|
137
|
+
const handlers = this.hooks.get(hookName);
|
|
138
|
+
if (!handlers || handlers.length === 0) {
|
|
139
|
+
return data;
|
|
140
|
+
}
|
|
141
|
+
let result = data;
|
|
142
|
+
let executed = false;
|
|
143
|
+
for (const handlerEntry of handlers) {
|
|
144
|
+
if (!this._isPluginEnabled(handlerEntry.pluginName)) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
executed = true;
|
|
148
|
+
const startTime = Date.now();
|
|
149
|
+
try {
|
|
150
|
+
result = await handlerEntry.handler(result, { ...this.context, ...context, hookName, plugin: handlerEntry.pluginName });
|
|
151
|
+
handlerEntry.executionCount++;
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
this._runErrorHooks(error, { ...this.context, ...context, hookName, data: result });
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
const duration = Date.now() - startTime;
|
|
158
|
+
if (duration > SLOW_HOOK_THRESHOLD_MS) {
|
|
159
|
+
console.warn(`Slow hook "${hookName}" detected (${duration}ms)`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (executed) {
|
|
164
|
+
this.stats.hookExecutions++;
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
async executeHooks(hookName, data, context = {}) {
|
|
169
|
+
return this.executeHook(hookName, data, context);
|
|
170
|
+
}
|
|
171
|
+
async executeWithPlugins(operation, input, options, handler) {
|
|
172
|
+
const metadata = options && options.metadata ? options.metadata : {};
|
|
173
|
+
const context = { operation, options, metadata };
|
|
174
|
+
const beforeHook = `before:${operation}`;
|
|
175
|
+
const afterHook = `after:${operation}`;
|
|
176
|
+
const beforeInput = await this.executeHook(beforeHook, input, context);
|
|
177
|
+
const middlewareContext = {
|
|
178
|
+
input: beforeInput,
|
|
179
|
+
options,
|
|
180
|
+
operation,
|
|
181
|
+
metadata
|
|
182
|
+
};
|
|
183
|
+
const resultHolder = { set: false, value: undefined };
|
|
184
|
+
try {
|
|
185
|
+
await this.executeMiddlewares(middlewareContext, context, async (ctx) => {
|
|
186
|
+
const handlerInput = ctx && Object.prototype.hasOwnProperty.call(ctx, 'input')
|
|
187
|
+
? ctx.input
|
|
188
|
+
: beforeInput;
|
|
189
|
+
const result = await handler(handlerInput, options);
|
|
190
|
+
ctx.result = result;
|
|
191
|
+
resultHolder.set = true;
|
|
192
|
+
resultHolder.value = result;
|
|
193
|
+
return result;
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
this._runErrorHooks(error, { ...this.context, ...context, data: beforeInput });
|
|
198
|
+
throw error;
|
|
199
|
+
}
|
|
200
|
+
const finalResult = resultHolder.set
|
|
201
|
+
? resultHolder.value
|
|
202
|
+
: (Object.prototype.hasOwnProperty.call(middlewareContext, 'result') ? middlewareContext.result : undefined);
|
|
203
|
+
return this.executeHook(afterHook, finalResult, context);
|
|
204
|
+
}
|
|
205
|
+
listPlugins() {
|
|
206
|
+
return Array.from(this.plugins.values()).map((plugin) => ({
|
|
207
|
+
id: plugin.id,
|
|
208
|
+
pluginName: plugin.name,
|
|
209
|
+
version: plugin.version,
|
|
210
|
+
description: plugin.description,
|
|
211
|
+
enabled: plugin.enabled
|
|
212
|
+
}));
|
|
213
|
+
}
|
|
214
|
+
listHooks() {
|
|
215
|
+
const result = {};
|
|
216
|
+
for (const [hookName, handlers] of this.hooks.entries()) {
|
|
217
|
+
result[hookName] = {
|
|
218
|
+
count: handlers.length,
|
|
219
|
+
handlers: handlers.map((handlerEntry) => ({
|
|
220
|
+
handler: handlerEntry.handler,
|
|
221
|
+
pluginName: handlerEntry.pluginName,
|
|
222
|
+
executionCount: handlerEntry.executionCount
|
|
223
|
+
}))
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
setPluginEnabled(name, enabled) {
|
|
229
|
+
const plugin = this.plugins.get(name);
|
|
230
|
+
if (!plugin) {
|
|
231
|
+
throw new Error(`Plugin "${name}" не найден`);
|
|
232
|
+
}
|
|
233
|
+
plugin.enabled = Boolean(enabled);
|
|
234
|
+
}
|
|
235
|
+
removePlugin(name) {
|
|
236
|
+
const plugin = this.plugins.get(name);
|
|
237
|
+
if (!plugin) {
|
|
238
|
+
throw new Error(`Plugin "${name}" не найден`);
|
|
239
|
+
}
|
|
240
|
+
if (plugin.destroy) {
|
|
241
|
+
try {
|
|
242
|
+
plugin.destroy();
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
console.error(`Error destroying plugin "${name}":`, error);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
this.plugins.delete(name);
|
|
249
|
+
for (const [hookName, handlers] of this.hooks.entries()) {
|
|
250
|
+
if (!handlers.length) {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
const remaining = handlers.filter((handlerEntry) => handlerEntry.pluginName !== name);
|
|
254
|
+
this.hooks.set(hookName, remaining);
|
|
255
|
+
}
|
|
256
|
+
this.middlewares = this.middlewares.filter((middleware) => middleware.pluginName !== name);
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
resetStats() {
|
|
260
|
+
this.stats.pluginLoads = 0;
|
|
261
|
+
this.stats.hookExecutions = 0;
|
|
262
|
+
this.stats.middlewareExecutions = 0;
|
|
263
|
+
}
|
|
264
|
+
async executeMiddlewares(ctx, context = {}, finalHandler) {
|
|
265
|
+
const entries = this.middlewares.filter((entry) => this._isPluginEnabled(entry.pluginName));
|
|
266
|
+
if (entries.length === 0) {
|
|
267
|
+
if (finalHandler) {
|
|
268
|
+
await finalHandler(ctx);
|
|
269
|
+
}
|
|
270
|
+
return ctx;
|
|
271
|
+
}
|
|
272
|
+
let index = -1;
|
|
273
|
+
const dispatch = async (i) => {
|
|
274
|
+
if (i <= index) {
|
|
275
|
+
throw new Error('next() вызван несколько раз');
|
|
276
|
+
}
|
|
277
|
+
index = i;
|
|
278
|
+
const entry = entries[i];
|
|
279
|
+
if (!entry) {
|
|
280
|
+
if (finalHandler) {
|
|
281
|
+
return finalHandler(ctx);
|
|
282
|
+
}
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const startTime = Date.now();
|
|
286
|
+
try {
|
|
287
|
+
const result = entry.handler(ctx, () => dispatch(i + 1));
|
|
288
|
+
await result;
|
|
289
|
+
entry.executionCount++;
|
|
290
|
+
this.stats.middlewareExecutions++;
|
|
291
|
+
}
|
|
292
|
+
catch (error) {
|
|
293
|
+
this._runErrorHooks(error, { ...this.context, ...context, data: ctx });
|
|
294
|
+
throw error;
|
|
295
|
+
}
|
|
296
|
+
finally {
|
|
297
|
+
const duration = Date.now() - startTime;
|
|
298
|
+
if (duration > SLOW_HOOK_THRESHOLD_MS) {
|
|
299
|
+
console.warn(`Slow middleware "${entry.pluginName || 'anonymous'}" detected (${duration}ms)`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
await dispatch(0);
|
|
304
|
+
return ctx;
|
|
305
|
+
}
|
|
306
|
+
async executeMiddleware(input, context = {}) {
|
|
307
|
+
return this.executeMiddlewares(input, context);
|
|
308
|
+
}
|
|
309
|
+
setContext(key, value) {
|
|
310
|
+
this.context[key] = value;
|
|
311
|
+
}
|
|
312
|
+
getContext(key) {
|
|
313
|
+
if (key) {
|
|
314
|
+
return this.context[key];
|
|
315
|
+
}
|
|
316
|
+
return { ...this.context };
|
|
317
|
+
}
|
|
318
|
+
getStats() {
|
|
319
|
+
let hookCount = 0;
|
|
320
|
+
for (const handlers of this.hooks.values()) {
|
|
321
|
+
hookCount += handlers.length;
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
...this.stats,
|
|
325
|
+
plugins: this.plugins.size,
|
|
326
|
+
hooks: hookCount,
|
|
327
|
+
middlewares: this.middlewares.length,
|
|
328
|
+
uniqueHooks: this.hooks.size
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
getPlugins() {
|
|
332
|
+
return Array.from(this.plugins.keys());
|
|
333
|
+
}
|
|
334
|
+
getHooks() {
|
|
335
|
+
return Array.from(this.hooks.keys());
|
|
336
|
+
}
|
|
337
|
+
unregisterPlugin(name) {
|
|
338
|
+
try {
|
|
339
|
+
this.removePlugin(name);
|
|
340
|
+
return true;
|
|
341
|
+
}
|
|
342
|
+
catch {
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
clear() {
|
|
347
|
+
this.plugins.forEach((plugin, name) => {
|
|
348
|
+
if (plugin.destroy) {
|
|
349
|
+
try {
|
|
350
|
+
plugin.destroy();
|
|
351
|
+
}
|
|
352
|
+
catch (error) {
|
|
353
|
+
console.error(`Error destroying plugin "${name}":`, error);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
this.plugins.clear();
|
|
358
|
+
this.hooks.clear();
|
|
359
|
+
this.middlewares = [];
|
|
360
|
+
this.context = {};
|
|
361
|
+
this._registerDefaultHooks();
|
|
362
|
+
console.log('🧹 Plugin system cleared');
|
|
363
|
+
}
|
|
364
|
+
async executeHookAsync(hookName, data, context = {}) {
|
|
365
|
+
return this.executeHook(hookName, data, context);
|
|
366
|
+
}
|
|
367
|
+
async executeMiddlewareAsync(input, context = {}) {
|
|
368
|
+
return this.executeMiddlewares(input, context);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
exports.PluginManager = PluginManager;
|
|
372
|
+
let globalPluginManager = null;
|
|
373
|
+
function getGlobalPluginManager() {
|
|
374
|
+
if (!globalPluginManager) {
|
|
375
|
+
globalPluginManager = new PluginManager();
|
|
376
|
+
}
|
|
377
|
+
return globalPluginManager;
|
|
378
|
+
}
|
|
379
|
+
async function getGlobalPluginManagerAsync() {
|
|
380
|
+
return getGlobalPluginManager();
|
|
381
|
+
}
|
|
382
|
+
exports.default = PluginManager;
|
|
383
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
384
|
+
const current = module.exports;
|
|
385
|
+
if (current && current.__esModule) {
|
|
386
|
+
current.PluginManager = PluginManager;
|
|
387
|
+
current.getGlobalPluginManager = getGlobalPluginManager;
|
|
388
|
+
current.getGlobalPluginManagerAsync = getGlobalPluginManagerAsync;
|
|
389
|
+
current.default = PluginManager;
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
module.exports = PluginManager;
|
|
393
|
+
module.exports.PluginManager = PluginManager;
|
|
394
|
+
module.exports.getGlobalPluginManager = getGlobalPluginManager;
|
|
395
|
+
module.exports.getGlobalPluginManagerAsync = getGlobalPluginManagerAsync;
|
|
396
|
+
module.exports.default = PluginManager;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
//# sourceMappingURL=plugin-system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-system.js","sourceRoot":"","sources":["../../../src/core/plugin-system.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Plugin System для JTCSV\r\n * Middleware-like архитектура с поддержкой hooks и плагинов\r\n * \r\n * @version 1.0.0\r\n * @date 2026-01-22\r\n */\r\n\r\ninterface PluginStatsCounters {\r\n pluginLoads: number;\r\n hookExecutions: number;\r\n middlewareExecutions: number;\r\n}\r\n\r\ninterface PluginStats extends PluginStatsCounters {\r\n plugins: number;\r\n hooks: number;\r\n middlewares: number;\r\n uniqueHooks: number;\r\n}\r\n\r\ninterface Plugin {\r\n name: string;\r\n version: string;\r\n description?: string;\r\n hooks?: Record<string, Function>;\r\n middlewares?: Function[];\r\n init?: (manager: PluginManager) => void;\r\n destroy?: () => void;\r\n}\r\n\r\ninterface PluginRecord extends Plugin {\r\n id: string;\r\n enabled: boolean;\r\n}\r\n\r\ninterface HookHandlerEntry {\r\n handler: Function;\r\n pluginName?: string;\r\n executionCount: number;\r\n}\r\n\r\ninterface MiddlewareEntry {\r\n handler: Function;\r\n pluginName?: string;\r\n executionCount: number;\r\n}\r\n\r\ntype HookName = \r\n | 'before:csvToJson'\r\n | 'after:csvToJson'\r\n | 'before:jsonToCsv'\r\n | 'after:jsonToCsv'\r\n | 'before:parse'\r\n | 'after:parse'\r\n | 'before:serialize'\r\n | 'after:serialize'\r\n | 'error'\r\n | 'validation'\r\n | 'transformation'\r\n | string;\r\n\r\nconst SLOW_HOOK_THRESHOLD_MS = 100;\r\n\r\nexport class PluginManager {\r\n private plugins: Map<string, PluginRecord>;\r\n private hooks: Map<HookName, HookHandlerEntry[]>;\r\n private middlewares: MiddlewareEntry[];\r\n private context: Record<string, any>;\r\n private stats: PluginStatsCounters;\r\n\r\n constructor() {\r\n this.plugins = new Map();\r\n this.hooks = new Map();\r\n this.middlewares = [];\r\n this.context = {};\r\n this.stats = {\r\n pluginLoads: 0,\r\n hookExecutions: 0,\r\n middlewareExecutions: 0\r\n };\r\n\r\n // Регистрируем стандартные hooks\r\n this._registerDefaultHooks();\r\n }\r\n\r\n /**\r\n * Backwards-compatible alias for registerPlugin.\r\n */\r\n use(name: string, plugin: Plugin): void {\r\n this.registerPlugin(name, plugin);\r\n }\r\n\r\n /**\r\n * Регистрирует стандартные hooks\r\n */\r\n private _registerDefaultHooks(): void {\r\n const defaultHooks: HookName[] = [\r\n 'before:csvToJson',\r\n 'after:csvToJson',\r\n 'before:jsonToCsv',\r\n 'after:jsonToCsv',\r\n 'before:parse',\r\n 'after:parse',\r\n 'before:serialize',\r\n 'after:serialize',\r\n 'error',\r\n 'validation',\r\n 'transformation'\r\n ];\r\n\r\n defaultHooks.forEach(hook => {\r\n this.hooks.set(hook, []);\r\n });\r\n }\r\n\r\n /**\r\n * Регистрирует плагин\r\n * @param name - Уникальное имя плагина\r\n * @param plugin - Объект плагина\r\n */\r\n registerPlugin(name: string, plugin: Plugin): void {\r\n if (!plugin || typeof plugin !== 'object' || !plugin.name || !plugin.version) {\r\n throw new Error('Plugin должен иметь name и version');\r\n }\r\n\r\n if (this.plugins.has(name)) {\r\n throw new Error(`Plugin \"${name}\" уже зарегистрирован`);\r\n }\r\n\r\n if (plugin.hooks && (typeof plugin.hooks !== 'object' || Array.isArray(plugin.hooks))) {\r\n throw new Error('hooks must be an object');\r\n }\r\n\r\n if (plugin.hooks) {\r\n for (const [hookName, handler] of Object.entries(plugin.hooks)) {\r\n if (typeof handler !== 'function') {\r\n throw new Error(`Hook handler for \"${hookName}\" must be a function`);\r\n }\r\n }\r\n }\r\n\r\n if (plugin.middlewares && !Array.isArray(plugin.middlewares)) {\r\n throw new Error('middlewares must be an array');\r\n }\r\n\r\n if (plugin.middlewares) {\r\n plugin.middlewares.forEach((middleware, index) => {\r\n if (typeof middleware !== 'function') {\r\n throw new Error(`Middleware ${index} must be a function`);\r\n }\r\n });\r\n }\r\n\r\n const record: PluginRecord = {\r\n id: name,\r\n enabled: true,\r\n ...plugin\r\n };\r\n\r\n // ?????????????????? ????????????\r\n this.plugins.set(name, record);\r\n this.stats.pluginLoads++;\r\n\r\n // ?????????????????????? hooks ??????????????\r\n if (plugin.hooks) {\r\n Object.entries(plugin.hooks).forEach(([hookName, handler]) => {\r\n this.registerHook(hookName as HookName, handler, name);\r\n });\r\n }\r\n\r\n // ?????????????????????? middleware ??????????????\r\n if (plugin.middlewares) {\r\n plugin.middlewares.forEach(middleware => {\r\n this.registerMiddleware(middleware, name);\r\n });\r\n }\r\n\r\n // ???????????????? init ???????? ????????\r\n if (plugin.init) {\r\n plugin.init(this);\r\n }\r\n }\r\n\r\n registerHook(hookName: HookName, handler: Function, pluginName?: string): void {\r\n if (typeof handler != 'function') {\r\n throw new Error('Hook handler must be a function');\r\n }\r\n if (!this.hooks.has(hookName)) {\r\n this.hooks.set(hookName, []);\r\n }\r\n\r\n const handlers = this.hooks.get(hookName)!;\r\n handlers.push({\r\n handler,\r\n pluginName,\r\n executionCount: 0\r\n });\r\n }\r\n\r\n registerMiddleware(middleware: Function, pluginName?: string): void {\r\n if (typeof middleware !== 'function') {\r\n throw new Error('Middleware must be a function');\r\n }\r\n this.middlewares.push({\r\n handler: middleware,\r\n pluginName,\r\n executionCount: 0\r\n });\r\n }\r\n\r\n private _isPluginEnabled(pluginName?: string): boolean {\r\n if (!pluginName) {\r\n return true;\r\n }\r\n const plugin = this.plugins.get(pluginName);\r\n if (!plugin) {\r\n return true;\r\n }\r\n return plugin.enabled !== false;\r\n }\r\n\r\n private _runErrorHooks(error: any, context: any): void {\r\n const errorHandlers = this.hooks.get('error');\r\n if (!errorHandlers || errorHandlers.length == 0) {\r\n return;\r\n }\r\n for (const handlerEntry of errorHandlers) {\r\n try {\r\n handlerEntry.handler(error, context);\r\n } catch {\r\n // ignore errors in error handlers\r\n }\r\n }\r\n }\r\n\r\n async executeHook(hookName: HookName, data: any, context: any = {}): Promise<any> {\r\n const handlers = this.hooks.get(hookName);\r\n\r\n if (!handlers || handlers.length === 0) {\r\n return data;\r\n }\r\n\r\n let result = data;\r\n let executed = false;\r\n\r\n for (const handlerEntry of handlers) {\r\n if (!this._isPluginEnabled(handlerEntry.pluginName)) {\r\n continue;\r\n }\r\n\r\n executed = true;\r\n const startTime = Date.now();\r\n try {\r\n result = await handlerEntry.handler(result, { ...this.context, ...context, hookName, plugin: handlerEntry.pluginName });\r\n handlerEntry.executionCount++;\r\n } catch (error) {\r\n this._runErrorHooks(error, { ...this.context, ...context, hookName, data: result });\r\n } finally {\r\n const duration = Date.now() - startTime;\r\n if (duration > SLOW_HOOK_THRESHOLD_MS) {\r\n console.warn(`Slow hook \"${hookName}\" detected (${duration}ms)`);\r\n }\r\n }\r\n }\r\n\r\n if (executed) {\r\n this.stats.hookExecutions++;\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Backwards-compatible alias for executeHook.\r\n */\r\n async executeHooks(hookName: HookName, data: any, context: any = {}): Promise<any> {\r\n return this.executeHook(hookName, data, context);\r\n }\r\n\r\n /**\r\n * Executes an operation with before/after hooks and middleware.\r\n */\r\n async executeWithPlugins(\r\n operation: string,\r\n input: any,\r\n options: any,\r\n handler: (input: any, options: any) => any | Promise<any>\r\n ): Promise<any> {\r\n const metadata = options && options.metadata ? options.metadata : {};\r\n const context = { operation, options, metadata };\r\n const beforeHook = `before:${operation}` as HookName;\r\n const afterHook = `after:${operation}` as HookName;\r\n\r\n const beforeInput = await this.executeHook(beforeHook, input, context);\r\n const middlewareContext: { input: any; options: any; operation: string; metadata: any; result?: any } = {\n input: beforeInput,\n options,\n operation,\n metadata\n };\n const resultHolder = { set: false, value: undefined as any };\r\n\r\n try {\r\n await this.executeMiddlewares(middlewareContext, context, async (ctx: any) => {\r\n const handlerInput = ctx && Object.prototype.hasOwnProperty.call(ctx, 'input')\r\n ? ctx.input\r\n : beforeInput;\r\n const result = await handler(handlerInput, options);\r\n ctx.result = result;\r\n resultHolder.set = true;\r\n resultHolder.value = result;\r\n return result;\r\n });\r\n } catch (error) {\r\n this._runErrorHooks(error, { ...this.context, ...context, data: beforeInput });\r\n throw error;\r\n }\r\n\r\n const finalResult = resultHolder.set\r\n ? resultHolder.value\r\n : (Object.prototype.hasOwnProperty.call(middlewareContext, 'result') ? middlewareContext.result : undefined);\r\n\r\n return this.executeHook(afterHook, finalResult, context);\r\n }\r\n\r\n /**\r\n * Returns registered plugin names.\r\n */\r\n listPlugins(): Array<{ id: string; pluginName: string; version: string; description?: string; enabled: boolean }> {\r\n return Array.from(this.plugins.values()).map((plugin) => ({\r\n id: plugin.id,\r\n pluginName: plugin.name,\r\n version: plugin.version,\r\n description: plugin.description,\r\n enabled: plugin.enabled\r\n }));\r\n }\r\n\r\n listHooks(): Record<string, { count: number; handlers: Array<{ handler: Function; pluginName?: string; executionCount: number }> }> {\r\n const result: Record<string, { count: number; handlers: Array<{ handler: Function; pluginName?: string; executionCount: number }> }> = {};\r\n for (const [hookName, handlers] of this.hooks.entries()) {\r\n result[hookName] = {\r\n count: handlers.length,\r\n handlers: handlers.map((handlerEntry) => ({\r\n handler: handlerEntry.handler,\r\n pluginName: handlerEntry.pluginName,\r\n executionCount: handlerEntry.executionCount\r\n }))\r\n };\r\n }\r\n return result;\r\n }\r\n\r\n\r\n setPluginEnabled(name: string, enabled: boolean): void {\r\n const plugin = this.plugins.get(name);\r\n if (!plugin) {\r\n throw new Error(`Plugin \"${name}\" не найден`);\r\n }\r\n plugin.enabled = Boolean(enabled);\r\n }\r\n\r\n removePlugin(name: string): boolean {\r\n const plugin = this.plugins.get(name);\r\n if (!plugin) {\r\n throw new Error(`Plugin \"${name}\" не найден`);\r\n }\r\n\r\n if (plugin.destroy) {\r\n try {\r\n plugin.destroy();\r\n } catch (error) {\r\n console.error(`Error destroying plugin \"${name}\":`, error);\r\n }\r\n }\r\n\r\n this.plugins.delete(name);\r\n\r\n for (const [hookName, handlers] of this.hooks.entries()) {\r\n if (!handlers.length) {\r\n continue;\r\n }\r\n const remaining = handlers.filter((handlerEntry) => handlerEntry.pluginName !== name);\r\n this.hooks.set(hookName, remaining);\r\n }\r\n\r\n this.middlewares = this.middlewares.filter((middleware) => middleware.pluginName !== name);\r\n\r\n return true;\r\n }\r\n\r\n resetStats(): void {\r\n this.stats.pluginLoads = 0;\r\n this.stats.hookExecutions = 0;\r\n this.stats.middlewareExecutions = 0;\r\n }\r\n\r\n async executeMiddlewares(ctx: any, context: any = {}, finalHandler?: (ctx: any) => any | Promise<any>): Promise<any> {\r\n const entries = this.middlewares.filter((entry) => this._isPluginEnabled(entry.pluginName));\r\n if (entries.length === 0) {\r\n if (finalHandler) {\r\n await finalHandler(ctx);\r\n }\r\n return ctx;\r\n }\r\n\r\n let index = -1;\r\n const dispatch = async (i: number): Promise<any> => {\r\n if (i <= index) {\r\n throw new Error('next() вызван несколько раз');\r\n }\r\n index = i;\r\n const entry = entries[i];\r\n if (!entry) {\r\n if (finalHandler) {\r\n return finalHandler(ctx);\r\n }\r\n return;\r\n }\r\n\r\n const startTime = Date.now();\r\n try {\r\n const result = entry.handler(ctx, () => dispatch(i + 1));\r\n await result;\r\n entry.executionCount++;\r\n this.stats.middlewareExecutions++;\r\n } catch (error) {\r\n this._runErrorHooks(error, { ...this.context, ...context, data: ctx });\r\n throw error;\r\n } finally {\r\n const duration = Date.now() - startTime;\r\n if (duration > SLOW_HOOK_THRESHOLD_MS) {\r\n console.warn(`Slow middleware \"${entry.pluginName || 'anonymous'}\" detected (${duration}ms)`);\r\n }\r\n }\r\n };\r\n\r\n await dispatch(0);\r\n return ctx;\r\n }\r\n\r\n /**\r\n * Backwards-compatible alias for executeMiddlewares.\r\n */\r\n async executeMiddleware(input: any, context: any = {}): Promise<any> {\r\n return this.executeMiddlewares(input, context);\r\n }\r\n\r\n setContext(key: string, value: any): void {\r\n this.context[key] = value;\r\n }\r\n\r\n /**\r\n * Получает контекст\r\n * @param key - Ключ контекста (опционально)\r\n */\r\n getContext(key?: string): any {\r\n if (key) {\r\n return this.context[key];\r\n }\r\n return { ...this.context };\r\n }\r\n\r\n /**\r\n * Возвращает статистику\r\n */\r\n getStats(): PluginStats {\r\n let hookCount = 0;\r\n for (const handlers of this.hooks.values()) {\r\n hookCount += handlers.length;\r\n }\r\n\r\n return {\r\n ...this.stats,\r\n plugins: this.plugins.size,\r\n hooks: hookCount,\r\n middlewares: this.middlewares.length,\r\n uniqueHooks: this.hooks.size\r\n };\r\n }\r\n\r\n /**\r\n * Возвращает список зарегистрированных плагинов\r\n */\r\n getPlugins(): string[] {\r\n return Array.from(this.plugins.keys());\r\n }\r\n\r\n /**\r\n * Возвращает список зарегистрированных hooks\r\n */\r\n getHooks(): HookName[] {\r\n return Array.from(this.hooks.keys());\r\n }\r\n\r\n /**\r\n * Удаляет плагин\r\n * @param name - Имя плагина\r\n */\r\n unregisterPlugin(name: string): boolean {\r\n try {\r\n this.removePlugin(name);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Очищает все плагины и hooks\r\n */\r\n clear(): void {\r\n // Вызываем destroy для всех плагинов\r\n this.plugins.forEach((plugin, name) => {\r\n if (plugin.destroy) {\r\n try {\r\n plugin.destroy();\r\n } catch (error) {\r\n console.error(`Error destroying plugin \"${name}\":`, error);\r\n }\r\n }\r\n });\r\n\r\n this.plugins.clear();\r\n this.hooks.clear();\r\n this.middlewares = [];\r\n this.context = {};\r\n \r\n // Регистрируем стандартные hooks заново\r\n this._registerDefaultHooks();\r\n \r\n console.log('🧹 Plugin system cleared');\r\n }\r\n\r\n /**\r\n * Асинхронная версия executeHook\r\n */\r\n async executeHookAsync(hookName: HookName, data: any, context: any = {}): Promise<any> {\r\n return this.executeHook(hookName, data, context);\r\n }\r\n\r\n /**\r\n * Асинхронная версия executeMiddleware\r\n */\r\n async executeMiddlewareAsync(input: any, context: any = {}): Promise<any> {\r\n return this.executeMiddlewares(input, context);\r\n }\r\n}\r\n\r\n// Создание глобального экземпляра PluginManager\r\nlet globalPluginManager: PluginManager | null = null;\r\n\r\n/**\r\n * Возвращает глобальный экземпляр PluginManager\r\n */\r\nexport function getGlobalPluginManager(): PluginManager {\r\n if (!globalPluginManager) {\r\n globalPluginManager = new PluginManager();\r\n }\r\n return globalPluginManager;\r\n}\r\n\r\n/**\r\n * Асинхронная версия getGlobalPluginManager\r\n */\r\nexport async function getGlobalPluginManagerAsync(): Promise<PluginManager> {\r\n return getGlobalPluginManager();\r\n}\r\n\r\nexport default PluginManager;\r\n\r\n// Экспорт для CommonJS\r\nif (typeof module !== 'undefined' && module.exports) {\r\n const current = module.exports;\r\n if (current && current.__esModule) {\r\n current.PluginManager = PluginManager;\r\n current.getGlobalPluginManager = getGlobalPluginManager;\r\n current.getGlobalPluginManagerAsync = getGlobalPluginManagerAsync;\r\n current.default = PluginManager;\r\n } else {\r\n module.exports = PluginManager;\r\n module.exports.PluginManager = PluginManager;\r\n module.exports.getGlobalPluginManager = getGlobalPluginManager;\r\n module.exports.getGlobalPluginManagerAsync = getGlobalPluginManagerAsync;\r\n module.exports.default = PluginManager;\r\n }\r\n}\r\n"]}
|