jtcsv 2.1.1 → 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 +20 -2
- package/bin/jtcsv.js +7 -24
- package/examples/simple-usage.js +2 -3
- package/package.json +34 -18
- 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/cli-tui.js +0 -1498
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# @jtcsv/remix
|
|
2
|
+
|
|
3
|
+
Remix helpers for JTCSV.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
```bash
|
|
7
|
+
npm install @jtcsv/remix jtcsv
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
```typescript
|
|
12
|
+
import { parseFormData, generateCsvResponse } from 'jtcsv/remix';
|
|
13
|
+
|
|
14
|
+
export async function action({ request }) {
|
|
15
|
+
const rows = await parseFormData(request, { delimiter: ',' });
|
|
16
|
+
return { parsed: rows };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function loader() {
|
|
20
|
+
return generateCsvResponse([{ id: 1, name: 'John' }], 'export.csv');
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Notes
|
|
25
|
+
- `parseFormData` looks for a file field named `file` by default.
|
|
26
|
+
- You can override the field name with `{ fieldName: 'upload' }`.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CsvToJsonOptions, JsonToCsvOptions } from 'jtcsv';
|
|
2
|
+
|
|
3
|
+
export interface RemixCsvParseOptions extends CsvToJsonOptions {
|
|
4
|
+
fieldName?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function parseFormData(
|
|
8
|
+
request: Request,
|
|
9
|
+
options?: RemixCsvParseOptions
|
|
10
|
+
): Promise<unknown[]>;
|
|
11
|
+
|
|
12
|
+
export function generateCsvResponse(
|
|
13
|
+
data: unknown[] | Record<string, unknown>,
|
|
14
|
+
filename?: string,
|
|
15
|
+
options?: JsonToCsvOptions
|
|
16
|
+
): Response;
|
|
@@ -0,0 +1,62 @@
|
|
|
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
|
+
async function extractCsvText(formData, fieldName) {
|
|
11
|
+
if (formData.has(fieldName)) {
|
|
12
|
+
const value = formData.get(fieldName);
|
|
13
|
+
if (value && typeof value.text === 'function') {
|
|
14
|
+
return await value.text();
|
|
15
|
+
}
|
|
16
|
+
if (value != null) {
|
|
17
|
+
return String(value);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
for (const value of formData.values()) {
|
|
22
|
+
if (value && typeof value.text === 'function') {
|
|
23
|
+
return await value.text();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function parseFormData(request, options = {}) {
|
|
31
|
+
if (!request || typeof request.formData !== 'function') {
|
|
32
|
+
throw new Error('parseFormData expects a Remix Request with formData()');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const { fieldName = 'file', ...csvOptions } = options;
|
|
36
|
+
const formData = await request.formData();
|
|
37
|
+
const csvText = await extractCsvText(formData, fieldName);
|
|
38
|
+
|
|
39
|
+
if (!csvText) {
|
|
40
|
+
throw new Error('No CSV file or field found in form data');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return jtcsv.csvToJson(csvText, csvOptions);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function generateCsvResponse(data, filename = 'export.csv', options = {}) {
|
|
47
|
+
const safeName = normalizeFilename(filename);
|
|
48
|
+
const rows = Array.isArray(data) ? data : [data];
|
|
49
|
+
const csv = jtcsv.jsonToCsv(rows, options);
|
|
50
|
+
|
|
51
|
+
return new Response(csv, {
|
|
52
|
+
headers: {
|
|
53
|
+
'Content-Type': 'text/csv; charset=utf-8',
|
|
54
|
+
'Content-Disposition': `attachment; filename="${safeName}"`
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = {
|
|
60
|
+
parseFormData,
|
|
61
|
+
generateCsvResponse
|
|
62
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jtcsv/remix",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Remix helpers for JTCSV (form-data parsing and CSV responses)",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"remix",
|
|
9
|
+
"csv",
|
|
10
|
+
"json",
|
|
11
|
+
"converter",
|
|
12
|
+
"jtcsv",
|
|
13
|
+
"formdata",
|
|
14
|
+
"response"
|
|
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/remix"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/Linol-Hamelton/jtcsv/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/Linol-Hamelton/jtcsv/tree/main/plugins/remix#readme",
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"jtcsv": "^2.1.3"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"index.js",
|
|
32
|
+
"index.d.ts",
|
|
33
|
+
"README.md"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# @jtcsv/sveltekit
|
|
2
|
+
|
|
3
|
+
SvelteKit helpers for JTCSV.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
```bash
|
|
7
|
+
npm install @jtcsv/sveltekit jtcsv
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
```typescript
|
|
12
|
+
import { parseCsv, generateCsv } from 'jtcsv/sveltekit';
|
|
13
|
+
|
|
14
|
+
export const actions = {
|
|
15
|
+
upload: async ({ request }) => {
|
|
16
|
+
const rows = await parseCsv(request, { delimiter: ',' });
|
|
17
|
+
return { success: true, rows };
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export async function GET() {
|
|
22
|
+
return generateCsv([{ id: 1, name: 'John' }], 'export.csv');
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Notes
|
|
27
|
+
- `parseCsv` reads `request.text()` by default.
|
|
28
|
+
- Use `{ formData: true, fieldName: 'file' }` for multipart uploads.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CsvToJsonOptions, JsonToCsvOptions } from 'jtcsv';
|
|
2
|
+
|
|
3
|
+
export interface SvelteKitCsvParseOptions extends CsvToJsonOptions {
|
|
4
|
+
fieldName?: string;
|
|
5
|
+
formData?: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function parseCsv(
|
|
9
|
+
request: Request,
|
|
10
|
+
options?: SvelteKitCsvParseOptions
|
|
11
|
+
): Promise<unknown[]>;
|
|
12
|
+
|
|
13
|
+
export function generateCsv(
|
|
14
|
+
data: unknown[] | Record<string, unknown>,
|
|
15
|
+
filename?: string,
|
|
16
|
+
options?: JsonToCsvOptions
|
|
17
|
+
): Response;
|
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
async function parseCsv(request, options = {}) {
|
|
11
|
+
if (!request || typeof request.text !== 'function') {
|
|
12
|
+
throw new Error('parseCsv expects a Request instance');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { fieldName = 'file', ...csvOptions } = options;
|
|
16
|
+
const contentType = request.headers?.get?.('content-type') || '';
|
|
17
|
+
let csvText = null;
|
|
18
|
+
|
|
19
|
+
if (options.formData || contentType.includes('multipart/form-data')) {
|
|
20
|
+
const formData = await request.formData();
|
|
21
|
+
const value = formData.get(fieldName) ?? formData.values().next().value;
|
|
22
|
+
if (value && typeof value.text === 'function') {
|
|
23
|
+
csvText = await value.text();
|
|
24
|
+
} else if (value != null) {
|
|
25
|
+
csvText = String(value);
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
csvText = await request.text();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!csvText) {
|
|
32
|
+
throw new Error('No CSV payload found in request');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return jtcsv.csvToJson(csvText, csvOptions);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function generateCsv(data, filename = 'export.csv', options = {}) {
|
|
39
|
+
const safeName = normalizeFilename(filename);
|
|
40
|
+
const rows = Array.isArray(data) ? data : [data];
|
|
41
|
+
const csv = jtcsv.jsonToCsv(rows, options);
|
|
42
|
+
|
|
43
|
+
return new Response(csv, {
|
|
44
|
+
headers: {
|
|
45
|
+
'Content-Type': 'text/csv; charset=utf-8',
|
|
46
|
+
'Content-Disposition': `attachment; filename="${safeName}"`
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = {
|
|
52
|
+
parseCsv,
|
|
53
|
+
generateCsv
|
|
54
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jtcsv/sveltekit",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "SvelteKit helpers for JTCSV",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"sveltekit",
|
|
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/sveltekit"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/Linol-Hamelton/jtcsv/issues"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/Linol-Hamelton/jtcsv/tree/main/plugins/sveltekit#readme",
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"jtcsv": "^2.1.3"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"index.js",
|
|
30
|
+
"index.d.ts",
|
|
31
|
+
"README.md"
|
|
32
|
+
]
|
|
33
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# @jtcsv/trpc
|
|
2
|
+
|
|
3
|
+
tRPC helper for JTCSV.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
```bash
|
|
7
|
+
npm install @jtcsv/trpc jtcsv
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
```typescript
|
|
12
|
+
import { initTRPC } from '@trpc/server';
|
|
13
|
+
import { z } from 'zod';
|
|
14
|
+
import { createCsvProcedure } from 'jtcsv/trpc';
|
|
15
|
+
|
|
16
|
+
const t = initTRPC.create();
|
|
17
|
+
|
|
18
|
+
export const router = t.router({
|
|
19
|
+
parseCsv: createCsvProcedure(t, z.string(), { delimiter: ',' })
|
|
20
|
+
.mutation(async ({ input }) => ({ parsed: input }))
|
|
21
|
+
});
|
|
22
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const jtcsv = require('jtcsv');
|
|
2
|
+
|
|
3
|
+
function extractCsvText(input) {
|
|
4
|
+
if (typeof input === 'string') {
|
|
5
|
+
return input;
|
|
6
|
+
}
|
|
7
|
+
if (input && typeof input === 'object' && typeof input.csv === 'string') {
|
|
8
|
+
return input.csv;
|
|
9
|
+
}
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function createCsvProcedure(t, schema, options = {}) {
|
|
14
|
+
if (!t || !t.procedure) {
|
|
15
|
+
throw new Error('createCsvProcedure expects initTRPC instance');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return t.procedure
|
|
19
|
+
.input(schema)
|
|
20
|
+
.use(async ({ input, next }) => {
|
|
21
|
+
const csvText = extractCsvText(input);
|
|
22
|
+
if (!csvText) {
|
|
23
|
+
throw new Error('CSV input must be a string or { csv: string }');
|
|
24
|
+
}
|
|
25
|
+
const parsed = jtcsv.csvToJson(csvText, options);
|
|
26
|
+
return next({ input: parsed });
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
createCsvProcedure
|
|
32
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jtcsv/trpc",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "tRPC helper for JTCSV CSV parsing",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"trpc",
|
|
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/trpc"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/Linol-Hamelton/jtcsv/issues"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/Linol-Hamelton/jtcsv/tree/main/plugins/trpc#readme",
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@trpc/server": "^10.0.0",
|
|
27
|
+
"jtcsv": "^2.1.3"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"index.js",
|
|
31
|
+
"index.d.ts",
|
|
32
|
+
"README.md"
|
|
33
|
+
]
|
|
34
|
+
}
|