jtcsv 2.2.7 ā 3.0.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 +31 -1
- package/bin/jtcsv.js +891 -821
- package/bin/jtcsv.ts +2534 -0
- package/csv-to-json.js +168 -145
- package/dist/jtcsv-core.cjs.js +1407 -0
- package/dist/jtcsv-core.cjs.js.map +1 -0
- package/dist/jtcsv-core.esm.js +1379 -0
- package/dist/jtcsv-core.esm.js.map +1 -0
- package/dist/jtcsv-core.umd.js +1413 -0
- package/dist/jtcsv-core.umd.js.map +1 -0
- package/dist/jtcsv-full.cjs.js +1912 -0
- package/dist/jtcsv-full.cjs.js.map +1 -0
- package/dist/jtcsv-full.esm.js +1880 -0
- package/dist/jtcsv-full.esm.js.map +1 -0
- package/dist/jtcsv-full.umd.js +1918 -0
- package/dist/jtcsv-full.umd.js.map +1 -0
- package/dist/jtcsv-workers.esm.js +759 -0
- package/dist/jtcsv-workers.esm.js.map +1 -0
- package/dist/jtcsv-workers.umd.js +773 -0
- package/dist/jtcsv-workers.umd.js.map +1 -0
- package/dist/jtcsv.cjs.js +61 -19
- package/dist/jtcsv.cjs.js.map +1 -1
- package/dist/jtcsv.esm.js +61 -19
- package/dist/jtcsv.esm.js.map +1 -1
- package/dist/jtcsv.umd.js +61 -19
- package/dist/jtcsv.umd.js.map +1 -1
- package/errors.js +188 -2
- package/examples/advanced/conditional-transformations.js +446 -0
- package/examples/advanced/conditional-transformations.ts +446 -0
- package/examples/advanced/csv-parser.worker.js +89 -0
- package/examples/advanced/csv-parser.worker.ts +89 -0
- package/examples/advanced/nested-objects-example.js +306 -0
- package/examples/advanced/nested-objects-example.ts +306 -0
- package/examples/advanced/performance-optimization.js +504 -0
- package/examples/advanced/performance-optimization.ts +504 -0
- package/examples/advanced/run-demo-server.js +116 -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 +288 -0
- package/examples/cli-batch-processing.ts +38 -0
- package/examples/cli-tool.js +0 -3
- package/examples/cli-tool.ts +183 -0
- package/examples/error-handling.js +21 -7
- package/examples/error-handling.ts +356 -0
- package/examples/express-api.js +0 -3
- package/examples/express-api.ts +164 -0
- package/examples/large-dataset-example.js +0 -3
- package/examples/large-dataset-example.ts +204 -0
- package/examples/ndjson-processing.js +1 -1
- package/examples/ndjson-processing.ts +456 -0
- package/examples/plugin-excel-exporter.js +3 -4
- package/examples/plugin-excel-exporter.ts +406 -0
- package/examples/react-integration.tsx +637 -0
- package/examples/schema-validation.ts +640 -0
- package/examples/simple-usage.js +254 -254
- package/examples/simple-usage.ts +194 -0
- package/examples/streaming-example.js +4 -5
- package/examples/streaming-example.ts +419 -0
- package/examples/web-workers-advanced.ts +28 -0
- package/index.d.ts +1 -3
- package/index.js +15 -1
- package/json-save.js +9 -3
- package/json-to-csv.js +168 -21
- package/package.json +69 -10
- package/plugins/express-middleware/README.md +21 -2
- package/plugins/express-middleware/example.js +3 -4
- package/plugins/express-middleware/example.ts +135 -0
- package/plugins/express-middleware/index.d.ts +1 -1
- package/plugins/express-middleware/index.js +270 -118
- package/plugins/express-middleware/index.ts +557 -0
- package/plugins/fastify-plugin/index.js +2 -4
- package/plugins/fastify-plugin/index.ts +443 -0
- package/plugins/hono/index.ts +226 -0
- package/plugins/nestjs/index.ts +201 -0
- package/plugins/nextjs-api/examples/ConverterComponent.tsx +386 -0
- package/plugins/nextjs-api/examples/api-convert.js +0 -2
- package/plugins/nextjs-api/examples/api-convert.ts +67 -0
- package/plugins/nextjs-api/index.tsx +339 -0
- package/plugins/nextjs-api/route.js +2 -3
- package/plugins/nextjs-api/route.ts +370 -0
- package/plugins/nuxt/index.ts +94 -0
- package/plugins/nuxt/runtime/composables/useJtcsv.ts +100 -0
- package/plugins/nuxt/runtime/plugin.ts +71 -0
- package/plugins/remix/index.js +1 -1
- package/plugins/remix/index.ts +260 -0
- package/plugins/sveltekit/index.js +1 -1
- package/plugins/sveltekit/index.ts +301 -0
- package/plugins/trpc/index.ts +267 -0
- package/src/browser/browser-functions.ts +402 -0
- package/src/browser/core.js +92 -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.js +36 -14
- package/src/browser/csv-to-json-browser.ts +264 -0
- package/src/browser/errors-browser.ts +303 -0
- package/src/browser/extensions/plugins.js +92 -0
- package/src/browser/extensions/plugins.ts +93 -0
- package/src/browser/extensions/workers.js +39 -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.js +13 -3
- package/src/browser/json-to-csv-browser.ts +262 -0
- package/src/browser/streams.js +12 -2
- package/src/browser/streams.ts +336 -0
- package/src/browser/workers/csv-parser.worker.ts +377 -0
- package/src/browser/workers/worker-pool.ts +548 -0
- package/src/core/delimiter-cache.js +22 -8
- package/src/core/delimiter-cache.ts +310 -0
- package/src/core/node-optimizations.ts +449 -0
- package/src/core/plugin-system.js +29 -11
- package/src/core/plugin-system.ts +400 -0
- package/src/core/transform-hooks.ts +558 -0
- package/src/engines/fast-path-engine-new.ts +347 -0
- package/src/engines/fast-path-engine.ts +854 -0
- package/src/errors.ts +72 -0
- package/src/formats/ndjson-parser.ts +469 -0
- package/src/formats/tsv-parser.ts +334 -0
- package/src/index-with-plugins.js +16 -9
- package/src/index-with-plugins.ts +395 -0
- package/src/types/index.ts +255 -0
- package/src/utils/bom-utils.js +259 -0
- package/src/utils/bom-utils.ts +373 -0
- package/src/utils/encoding-support.js +124 -0
- package/src/utils/encoding-support.ts +155 -0
- package/src/utils/schema-validator.js +19 -19
- package/src/utils/schema-validator.ts +819 -0
- package/src/utils/transform-loader.js +1 -1
- package/src/utils/transform-loader.ts +389 -0
- package/src/utils/zod-adapter.js +170 -0
- package/src/utils/zod-adapter.ts +280 -0
- package/src/web-server/index.js +10 -10
- package/src/web-server/index.ts +683 -0
- 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/stream-csv-to-json.js +26 -8
- package/stream-json-to-csv.js +1 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// Express API example for jtcsv
|
|
2
|
+
// Run: node examples/express-api.ts
|
|
3
|
+
// Then visit: http://localhost:3000/export/users
|
|
4
|
+
|
|
5
|
+
import express from 'express';
|
|
6
|
+
import { jsonToCsv } from '../index';
|
|
7
|
+
import fs from 'fs/promises';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
|
|
10
|
+
const app = express();
|
|
11
|
+
const PORT = 3000;
|
|
12
|
+
|
|
13
|
+
// Mock database
|
|
14
|
+
const mockUsers = Array.from({ length: 100 }, (_, i) => ({
|
|
15
|
+
id: i + 1,
|
|
16
|
+
name: `User ${i + 1}`,
|
|
17
|
+
email: `user${i + 1}@example.com`,
|
|
18
|
+
role: i % 3 === 0 ? 'admin' : i % 3 === 1 ? 'moderator' : 'user',
|
|
19
|
+
status: i % 5 === 0 ? 'inactive' : 'active',
|
|
20
|
+
createdAt: new Date(Date.now() - Math.random() * 31536000000).toISOString(),
|
|
21
|
+
profile: {
|
|
22
|
+
age: Math.floor(Math.random() * 50) + 18,
|
|
23
|
+
country: ['USA', 'UK', 'Germany', 'France', 'Japan'][Math.floor(Math.random() * 5)],
|
|
24
|
+
bio: `Bio for user ${i + 1}`
|
|
25
|
+
},
|
|
26
|
+
tags: ['customer', `tier${Math.floor(Math.random() * 3) + 1}`]
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
// Middleware
|
|
30
|
+
app.use(express.json());
|
|
31
|
+
|
|
32
|
+
// Health check
|
|
33
|
+
app.get('/', (req, res) => {
|
|
34
|
+
res.json({
|
|
35
|
+
message: 'jtcsv Express API Example',
|
|
36
|
+
endpoints: [
|
|
37
|
+
'GET /export/users - Export users as CSV',
|
|
38
|
+
'GET /export/users/download - Download users CSV file',
|
|
39
|
+
'POST /export/custom - Convert custom JSON to CSV'
|
|
40
|
+
]
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Export users as CSV (inline)
|
|
45
|
+
app.get('/export/users', (req, res) => {
|
|
46
|
+
try {
|
|
47
|
+
const csv = jsonToCsv(mockUsers, {
|
|
48
|
+
delimiter: ',',
|
|
49
|
+
renameMap: {
|
|
50
|
+
id: 'ID',
|
|
51
|
+
name: 'Full Name',
|
|
52
|
+
email: 'Email Address',
|
|
53
|
+
role: 'Role',
|
|
54
|
+
status: 'Status',
|
|
55
|
+
'profile.age': 'Age',
|
|
56
|
+
'profile.country': 'Country',
|
|
57
|
+
'profile.bio': 'Bio',
|
|
58
|
+
'createdAt': 'Created At'
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
res.set('Content-Type', 'text/plain');
|
|
63
|
+
res.send(csv);
|
|
64
|
+
} catch (error: any) {
|
|
65
|
+
res.status(500).json({ error: error.message });
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Download users CSV file
|
|
70
|
+
app.get('/export/users/download', async (req, res) => {
|
|
71
|
+
try {
|
|
72
|
+
const csv = jsonToCsv(mockUsers, {
|
|
73
|
+
delimiter: ',',
|
|
74
|
+
renameMap: {
|
|
75
|
+
id: 'ID',
|
|
76
|
+
name: 'Full Name',
|
|
77
|
+
email: 'Email Address'
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const filename = `users-export-${Date.now()}.csv`;
|
|
82
|
+
const filePath = path.join(__dirname, 'temp', filename);
|
|
83
|
+
|
|
84
|
+
// Ensure temp directory exists
|
|
85
|
+
await fs.mkdir(path.join(__dirname, 'temp'), { recursive: true });
|
|
86
|
+
|
|
87
|
+
// Write file
|
|
88
|
+
await fs.writeFile(filePath, csv, 'utf8');
|
|
89
|
+
|
|
90
|
+
// Send file for download
|
|
91
|
+
res.download(filePath, filename, (err) => {
|
|
92
|
+
// Clean up temp file
|
|
93
|
+
fs.unlink(filePath).catch(() => {});
|
|
94
|
+
});
|
|
95
|
+
} catch (error: any) {
|
|
96
|
+
res.status(500).json({ error: error.message });
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Convert custom JSON to CSV
|
|
101
|
+
app.post('/export/custom', (req, res) => {
|
|
102
|
+
try {
|
|
103
|
+
const { data, options = {} } = req.body;
|
|
104
|
+
|
|
105
|
+
if (!Array.isArray(data)) {
|
|
106
|
+
return res.status(400).json({ error: 'Data must be an array' });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Limit to 10,000 records for safety
|
|
110
|
+
const safeData = data.slice(0, 10000);
|
|
111
|
+
|
|
112
|
+
const csv = jsonToCsv(safeData, {
|
|
113
|
+
delimiter: options.delimiter || ',',
|
|
114
|
+
renameMap: options.renameMap || {}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
res.json({
|
|
118
|
+
success: true,
|
|
119
|
+
records: safeData.length,
|
|
120
|
+
csvSize: csv.length,
|
|
121
|
+
csv: options.returnCsv !== false ? csv : undefined
|
|
122
|
+
});
|
|
123
|
+
} catch (error: any) {
|
|
124
|
+
res.status(500).json({
|
|
125
|
+
success: false,
|
|
126
|
+
error: error.message,
|
|
127
|
+
type: error.constructor.name
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Example with CSV injection protection
|
|
133
|
+
app.get('/export/safe', (req, res) => {
|
|
134
|
+
const dangerousData = [
|
|
135
|
+
{ id: 1, input: '=cmd|"/c calc.exe"!A0', note: 'Malicious formula' },
|
|
136
|
+
{ id: 2, input: '@SUM(A1:A10)', note: 'Excel function' },
|
|
137
|
+
{ id: 3, input: '+1-1', note: 'Another formula' },
|
|
138
|
+
{ id: 4, input: '-2+2', note: 'Formula with minus' },
|
|
139
|
+
{ id: 5, input: 'Normal text', note: 'Safe content' },
|
|
140
|
+
{ id: 6, input: 'Text with, commas', note: 'With comma' },
|
|
141
|
+
{ id: 7, input: 'Text with\nnewlines', note: 'With newline' },
|
|
142
|
+
{ id: 8, input: 'Text with "quotes"', note: 'With quotes' }
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
const csv = jsonToCsv(dangerousData, { delimiter: ',' });
|
|
146
|
+
|
|
147
|
+
res.set('Content-Type', 'text/plain');
|
|
148
|
+
res.send(`# CSV Injection Protection Demo\n\n${csv}`);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Start server
|
|
152
|
+
app.listen(PORT, () => {
|
|
153
|
+
console.log(`š Express API running at http://localhost:${PORT}`);
|
|
154
|
+
console.log('š Try these endpoints:');
|
|
155
|
+
console.log(` http://localhost:${PORT}/export/users`);
|
|
156
|
+
console.log(` http://localhost:${PORT}/export/users/download`);
|
|
157
|
+
console.log(` http://localhost:${PORT}/export/safe`);
|
|
158
|
+
console.log('\nExample POST to /export/custom:');
|
|
159
|
+
console.log(`curl -X POST http://localhost:${PORT}/export/custom \\
|
|
160
|
+
-H "Content-Type: application/json" \\
|
|
161
|
+
-d '{"data":[{"name":"John","age":30}],"options":{"delimiter":";"}}'`);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
export default app;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
// Large dataset example for jtcsv
|
|
2
|
+
// Demonstrates handling of large datasets and memory efficiency
|
|
3
|
+
|
|
4
|
+
import { jsonToCsv } from '../index-core.js';
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
|
|
8
|
+
interface DatasetRecord {
|
|
9
|
+
id: number;
|
|
10
|
+
timestamp: string;
|
|
11
|
+
userId: string;
|
|
12
|
+
action: string;
|
|
13
|
+
amount: number;
|
|
14
|
+
success: boolean;
|
|
15
|
+
metadata: {
|
|
16
|
+
ip: string;
|
|
17
|
+
userAgent: string;
|
|
18
|
+
sessionId: string;
|
|
19
|
+
};
|
|
20
|
+
tags: string[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface MemoryUsage {
|
|
24
|
+
rss: number;
|
|
25
|
+
heapTotal: number;
|
|
26
|
+
heapUsed: number;
|
|
27
|
+
external: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Generate large dataset
|
|
31
|
+
export function generateLargeDataset(rows: number): DatasetRecord[] {
|
|
32
|
+
console.log(`Generating ${rows.toLocaleString()} records...`);
|
|
33
|
+
|
|
34
|
+
const dataset: DatasetRecord[] = [];
|
|
35
|
+
const batchSize = 10000;
|
|
36
|
+
const batches = Math.ceil(rows / batchSize);
|
|
37
|
+
|
|
38
|
+
for (let batch = 0; batch < batches; batch++) {
|
|
39
|
+
const start = batch * batchSize;
|
|
40
|
+
const end = Math.min(start + batchSize, rows);
|
|
41
|
+
|
|
42
|
+
for (let i = start; i < end; i++) {
|
|
43
|
+
dataset.push({
|
|
44
|
+
id: i + 1,
|
|
45
|
+
timestamp: new Date(Date.now() - Math.random() * 31536000000).toISOString(),
|
|
46
|
+
userId: `user_${Math.floor(Math.random() * 10000)}`,
|
|
47
|
+
action: ['login', 'purchase', 'view', 'click', 'logout'][Math.floor(Math.random() * 5)],
|
|
48
|
+
amount: Math.random() * 1000,
|
|
49
|
+
success: Math.random() > 0.1,
|
|
50
|
+
metadata: {
|
|
51
|
+
ip: `${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}`,
|
|
52
|
+
userAgent: `Browser/${Math.floor(Math.random() * 100)}`,
|
|
53
|
+
sessionId: `session_${Math.random().toString(36).substr(2, 9)}`
|
|
54
|
+
},
|
|
55
|
+
tags: Array.from({ length: Math.floor(Math.random() * 5) + 1 },
|
|
56
|
+
() => ['tag' + Math.floor(Math.random() * 20), 'cat' + Math.floor(Math.random() * 10)]
|
|
57
|
+
).flat()
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if ((batch + 1) % 10 === 0 || batch === batches - 1) {
|
|
62
|
+
console.log(` Generated ${Math.min((batch + 1) * batchSize, rows).toLocaleString()} records`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return dataset;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Memory usage helper
|
|
70
|
+
export function getMemoryUsage(): MemoryUsage {
|
|
71
|
+
const used = process.memoryUsage();
|
|
72
|
+
return {
|
|
73
|
+
rss: Math.round(used.rss / 1024 / 1024),
|
|
74
|
+
heapTotal: Math.round(used.heapTotal / 1024 / 1024),
|
|
75
|
+
heapUsed: Math.round(used.heapUsed / 1024 / 1024),
|
|
76
|
+
external: Math.round(used.external / 1024 / 1024)
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Benchmark conversion
|
|
81
|
+
export async function benchmarkConversion(dataset: DatasetRecord[], name: string): Promise<string | null> {
|
|
82
|
+
console.log(`\n${name}:`);
|
|
83
|
+
console.log(` Records: ${dataset.length.toLocaleString()}`);
|
|
84
|
+
|
|
85
|
+
const memBefore = getMemoryUsage();
|
|
86
|
+
console.log(` Memory before: ${memBefore.heapUsed}MB heap`);
|
|
87
|
+
|
|
88
|
+
const startTime = performance.now();
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const csv = jsonToCsv(dataset, {
|
|
92
|
+
delimiter: ','
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const endTime = performance.now();
|
|
96
|
+
const memAfter = getMemoryUsage();
|
|
97
|
+
|
|
98
|
+
console.log(` Conversion time: ${(endTime - startTime).toFixed(2)}ms`);
|
|
99
|
+
console.log(` Memory after: ${memAfter.heapUsed}MB heap`);
|
|
100
|
+
console.log(` Memory delta: ${(memAfter.heapUsed - memBefore.heapUsed)}MB`);
|
|
101
|
+
console.log(` CSV size: ${(csv.length / 1024 / 1024).toFixed(2)}MB`);
|
|
102
|
+
console.log(` Rows/second: ${Math.round((dataset.length / (endTime - startTime)) * 1000).toLocaleString()}`);
|
|
103
|
+
|
|
104
|
+
return csv;
|
|
105
|
+
} catch (error: unknown) {
|
|
106
|
+
console.error(` Error: ${(error as Error).message}`);
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Save CSV in chunks (for very large files)
|
|
112
|
+
export function saveCsvInChunks(csv: string, filename: string, chunkSize = 10 * 1024 * 1024): Promise<void> { // 10MB chunks
|
|
113
|
+
console.log(`\nSaving CSV in chunks to ${filename}...`);
|
|
114
|
+
|
|
115
|
+
const totalChunks = Math.ceil(csv.length / chunkSize);
|
|
116
|
+
const writeStream = fs.createWriteStream(filename);
|
|
117
|
+
|
|
118
|
+
return new Promise((resolve, reject) => {
|
|
119
|
+
writeStream.on('error', reject);
|
|
120
|
+
writeStream.on('finish', resolve);
|
|
121
|
+
|
|
122
|
+
for (let i = 0; i < totalChunks; i++) {
|
|
123
|
+
const start = i * chunkSize;
|
|
124
|
+
const end = Math.min(start + chunkSize, csv.length);
|
|
125
|
+
const chunk = csv.substring(start, end);
|
|
126
|
+
|
|
127
|
+
if (!writeStream.write(chunk)) {
|
|
128
|
+
// Wait for drain if buffer is full
|
|
129
|
+
writeStream.once('drain', () => {
|
|
130
|
+
if (i % 10 === 0 || i === totalChunks - 1) {
|
|
131
|
+
console.log(` Written chunk ${i + 1}/${totalChunks} (${Math.round((i + 1) / totalChunks * 100)}%)`);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
} else {
|
|
135
|
+
if (i % 10 === 0 || i === totalChunks - 1) {
|
|
136
|
+
console.log(` Written chunk ${i + 1}/${totalChunks} (${Math.round((i + 1) / totalChunks * 100)}%)`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
writeStream.end();
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Main function
|
|
146
|
+
export async function main(): Promise<void> {
|
|
147
|
+
console.log('š jtcsv Large Dataset Demo');
|
|
148
|
+
console.log('=' .repeat(50));
|
|
149
|
+
|
|
150
|
+
// Test with different dataset sizes
|
|
151
|
+
const testSizes = [1000, 10000, 50000];
|
|
152
|
+
|
|
153
|
+
for (const size of testSizes) {
|
|
154
|
+
const dataset = generateLargeDataset(size);
|
|
155
|
+
const csv = await benchmarkConversion(dataset, `Dataset: ${size.toLocaleString()} records`);
|
|
156
|
+
|
|
157
|
+
if (csv && size === 50000) {
|
|
158
|
+
// Save the largest dataset as example
|
|
159
|
+
const filename = `large-dataset-${size}-records.csv`;
|
|
160
|
+
await saveCsvInChunks(csv, filename);
|
|
161
|
+
|
|
162
|
+
const stats = fs.statSync(filename);
|
|
163
|
+
console.log(`\nā
Saved to ${filename}`);
|
|
164
|
+
console.log(` File size: ${(stats.size / 1024 / 1024).toFixed(2)}MB`);
|
|
165
|
+
|
|
166
|
+
// Show first few lines
|
|
167
|
+
const sample = csv.split('\n').slice(0, 3).join('\n');
|
|
168
|
+
console.log('\nSample output (first 3 lines):');
|
|
169
|
+
console.log(sample);
|
|
170
|
+
console.log('...');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Force garbage collection if available
|
|
174
|
+
if (global.gc) {
|
|
175
|
+
(global.gc as () => void)();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
console.log('\nšÆ Performance Summary:');
|
|
180
|
+
console.log('| Records | Approx. Time | Memory Usage | CSV Size |');
|
|
181
|
+
console.log('|---------|--------------|--------------|----------|');
|
|
182
|
+
console.log('| 1,000 | ~5ms | ~2MB | ~0.5MB |');
|
|
183
|
+
console.log('| 10,000 | ~50ms | ~10MB | ~5MB |');
|
|
184
|
+
console.log('| 50,000 | ~250ms | ~40MB | ~25MB |');
|
|
185
|
+
console.log('| 100,000 | ~500ms* | ~80MB* | ~50MB* |');
|
|
186
|
+
console.log('\n* Estimated values');
|
|
187
|
+
|
|
188
|
+
console.log('\nš” Tips for very large datasets:');
|
|
189
|
+
console.log('1. Use the maxRecords option optionally to limit processing');
|
|
190
|
+
console.log('2. Process data in batches if memory is limited');
|
|
191
|
+
console.log('3. Use saveAsCsv() for secure file writing');
|
|
192
|
+
console.log('4. Monitor memory usage with process.memoryUsage()');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Run if called directly
|
|
196
|
+
if (require.main === module) {
|
|
197
|
+
main().catch(console.error);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export default {
|
|
201
|
+
generateLargeDataset,
|
|
202
|
+
benchmarkConversion,
|
|
203
|
+
saveCsvInChunks
|
|
204
|
+
};
|