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
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.jtcsvFastifyPlugin = jtcsvFastifyPlugin;
|
|
4
|
+
const fp = require('fastify-plugin');
|
|
5
|
+
const index_core_1 = require("../../index-core");
|
|
6
|
+
async function jtcsvFastifyPlugin(fastify, options = {}) {
|
|
7
|
+
const { prefix = '/convert', delimiter = ',', enableFastPath = true, preventCsvInjection = true, rfc4180Compliant = true } = options;
|
|
8
|
+
fastify.get(`${prefix}/health`, async () => {
|
|
9
|
+
return {
|
|
10
|
+
service: 'jtcsv-fastify-plugin',
|
|
11
|
+
status: 'healthy',
|
|
12
|
+
version: '1.0.0',
|
|
13
|
+
timestamp: new Date().toISOString(),
|
|
14
|
+
features: {
|
|
15
|
+
csvToJson: true,
|
|
16
|
+
jsonToCsv: true,
|
|
17
|
+
fastPathEngine: enableFastPath,
|
|
18
|
+
csvInjectionProtection: preventCsvInjection,
|
|
19
|
+
streaming: true,
|
|
20
|
+
ndjson: true
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
fastify.post(`${prefix}/csv-to-json`, {
|
|
25
|
+
schema: {
|
|
26
|
+
body: {
|
|
27
|
+
type: 'object',
|
|
28
|
+
required: ['csv'],
|
|
29
|
+
properties: {
|
|
30
|
+
csv: { type: 'string' },
|
|
31
|
+
delimiter: { type: 'string', default: delimiter },
|
|
32
|
+
parseNumbers: { type: 'boolean', default: true },
|
|
33
|
+
parseBooleans: { type: 'boolean', default: true },
|
|
34
|
+
useFastPath: { type: 'boolean', default: enableFastPath }
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
response: {
|
|
38
|
+
200: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
properties: {
|
|
41
|
+
success: { type: 'boolean' },
|
|
42
|
+
data: { type: 'array' },
|
|
43
|
+
stats: {
|
|
44
|
+
type: 'object',
|
|
45
|
+
properties: {
|
|
46
|
+
rows: { type: 'number' },
|
|
47
|
+
processingTime: { type: 'number' }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}, async (request, reply) => {
|
|
55
|
+
const startTime = Date.now();
|
|
56
|
+
const { csv, delimiter: reqDelimiter = delimiter, parseNumbers = true, parseBooleans = true, useFastPath = enableFastPath } = request.body;
|
|
57
|
+
try {
|
|
58
|
+
const json = await (0, index_core_1.csvToJsonAsync)(csv, {
|
|
59
|
+
delimiter: reqDelimiter,
|
|
60
|
+
parseNumbers,
|
|
61
|
+
parseBooleans,
|
|
62
|
+
useFastPath,
|
|
63
|
+
preventCsvInjection,
|
|
64
|
+
rfc4180Compliant
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
success: true,
|
|
68
|
+
data: json,
|
|
69
|
+
stats: {
|
|
70
|
+
rows: json.length,
|
|
71
|
+
processingTime: Date.now() - startTime
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
reply.code(400);
|
|
77
|
+
return {
|
|
78
|
+
success: false,
|
|
79
|
+
error: error.message,
|
|
80
|
+
code: 'CSV_CONVERSION_ERROR'
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
fastify.post(`${prefix}/json-to-csv`, {
|
|
85
|
+
schema: {
|
|
86
|
+
body: {
|
|
87
|
+
type: 'object',
|
|
88
|
+
required: ['json'],
|
|
89
|
+
properties: {
|
|
90
|
+
json: { type: 'array' },
|
|
91
|
+
delimiter: { type: 'string', default: delimiter },
|
|
92
|
+
includeHeaders: { type: 'boolean', default: true }
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
response: {
|
|
96
|
+
200: {
|
|
97
|
+
type: 'object',
|
|
98
|
+
properties: {
|
|
99
|
+
success: { type: 'boolean' },
|
|
100
|
+
data: { type: 'string' },
|
|
101
|
+
stats: {
|
|
102
|
+
type: 'object',
|
|
103
|
+
properties: {
|
|
104
|
+
size: { type: 'number' },
|
|
105
|
+
processingTime: { type: 'number' }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}, async (request, reply) => {
|
|
113
|
+
const startTime = Date.now();
|
|
114
|
+
const { json, delimiter: reqDelimiter = delimiter, includeHeaders = true } = request.body;
|
|
115
|
+
try {
|
|
116
|
+
const csv = await (0, index_core_1.jsonToCsvAsync)(json, {
|
|
117
|
+
delimiter: reqDelimiter,
|
|
118
|
+
includeHeaders,
|
|
119
|
+
preventCsvInjection,
|
|
120
|
+
rfc4180Compliant
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
success: true,
|
|
124
|
+
data: csv,
|
|
125
|
+
stats: {
|
|
126
|
+
size: Buffer.byteLength(csv),
|
|
127
|
+
processingTime: Date.now() - startTime
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
reply.code(400);
|
|
133
|
+
return {
|
|
134
|
+
success: false,
|
|
135
|
+
error: error.message,
|
|
136
|
+
code: 'JSON_CONVERSION_ERROR'
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
fastify.post(`${prefix}/auto`, {
|
|
141
|
+
schema: {
|
|
142
|
+
body: {
|
|
143
|
+
oneOf: [
|
|
144
|
+
{ type: 'string' },
|
|
145
|
+
{ type: 'array' },
|
|
146
|
+
{ type: 'object' }
|
|
147
|
+
]
|
|
148
|
+
},
|
|
149
|
+
headers: {
|
|
150
|
+
type: 'object',
|
|
151
|
+
properties: {
|
|
152
|
+
'content-type': {
|
|
153
|
+
type: 'string',
|
|
154
|
+
enum: ['application/json', 'text/csv', 'text/plain']
|
|
155
|
+
},
|
|
156
|
+
'accept': {
|
|
157
|
+
type: 'string',
|
|
158
|
+
enum: ['application/json', 'text/csv']
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
querystring: {
|
|
163
|
+
type: 'object',
|
|
164
|
+
properties: {
|
|
165
|
+
format: { type: 'string', enum: ['json', 'csv'] },
|
|
166
|
+
delimiter: { type: 'string' }
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}, async (request, reply) => {
|
|
171
|
+
const startTime = Date.now();
|
|
172
|
+
const contentType = request.headers['content-type'] || '';
|
|
173
|
+
const acceptHeader = request.headers['accept'] || 'application/json';
|
|
174
|
+
const { format, delimiter: queryDelimiter } = request.query;
|
|
175
|
+
const reqDelimiter = queryDelimiter || delimiter;
|
|
176
|
+
try {
|
|
177
|
+
let inputFormat = 'unknown';
|
|
178
|
+
const outputFormat = format || (acceptHeader.includes('text/csv') ? 'csv' : 'json');
|
|
179
|
+
if (contentType.includes('application/json') || Array.isArray(request.body)) {
|
|
180
|
+
inputFormat = 'json';
|
|
181
|
+
}
|
|
182
|
+
else if (contentType.includes('text/csv') ||
|
|
183
|
+
contentType.includes('text/plain') ||
|
|
184
|
+
(typeof request.body === 'string' && request.body.includes(','))) {
|
|
185
|
+
inputFormat = 'csv';
|
|
186
|
+
}
|
|
187
|
+
if (inputFormat === 'unknown') {
|
|
188
|
+
reply.code(400);
|
|
189
|
+
return {
|
|
190
|
+
success: false,
|
|
191
|
+
error: 'Unable to determine input format',
|
|
192
|
+
code: 'UNKNOWN_FORMAT'
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
let result;
|
|
196
|
+
const stats = {
|
|
197
|
+
inputSize: 0,
|
|
198
|
+
outputSize: 0,
|
|
199
|
+
processingTime: 0,
|
|
200
|
+
conversion: `${inputFormat}→${outputFormat}`
|
|
201
|
+
};
|
|
202
|
+
const conversionOptions = {
|
|
203
|
+
delimiter: reqDelimiter,
|
|
204
|
+
useFastPath: enableFastPath,
|
|
205
|
+
preventCsvInjection,
|
|
206
|
+
rfc4180Compliant
|
|
207
|
+
};
|
|
208
|
+
if (inputFormat === 'json' && outputFormat === 'csv') {
|
|
209
|
+
const jsonData = Array.isArray(request.body) ? request.body : [request.body];
|
|
210
|
+
stats.inputSize = Buffer.byteLength(JSON.stringify(jsonData));
|
|
211
|
+
result = await (0, index_core_1.jsonToCsvAsync)(jsonData, {
|
|
212
|
+
...conversionOptions,
|
|
213
|
+
includeHeaders: true
|
|
214
|
+
});
|
|
215
|
+
stats.outputSize = Buffer.byteLength(result);
|
|
216
|
+
reply.header('Content-Type', 'text/csv; charset=utf-8');
|
|
217
|
+
}
|
|
218
|
+
else if (inputFormat === 'csv' && outputFormat === 'json') {
|
|
219
|
+
const csvData = typeof request.body === 'string' ? request.body : String(request.body);
|
|
220
|
+
stats.inputSize = Buffer.byteLength(csvData);
|
|
221
|
+
result = await (0, index_core_1.csvToJsonAsync)(csvData, {
|
|
222
|
+
...conversionOptions,
|
|
223
|
+
parseNumbers: true,
|
|
224
|
+
parseBooleans: true
|
|
225
|
+
});
|
|
226
|
+
stats.outputSize = Buffer.byteLength(JSON.stringify(result));
|
|
227
|
+
reply.header('Content-Type', 'application/json; charset=utf-8');
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
result = request.body;
|
|
231
|
+
stats.conversion = 'none';
|
|
232
|
+
stats.inputSize = Buffer.byteLength(JSON.stringify(result));
|
|
233
|
+
stats.outputSize = stats.inputSize;
|
|
234
|
+
}
|
|
235
|
+
stats.processingTime = Date.now() - startTime;
|
|
236
|
+
return {
|
|
237
|
+
success: true,
|
|
238
|
+
data: result,
|
|
239
|
+
format: outputFormat,
|
|
240
|
+
inputFormat,
|
|
241
|
+
stats
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
reply.code(400);
|
|
246
|
+
return {
|
|
247
|
+
success: false,
|
|
248
|
+
error: error.message,
|
|
249
|
+
code: 'CONVERSION_ERROR',
|
|
250
|
+
details: process.env['NODE_ENV'] === 'development' ? error.stack : undefined
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
fastify.post(`${prefix}/stream`, {
|
|
255
|
+
schema: {
|
|
256
|
+
body: {
|
|
257
|
+
type: 'object',
|
|
258
|
+
required: ['direction'],
|
|
259
|
+
properties: {
|
|
260
|
+
direction: {
|
|
261
|
+
type: 'string',
|
|
262
|
+
enum: ['csv-to-json', 'json-to-csv']
|
|
263
|
+
},
|
|
264
|
+
delimiter: { type: 'string', default: delimiter }
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}, async (request, reply) => {
|
|
269
|
+
const { direction, delimiter: reqDelimiter = delimiter } = request.body;
|
|
270
|
+
if (direction === 'csv-to-json') {
|
|
271
|
+
reply.header('Content-Type', 'application/x-ndjson');
|
|
272
|
+
reply.header('Transfer-Encoding', 'chunked');
|
|
273
|
+
reply.send(JSON.stringify({
|
|
274
|
+
success: false,
|
|
275
|
+
error: 'Streaming endpoint not implemented yet',
|
|
276
|
+
code: 'NOT_IMPLEMENTED'
|
|
277
|
+
}));
|
|
278
|
+
}
|
|
279
|
+
else if (direction === 'json-to-csv') {
|
|
280
|
+
reply.header('Content-Type', 'text/csv');
|
|
281
|
+
reply.header('Transfer-Encoding', 'chunked');
|
|
282
|
+
reply.send('Streaming endpoint not implemented yet\n');
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
fastify.decorate('jtcsv', {
|
|
286
|
+
csvToJson: async (csv, options = {}) => {
|
|
287
|
+
return (0, index_core_1.csvToJsonAsync)(csv, {
|
|
288
|
+
delimiter,
|
|
289
|
+
useFastPath: enableFastPath,
|
|
290
|
+
preventCsvInjection,
|
|
291
|
+
rfc4180Compliant,
|
|
292
|
+
...options
|
|
293
|
+
});
|
|
294
|
+
},
|
|
295
|
+
jsonToCsv: async (json, options = {}) => {
|
|
296
|
+
return (0, index_core_1.jsonToCsvAsync)(json, {
|
|
297
|
+
delimiter,
|
|
298
|
+
preventCsvInjection,
|
|
299
|
+
rfc4180Compliant,
|
|
300
|
+
...options
|
|
301
|
+
});
|
|
302
|
+
},
|
|
303
|
+
health: () => ({
|
|
304
|
+
service: 'jtcsv-fastify-plugin',
|
|
305
|
+
status: 'healthy',
|
|
306
|
+
version: '1.0.0'
|
|
307
|
+
})
|
|
308
|
+
});
|
|
309
|
+
console.log(`✅ JTCSV Fastify plugin зарегистрирован с префиксом: ${prefix}`);
|
|
310
|
+
}
|
|
311
|
+
exports.default = fp(jtcsvFastifyPlugin, {
|
|
312
|
+
fastify: '4.x',
|
|
313
|
+
name: '@jtcsv/fastify'
|
|
314
|
+
});
|
|
315
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../plugins/fastify-plugin/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Fastify plugin для JTCSV\r\n * Плагин для автоматической конвертации CSV/JSON в Fastify приложениях\r\n * \r\n * @version 1.0.0\r\n * @date 2026-01-23\r\n */\r\n\r\nconst fp = require('fastify-plugin');\r\nimport { csvToJson, csvToJsonAsync, jsonToCsv, jsonToCsvAsync } from '../../index-core';\r\nimport { CsvToJsonOptions, JsonToCsvOptions } from '../../src/types';\r\n\r\n/**\r\n * Опции плагина Fastify для JTCSV\r\n */\r\nexport interface JtcsvFastifyPluginOptions {\r\n /** Префикс для маршрутов API */\r\n prefix?: string;\r\n /** Разделитель CSV по умолчанию */\r\n delimiter?: string;\r\n /** Включить fast-path engine */\r\n enableFastPath?: boolean;\r\n /** Защита от CSV инъекций */\r\n preventCsvInjection?: boolean;\r\n /** Соответствие стандарту RFC 4180 */\r\n rfc4180Compliant?: boolean;\r\n}\r\n\r\n/**\r\n * Статистика обработки\r\n */\r\ninterface ProcessingStats {\r\n rows?: number;\r\n size?: number;\r\n processingTime: number;\r\n inputSize?: number;\r\n outputSize?: number;\r\n conversion?: string;\r\n}\r\n\r\n/**\r\n * Ответ API\r\n */\r\ninterface ApiResponse<T = any> {\r\n success: boolean;\r\n data?: T;\r\n stats?: ProcessingStats;\r\n error?: string;\r\n code?: string;\r\n details?: string;\r\n format?: string;\r\n inputFormat?: string;\r\n}\r\n\r\n/**\r\n * Fastify plugin для JTCSV\r\n * \r\n * @param fastify - Fastify instance\r\n * @param options - Опции плагина\r\n * @param next - Callback\r\n * \r\n * @example\r\n * // Базовое использование\r\n * const fastify = require('fastify')();\r\n * await fastify.register(require('@jtcsv/fastify'), {\r\n * prefix: '/api/convert'\r\n * });\r\n * \r\n * @example\r\n * // С кастомными опциями\r\n * await fastify.register(require('@jtcsv/fastify'), {\r\n * prefix: '/api',\r\n * enableFastPath: true,\r\n * delimiter: ';'\r\n * });\r\n */\r\nasync function jtcsvFastifyPlugin(fastify: any, options: JtcsvFastifyPluginOptions = {}) {\r\n const {\r\n prefix = '/convert',\r\n delimiter = ',',\r\n enableFastPath = true,\r\n preventCsvInjection = true,\r\n rfc4180Compliant = true\r\n } = options;\r\n\r\n // Health check endpoint\r\n fastify.get(`${prefix}/health`, async () => {\r\n return {\r\n service: 'jtcsv-fastify-plugin',\r\n status: 'healthy',\r\n version: '1.0.0',\r\n timestamp: new Date().toISOString(),\r\n features: {\r\n csvToJson: true,\r\n jsonToCsv: true,\r\n fastPathEngine: enableFastPath,\r\n csvInjectionProtection: preventCsvInjection,\r\n streaming: true,\r\n ndjson: true\r\n }\r\n };\r\n });\r\n\r\n // CSV to JSON endpoint\r\n fastify.post(`${prefix}/csv-to-json`, {\r\n schema: {\r\n body: {\r\n type: 'object',\r\n required: ['csv'],\r\n properties: {\r\n csv: { type: 'string' },\r\n delimiter: { type: 'string', default: delimiter },\r\n parseNumbers: { type: 'boolean', default: true },\r\n parseBooleans: { type: 'boolean', default: true },\r\n useFastPath: { type: 'boolean', default: enableFastPath }\r\n }\r\n },\r\n response: {\r\n 200: {\r\n type: 'object',\r\n properties: {\r\n success: { type: 'boolean' },\r\n data: { type: 'array' },\r\n stats: {\r\n type: 'object',\r\n properties: {\r\n rows: { type: 'number' },\r\n processingTime: { type: 'number' }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }, async (request: any, reply: any) => {\r\n const startTime = Date.now();\r\n const {\r\n csv,\r\n delimiter: reqDelimiter = delimiter,\r\n parseNumbers = true,\r\n parseBooleans = true,\r\n useFastPath = enableFastPath\r\n } = request.body;\r\n\r\n try {\r\n const json = await csvToJsonAsync(csv, {\r\n delimiter: reqDelimiter,\r\n parseNumbers,\r\n parseBooleans,\r\n useFastPath,\r\n preventCsvInjection,\r\n rfc4180Compliant\r\n });\r\n\r\n return {\r\n success: true,\r\n data: json,\r\n stats: {\r\n rows: json.length,\r\n processingTime: Date.now() - startTime\r\n }\r\n };\r\n } catch (error: any) {\r\n reply.code(400);\r\n return {\r\n success: false,\r\n error: error.message,\r\n code: 'CSV_CONVERSION_ERROR'\r\n };\r\n }\r\n });\r\n\r\n // JSON to CSV endpoint\r\n fastify.post(`${prefix}/json-to-csv`, {\r\n schema: {\r\n body: {\r\n type: 'object',\r\n required: ['json'],\r\n properties: {\r\n json: { type: 'array' },\r\n delimiter: { type: 'string', default: delimiter },\r\n includeHeaders: { type: 'boolean', default: true }\r\n }\r\n },\r\n response: {\r\n 200: {\r\n type: 'object',\r\n properties: {\r\n success: { type: 'boolean' },\r\n data: { type: 'string' },\r\n stats: {\r\n type: 'object',\r\n properties: {\r\n size: { type: 'number' },\r\n processingTime: { type: 'number' }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }, async (request: any, reply: any) => {\r\n const startTime = Date.now();\r\n const {\r\n json,\r\n delimiter: reqDelimiter = delimiter,\r\n includeHeaders = true\r\n } = request.body;\r\n\r\n try {\r\n const csv = await jsonToCsvAsync(json, {\r\n delimiter: reqDelimiter,\r\n includeHeaders,\r\n preventCsvInjection,\r\n rfc4180Compliant\r\n });\r\n\r\n return {\r\n success: true,\r\n data: csv,\r\n stats: {\r\n size: Buffer.byteLength(csv),\r\n processingTime: Date.now() - startTime\r\n }\r\n };\r\n } catch (error: any) {\r\n reply.code(400);\r\n return {\r\n success: false,\r\n error: error.message,\r\n code: 'JSON_CONVERSION_ERROR'\r\n };\r\n }\r\n });\r\n\r\n // Универсальный endpoint для автоматической конвертации\r\n fastify.post(`${prefix}/auto`, {\r\n schema: {\r\n body: {\r\n oneOf: [\r\n { type: 'string' }, // CSV data\r\n { type: 'array' }, // JSON array\r\n { type: 'object' } // JSON object\r\n ]\r\n },\r\n headers: {\r\n type: 'object',\r\n properties: {\r\n 'content-type': { \r\n type: 'string',\r\n enum: ['application/json', 'text/csv', 'text/plain']\r\n },\r\n 'accept': { \r\n type: 'string',\r\n enum: ['application/json', 'text/csv']\r\n }\r\n }\r\n },\r\n querystring: {\r\n type: 'object',\r\n properties: {\r\n format: { type: 'string', enum: ['json', 'csv'] },\r\n delimiter: { type: 'string' }\r\n }\r\n }\r\n }\r\n }, async (request: any, reply: any) => {\r\n const startTime = Date.now();\r\n const contentType = request.headers['content-type'] || '';\r\n const acceptHeader = request.headers['accept'] || 'application/json';\r\n const { format, delimiter: queryDelimiter } = request.query;\r\n \r\n const reqDelimiter = queryDelimiter || delimiter;\r\n \r\n try {\r\n let inputFormat = 'unknown';\r\n const outputFormat = format || (acceptHeader.includes('text/csv') ? 'csv' : 'json');\r\n \r\n // Определяем формат входных данных\r\n if (contentType.includes('application/json') || Array.isArray(request.body)) {\r\n inputFormat = 'json';\r\n } else if (contentType.includes('text/csv') || \r\n contentType.includes('text/plain') ||\r\n (typeof request.body === 'string' && request.body.includes(','))) {\r\n inputFormat = 'csv';\r\n }\r\n\r\n if (inputFormat === 'unknown') {\r\n reply.code(400);\r\n return {\r\n success: false,\r\n error: 'Unable to determine input format',\r\n code: 'UNKNOWN_FORMAT'\r\n };\r\n }\r\n\r\n let result: any;\r\n const stats: ProcessingStats = {\r\n inputSize: 0,\r\n outputSize: 0,\r\n processingTime: 0,\r\n conversion: `${inputFormat}→${outputFormat}`\r\n };\r\n\r\n const conversionOptions = {\r\n delimiter: reqDelimiter,\r\n useFastPath: enableFastPath,\r\n preventCsvInjection,\r\n rfc4180Compliant\r\n };\r\n\r\n if (inputFormat === 'json' && outputFormat === 'csv') {\r\n const jsonData = Array.isArray(request.body) ? request.body : [request.body];\r\n stats.inputSize = Buffer.byteLength(JSON.stringify(jsonData));\r\n \r\n result = await jsonToCsvAsync(jsonData, {\r\n ...conversionOptions,\r\n includeHeaders: true\r\n });\r\n stats.outputSize = Buffer.byteLength(result);\r\n \r\n reply.header('Content-Type', 'text/csv; charset=utf-8');\r\n \r\n } else if (inputFormat === 'csv' && outputFormat === 'json') {\r\n const csvData = typeof request.body === 'string' ? request.body : String(request.body);\r\n stats.inputSize = Buffer.byteLength(csvData);\r\n \r\n result = await csvToJsonAsync(csvData, {\r\n ...conversionOptions,\r\n parseNumbers: true,\r\n parseBooleans: true\r\n });\r\n stats.outputSize = Buffer.byteLength(JSON.stringify(result));\r\n \r\n reply.header('Content-Type', 'application/json; charset=utf-8');\r\n \r\n } else {\r\n // Нет необходимости в конвертации\r\n result = request.body;\r\n stats.conversion = 'none';\r\n stats.inputSize = Buffer.byteLength(JSON.stringify(result));\r\n stats.outputSize = stats.inputSize;\r\n }\r\n\r\n stats.processingTime = Date.now() - startTime;\r\n\r\n return {\r\n success: true,\r\n data: result,\r\n format: outputFormat,\r\n inputFormat,\r\n stats\r\n };\r\n\r\n } catch (error: any) {\r\n reply.code(400);\r\n return {\r\n success: false,\r\n error: error.message,\r\n code: 'CONVERSION_ERROR',\r\n details: (process.env as any)['NODE_ENV'] === 'development' ? error.stack : undefined\r\n };\r\n }\r\n });\r\n\r\n // Streaming endpoint для больших файлов\r\n fastify.post(`${prefix}/stream`, {\r\n schema: {\r\n body: {\r\n type: 'object',\r\n required: ['direction'],\r\n properties: {\r\n direction: { \r\n type: 'string', \r\n enum: ['csv-to-json', 'json-to-csv'] \r\n },\r\n delimiter: { type: 'string', default: delimiter }\r\n }\r\n }\r\n }\r\n }, async (request: any, reply: any) => {\r\n const { direction, delimiter: reqDelimiter = delimiter } = request.body;\r\n \r\n if (direction === 'csv-to-json') {\r\n reply.header('Content-Type', 'application/x-ndjson');\r\n reply.header('Transfer-Encoding', 'chunked');\r\n \r\n // Здесь будет реализация streaming\r\n // Пока возвращаем заглушку\r\n reply.send(JSON.stringify({\r\n success: false,\r\n error: 'Streaming endpoint not implemented yet',\r\n code: 'NOT_IMPLEMENTED'\r\n }));\r\n \r\n } else if (direction === 'json-to-csv') {\r\n reply.header('Content-Type', 'text/csv');\r\n reply.header('Transfer-Encoding', 'chunked');\r\n \r\n // Здесь будет реализация streaming\r\n reply.send('Streaming endpoint not implemented yet\\n');\r\n }\r\n });\r\n\r\n // Декоратор для прямого доступа к функциям конвертации\r\n fastify.decorate('jtcsv', {\r\n csvToJson: async (csv: string, options: Partial<CsvToJsonOptions> = {}) => {\r\n return csvToJsonAsync(csv, {\r\n delimiter,\r\n useFastPath: enableFastPath,\r\n preventCsvInjection,\r\n rfc4180Compliant,\r\n ...options\r\n });\r\n },\r\n \r\n jsonToCsv: async (json: any[], options: Partial<JsonToCsvOptions> = {}) => {\r\n return jsonToCsvAsync(json, {\r\n delimiter,\r\n preventCsvInjection,\r\n rfc4180Compliant,\r\n ...options\r\n });\r\n },\r\n \r\n health: () => ({\r\n service: 'jtcsv-fastify-plugin',\r\n status: 'healthy',\r\n version: '1.0.0'\r\n })\r\n });\r\n\r\n console.log(`✅ JTCSV Fastify plugin зарегистрирован с префиксом: ${prefix}`);\r\n}\r\n\r\n// Экспортируем как Fastify plugin\r\nexport default fp(jtcsvFastifyPlugin, {\r\n fastify: '4.x',\r\n name: '@jtcsv/fastify'\r\n});\r\n\r\n// Экспортируем также как обычную функцию\r\nexport { jtcsvFastifyPlugin };"]}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.csvMiddleware = csvMiddleware;
|
|
4
|
+
exports.asyncCsvMiddleware = asyncCsvMiddleware;
|
|
5
|
+
exports.createCsvResponse = createCsvResponse;
|
|
6
|
+
exports.createAsyncCsvResponse = createAsyncCsvResponse;
|
|
7
|
+
exports.csvResponse = csvResponse;
|
|
8
|
+
exports.asyncCsvResponse = asyncCsvResponse;
|
|
9
|
+
exports.csvParseEndpoint = csvParseEndpoint;
|
|
10
|
+
exports.csvDownloadEndpoint = csvDownloadEndpoint;
|
|
11
|
+
const index_core_1 = require("../../index-core");
|
|
12
|
+
function normalizeFilename(filename) {
|
|
13
|
+
if (!filename || typeof filename !== 'string') {
|
|
14
|
+
return 'export.csv';
|
|
15
|
+
}
|
|
16
|
+
return filename.includes('.') ? filename : `${filename}.csv`;
|
|
17
|
+
}
|
|
18
|
+
function csvMiddleware(options = {}) {
|
|
19
|
+
return async (c, next) => {
|
|
20
|
+
try {
|
|
21
|
+
const csvText = await c.req.text();
|
|
22
|
+
const rows = await (0, index_core_1.csvToJson)(csvText, options);
|
|
23
|
+
c.set('csv', rows);
|
|
24
|
+
await next();
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function asyncCsvMiddleware(options = {}) {
|
|
32
|
+
return async (c, next) => {
|
|
33
|
+
try {
|
|
34
|
+
const csvText = await c.req.text();
|
|
35
|
+
const rows = await (0, index_core_1.csvToJson)(csvText, options);
|
|
36
|
+
c.set('csv', rows);
|
|
37
|
+
await next();
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function createCsvResponse(data, filename = 'export.csv', options = {}) {
|
|
45
|
+
const safeName = normalizeFilename(filename);
|
|
46
|
+
const rows = Array.isArray(data) ? data : [data];
|
|
47
|
+
const csv = (0, index_core_1.jsonToCsv)(rows, options);
|
|
48
|
+
return {
|
|
49
|
+
csv,
|
|
50
|
+
headers: {
|
|
51
|
+
'Content-Type': 'text/csv; charset=utf-8',
|
|
52
|
+
'Content-Disposition': `attachment; filename="${safeName}"`
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async function createAsyncCsvResponse(data, filename = 'export.csv', options = {}) {
|
|
57
|
+
const safeName = normalizeFilename(filename);
|
|
58
|
+
const rows = Array.isArray(data) ? data : [data];
|
|
59
|
+
const csv = await (0, index_core_1.jsonToCsv)(rows, options);
|
|
60
|
+
return {
|
|
61
|
+
csv,
|
|
62
|
+
headers: {
|
|
63
|
+
'Content-Type': 'text/csv; charset=utf-8',
|
|
64
|
+
'Content-Disposition': `attachment; filename="${safeName}"`
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function csvResponse(data, filename = 'export.csv', options = {}) {
|
|
69
|
+
const { csv, headers } = createCsvResponse(data, filename, options);
|
|
70
|
+
return new Response(csv, { headers });
|
|
71
|
+
}
|
|
72
|
+
async function asyncCsvResponse(data, filename = 'export.csv', options = {}) {
|
|
73
|
+
const { csv, headers } = await createAsyncCsvResponse(data, filename, options);
|
|
74
|
+
return new Response(csv, { headers });
|
|
75
|
+
}
|
|
76
|
+
function csvParseEndpoint(options = {}) {
|
|
77
|
+
return async (c) => {
|
|
78
|
+
try {
|
|
79
|
+
const csvText = await c.req.text();
|
|
80
|
+
const rows = await (0, index_core_1.csvToJson)(csvText, options);
|
|
81
|
+
return new Response(JSON.stringify(rows), {
|
|
82
|
+
headers: { 'Content-Type': 'application/json' }
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
return new Response(JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error' }), { status: 400, headers: { 'Content-Type': 'application/json' } });
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function csvDownloadEndpoint(dataProvider, filename = 'export.csv', options = {}) {
|
|
91
|
+
return async (c) => {
|
|
92
|
+
try {
|
|
93
|
+
const data = await (typeof dataProvider === 'function' ? dataProvider() : dataProvider);
|
|
94
|
+
return asyncCsvResponse(data, filename, options);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
return new Response(JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error' }), { status: 500, headers: { 'Content-Type': 'application/json' } });
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
exports.default = {
|
|
102
|
+
csvMiddleware,
|
|
103
|
+
asyncCsvMiddleware,
|
|
104
|
+
createCsvResponse,
|
|
105
|
+
createAsyncCsvResponse,
|
|
106
|
+
csvResponse,
|
|
107
|
+
asyncCsvResponse,
|
|
108
|
+
csvParseEndpoint,
|
|
109
|
+
csvDownloadEndpoint,
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../plugins/hono/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Hono plugin for jtcsv\r\n * Provides middleware and response helpers for CSV processing in Hono applications\r\n * @module plugins/hono\r\n */\r\n\r\nimport { csvToJson, jsonToCsv } from '../../index-core';\r\nimport type { CsvToJsonOptions, JsonToCsvOptions } from '../../src/types';\r\n\r\n/**\r\n * Hono context type (simplified)\r\n */\r\ninterface HonoContext {\r\n req: {\r\n text(): Promise<string>;\r\n };\r\n set(key: string, value: any): void;\r\n}\r\n\r\n/**\r\n * Options for CSV middleware\r\n */\r\nexport interface CsvMiddlewareOptions extends CsvToJsonOptions {\r\n // Additional options specific to CSV middleware\r\n}\r\n\r\n/**\r\n * Options for CSV response\r\n */\r\nexport interface CsvResponseOptions extends JsonToCsvOptions {\r\n // Additional options specific to CSV response\r\n}\r\n\r\n/**\r\n * Normalize filename for CSV download\r\n */\r\nfunction normalizeFilename(filename?: string): string {\r\n if (!filename || typeof filename !== 'string') {\r\n return 'export.csv';\r\n }\r\n return filename.includes('.') ? filename : `${filename}.csv`;\r\n}\r\n\r\n/**\r\n * CSV middleware for Hono\r\n * Parses incoming CSV request bodies and attaches parsed data to context\r\n * \r\n * @example\r\n * app.post('/upload', csvMiddleware(), async (c) => {\r\n * const data = c.get('csv');\r\n * return c.json({ success: true, data });\r\n * });\r\n */\r\nexport function csvMiddleware(options: CsvMiddlewareOptions = {}): any {\r\n return async (c: HonoContext, next: () => Promise<void>) => {\r\n try {\r\n const csvText = await c.req.text();\r\n const rows = await csvToJson(csvText, options);\r\n c.set('csv', rows);\r\n await next();\r\n } catch (error) {\r\n // Re-throw error for Hono error handling\r\n throw error;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Async CSV middleware for Hono\r\n * Uses async/await for better performance with large files\r\n */\r\nexport function asyncCsvMiddleware(options: CsvMiddlewareOptions = {}): any {\r\n return async (c: HonoContext, next: () => Promise<void>) => {\r\n try {\r\n const csvText = await c.req.text();\r\n const rows = await csvToJson(csvText, options);\r\n c.set('csv', rows);\r\n await next();\r\n } catch (error) {\r\n throw error;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Creates a CSV response for Hono\r\n * Converts data to CSV and returns appropriate headers\r\n * \r\n * @example\r\n * app.get('/export', async (c) => {\r\n * const data = await getData();\r\n * const response = createCsvResponse(data, 'export.csv');\r\n * return new Response(response.csv, { headers: response.headers });\r\n * });\r\n */\r\nexport function createCsvResponse(\r\n data: any,\r\n filename: string = 'export.csv',\r\n options: CsvResponseOptions = {}\r\n): { csv: string; headers: Record<string, string> } {\r\n const safeName = normalizeFilename(filename);\r\n const rows = Array.isArray(data) ? data : [data];\r\n const csv = jsonToCsv(rows, options);\r\n\r\n return {\r\n csv,\r\n headers: {\r\n 'Content-Type': 'text/csv; charset=utf-8',\r\n 'Content-Disposition': `attachment; filename=\"${safeName}\"`\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Async version of createCsvResponse\r\n * Uses async/await for better performance with large files\r\n */\r\nexport async function createAsyncCsvResponse(\r\n data: any,\r\n filename: string = 'export.csv',\r\n options: CsvResponseOptions = {}\r\n): Promise<{ csv: string; headers: Record<string, string> }> {\r\n const safeName = normalizeFilename(filename);\r\n const rows = Array.isArray(data) ? data : [data];\r\n const csv = await jsonToCsv(rows, options);\r\n\r\n return {\r\n csv,\r\n headers: {\r\n 'Content-Type': 'text/csv; charset=utf-8',\r\n 'Content-Disposition': `attachment; filename=\"${safeName}\"`\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * CSV response helper for Hono\r\n * Returns a Response object with CSV data\r\n * \r\n * @example\r\n * app.get('/export', async (c) => {\r\n * const data = await getData();\r\n * return csvResponse(c, data, 'export.csv');\r\n * });\r\n */\r\nexport function csvResponse(\r\n data: any,\r\n filename: string = 'export.csv',\r\n options: CsvResponseOptions = {}\r\n): Response {\r\n const { csv, headers } = createCsvResponse(data, filename, options);\r\n return new Response(csv, { headers });\r\n}\r\n\r\n/**\r\n * Async CSV response helper for Hono\r\n * Returns a Response object with CSV data using async processing\r\n */\r\nexport async function asyncCsvResponse(\r\n data: any,\r\n filename: string = 'export.csv',\r\n options: CsvResponseOptions = {}\r\n): Promise<Response> {\r\n const { csv, headers } = await createAsyncCsvResponse(data, filename, options);\r\n return new Response(csv, { headers });\r\n}\r\n\r\n/**\r\n * CSV parsing endpoint helper\r\n * Creates a route handler that parses CSV and returns JSON\r\n * \r\n * @example\r\n * app.post('/parse', csvParseEndpoint());\r\n */\r\nexport function csvParseEndpoint(options: CsvMiddlewareOptions = {}): any {\r\n return async (c: HonoContext) => {\r\n try {\r\n const csvText = await c.req.text();\r\n const rows = await csvToJson(csvText, options);\r\n return new Response(JSON.stringify(rows), {\r\n headers: { 'Content-Type': 'application/json' }\r\n });\r\n } catch (error) {\r\n return new Response(\r\n JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error' }),\r\n { status: 400, headers: { 'Content-Type': 'application/json' } }\r\n );\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * CSV download endpoint helper\r\n * Creates a route handler that returns CSV data\r\n * \r\n * @example\r\n * app.get('/download', csvDownloadEndpoint(async () => await getData()));\r\n */\r\nexport function csvDownloadEndpoint(\r\n dataProvider: () => Promise<any> | any,\r\n filename: string = 'export.csv',\r\n options: CsvResponseOptions = {}\r\n): any {\r\n return async (c: HonoContext) => {\r\n try {\r\n const data = await (typeof dataProvider === 'function' ? dataProvider() : dataProvider);\r\n return asyncCsvResponse(data, filename, options);\r\n } catch (error) {\r\n return new Response(\r\n JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error' }),\r\n { status: 500, headers: { 'Content-Type': 'application/json' } }\r\n );\r\n }\r\n };\r\n}\r\n\r\nexport default {\r\n csvMiddleware,\r\n asyncCsvMiddleware,\r\n createCsvResponse,\r\n createAsyncCsvResponse,\r\n csvResponse,\r\n asyncCsvResponse,\r\n csvParseEndpoint,\r\n csvDownloadEndpoint,\r\n};"]}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createCsvParserInterceptor = createCsvParserInterceptor;
|
|
4
|
+
exports.createCsvDownloadInterceptor = createCsvDownloadInterceptor;
|
|
5
|
+
exports.CsvParserInterceptor = CsvParserInterceptor;
|
|
6
|
+
exports.CsvDownloadDecorator = CsvDownloadDecorator;
|
|
7
|
+
exports.createAsyncCsvParserInterceptor = createAsyncCsvParserInterceptor;
|
|
8
|
+
exports.createAsyncCsvDownloadInterceptor = createAsyncCsvDownloadInterceptor;
|
|
9
|
+
exports.AsyncCsvParserInterceptor = AsyncCsvParserInterceptor;
|
|
10
|
+
exports.AsyncCsvDownloadDecorator = AsyncCsvDownloadDecorator;
|
|
11
|
+
const index_core_1 = require("../../index-core");
|
|
12
|
+
function normalizeFilename(filename) {
|
|
13
|
+
if (!filename || typeof filename !== 'string') {
|
|
14
|
+
return 'export.csv';
|
|
15
|
+
}
|
|
16
|
+
return filename.includes('.') ? filename : `${filename}.csv`;
|
|
17
|
+
}
|
|
18
|
+
function createCsvParserInterceptor(options = {}) {
|
|
19
|
+
class CsvParserInterceptorImpl {
|
|
20
|
+
async intercept(context, next) {
|
|
21
|
+
const req = context.switchToHttp().getRequest();
|
|
22
|
+
const body = req && req.body;
|
|
23
|
+
if (typeof body === 'string' || Buffer.isBuffer(body)) {
|
|
24
|
+
const csv = Buffer.isBuffer(body) ? body.toString('utf8') : body;
|
|
25
|
+
req.body = await (0, index_core_1.csvToJson)(csv, options);
|
|
26
|
+
}
|
|
27
|
+
return next.handle();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return CsvParserInterceptorImpl;
|
|
31
|
+
}
|
|
32
|
+
function createCsvDownloadInterceptor(options = {}) {
|
|
33
|
+
class CsvDownloadInterceptorImpl {
|
|
34
|
+
intercept(context, next) {
|
|
35
|
+
const res = context.switchToHttp().getResponse();
|
|
36
|
+
const filename = normalizeFilename(options.filename);
|
|
37
|
+
const csvOptions = { ...options };
|
|
38
|
+
delete csvOptions.filename;
|
|
39
|
+
return next.handle().pipe((async (data) => {
|
|
40
|
+
const rows = Array.isArray(data) ? data : [data];
|
|
41
|
+
const csv = await (0, index_core_1.jsonToCsv)(rows, csvOptions);
|
|
42
|
+
if (res && typeof res.setHeader === 'function') {
|
|
43
|
+
res.setHeader('Content-Type', 'text/csv; charset=utf-8');
|
|
44
|
+
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
|
|
45
|
+
}
|
|
46
|
+
return csv;
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return CsvDownloadInterceptorImpl;
|
|
51
|
+
}
|
|
52
|
+
function CsvParserInterceptor(options = {}) {
|
|
53
|
+
const Interceptor = createCsvParserInterceptor(options);
|
|
54
|
+
return Interceptor;
|
|
55
|
+
}
|
|
56
|
+
function CsvDownloadDecorator(options = {}) {
|
|
57
|
+
const Interceptor = createCsvDownloadInterceptor(options);
|
|
58
|
+
return Interceptor;
|
|
59
|
+
}
|
|
60
|
+
function createAsyncCsvParserInterceptor(options = {}) {
|
|
61
|
+
class AsyncCsvParserInterceptorImpl {
|
|
62
|
+
async intercept(context, next) {
|
|
63
|
+
const req = context.switchToHttp().getRequest();
|
|
64
|
+
const body = req && req.body;
|
|
65
|
+
if (typeof body === 'string' || Buffer.isBuffer(body)) {
|
|
66
|
+
const csv = Buffer.isBuffer(body) ? body.toString('utf8') : body;
|
|
67
|
+
req.body = await (0, index_core_1.csvToJson)(csv, options);
|
|
68
|
+
}
|
|
69
|
+
return next.handle();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return AsyncCsvParserInterceptorImpl;
|
|
73
|
+
}
|
|
74
|
+
function createAsyncCsvDownloadInterceptor(options = {}) {
|
|
75
|
+
class AsyncCsvDownloadInterceptorImpl {
|
|
76
|
+
async intercept(context, next) {
|
|
77
|
+
const res = context.switchToHttp().getResponse();
|
|
78
|
+
const filename = normalizeFilename(options.filename);
|
|
79
|
+
const csvOptions = { ...options };
|
|
80
|
+
delete csvOptions.filename;
|
|
81
|
+
return next.handle().pipe((async (data) => {
|
|
82
|
+
const rows = Array.isArray(data) ? data : [data];
|
|
83
|
+
const csv = await (0, index_core_1.jsonToCsv)(rows, csvOptions);
|
|
84
|
+
if (res && typeof res.setHeader === 'function') {
|
|
85
|
+
res.setHeader('Content-Type', 'text/csv; charset=utf-8');
|
|
86
|
+
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
|
|
87
|
+
}
|
|
88
|
+
return csv;
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return AsyncCsvDownloadInterceptorImpl;
|
|
93
|
+
}
|
|
94
|
+
function AsyncCsvParserInterceptor(options = {}) {
|
|
95
|
+
const Interceptor = createAsyncCsvParserInterceptor(options);
|
|
96
|
+
return Interceptor;
|
|
97
|
+
}
|
|
98
|
+
function AsyncCsvDownloadDecorator(options = {}) {
|
|
99
|
+
const Interceptor = createAsyncCsvDownloadInterceptor(options);
|
|
100
|
+
return Interceptor;
|
|
101
|
+
}
|
|
102
|
+
exports.default = {
|
|
103
|
+
CsvParserInterceptor,
|
|
104
|
+
CsvDownloadDecorator,
|
|
105
|
+
createCsvParserInterceptor,
|
|
106
|
+
createCsvDownloadInterceptor,
|
|
107
|
+
AsyncCsvParserInterceptor,
|
|
108
|
+
AsyncCsvDownloadDecorator,
|
|
109
|
+
createAsyncCsvParserInterceptor,
|
|
110
|
+
createAsyncCsvDownloadInterceptor,
|
|
111
|
+
};
|
|
112
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../plugins/nestjs/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * NestJS plugin for jtcsv\r\n * Provides interceptors and decorators for CSV parsing and downloading in NestJS applications\r\n * @module plugins/nestjs\r\n */\r\n\r\n// Note: NestJS and RxJS types are optional - users need to install @nestjs/common and rxjs\r\n// We use conditional imports to avoid breaking the build\r\ntype Injectable = any;\r\ntype UseInterceptors = any;\r\ntype ExecutionContext = any;\r\ntype CallHandler = any;\r\ntype NestInterceptor = any;\r\ntype Observable<T> = any;\r\n\r\nimport { csvToJson, jsonToCsv } from '../../index-core';\r\nimport type { CsvToJsonOptions, JsonToCsvOptions } from '../../src/types';\r\n\r\n/**\r\n * Options for CSV parser interceptor\r\n */\r\nexport interface CsvParserOptions extends CsvToJsonOptions {\r\n // Additional options specific to CSV parsing\r\n}\r\n\r\n/**\r\n * Options for CSV download interceptor\r\n */\r\nexport interface CsvDownloadOptions extends JsonToCsvOptions {\r\n /** Filename for the downloaded CSV file */\r\n filename?: string;\r\n}\r\n\r\n/**\r\n * Normalize filename for CSV download\r\n */\r\nfunction normalizeFilename(filename?: string): string {\r\n if (!filename || typeof filename !== 'string') {\r\n return 'export.csv';\r\n }\r\n return filename.includes('.') ? filename : `${filename}.csv`;\r\n}\r\n\r\n/**\r\n * Creates a CSV parser interceptor for NestJS\r\n * Parses incoming CSV request bodies into JSON\r\n */\r\nexport function createCsvParserInterceptor(options: CsvParserOptions = {}): any {\r\n class CsvParserInterceptorImpl {\r\n async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> {\r\n const req = context.switchToHttp().getRequest();\r\n const body = req && req.body;\r\n\r\n if (typeof body === 'string' || Buffer.isBuffer(body)) {\r\n const csv = Buffer.isBuffer(body) ? body.toString('utf8') : body;\r\n req.body = await csvToJson(csv, options);\r\n }\r\n\r\n return next.handle();\r\n }\r\n }\r\n\r\n return CsvParserInterceptorImpl;\r\n}\r\n\r\n/**\r\n * Creates a CSV download interceptor for NestJS\r\n * Converts JSON responses to CSV and sets appropriate headers\r\n */\r\nexport function createCsvDownloadInterceptor(options: CsvDownloadOptions = {}): any {\r\n class CsvDownloadInterceptorImpl {\r\n intercept(context: ExecutionContext, next: CallHandler): Observable<any> {\r\n const res = context.switchToHttp().getResponse();\r\n const filename = normalizeFilename(options.filename);\r\n const csvOptions = { ...options } as JsonToCsvOptions;\r\n delete (csvOptions as any).filename;\r\n\r\n return next.handle().pipe(\r\n (async (data: any) => {\r\n const rows = Array.isArray(data) ? data : [data];\r\n const csv = await jsonToCsv(rows, csvOptions);\r\n\r\n if (res && typeof res.setHeader === 'function') {\r\n res.setHeader('Content-Type', 'text/csv; charset=utf-8');\r\n res.setHeader(\r\n 'Content-Disposition',\r\n `attachment; filename=\"${filename}\"`\r\n );\r\n }\r\n\r\n return csv;\r\n }) as any\r\n );\r\n }\r\n }\r\n\r\n return CsvDownloadInterceptorImpl;\r\n}\r\n\r\n/**\r\n * Decorator for CSV parsing interceptor\r\n * Usage: @CsvParserInterceptor({ delimiter: ',' })\r\n */\r\nexport function CsvParserInterceptor(options: CsvParserOptions = {}): any {\r\n const Interceptor = createCsvParserInterceptor(options);\r\n return Interceptor;\r\n}\r\n\r\n/**\r\n * Decorator for CSV download interceptor\r\n * Usage: @CsvDownloadDecorator({ filename: 'data.csv' })\r\n */\r\nexport function CsvDownloadDecorator(options: CsvDownloadOptions = {}): any {\r\n const Interceptor = createCsvDownloadInterceptor(options);\r\n return Interceptor;\r\n}\r\n\r\n/**\r\n * Async version of CSV parser interceptor\r\n * Uses async/await for better performance with large files\r\n */\r\nexport function createAsyncCsvParserInterceptor(options: CsvParserOptions = {}): any {\r\n class AsyncCsvParserInterceptorImpl {\r\n async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> {\r\n const req = context.switchToHttp().getRequest();\r\n const body = req && req.body;\r\n\r\n if (typeof body === 'string' || Buffer.isBuffer(body)) {\r\n const csv = Buffer.isBuffer(body) ? body.toString('utf8') : body;\r\n req.body = await csvToJson(csv, options);\r\n }\r\n\r\n return next.handle();\r\n }\r\n }\r\n\r\n return AsyncCsvParserInterceptorImpl;\r\n}\r\n\r\n/**\r\n * Async version of CSV download interceptor\r\n * Uses async/await for better performance with large files\r\n */\r\nexport function createAsyncCsvDownloadInterceptor(options: CsvDownloadOptions = {}): any {\r\n class AsyncCsvDownloadInterceptorImpl {\r\n async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> {\r\n const res = context.switchToHttp().getResponse();\r\n const filename = normalizeFilename(options.filename);\r\n const csvOptions = { ...options } as JsonToCsvOptions;\r\n delete (csvOptions as any).filename;\r\n\r\n return next.handle().pipe(\r\n (async (data: any) => {\r\n const rows = Array.isArray(data) ? data : [data];\r\n const csv = await jsonToCsv(rows, csvOptions);\r\n\r\n if (res && typeof res.setHeader === 'function') {\r\n res.setHeader('Content-Type', 'text/csv; charset=utf-8');\r\n res.setHeader(\r\n 'Content-Disposition',\r\n `attachment; filename=\"${filename}\"`\r\n );\r\n }\r\n\r\n return csv;\r\n }) as any\r\n );\r\n }\r\n }\r\n\r\n return AsyncCsvDownloadInterceptorImpl;\r\n}\r\n\r\n/**\r\n * Async decorator for CSV parsing interceptor\r\n * Usage: @AsyncCsvParserInterceptor({ delimiter: ',' })\r\n */\r\nexport function AsyncCsvParserInterceptor(options: CsvParserOptions = {}): any {\r\n const Interceptor = createAsyncCsvParserInterceptor(options);\r\n return Interceptor;\r\n}\r\n\r\n/**\r\n * Async decorator for CSV download interceptor\r\n * Usage: @AsyncCsvDownloadDecorator({ filename: 'data.csv' })\r\n */\r\nexport function AsyncCsvDownloadDecorator(options: CsvDownloadOptions = {}): any {\r\n const Interceptor = createAsyncCsvDownloadInterceptor(options);\r\n return Interceptor;\r\n}\r\n\r\nexport default {\r\n CsvParserInterceptor,\r\n CsvDownloadDecorator,\r\n createCsvParserInterceptor,\r\n createCsvDownloadInterceptor,\r\n AsyncCsvParserInterceptor,\r\n AsyncCsvDownloadDecorator,\r\n createAsyncCsvParserInterceptor,\r\n createAsyncCsvDownloadInterceptor,\r\n};"]}
|