jtcsv 2.2.7 → 3.0.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.
Files changed (140) hide show
  1. package/README.md +31 -1
  2. package/bin/jtcsv.js +891 -821
  3. package/bin/jtcsv.ts +2534 -0
  4. package/csv-to-json.js +168 -145
  5. package/dist/jtcsv-core.cjs.js +1407 -0
  6. package/dist/jtcsv-core.cjs.js.map +1 -0
  7. package/dist/jtcsv-core.esm.js +1379 -0
  8. package/dist/jtcsv-core.esm.js.map +1 -0
  9. package/dist/jtcsv-core.umd.js +1413 -0
  10. package/dist/jtcsv-core.umd.js.map +1 -0
  11. package/dist/jtcsv-full.cjs.js +1912 -0
  12. package/dist/jtcsv-full.cjs.js.map +1 -0
  13. package/dist/jtcsv-full.esm.js +1880 -0
  14. package/dist/jtcsv-full.esm.js.map +1 -0
  15. package/dist/jtcsv-full.umd.js +1918 -0
  16. package/dist/jtcsv-full.umd.js.map +1 -0
  17. package/dist/jtcsv-workers.esm.js +759 -0
  18. package/dist/jtcsv-workers.esm.js.map +1 -0
  19. package/dist/jtcsv-workers.umd.js +773 -0
  20. package/dist/jtcsv-workers.umd.js.map +1 -0
  21. package/dist/jtcsv.cjs.js +61 -19
  22. package/dist/jtcsv.cjs.js.map +1 -1
  23. package/dist/jtcsv.esm.js +61 -19
  24. package/dist/jtcsv.esm.js.map +1 -1
  25. package/dist/jtcsv.umd.js +61 -19
  26. package/dist/jtcsv.umd.js.map +1 -1
  27. package/errors.js +188 -2
  28. package/examples/advanced/conditional-transformations.js +446 -0
  29. package/examples/advanced/conditional-transformations.ts +446 -0
  30. package/examples/advanced/csv-parser.worker.js +89 -0
  31. package/examples/advanced/csv-parser.worker.ts +89 -0
  32. package/examples/advanced/nested-objects-example.js +306 -0
  33. package/examples/advanced/nested-objects-example.ts +306 -0
  34. package/examples/advanced/performance-optimization.js +504 -0
  35. package/examples/advanced/performance-optimization.ts +504 -0
  36. package/examples/advanced/run-demo-server.js +116 -0
  37. package/examples/advanced/run-demo-server.ts +116 -0
  38. package/examples/advanced/web-worker-usage.html +874 -0
  39. package/examples/async-multithreaded-example.ts +335 -0
  40. package/examples/cli-advanced-usage.md +288 -0
  41. package/examples/cli-batch-processing.ts +38 -0
  42. package/examples/cli-tool.js +0 -3
  43. package/examples/cli-tool.ts +183 -0
  44. package/examples/error-handling.js +21 -7
  45. package/examples/error-handling.ts +356 -0
  46. package/examples/express-api.js +0 -3
  47. package/examples/express-api.ts +164 -0
  48. package/examples/large-dataset-example.js +0 -3
  49. package/examples/large-dataset-example.ts +204 -0
  50. package/examples/ndjson-processing.js +1 -1
  51. package/examples/ndjson-processing.ts +456 -0
  52. package/examples/plugin-excel-exporter.js +3 -4
  53. package/examples/plugin-excel-exporter.ts +406 -0
  54. package/examples/react-integration.tsx +637 -0
  55. package/examples/schema-validation.ts +640 -0
  56. package/examples/simple-usage.js +254 -254
  57. package/examples/simple-usage.ts +194 -0
  58. package/examples/streaming-example.js +4 -5
  59. package/examples/streaming-example.ts +419 -0
  60. package/examples/web-workers-advanced.ts +28 -0
  61. package/index.d.ts +1 -3
  62. package/index.js +15 -1
  63. package/json-save.js +9 -3
  64. package/json-to-csv.js +168 -21
  65. package/package.json +69 -10
  66. package/plugins/express-middleware/README.md +21 -2
  67. package/plugins/express-middleware/example.js +3 -4
  68. package/plugins/express-middleware/example.ts +135 -0
  69. package/plugins/express-middleware/index.d.ts +1 -1
  70. package/plugins/express-middleware/index.js +270 -118
  71. package/plugins/express-middleware/index.ts +557 -0
  72. package/plugins/fastify-plugin/index.js +2 -4
  73. package/plugins/fastify-plugin/index.ts +443 -0
  74. package/plugins/hono/index.ts +226 -0
  75. package/plugins/nestjs/index.ts +201 -0
  76. package/plugins/nextjs-api/examples/ConverterComponent.tsx +386 -0
  77. package/plugins/nextjs-api/examples/api-convert.js +0 -2
  78. package/plugins/nextjs-api/examples/api-convert.ts +67 -0
  79. package/plugins/nextjs-api/index.tsx +339 -0
  80. package/plugins/nextjs-api/route.js +2 -3
  81. package/plugins/nextjs-api/route.ts +370 -0
  82. package/plugins/nuxt/index.ts +94 -0
  83. package/plugins/nuxt/runtime/composables/useJtcsv.ts +100 -0
  84. package/plugins/nuxt/runtime/plugin.ts +71 -0
  85. package/plugins/remix/index.js +1 -1
  86. package/plugins/remix/index.ts +260 -0
  87. package/plugins/sveltekit/index.js +1 -1
  88. package/plugins/sveltekit/index.ts +301 -0
  89. package/plugins/trpc/index.ts +267 -0
  90. package/src/browser/browser-functions.ts +402 -0
  91. package/src/browser/core.js +92 -0
  92. package/src/browser/core.ts +152 -0
  93. package/src/browser/csv-to-json-browser.d.ts +3 -0
  94. package/src/browser/csv-to-json-browser.js +36 -14
  95. package/src/browser/csv-to-json-browser.ts +264 -0
  96. package/src/browser/errors-browser.ts +303 -0
  97. package/src/browser/extensions/plugins.js +92 -0
  98. package/src/browser/extensions/plugins.ts +93 -0
  99. package/src/browser/extensions/workers.js +39 -0
  100. package/src/browser/extensions/workers.ts +39 -0
  101. package/src/browser/globals.d.ts +5 -0
  102. package/src/browser/index.ts +192 -0
  103. package/src/browser/json-to-csv-browser.d.ts +3 -0
  104. package/src/browser/json-to-csv-browser.js +13 -3
  105. package/src/browser/json-to-csv-browser.ts +262 -0
  106. package/src/browser/streams.js +12 -2
  107. package/src/browser/streams.ts +336 -0
  108. package/src/browser/workers/csv-parser.worker.ts +377 -0
  109. package/src/browser/workers/worker-pool.ts +548 -0
  110. package/src/core/delimiter-cache.js +22 -8
  111. package/src/core/delimiter-cache.ts +310 -0
  112. package/src/core/node-optimizations.ts +449 -0
  113. package/src/core/plugin-system.js +29 -11
  114. package/src/core/plugin-system.ts +400 -0
  115. package/src/core/transform-hooks.ts +558 -0
  116. package/src/engines/fast-path-engine-new.ts +347 -0
  117. package/src/engines/fast-path-engine.ts +854 -0
  118. package/src/errors.ts +72 -0
  119. package/src/formats/ndjson-parser.ts +469 -0
  120. package/src/formats/tsv-parser.ts +334 -0
  121. package/src/index-with-plugins.js +16 -9
  122. package/src/index-with-plugins.ts +395 -0
  123. package/src/types/index.ts +255 -0
  124. package/src/utils/bom-utils.js +259 -0
  125. package/src/utils/bom-utils.ts +373 -0
  126. package/src/utils/encoding-support.js +124 -0
  127. package/src/utils/encoding-support.ts +155 -0
  128. package/src/utils/schema-validator.js +19 -19
  129. package/src/utils/schema-validator.ts +819 -0
  130. package/src/utils/transform-loader.js +1 -1
  131. package/src/utils/transform-loader.ts +389 -0
  132. package/src/utils/zod-adapter.js +170 -0
  133. package/src/utils/zod-adapter.ts +280 -0
  134. package/src/web-server/index.js +10 -10
  135. package/src/web-server/index.ts +683 -0
  136. package/src/workers/csv-multithreaded.ts +310 -0
  137. package/src/workers/csv-parser.worker.ts +227 -0
  138. package/src/workers/worker-pool.ts +409 -0
  139. package/stream-csv-to-json.js +26 -8
  140. package/stream-json-to-csv.js +1 -0
@@ -0,0 +1,449 @@
1
+ /**
2
+ * Node.js Runtime Optimizations
3
+ *
4
+ * Detects Node.js version and provides optimized implementations
5
+ * for modern runtimes while maintaining backward compatibility.
6
+ *
7
+ * Optimized for: Node 20, 22, 24
8
+ * Compatible with: Node 12+
9
+ */
10
+
11
+ // Parse Node.js version
12
+ const nodeVersionStr = process.versions?.node || '12.0.0';
13
+ const [major, minor] = nodeVersionStr.split('.').map(Number);
14
+
15
+ // Feature detection flags
16
+ export const features = {
17
+ // Node 14.17+ / 16+
18
+ hasAbortController: typeof AbortController !== 'undefined',
19
+
20
+ // Node 15+
21
+ hasPromiseAny: typeof (Promise as any).any === 'function',
22
+
23
+ // Node 16+
24
+ hasArrayAt: typeof Array.prototype.at === 'function',
25
+ hasObjectHasOwn: typeof (Object as any).hasOwn === 'function',
26
+
27
+ // Node 17+
28
+ hasStructuredClone: typeof globalThis.structuredClone === 'function',
29
+
30
+ // Node 18+
31
+ hasFetch: typeof globalThis.fetch === 'function',
32
+
33
+ // Node 20+
34
+ hasWebStreams: typeof globalThis.ReadableStream !== 'undefined' && major >= 20,
35
+ hasArrayGroup: typeof (Array.prototype as any).group === 'function',
36
+
37
+ // Node 21+
38
+ hasSetMethods: typeof (Set.prototype as any).union === 'function',
39
+
40
+ // Node 22+
41
+ hasImportMeta: major >= 22,
42
+ hasExplicitResourceManagement: major >= 22,
43
+
44
+ // Version checks
45
+ isNode20Plus: major >= 20,
46
+ isNode22Plus: major >= 22,
47
+ isNode24Plus: major >= 24
48
+ };
49
+
50
+ /**
51
+ * Optimized Object.hasOwn polyfill for older Node versions
52
+ */
53
+ export const hasOwn = features.hasObjectHasOwn
54
+ ? (Object as any).hasOwn
55
+ : (obj: object, prop: string | number | symbol): boolean =>
56
+ Object.prototype.hasOwnProperty.call(obj, prop);
57
+
58
+ /**
59
+ * Optimized deep clone function
60
+ * Uses structuredClone on Node 17+ for best performance
61
+ */
62
+ export const deepClone = features.hasStructuredClone
63
+ ? <T>(obj: T): T => structuredClone(obj)
64
+ : <T>(obj: T): T => JSON.parse(JSON.stringify(obj));
65
+
66
+ /**
67
+ * Optimized array access with at() method
68
+ */
69
+ export const arrayAt = features.hasArrayAt
70
+ ? <T>(arr: T[], index: number): T | undefined => arr.at(index)
71
+ : <T>(arr: T[], index: number): T | undefined => {
72
+ const len = arr.length;
73
+ const normalizedIndex = index < 0 ? len + index : index;
74
+ return normalizedIndex >= 0 && normalizedIndex < len ? arr[normalizedIndex] : undefined;
75
+ };
76
+
77
+ /**
78
+ * High-performance string builder for large CSV generation
79
+ * Uses different strategies based on Node version
80
+ */
81
+ export class StringBuilderOptimized {
82
+ private parts: string[];
83
+ private length: number;
84
+ private initialCapacity: number;
85
+ private chunkSize: number;
86
+
87
+ constructor(initialCapacity = 1024) {
88
+ this.parts = [];
89
+ this.length = 0;
90
+ this.initialCapacity = initialCapacity;
91
+
92
+ // Node 20+ uses more aggressive chunking
93
+ this.chunkSize = features.isNode20Plus ? 65536 : 16384;
94
+ }
95
+
96
+ append(str: string): this {
97
+ if (str) {
98
+ this.parts.push(str);
99
+ this.length += str.length;
100
+ }
101
+ return this;
102
+ }
103
+
104
+ toString(): string {
105
+ return this.parts.join('');
106
+ }
107
+
108
+ clear(): void {
109
+ this.parts = [];
110
+ this.length = 0;
111
+ }
112
+
113
+ getLength(): number {
114
+ return this.length;
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Optimized row buffer for streaming CSV parsing
120
+ * Minimizes allocations on modern Node versions
121
+ */
122
+ export class RowBuffer<T = any> {
123
+ private rows: T[][];
124
+ private currentRow: T[];
125
+ private rowCount: number;
126
+
127
+ constructor(initialSize = 100) {
128
+ this.rows = [];
129
+ this.currentRow = [];
130
+ this.rowCount = 0;
131
+
132
+ // Pre-allocate on Node 20+
133
+ if (features.isNode20Plus) {
134
+ this.rows = new Array(initialSize);
135
+ this.rows.length = 0;
136
+ }
137
+ }
138
+
139
+ addField(field: T): void {
140
+ this.currentRow.push(field);
141
+ }
142
+
143
+ commitRow(): void {
144
+ if (this.currentRow.length > 0) {
145
+ this.rows.push(this.currentRow);
146
+ this.rowCount++;
147
+ this.currentRow = [];
148
+ }
149
+ }
150
+
151
+ getRows(): T[][] {
152
+ return this.rows;
153
+ }
154
+
155
+ clear(): void {
156
+ this.rows = features.isNode20Plus ? new Array(100) : [];
157
+ this.rows.length = 0;
158
+ this.currentRow = [];
159
+ this.rowCount = 0;
160
+ }
161
+
162
+ getRowCount(): number {
163
+ return this.rowCount;
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Optimized field parser with char code comparisons
169
+ * Faster than string comparisons on all Node versions
170
+ */
171
+ export const CHAR_CODES = {
172
+ QUOTE: 34, // "
173
+ COMMA: 44, // ,
174
+ SEMICOLON: 59, // ;
175
+ TAB: 9, // \t
176
+ PIPE: 124, // |
177
+ NEWLINE: 10, // \n
178
+ CARRIAGE: 13, // \r
179
+ SPACE: 32, // space
180
+ EQUALS: 61, // =
181
+ PLUS: 43, // +
182
+ MINUS: 45, // -
183
+ AT: 64, // @
184
+ BACKSLASH: 92, // \
185
+ APOSTROPHE: 39 // '
186
+ } as const;
187
+
188
+ /**
189
+ * Fast delimiter detection using char codes
190
+ */
191
+ export function fastDetectDelimiter(sample: string, candidates = [';', ',', '\t', '|']): string {
192
+ const firstLineEnd = sample.indexOf('\n');
193
+ const firstLine = firstLineEnd > -1 ? sample.slice(0, firstLineEnd) : sample;
194
+
195
+ const candidateCodes = candidates.map(c => c.charCodeAt(0));
196
+ const counts = new Array(candidateCodes.length).fill(0);
197
+
198
+ // Use fast char code iteration on Node 20+
199
+ const len = Math.min(firstLine.length, 10000);
200
+
201
+ for (let i = 0; i < len; i++) {
202
+ const code = firstLine.charCodeAt(i);
203
+ for (let j = 0; j < candidateCodes.length; j++) {
204
+ if (code === candidateCodes[j]) {
205
+ counts[j]++;
206
+ }
207
+ }
208
+ }
209
+
210
+ let maxCount = 0;
211
+ let maxIndex = 0;
212
+
213
+ for (let i = 0; i < counts.length; i++) {
214
+ if (counts[i] > maxCount) {
215
+ maxCount = counts[i];
216
+ maxIndex = i;
217
+ }
218
+ }
219
+
220
+ return candidates[maxIndex];
221
+ }
222
+
223
+ /**
224
+ * Optimized batch processor for large datasets
225
+ * Uses different chunk sizes based on Node version
226
+ */
227
+ export function createBatchProcessor<T, R>(
228
+ processor: (batch: T[]) => Promise<R[]> | R[],
229
+ options: { batchSize?: number; parallelism?: number } = {}
230
+ ): (items: T[]) => AsyncGenerator<R> {
231
+ const batchSize = options.batchSize || (features.isNode20Plus ? 10000 : 5000);
232
+ const parallelism = options.parallelism || (features.isNode22Plus ? 4 : 2);
233
+
234
+ return async function* processBatches(items: T[]): AsyncGenerator<R> {
235
+ const batches: T[][] = [];
236
+
237
+ for (let i = 0; i < items.length; i += batchSize) {
238
+ batches.push(items.slice(i, i + batchSize));
239
+ }
240
+
241
+ // Process batches with limited parallelism
242
+ for (let i = 0; i < batches.length; i += parallelism) {
243
+ const chunk = batches.slice(i, i + parallelism);
244
+ const results = await Promise.all(chunk.map(batch => processor(batch)));
245
+
246
+ for (const result of results) {
247
+ yield* result;
248
+ }
249
+ }
250
+ };
251
+ }
252
+
253
+ /**
254
+ * Memory-efficient object pool for row objects
255
+ * Reduces GC pressure on large CSV files
256
+ */
257
+ export class ObjectPool<T> {
258
+ private factory: () => T;
259
+ private pool: T[];
260
+ private inUse: number;
261
+
262
+ constructor(factory: () => T, initialSize = 100) {
263
+ this.factory = factory;
264
+ this.pool = [];
265
+ this.inUse = 0;
266
+
267
+ // Pre-warm pool on Node 20+
268
+ if (features.isNode20Plus) {
269
+ for (let i = 0; i < initialSize; i++) {
270
+ this.pool.push(factory());
271
+ }
272
+ }
273
+ }
274
+
275
+ acquire(): T {
276
+ this.inUse++;
277
+ if (this.pool.length > 0) {
278
+ return this.pool.pop()!;
279
+ }
280
+ return this.factory();
281
+ }
282
+
283
+ release(obj: T): void {
284
+ this.inUse--;
285
+ // Clear object properties before returning to pool
286
+ for (const key in obj) {
287
+ if (hasOwn(obj, key)) {
288
+ delete (obj as any)[key];
289
+ }
290
+ }
291
+ this.pool.push(obj);
292
+ }
293
+
294
+ getStats(): { poolSize: number; inUse: number } {
295
+ return {
296
+ poolSize: this.pool.length,
297
+ inUse: this.inUse
298
+ };
299
+ }
300
+ }
301
+
302
+ /**
303
+ * Fast string escape for CSV values
304
+ * Uses pre-computed regex on all versions
305
+ */
306
+ const QUOTE_REGEX = /"/g;
307
+
308
+ export function fastEscapeValue(value: any, delimiterCode: number): string {
309
+ if (value === null || value === undefined || value === '') {
310
+ return '';
311
+ }
312
+
313
+ const str = typeof value === 'string' ? value : String(value);
314
+ const len = str.length;
315
+
316
+ // Quick scan for special characters using char codes
317
+ let needsQuoting = false;
318
+ let hasQuote = false;
319
+
320
+ for (let i = 0; i < len; i++) {
321
+ const code = str.charCodeAt(i);
322
+ if (code === CHAR_CODES.QUOTE) {
323
+ hasQuote = true;
324
+ needsQuoting = true;
325
+ } else if (code === delimiterCode || code === CHAR_CODES.NEWLINE || code === CHAR_CODES.CARRIAGE) {
326
+ needsQuoting = true;
327
+ }
328
+ }
329
+
330
+ if (!needsQuoting) {
331
+ return str;
332
+ }
333
+
334
+ const escaped = hasQuote ? str.replace(QUOTE_REGEX, '""') : str;
335
+ return `"${escaped}"`;
336
+ }
337
+
338
+ /**
339
+ * Async iterator utilities for streaming
340
+ */
341
+ export const asyncIterUtils = {
342
+ /**
343
+ * Map over async iterator with concurrency control (Node 20+)
344
+ */
345
+ async *mapConcurrent<T, R>(
346
+ iterator: AsyncIterable<T>,
347
+ mapper: (item: T) => Promise<R> | R,
348
+ concurrency = 4
349
+ ): AsyncGenerator<R> {
350
+ const pending: Promise<R>[] = [];
351
+
352
+ for await (const item of iterator) {
353
+ pending.push(Promise.resolve(mapper(item)));
354
+
355
+ if (pending.length >= concurrency) {
356
+ const results = await Promise.all(pending.splice(0, concurrency));
357
+ for (const result of results) {
358
+ yield result;
359
+ }
360
+ }
361
+ }
362
+
363
+ if (pending.length > 0) {
364
+ const results = await Promise.all(pending);
365
+ for (const result of results) {
366
+ yield result;
367
+ }
368
+ }
369
+ },
370
+
371
+ /**
372
+ * Batch items from async iterator
373
+ */
374
+ async *batch<T>(iterator: AsyncIterable<T>, size = 1000): AsyncGenerator<T[]> {
375
+ let batch: T[] = [];
376
+
377
+ for await (const item of iterator) {
378
+ batch.push(item);
379
+
380
+ if (batch.length >= size) {
381
+ yield batch;
382
+ batch = [];
383
+ }
384
+ }
385
+
386
+ if (batch.length > 0) {
387
+ yield batch;
388
+ }
389
+ }
390
+ };
391
+
392
+ /**
393
+ * Get runtime optimization hints
394
+ */
395
+ export function getOptimizationHints(): {
396
+ nodeVersion: string;
397
+ features: typeof features;
398
+ recommendations: {
399
+ useWebStreams: boolean;
400
+ useStructuredClone: boolean;
401
+ useLargerBatches: boolean;
402
+ useHigherParallelism: boolean;
403
+ preferredChunkSize: number;
404
+ };
405
+ } {
406
+ return {
407
+ nodeVersion: `${major}.${minor}`,
408
+ features,
409
+ recommendations: {
410
+ useWebStreams: features.hasWebStreams,
411
+ useStructuredClone: features.hasStructuredClone,
412
+ useLargerBatches: features.isNode20Plus,
413
+ useHigherParallelism: features.isNode22Plus,
414
+ preferredChunkSize: features.isNode24Plus ? 131072 : (features.isNode20Plus ? 65536 : 16384)
415
+ }
416
+ };
417
+ }
418
+
419
+ export const nodeVersionInfo = { major, minor };
420
+
421
+ export default {
422
+ // Feature detection
423
+ features,
424
+ nodeVersion: { major, minor },
425
+
426
+ // Polyfills and optimized functions
427
+ hasOwn,
428
+ deepClone,
429
+ arrayAt,
430
+
431
+ // Classes
432
+ StringBuilderOptimized,
433
+ RowBuffer,
434
+ ObjectPool,
435
+
436
+ // Constants
437
+ CHAR_CODES,
438
+
439
+ // Functions
440
+ fastDetectDelimiter,
441
+ fastEscapeValue,
442
+ createBatchProcessor,
443
+
444
+ // Async utilities
445
+ asyncIterUtils,
446
+
447
+ // Diagnostics
448
+ getOptimizationHints
449
+ };
@@ -97,7 +97,9 @@ class PluginManager {
97
97
  }
98
98
 
99
99
  this.stats.pluginLoads++;
100
- console.log(`✅ Plugin "${name}" зарегистрирован`);
100
+ if (process.env.NODE_ENV === 'development') {
101
+ console.log(`✅ Plugin "${name}" зарегистрирован`);
102
+ }
101
103
  return this;
102
104
  }
103
105
 
@@ -163,7 +165,9 @@ class PluginManager {
163
165
  registeredAt: new Date()
164
166
  });
165
167
 
166
- console.log(`📌 Hook "${hookName}" зарегистрирован${pluginName ? ` для плагина "${pluginName}"` : ''}`);
168
+ if (process.env.NODE_ENV === 'development') {
169
+ console.log(`📌 Hook "${hookName}" зарегистрирован${pluginName ? ` для плагина "${pluginName}"` : ''}`);
170
+ }
167
171
  }
168
172
 
169
173
  /**
@@ -178,7 +182,9 @@ class PluginManager {
178
182
  registeredAt: new Date()
179
183
  });
180
184
 
181
- console.log(`🔄 Middleware "${name || 'anonymous'}" зарегистрирован`);
185
+ if (process.env.NODE_ENV === 'development') {
186
+ console.log(`🔄 Middleware "${name || 'anonymous'}" зарегистрирован`);
187
+ }
182
188
  }
183
189
 
184
190
  /**
@@ -195,7 +201,9 @@ class PluginManager {
195
201
  return data;
196
202
  }
197
203
 
198
- console.log(`⚡ Выполнение hook "${hookName}" с ${handlers.length} обработчиками`);
204
+ if (process.env.NODE_ENV === 'development') {
205
+ console.log(`⚡ Выполнение hook "${hookName}" с ${handlers.length} обработчиками`);
206
+ }
199
207
 
200
208
  let result = data;
201
209
 
@@ -238,7 +246,9 @@ class PluginManager {
238
246
  return ctx;
239
247
  }
240
248
 
241
- console.log(`🚀 Запуск middleware pipeline с ${this.middlewares.length} middleware`);
249
+ if (process.env.NODE_ENV === 'development') {
250
+ console.log(`🚀 Запуск middleware pipeline с ${this.middlewares.length} middleware`);
251
+ }
242
252
 
243
253
  let index = -1;
244
254
  const middlewares = this.middlewares.map(m => m.middleware);
@@ -336,8 +346,10 @@ class PluginManager {
336
346
  // Записываем время выполнения
337
347
  ctx.duration = Date.now() - ctx.startTime;
338
348
 
339
- // Логируем успешное выполнение
340
- console.log(`✅ Операция "${operation}" выполнена за ${ctx.duration}ms`);
349
+ // Логируем успешное выполнение только в development
350
+ if (process.env.NODE_ENV === 'development') {
351
+ console.log(`✅ Операция "${operation}" выполнена за ${ctx.duration}ms`);
352
+ }
341
353
 
342
354
  return ctx.result;
343
355
  } catch (error) {
@@ -407,7 +419,9 @@ class PluginManager {
407
419
 
408
420
  plugin.enabled = enabled;
409
421
  /* istanbul ignore next */
410
- console.log(`🔧 Plugin "${pluginName}" ${enabled ? 'включен' : 'выключен'}`);
422
+ if (process.env.NODE_ENV === 'development') {
423
+ console.log(`🔧 Plugin "${pluginName}" ${enabled ? 'включен' : 'выключен'}`);
424
+ }
411
425
  }
412
426
 
413
427
  /**
@@ -431,7 +445,9 @@ class PluginManager {
431
445
  // Удаляем плагин
432
446
  this.plugins.delete(pluginName);
433
447
 
434
- console.log(`🗑️ Plugin "${pluginName}" удален`);
448
+ if (process.env.NODE_ENV === 'development') {
449
+ console.log(`🗑️ Plugin "${pluginName}" удален`);
450
+ }
435
451
  }
436
452
 
437
453
  /**
@@ -469,8 +485,10 @@ class PluginManager {
469
485
  this.resetStats();
470
486
  this._registerDefaultHooks();
471
487
 
472
- console.log('🧹 Все плагины и hooks очищены');
488
+ if (process.env.NODE_ENV === 'development') {
489
+ console.log('🧹 Все плагины и hooks очищены');
490
+ }
473
491
  }
474
492
  }
475
493
 
476
- module.exports = PluginManager;
494
+ module.exports = PluginManager;