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.
Files changed (246) hide show
  1. package/README.md +204 -115
  2. package/bin/jtcsv.ts +2612 -0
  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 +1262 -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 +1736 -0
  23. package/dist/jtcsv-core.cjs.js.map +1 -0
  24. package/dist/jtcsv-core.esm.js +1708 -0
  25. package/dist/jtcsv-core.esm.js.map +1 -0
  26. package/dist/jtcsv-core.umd.js +1742 -0
  27. package/dist/jtcsv-core.umd.js.map +1 -0
  28. package/dist/jtcsv-full.cjs.js +2241 -0
  29. package/dist/jtcsv-full.cjs.js.map +1 -0
  30. package/dist/jtcsv-full.esm.js +2209 -0
  31. package/dist/jtcsv-full.esm.js.map +1 -0
  32. package/dist/jtcsv-full.umd.js +2247 -0
  33. package/dist/jtcsv-full.umd.js.map +1 -0
  34. package/dist/jtcsv-workers.esm.js +768 -0
  35. package/dist/jtcsv-workers.esm.js.map +1 -0
  36. package/dist/jtcsv-workers.umd.js +782 -0
  37. package/dist/jtcsv-workers.umd.js.map +1 -0
  38. package/dist/jtcsv.cjs.js +1996 -2048
  39. package/dist/jtcsv.cjs.js.map +1 -1
  40. package/dist/jtcsv.esm.js +1992 -2048
  41. package/dist/jtcsv.esm.js.map +1 -1
  42. package/dist/jtcsv.umd.js +2157 -2209
  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 +112 -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/dist/src/web-server/index.js +648 -0
  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 +665 -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 +446 -0
  131. package/examples/advanced/csv-parser.worker.ts +89 -0
  132. package/examples/advanced/nested-objects-example.ts +306 -0
  133. package/examples/advanced/performance-optimization.ts +504 -0
  134. package/examples/advanced/run-demo-server.ts +116 -0
  135. package/examples/advanced/web-worker-usage.html +874 -0
  136. package/examples/async-multithreaded-example.ts +335 -0
  137. package/examples/cli-advanced-usage.md +290 -0
  138. package/examples/{cli-batch-processing.js → cli-batch-processing.ts} +38 -38
  139. package/examples/{cli-tool.js → cli-tool.ts} +5 -8
  140. package/examples/{error-handling.js → error-handling.ts} +356 -324
  141. package/examples/{express-api.js → express-api.ts} +161 -164
  142. package/examples/{large-dataset-example.js → large-dataset-example.ts} +201 -182
  143. package/examples/{ndjson-processing.js → ndjson-processing.ts} +456 -434
  144. package/examples/{plugin-excel-exporter.js → plugin-excel-exporter.ts} +6 -7
  145. package/examples/react-integration.tsx +637 -0
  146. package/examples/{schema-validation.js → schema-validation.ts} +2 -2
  147. package/examples/simple-usage.ts +194 -0
  148. package/examples/{streaming-example.js → streaming-example.ts} +12 -12
  149. package/index.d.ts +187 -18
  150. package/package.json +75 -81
  151. package/plugins.d.ts +37 -0
  152. package/schema.d.ts +103 -0
  153. package/src/browser/browser-functions.ts +402 -0
  154. package/src/browser/core.ts +152 -0
  155. package/src/browser/csv-to-json-browser.d.ts +3 -0
  156. package/src/browser/csv-to-json-browser.ts +494 -0
  157. package/src/browser/{errors-browser.js → errors-browser.ts} +305 -197
  158. package/src/browser/extensions/plugins.ts +93 -0
  159. package/src/browser/extensions/workers.ts +39 -0
  160. package/src/browser/globals.d.ts +5 -0
  161. package/src/browser/index.ts +192 -0
  162. package/src/browser/json-to-csv-browser.d.ts +3 -0
  163. package/src/browser/json-to-csv-browser.ts +338 -0
  164. package/src/browser/streams.ts +403 -0
  165. package/src/browser/workers/{csv-parser.worker.js → csv-parser.worker.ts} +3 -3
  166. package/src/browser/workers/{worker-pool.js → worker-pool.ts} +51 -30
  167. package/src/core/delimiter-cache.ts +320 -0
  168. package/src/core/{node-optimizations.js → node-optimizations.ts} +448 -407
  169. package/src/core/plugin-system.ts +588 -0
  170. package/src/core/transform-hooks.ts +566 -0
  171. package/src/engines/{fast-path-engine-new.js → fast-path-engine-new.ts} +11 -2
  172. package/src/engines/{fast-path-engine.js → fast-path-engine.ts} +79 -53
  173. package/src/errors.ts +1 -0
  174. package/src/formats/{ndjson-parser.js → ndjson-parser.ts} +24 -16
  175. package/src/formats/{tsv-parser.js → tsv-parser.ts} +18 -17
  176. package/src/{index-with-plugins.js → index-with-plugins.ts} +381 -357
  177. package/src/types/index.ts +275 -0
  178. package/src/utils/bom-utils.ts +373 -0
  179. package/src/utils/encoding-support.ts +155 -0
  180. package/src/utils/{schema-validator.js → schema-validator.ts} +814 -589
  181. package/src/utils/transform-loader.ts +389 -0
  182. package/src/utils/validators.ts +35 -0
  183. package/src/utils/zod-adapter.ts +280 -0
  184. package/src/web-server/{index.js → index.ts} +19 -19
  185. package/src/workers/csv-multithreaded.ts +310 -0
  186. package/src/workers/csv-parser.worker.ts +227 -0
  187. package/src/workers/worker-pool.ts +409 -0
  188. package/bin/jtcsv.js +0 -2462
  189. package/csv-to-json.js +0 -688
  190. package/errors.js +0 -208
  191. package/examples/simple-usage.js +0 -282
  192. package/index.js +0 -68
  193. package/json-save.js +0 -254
  194. package/json-to-csv.js +0 -526
  195. package/plugins/README.md +0 -91
  196. package/plugins/express-middleware/README.md +0 -64
  197. package/plugins/express-middleware/example.js +0 -136
  198. package/plugins/express-middleware/index.d.ts +0 -114
  199. package/plugins/express-middleware/index.js +0 -360
  200. package/plugins/express-middleware/package.json +0 -52
  201. package/plugins/fastify-plugin/index.js +0 -406
  202. package/plugins/fastify-plugin/package.json +0 -55
  203. package/plugins/hono/README.md +0 -28
  204. package/plugins/hono/index.d.ts +0 -12
  205. package/plugins/hono/index.js +0 -36
  206. package/plugins/hono/package.json +0 -35
  207. package/plugins/nestjs/README.md +0 -35
  208. package/plugins/nestjs/index.d.ts +0 -25
  209. package/plugins/nestjs/index.js +0 -77
  210. package/plugins/nestjs/package.json +0 -37
  211. package/plugins/nextjs-api/README.md +0 -57
  212. package/plugins/nextjs-api/examples/ConverterComponent.jsx +0 -386
  213. package/plugins/nextjs-api/examples/api-convert.js +0 -69
  214. package/plugins/nextjs-api/index.js +0 -387
  215. package/plugins/nextjs-api/package.json +0 -63
  216. package/plugins/nextjs-api/route.js +0 -371
  217. package/plugins/nuxt/README.md +0 -24
  218. package/plugins/nuxt/index.js +0 -21
  219. package/plugins/nuxt/package.json +0 -35
  220. package/plugins/nuxt/runtime/composables/useJtcsv.js +0 -6
  221. package/plugins/nuxt/runtime/plugin.js +0 -6
  222. package/plugins/remix/README.md +0 -26
  223. package/plugins/remix/index.d.ts +0 -16
  224. package/plugins/remix/index.js +0 -62
  225. package/plugins/remix/package.json +0 -35
  226. package/plugins/sveltekit/README.md +0 -28
  227. package/plugins/sveltekit/index.d.ts +0 -17
  228. package/plugins/sveltekit/index.js +0 -54
  229. package/plugins/sveltekit/package.json +0 -33
  230. package/plugins/trpc/README.md +0 -25
  231. package/plugins/trpc/index.d.ts +0 -7
  232. package/plugins/trpc/index.js +0 -32
  233. package/plugins/trpc/package.json +0 -34
  234. package/src/browser/browser-functions.js +0 -219
  235. package/src/browser/csv-to-json-browser.js +0 -700
  236. package/src/browser/index.js +0 -113
  237. package/src/browser/json-to-csv-browser.js +0 -309
  238. package/src/browser/streams.js +0 -393
  239. package/src/core/delimiter-cache.js +0 -186
  240. package/src/core/plugin-system.js +0 -476
  241. package/src/core/transform-hooks.js +0 -350
  242. package/src/errors.js +0 -26
  243. package/src/utils/transform-loader.js +0 -205
  244. package/stream-csv-to-json.js +0 -542
  245. package/stream-json-to-csv.js +0 -464
  246. /package/examples/{web-workers-advanced.js → web-workers-advanced.ts} +0 -0
@@ -0,0 +1,782 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.jtcsvWorkers = {}));
5
+ })(this, (function (exports) { 'use strict';
6
+
7
+ // Система ошибок для браузерной версии jtcsv
8
+ // Адаптирована для работы без Node.js специфичных API
9
+ /**
10
+ * Базовый класс ошибки jtcsv
11
+ */
12
+ class JTCSVError extends Error {
13
+ constructor(message, code = 'JTCSV_ERROR', details = {}) {
14
+ super(message);
15
+ this.name = 'JTCSVError';
16
+ this.code = code;
17
+ this.details = details;
18
+ this.hint = details.hint;
19
+ this.docs = details.docs;
20
+ this.context = details.context;
21
+ // Сохранение stack trace
22
+ if (Error.captureStackTrace) {
23
+ Error.captureStackTrace(this, JTCSVError);
24
+ }
25
+ }
26
+ }
27
+ /**
28
+ * Ошибка валидации
29
+ */
30
+ class ValidationError extends JTCSVError {
31
+ constructor(message, details = {}) {
32
+ super(message, 'VALIDATION_ERROR', details);
33
+ this.name = 'ValidationError';
34
+ }
35
+ }
36
+ /**
37
+ * Ошибка безопасности
38
+ */
39
+ class SecurityError extends JTCSVError {
40
+ constructor(message, details = {}) {
41
+ super(message, 'SECURITY_ERROR', details);
42
+ this.name = 'SecurityError';
43
+ }
44
+ }
45
+ /**
46
+ * Ошибка файловой системы (адаптирована для браузера)
47
+ */
48
+ class FileSystemError extends JTCSVError {
49
+ constructor(message, originalError, details = {}) {
50
+ super(message, 'FILE_SYSTEM_ERROR', { ...details, originalError });
51
+ this.name = 'FileSystemError';
52
+ if (originalError && originalError.code) {
53
+ this.code = originalError.code;
54
+ }
55
+ }
56
+ }
57
+ /**
58
+ * Ошибка парсинга
59
+ */
60
+ class ParsingError extends JTCSVError {
61
+ constructor(message, lineNumber, details = {}) {
62
+ super(message, 'PARSING_ERROR', { ...details, lineNumber });
63
+ this.name = 'ParsingError';
64
+ this.lineNumber = lineNumber;
65
+ }
66
+ }
67
+ /**
68
+ * Ошибка превышения лимита
69
+ */
70
+ class LimitError extends JTCSVError {
71
+ constructor(message, limit, actual, details = {}) {
72
+ super(message, 'LIMIT_ERROR', { ...details, limit, actual });
73
+ this.name = 'LimitError';
74
+ this.limit = limit;
75
+ this.actual = actual;
76
+ }
77
+ }
78
+ /**
79
+ * Ошибка конфигурации
80
+ */
81
+ class ConfigurationError extends JTCSVError {
82
+ constructor(message, details = {}) {
83
+ super(message, 'CONFIGURATION_ERROR', details);
84
+ this.name = 'ConfigurationError';
85
+ }
86
+ }
87
+ /**
88
+ * Коды ошибок
89
+ */
90
+ const ERROR_CODES = {
91
+ JTCSV_ERROR: 'JTCSV_ERROR',
92
+ VALIDATION_ERROR: 'VALIDATION_ERROR',
93
+ SECURITY_ERROR: 'SECURITY_ERROR',
94
+ FILE_SYSTEM_ERROR: 'FILE_SYSTEM_ERROR',
95
+ PARSING_ERROR: 'PARSING_ERROR',
96
+ LIMIT_ERROR: 'LIMIT_ERROR',
97
+ CONFIGURATION_ERROR: 'CONFIGURATION_ERROR',
98
+ INVALID_INPUT: 'INVALID_INPUT',
99
+ SECURITY_VIOLATION: 'SECURITY_VIOLATION',
100
+ FILE_NOT_FOUND: 'FILE_NOT_FOUND',
101
+ PARSE_FAILED: 'PARSE_FAILED',
102
+ SIZE_LIMIT: 'SIZE_LIMIT',
103
+ INVALID_CONFIG: 'INVALID_CONFIG',
104
+ UNKNOWN_ERROR: 'UNKNOWN_ERROR'
105
+ };
106
+ /**
107
+ * Безопасное выполнение функции с обработкой ошибок
108
+ *
109
+ * @param fn - Функция для выполнения
110
+ * @param errorCode - Код ошибки по умолчанию
111
+ * @param errorDetails - Детали ошибки
112
+ * @returns Результат выполнения функции
113
+ */
114
+ function safeExecute(fn, errorCode = 'UNKNOWN_ERROR', errorDetails = {}) {
115
+ try {
116
+ if (typeof fn === 'function') {
117
+ return fn();
118
+ }
119
+ throw new ValidationError('Function expected');
120
+ }
121
+ catch (error) {
122
+ // Если ошибка уже является JTCSVError, перебросить её
123
+ if (error instanceof JTCSVError) {
124
+ throw error;
125
+ }
126
+ // Определить тип ошибки на основе сообщения или кода
127
+ let enhancedError;
128
+ const errorMessage = error.message || String(error);
129
+ if (errorMessage.includes('validation') || errorMessage.includes('Validation')) {
130
+ enhancedError = new ValidationError(errorMessage, { ...errorDetails, originalError: error });
131
+ }
132
+ else if (errorMessage.includes('security') || errorMessage.includes('Security')) {
133
+ enhancedError = new SecurityError(errorMessage, { ...errorDetails, originalError: error });
134
+ }
135
+ else if (errorMessage.includes('parsing') || errorMessage.includes('Parsing')) {
136
+ enhancedError = new ParsingError(errorMessage, undefined, { ...errorDetails, originalError: error });
137
+ }
138
+ else if (errorMessage.includes('limit') || errorMessage.includes('Limit')) {
139
+ enhancedError = new LimitError(errorMessage, null, null, { ...errorDetails, originalError: error });
140
+ }
141
+ else if (errorMessage.includes('configuration') || errorMessage.includes('Configuration')) {
142
+ enhancedError = new ConfigurationError(errorMessage, { ...errorDetails, originalError: error });
143
+ }
144
+ else if (errorMessage.includes('file') || errorMessage.includes('File')) {
145
+ enhancedError = new FileSystemError(errorMessage, error, errorDetails);
146
+ }
147
+ else {
148
+ // Общая ошибка
149
+ enhancedError = new JTCSVError(errorMessage, errorCode, { ...errorDetails, originalError: error });
150
+ }
151
+ // Сохранить оригинальный stack trace если возможно
152
+ if (error.stack) {
153
+ enhancedError.stack = error.stack;
154
+ }
155
+ throw enhancedError;
156
+ }
157
+ }
158
+ /**
159
+ * Асинхронная версия safeExecute
160
+ */
161
+ async function safeExecuteAsync(fn, errorCode = 'UNKNOWN_ERROR', errorDetails = {}) {
162
+ try {
163
+ if (typeof fn === 'function') {
164
+ return await fn();
165
+ }
166
+ throw new ValidationError('Function expected');
167
+ }
168
+ catch (error) {
169
+ // Если ошибка уже является JTCSVError, перебросить её
170
+ if (error instanceof JTCSVError) {
171
+ throw error;
172
+ }
173
+ // Определить тип ошибки
174
+ let enhancedError;
175
+ const errorMessage = error.message || String(error);
176
+ if (errorMessage.includes('validation') || errorMessage.includes('Validation')) {
177
+ enhancedError = new ValidationError(errorMessage, { ...errorDetails, originalError: error });
178
+ }
179
+ else if (errorMessage.includes('security') || errorMessage.includes('Security')) {
180
+ enhancedError = new SecurityError(errorMessage, { ...errorDetails, originalError: error });
181
+ }
182
+ else if (errorMessage.includes('parsing') || errorMessage.includes('Parsing')) {
183
+ enhancedError = new ParsingError(errorMessage, undefined, { ...errorDetails, originalError: error });
184
+ }
185
+ else if (errorMessage.includes('limit') || errorMessage.includes('Limit')) {
186
+ enhancedError = new LimitError(errorMessage, null, null, { ...errorDetails, originalError: error });
187
+ }
188
+ else if (errorMessage.includes('configuration') || errorMessage.includes('Configuration')) {
189
+ enhancedError = new ConfigurationError(errorMessage, { ...errorDetails, originalError: error });
190
+ }
191
+ else if (errorMessage.includes('file') || errorMessage.includes('File')) {
192
+ enhancedError = new FileSystemError(errorMessage, error, errorDetails);
193
+ }
194
+ else {
195
+ enhancedError = new JTCSVError(errorMessage, errorCode, { ...errorDetails, originalError: error });
196
+ }
197
+ if (error.stack) {
198
+ enhancedError.stack = error.stack;
199
+ }
200
+ throw enhancedError;
201
+ }
202
+ }
203
+ /**
204
+ * Создать сообщение об ошибке
205
+ */
206
+ function createErrorMessage(error, includeStack = false) {
207
+ let message = error.message || 'Unknown error';
208
+ if (error instanceof JTCSVError) {
209
+ message = `[${error.code}] ${message}`;
210
+ if (error instanceof ParsingError && error.lineNumber) {
211
+ message += ` (line ${error.lineNumber})`;
212
+ }
213
+ if (error instanceof LimitError && error.limit && error.actual) {
214
+ message += ` (limit: ${error.limit}, actual: ${error.actual})`;
215
+ }
216
+ if (error.hint) {
217
+ message += `\nHint: ${error.hint}`;
218
+ }
219
+ if (error.docs) {
220
+ message += `\nDocs: ${error.docs}`;
221
+ }
222
+ }
223
+ if (includeStack && error.stack) {
224
+ message += `\n${error.stack}`;
225
+ }
226
+ return message;
227
+ }
228
+ /**
229
+ * Обработка ошибки
230
+ */
231
+ function handleError(error, options = {}) {
232
+ const { log = true, throw: shouldThrow = false, format = true } = options;
233
+ const message = format ? createErrorMessage(error) : error.message;
234
+ if (log) {
235
+ console.error(`[jtcsv] ${message}`);
236
+ if (error instanceof JTCSVError && error.details) {
237
+ console.error('Error details:', error.details);
238
+ }
239
+ }
240
+ if (shouldThrow) {
241
+ throw error;
242
+ }
243
+ return message;
244
+ }
245
+ // Экспорт для Node.js совместимости
246
+ if (typeof module !== 'undefined' && module.exports) {
247
+ module.exports = {
248
+ JTCSVError,
249
+ ValidationError,
250
+ SecurityError,
251
+ FileSystemError,
252
+ ParsingError,
253
+ LimitError,
254
+ ConfigurationError,
255
+ ERROR_CODES,
256
+ safeExecute,
257
+ safeExecuteAsync,
258
+ createErrorMessage,
259
+ handleError
260
+ };
261
+ }
262
+
263
+ // Worker Pool для параллельной обработки CSV
264
+ // Использует Comlink для простой коммуникации с Web Workers
265
+ // Проверка поддержки Web Workers
266
+ const WORKERS_SUPPORTED = typeof Worker !== 'undefined';
267
+ function isTransferableBuffer(value) {
268
+ if (!(value instanceof ArrayBuffer)) {
269
+ return false;
270
+ }
271
+ if (typeof SharedArrayBuffer !== 'undefined' && value instanceof SharedArrayBuffer) {
272
+ return false;
273
+ }
274
+ return true;
275
+ }
276
+ function collectTransferables(args) {
277
+ const transferables = [];
278
+ const collectFromValue = (value) => {
279
+ if (!value) {
280
+ return;
281
+ }
282
+ if (isTransferableBuffer(value)) {
283
+ transferables.push(value);
284
+ return;
285
+ }
286
+ if (ArrayBuffer.isView(value) && isTransferableBuffer(value.buffer)) {
287
+ transferables.push(value.buffer);
288
+ return;
289
+ }
290
+ if (Array.isArray(value)) {
291
+ value.forEach(collectFromValue);
292
+ }
293
+ };
294
+ args.forEach(collectFromValue);
295
+ return transferables.length ? transferables : null;
296
+ }
297
+ /**
298
+ * Опции для Worker Pool
299
+ * @typedef {Object} WorkerPoolOptions
300
+ * @property {number} [workerCount=4] - Количество workers в pool
301
+ * @property {number} [maxQueueSize=100] - Максимальный размер очереди задач
302
+ * @property {boolean} [autoScale=true] - Автоматическое масштабирование pool
303
+ * @property {number} [idleTimeout=60000] - Таймаут простоя worker (мс)
304
+ */
305
+ /**
306
+ * Статистика Worker Pool
307
+ * @typedef {Object} WorkerPoolStats
308
+ * @property {number} totalWorkers - Всего workers
309
+ * @property {number} activeWorkers - Активные workers
310
+ * @property {number} idleWorkers - Простаивающие workers
311
+ * @property {number} queueSize - Размер очереди
312
+ * @property {number} tasksCompleted - Завершенные задачи
313
+ * @property {number} tasksFailed - Неудачные задачи
314
+ */
315
+ /**
316
+ * Прогресс обработки задачи
317
+ * @typedef {Object} TaskProgress
318
+ * @property {number} processed - Обработано элементов
319
+ * @property {number} total - Всего элементов
320
+ * @property {number} percentage - Процент выполнения
321
+ * @property {number} speed - Скорость обработки (элементов/сек)
322
+ */
323
+ /**
324
+ * Worker Pool для параллельной обработки CSV
325
+ */
326
+ class WorkerPool {
327
+ /**
328
+ * Создает новый Worker Pool
329
+ * @param {string} workerScript - URL скрипта worker
330
+ * @param {WorkerPoolOptions} [options] - Опции pool
331
+ */
332
+ constructor(workerScript, options = {}) {
333
+ if (!WORKERS_SUPPORTED) {
334
+ throw new ValidationError('Web Workers не поддерживаются в этом браузере');
335
+ }
336
+ this.workerScript = workerScript;
337
+ this.options = {
338
+ workerCount: 4,
339
+ maxQueueSize: 100,
340
+ autoScale: true,
341
+ idleTimeout: 60000,
342
+ ...options
343
+ };
344
+ this.workers = [];
345
+ this.taskQueue = [];
346
+ this.activeTasks = new Map();
347
+ this.stats = {
348
+ totalWorkers: 0,
349
+ activeWorkers: 0,
350
+ idleWorkers: 0,
351
+ queueSize: 0,
352
+ tasksCompleted: 0,
353
+ tasksFailed: 0
354
+ };
355
+ this.initializeWorkers();
356
+ }
357
+ /**
358
+ * Инициализация workers
359
+ * @private
360
+ */
361
+ initializeWorkers() {
362
+ const { workerCount } = this.options;
363
+ for (let i = 0; i < workerCount; i++) {
364
+ this.createWorker();
365
+ }
366
+ this.updateStats();
367
+ }
368
+ /**
369
+ * Создает нового worker
370
+ * @private
371
+ */
372
+ createWorker() {
373
+ try {
374
+ const worker = new Worker(this.workerScript, { type: 'module' });
375
+ worker.id = `worker-${this.workers.length}`;
376
+ worker.status = 'idle';
377
+ worker.lastUsed = Date.now();
378
+ worker.taskId = null;
379
+ // Обработчики событий
380
+ worker.onmessage = (event) => this.handleWorkerMessage(worker, event);
381
+ worker.onerror = (error) => this.handleWorkerError(worker, error);
382
+ worker.onmessageerror = (error) => this.handleWorkerMessageError(worker, error);
383
+ this.workers.push(worker);
384
+ this.stats.totalWorkers++;
385
+ this.stats.idleWorkers++;
386
+ return worker;
387
+ }
388
+ catch (error) {
389
+ throw new ConfigurationError(`Не удалось создать worker: ${error.message}`);
390
+ }
391
+ }
392
+ /**
393
+ * Обработка сообщений от worker
394
+ * @private
395
+ */
396
+ handleWorkerMessage(worker, event) {
397
+ const { data } = event;
398
+ if (data.type === 'PROGRESS') {
399
+ this.handleProgress(worker, data);
400
+ }
401
+ else if (data.type === 'RESULT') {
402
+ this.handleResult(worker, data);
403
+ }
404
+ else if (data.type === 'ERROR') {
405
+ this.handleWorkerTaskError(worker, data);
406
+ }
407
+ }
408
+ /**
409
+ * Обработка прогресса задачи
410
+ * @private
411
+ */
412
+ handleProgress(worker, progressData) {
413
+ const taskId = worker.taskId;
414
+ if (taskId && this.activeTasks.has(taskId)) {
415
+ const task = this.activeTasks.get(taskId);
416
+ if (task.onProgress) {
417
+ task.onProgress({
418
+ processed: progressData.processed,
419
+ total: progressData.total,
420
+ percentage: (progressData.processed / progressData.total) * 100,
421
+ speed: progressData.speed || 0
422
+ });
423
+ }
424
+ }
425
+ }
426
+ /**
427
+ * Обработка результата задачи
428
+ * @private
429
+ */
430
+ handleResult(worker, resultData) {
431
+ const taskId = worker.taskId;
432
+ if (taskId && this.activeTasks.has(taskId)) {
433
+ const task = this.activeTasks.get(taskId);
434
+ // Освобождение worker
435
+ worker.status = 'idle';
436
+ worker.lastUsed = Date.now();
437
+ worker.taskId = null;
438
+ this.stats.activeWorkers--;
439
+ this.stats.idleWorkers++;
440
+ // Завершение задачи
441
+ task.resolve(resultData.data);
442
+ this.activeTasks.delete(taskId);
443
+ this.stats.tasksCompleted++;
444
+ // Обработка следующей задачи в очереди
445
+ this.processQueue();
446
+ this.updateStats();
447
+ }
448
+ }
449
+ /**
450
+ * Обработка ошибки задачи
451
+ * @private
452
+ */
453
+ handleWorkerTaskError(worker, errorData) {
454
+ const taskId = worker.taskId;
455
+ if (taskId && this.activeTasks.has(taskId)) {
456
+ const task = this.activeTasks.get(taskId);
457
+ // Освобождение worker
458
+ worker.status = 'idle';
459
+ worker.lastUsed = Date.now();
460
+ worker.taskId = null;
461
+ this.stats.activeWorkers--;
462
+ this.stats.idleWorkers++;
463
+ // Завершение с ошибкой
464
+ const workerError = new Error(errorData.message || 'Ошибка в worker');
465
+ if (errorData.code) {
466
+ workerError.code = errorData.code;
467
+ }
468
+ if (errorData.details) {
469
+ workerError.details = errorData.details;
470
+ }
471
+ task.reject(workerError);
472
+ this.activeTasks.delete(taskId);
473
+ this.stats.tasksFailed++;
474
+ // Обработка следующей задачи
475
+ this.processQueue();
476
+ this.updateStats();
477
+ }
478
+ }
479
+ /**
480
+ * Обработка ошибок worker
481
+ * @private
482
+ */
483
+ handleWorkerError(worker, error) {
484
+ console.error(`Worker ${worker.id} error:`, error);
485
+ // Перезапуск worker
486
+ this.restartWorker(worker);
487
+ }
488
+ /**
489
+ * Обработка ошибок сообщений
490
+ * @private
491
+ */
492
+ handleWorkerMessageError(worker, error) {
493
+ console.error(`Worker ${worker.id} message error:`, error);
494
+ }
495
+ /**
496
+ * Перезапуск worker
497
+ * @private
498
+ */
499
+ restartWorker(worker) {
500
+ const index = this.workers.indexOf(worker);
501
+ if (index !== -1) {
502
+ // Завершение старого worker
503
+ worker.terminate();
504
+ // Удаление из статистики
505
+ if (worker.status === 'active') {
506
+ this.stats.activeWorkers--;
507
+ }
508
+ else {
509
+ this.stats.idleWorkers--;
510
+ }
511
+ this.stats.totalWorkers--;
512
+ // Создание нового worker
513
+ const newWorker = this.createWorker();
514
+ this.workers[index] = newWorker;
515
+ // Перезапуск задачи если была активна
516
+ if (worker.taskId && this.activeTasks.has(worker.taskId)) {
517
+ const task = this.activeTasks.get(worker.taskId);
518
+ this.executeTask(newWorker, task);
519
+ }
520
+ }
521
+ }
522
+ /**
523
+ * Выполнение задачи на worker
524
+ * @private
525
+ */
526
+ executeTask(worker, task) {
527
+ worker.status = 'active';
528
+ worker.lastUsed = Date.now();
529
+ worker.taskId = task.id;
530
+ this.stats.idleWorkers--;
531
+ this.stats.activeWorkers++;
532
+ // Отправка задачи в worker
533
+ const payload = {
534
+ type: 'EXECUTE',
535
+ taskId: task.id,
536
+ method: task.method,
537
+ args: task.args,
538
+ options: task.options
539
+ };
540
+ if (task.transferList && task.transferList.length) {
541
+ worker.postMessage(payload, task.transferList);
542
+ }
543
+ else {
544
+ worker.postMessage(payload);
545
+ }
546
+ }
547
+ /**
548
+ * Обработка очереди задач
549
+ * @private
550
+ */
551
+ processQueue() {
552
+ if (this.taskQueue.length === 0) {
553
+ return;
554
+ }
555
+ while (this.taskQueue.length > 0) {
556
+ const idleWorker = this.workers.find(w => w.status === 'idle');
557
+ if (!idleWorker) {
558
+ if (this.options.autoScale && this.workers.length < this.options.maxQueueSize) {
559
+ this.createWorker();
560
+ continue;
561
+ }
562
+ break;
563
+ }
564
+ const task = this.taskQueue.shift();
565
+ this.stats.queueSize--;
566
+ this.executeTask(idleWorker, task);
567
+ }
568
+ this.updateStats();
569
+ }
570
+ /**
571
+ * Обновление статистики
572
+ * @private
573
+ */
574
+ updateStats() {
575
+ this.stats.queueSize = this.taskQueue.length;
576
+ }
577
+ /**
578
+ * Выполнение задачи через pool
579
+ * @param {string} method - Метод для вызова в worker
580
+ * @param {Array} args - Аргументы метода
581
+ * @param {Object} [options] - Опции задачи
582
+ * @param {Function} [onProgress] - Callback прогресса
583
+ * @returns {Promise<unknown>} Результат выполнения
584
+ */
585
+ async exec(method, args = [], options = {}, onProgress = null) {
586
+ return new Promise((resolve, reject) => {
587
+ // Проверка размера очереди
588
+ if (this.taskQueue.length >= this.options.maxQueueSize) {
589
+ reject(new Error('Очередь задач переполнена'));
590
+ return;
591
+ }
592
+ // Создание задачи
593
+ const taskId = `task-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
594
+ const { transfer, ...taskOptions } = options || {};
595
+ const transferList = transfer || collectTransferables(args);
596
+ const task = {
597
+ id: taskId,
598
+ method,
599
+ args,
600
+ options: taskOptions,
601
+ transferList,
602
+ onProgress,
603
+ resolve,
604
+ reject,
605
+ createdAt: Date.now()
606
+ };
607
+ // Добавление в очередь
608
+ this.taskQueue.push(task);
609
+ this.stats.queueSize++;
610
+ // Запуск обработки очереди
611
+ this.processQueue();
612
+ this.updateStats();
613
+ });
614
+ }
615
+ /**
616
+ * Получение статистики pool
617
+ * @returns {WorkerPoolStats} Статистика
618
+ */
619
+ getStats() {
620
+ return { ...this.stats };
621
+ }
622
+ /**
623
+ * Очистка простаивающих workers
624
+ */
625
+ cleanupIdleWorkers() {
626
+ const now = Date.now();
627
+ const { idleTimeout } = this.options;
628
+ for (let i = this.workers.length - 1; i >= 0; i--) {
629
+ const worker = this.workers[i];
630
+ if (worker.status === 'idle' && (now - worker.lastUsed) > idleTimeout) {
631
+ // Сохранение минимального количества workers
632
+ if (this.workers.length > 1) {
633
+ worker.terminate();
634
+ this.workers.splice(i, 1);
635
+ this.stats.totalWorkers--;
636
+ this.stats.idleWorkers--;
637
+ }
638
+ }
639
+ }
640
+ }
641
+ /**
642
+ * Завершение всех workers
643
+ */
644
+ terminate() {
645
+ this.workers.forEach(worker => {
646
+ worker.terminate();
647
+ });
648
+ this.workers = [];
649
+ this.taskQueue = [];
650
+ this.activeTasks.clear();
651
+ // Сброс статистики
652
+ this.stats = {
653
+ totalWorkers: 0,
654
+ activeWorkers: 0,
655
+ idleWorkers: 0,
656
+ queueSize: 0,
657
+ tasksCompleted: 0,
658
+ tasksFailed: 0
659
+ };
660
+ }
661
+ }
662
+ /**
663
+ * Создает Worker Pool для обработки CSV
664
+ * @param {WorkerPoolOptions} [options] - Опции pool
665
+ * @returns {WorkerPool} Worker Pool
666
+ */
667
+ function createWorkerPool(options = {}) {
668
+ // Используем встроенный worker скрипт
669
+ const baseUrl = typeof document !== 'undefined'
670
+ ? document.baseURI
671
+ : (typeof self !== 'undefined' && self.location
672
+ ? self.location.href
673
+ : '');
674
+ const workerScript = new URL('./csv-parser.worker.js', baseUrl).href;
675
+ return new WorkerPool(workerScript, options);
676
+ }
677
+ /**
678
+ * Парсит CSV с использованием Web Workers
679
+ * @param {string|File} csvInput - CSV строка или File объект
680
+ * @param {Object} [options] - Опции парсинга
681
+ * @param {Function} [onProgress] - Callback прогресса
682
+ * @returns {Promise<Array<Object>>} JSON данные
683
+ */
684
+ async function parseCSVWithWorker(csvInput, options = {}, onProgress = null) {
685
+ // Создание pool если нужно
686
+ const poolHolder = parseCSVWithWorker;
687
+ if (!poolHolder.pool) {
688
+ poolHolder.pool = createWorkerPool();
689
+ }
690
+ const pool = poolHolder.pool;
691
+ // Подготовка CSV строки
692
+ // ?????????? CSV ??????
693
+ let csvPayload = csvInput;
694
+ let transfer = null;
695
+ if (csvInput instanceof File) {
696
+ const buffer = await readFileAsArrayBuffer(csvInput);
697
+ csvPayload = new Uint8Array(buffer);
698
+ transfer = [buffer];
699
+ }
700
+ else if (csvInput instanceof ArrayBuffer) {
701
+ csvPayload = csvInput;
702
+ transfer = [csvInput];
703
+ }
704
+ else if (ArrayBuffer.isView(csvInput)) {
705
+ csvPayload = csvInput;
706
+ if (csvInput.buffer instanceof ArrayBuffer) {
707
+ transfer = [csvInput.buffer];
708
+ }
709
+ }
710
+ else if (typeof csvInput !== 'string') {
711
+ throw new ValidationError('Input must be a CSV string, File, or ArrayBuffer');
712
+ }
713
+ // ????????? ?????? ????? pool
714
+ const execOptions = transfer ? { transfer } : {};
715
+ return pool.exec('parseCSV', [csvPayload, options], execOptions, onProgress);
716
+ }
717
+ /**
718
+ * Чтение файла как текст
719
+ * @private
720
+ */
721
+ async function readFileAsArrayBuffer(file) {
722
+ return new Promise((resolve, reject) => {
723
+ const reader = new FileReader();
724
+ reader.onload = (event) => resolve(event.target.result);
725
+ reader.onerror = (error) => reject(error);
726
+ reader.readAsArrayBuffer(file);
727
+ });
728
+ }
729
+ // Экспорт для Node.js совместимости
730
+ if (typeof module !== 'undefined' && module.exports) {
731
+ module.exports = {
732
+ WorkerPool,
733
+ createWorkerPool,
734
+ parseCSVWithWorker
735
+ };
736
+ }
737
+
738
+ var workerPool = /*#__PURE__*/Object.freeze({
739
+ __proto__: null,
740
+ WorkerPool: WorkerPool,
741
+ createWorkerPool: createWorkerPool,
742
+ parseCSVWithWorker: parseCSVWithWorker
743
+ });
744
+
745
+ // Расширение Web Workers для jtcsv
746
+ // Дополнительный модуль для параллельной обработки больших CSV
747
+ async function createWorkerPoolLazy(options = {}) {
748
+ const mod = await Promise.resolve().then(function () { return workerPool; });
749
+ return mod.createWorkerPool(options);
750
+ }
751
+ async function parseCSVWithWorkerLazy(csvInput, options = {}, onProgress = null) {
752
+ const mod = await Promise.resolve().then(function () { return workerPool; });
753
+ return mod.parseCSVWithWorker(csvInput, options, onProgress);
754
+ }
755
+ const jtcsvWorkers = {
756
+ createWorkerPool,
757
+ parseCSVWithWorker,
758
+ createWorkerPoolLazy,
759
+ parseCSVWithWorkerLazy
760
+ };
761
+ // Экспорт
762
+ if (typeof module !== 'undefined' && module.exports) {
763
+ module.exports = jtcsvWorkers;
764
+ }
765
+ else if (typeof define === 'function' && define.amd) {
766
+ define([], () => jtcsvWorkers);
767
+ }
768
+ else if (typeof window !== 'undefined' && window.jtcsv) {
769
+ // Расширяем глобальный jtcsv, если он существует
770
+ Object.assign(window.jtcsv, jtcsvWorkers);
771
+ }
772
+
773
+ exports.createWorkerPool = createWorkerPool;
774
+ exports.createWorkerPoolLazy = createWorkerPoolLazy;
775
+ exports.default = jtcsvWorkers;
776
+ exports.parseCSVWithWorker = parseCSVWithWorker;
777
+ exports.parseCSVWithWorkerLazy = parseCSVWithWorkerLazy;
778
+
779
+ Object.defineProperty(exports, '__esModule', { value: true });
780
+
781
+ }));
782
+ //# sourceMappingURL=jtcsv-workers.umd.js.map