jtcsv 3.0.0 → 3.1.1

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