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
|
@@ -1,476 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plugin System для JTCSV
|
|
3
|
-
* Middleware-like архитектура с поддержкой hooks и плагинов
|
|
4
|
-
*
|
|
5
|
-
* @version 1.0.0
|
|
6
|
-
* @date 2026-01-22
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
class PluginManager {
|
|
10
|
-
constructor() {
|
|
11
|
-
this.plugins = new Map();
|
|
12
|
-
this.hooks = new Map();
|
|
13
|
-
this.middlewares = [];
|
|
14
|
-
this.context = {};
|
|
15
|
-
this.stats = {
|
|
16
|
-
pluginLoads: 0,
|
|
17
|
-
hookExecutions: 0,
|
|
18
|
-
middlewareExecutions: 0
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
// Регистрируем стандартные hooks
|
|
22
|
-
this._registerDefaultHooks();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Регистрирует стандартные hooks
|
|
27
|
-
*/
|
|
28
|
-
_registerDefaultHooks() {
|
|
29
|
-
const defaultHooks = [
|
|
30
|
-
'before:csvToJson',
|
|
31
|
-
'after:csvToJson',
|
|
32
|
-
'before:jsonToCsv',
|
|
33
|
-
'after:jsonToCsv',
|
|
34
|
-
'before:parse',
|
|
35
|
-
'after:parse',
|
|
36
|
-
'before:serialize',
|
|
37
|
-
'after:serialize',
|
|
38
|
-
'error',
|
|
39
|
-
'validation',
|
|
40
|
-
'transformation'
|
|
41
|
-
];
|
|
42
|
-
|
|
43
|
-
defaultHooks.forEach(hook => {
|
|
44
|
-
this.hooks.set(hook, []);
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Регистрирует плагин
|
|
50
|
-
* @param {string} name - Уникальное имя плагина
|
|
51
|
-
* @param {Object} plugin - Конфигурация плагина
|
|
52
|
-
* @returns {PluginManager} this для chaining
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* pluginManager.use('excel-exporter', {
|
|
56
|
-
* name: 'Excel Exporter',
|
|
57
|
-
* version: '1.0.0',
|
|
58
|
-
* description: 'Экспорт в Excel формат',
|
|
59
|
-
* hooks: {
|
|
60
|
-
* 'after:jsonToCsv': (csv) => convertToExcel(csv)
|
|
61
|
-
* },
|
|
62
|
-
* middlewares: [
|
|
63
|
-
* async (ctx, next) => {
|
|
64
|
-
* console.log('Before conversion:', ctx);
|
|
65
|
-
* await next();
|
|
66
|
-
* console.log('After conversion:', ctx);
|
|
67
|
-
* }
|
|
68
|
-
* ]
|
|
69
|
-
* });
|
|
70
|
-
*/
|
|
71
|
-
use(name, plugin) {
|
|
72
|
-
if (this.plugins.has(name)) {
|
|
73
|
-
throw new Error(`Plugin "${name}" уже зарегистрирован`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
this._validatePlugin(plugin);
|
|
77
|
-
|
|
78
|
-
// Сохраняем плагин
|
|
79
|
-
this.plugins.set(name, {
|
|
80
|
-
...plugin,
|
|
81
|
-
registeredAt: new Date(),
|
|
82
|
-
enabled: true
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// Регистрируем hooks
|
|
86
|
-
if (plugin.hooks) {
|
|
87
|
-
Object.entries(plugin.hooks).forEach(([hookName, handler]) => {
|
|
88
|
-
this.registerHook(hookName, handler, name);
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Регистрируем middlewares
|
|
93
|
-
if (plugin.middlewares) {
|
|
94
|
-
plugin.middlewares.forEach((middleware, index) => {
|
|
95
|
-
this.registerMiddleware(middleware, `${name}:${index}`);
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
this.stats.pluginLoads++;
|
|
100
|
-
console.log(`✅ Plugin "${name}" зарегистрирован`);
|
|
101
|
-
return this;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Валидирует плагин
|
|
106
|
-
*/
|
|
107
|
-
_validatePlugin(plugin) {
|
|
108
|
-
if (!plugin.name || !plugin.version) {
|
|
109
|
-
throw new Error('Plugin должен иметь name и version');
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Проверяем обязательные поля
|
|
113
|
-
const required = ['name', 'version'];
|
|
114
|
-
required.forEach(field => {
|
|
115
|
-
/* istanbul ignore next */
|
|
116
|
-
if (!plugin[field]) {
|
|
117
|
-
/* istanbul ignore next */
|
|
118
|
-
throw new Error(`Plugin missing required field: ${field}`);
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
// Проверяем hooks если есть
|
|
123
|
-
if (plugin.hooks) {
|
|
124
|
-
if (typeof plugin.hooks !== 'object') {
|
|
125
|
-
throw new Error('Plugin hooks должен быть объектом');
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
Object.entries(plugin.hooks).forEach(([hookName, handler]) => {
|
|
129
|
-
if (typeof handler !== 'function') {
|
|
130
|
-
throw new Error(`Hook handler для "${hookName}" должен быть функцией`);
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Проверяем middlewares если есть
|
|
136
|
-
if (plugin.middlewares) {
|
|
137
|
-
if (!Array.isArray(plugin.middlewares)) {
|
|
138
|
-
throw new Error('Plugin middlewares должен быть массивом');
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
plugin.middlewares.forEach((middleware, index) => {
|
|
142
|
-
if (typeof middleware !== 'function') {
|
|
143
|
-
throw new Error(`Middleware ${index} должен быть функцией`);
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Регистрирует hook
|
|
151
|
-
* @param {string} hookName - Имя hook
|
|
152
|
-
* @param {Function} handler - Обработчик hook
|
|
153
|
-
* @param {string} pluginName - Имя плагина (опционально)
|
|
154
|
-
*/
|
|
155
|
-
registerHook(hookName, handler, pluginName = null) {
|
|
156
|
-
if (!this.hooks.has(hookName)) {
|
|
157
|
-
this.hooks.set(hookName, []);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
this.hooks.get(hookName).push({
|
|
161
|
-
handler,
|
|
162
|
-
pluginName,
|
|
163
|
-
registeredAt: new Date()
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
console.log(`📌 Hook "${hookName}" зарегистрирован${pluginName ? ` для плагина "${pluginName}"` : ''}`);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Регистрирует middleware
|
|
171
|
-
* @param {Function} middleware - Middleware функция
|
|
172
|
-
* @param {string} name - Имя middleware (опционально)
|
|
173
|
-
*/
|
|
174
|
-
registerMiddleware(middleware, name = null) {
|
|
175
|
-
this.middlewares.push({
|
|
176
|
-
middleware,
|
|
177
|
-
name,
|
|
178
|
-
registeredAt: new Date()
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
console.log(`🔄 Middleware "${name || 'anonymous'}" зарегистрирован`);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Выполняет все handlers для конкретного hook
|
|
186
|
-
* @param {string} hookName - Имя hook
|
|
187
|
-
* @param {any} data - Данные для обработки
|
|
188
|
-
* @param {Object} context - Контекст выполнения
|
|
189
|
-
* @returns {Promise<any>} Результат обработки
|
|
190
|
-
*/
|
|
191
|
-
async executeHooks(hookName, data, context = {}) {
|
|
192
|
-
const handlers = this.hooks.get(hookName) || [];
|
|
193
|
-
|
|
194
|
-
if (handlers.length === 0) {
|
|
195
|
-
return data;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
console.log(`⚡ Выполнение hook "${hookName}" с ${handlers.length} обработчиками`);
|
|
199
|
-
|
|
200
|
-
let result = data;
|
|
201
|
-
|
|
202
|
-
for (const { handler, pluginName } of handlers) {
|
|
203
|
-
try {
|
|
204
|
-
const startTime = Date.now();
|
|
205
|
-
result = await handler(result, { ...context, pluginName });
|
|
206
|
-
const duration = Date.now() - startTime;
|
|
207
|
-
|
|
208
|
-
if (duration > 100) {
|
|
209
|
-
console.warn(`⚠️ Hook "${hookName}" от плагина "${pluginName}" выполнился за ${duration}ms`);
|
|
210
|
-
}
|
|
211
|
-
} catch (error) {
|
|
212
|
-
console.error(`❌ Ошибка в hook "${hookName}" от плагина "${pluginName}":`, error.message);
|
|
213
|
-
|
|
214
|
-
// Выполняем error hook если есть
|
|
215
|
-
await this.executeHooks('error', {
|
|
216
|
-
hook: hookName,
|
|
217
|
-
plugin: pluginName,
|
|
218
|
-
error,
|
|
219
|
-
data: result
|
|
220
|
-
}, context);
|
|
221
|
-
|
|
222
|
-
// Продолжаем выполнение с другими обработчиками
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
this.stats.hookExecutions++;
|
|
228
|
-
return result;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Выполняет middleware pipeline
|
|
233
|
-
* @param {Object} ctx - Контекст выполнения
|
|
234
|
-
* @returns {Promise<Object>} Обработанный контекст
|
|
235
|
-
*/
|
|
236
|
-
async executeMiddlewares(ctx) {
|
|
237
|
-
if (this.middlewares.length === 0) {
|
|
238
|
-
return ctx;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
console.log(`🚀 Запуск middleware pipeline с ${this.middlewares.length} middleware`);
|
|
242
|
-
|
|
243
|
-
let index = -1;
|
|
244
|
-
const middlewares = this.middlewares.map(m => m.middleware);
|
|
245
|
-
|
|
246
|
-
const dispatch = async (i) => {
|
|
247
|
-
if (i <= index) {
|
|
248
|
-
throw new Error('next() вызван несколько раз');
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
index = i;
|
|
252
|
-
const middleware = middlewares[i];
|
|
253
|
-
|
|
254
|
-
if (!middleware) {
|
|
255
|
-
return ctx;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
try {
|
|
259
|
-
const startTime = Date.now();
|
|
260
|
-
await middleware(ctx, () => dispatch(i + 1));
|
|
261
|
-
const duration = Date.now() - startTime;
|
|
262
|
-
|
|
263
|
-
if (duration > 50) {
|
|
264
|
-
console.warn(`⚠️ Middleware ${i} выполнился за ${duration}ms`);
|
|
265
|
-
}
|
|
266
|
-
} catch (error) {
|
|
267
|
-
console.error(`❌ Ошибка в middleware ${i}:`, error.message);
|
|
268
|
-
|
|
269
|
-
// Выполняем error hook
|
|
270
|
-
await this.executeHooks('error', {
|
|
271
|
-
middleware: i,
|
|
272
|
-
error,
|
|
273
|
-
context: ctx
|
|
274
|
-
}, ctx);
|
|
275
|
-
|
|
276
|
-
throw error;
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
await dispatch(0);
|
|
281
|
-
this.stats.middlewareExecutions++;
|
|
282
|
-
return ctx;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Создает контекст для операции
|
|
287
|
-
* @param {string} operation - Тип операции
|
|
288
|
-
* @param {any} input - Входные данные
|
|
289
|
-
* @param {Object} options - Опции
|
|
290
|
-
* @returns {Object} Контекст
|
|
291
|
-
*/
|
|
292
|
-
/* istanbul ignore next */
|
|
293
|
-
createContext(operation, input, options = {}) {
|
|
294
|
-
return {
|
|
295
|
-
operation,
|
|
296
|
-
input,
|
|
297
|
-
options,
|
|
298
|
-
startTime: Date.now(),
|
|
299
|
-
metadata: {
|
|
300
|
-
version: '1.0.0',
|
|
301
|
-
timestamp: new Date().toISOString(),
|
|
302
|
-
...options.metadata
|
|
303
|
-
},
|
|
304
|
-
state: {},
|
|
305
|
-
result: null,
|
|
306
|
-
errors: [],
|
|
307
|
-
warnings: []
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Выполняет операцию с поддержкой плагинов
|
|
313
|
-
* @param {string} operation - Тип операции
|
|
314
|
-
* @param {any} input - Входные данные
|
|
315
|
-
* @param {Object} options - Опции
|
|
316
|
-
* @param {Function} coreFunction - Основная функция
|
|
317
|
-
* @returns {Promise<any>} Результат
|
|
318
|
-
*/
|
|
319
|
-
async executeWithPlugins(operation, input, options, coreFunction) {
|
|
320
|
-
// Создаем контекст
|
|
321
|
-
const ctx = this.createContext(operation, input, options);
|
|
322
|
-
|
|
323
|
-
try {
|
|
324
|
-
// Выполняем before hooks
|
|
325
|
-
ctx.input = await this.executeHooks(`before:${operation}`, ctx.input, ctx);
|
|
326
|
-
|
|
327
|
-
// Выполняем middlewares
|
|
328
|
-
await this.executeMiddlewares(ctx);
|
|
329
|
-
|
|
330
|
-
// Выполняем основную функцию
|
|
331
|
-
ctx.result = await coreFunction(ctx.input, ctx.options);
|
|
332
|
-
|
|
333
|
-
// Выполняем after hooks
|
|
334
|
-
ctx.result = await this.executeHooks(`after:${operation}`, ctx.result, ctx);
|
|
335
|
-
|
|
336
|
-
// Записываем время выполнения
|
|
337
|
-
ctx.duration = Date.now() - ctx.startTime;
|
|
338
|
-
|
|
339
|
-
// Логируем успешное выполнение
|
|
340
|
-
console.log(`✅ Операция "${operation}" выполнена за ${ctx.duration}ms`);
|
|
341
|
-
|
|
342
|
-
return ctx.result;
|
|
343
|
-
} catch (error) {
|
|
344
|
-
// Записываем ошибку
|
|
345
|
-
ctx.errors.push(error);
|
|
346
|
-
ctx.duration = Date.now() - ctx.startTime;
|
|
347
|
-
|
|
348
|
-
// Выполняем error hooks
|
|
349
|
-
await this.executeHooks('error', {
|
|
350
|
-
operation,
|
|
351
|
-
error,
|
|
352
|
-
context: ctx
|
|
353
|
-
}, ctx);
|
|
354
|
-
|
|
355
|
-
console.error(`❌ Ошибка в операции "${operation}":`, error.message);
|
|
356
|
-
throw error;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Возвращает список всех зарегистрированных плагинов
|
|
362
|
-
* @returns {Array} Список плагинов
|
|
363
|
-
*/
|
|
364
|
-
listPlugins() {
|
|
365
|
-
return Array.from(this.plugins.entries()).map(([name, plugin]) => ({
|
|
366
|
-
name,
|
|
367
|
-
pluginName: plugin.name,
|
|
368
|
-
version: plugin.version,
|
|
369
|
-
description: plugin.description || '',
|
|
370
|
-
enabled: plugin.enabled,
|
|
371
|
-
registeredAt: plugin.registeredAt,
|
|
372
|
-
hooks: Object.keys(plugin.hooks || {}).length,
|
|
373
|
-
middlewares: (plugin.middlewares || []).length
|
|
374
|
-
}));
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* Возвращает список всех hooks
|
|
379
|
-
* @returns {Object} Статистика hooks
|
|
380
|
-
*/
|
|
381
|
-
listHooks() {
|
|
382
|
-
const result = {};
|
|
383
|
-
|
|
384
|
-
for (const [hookName, handlers] of this.hooks.entries()) {
|
|
385
|
-
result[hookName] = {
|
|
386
|
-
count: handlers.length,
|
|
387
|
-
handlers: handlers.map(h => ({
|
|
388
|
-
pluginName: h.pluginName,
|
|
389
|
-
registeredAt: h.registeredAt
|
|
390
|
-
}))
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
return result;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* Включает/выключает плагин
|
|
399
|
-
* @param {string} pluginName - Имя плагина
|
|
400
|
-
* @param {boolean} enabled - Состояние
|
|
401
|
-
*/
|
|
402
|
-
setPluginEnabled(pluginName, enabled) {
|
|
403
|
-
const plugin = this.plugins.get(pluginName);
|
|
404
|
-
if (!plugin) {
|
|
405
|
-
throw new Error(`Plugin "${pluginName}" не найден`);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
plugin.enabled = enabled;
|
|
409
|
-
/* istanbul ignore next */
|
|
410
|
-
console.log(`🔧 Plugin "${pluginName}" ${enabled ? 'включен' : 'выключен'}`);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
* Удаляет плагин
|
|
415
|
-
* @param {string} pluginName - Имя плагина
|
|
416
|
-
*/
|
|
417
|
-
removePlugin(pluginName) {
|
|
418
|
-
if (!this.plugins.has(pluginName)) {
|
|
419
|
-
throw new Error(`Plugin "${pluginName}" не найден`);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// Удаляем связанные hooks
|
|
423
|
-
for (const [hookName, handlers] of this.hooks.entries()) {
|
|
424
|
-
const filtered = handlers.filter(h => h.pluginName !== pluginName);
|
|
425
|
-
this.hooks.set(hookName, filtered);
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// Удаляем связанные middlewares
|
|
429
|
-
this.middlewares = this.middlewares.filter(m => !m.name?.startsWith(`${pluginName}:`));
|
|
430
|
-
|
|
431
|
-
// Удаляем плагин
|
|
432
|
-
this.plugins.delete(pluginName);
|
|
433
|
-
|
|
434
|
-
console.log(`🗑️ Plugin "${pluginName}" удален`);
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
/**
|
|
438
|
-
* Возвращает статистику
|
|
439
|
-
* @returns {Object} Статистика
|
|
440
|
-
*/
|
|
441
|
-
getStats() {
|
|
442
|
-
return {
|
|
443
|
-
...this.stats,
|
|
444
|
-
plugins: this.plugins.size,
|
|
445
|
-
hooks: Array.from(this.hooks.values()).reduce((sum, handlers) => sum + handlers.length, 0),
|
|
446
|
-
middlewares: this.middlewares.length,
|
|
447
|
-
uniqueHooks: this.hooks.size
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
/**
|
|
452
|
-
* Сбрасывает статистику
|
|
453
|
-
*/
|
|
454
|
-
resetStats() {
|
|
455
|
-
this.stats = {
|
|
456
|
-
pluginLoads: 0,
|
|
457
|
-
hookExecutions: 0,
|
|
458
|
-
middlewareExecutions: 0
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
/**
|
|
463
|
-
* Очищает все плагины и hooks
|
|
464
|
-
*/
|
|
465
|
-
clear() {
|
|
466
|
-
this.plugins.clear();
|
|
467
|
-
this.hooks.clear();
|
|
468
|
-
this.middlewares = [];
|
|
469
|
-
this.resetStats();
|
|
470
|
-
this._registerDefaultHooks();
|
|
471
|
-
|
|
472
|
-
console.log('🧹 Все плагины и hooks очищены');
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
module.exports = PluginManager;
|