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
@@ -1,350 +0,0 @@
1
- /**
2
- * Transform Hooks System
3
- * Система хуков для трансформации данных перед/после конвертации
4
- *
5
- * @version 1.0.0
6
- * @date 2026-01-23
7
- */
8
-
9
- const { ValidationError } = require('../../errors');
10
-
11
- class TransformHooks {
12
- constructor() {
13
- this.hooks = {
14
- beforeConvert: [],
15
- afterConvert: [],
16
- perRow: []
17
- };
18
- }
19
-
20
- /**
21
- * Регистрирует хук beforeConvert
22
- * @param {Function} hook - Функция хука
23
- * @returns {TransformHooks} this для цепочки вызовов
24
- */
25
- beforeConvert(hook) {
26
- if (typeof hook !== 'function') {
27
- throw new ValidationError('beforeConvert hook must be a function');
28
- }
29
- this.hooks.beforeConvert.push(hook);
30
- return this;
31
- }
32
-
33
- /**
34
- * Регистрирует хук afterConvert
35
- * @param {Function} hook - Функция хука
36
- * @returns {TransformHooks} this для цепочки вызовов
37
- */
38
- afterConvert(hook) {
39
- if (typeof hook !== 'function') {
40
- throw new ValidationError('afterConvert hook must be a function');
41
- }
42
- this.hooks.afterConvert.push(hook);
43
- return this;
44
- }
45
-
46
- /**
47
- * Регистрирует per-row хук
48
- * @param {Function} hook - Функция хука
49
- * @returns {TransformHooks} this для цепочки вызовов
50
- */
51
- perRow(hook) {
52
- if (typeof hook !== 'function') {
53
- throw new ValidationError('perRow hook must be a function');
54
- }
55
- this.hooks.perRow.push(hook);
56
- return this;
57
- }
58
-
59
- /**
60
- * Применяет beforeConvert хуки
61
- * @param {any} data - Входные данные
62
- * @param {Object} context - Контекст выполнения
63
- * @returns {any} Трансформированные данные
64
- */
65
- applyBeforeConvert(data, context = {}) {
66
- let result = data;
67
- for (const hook of this.hooks.beforeConvert) {
68
- result = hook(result, context);
69
- }
70
- return result;
71
- }
72
-
73
- /**
74
- * Применяет afterConvert хуки
75
- * @param {any} data - Выходные данные
76
- * @param {Object} context - Контекст выполнения
77
- * @returns {any} Трансформированные данные
78
- */
79
- applyAfterConvert(data, context = {}) {
80
- let result = data;
81
- for (const hook of this.hooks.afterConvert) {
82
- result = hook(result, context);
83
- }
84
- return result;
85
- }
86
-
87
- /**
88
- * Применяет per-row хуки
89
- * @param {any} row - Строка данных
90
- * @param {number} index - Индекс строки
91
- * @param {Object} context - Контекст выполнения
92
- * @returns {any} Трансформированная строка
93
- */
94
- applyPerRow(row, index, context = {}) {
95
- let result = row;
96
- for (const hook of this.hooks.perRow) {
97
- result = hook(result, index, context);
98
- }
99
- return result;
100
- }
101
-
102
- /**
103
- * Применяет все хуки к массиву данных
104
- * @param {Array} data - Массив данных
105
- * @param {Object} context - Контекст выполнения
106
- * @returns {Array} Трансформированный массив
107
- */
108
- applyAll(data, context = {}) {
109
- if (!Array.isArray(data)) {
110
- throw new ValidationError('Data must be an array for applyAll');
111
- }
112
-
113
- // Применяем beforeConvert хуки
114
- let processedData = this.applyBeforeConvert(data, context);
115
-
116
- // Применяем per-row хуки к каждой строке
117
- if (this.hooks.perRow.length > 0) {
118
- processedData = processedData.map((row, index) =>
119
- this.applyPerRow(row, index, context)
120
- );
121
- }
122
-
123
- // Применяем afterConvert хуки
124
- return this.applyAfterConvert(processedData, context);
125
- }
126
-
127
- /**
128
- * Создает копию системы хуков
129
- * @returns {TransformHooks} Новая копия
130
- */
131
- clone() {
132
- const cloned = new TransformHooks();
133
- cloned.hooks = {
134
- beforeConvert: [...this.hooks.beforeConvert],
135
- afterConvert: [...this.hooks.afterConvert],
136
- perRow: [...this.hooks.perRow]
137
- };
138
- return cloned;
139
- }
140
-
141
- /**
142
- * Очищает все хуки
143
- */
144
- clear() {
145
- this.hooks = {
146
- beforeConvert: [],
147
- afterConvert: [],
148
- perRow: []
149
- };
150
- }
151
-
152
- /**
153
- * Возвращает статистику по хукам
154
- * @returns {Object} Статистика
155
- */
156
- getStats() {
157
- return {
158
- beforeConvert: this.hooks.beforeConvert.length,
159
- afterConvert: this.hooks.afterConvert.length,
160
- perRow: this.hooks.perRow.length,
161
- total: this.hooks.beforeConvert.length +
162
- this.hooks.afterConvert.length +
163
- this.hooks.perRow.length
164
- };
165
- }
166
- }
167
-
168
- /**
169
- * Предопределенные хуки
170
- */
171
- const predefinedHooks = {
172
- /**
173
- * Хук для фильтрации данных
174
- * @param {Function} predicate - Функция-предикат
175
- * @returns {Function} Хук фильтрации
176
- */
177
- filter(predicate) {
178
- return (data) => {
179
- if (Array.isArray(data)) {
180
- return data.filter(predicate);
181
- }
182
- return data;
183
- };
184
- },
185
-
186
- /**
187
- * Хук для маппинга данных
188
- * @param {Function} mapper - Функция-маппер
189
- * @returns {Function} Хук маппинга
190
- */
191
- map(mapper) {
192
- return (data) => {
193
- if (Array.isArray(data)) {
194
- return data.map(mapper);
195
- }
196
- return data;
197
- };
198
- },
199
-
200
- /**
201
- * Хук для сортировки данных
202
- * @param {Function} compareFn - Функция сравнения
203
- * @returns {Function} Хук сортировки
204
- */
205
- sort(compareFn) {
206
- return (data) => {
207
- if (Array.isArray(data)) {
208
- return [...data].sort(compareFn);
209
- }
210
- return data;
211
- };
212
- },
213
-
214
- /**
215
- * Хук для ограничения количества записей
216
- * @param {number} limit - Максимальное количество записей
217
- * @returns {Function} Хук ограничения
218
- */
219
- limit(limit) {
220
- return (data) => {
221
- if (Array.isArray(data)) {
222
- return data.slice(0, limit);
223
- }
224
- return data;
225
- };
226
- },
227
-
228
- /**
229
- * Хук для добавления метаданных
230
- * @param {Object} metadata - Метаданные для добавления
231
- * @returns {Function} Хук добавления метаданных
232
- */
233
- addMetadata(metadata) {
234
- return (data, context) => {
235
- if (Array.isArray(data)) {
236
- return data.map(item => ({
237
- ...item,
238
- _metadata: {
239
- ...metadata,
240
- timestamp: new Date().toISOString(),
241
- context
242
- }
243
- }));
244
- }
245
- return data;
246
- };
247
- },
248
-
249
- /**
250
- * Хук для преобразования ключей
251
- * @param {Function} keyTransformer - Функция преобразования ключей
252
- * @returns {Function} Хук преобразования ключей
253
- */
254
- transformKeys(keyTransformer) {
255
- return (data) => {
256
- if (Array.isArray(data)) {
257
- return data.map(item => {
258
- const transformed = {};
259
- for (const [key, value] of Object.entries(item)) {
260
- transformed[keyTransformer(key)] = value;
261
- }
262
- return transformed;
263
- });
264
- }
265
- return data;
266
- };
267
- },
268
-
269
- /**
270
- * Хук для преобразования значений
271
- * @param {Function} valueTransformer - Функция преобразования значений
272
- * @returns {Function} Хук преобразования значений
273
- */
274
- transformValues(valueTransformer) {
275
- return (data) => {
276
- if (Array.isArray(data)) {
277
- return data.map(item => {
278
- const transformed = {};
279
- for (const [key, value] of Object.entries(item)) {
280
- transformed[key] = valueTransformer(value, key);
281
- }
282
- return transformed;
283
- });
284
- }
285
- return data;
286
- };
287
- },
288
-
289
- /**
290
- * Хук для валидации данных
291
- * @param {Function} validator - Функция валидации
292
- * @param {Function} onError - Обработчик ошибки
293
- * @returns {Function} Хук валидации
294
- */
295
- validate(validator, onError = console.error) {
296
- return (data) => {
297
- if (Array.isArray(data)) {
298
- const validData = [];
299
- const errors = [];
300
-
301
- data.forEach((item, index) => {
302
- try {
303
- const isValid = validator(item, index);
304
- if (isValid) {
305
- validData.push(item);
306
- } else {
307
- errors.push({ index, item, reason: 'Validation failed' });
308
- }
309
- } catch (error) {
310
- errors.push({ index, item, error: error.message });
311
- }
312
- });
313
-
314
- if (errors.length > 0) {
315
- onError('Validation errors:', errors);
316
- }
317
-
318
- return validData;
319
- }
320
- return data;
321
- };
322
- },
323
-
324
- /**
325
- * Хук для дедупликации данных
326
- * @param {Function} keySelector - Функция выбора ключа
327
- * @returns {Function} Хук дедупликации
328
- */
329
- deduplicate(keySelector = JSON.stringify) {
330
- return (data) => {
331
- if (Array.isArray(data)) {
332
- const seen = new Set();
333
- return data.filter(item => {
334
- const key = keySelector(item);
335
- if (seen.has(key)) {
336
- return false;
337
- }
338
- seen.add(key);
339
- return true;
340
- });
341
- }
342
- return data;
343
- };
344
- }
345
- };
346
-
347
- module.exports = {
348
- TransformHooks,
349
- predefinedHooks
350
- };
package/src/errors.js DELETED
@@ -1,26 +0,0 @@
1
- class ValidationError extends Error {
2
- constructor(message) {
3
- super(message);
4
- this.name = 'ValidationError';
5
- }
6
- }
7
-
8
- class SecurityError extends Error {
9
- constructor(message) {
10
- super(message);
11
- this.name = 'SecurityError';
12
- }
13
- }
14
-
15
- class ConfigurationError extends Error {
16
- constructor(message) {
17
- super(message);
18
- this.name = 'ConfigurationError';
19
- }
20
- }
21
-
22
- module.exports = {
23
- ValidationError,
24
- SecurityError,
25
- ConfigurationError
26
- };
@@ -1,205 +0,0 @@
1
- /**
2
- * Transform Loader Utility
3
- *
4
- * Utility for loading and applying transform functions from JavaScript files
5
- */
6
-
7
- const fs = require('fs');
8
- const path = require('path');
9
- const vm = require('vm');
10
-
11
- const {
12
- ValidationError,
13
- SecurityError,
14
- ConfigurationError
15
- } = require('../errors');
16
-
17
- /**
18
- * Validates transform function
19
- * @private
20
- */
21
- function validateTransformFunction(fn) {
22
- if (typeof fn !== 'function') {
23
- throw new ValidationError('Transform must export a function');
24
- }
25
-
26
- // Check function arity (should accept 1-2 parameters)
27
- const functionString = fn.toString();
28
- const paramMatch = functionString.match(/\(([^)]*)\)/);
29
- if (paramMatch) {
30
- const params = paramMatch[1].split(',').map(p => p.trim()).filter(p => p);
31
- if (params.length === 0 || params.length > 2) {
32
- throw new ValidationError('Transform function should accept 1-2 parameters: (row, index)');
33
- }
34
- }
35
-
36
- return true;
37
- }
38
-
39
- /**
40
- * Loads transform function from a JavaScript file
41
- *
42
- * @param {string} transformPath - Path to JavaScript file with transform function
43
- * @returns {Function} Transform function
44
- *
45
- * @example
46
- * // transform.js
47
- * module.exports = function(row, index) {
48
- * return { ...row, processed: true, index };
49
- * };
50
- *
51
- * // Usage
52
- * const transform = loadTransform('./transform.js');
53
- * const result = transform({ id: 1, name: 'John' }, 0);
54
- */
55
- function loadTransform(transformPath) {
56
- if (!transformPath || typeof transformPath !== 'string') {
57
- throw new ValidationError('Transform path must be a string');
58
- }
59
-
60
- // Validate file path
61
- const safePath = path.resolve(transformPath);
62
-
63
- // Prevent directory traversal
64
- const normalizedPath = path.normalize(transformPath);
65
- if (normalizedPath.includes('..') ||
66
- /\\\.\.\\|\/\.\.\//.test(transformPath) ||
67
- transformPath.startsWith('..') ||
68
- transformPath.includes('/..')) {
69
- throw new SecurityError('Directory traversal detected in transform file path');
70
- }
71
-
72
- // Check file exists and has .js extension
73
- if (!fs.existsSync(safePath)) {
74
- throw new ValidationError(`Transform file not found: ${transformPath}`);
75
- }
76
-
77
- if (!safePath.toLowerCase().endsWith('.js')) {
78
- throw new ValidationError('Transform file must have .js extension');
79
- }
80
-
81
- try {
82
- // Read and evaluate the transform file in a safe context
83
- const transformCode = fs.readFileSync(safePath, 'utf8');
84
-
85
- // Create a safe context with limited access
86
- const sandbox = {
87
- console,
88
- require,
89
- module: { exports: {} },
90
- exports: {},
91
- __filename: safePath,
92
- __dirname: path.dirname(safePath),
93
- Buffer,
94
- process: {
95
- env: process.env,
96
- cwd: process.cwd,
97
- platform: process.platform
98
- }
99
- };
100
-
101
- // Create a context and run the code
102
- const context = vm.createContext(sandbox);
103
- const script = new vm.Script(transformCode, { filename: safePath });
104
- script.runInContext(context);
105
-
106
- // Get the exported function
107
- const transformFn = context.module.exports || context.exports;
108
-
109
- // Handle default export for ES6 modules
110
- const finalTransform = transformFn.default || transformFn;
111
-
112
- // Validate the transform function
113
- validateTransformFunction(finalTransform);
114
-
115
- return finalTransform;
116
- } catch (error) {
117
- if (error instanceof ValidationError || error instanceof SecurityError) {
118
- throw error;
119
- }
120
-
121
- if (error.code === 'EACCES') {
122
- throw new SecurityError(`Permission denied reading transform file: ${transformPath}`);
123
- }
124
-
125
- throw new ValidationError(`Failed to load transform function: ${error.message}`);
126
- }
127
- }
128
-
129
- /**
130
- * Creates a transform hook for use with csvToJson/jsonToCsv hooks system
131
- *
132
- * @param {string|Function} transform - Transform function or path to transform file
133
- * @returns {Function} Transform hook function
134
- */
135
- function createTransformHook(transform) {
136
- let transformFn;
137
-
138
- if (typeof transform === 'string') {
139
- // Load transform from file
140
- transformFn = loadTransform(transform);
141
- } else if (typeof transform === 'function') {
142
- // Use provided function
143
- validateTransformFunction(transform);
144
- transformFn = transform;
145
- } else {
146
- throw new ValidationError('Transform must be a function or a path to a JavaScript file');
147
- }
148
-
149
- // Return a hook function compatible with hooks.perRow
150
- return function(row, index, context) {
151
- try {
152
- return transformFn(row, index);
153
- } catch (error) {
154
- // Log error but don't crash - return original row
155
- console.error(`Transform error at row ${index}: ${error.message}`);
156
- if (process.env.NODE_ENV === 'development') {
157
- console.error(error.stack);
158
- }
159
- return row;
160
- }
161
- };
162
- }
163
-
164
- /**
165
- * Applies transform to data array
166
- *
167
- * @param {Array} data - Array of data to transform
168
- * @param {string|Function} transform - Transform function or path to transform file
169
- * @returns {Array} Transformed data
170
- */
171
- function applyTransform(data, transform) {
172
- if (!Array.isArray(data)) {
173
- throw new ValidationError('Data must be an array');
174
- }
175
-
176
- const transformHook = createTransformHook(transform);
177
-
178
- return data.map((row, index) => {
179
- return transformHook(row, index, { operation: 'applyTransform' });
180
- });
181
- }
182
-
183
- /**
184
- * Creates a TransformHooks instance with transform function
185
- *
186
- * @param {string|Function} transform - Transform function or path to transform file
187
- * @returns {TransformHooks} TransformHooks instance
188
- */
189
- function createTransformHooksWithTransform(transform) {
190
- const { TransformHooks } = require('../core/transform-hooks');
191
- const hooks = new TransformHooks();
192
-
193
- const transformHook = createTransformHook(transform);
194
- hooks.perRow(transformHook);
195
-
196
- return hooks;
197
- }
198
-
199
- module.exports = {
200
- loadTransform,
201
- createTransformHook,
202
- applyTransform,
203
- createTransformHooksWithTransform,
204
- validateTransformFunction
205
- };