jtcsv 1.2.0 → 2.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.
- package/README.md +252 -337
- package/bin/jtcsv.js +167 -85
- package/cli-tui.js +0 -0
- package/dist/jtcsv.cjs.js +1619 -0
- package/dist/jtcsv.cjs.js.map +1 -0
- package/dist/jtcsv.esm.js +1599 -0
- package/dist/jtcsv.esm.js.map +1 -0
- package/dist/jtcsv.umd.js +1625 -0
- package/dist/jtcsv.umd.js.map +1 -0
- package/examples/cli-tool.js +186 -0
- package/examples/express-api.js +167 -0
- package/examples/large-dataset-example.js +185 -0
- package/examples/plugin-excel-exporter.js +407 -0
- package/examples/simple-usage.js +280 -0
- package/examples/streaming-example.js +419 -0
- package/index.d.ts +4 -0
- package/json-save.js +1 -1
- package/package.json +128 -14
- package/plugins/README.md +373 -0
- package/plugins/express-middleware/README.md +306 -0
- package/plugins/express-middleware/example.js +136 -0
- package/plugins/express-middleware/index.d.ts +114 -0
- package/plugins/express-middleware/index.js +360 -0
- package/plugins/express-middleware/package.json +52 -0
- package/plugins/fastify-plugin/index.js +406 -0
- package/plugins/fastify-plugin/package.json +55 -0
- package/plugins/nextjs-api/README.md +452 -0
- package/plugins/nextjs-api/examples/ConverterComponent.jsx +386 -0
- package/plugins/nextjs-api/examples/api-convert.js +69 -0
- package/plugins/nextjs-api/index.js +388 -0
- package/plugins/nextjs-api/package.json +63 -0
- package/plugins/nextjs-api/route.js +372 -0
- package/src/browser/browser-functions.js +189 -0
- package/src/browser/csv-to-json-browser.js +442 -0
- package/src/browser/errors-browser.js +194 -0
- package/src/browser/index.js +79 -0
- package/src/browser/json-to-csv-browser.js +309 -0
- package/src/browser/workers/csv-parser.worker.js +359 -0
- package/src/browser/workers/worker-pool.js +467 -0
- package/src/core/plugin-system.js +472 -0
- package/src/engines/fast-path-engine-new.js +338 -0
- package/src/engines/fast-path-engine.js +347 -0
- package/src/formats/ndjson-parser.js +419 -0
- package/src/index-with-plugins.js +349 -0
- package/stream-csv-to-json.js +1 -1
- package/stream-json-to-csv.js +1 -1
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
# @jtcsv/nextjs
|
|
2
|
+
|
|
3
|
+
Next.js интеграция для JTCSV - API routes, React hooks и компоненты для конвертации CSV/JSON.
|
|
4
|
+
|
|
5
|
+
## 📦 Установка
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @jtcsv/nextjs jtcsv
|
|
9
|
+
# или
|
|
10
|
+
pnpm add @jtcsv/nextjs jtcsv
|
|
11
|
+
# или
|
|
12
|
+
yarn add @jtcsv/nextjs jtcsv
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 🚀 Быстрый старт
|
|
16
|
+
|
|
17
|
+
### 1. API Route
|
|
18
|
+
|
|
19
|
+
Создайте файл `pages/api/convert.js`:
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
// pages/api/convert.js
|
|
23
|
+
import { handler } from '@jtcsv/nextjs/route';
|
|
24
|
+
|
|
25
|
+
export default handler;
|
|
26
|
+
|
|
27
|
+
export const config = {
|
|
28
|
+
api: {
|
|
29
|
+
bodyParser: {
|
|
30
|
+
sizeLimit: '50mb'
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 2. React компонент
|
|
37
|
+
|
|
38
|
+
```jsx
|
|
39
|
+
// components/Converter.jsx
|
|
40
|
+
'use client';
|
|
41
|
+
|
|
42
|
+
import { useJtcsv } from '@jtcsv/nextjs';
|
|
43
|
+
|
|
44
|
+
export default function Converter() {
|
|
45
|
+
const {
|
|
46
|
+
convertCsvToJson,
|
|
47
|
+
convertJsonToCsv,
|
|
48
|
+
isLoading,
|
|
49
|
+
error,
|
|
50
|
+
result
|
|
51
|
+
} = useJtcsv();
|
|
52
|
+
|
|
53
|
+
const handleConvert = async () => {
|
|
54
|
+
const csv = 'name,age\nJohn,30\nJane,25';
|
|
55
|
+
const json = await convertCsvToJson(csv);
|
|
56
|
+
console.log('Converted:', json);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div>
|
|
61
|
+
<button onClick={handleConvert} disabled={isLoading}>
|
|
62
|
+
{isLoading ? 'Converting...' : 'Convert CSV to JSON'}
|
|
63
|
+
</button>
|
|
64
|
+
{error && <div>Error: {error}</div>}
|
|
65
|
+
{result && <pre>{JSON.stringify(result, null, 2)}</pre>}
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 📖 Документация
|
|
72
|
+
|
|
73
|
+
### API Routes
|
|
74
|
+
|
|
75
|
+
#### Автоматическая конвертация
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
// pages/api/convert.js
|
|
79
|
+
import { handler } from '@jtcsv/nextjs/route';
|
|
80
|
+
|
|
81
|
+
export default handler;
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Примеры запросов:**
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# JSON → CSV
|
|
88
|
+
curl -X POST http://localhost:3000/api/convert \
|
|
89
|
+
-H "Content-Type: application/json" \
|
|
90
|
+
-d '[{"name":"John","age":30}]'
|
|
91
|
+
|
|
92
|
+
# CSV → JSON
|
|
93
|
+
curl -X POST http://localhost:3000/api/convert \
|
|
94
|
+
-H "Content-Type: text/csv" \
|
|
95
|
+
-d 'name,age\nJohn,30\nJane,25'
|
|
96
|
+
|
|
97
|
+
# Специфичный формат вывода
|
|
98
|
+
curl -X POST "http://localhost:3000/api/convert?format=csv" \
|
|
99
|
+
-H "Content-Type: application/json" \
|
|
100
|
+
-d '[{"name":"John","age":30}]'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### Специализированные handlers
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
// pages/api/convert/[...path].js
|
|
107
|
+
import {
|
|
108
|
+
csvToJsonHandler,
|
|
109
|
+
jsonToCsvHandler,
|
|
110
|
+
healthCheckHandler
|
|
111
|
+
} from '@jtcsv/nextjs/route';
|
|
112
|
+
|
|
113
|
+
export default async function handler(req, res) {
|
|
114
|
+
const { path } = req.query;
|
|
115
|
+
|
|
116
|
+
switch (path?.[0]) {
|
|
117
|
+
case 'csv-to-json':
|
|
118
|
+
return csvToJsonHandler(req, res);
|
|
119
|
+
case 'json-to-csv':
|
|
120
|
+
return jsonToCsvHandler(req, res);
|
|
121
|
+
case 'health':
|
|
122
|
+
return healthCheckHandler(req, res);
|
|
123
|
+
default:
|
|
124
|
+
res.status(404).json({ error: 'Not found' });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### React Hooks
|
|
130
|
+
|
|
131
|
+
#### useJtcsv
|
|
132
|
+
|
|
133
|
+
```jsx
|
|
134
|
+
import { useJtcsv } from '@jtcsv/nextjs';
|
|
135
|
+
|
|
136
|
+
function Converter() {
|
|
137
|
+
const {
|
|
138
|
+
convertCsvToJson,
|
|
139
|
+
convertJsonToCsv,
|
|
140
|
+
isLoading,
|
|
141
|
+
error,
|
|
142
|
+
result,
|
|
143
|
+
stats,
|
|
144
|
+
reset
|
|
145
|
+
} = useJtcsv({
|
|
146
|
+
delimiter: ',', // Разделитель CSV
|
|
147
|
+
parseNumbers: true, // Парсить числа
|
|
148
|
+
parseBooleans: true, // Парсить булевы значения
|
|
149
|
+
preventCsvInjection: true // Защита от инъекций
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// ...
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### JtcsvProvider (Context)
|
|
157
|
+
|
|
158
|
+
```jsx
|
|
159
|
+
// app/layout.jsx
|
|
160
|
+
import { JtcsvProvider } from '@jtcsv/nextjs';
|
|
161
|
+
|
|
162
|
+
export default function Layout({ children }) {
|
|
163
|
+
return (
|
|
164
|
+
<JtcsvProvider options={{ delimiter: ',' }}>
|
|
165
|
+
{children}
|
|
166
|
+
</JtcsvProvider>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// components/Converter.jsx
|
|
171
|
+
'use client';
|
|
172
|
+
import { useJtcsvContext } from '@jtcsv/nextjs';
|
|
173
|
+
|
|
174
|
+
export default function Converter() {
|
|
175
|
+
const { csvToJson, jsonToCsv } = useJtcsvContext();
|
|
176
|
+
// ...
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Компоненты
|
|
181
|
+
|
|
182
|
+
#### CsvFileUploader
|
|
183
|
+
|
|
184
|
+
```jsx
|
|
185
|
+
import { CsvFileUploader } from '@jtcsv/nextjs';
|
|
186
|
+
|
|
187
|
+
function FileUpload() {
|
|
188
|
+
const handleConvert = (result, stats) => {
|
|
189
|
+
console.log('Converted:', result);
|
|
190
|
+
console.log('Stats:', stats);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<CsvFileUploader
|
|
195
|
+
onConvert={handleConvert}
|
|
196
|
+
options={{ delimiter: ',' }}
|
|
197
|
+
>
|
|
198
|
+
<button>📁 Upload CSV File</button>
|
|
199
|
+
</CsvFileUploader>
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Утилиты
|
|
205
|
+
|
|
206
|
+
#### downloadCsv
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
import { downloadCsv } from '@jtcsv/nextjs';
|
|
210
|
+
|
|
211
|
+
const data = [{ name: 'John', age: 30 }];
|
|
212
|
+
await downloadCsv(data, 'users.csv', { delimiter: ',' });
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### createJtcsvApiClient
|
|
216
|
+
|
|
217
|
+
```javascript
|
|
218
|
+
import { createJtcsvApiClient } from '@jtcsv/nextjs';
|
|
219
|
+
|
|
220
|
+
const api = createJtcsvApiClient('/api/convert');
|
|
221
|
+
|
|
222
|
+
// Конвертация CSV в JSON
|
|
223
|
+
const json = await api.csvToJson('name,age\nJohn,30');
|
|
224
|
+
|
|
225
|
+
// Конвертация JSON в CSV
|
|
226
|
+
const csv = await api.jsonToCsv([{ name: 'John', age: 30 }]);
|
|
227
|
+
|
|
228
|
+
// Проверка здоровья
|
|
229
|
+
const health = await api.health();
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## 🔧 Конфигурация
|
|
233
|
+
|
|
234
|
+
### Опции API Route
|
|
235
|
+
|
|
236
|
+
| Параметр | Тип | По умолчанию | Описание |
|
|
237
|
+
|----------|-----|--------------|----------|
|
|
238
|
+
| `format` | `string` | `auto` | Формат вывода: `json`, `csv` |
|
|
239
|
+
| `delimiter` | `string` | `','` | Разделитель CSV |
|
|
240
|
+
| `includeHeaders` | `boolean` | `true` | Включать заголовки в CSV |
|
|
241
|
+
| `parseNumbers` | `boolean` | `true` | Парсить числа |
|
|
242
|
+
| `parseBooleans` | `boolean` | `true` | Парсить булевы значения |
|
|
243
|
+
| `useFastPath` | `boolean` | `true` | Использовать Fast-Path Engine |
|
|
244
|
+
| `preventCsvInjection` | `boolean` | `true` | Защита от CSV инъекций |
|
|
245
|
+
|
|
246
|
+
### Опции React Hook
|
|
247
|
+
|
|
248
|
+
```javascript
|
|
249
|
+
const options = {
|
|
250
|
+
delimiter: ',', // Разделитель CSV
|
|
251
|
+
includeHeaders: true, // Включать заголовки
|
|
252
|
+
parseNumbers: true, // Парсить числа
|
|
253
|
+
parseBooleans: true, // Парсить булевы значения
|
|
254
|
+
useFastPath: true, // Использовать Fast-Path Engine
|
|
255
|
+
preventCsvInjection: true,// Защита от инъекций
|
|
256
|
+
rfc4180Compliant: true // Соответствие RFC 4180
|
|
257
|
+
};
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## 🌐 Примеры
|
|
261
|
+
|
|
262
|
+
### Полный пример приложения
|
|
263
|
+
|
|
264
|
+
Смотрите `examples/ConverterComponent.jsx` для полного примера React компонента.
|
|
265
|
+
|
|
266
|
+
### Кастомная API Route
|
|
267
|
+
|
|
268
|
+
```javascript
|
|
269
|
+
// pages/api/convert/secure.js
|
|
270
|
+
import { handler } from '@jtcsv/nextjs/route';
|
|
271
|
+
|
|
272
|
+
export default async function secureHandler(req, res) {
|
|
273
|
+
// Проверка API ключа
|
|
274
|
+
const apiKey = req.headers['x-api-key'];
|
|
275
|
+
if (apiKey !== process.env.API_KEY) {
|
|
276
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Rate limiting
|
|
280
|
+
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
|
281
|
+
// ... ваша логика rate limiting
|
|
282
|
+
|
|
283
|
+
// Логирование
|
|
284
|
+
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
|
|
285
|
+
|
|
286
|
+
// Вызов основного обработчика
|
|
287
|
+
return handler(req, res);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export const config = {
|
|
291
|
+
api: {
|
|
292
|
+
bodyParser: {
|
|
293
|
+
sizeLimit: '10mb'
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Интеграция с формой
|
|
300
|
+
|
|
301
|
+
```jsx
|
|
302
|
+
'use client';
|
|
303
|
+
import { useState } from 'react';
|
|
304
|
+
import { useJtcsv, downloadCsv } from '@jtcsv/nextjs';
|
|
305
|
+
|
|
306
|
+
export default function DataForm() {
|
|
307
|
+
const [data, setData] = useState([]);
|
|
308
|
+
const { convertJsonToCsv } = useJtcsv();
|
|
309
|
+
|
|
310
|
+
const handleSubmit = async (e) => {
|
|
311
|
+
e.preventDefault();
|
|
312
|
+
|
|
313
|
+
// Конвертируем данные в CSV
|
|
314
|
+
const csv = await convertJsonToCsv(data);
|
|
315
|
+
|
|
316
|
+
// Скачиваем файл
|
|
317
|
+
await downloadCsv(data, 'form-data.csv');
|
|
318
|
+
|
|
319
|
+
// Отправляем на сервер
|
|
320
|
+
await fetch('/api/submit', {
|
|
321
|
+
method: 'POST',
|
|
322
|
+
headers: { 'Content-Type': 'application/json' },
|
|
323
|
+
body: JSON.stringify({ csv, data })
|
|
324
|
+
});
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
return (
|
|
328
|
+
<form onSubmit={handleSubmit}>
|
|
329
|
+
{/* поля формы */}
|
|
330
|
+
<button type="submit">Submit and Download CSV</button>
|
|
331
|
+
</form>
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## 🛡️ Безопасность
|
|
337
|
+
|
|
338
|
+
### Защита от CSV инъекций
|
|
339
|
+
|
|
340
|
+
Все конвертации по умолчанию защищены от CSV инъекций:
|
|
341
|
+
|
|
342
|
+
```javascript
|
|
343
|
+
// Опасные данные
|
|
344
|
+
const dangerous = [{ formula: '=1+1', command: '@echo hello' }];
|
|
345
|
+
|
|
346
|
+
// Безопасный CSV
|
|
347
|
+
const safeCsv = await jsonToCsv(dangerous, { preventCsvInjection: true });
|
|
348
|
+
// Результат: "'=1+1','@echo hello"
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Валидация размера
|
|
352
|
+
|
|
353
|
+
```javascript
|
|
354
|
+
// pages/api/convert.js
|
|
355
|
+
export const config = {
|
|
356
|
+
api: {
|
|
357
|
+
bodyParser: {
|
|
358
|
+
sizeLimit: '10mb' // Ограничение размера
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## 📊 Мониторинг
|
|
365
|
+
|
|
366
|
+
### Health Check
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
curl http://localhost:3000/api/convert/health
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
**Ответ:**
|
|
373
|
+
```json
|
|
374
|
+
{
|
|
375
|
+
"service": "jtcsv-nextjs-api",
|
|
376
|
+
"status": "healthy",
|
|
377
|
+
"version": "1.0.0",
|
|
378
|
+
"timestamp": "2026-01-23T10:30:00.000Z",
|
|
379
|
+
"features": {
|
|
380
|
+
"csvToJson": true,
|
|
381
|
+
"jsonToCsv": true,
|
|
382
|
+
"fastPathEngine": true,
|
|
383
|
+
"csvInjectionProtection": true,
|
|
384
|
+
"streaming": true,
|
|
385
|
+
"ndjson": true
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Статистика
|
|
391
|
+
|
|
392
|
+
Каждая операция возвращает статистику:
|
|
393
|
+
|
|
394
|
+
```json
|
|
395
|
+
{
|
|
396
|
+
"stats": {
|
|
397
|
+
"inputSize": 45,
|
|
398
|
+
"outputSize": 28,
|
|
399
|
+
"processingTime": 12,
|
|
400
|
+
"conversion": "json→csv",
|
|
401
|
+
"rows": 2
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
## 🔌 TypeScript
|
|
407
|
+
|
|
408
|
+
Полная поддержка TypeScript:
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
import {
|
|
412
|
+
useJtcsv,
|
|
413
|
+
CsvFileUploader,
|
|
414
|
+
type ConversionStats
|
|
415
|
+
} from '@jtcsv/nextjs';
|
|
416
|
+
|
|
417
|
+
interface MyComponentProps {
|
|
418
|
+
onConvert: (result: any[], stats: ConversionStats) => void;
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## 🧪 Тестирование
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
# Запуск примеров
|
|
426
|
+
cd plugins/nextjs-api/examples
|
|
427
|
+
|
|
428
|
+
# Тестовые запросы к API
|
|
429
|
+
curl -X POST http://localhost:3000/api/convert \
|
|
430
|
+
-H "Content-Type: application/json" \
|
|
431
|
+
-d '[{"test":"data"}]'
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
## 📄 Лицензия
|
|
435
|
+
|
|
436
|
+
MIT
|
|
437
|
+
|
|
438
|
+
## 🤝 Вклад в развитие
|
|
439
|
+
|
|
440
|
+
1. Форкните репозиторий
|
|
441
|
+
2. Создайте ветку для вашей функции
|
|
442
|
+
3. Закоммитьте изменения
|
|
443
|
+
4. Запушьте в ветку
|
|
444
|
+
5. Откройте Pull Request
|
|
445
|
+
|
|
446
|
+
## 📞 Поддержка
|
|
447
|
+
|
|
448
|
+
- [Issues](https://github.com/Linol-Hamelton/jtcsv/issues)
|
|
449
|
+
- [Discussions](https://github.com/Linol-Hamelton/jtcsv/discussions)
|
|
450
|
+
- [Documentation](https://github.com/Linol-Hamelton/jtcsv#readme)
|
|
451
|
+
|
|
452
|
+
|