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
package/plugins/nestjs/index.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# @jtcsv/nextjs
|
|
2
|
-
|
|
3
|
-
Next.js helpers for JTCSV: API route handler, React hooks, and browser helpers.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
```bash
|
|
7
|
-
npm install @jtcsv/nextjs jtcsv
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
## API route
|
|
11
|
-
```javascript
|
|
12
|
-
// pages/api/convert.js
|
|
13
|
-
import handler from '@jtcsv/nextjs/route';
|
|
14
|
-
|
|
15
|
-
export default handler;
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Query options handled by the route:
|
|
19
|
-
- format: json|csv
|
|
20
|
-
- delimiter
|
|
21
|
-
- includeHeaders
|
|
22
|
-
- parseNumbers
|
|
23
|
-
- parseBooleans
|
|
24
|
-
- useFastPath
|
|
25
|
-
- preventCsvInjection
|
|
26
|
-
|
|
27
|
-
## React hook
|
|
28
|
-
```jsx
|
|
29
|
-
'use client';
|
|
30
|
-
import { useJtcsv } from '@jtcsv/nextjs';
|
|
31
|
-
|
|
32
|
-
export default function Converter() {
|
|
33
|
-
const { convertCsvToJson, convertJsonToCsv, isLoading, error, result } = useJtcsv();
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Components and utilities
|
|
39
|
-
```javascript
|
|
40
|
-
import {
|
|
41
|
-
CsvFileUploader,
|
|
42
|
-
downloadCsv,
|
|
43
|
-
createJtcsvApiClient,
|
|
44
|
-
JtcsvProvider,
|
|
45
|
-
useJtcsvContext
|
|
46
|
-
} from '@jtcsv/nextjs';
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Route helpers
|
|
50
|
-
```javascript
|
|
51
|
-
import {
|
|
52
|
-
csvToJsonHandler,
|
|
53
|
-
jsonToCsvHandler,
|
|
54
|
-
healthCheckHandler,
|
|
55
|
-
createJtcsvApiEndpoint
|
|
56
|
-
} from '@jtcsv/nextjs/route';
|
|
57
|
-
```
|
|
@@ -1,386 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Пример React компонента для конвертации CSV/JSON
|
|
3
|
-
* Использование в Next.js приложении
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import React, { useState } from 'react';
|
|
7
|
-
import { useJtcsv, CsvFileUploader, downloadCsv } from '../index';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Компонент для конвертации CSV ↔ JSON
|
|
11
|
-
*/
|
|
12
|
-
export default function ConverterComponent() {
|
|
13
|
-
const [input, setInput] = useState('');
|
|
14
|
-
const [output, setOutput] = useState('');
|
|
15
|
-
const [format, setFormat] = useState('csv'); // 'csv' или 'json'
|
|
16
|
-
const [delimiter, setDelimiter] = useState(',');
|
|
17
|
-
|
|
18
|
-
const {
|
|
19
|
-
convertCsvToJson,
|
|
20
|
-
convertJsonToCsv,
|
|
21
|
-
isLoading,
|
|
22
|
-
error,
|
|
23
|
-
stats
|
|
24
|
-
} = useJtcsv({
|
|
25
|
-
delimiter,
|
|
26
|
-
parseNumbers: true,
|
|
27
|
-
parseBooleans: true,
|
|
28
|
-
preventCsvInjection: true
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
const handleConvert = async () => {
|
|
32
|
-
if (!input.trim()) return;
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
if (format === 'csv') {
|
|
36
|
-
// Конвертируем CSV в JSON
|
|
37
|
-
const result = await convertCsvToJson(input);
|
|
38
|
-
setOutput(JSON.stringify(result, null, 2));
|
|
39
|
-
} else {
|
|
40
|
-
// Конвертируем JSON в CSV
|
|
41
|
-
const json = JSON.parse(input);
|
|
42
|
-
const result = await convertJsonToCsv(json);
|
|
43
|
-
setOutput(result);
|
|
44
|
-
}
|
|
45
|
-
} catch (err) {
|
|
46
|
-
setOutput(`Error: ${err.message}`);
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const handleFileUpload = (result, fileStats) => {
|
|
51
|
-
setInput(JSON.stringify(result, null, 2));
|
|
52
|
-
setFormat('json');
|
|
53
|
-
|
|
54
|
-
console.log('File converted:', fileStats);
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const handleDownload = async () => {
|
|
58
|
-
if (!output) return;
|
|
59
|
-
|
|
60
|
-
try {
|
|
61
|
-
if (format === 'csv') {
|
|
62
|
-
// Скачиваем как CSV
|
|
63
|
-
const json = JSON.parse(input);
|
|
64
|
-
await downloadCsv(json, 'converted.csv', { delimiter });
|
|
65
|
-
} else {
|
|
66
|
-
// Скачиваем как JSON
|
|
67
|
-
const blob = new Blob([output], { type: 'application/json' });
|
|
68
|
-
const url = URL.createObjectURL(blob);
|
|
69
|
-
const link = document.createElement('a');
|
|
70
|
-
link.href = url;
|
|
71
|
-
link.download = 'converted.json';
|
|
72
|
-
link.click();
|
|
73
|
-
URL.revokeObjectURL(url);
|
|
74
|
-
}
|
|
75
|
-
} catch (err) {
|
|
76
|
-
console.error('Download error:', err);
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const handleExample = () => {
|
|
81
|
-
if (format === 'csv') {
|
|
82
|
-
setInput('name,email,age\nJohn Doe,john@example.com,30\nJane Smith,jane@example.com,25');
|
|
83
|
-
} else {
|
|
84
|
-
setInput(JSON.stringify([
|
|
85
|
-
{ name: 'John Doe', email: 'john@example.com', age: 30 },
|
|
86
|
-
{ name: 'Jane Smith', email: 'jane@example.com', age: 25 }
|
|
87
|
-
], null, 2));
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const handleClear = () => {
|
|
92
|
-
setInput('');
|
|
93
|
-
setOutput('');
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
return (
|
|
97
|
-
<div style={styles.container}>
|
|
98
|
-
<h1 style={styles.title}>🔄 JTCSV Converter</h1>
|
|
99
|
-
|
|
100
|
-
<div style={styles.controls}>
|
|
101
|
-
<div style={styles.formatSelector}>
|
|
102
|
-
<label>
|
|
103
|
-
<input
|
|
104
|
-
type="radio"
|
|
105
|
-
value="csv"
|
|
106
|
-
checked={format === 'csv'}
|
|
107
|
-
onChange={(e) => setFormat(e.target.value)}
|
|
108
|
-
/>
|
|
109
|
-
CSV → JSON
|
|
110
|
-
</label>
|
|
111
|
-
<label>
|
|
112
|
-
<input
|
|
113
|
-
type="radio"
|
|
114
|
-
value="json"
|
|
115
|
-
checked={format === 'json'}
|
|
116
|
-
onChange={(e) => setFormat(e.target.value)}
|
|
117
|
-
/>
|
|
118
|
-
JSON → CSV
|
|
119
|
-
</label>
|
|
120
|
-
</div>
|
|
121
|
-
|
|
122
|
-
<div style={styles.delimiterSelector}>
|
|
123
|
-
<label>
|
|
124
|
-
Разделитель:
|
|
125
|
-
<select
|
|
126
|
-
value={delimiter}
|
|
127
|
-
onChange={(e) => setDelimiter(e.target.value)}
|
|
128
|
-
style={styles.select}
|
|
129
|
-
>
|
|
130
|
-
<option value=",">Запятая (,)</option>
|
|
131
|
-
<option value=";">Точка с запятой (;)</option>
|
|
132
|
-
<option value="\t">Табуляция (\t)</option>
|
|
133
|
-
<option value="|">Вертикальная черта (|)</option>
|
|
134
|
-
</select>
|
|
135
|
-
</label>
|
|
136
|
-
</div>
|
|
137
|
-
</div>
|
|
138
|
-
|
|
139
|
-
<div style={styles.inputSection}>
|
|
140
|
-
<div style={styles.inputHeader}>
|
|
141
|
-
<h3 style={styles.sectionTitle}>
|
|
142
|
-
{format === 'csv' ? 'CSV Input' : 'JSON Input'}
|
|
143
|
-
</h3>
|
|
144
|
-
<div style={styles.inputActions}>
|
|
145
|
-
<CsvFileUploader
|
|
146
|
-
onConvert={handleFileUpload}
|
|
147
|
-
options={{ delimiter }}
|
|
148
|
-
>
|
|
149
|
-
<button style={styles.buttonSecondary}>📁 Upload CSV</button>
|
|
150
|
-
</CsvFileUploader>
|
|
151
|
-
<button
|
|
152
|
-
onClick={handleExample}
|
|
153
|
-
style={styles.buttonSecondary}
|
|
154
|
-
>
|
|
155
|
-
📋 Example
|
|
156
|
-
</button>
|
|
157
|
-
<button
|
|
158
|
-
onClick={handleClear}
|
|
159
|
-
style={styles.buttonSecondary}
|
|
160
|
-
>
|
|
161
|
-
🗑️ Clear
|
|
162
|
-
</button>
|
|
163
|
-
</div>
|
|
164
|
-
</div>
|
|
165
|
-
|
|
166
|
-
<textarea
|
|
167
|
-
value={input}
|
|
168
|
-
onChange={(e) => setInput(e.target.value)}
|
|
169
|
-
placeholder={format === 'csv'
|
|
170
|
-
? 'Введите CSV данные...\nПример:\nname,email,age\nJohn,john@example.com,30'
|
|
171
|
-
: 'Введите JSON данные...\nПример:\n[{"name":"John","age":30}]'
|
|
172
|
-
}
|
|
173
|
-
style={styles.textarea}
|
|
174
|
-
rows={10}
|
|
175
|
-
/>
|
|
176
|
-
</div>
|
|
177
|
-
|
|
178
|
-
<div style={styles.convertButtonContainer}>
|
|
179
|
-
<button
|
|
180
|
-
onClick={handleConvert}
|
|
181
|
-
disabled={isLoading || !input.trim()}
|
|
182
|
-
style={{
|
|
183
|
-
...styles.buttonPrimary,
|
|
184
|
-
opacity: isLoading || !input.trim() ? 0.6 : 1,
|
|
185
|
-
cursor: isLoading || !input.trim() ? 'not-allowed' : 'pointer'
|
|
186
|
-
}}
|
|
187
|
-
>
|
|
188
|
-
{isLoading ? '🔄 Converting...' : '🚀 Convert'}
|
|
189
|
-
</button>
|
|
190
|
-
|
|
191
|
-
{stats && (
|
|
192
|
-
<div style={styles.stats}>
|
|
193
|
-
<span>⏱️ {stats.processingTime}ms</span>
|
|
194
|
-
<span>📊 {stats.rows || stats.size} {stats.rows ? 'rows' : 'chars'}</span>
|
|
195
|
-
</div>
|
|
196
|
-
)}
|
|
197
|
-
</div>
|
|
198
|
-
|
|
199
|
-
{error && (
|
|
200
|
-
<div style={styles.error}>
|
|
201
|
-
❌ Error: {error}
|
|
202
|
-
</div>
|
|
203
|
-
)}
|
|
204
|
-
|
|
205
|
-
<div style={styles.outputSection}>
|
|
206
|
-
<div style={styles.outputHeader}>
|
|
207
|
-
<h3 style={styles.sectionTitle}>
|
|
208
|
-
{format === 'csv' ? 'JSON Output' : 'CSV Output'}
|
|
209
|
-
</h3>
|
|
210
|
-
<div style={styles.outputActions}>
|
|
211
|
-
<button
|
|
212
|
-
onClick={handleDownload}
|
|
213
|
-
disabled={!output}
|
|
214
|
-
style={styles.buttonSecondary}
|
|
215
|
-
>
|
|
216
|
-
⬇️ Download
|
|
217
|
-
</button>
|
|
218
|
-
<button
|
|
219
|
-
onClick={() => navigator.clipboard.writeText(output)}
|
|
220
|
-
disabled={!output}
|
|
221
|
-
style={styles.buttonSecondary}
|
|
222
|
-
>
|
|
223
|
-
📋 Copy
|
|
224
|
-
</button>
|
|
225
|
-
</div>
|
|
226
|
-
</div>
|
|
227
|
-
|
|
228
|
-
<pre style={styles.output}>
|
|
229
|
-
{output || 'Результат появится здесь...'}
|
|
230
|
-
</pre>
|
|
231
|
-
</div>
|
|
232
|
-
|
|
233
|
-
<div style={styles.info}>
|
|
234
|
-
<p>💡 <strong>Подсказки:</strong></p>
|
|
235
|
-
<ul style={styles.tipsList}>
|
|
236
|
-
<li>Используйте кнопку "Example" для быстрого заполнения</li>
|
|
237
|
-
<li>Загружайте CSV файлы через кнопку "Upload CSV"</li>
|
|
238
|
-
<li>Выберите разделитель соответствующий вашим данным</li>
|
|
239
|
-
<li>Скачивайте результат в нужном формате</li>
|
|
240
|
-
</ul>
|
|
241
|
-
</div>
|
|
242
|
-
</div>
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const styles = {
|
|
247
|
-
container: {
|
|
248
|
-
maxWidth: '1200px',
|
|
249
|
-
margin: '0 auto',
|
|
250
|
-
padding: '20px',
|
|
251
|
-
fontFamily: 'system-ui, -apple-system, sans-serif'
|
|
252
|
-
},
|
|
253
|
-
title: {
|
|
254
|
-
color: '#333',
|
|
255
|
-
textAlign: 'center',
|
|
256
|
-
marginBottom: '30px'
|
|
257
|
-
},
|
|
258
|
-
controls: {
|
|
259
|
-
display: 'flex',
|
|
260
|
-
justifyContent: 'space-between',
|
|
261
|
-
alignItems: 'center',
|
|
262
|
-
marginBottom: '20px',
|
|
263
|
-
flexWrap: 'wrap',
|
|
264
|
-
gap: '20px'
|
|
265
|
-
},
|
|
266
|
-
formatSelector: {
|
|
267
|
-
display: 'flex',
|
|
268
|
-
gap: '20px'
|
|
269
|
-
},
|
|
270
|
-
delimiterSelector: {
|
|
271
|
-
display: 'flex',
|
|
272
|
-
alignItems: 'center',
|
|
273
|
-
gap: '10px'
|
|
274
|
-
},
|
|
275
|
-
select: {
|
|
276
|
-
padding: '5px 10px',
|
|
277
|
-
marginLeft: '10px',
|
|
278
|
-
borderRadius: '4px',
|
|
279
|
-
border: '1px solid #ccc'
|
|
280
|
-
},
|
|
281
|
-
inputSection: {
|
|
282
|
-
marginBottom: '20px'
|
|
283
|
-
},
|
|
284
|
-
inputHeader: {
|
|
285
|
-
display: 'flex',
|
|
286
|
-
justifyContent: 'space-between',
|
|
287
|
-
alignItems: 'center',
|
|
288
|
-
marginBottom: '10px'
|
|
289
|
-
},
|
|
290
|
-
inputActions: {
|
|
291
|
-
display: 'flex',
|
|
292
|
-
gap: '10px'
|
|
293
|
-
},
|
|
294
|
-
sectionTitle: {
|
|
295
|
-
margin: '0',
|
|
296
|
-
color: '#555'
|
|
297
|
-
},
|
|
298
|
-
textarea: {
|
|
299
|
-
width: '100%',
|
|
300
|
-
padding: '15px',
|
|
301
|
-
border: '1px solid #ddd',
|
|
302
|
-
borderRadius: '8px',
|
|
303
|
-
fontFamily: 'monospace',
|
|
304
|
-
fontSize: '14px',
|
|
305
|
-
resize: 'vertical',
|
|
306
|
-
boxSizing: 'border-box'
|
|
307
|
-
},
|
|
308
|
-
convertButtonContainer: {
|
|
309
|
-
display: 'flex',
|
|
310
|
-
flexDirection: 'column',
|
|
311
|
-
alignItems: 'center',
|
|
312
|
-
gap: '10px',
|
|
313
|
-
margin: '20px 0'
|
|
314
|
-
},
|
|
315
|
-
buttonPrimary: {
|
|
316
|
-
padding: '12px 30px',
|
|
317
|
-
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
318
|
-
color: 'white',
|
|
319
|
-
border: 'none',
|
|
320
|
-
borderRadius: '25px',
|
|
321
|
-
fontSize: '16px',
|
|
322
|
-
fontWeight: 'bold',
|
|
323
|
-
cursor: 'pointer',
|
|
324
|
-
transition: 'transform 0.2s'
|
|
325
|
-
},
|
|
326
|
-
buttonSecondary: {
|
|
327
|
-
padding: '8px 16px',
|
|
328
|
-
background: '#f0f0f0',
|
|
329
|
-
color: '#333',
|
|
330
|
-
border: '1px solid #ddd',
|
|
331
|
-
borderRadius: '4px',
|
|
332
|
-
cursor: 'pointer',
|
|
333
|
-
transition: 'background 0.2s'
|
|
334
|
-
},
|
|
335
|
-
stats: {
|
|
336
|
-
display: 'flex',
|
|
337
|
-
gap: '20px',
|
|
338
|
-
color: '#666',
|
|
339
|
-
fontSize: '14px'
|
|
340
|
-
},
|
|
341
|
-
error: {
|
|
342
|
-
padding: '15px',
|
|
343
|
-
background: '#fee',
|
|
344
|
-
border: '1px solid #f99',
|
|
345
|
-
borderRadius: '8px',
|
|
346
|
-
color: '#c00',
|
|
347
|
-
marginBottom: '20px'
|
|
348
|
-
},
|
|
349
|
-
outputSection: {
|
|
350
|
-
marginTop: '20px'
|
|
351
|
-
},
|
|
352
|
-
outputHeader: {
|
|
353
|
-
display: 'flex',
|
|
354
|
-
justifyContent: 'space-between',
|
|
355
|
-
alignItems: 'center',
|
|
356
|
-
marginBottom: '10px'
|
|
357
|
-
},
|
|
358
|
-
outputActions: {
|
|
359
|
-
display: 'flex',
|
|
360
|
-
gap: '10px'
|
|
361
|
-
},
|
|
362
|
-
output: {
|
|
363
|
-
padding: '15px',
|
|
364
|
-
background: '#f8f8f8',
|
|
365
|
-
border: '1px solid #ddd',
|
|
366
|
-
borderRadius: '8px',
|
|
367
|
-
minHeight: '200px',
|
|
368
|
-
overflow: 'auto',
|
|
369
|
-
whiteSpace: 'pre-wrap',
|
|
370
|
-
wordBreak: 'break-all',
|
|
371
|
-
fontFamily: 'monospace',
|
|
372
|
-
fontSize: '14px'
|
|
373
|
-
},
|
|
374
|
-
info: {
|
|
375
|
-
marginTop: '30px',
|
|
376
|
-
padding: '20px',
|
|
377
|
-
background: '#f0f8ff',
|
|
378
|
-
border: '1px solid #cce5ff',
|
|
379
|
-
borderRadius: '8px'
|
|
380
|
-
},
|
|
381
|
-
tipsList: {
|
|
382
|
-
margin: '10px 0 0 20px',
|
|
383
|
-
color: '#555'
|
|
384
|
-
}
|
|
385
|
-
};
|
|
386
|
-
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Пример API route для Next.js
|
|
3
|
-
* Сохраните этот файл как pages/api/convert.js
|
|
4
|
-
*
|
|
5
|
-
* @example
|
|
6
|
-
* // Запросы к API:
|
|
7
|
-
* // POST /api/convert с JSON телом → получите CSV
|
|
8
|
-
* // POST /api/convert с CSV телом → получите JSON
|
|
9
|
-
* // GET /api/convert/health → проверка состояния
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
handler as jtcsvHandler,
|
|
14
|
-
csvToJsonHandler,
|
|
15
|
-
jsonToCsvHandler,
|
|
16
|
-
healthCheckHandler
|
|
17
|
-
} from '../../route';
|
|
18
|
-
|
|
19
|
-
// Основной endpoint для автоматической конвертации
|
|
20
|
-
export default jtcsvHandler;
|
|
21
|
-
|
|
22
|
-
// Специализированные endpoints
|
|
23
|
-
export const config = {
|
|
24
|
-
api: {
|
|
25
|
-
bodyParser: {
|
|
26
|
-
sizeLimit: '50mb'
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// Альтернативная реализация с отдельными путями
|
|
32
|
-
// export default async function handler(req, res) {
|
|
33
|
-
// const { path } = req.query;
|
|
34
|
-
//
|
|
35
|
-
// switch (path) {
|
|
36
|
-
// case 'csv-to-json':
|
|
37
|
-
// return csvToJsonHandler(req, res);
|
|
38
|
-
// case 'json-to-csv':
|
|
39
|
-
// return jsonToCsvHandler(req, res);
|
|
40
|
-
// case 'health':
|
|
41
|
-
// return healthCheckHandler(req, res);
|
|
42
|
-
// default:
|
|
43
|
-
// return jtcsvHandler(req, res);
|
|
44
|
-
// }
|
|
45
|
-
// }
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Пример использования с кастомной логикой
|
|
49
|
-
*
|
|
50
|
-
* export default async function handler(req, res) {
|
|
51
|
-
* // Добавляем логирование
|
|
52
|
-
* console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
|
|
53
|
-
*
|
|
54
|
-
* // Проверяем аутентификацию
|
|
55
|
-
* const apiKey = req.headers['x-api-key'];
|
|
56
|
-
* if (!apiKey || apiKey !== process.env.API_KEY) {
|
|
57
|
-
* return res.status(401).json({ error: 'Unauthorized' });
|
|
58
|
-
* }
|
|
59
|
-
*
|
|
60
|
-
* // Ограничение по частоте запросов
|
|
61
|
-
* const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
|
62
|
-
* // ... rate limiting logic
|
|
63
|
-
*
|
|
64
|
-
* // Вызываем основной обработчик
|
|
65
|
-
* return jtcsvHandler(req, res);
|
|
66
|
-
* }
|
|
67
|
-
*/
|
|
68
|
-
|
|
69
|
-
|