jtcsv 2.1.0 → 2.1.3
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 +63 -17
- package/bin/jtcsv.js +1013 -117
- package/csv-to-json.js +385 -311
- package/examples/simple-usage.js +2 -3
- package/index.d.ts +288 -5
- package/index.js +23 -0
- package/json-to-csv.js +130 -89
- package/package.json +47 -19
- package/plugins/README.md +146 -2
- package/plugins/hono/README.md +25 -0
- package/plugins/hono/index.d.ts +12 -0
- package/plugins/hono/index.js +36 -0
- package/plugins/hono/package.json +35 -0
- package/plugins/nestjs/README.md +33 -0
- package/plugins/nestjs/index.d.ts +25 -0
- package/plugins/nestjs/index.js +77 -0
- package/plugins/nestjs/package.json +37 -0
- package/plugins/nuxt/README.md +25 -0
- package/plugins/nuxt/index.js +21 -0
- package/plugins/nuxt/package.json +35 -0
- package/plugins/nuxt/runtime/composables/useJtcsv.js +6 -0
- package/plugins/nuxt/runtime/plugin.js +6 -0
- package/plugins/remix/README.md +26 -0
- package/plugins/remix/index.d.ts +16 -0
- package/plugins/remix/index.js +62 -0
- package/plugins/remix/package.json +35 -0
- package/plugins/sveltekit/README.md +28 -0
- package/plugins/sveltekit/index.d.ts +17 -0
- package/plugins/sveltekit/index.js +54 -0
- package/plugins/sveltekit/package.json +33 -0
- package/plugins/trpc/README.md +22 -0
- package/plugins/trpc/index.d.ts +7 -0
- package/plugins/trpc/index.js +32 -0
- package/plugins/trpc/package.json +34 -0
- package/src/core/delimiter-cache.js +186 -0
- package/src/core/transform-hooks.js +350 -0
- package/src/engines/fast-path-engine.js +829 -340
- package/src/formats/tsv-parser.js +336 -0
- package/src/index-with-plugins.js +36 -14
- package/cli-tui.js +0 -5
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jtcsv",
|
|
3
|
-
"version": "2.1.
|
|
4
|
-
"description": "Complete JSON
|
|
3
|
+
"version": "2.1.3",
|
|
4
|
+
"description": "Complete JSON<->CSV and CSV<->JSON converter for Node.js and Browser with streaming, security, Web Workers, TypeScript support, and optional ecosystem (zero-deps core)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"browser": "dist/jtcsv.umd.js",
|
|
7
7
|
"module": "dist/jtcsv.esm.js",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"bin": {
|
|
10
10
|
"jtcsv": "bin/jtcsv.js"
|
|
11
11
|
},
|
|
12
|
-
|
|
12
|
+
"exports": {
|
|
13
13
|
".": {
|
|
14
14
|
"require": "./index.js",
|
|
15
15
|
"import": "./dist/jtcsv.esm.js",
|
|
@@ -46,6 +46,36 @@
|
|
|
46
46
|
"require": "./plugins/nextjs-api/route.js",
|
|
47
47
|
"import": "./plugins/nextjs-api/route.js",
|
|
48
48
|
"default": "./plugins/nextjs-api/route.js"
|
|
49
|
+
},
|
|
50
|
+
"./nestjs": {
|
|
51
|
+
"require": "./plugins/nestjs/index.js",
|
|
52
|
+
"import": "./plugins/nestjs/index.js",
|
|
53
|
+
"default": "./plugins/nestjs/index.js"
|
|
54
|
+
},
|
|
55
|
+
"./remix": {
|
|
56
|
+
"require": "./plugins/remix/index.js",
|
|
57
|
+
"import": "./plugins/remix/index.js",
|
|
58
|
+
"default": "./plugins/remix/index.js"
|
|
59
|
+
},
|
|
60
|
+
"./nuxt": {
|
|
61
|
+
"require": "./plugins/nuxt/index.js",
|
|
62
|
+
"import": "./plugins/nuxt/index.js",
|
|
63
|
+
"default": "./plugins/nuxt/index.js"
|
|
64
|
+
},
|
|
65
|
+
"./sveltekit": {
|
|
66
|
+
"require": "./plugins/sveltekit/index.js",
|
|
67
|
+
"import": "./plugins/sveltekit/index.js",
|
|
68
|
+
"default": "./plugins/sveltekit/index.js"
|
|
69
|
+
},
|
|
70
|
+
"./hono": {
|
|
71
|
+
"require": "./plugins/hono/index.js",
|
|
72
|
+
"import": "./plugins/hono/index.js",
|
|
73
|
+
"default": "./plugins/hono/index.js"
|
|
74
|
+
},
|
|
75
|
+
"./trpc": {
|
|
76
|
+
"require": "./plugins/trpc/index.js",
|
|
77
|
+
"import": "./plugins/trpc/index.js",
|
|
78
|
+
"default": "./plugins/trpc/index.js"
|
|
49
79
|
}
|
|
50
80
|
},
|
|
51
81
|
"scripts": {
|
|
@@ -56,7 +86,7 @@
|
|
|
56
86
|
"test:plugins": "jest __tests__/plugin-system.test.js",
|
|
57
87
|
"test:fastpath": "jest __tests__/fast-path-engine.test.js",
|
|
58
88
|
"test:ndjson": "jest __tests__/ndjson-parser.test.js",
|
|
59
|
-
|
|
89
|
+
"test:performance": "jest __tests__/*.test.js --testNamePattern=\"Производительность|производительность\"",
|
|
60
90
|
"test:express": "cd plugins/express-middleware && npm test",
|
|
61
91
|
"test:fastify": "cd plugins/fastify-plugin && npm test",
|
|
62
92
|
"test:nextjs": "cd plugins/nextjs-api && npm test",
|
|
@@ -65,7 +95,7 @@
|
|
|
65
95
|
"lint:plugins": "eslint plugins/",
|
|
66
96
|
"security-check": "npm audit",
|
|
67
97
|
"prepublishOnly": "npm test && npm run build && eslint index.js json-to-csv.js csv-to-json.js errors.js stream-json-to-csv.js stream-csv-to-json.js json-save.js src/browser src/engines src/formats src/core",
|
|
68
|
-
"tui": "node
|
|
98
|
+
"tui": "node packages/jtcsv-tui/bin/jtcsv-tui.js",
|
|
69
99
|
"cli": "node bin/jtcsv.js",
|
|
70
100
|
"build": "rollup -c rollup.config.mjs",
|
|
71
101
|
"build:watch": "rollup -c rollup.config.mjs -w",
|
|
@@ -118,7 +148,7 @@
|
|
|
118
148
|
"gui",
|
|
119
149
|
"tool",
|
|
120
150
|
"utility",
|
|
121
|
-
|
|
151
|
+
"plugin-system",
|
|
122
152
|
"ndjson",
|
|
123
153
|
"fast-path",
|
|
124
154
|
"optimization",
|
|
@@ -155,8 +185,7 @@
|
|
|
155
185
|
"stream-csv-to-json.js",
|
|
156
186
|
"json-save.js",
|
|
157
187
|
"index.d.ts",
|
|
158
|
-
|
|
159
|
-
"cli-tui.js",
|
|
188
|
+
"bin/",
|
|
160
189
|
"dist/",
|
|
161
190
|
"src/",
|
|
162
191
|
"examples/",
|
|
@@ -169,25 +198,27 @@
|
|
|
169
198
|
"@rollup/plugin-commonjs": "^25.0.0",
|
|
170
199
|
"@rollup/plugin-node-resolve": "^15.0.0",
|
|
171
200
|
"@rollup/plugin-terser": "^0.4.0",
|
|
201
|
+
"@size-limit/preset-small-lib": "12.0.0",
|
|
172
202
|
"eslint": "8.57.1",
|
|
173
203
|
"jest": "^29.0.0",
|
|
174
204
|
"rollup": "^4.0.0",
|
|
175
|
-
"size-limit": "
|
|
176
|
-
},
|
|
177
|
-
"optionalDependencies": {
|
|
178
|
-
"blessed": "^0.1.81",
|
|
179
|
-
"blessed-contrib": "^4.11.0",
|
|
180
|
-
"exceljs": "^4.4.0"
|
|
205
|
+
"size-limit": "12.0.0"
|
|
181
206
|
},
|
|
182
207
|
"type": "commonjs",
|
|
183
208
|
"size-limit": [
|
|
184
209
|
{
|
|
185
210
|
"path": "dist/jtcsv.umd.js",
|
|
186
|
-
"limit": "
|
|
211
|
+
"limit": "60 KB",
|
|
212
|
+
"ignore": [
|
|
213
|
+
"url"
|
|
214
|
+
]
|
|
187
215
|
},
|
|
188
216
|
{
|
|
189
217
|
"path": "dist/jtcsv.esm.js",
|
|
190
|
-
"limit": "
|
|
218
|
+
"limit": "55 KB",
|
|
219
|
+
"ignore": [
|
|
220
|
+
"url"
|
|
221
|
+
]
|
|
191
222
|
}
|
|
192
223
|
],
|
|
193
224
|
"browserslist": [
|
|
@@ -196,6 +227,3 @@
|
|
|
196
227
|
"maintained node versions"
|
|
197
228
|
]
|
|
198
229
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
package/plugins/README.md
CHANGED
|
@@ -78,6 +78,152 @@ export default function Converter() {
|
|
|
78
78
|
|
|
79
79
|
[📚 Документация](./nextjs-api/README.md)
|
|
80
80
|
|
|
81
|
+
### 4. NestJS Integration (@jtcsv/nestjs)
|
|
82
|
+
|
|
83
|
+
**NestJS interceptors and decorators for CSV upload/download.**
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm install @jtcsv/nestjs jtcsv
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { CsvParserInterceptor, CsvDownloadDecorator } from 'jtcsv/nestjs';
|
|
91
|
+
|
|
92
|
+
@Controller('data')
|
|
93
|
+
export class DataController {
|
|
94
|
+
@Post('upload')
|
|
95
|
+
@CsvParserInterceptor({ delimiter: ',' })
|
|
96
|
+
uploadCsv(@Body() jsonData: any[]) {
|
|
97
|
+
return { parsed: jsonData };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@Get('export')
|
|
101
|
+
@CsvDownloadDecorator({ filename: 'export.csv' })
|
|
102
|
+
exportData() {
|
|
103
|
+
return [{ id: 1, name: 'John' }];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
[📚 Документация](./nestjs/README.md)
|
|
109
|
+
|
|
110
|
+
### 5. Remix Integration (@jtcsv/remix)
|
|
111
|
+
|
|
112
|
+
**Helpers for form-data parsing and CSV downloads in Remix.**
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npm install @jtcsv/remix jtcsv
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { parseFormData, generateCsvResponse } from 'jtcsv/remix';
|
|
120
|
+
|
|
121
|
+
export async function action({ request }) {
|
|
122
|
+
const rows = await parseFormData(request, { delimiter: ',' });
|
|
123
|
+
return { parsed: rows };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export async function loader() {
|
|
127
|
+
return generateCsvResponse([{ id: 1, name: 'John' }], 'export.csv');
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
[📚 Документация](./remix/README.md)
|
|
132
|
+
|
|
133
|
+
### 6. Nuxt Integration (@jtcsv/nuxt)
|
|
134
|
+
|
|
135
|
+
**Nuxt module with auto-imported composable.**
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
npm install @jtcsv/nuxt jtcsv
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
export default defineNuxtConfig({
|
|
143
|
+
modules: ['@jtcsv/nuxt'],
|
|
144
|
+
jtcsv: { autoimport: true }
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```vue
|
|
149
|
+
<script setup>
|
|
150
|
+
const { csvToJson, jsonToCsv } = useJtcsv();
|
|
151
|
+
</script>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
[📚 Документация](./nuxt/README.md)
|
|
155
|
+
|
|
156
|
+
### 7. SvelteKit Integration (@jtcsv/sveltekit)
|
|
157
|
+
|
|
158
|
+
**Request helpers for SvelteKit actions/endpoints.**
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
npm install @jtcsv/sveltekit jtcsv
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { parseCsv, generateCsv } from 'jtcsv/sveltekit';
|
|
166
|
+
|
|
167
|
+
export const actions = {
|
|
168
|
+
upload: async ({ request }) => {
|
|
169
|
+
const rows = await parseCsv(request, { delimiter: ',' });
|
|
170
|
+
return { rows };
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
export async function GET() {
|
|
175
|
+
return generateCsv([{ id: 1 }], 'export.csv');
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
[📚 Документация](./sveltekit/README.md)
|
|
180
|
+
|
|
181
|
+
### 8. Hono Integration (@jtcsv/hono)
|
|
182
|
+
|
|
183
|
+
**Minimal middleware for CSV parsing with Hono.**
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
npm install @jtcsv/hono jtcsv
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
import { Hono } from 'hono';
|
|
191
|
+
import { csvMiddleware, createCsvResponse } from 'jtcsv/hono';
|
|
192
|
+
|
|
193
|
+
const app = new Hono()
|
|
194
|
+
.use('/upload', csvMiddleware())
|
|
195
|
+
.post('/upload', (c) => c.json({ rows: c.get('csv') }))
|
|
196
|
+
.get('/export', (c) => {
|
|
197
|
+
const { csv, headers } = createCsvResponse([{ id: 1 }], 'export.csv');
|
|
198
|
+
return c.text(csv, 200, headers);
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
[📚 Документация](./hono/README.md)
|
|
203
|
+
|
|
204
|
+
### 9. tRPC Integration (@jtcsv/trpc)
|
|
205
|
+
|
|
206
|
+
**Middleware helper for CSV input parsing in tRPC procedures.**
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
npm install @jtcsv/trpc jtcsv
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
import { initTRPC } from '@trpc/server';
|
|
214
|
+
import { z } from 'zod';
|
|
215
|
+
import { createCsvProcedure } from 'jtcsv/trpc';
|
|
216
|
+
|
|
217
|
+
const t = initTRPC.create();
|
|
218
|
+
|
|
219
|
+
export const router = t.router({
|
|
220
|
+
parseCsv: createCsvProcedure(t, z.string())
|
|
221
|
+
.mutation(async ({ input }) => ({ parsed: input }))
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
[📚 Документация](./trpc/README.md)
|
|
226
|
+
|
|
81
227
|
## 🎯 Особенности
|
|
82
228
|
|
|
83
229
|
### Единый API
|
|
@@ -369,5 +515,3 @@ node api-convert.js
|
|
|
369
515
|
---
|
|
370
516
|
|
|
371
517
|
**JTCSV Плагины** - делаем работу с CSV/JSON проще в любом фреймворке! 🚀
|
|
372
|
-
|
|
373
|
-
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# @jtcsv/hono
|
|
2
|
+
|
|
3
|
+
Hono middleware for JTCSV.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
```bash
|
|
7
|
+
npm install @jtcsv/hono jtcsv
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
```typescript
|
|
12
|
+
import { Hono } from 'hono';
|
|
13
|
+
import { csvMiddleware, createCsvResponse } from 'jtcsv/hono';
|
|
14
|
+
|
|
15
|
+
const app = new Hono()
|
|
16
|
+
.use('/upload', csvMiddleware({ delimiter: ',' }))
|
|
17
|
+
.post('/upload', (c) => {
|
|
18
|
+
const rows = c.get('csv');
|
|
19
|
+
return c.json({ rows });
|
|
20
|
+
})
|
|
21
|
+
.get('/export', (c) => {
|
|
22
|
+
const { csv, headers } = createCsvResponse([{ id: 1 }], 'export.csv');
|
|
23
|
+
return c.text(csv, 200, headers);
|
|
24
|
+
});
|
|
25
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CsvToJsonOptions, JsonToCsvOptions } from 'jtcsv';
|
|
2
|
+
import type { Context } from 'hono';
|
|
3
|
+
|
|
4
|
+
export function csvMiddleware(
|
|
5
|
+
options?: CsvToJsonOptions
|
|
6
|
+
): (c: Context, next: () => Promise<void>) => Promise<void>;
|
|
7
|
+
|
|
8
|
+
export function createCsvResponse(
|
|
9
|
+
data: unknown[] | Record<string, unknown>,
|
|
10
|
+
filename?: string,
|
|
11
|
+
options?: JsonToCsvOptions
|
|
12
|
+
): { csv: string; headers: Record<string, string> };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const jtcsv = require('jtcsv');
|
|
2
|
+
|
|
3
|
+
function normalizeFilename(filename) {
|
|
4
|
+
if (!filename || typeof filename !== 'string') {
|
|
5
|
+
return 'export.csv';
|
|
6
|
+
}
|
|
7
|
+
return filename.includes('.') ? filename : `${filename}.csv`;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function csvMiddleware(options = {}) {
|
|
11
|
+
return async (c, next) => {
|
|
12
|
+
const csvText = await c.req.text();
|
|
13
|
+
const rows = jtcsv.csvToJson(csvText, options);
|
|
14
|
+
c.set('csv', rows);
|
|
15
|
+
await next();
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function createCsvResponse(data, filename = 'export.csv', options = {}) {
|
|
20
|
+
const safeName = normalizeFilename(filename);
|
|
21
|
+
const rows = Array.isArray(data) ? data : [data];
|
|
22
|
+
const csv = jtcsv.jsonToCsv(rows, options);
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
csv,
|
|
26
|
+
headers: {
|
|
27
|
+
'Content-Type': 'text/csv; charset=utf-8',
|
|
28
|
+
'Content-Disposition': `attachment; filename="${safeName}"`
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
csvMiddleware,
|
|
35
|
+
createCsvResponse
|
|
36
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jtcsv/hono",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Hono middleware for JTCSV",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"hono",
|
|
9
|
+
"csv",
|
|
10
|
+
"json",
|
|
11
|
+
"converter",
|
|
12
|
+
"jtcsv",
|
|
13
|
+
"middleware"
|
|
14
|
+
],
|
|
15
|
+
"author": "Ruslan Fomenko",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/Linol-Hamelton/jtcsv.git",
|
|
20
|
+
"directory": "plugins/hono"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/Linol-Hamelton/jtcsv/issues"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/Linol-Hamelton/jtcsv/tree/main/plugins/hono#readme",
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"hono": "^4.0.0",
|
|
28
|
+
"jtcsv": "^2.1.3"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"index.js",
|
|
32
|
+
"index.d.ts",
|
|
33
|
+
"README.md"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# @jtcsv/nestjs
|
|
2
|
+
|
|
3
|
+
NestJS interceptors and decorators for JTCSV.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
```bash
|
|
7
|
+
npm install @jtcsv/nestjs jtcsv
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
```typescript
|
|
12
|
+
import { CsvParserInterceptor, CsvDownloadDecorator } from 'jtcsv/nestjs';
|
|
13
|
+
import { Body, Controller, Get, Post } from '@nestjs/common';
|
|
14
|
+
|
|
15
|
+
@Controller('data')
|
|
16
|
+
export class DataController {
|
|
17
|
+
@Post('upload')
|
|
18
|
+
@CsvParserInterceptor({ delimiter: ',' })
|
|
19
|
+
uploadCsv(@Body() jsonData: any[]) {
|
|
20
|
+
return { parsed: jsonData };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@Get('export')
|
|
24
|
+
@CsvDownloadDecorator({ filename: 'export.csv' })
|
|
25
|
+
exportData() {
|
|
26
|
+
return [{ id: 1, name: 'John' }];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Notes
|
|
32
|
+
- `CsvParserInterceptor` expects CSV text in the request body.
|
|
33
|
+
- `CsvDownloadDecorator` converts the handler result to CSV and sets download headers.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Type } from '@nestjs/common';
|
|
2
|
+
import type { NestInterceptor } from '@nestjs/common';
|
|
3
|
+
import type { CsvToJsonOptions, JsonToCsvOptions } from 'jtcsv';
|
|
4
|
+
|
|
5
|
+
export interface CsvParserOptions extends CsvToJsonOptions {}
|
|
6
|
+
|
|
7
|
+
export interface CsvDownloadOptions extends JsonToCsvOptions {
|
|
8
|
+
filename?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function createCsvParserInterceptor(
|
|
12
|
+
options?: CsvParserOptions
|
|
13
|
+
): Type<NestInterceptor>;
|
|
14
|
+
|
|
15
|
+
export function createCsvDownloadInterceptor(
|
|
16
|
+
options?: CsvDownloadOptions
|
|
17
|
+
): Type<NestInterceptor>;
|
|
18
|
+
|
|
19
|
+
export function CsvParserInterceptor(
|
|
20
|
+
options?: CsvParserOptions
|
|
21
|
+
): MethodDecorator & ClassDecorator;
|
|
22
|
+
|
|
23
|
+
export function CsvDownloadDecorator(
|
|
24
|
+
options?: CsvDownloadOptions
|
|
25
|
+
): MethodDecorator & ClassDecorator;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const { Injectable, UseInterceptors } = require('@nestjs/common');
|
|
2
|
+
const { map } = require('rxjs/operators');
|
|
3
|
+
const jtcsv = require('jtcsv');
|
|
4
|
+
|
|
5
|
+
function normalizeFilename(filename) {
|
|
6
|
+
if (!filename || typeof filename !== 'string') {
|
|
7
|
+
return 'export.csv';
|
|
8
|
+
}
|
|
9
|
+
return filename.includes('.') ? filename : `${filename}.csv`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function createCsvParserInterceptor(options = {}) {
|
|
13
|
+
class CsvParserInterceptorImpl {
|
|
14
|
+
intercept(context, next) {
|
|
15
|
+
const req = context.switchToHttp().getRequest();
|
|
16
|
+
const body = req && req.body;
|
|
17
|
+
|
|
18
|
+
if (typeof body === 'string' || Buffer.isBuffer(body)) {
|
|
19
|
+
const csv = Buffer.isBuffer(body) ? body.toString('utf8') : body;
|
|
20
|
+
req.body = jtcsv.csvToJson(csv, options);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return next.handle();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Injectable()(CsvParserInterceptorImpl);
|
|
28
|
+
return CsvParserInterceptorImpl;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function createCsvDownloadInterceptor(options = {}) {
|
|
32
|
+
class CsvDownloadInterceptorImpl {
|
|
33
|
+
intercept(context, next) {
|
|
34
|
+
const res = context.switchToHttp().getResponse();
|
|
35
|
+
const filename = normalizeFilename(options.filename);
|
|
36
|
+
const csvOptions = { ...options };
|
|
37
|
+
delete csvOptions.filename;
|
|
38
|
+
|
|
39
|
+
return next.handle().pipe(
|
|
40
|
+
map(data => {
|
|
41
|
+
const rows = Array.isArray(data) ? data : [data];
|
|
42
|
+
const csv = jtcsv.jsonToCsv(rows, csvOptions);
|
|
43
|
+
|
|
44
|
+
if (res && typeof res.setHeader === 'function') {
|
|
45
|
+
res.setHeader('Content-Type', 'text/csv; charset=utf-8');
|
|
46
|
+
res.setHeader(
|
|
47
|
+
'Content-Disposition',
|
|
48
|
+
`attachment; filename="${filename}"`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return csv;
|
|
53
|
+
})
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
Injectable()(CsvDownloadInterceptorImpl);
|
|
59
|
+
return CsvDownloadInterceptorImpl;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function CsvParserInterceptor(options = {}) {
|
|
63
|
+
const Interceptor = createCsvParserInterceptor(options);
|
|
64
|
+
return UseInterceptors(new Interceptor());
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function CsvDownloadDecorator(options = {}) {
|
|
68
|
+
const Interceptor = createCsvDownloadInterceptor(options);
|
|
69
|
+
return UseInterceptors(new Interceptor());
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = {
|
|
73
|
+
CsvParserInterceptor,
|
|
74
|
+
CsvDownloadDecorator,
|
|
75
|
+
createCsvParserInterceptor,
|
|
76
|
+
createCsvDownloadInterceptor
|
|
77
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jtcsv/nestjs",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "NestJS interceptors and decorators for JTCSV",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"nestjs",
|
|
9
|
+
"csv",
|
|
10
|
+
"json",
|
|
11
|
+
"converter",
|
|
12
|
+
"jtcsv",
|
|
13
|
+
"interceptor",
|
|
14
|
+
"decorator"
|
|
15
|
+
],
|
|
16
|
+
"author": "Ruslan Fomenko",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/Linol-Hamelton/jtcsv.git",
|
|
21
|
+
"directory": "plugins/nestjs"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/Linol-Hamelton/jtcsv/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/Linol-Hamelton/jtcsv/tree/main/plugins/nestjs#readme",
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@nestjs/common": "^9.0.0 || ^10.0.0",
|
|
29
|
+
"jtcsv": "^2.1.3",
|
|
30
|
+
"rxjs": "^7.0.0"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"index.js",
|
|
34
|
+
"index.d.ts",
|
|
35
|
+
"README.md"
|
|
36
|
+
]
|
|
37
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# @jtcsv/nuxt
|
|
2
|
+
|
|
3
|
+
Nuxt module for JTCSV.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
```bash
|
|
7
|
+
npm install @jtcsv/nuxt jtcsv
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Setup
|
|
11
|
+
```typescript
|
|
12
|
+
export default defineNuxtConfig({
|
|
13
|
+
modules: ['@jtcsv/nuxt'],
|
|
14
|
+
jtcsv: {
|
|
15
|
+
autoimport: true
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
```vue
|
|
22
|
+
<script setup>
|
|
23
|
+
const { csvToJson, jsonToCsv } = useJtcsv();
|
|
24
|
+
</script>
|
|
25
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const { defineNuxtModule, addPlugin, addImports, createResolver } = require('@nuxt/kit');
|
|
2
|
+
|
|
3
|
+
module.exports = defineNuxtModule({
|
|
4
|
+
meta: {
|
|
5
|
+
name: '@jtcsv/nuxt',
|
|
6
|
+
configKey: 'jtcsv'
|
|
7
|
+
},
|
|
8
|
+
defaults: {
|
|
9
|
+
autoimport: true
|
|
10
|
+
},
|
|
11
|
+
setup(options) {
|
|
12
|
+
const resolver = createResolver(__dirname);
|
|
13
|
+
addPlugin(resolver.resolve('runtime/plugin'));
|
|
14
|
+
|
|
15
|
+
if (options.autoimport !== false) {
|
|
16
|
+
addImports([
|
|
17
|
+
{ name: 'useJtcsv', from: resolver.resolve('runtime/composables/useJtcsv') }
|
|
18
|
+
]);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jtcsv/nuxt",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Nuxt module for JTCSV (auto-imported composable)",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"nuxt",
|
|
8
|
+
"module",
|
|
9
|
+
"csv",
|
|
10
|
+
"json",
|
|
11
|
+
"converter",
|
|
12
|
+
"jtcsv"
|
|
13
|
+
],
|
|
14
|
+
"author": "Ruslan Fomenko",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/Linol-Hamelton/jtcsv.git",
|
|
19
|
+
"directory": "plugins/nuxt"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/Linol-Hamelton/jtcsv/issues"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/Linol-Hamelton/jtcsv/tree/main/plugins/nuxt#readme",
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@nuxt/kit": "^3.0.0",
|
|
27
|
+
"jtcsv": "^2.1.3",
|
|
28
|
+
"nuxt": "^3.0.0"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"index.js",
|
|
32
|
+
"README.md",
|
|
33
|
+
"runtime/"
|
|
34
|
+
]
|
|
35
|
+
}
|