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.
- package/README.md +204 -115
- package/bin/jtcsv.ts +2612 -0
- package/browser.d.ts +142 -0
- package/dist/benchmark.js +446 -0
- package/dist/benchmark.js.map +1 -0
- package/dist/bin/jtcsv.js +1940 -0
- package/dist/bin/jtcsv.js.map +1 -0
- package/dist/csv-to-json.js +1262 -0
- package/dist/csv-to-json.js.map +1 -0
- package/dist/errors.js +291 -0
- package/dist/errors.js.map +1 -0
- package/dist/eslint.config.js +147 -0
- package/dist/eslint.config.js.map +1 -0
- package/dist/index-core.js +95 -0
- package/dist/index-core.js.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/json-save.js +229 -0
- package/dist/json-save.js.map +1 -0
- package/dist/json-to-csv.js +576 -0
- package/dist/json-to-csv.js.map +1 -0
- package/dist/jtcsv-core.cjs.js +1736 -0
- package/dist/jtcsv-core.cjs.js.map +1 -0
- package/dist/jtcsv-core.esm.js +1708 -0
- package/dist/jtcsv-core.esm.js.map +1 -0
- package/dist/jtcsv-core.umd.js +1742 -0
- package/dist/jtcsv-core.umd.js.map +1 -0
- package/dist/jtcsv-full.cjs.js +2241 -0
- package/dist/jtcsv-full.cjs.js.map +1 -0
- package/dist/jtcsv-full.esm.js +2209 -0
- package/dist/jtcsv-full.esm.js.map +1 -0
- package/dist/jtcsv-full.umd.js +2247 -0
- package/dist/jtcsv-full.umd.js.map +1 -0
- package/dist/jtcsv-workers.esm.js +768 -0
- package/dist/jtcsv-workers.esm.js.map +1 -0
- package/dist/jtcsv-workers.umd.js +782 -0
- package/dist/jtcsv-workers.umd.js.map +1 -0
- package/dist/jtcsv.cjs.js +1996 -2048
- package/dist/jtcsv.cjs.js.map +1 -1
- package/dist/jtcsv.esm.js +1992 -2048
- package/dist/jtcsv.esm.js.map +1 -1
- package/dist/jtcsv.umd.js +2157 -2209
- package/dist/jtcsv.umd.js.map +1 -1
- package/dist/plugins/express-middleware/index.js +350 -0
- package/dist/plugins/express-middleware/index.js.map +1 -0
- package/dist/plugins/fastify-plugin/index.js +315 -0
- package/dist/plugins/fastify-plugin/index.js.map +1 -0
- package/dist/plugins/hono/index.js +111 -0
- package/dist/plugins/hono/index.js.map +1 -0
- package/dist/plugins/nestjs/index.js +112 -0
- package/dist/plugins/nestjs/index.js.map +1 -0
- package/dist/plugins/nuxt/index.js +53 -0
- package/dist/plugins/nuxt/index.js.map +1 -0
- package/dist/plugins/remix/index.js +133 -0
- package/dist/plugins/remix/index.js.map +1 -0
- package/dist/plugins/sveltekit/index.js +155 -0
- package/dist/plugins/sveltekit/index.js.map +1 -0
- package/dist/plugins/trpc/index.js +136 -0
- package/dist/plugins/trpc/index.js.map +1 -0
- package/dist/run-demo.js +49 -0
- package/dist/run-demo.js.map +1 -0
- package/dist/src/browser/browser-functions.js +193 -0
- package/dist/src/browser/browser-functions.js.map +1 -0
- package/dist/src/browser/core.js +123 -0
- package/dist/src/browser/core.js.map +1 -0
- package/dist/src/browser/csv-to-json-browser.js +353 -0
- package/dist/src/browser/csv-to-json-browser.js.map +1 -0
- package/dist/src/browser/errors-browser.js +219 -0
- package/dist/src/browser/errors-browser.js.map +1 -0
- package/dist/src/browser/extensions/plugins.js +106 -0
- package/dist/src/browser/extensions/plugins.js.map +1 -0
- package/dist/src/browser/extensions/workers.js +66 -0
- package/dist/src/browser/extensions/workers.js.map +1 -0
- package/dist/src/browser/index.js +140 -0
- package/dist/src/browser/index.js.map +1 -0
- package/dist/src/browser/json-to-csv-browser.js +225 -0
- package/dist/src/browser/json-to-csv-browser.js.map +1 -0
- package/dist/src/browser/streams.js +340 -0
- package/dist/src/browser/streams.js.map +1 -0
- package/dist/src/browser/workers/csv-parser.worker.js +264 -0
- package/dist/src/browser/workers/csv-parser.worker.js.map +1 -0
- package/dist/src/browser/workers/worker-pool.js +338 -0
- package/dist/src/browser/workers/worker-pool.js.map +1 -0
- package/dist/src/core/delimiter-cache.js +196 -0
- package/dist/src/core/delimiter-cache.js.map +1 -0
- package/dist/src/core/node-optimizations.js +279 -0
- package/dist/src/core/node-optimizations.js.map +1 -0
- package/dist/src/core/plugin-system.js +399 -0
- package/dist/src/core/plugin-system.js.map +1 -0
- package/dist/src/core/transform-hooks.js +348 -0
- package/dist/src/core/transform-hooks.js.map +1 -0
- package/dist/src/engines/fast-path-engine-new.js +262 -0
- package/dist/src/engines/fast-path-engine-new.js.map +1 -0
- package/dist/src/engines/fast-path-engine.js +671 -0
- package/dist/src/engines/fast-path-engine.js.map +1 -0
- package/dist/src/errors.js +18 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/formats/ndjson-parser.js +332 -0
- package/dist/src/formats/ndjson-parser.js.map +1 -0
- package/dist/src/formats/tsv-parser.js +230 -0
- package/dist/src/formats/tsv-parser.js.map +1 -0
- package/dist/src/index-with-plugins.js +259 -0
- package/dist/src/index-with-plugins.js.map +1 -0
- package/dist/src/types/index.js +3 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/utils/bom-utils.js +267 -0
- package/dist/src/utils/bom-utils.js.map +1 -0
- package/dist/src/utils/encoding-support.js +77 -0
- package/dist/src/utils/encoding-support.js.map +1 -0
- package/dist/src/utils/schema-validator.js +609 -0
- package/dist/src/utils/schema-validator.js.map +1 -0
- package/dist/src/utils/transform-loader.js +281 -0
- package/dist/src/utils/transform-loader.js.map +1 -0
- package/dist/src/utils/validators.js +40 -0
- package/dist/src/utils/validators.js.map +1 -0
- package/dist/src/utils/zod-adapter.js +144 -0
- package/dist/src/utils/zod-adapter.js.map +1 -0
- package/dist/src/web-server/index.js +648 -0
- package/dist/src/web-server/index.js.map +1 -0
- package/dist/src/workers/csv-multithreaded.js +211 -0
- package/dist/src/workers/csv-multithreaded.js.map +1 -0
- package/dist/src/workers/csv-parser.worker.js +179 -0
- package/dist/src/workers/csv-parser.worker.js.map +1 -0
- package/dist/src/workers/worker-pool.js +228 -0
- package/dist/src/workers/worker-pool.js.map +1 -0
- package/dist/stream-csv-to-json.js +665 -0
- package/dist/stream-csv-to-json.js.map +1 -0
- package/dist/stream-json-to-csv.js +389 -0
- package/dist/stream-json-to-csv.js.map +1 -0
- package/examples/advanced/conditional-transformations.ts +446 -0
- package/examples/advanced/csv-parser.worker.ts +89 -0
- package/examples/advanced/nested-objects-example.ts +306 -0
- package/examples/advanced/performance-optimization.ts +504 -0
- package/examples/advanced/run-demo-server.ts +116 -0
- package/examples/advanced/web-worker-usage.html +874 -0
- package/examples/async-multithreaded-example.ts +335 -0
- package/examples/cli-advanced-usage.md +290 -0
- package/examples/{cli-batch-processing.js → cli-batch-processing.ts} +38 -38
- package/examples/{cli-tool.js → cli-tool.ts} +5 -8
- package/examples/{error-handling.js → error-handling.ts} +356 -324
- package/examples/{express-api.js → express-api.ts} +161 -164
- package/examples/{large-dataset-example.js → large-dataset-example.ts} +201 -182
- package/examples/{ndjson-processing.js → ndjson-processing.ts} +456 -434
- package/examples/{plugin-excel-exporter.js → plugin-excel-exporter.ts} +6 -7
- package/examples/react-integration.tsx +637 -0
- package/examples/{schema-validation.js → schema-validation.ts} +2 -2
- package/examples/simple-usage.ts +194 -0
- package/examples/{streaming-example.js → streaming-example.ts} +12 -12
- package/index.d.ts +187 -18
- package/package.json +75 -81
- package/plugins.d.ts +37 -0
- package/schema.d.ts +103 -0
- package/src/browser/browser-functions.ts +402 -0
- package/src/browser/core.ts +152 -0
- package/src/browser/csv-to-json-browser.d.ts +3 -0
- package/src/browser/csv-to-json-browser.ts +494 -0
- package/src/browser/{errors-browser.js → errors-browser.ts} +305 -197
- package/src/browser/extensions/plugins.ts +93 -0
- package/src/browser/extensions/workers.ts +39 -0
- package/src/browser/globals.d.ts +5 -0
- package/src/browser/index.ts +192 -0
- package/src/browser/json-to-csv-browser.d.ts +3 -0
- package/src/browser/json-to-csv-browser.ts +338 -0
- package/src/browser/streams.ts +403 -0
- package/src/browser/workers/{csv-parser.worker.js → csv-parser.worker.ts} +3 -3
- package/src/browser/workers/{worker-pool.js → worker-pool.ts} +51 -30
- package/src/core/delimiter-cache.ts +320 -0
- package/src/core/{node-optimizations.js → node-optimizations.ts} +448 -407
- package/src/core/plugin-system.ts +588 -0
- package/src/core/transform-hooks.ts +566 -0
- package/src/engines/{fast-path-engine-new.js → fast-path-engine-new.ts} +11 -2
- package/src/engines/{fast-path-engine.js → fast-path-engine.ts} +79 -53
- package/src/errors.ts +1 -0
- package/src/formats/{ndjson-parser.js → ndjson-parser.ts} +24 -16
- package/src/formats/{tsv-parser.js → tsv-parser.ts} +18 -17
- package/src/{index-with-plugins.js → index-with-plugins.ts} +381 -357
- package/src/types/index.ts +275 -0
- package/src/utils/bom-utils.ts +373 -0
- package/src/utils/encoding-support.ts +155 -0
- package/src/utils/{schema-validator.js → schema-validator.ts} +814 -589
- package/src/utils/transform-loader.ts +389 -0
- package/src/utils/validators.ts +35 -0
- package/src/utils/zod-adapter.ts +280 -0
- package/src/web-server/{index.js → index.ts} +19 -19
- package/src/workers/csv-multithreaded.ts +310 -0
- package/src/workers/csv-parser.worker.ts +227 -0
- package/src/workers/worker-pool.ts +409 -0
- package/bin/jtcsv.js +0 -2462
- package/csv-to-json.js +0 -688
- package/errors.js +0 -208
- package/examples/simple-usage.js +0 -282
- package/index.js +0 -68
- package/json-save.js +0 -254
- package/json-to-csv.js +0 -526
- package/plugins/README.md +0 -91
- package/plugins/express-middleware/README.md +0 -64
- package/plugins/express-middleware/example.js +0 -136
- package/plugins/express-middleware/index.d.ts +0 -114
- package/plugins/express-middleware/index.js +0 -360
- package/plugins/express-middleware/package.json +0 -52
- package/plugins/fastify-plugin/index.js +0 -406
- package/plugins/fastify-plugin/package.json +0 -55
- package/plugins/hono/README.md +0 -28
- package/plugins/hono/index.d.ts +0 -12
- package/plugins/hono/index.js +0 -36
- package/plugins/hono/package.json +0 -35
- package/plugins/nestjs/README.md +0 -35
- package/plugins/nestjs/index.d.ts +0 -25
- package/plugins/nestjs/index.js +0 -77
- package/plugins/nestjs/package.json +0 -37
- package/plugins/nextjs-api/README.md +0 -57
- package/plugins/nextjs-api/examples/ConverterComponent.jsx +0 -386
- package/plugins/nextjs-api/examples/api-convert.js +0 -69
- package/plugins/nextjs-api/index.js +0 -387
- package/plugins/nextjs-api/package.json +0 -63
- package/plugins/nextjs-api/route.js +0 -371
- package/plugins/nuxt/README.md +0 -24
- package/plugins/nuxt/index.js +0 -21
- package/plugins/nuxt/package.json +0 -35
- package/plugins/nuxt/runtime/composables/useJtcsv.js +0 -6
- package/plugins/nuxt/runtime/plugin.js +0 -6
- package/plugins/remix/README.md +0 -26
- package/plugins/remix/index.d.ts +0 -16
- package/plugins/remix/index.js +0 -62
- package/plugins/remix/package.json +0 -35
- package/plugins/sveltekit/README.md +0 -28
- package/plugins/sveltekit/index.d.ts +0 -17
- package/plugins/sveltekit/index.js +0 -54
- package/plugins/sveltekit/package.json +0 -33
- package/plugins/trpc/README.md +0 -25
- package/plugins/trpc/index.d.ts +0 -7
- package/plugins/trpc/index.js +0 -32
- package/plugins/trpc/package.json +0 -34
- package/src/browser/browser-functions.js +0 -219
- package/src/browser/csv-to-json-browser.js +0 -700
- package/src/browser/index.js +0 -113
- package/src/browser/json-to-csv-browser.js +0 -309
- package/src/browser/streams.js +0 -393
- package/src/core/delimiter-cache.js +0 -186
- package/src/core/plugin-system.js +0 -476
- package/src/core/transform-hooks.js +0 -350
- package/src/errors.js +0 -26
- package/src/utils/transform-loader.js +0 -205
- package/stream-csv-to-json.js +0 -542
- package/stream-json-to-csv.js +0 -464
- /package/examples/{web-workers-advanced.js → web-workers-advanced.ts} +0 -0
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Пример использования Express middleware для JTCSV
|
|
3
|
-
*
|
|
4
|
-
* Запуск: node example.js
|
|
5
|
-
* Затем отправьте запросы:
|
|
6
|
-
* - POST /api/convert с JSON телом → получите CSV
|
|
7
|
-
* - POST /api/convert с CSV телом → получите JSON
|
|
8
|
-
* - POST /api/csv-to-json → конвертация CSV в JSON
|
|
9
|
-
* - POST /api/json-to-csv → конвертация JSON в CSV
|
|
10
|
-
* - GET /api/health → проверка состояния
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
const express = require('express');
|
|
14
|
-
const bodyParser = require('body-parser');
|
|
15
|
-
const {
|
|
16
|
-
middleware,
|
|
17
|
-
csvToJsonRoute,
|
|
18
|
-
jsonToCsvRoute,
|
|
19
|
-
healthCheck
|
|
20
|
-
} = require('./index');
|
|
21
|
-
|
|
22
|
-
const app = express();
|
|
23
|
-
const PORT = process.env.PORT || 3000;
|
|
24
|
-
|
|
25
|
-
// Middleware для парсинга JSON и текста
|
|
26
|
-
app.use(bodyParser.json());
|
|
27
|
-
app.use(bodyParser.text({ type: 'text/csv' }));
|
|
28
|
-
|
|
29
|
-
// Добавляем время начала обработки запроса
|
|
30
|
-
app.use((req, res, next) => {
|
|
31
|
-
req.startTime = Date.now();
|
|
32
|
-
next();
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// Основное middleware для автоматической конвертации
|
|
36
|
-
app.use(middleware({
|
|
37
|
-
maxSize: '50mb',
|
|
38
|
-
delimiter: ',',
|
|
39
|
-
enableFastPath: true,
|
|
40
|
-
preventCsvInjection: true
|
|
41
|
-
}));
|
|
42
|
-
|
|
43
|
-
// Роуты для конкретных операций
|
|
44
|
-
app.post('/api/csv-to-json', csvToJsonRoute({
|
|
45
|
-
delimiter: ',',
|
|
46
|
-
parseNumbers: true,
|
|
47
|
-
parseBooleans: true
|
|
48
|
-
}));
|
|
49
|
-
|
|
50
|
-
app.post('/api/json-to-csv', jsonToCsvRoute({
|
|
51
|
-
delimiter: ',',
|
|
52
|
-
includeHeaders: true,
|
|
53
|
-
preventCsvInjection: true
|
|
54
|
-
}));
|
|
55
|
-
|
|
56
|
-
// Health check
|
|
57
|
-
app.get('/api/health', healthCheck());
|
|
58
|
-
|
|
59
|
-
// Пример роута, использующего автоматическую конвертацию
|
|
60
|
-
app.post('/api/convert', (req, res) => {
|
|
61
|
-
if (!req.converted) {
|
|
62
|
-
return res.status(400).json({
|
|
63
|
-
success: false,
|
|
64
|
-
error: 'No data to convert'
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
res.json({
|
|
69
|
-
success: true,
|
|
70
|
-
conversion: req.converted.conversion,
|
|
71
|
-
data: req.converted.data,
|
|
72
|
-
stats: {
|
|
73
|
-
...req.converted.stats,
|
|
74
|
-
totalTime: Date.now() - req.startTime
|
|
75
|
-
},
|
|
76
|
-
format: req.converted.outputFormat
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
// Пример роута для скачивания CSV
|
|
81
|
-
app.post('/api/download-csv', (req, res) => {
|
|
82
|
-
if (!req.converted || req.converted.outputFormat !== 'csv') {
|
|
83
|
-
return res.status(400).json({
|
|
84
|
-
success: false,
|
|
85
|
-
error: 'CSV data not available'
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
res.setHeader('Content-Type', 'text/csv');
|
|
90
|
-
res.setHeader('Content-Disposition', 'attachment; filename="converted.csv"');
|
|
91
|
-
res.send(req.converted.data);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// Обработка ошибок
|
|
95
|
-
app.use((err, req, res, next) => {
|
|
96
|
-
console.error('Server error:', err);
|
|
97
|
-
res.status(500).json({
|
|
98
|
-
success: false,
|
|
99
|
-
error: 'Internal server error',
|
|
100
|
-
message: process.env.NODE_ENV === 'development' ? err.message : undefined
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
// 404 handler
|
|
105
|
-
app.use((req, res) => {
|
|
106
|
-
res.status(404).json({
|
|
107
|
-
success: false,
|
|
108
|
-
error: 'Route not found',
|
|
109
|
-
availableRoutes: [
|
|
110
|
-
'POST /api/convert',
|
|
111
|
-
'POST /api/csv-to-json',
|
|
112
|
-
'POST /api/json-to-csv',
|
|
113
|
-
'POST /api/download-csv',
|
|
114
|
-
'GET /api/health'
|
|
115
|
-
]
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// Запуск сервера
|
|
120
|
-
app.listen(PORT, () => {
|
|
121
|
-
console.log(`🚀 JTCSV Express server запущен на порту ${PORT}`);
|
|
122
|
-
console.log(`📚 Примеры запросов:`);
|
|
123
|
-
console.log(` curl -X POST http://localhost:${PORT}/api/convert \
|
|
124
|
-
-H "Content-Type: application/json" \
|
|
125
|
-
-d '[{"name":"John","age":30},{"name":"Jane","age":25}]'`);
|
|
126
|
-
console.log();
|
|
127
|
-
console.log(` curl -X POST http://localhost:${PORT}/api/convert \
|
|
128
|
-
-H "Content-Type: text/csv" \
|
|
129
|
-
-d 'name,age\nJohn,30\nJane,25'`);
|
|
130
|
-
console.log();
|
|
131
|
-
console.log(` curl -X GET http://localhost:${PORT}/api/health`);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
module.exports = app;
|
|
135
|
-
|
|
136
|
-
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypeScript definitions для JTCSV Express Middleware
|
|
3
|
-
*
|
|
4
|
-
* @version 1.0.0
|
|
5
|
-
* @date 2026-01-23
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
declare module '@jtcsv/express-middleware' {
|
|
9
|
-
import { RequestHandler } from 'express';
|
|
10
|
-
import { CsvToJsonOptions, JsonToCsvOptions } from 'jtcsv
|
|
11
|
-
|
|
12
|
-
export interface JtcsvMiddlewareOptions {
|
|
13
|
-
/** Максимальный размер тела запроса */
|
|
14
|
-
maxSize?: string;
|
|
15
|
-
|
|
16
|
-
/** Автоматическое определение формата */
|
|
17
|
-
autoDetect?: boolean;
|
|
18
|
-
|
|
19
|
-
/** Разделитель CSV */
|
|
20
|
-
delimiter?: string;
|
|
21
|
-
|
|
22
|
-
/** Включить Fast-Path Engine */
|
|
23
|
-
enableFastPath?: boolean;
|
|
24
|
-
|
|
25
|
-
/** Защита от CSV инъекций */
|
|
26
|
-
preventCsvInjection?: boolean;
|
|
27
|
-
|
|
28
|
-
/** Соответствие RFC 4180 */
|
|
29
|
-
rfc4180Compliant?: boolean;
|
|
30
|
-
|
|
31
|
-
/** Дополнительные опции конвертации */
|
|
32
|
-
conversionOptions?: CsvToJsonOptions | JsonToCsvOptions;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface ConversionStats {
|
|
36
|
-
/** Размер входных данных в байтах */
|
|
37
|
-
inputSize: number;
|
|
38
|
-
|
|
39
|
-
/** Размер выходных данных в байтах */
|
|
40
|
-
outputSize: number;
|
|
41
|
-
|
|
42
|
-
/** Время обработки в миллисекундах */
|
|
43
|
-
processingTime: number;
|
|
44
|
-
|
|
45
|
-
/** Тип конвертации */
|
|
46
|
-
conversion: string;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface ConvertedData {
|
|
50
|
-
/** Конвертированные данные */
|
|
51
|
-
data: any;
|
|
52
|
-
|
|
53
|
-
/** Формат выходных данных */
|
|
54
|
-
format: 'json' | 'csv';
|
|
55
|
-
|
|
56
|
-
/** Формат входных данных */
|
|
57
|
-
inputFormat: 'json' | 'csv' | 'unknown';
|
|
58
|
-
|
|
59
|
-
/** Формат выходных данных */
|
|
60
|
-
outputFormat: 'json' | 'csv';
|
|
61
|
-
|
|
62
|
-
/** Статистика конвертации */
|
|
63
|
-
stats: ConversionStats;
|
|
64
|
-
|
|
65
|
-
/** Использованные опции */
|
|
66
|
-
options: CsvToJsonOptions | JsonToCsvOptions;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Расширяем интерфейс Request Express
|
|
70
|
-
declare global {
|
|
71
|
-
namespace Express {
|
|
72
|
-
interface Request {
|
|
73
|
-
/** Конвертированные данные */
|
|
74
|
-
converted?: ConvertedData;
|
|
75
|
-
|
|
76
|
-
/** Время начала обработки запроса */
|
|
77
|
-
startTime?: number;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Express middleware для автоматической конвертации CSV/JSON
|
|
84
|
-
*/
|
|
85
|
-
export function middleware(options?: JtcsvMiddlewareOptions): RequestHandler;
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Express route для конвертации CSV в JSON
|
|
89
|
-
*/
|
|
90
|
-
export function csvToJsonRoute(options?: CsvToJsonOptions): RequestHandler;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Express route для конвертации JSON в CSV
|
|
94
|
-
*/
|
|
95
|
-
export function jsonToCsvRoute(options?: JsonToCsvOptions): RequestHandler;
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Express route для загрузки CSV файла
|
|
99
|
-
*/
|
|
100
|
-
export function uploadCsvRoute(options?: CsvToJsonOptions): RequestHandler;
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Health check endpoint
|
|
104
|
-
*/
|
|
105
|
-
export function healthCheck(): RequestHandler;
|
|
106
|
-
|
|
107
|
-
// Aliases
|
|
108
|
-
export const jtcsvMiddleware: typeof middleware;
|
|
109
|
-
export const createMiddleware: typeof middleware;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export {};
|
|
113
|
-
|
|
114
|
-
|
|
@@ -1,360 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Express middleware для JTCSV
|
|
3
|
-
* Автоматическая конвертация CSV/JSON в HTTP запросах
|
|
4
|
-
*
|
|
5
|
-
* @version 1.0.0
|
|
6
|
-
* @date 2026-01-23
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const { csvToJson, jsonToCsv } = require('../../index.js');
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Express middleware для обработки CSV/JSON конвертации
|
|
13
|
-
*
|
|
14
|
-
* @param {Object} options - Опции middleware
|
|
15
|
-
* @param {string} options.maxSize - Максимальный размер тела запроса (default: '10mb')
|
|
16
|
-
* @param {boolean} options.autoDetect - Автоматическое определение формата (default: true)
|
|
17
|
-
* @param {string} options.delimiter - Разделитель CSV (default: ',')
|
|
18
|
-
* @param {boolean} options.enableFastPath - Включить Fast-Path Engine (default: true)
|
|
19
|
-
* @param {boolean} options.preventCsvInjection - Защита от CSV инъекций (default: true)
|
|
20
|
-
*
|
|
21
|
-
* @returns {Function} Express middleware
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* // Базовое использование
|
|
25
|
-
* const app = express();
|
|
26
|
-
* app.use(express.json());
|
|
27
|
-
* app.use(express.text({ type: 'text/csv' }));
|
|
28
|
-
* app.use(jtcsvMiddleware());
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* // С кастомными опциями
|
|
32
|
-
* app.use(jtcsvMiddleware({
|
|
33
|
-
* maxSize: '50mb',
|
|
34
|
-
* delimiter: ';',
|
|
35
|
-
* enableFastPath: true
|
|
36
|
-
* }));
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* // Использование в роуте
|
|
40
|
-
* app.post('/api/convert', (req, res) => {
|
|
41
|
-
* // Конвертированные данные доступны в req.converted
|
|
42
|
-
* res.json({
|
|
43
|
-
* success: true,
|
|
44
|
-
* data: req.converted.data,
|
|
45
|
-
* format: req.converted.format
|
|
46
|
-
* });
|
|
47
|
-
* });
|
|
48
|
-
*/
|
|
49
|
-
function jtcsvExpressMiddleware(options = {}) {
|
|
50
|
-
const {
|
|
51
|
-
maxSize = '10mb',
|
|
52
|
-
autoDetect = true,
|
|
53
|
-
delimiter = ',',
|
|
54
|
-
enableFastPath = true,
|
|
55
|
-
preventCsvInjection = true,
|
|
56
|
-
rfc4180Compliant = true
|
|
57
|
-
} = options;
|
|
58
|
-
|
|
59
|
-
return async (req, res, next) => {
|
|
60
|
-
// Пропускаем запросы без тела
|
|
61
|
-
if (!req.body || (typeof req.body !== 'string' && typeof req.body !== 'object')) {
|
|
62
|
-
return next();
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const contentType = req.get('content-type') || '';
|
|
66
|
-
const acceptHeader = req.get('accept') || 'application/json';
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
// Определяем формат входных данных
|
|
70
|
-
let inputFormat = 'unknown';
|
|
71
|
-
let inputData = req.body;
|
|
72
|
-
|
|
73
|
-
if (autoDetect) {
|
|
74
|
-
if (contentType.includes('application/json') ||
|
|
75
|
-
(typeof req.body === 'object' && !Array.isArray(req.body))) {
|
|
76
|
-
inputFormat = 'json';
|
|
77
|
-
} else if (contentType.includes('text/csv') ||
|
|
78
|
-
contentType.includes('text/plain') ||
|
|
79
|
-
(typeof req.body === 'string' && req.body.includes(','))) {
|
|
80
|
-
inputFormat = 'csv';
|
|
81
|
-
}
|
|
82
|
-
} else {
|
|
83
|
-
// Ручное определение на основе content-type
|
|
84
|
-
if (contentType.includes('application/json')) {
|
|
85
|
-
inputFormat = 'json';
|
|
86
|
-
} else if (contentType.includes('text/csv')) {
|
|
87
|
-
inputFormat = 'csv';
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Если формат не определен, пропускаем
|
|
92
|
-
if (inputFormat === 'unknown') {
|
|
93
|
-
return next();
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Определяем желаемый формат вывода на основе Accept header
|
|
97
|
-
let outputFormat = 'json';
|
|
98
|
-
if (acceptHeader.includes('text/csv')) {
|
|
99
|
-
outputFormat = 'csv';
|
|
100
|
-
} else if (req.query.format === 'csv') {
|
|
101
|
-
outputFormat = 'csv';
|
|
102
|
-
} else if (req.body.format === 'csv') {
|
|
103
|
-
outputFormat = 'csv';
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Опции конвертации
|
|
107
|
-
const conversionOptions = {
|
|
108
|
-
delimiter,
|
|
109
|
-
preventCsvInjection,
|
|
110
|
-
rfc4180Compliant,
|
|
111
|
-
useFastPath: enableFastPath,
|
|
112
|
-
...req.query,
|
|
113
|
-
...options.conversionOptions
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
// Удаляем параметры, которые не относятся к конвертации
|
|
117
|
-
delete conversionOptions.maxSize;
|
|
118
|
-
delete conversionOptions.autoDetect;
|
|
119
|
-
delete conversionOptions.enableFastPath;
|
|
120
|
-
|
|
121
|
-
let result;
|
|
122
|
-
let stats = {
|
|
123
|
-
inputSize: 0,
|
|
124
|
-
outputSize: 0,
|
|
125
|
-
processingTime: 0,
|
|
126
|
-
conversion: `${inputFormat}→${outputFormat}`
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
const startTime = Date.now();
|
|
130
|
-
|
|
131
|
-
// Выполняем конвертацию
|
|
132
|
-
if (inputFormat === 'json' && outputFormat === 'csv') {
|
|
133
|
-
const jsonData = typeof inputData === 'string' ? JSON.parse(inputData) : inputData;
|
|
134
|
-
stats.inputSize = Buffer.byteLength(JSON.stringify(jsonData));
|
|
135
|
-
|
|
136
|
-
result = await jsonToCsv(jsonData, conversionOptions);
|
|
137
|
-
stats.outputSize = Buffer.byteLength(result);
|
|
138
|
-
|
|
139
|
-
} else if (inputFormat === 'csv' && outputFormat === 'json') {
|
|
140
|
-
const csvData = typeof inputData === 'string' ? inputData : String(inputData);
|
|
141
|
-
stats.inputSize = Buffer.byteLength(csvData);
|
|
142
|
-
|
|
143
|
-
result = await csvToJson(csvData, conversionOptions);
|
|
144
|
-
stats.outputSize = Buffer.byteLength(JSON.stringify(result));
|
|
145
|
-
|
|
146
|
-
} else {
|
|
147
|
-
// Нет необходимости в конвертации
|
|
148
|
-
result = inputData;
|
|
149
|
-
stats.conversion = 'none';
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
stats.processingTime = Date.now() - startTime;
|
|
153
|
-
|
|
154
|
-
// Сохраняем результат в request object
|
|
155
|
-
req.converted = {
|
|
156
|
-
data: result,
|
|
157
|
-
format: outputFormat,
|
|
158
|
-
inputFormat,
|
|
159
|
-
outputFormat,
|
|
160
|
-
stats,
|
|
161
|
-
options: conversionOptions
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
// Устанавливаем соответствующий Content-Type для ответа
|
|
165
|
-
if (outputFormat === 'csv') {
|
|
166
|
-
res.set('Content-Type', 'text/csv; charset=utf-8');
|
|
167
|
-
} else {
|
|
168
|
-
res.set('Content-Type', 'application/json; charset=utf-8');
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
next();
|
|
172
|
-
|
|
173
|
-
} catch (error) {
|
|
174
|
-
// Обработка ошибок конвертации
|
|
175
|
-
const errorResponse = {
|
|
176
|
-
success: false,
|
|
177
|
-
error: error.message,
|
|
178
|
-
code: error.code || 'CONVERSION_ERROR',
|
|
179
|
-
timestamp: new Date().toISOString()
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
// Добавляем дополнительную информацию для отладки
|
|
183
|
-
if (process.env.NODE_ENV === 'development') {
|
|
184
|
-
errorResponse.stack = error.stack;
|
|
185
|
-
errorResponse.details = {
|
|
186
|
-
contentType: req.get('content-type'),
|
|
187
|
-
contentLength: req.get('content-length'),
|
|
188
|
-
method: req.method,
|
|
189
|
-
url: req.url
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
res.status(400).json(errorResponse);
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Express route для конвертации CSV в JSON
|
|
200
|
-
*
|
|
201
|
-
* @param {Object} options - Опции конвертации
|
|
202
|
-
* @returns {Function} Express route handler
|
|
203
|
-
*
|
|
204
|
-
* @example
|
|
205
|
-
* app.post('/api/csv-to-json', jtcsvCsvToJsonRoute());
|
|
206
|
-
*/
|
|
207
|
-
function jtcsvCsvToJsonRoute(options = {}) {
|
|
208
|
-
return async (req, res) => {
|
|
209
|
-
try {
|
|
210
|
-
const csvData = req.body;
|
|
211
|
-
|
|
212
|
-
if (!csvData || (typeof csvData !== 'string' && !Buffer.isBuffer(csvData))) {
|
|
213
|
-
return res.status(400).json({
|
|
214
|
-
success: false,
|
|
215
|
-
error: 'CSV data is required'
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const result = await csvToJson(csvData, options);
|
|
220
|
-
|
|
221
|
-
res.json({
|
|
222
|
-
success: true,
|
|
223
|
-
data: result,
|
|
224
|
-
stats: {
|
|
225
|
-
rows: result.length,
|
|
226
|
-
processingTime: Date.now() - req.startTime
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
} catch (error) {
|
|
230
|
-
res.status(400).json({
|
|
231
|
-
success: false,
|
|
232
|
-
error: error.message
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Express route для конвертации JSON в CSV
|
|
240
|
-
*
|
|
241
|
-
* @param {Object} options - Опции конвертации
|
|
242
|
-
* @returns {Function} Express route handler
|
|
243
|
-
*
|
|
244
|
-
* @example
|
|
245
|
-
* app.post('/api/json-to-csv', jtcsvJsonToCsvRoute());
|
|
246
|
-
*/
|
|
247
|
-
function jtcsvJsonToCsvRoute(options = {}) {
|
|
248
|
-
return async (req, res) => {
|
|
249
|
-
try {
|
|
250
|
-
const jsonData = req.body;
|
|
251
|
-
|
|
252
|
-
if (!jsonData || (typeof jsonData !== 'object' && typeof jsonData !== 'string')) {
|
|
253
|
-
return res.status(400).json({
|
|
254
|
-
success: false,
|
|
255
|
-
error: 'JSON data is required'
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
const data = typeof jsonData === 'string' ? JSON.parse(jsonData) : jsonData;
|
|
260
|
-
const result = await jsonToCsv(data, options);
|
|
261
|
-
|
|
262
|
-
res.set('Content-Type', 'text/csv; charset=utf-8');
|
|
263
|
-
res.set('Content-Disposition', 'attachment; filename="data.csv"');
|
|
264
|
-
|
|
265
|
-
res.send(result);
|
|
266
|
-
} catch (error) {
|
|
267
|
-
res.status(400).json({
|
|
268
|
-
success: false,
|
|
269
|
-
error: error.message
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Express route для загрузки CSV файла
|
|
277
|
-
*
|
|
278
|
-
* @param {Object} options - Опции конвертации
|
|
279
|
-
* @returns {Function} Express route handler
|
|
280
|
-
*
|
|
281
|
-
* @example
|
|
282
|
-
* const multer = require('multer');
|
|
283
|
-
* const upload = multer({ dest: 'uploads/' });
|
|
284
|
-
* app.post('/api/upload-csv', upload.single('file'), jtcsvUploadCsvRoute());
|
|
285
|
-
*/
|
|
286
|
-
function jtcsvUploadCsvRoute(options = {}) {
|
|
287
|
-
return async (req, res) => {
|
|
288
|
-
try {
|
|
289
|
-
if (!req.file) {
|
|
290
|
-
return res.status(400).json({
|
|
291
|
-
success: false,
|
|
292
|
-
error: 'CSV file is required'
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const fs = require('fs').promises;
|
|
297
|
-
const csvData = await fs.readFile(req.file.path, 'utf8');
|
|
298
|
-
|
|
299
|
-
const result = await csvToJson(csvData, options);
|
|
300
|
-
|
|
301
|
-
// Очищаем временный файл
|
|
302
|
-
await fs.unlink(req.file.path);
|
|
303
|
-
|
|
304
|
-
res.json({
|
|
305
|
-
success: true,
|
|
306
|
-
data: result,
|
|
307
|
-
stats: {
|
|
308
|
-
rows: result.length,
|
|
309
|
-
fileSize: req.file.size,
|
|
310
|
-
processingTime: Date.now() - req.startTime
|
|
311
|
-
}
|
|
312
|
-
});
|
|
313
|
-
} catch (error) {
|
|
314
|
-
res.status(400).json({
|
|
315
|
-
success: false,
|
|
316
|
-
error: error.message
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Health check endpoint для JTCSV
|
|
324
|
-
*
|
|
325
|
-
* @returns {Function} Express route handler
|
|
326
|
-
*
|
|
327
|
-
* @example
|
|
328
|
-
* app.get('/api/health', jtcsvHealthCheck());
|
|
329
|
-
*/
|
|
330
|
-
function jtcsvHealthCheck() {
|
|
331
|
-
return (req, res) => {
|
|
332
|
-
res.json({
|
|
333
|
-
service: 'jtcsv-express-middleware',
|
|
334
|
-
status: 'healthy',
|
|
335
|
-
version: '1.0.0',
|
|
336
|
-
timestamp: new Date().toISOString(),
|
|
337
|
-
features: {
|
|
338
|
-
csvToJson: true,
|
|
339
|
-
jsonToCsv: true,
|
|
340
|
-
fastPathEngine: true,
|
|
341
|
-
csvInjectionProtection: true,
|
|
342
|
-
streaming: true
|
|
343
|
-
}
|
|
344
|
-
});
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
module.exports = {
|
|
349
|
-
middleware: jtcsvExpressMiddleware,
|
|
350
|
-
csvToJsonRoute: jtcsvCsvToJsonRoute,
|
|
351
|
-
jsonToCsvRoute: jtcsvJsonToCsvRoute,
|
|
352
|
-
uploadCsvRoute: jtcsvUploadCsvRoute,
|
|
353
|
-
healthCheck: jtcsvHealthCheck,
|
|
354
|
-
|
|
355
|
-
// Aliases для удобства
|
|
356
|
-
jtcsvMiddleware: jtcsvExpressMiddleware,
|
|
357
|
-
createMiddleware: jtcsvExpressMiddleware
|
|
358
|
-
};
|
|
359
|
-
|
|
360
|
-
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@jtcsv/express-middleware",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "Express middleware для автоматической конвертации CSV/JSON в HTTP запросах",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"types": "index.d.ts",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"test": "jest",
|
|
9
|
-
"lint": "eslint index.js",
|
|
10
|
-
"example": "node example.js"
|
|
11
|
-
},
|
|
12
|
-
"keywords": [
|
|
13
|
-
"express",
|
|
14
|
-
"middleware",
|
|
15
|
-
"csv",
|
|
16
|
-
"json",
|
|
17
|
-
"converter",
|
|
18
|
-
"jtcsv",
|
|
19
|
-
"api",
|
|
20
|
-
"rest",
|
|
21
|
-
"http"
|
|
22
|
-
],
|
|
23
|
-
"author": "Ruslan Fomenko",
|
|
24
|
-
"license": "MIT",
|
|
25
|
-
"repository": {
|
|
26
|
-
"type": "git",
|
|
27
|
-
"url": "git+https://github.com/Linol-Hamelton/jtcsv.git",
|
|
28
|
-
"directory": "plugins/express-middleware"
|
|
29
|
-
},
|
|
30
|
-
"bugs": {
|
|
31
|
-
"url": "https://github.com/Linol-Hamelton/jtcsv/issues"
|
|
32
|
-
},
|
|
33
|
-
"homepage": "https://github.com/Linol-Hamelton/jtcsv/tree/main/plugins/express-middleware#readme",
|
|
34
|
-
"peerDependencies": {
|
|
35
|
-
"express": "^4.18.0",
|
|
36
|
-
"jtcsv": "^2.1.0"
|
|
37
|
-
},
|
|
38
|
-
"devDependencies": {
|
|
39
|
-
"express": "^4.18.0",
|
|
40
|
-
"jest": "^29.0.0",
|
|
41
|
-
"eslint": "^8.57.0",
|
|
42
|
-
"supertest": "^6.3.0"
|
|
43
|
-
},
|
|
44
|
-
"files": [
|
|
45
|
-
"index.js",
|
|
46
|
-
"index.d.ts",
|
|
47
|
-
"README.md",
|
|
48
|
-
"example.js"
|
|
49
|
-
]
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|