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,267 @@
1
+ /**
2
+ * tRPC plugin for jtcsv
3
+ * Provides utilities for CSV parsing and generation in tRPC applications
4
+ * @module plugins/trpc
5
+ */
6
+
7
+ import { csvToJson, jsonToCsv } from '../../index-core';
8
+ import type { CsvToJsonOptions, JsonToCsvOptions } from '../../src/types';
9
+
10
+ /**
11
+ * tRPC context type (simplified)
12
+ */
13
+ interface TRPCContext {
14
+ // tRPC context properties
15
+ }
16
+
17
+ /**
18
+ * tRPC procedure type (simplified)
19
+ */
20
+ interface TRPCProcedure {
21
+ input(schema: any): any;
22
+ use(middleware: any): any;
23
+ }
24
+
25
+ /**
26
+ * tRPC instance type (simplified)
27
+ */
28
+ interface TRPCInstance {
29
+ procedure: TRPCProcedure;
30
+ }
31
+
32
+ /**
33
+ * Options for CSV parsing in tRPC procedures
34
+ */
35
+ export interface CsvProcedureOptions extends CsvToJsonOptions {
36
+ /** Whether to return raw CSV text instead of parsed JSON */
37
+ raw?: boolean;
38
+ /** Whether to use async parsing */
39
+ async?: boolean;
40
+ }
41
+
42
+ /**
43
+ * Options for CSV generation in tRPC procedures
44
+ */
45
+ export interface CsvResponseOptions extends JsonToCsvOptions {
46
+ /** Filename for download (default: 'export.csv') */
47
+ filename?: string;
48
+ /** Whether to return as Response object */
49
+ asResponse?: boolean;
50
+ /** Whether to use async generation */
51
+ async?: boolean;
52
+ }
53
+
54
+ /**
55
+ * Extract CSV text from various input formats
56
+ */
57
+ function extractCsvText(input: any): string | null {
58
+ if (typeof input === 'string') {
59
+ return input;
60
+ }
61
+ if (input && typeof input === 'object' && typeof input.csv === 'string') {
62
+ return input.csv;
63
+ }
64
+ if (input && typeof input === 'object' && input.file && typeof input.file.text === 'function') {
65
+ return input.file.text();
66
+ }
67
+ return null;
68
+ }
69
+
70
+ /**
71
+ * Create a tRPC procedure for CSV parsing
72
+ *
73
+ * @example
74
+ * // In your tRPC router:
75
+ * import { createCsvProcedure } from 'jtcsv/plugins/trpc';
76
+ *
77
+ * export const csvRouter = t.router({
78
+ * parse: createCsvProcedure(t, z.string(), { delimiter: ',' })
79
+ * });
80
+ */
81
+ export function createCsvProcedure(
82
+ t: TRPCInstance,
83
+ schema: any,
84
+ options: CsvProcedureOptions = {}
85
+ ): any {
86
+ if (!t || !t.procedure) {
87
+ throw new Error('createCsvProcedure expects initTRPC instance');
88
+ }
89
+
90
+ return t.procedure
91
+ .input(schema)
92
+ .use(async ({ input, next }: { input: any; next: any }) => {
93
+ const csvText = extractCsvText(input);
94
+ if (!csvText) {
95
+ throw new Error('CSV input must be a string or { csv: string }');
96
+ }
97
+
98
+ if (options.async) {
99
+ const parsed = await csvToJson(csvText, options);
100
+ return next({ input: parsed });
101
+ } else {
102
+ const parsed = csvToJson(csvText, options);
103
+ return next({ input: parsed });
104
+ }
105
+ });
106
+ }
107
+
108
+ /**
109
+ * Async version of createCsvProcedure
110
+ */
111
+ export function createAsyncCsvProcedure(
112
+ t: TRPCInstance,
113
+ schema: any,
114
+ options: CsvProcedureOptions = {}
115
+ ): any {
116
+ return createCsvProcedure(t, schema, { ...options, async: true });
117
+ }
118
+
119
+ /**
120
+ * Create a tRPC procedure for CSV generation
121
+ *
122
+ * @example
123
+ * // In your tRPC router:
124
+ * import { createCsvResponseProcedure } from 'jtcsv/plugins/trpc';
125
+ *
126
+ * export const csvRouter = t.router({
127
+ * export: createCsvResponseProcedure(t, z.array(z.any()), { filename: 'data.csv' })
128
+ * });
129
+ */
130
+ export function createCsvResponseProcedure(
131
+ t: TRPCInstance,
132
+ schema: any,
133
+ options: CsvResponseOptions = {}
134
+ ): any {
135
+ if (!t || !t.procedure) {
136
+ throw new Error('createCsvResponseProcedure expects initTRPC instance');
137
+ }
138
+
139
+ return t.procedure
140
+ .input(schema)
141
+ .use(async ({ input, next }: { input: any; next: any }) => {
142
+ const { filename = 'export.csv', asResponse = false, ...csvOptions } = options;
143
+ const rows = Array.isArray(input) ? input : [input];
144
+
145
+ if (options.async) {
146
+ const csv = await jsonToCsv(rows, csvOptions);
147
+
148
+ if (asResponse) {
149
+ const response = new Response(csv, {
150
+ headers: {
151
+ 'Content-Type': 'text/csv; charset=utf-8',
152
+ 'Content-Disposition': `attachment; filename="${filename}"`
153
+ }
154
+ });
155
+ return next({ input: response });
156
+ }
157
+
158
+ return next({ input: csv });
159
+ } else {
160
+ const csv = jsonToCsv(rows, csvOptions);
161
+
162
+ if (asResponse) {
163
+ const response = new Response(csv, {
164
+ headers: {
165
+ 'Content-Type': 'text/csv; charset=utf-8',
166
+ 'Content-Disposition': `attachment; filename="${filename}"`
167
+ }
168
+ });
169
+ return next({ input: response });
170
+ }
171
+
172
+ return next({ input: csv });
173
+ }
174
+ });
175
+ }
176
+
177
+ /**
178
+ * Async version of createCsvResponseProcedure
179
+ */
180
+ export function createAsyncCsvResponseProcedure(
181
+ t: TRPCInstance,
182
+ schema: any,
183
+ options: CsvResponseOptions = {}
184
+ ): any {
185
+ return createCsvResponseProcedure(t, schema, { ...options, async: true });
186
+ }
187
+
188
+ /**
189
+ * Create a complete tRPC router for CSV operations
190
+ *
191
+ * @example
192
+ * // In your tRPC setup:
193
+ * import { createCsvRouter } from 'jtcsv/plugins/trpc';
194
+ *
195
+ * export const csvRouter = createCsvRouter(t);
196
+ */
197
+ export function createCsvRouter(t: TRPCInstance, options: {
198
+ parseOptions?: CsvProcedureOptions;
199
+ responseOptions?: CsvResponseOptions;
200
+ } = {}) {
201
+ if (!t || !t.procedure) {
202
+ throw new Error('createCsvRouter expects initTRPC instance');
203
+ }
204
+
205
+ return {
206
+ parse: createCsvProcedure(t, z.string(), options.parseOptions),
207
+ parseAsync: createAsyncCsvProcedure(t, z.string(), options.parseOptions),
208
+ export: createCsvResponseProcedure(t, z.array(z.any()), options.responseOptions),
209
+ exportAsync: createAsyncCsvResponseProcedure(t, z.array(z.any()), options.responseOptions),
210
+ batch: t.procedure
211
+ .input(z.array(z.string()))
212
+ .use(async ({ input, next }: { input: string[]; next: any }) => {
213
+ const results = await Promise.all(
214
+ input.map((csv: string) => csvToJson(csv, options.parseOptions))
215
+ );
216
+ return next({ input: results });
217
+ }),
218
+ batchAsync: t.procedure
219
+ .input(z.array(z.string()))
220
+ .use(async ({ input, next }: { input: string[]; next: any }) => {
221
+ const results = await Promise.all(
222
+ input.map((csv: string) => csvToJson(csv, options.parseOptions))
223
+ );
224
+ return next({ input: results });
225
+ }),
226
+ };
227
+ }
228
+
229
+ /**
230
+ * tRPC middleware for CSV processing
231
+ * Adds CSV utilities to tRPC context
232
+ */
233
+ export function createCsvMiddleware(options: CsvProcedureOptions = {}) {
234
+ return async ({ ctx, next }: { ctx: TRPCContext; next: any }) => {
235
+ const enhancedCtx = {
236
+ ...ctx,
237
+ csv: {
238
+ parse: (csvText: string) => csvToJson(csvText, options),
239
+ parseAsync: async (csvText: string) => await csvToJson(csvText, options),
240
+ generate: (data: any, opts?: JsonToCsvOptions) => jsonToCsv(data, { ...options, ...opts }),
241
+ generateAsync: async (data: any, opts?: JsonToCsvOptions) =>
242
+ await jsonToCsv(data, { ...options, ...opts }),
243
+ }
244
+ };
245
+
246
+ return next({ ctx: enhancedCtx });
247
+ };
248
+ }
249
+
250
+ /**
251
+ * Zod schema for CSV input validation
252
+ * Note: This is a placeholder - in real usage, import zod
253
+ */
254
+ const z = {
255
+ string: () => ({ _type: 'string' }),
256
+ array: (schema: any) => ({ _type: 'array', schema }),
257
+ any: () => ({ _type: 'any' }),
258
+ };
259
+
260
+ export default {
261
+ createCsvProcedure,
262
+ createAsyncCsvProcedure,
263
+ createCsvResponseProcedure,
264
+ createAsyncCsvResponseProcedure,
265
+ createCsvRouter,
266
+ createCsvMiddleware,
267
+ };
@@ -0,0 +1,402 @@
1
+ // Браузерные специфичные функции для jtcsv
2
+ // Функции, которые работают только в браузере
3
+
4
+ import { jsonToCsv } from './json-to-csv-browser';
5
+ import { csvToJson, csvToJsonIterator } from './csv-to-json-browser';
6
+ import {
7
+ csvToJsonStream as createCsvToJsonStream,
8
+ jsonToCsvStream as createJsonToCsvStream,
9
+ jsonToNdjsonStream as createJsonToNdjsonStream
10
+ } from './streams';
11
+ import { ValidationError } from './errors-browser';
12
+
13
+ import type { JsonToCsvOptions, CsvToJsonOptions } from '../types';
14
+
15
+ /**
16
+ * Скачивает JSON данные как CSV файл
17
+ *
18
+ * @param data - Массив объектов для конвертации
19
+ * @param filename - Имя файла для скачивания (по умолчанию 'data.csv')
20
+ * @param options - Опции для jsonToCsv
21
+ *
22
+ * @example
23
+ * const data = [
24
+ * { id: 1, name: 'John' },
25
+ * { id: 2, name: 'Jane' }
26
+ * ];
27
+ * downloadAsCsv(data, 'users.csv', { delimiter: ',' });
28
+ */
29
+ export function downloadAsCsv(
30
+ data: any[],
31
+ filename: string = 'data.csv',
32
+ options: JsonToCsvOptions = {}
33
+ ): void {
34
+ // Проверка что мы в браузере
35
+ if (typeof window === 'undefined') {
36
+ throw new ValidationError('downloadAsCsv() работает только в браузере. Используйте saveAsCsv() в Node.js');
37
+ }
38
+
39
+ // Валидация имени файла
40
+ if (typeof filename !== 'string' || filename.trim() === '') {
41
+ throw new ValidationError('Filename must be a non-empty string');
42
+ }
43
+
44
+ // Добавление расширения .csv если его нет
45
+ if (!filename.toLowerCase().endsWith('.csv')) {
46
+ filename += '.csv';
47
+ }
48
+
49
+ // Конвертация в CSV
50
+ const csv = jsonToCsv(data, options);
51
+
52
+ // Создание Blob
53
+ const blob = new Blob([csv], {
54
+ type: 'text/csv;charset=utf-8;'
55
+ });
56
+
57
+ // Создание ссылки для скачивания
58
+ const link = document.createElement('a');
59
+ const url = URL.createObjectURL(blob);
60
+
61
+ link.setAttribute('href', url);
62
+ link.setAttribute('download', filename);
63
+ link.style.visibility = 'hidden';
64
+
65
+ document.body.appendChild(link);
66
+ link.click();
67
+ document.body.removeChild(link);
68
+
69
+ // Освобождение URL
70
+ setTimeout(() => URL.revokeObjectURL(url), 100);
71
+ }
72
+
73
+ /**
74
+ * Асинхронная версия downloadAsCsv
75
+ */
76
+ export async function downloadAsCsvAsync(
77
+ data: any[],
78
+ filename: string = 'data.csv',
79
+ options: JsonToCsvOptions = {}
80
+ ): Promise<void> {
81
+ return downloadAsCsv(data, filename, options);
82
+ }
83
+
84
+ /**
85
+ * Парсит CSV файл из input[type="file"]
86
+ *
87
+ * @param file - File объект из input
88
+ * @param options - Опции для csvToJson
89
+ * @returns Promise с распарсенными данными
90
+ */
91
+ export async function parseCsvFile(
92
+ file: File,
93
+ options: CsvToJsonOptions = {}
94
+ ): Promise<any[]> {
95
+ if (!(file instanceof File)) {
96
+ throw new ValidationError('parseCsvFile() ожидает объект File');
97
+ }
98
+
99
+ // Чтение файла как текст
100
+ const text = await file.text();
101
+
102
+ // Парсинг CSV
103
+ return csvToJson(text, options);
104
+ }
105
+
106
+ /**
107
+ * Парсит CSV файл потоково
108
+ *
109
+ * @param file - File объект
110
+ * @param options - Опции для потокового парсинга
111
+ * @returns AsyncIterator с данными
112
+ */
113
+ export function parseCsvFileStream(
114
+ file: File,
115
+ options: CsvToJsonOptions = {}
116
+ ): AsyncIterator<any> {
117
+ if (!(file instanceof File)) {
118
+ throw new ValidationError('parseCsvFileStream() ожидает объект File');
119
+ }
120
+
121
+ // Используем csvToJsonIterator из импортированного модуля
122
+ return csvToJsonIterator(file, options);
123
+ }
124
+
125
+ /**
126
+ * Создает поток для конвертации JSON в CSV
127
+ *
128
+ * @param options - Опции для jsonToCsv
129
+ * @returns ReadableStream
130
+ */
131
+ export function jsonToCsvStream(options: JsonToCsvOptions = {}): ReadableStream {
132
+ return createJsonToCsvStream(options);
133
+ }
134
+
135
+ /**
136
+ * Создает поток для конвертации JSON в NDJSON
137
+ *
138
+ * @param options - Опции для конвертации
139
+ * @returns ReadableStream
140
+ */
141
+ export function jsonToNdjsonStream(options: any = {}): ReadableStream {
142
+ return createJsonToNdjsonStream(options);
143
+ }
144
+
145
+ /**
146
+ * Создает поток для парсинга CSV в JSON
147
+ *
148
+ * @param options - Опции для csvToJson
149
+ * @returns ReadableStream
150
+ */
151
+ export function csvToJsonStream(options: CsvToJsonOptions = {}): ReadableStream {
152
+ return createCsvToJsonStream(options);
153
+ }
154
+
155
+ /**
156
+ * Загружает CSV файл по URL
157
+ *
158
+ * @param url - URL CSV файла
159
+ * @param options - Опции для csvToJson
160
+ * @returns Promise с распарсенными данными
161
+ */
162
+ export async function loadCsvFromUrl(
163
+ url: string,
164
+ options: CsvToJsonOptions = {}
165
+ ): Promise<any[]> {
166
+ if (typeof window === 'undefined') {
167
+ throw new ValidationError('loadCsvFromUrl() работает только в браузере');
168
+ }
169
+
170
+ const response = await fetch(url);
171
+
172
+ if (!response.ok) {
173
+ throw new ValidationError(`Failed to load CSV from URL: ${response.status} ${response.statusText}`);
174
+ }
175
+
176
+ const text = await response.text();
177
+ return csvToJson(text, options);
178
+ }
179
+
180
+ /**
181
+ * Асинхронная версия loadCsvFromUrl
182
+ */
183
+ export async function loadCsvFromUrlAsync(
184
+ url: string,
185
+ options: CsvToJsonOptions = {}
186
+ ): Promise<any[]> {
187
+ return loadCsvFromUrl(url, options);
188
+ }
189
+
190
+ /**
191
+ * Экспортирует данные в CSV и открывает в новой вкладке
192
+ *
193
+ * @param data - Данные для экспорта
194
+ * @param options - Опции для jsonToCsv
195
+ */
196
+ export function openCsvInNewTab(
197
+ data: any[],
198
+ options: JsonToCsvOptions = {}
199
+ ): void {
200
+ if (typeof window === 'undefined') {
201
+ throw new ValidationError('openCsvInNewTab() работает только в браузере');
202
+ }
203
+
204
+ const csv = jsonToCsv(data, options);
205
+ const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' });
206
+ const url = URL.createObjectURL(blob);
207
+
208
+ window.open(url, '_blank');
209
+
210
+ // Освобождение URL через некоторое время
211
+ setTimeout(() => URL.revokeObjectURL(url), 1000);
212
+ }
213
+
214
+ /**
215
+ * Асинхронная версия openCsvInNewTab
216
+ */
217
+ export async function openCsvInNewTabAsync(
218
+ data: any[],
219
+ options: JsonToCsvOptions = {}
220
+ ): Promise<void> {
221
+ return openCsvInNewTab(data, options);
222
+ }
223
+
224
+ /**
225
+ * Копирует CSV в буфер обмена
226
+ *
227
+ * @param data - Данные для копирования
228
+ * @param options - Опции для jsonToCsv
229
+ * @returns Promise с результатом копирования
230
+ */
231
+ export async function copyCsvToClipboard(
232
+ data: any[],
233
+ options: JsonToCsvOptions = {}
234
+ ): Promise<boolean> {
235
+ if (typeof window === 'undefined' || !navigator.clipboard) {
236
+ throw new ValidationError('copyCsvToClipboard() требует поддержки Clipboard API');
237
+ }
238
+
239
+ const csv = jsonToCsv(data, options);
240
+
241
+ try {
242
+ await navigator.clipboard.writeText(csv);
243
+ return true;
244
+ } catch (error) {
245
+ console.error('Failed to copy to clipboard:', error);
246
+ return false;
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Сохраняет CSV в localStorage
252
+ *
253
+ * @param key - Ключ для сохранения
254
+ * @param data - Данные для сохранения
255
+ * @param options - Опции для jsonToCsv
256
+ */
257
+ export function saveCsvToLocalStorage(
258
+ key: string,
259
+ data: any[],
260
+ options: JsonToCsvOptions = {}
261
+ ): void {
262
+ if (typeof window === 'undefined' || !localStorage) {
263
+ throw new ValidationError('saveCsvToLocalStorage() требует localStorage');
264
+ }
265
+
266
+ const csv = jsonToCsv(data, options);
267
+ localStorage.setItem(key, csv);
268
+ }
269
+
270
+ /**
271
+ * Загружает CSV из localStorage
272
+ *
273
+ * @param key - Ключ для загрузки
274
+ * @param options - Опции для csvToJson
275
+ * @returns Распарсенные данные или null
276
+ */
277
+ export function loadCsvFromLocalStorage(
278
+ key: string,
279
+ options: CsvToJsonOptions = {}
280
+ ): any[] | null {
281
+ if (typeof window === 'undefined' || !localStorage) {
282
+ throw new ValidationError('loadCsvFromLocalStorage() требует localStorage');
283
+ }
284
+
285
+ const csv = localStorage.getItem(key);
286
+
287
+ if (!csv) {
288
+ return null;
289
+ }
290
+
291
+ return csvToJson(csv, options);
292
+ }
293
+
294
+ /**
295
+ * Асинхронная версия loadCsvFromLocalStorage
296
+ */
297
+ export async function loadCsvFromLocalStorageAsync(
298
+ key: string,
299
+ options: CsvToJsonOptions = {}
300
+ ): Promise<any[] | null> {
301
+ return loadCsvFromLocalStorage(key, options);
302
+ }
303
+
304
+ /**
305
+ * Создает CSV файл из JSON данных (альтернатива downloadAsCsv)
306
+ * Возвращает Blob вместо автоматического скачивания
307
+ *
308
+ * @param data - Массив объектов
309
+ * @param options - Опции для jsonToCsv
310
+ * @returns CSV Blob
311
+ */
312
+ export function createCsvBlob(
313
+ data: any[],
314
+ options: JsonToCsvOptions = {}
315
+ ): Blob {
316
+ const csv = jsonToCsv(data, options);
317
+ return new Blob([csv], {
318
+ type: 'text/csv;charset=utf-8;'
319
+ });
320
+ }
321
+
322
+ /**
323
+ * Асинхронная версия createCsvBlob
324
+ */
325
+ export async function createCsvBlobAsync(
326
+ data: any[],
327
+ options: JsonToCsvOptions = {}
328
+ ): Promise<Blob> {
329
+ return createCsvBlob(data, options);
330
+ }
331
+
332
+ /**
333
+ * Парсит CSV строку из Blob
334
+ *
335
+ * @param blob - CSV Blob
336
+ * @param options - Опции для csvToJson
337
+ * @returns Promise с JSON данными
338
+ */
339
+ export async function parseCsvBlob(
340
+ blob: Blob,
341
+ options: CsvToJsonOptions = {}
342
+ ): Promise<any[]> {
343
+ if (!(blob instanceof Blob)) {
344
+ throw new ValidationError('Input must be a Blob object');
345
+ }
346
+
347
+ return new Promise((resolve, reject) => {
348
+ const reader = new FileReader();
349
+
350
+ reader.onload = function (event: ProgressEvent<FileReader>) {
351
+ try {
352
+ const csvText = event.target?.result as string;
353
+ const json = csvToJson(csvText, options);
354
+ resolve(json);
355
+ } catch (error) {
356
+ reject(error);
357
+ }
358
+ };
359
+
360
+ reader.onerror = function () {
361
+ reject(new ValidationError('Ошибка чтения Blob'));
362
+ };
363
+
364
+ reader.readAsText(blob, 'UTF-8');
365
+ });
366
+ }
367
+
368
+ /**
369
+ * Асинхронная версия parseCsvBlob
370
+ */
371
+ export async function parseCsvBlobAsync(
372
+ blob: Blob,
373
+ options: CsvToJsonOptions = {}
374
+ ): Promise<any[]> {
375
+ return parseCsvBlob(blob, options);
376
+ }
377
+
378
+ // Экспорт для Node.js совместимости
379
+ if (typeof module !== 'undefined' && module.exports) {
380
+ module.exports = {
381
+ downloadAsCsv,
382
+ downloadAsCsvAsync,
383
+ parseCsvFile,
384
+ parseCsvFileStream,
385
+ createCsvBlob,
386
+ createCsvBlobAsync,
387
+ parseCsvBlob,
388
+ parseCsvBlobAsync,
389
+ jsonToCsvStream,
390
+ jsonToNdjsonStream,
391
+ csvToJsonStream,
392
+ loadCsvFromUrl,
393
+ loadCsvFromUrlAsync,
394
+ openCsvInNewTab,
395
+ openCsvInNewTabAsync,
396
+ copyCsvToClipboard,
397
+ saveCsvToLocalStorage,
398
+ loadCsvFromLocalStorage,
399
+ loadCsvFromLocalStorageAsync
400
+ };
401
+ }
402
+