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,183 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// jtcsv CLI Tool
|
|
4
|
+
// Usage: node cli-tool.js input.json output.csv [options]
|
|
5
|
+
// Example: node cli-tool.js data.json output.csv --delimiter=,
|
|
6
|
+
|
|
7
|
+
import fs from "fs";
|
|
8
|
+
import path from "path";
|
|
9
|
+
const { jsonToCsv, saveAsCsv } = await import("../index.js");
|
|
10
|
+
|
|
11
|
+
// Parse command line arguments
|
|
12
|
+
function parseArgs() {
|
|
13
|
+
const args = process.argv.slice(2);
|
|
14
|
+
const result = {
|
|
15
|
+
input: null,
|
|
16
|
+
output: null,
|
|
17
|
+
delimiter: ';',
|
|
18
|
+
noHeaders: false,
|
|
19
|
+
help: false,
|
|
20
|
+
version: false
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
for (let i = 0; i < args.length; i++) {
|
|
24
|
+
const arg = args[i];
|
|
25
|
+
|
|
26
|
+
if (arg.startsWith('--')) {
|
|
27
|
+
const [key, value] = arg.slice(2).split('=');
|
|
28
|
+
|
|
29
|
+
switch (key) {
|
|
30
|
+
case 'delimiter':
|
|
31
|
+
result.delimiter = value || ',';
|
|
32
|
+
break;
|
|
33
|
+
case 'no-headers':
|
|
34
|
+
result.noHeaders = true;
|
|
35
|
+
break;
|
|
36
|
+
case 'help':
|
|
37
|
+
result.help = true;
|
|
38
|
+
break;
|
|
39
|
+
case 'version':
|
|
40
|
+
result.version = true;
|
|
41
|
+
break;
|
|
42
|
+
default:
|
|
43
|
+
console.warn(`Warning: Unknown option --${key}`);
|
|
44
|
+
}
|
|
45
|
+
} else if (!result.input) {
|
|
46
|
+
result.input = arg;
|
|
47
|
+
} else if (!result.output) {
|
|
48
|
+
result.output = arg;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Show help
|
|
56
|
+
function showHelp() {
|
|
57
|
+
console.log(`
|
|
58
|
+
jtcsv CLI Tool - Convert JSON files to CSV
|
|
59
|
+
`);
|
|
60
|
+
console.log('Usage:');
|
|
61
|
+
console.log(' node cli-tool.js <input.json> [output.csv] [options]');
|
|
62
|
+
console.log(' node cli-tool.js --help');
|
|
63
|
+
console.log(' node cli-tool.js --version');
|
|
64
|
+
console.log('');
|
|
65
|
+
console.log('Arguments:');
|
|
66
|
+
console.log(' input.json Input JSON file (required)');
|
|
67
|
+
console.log(' output.csv Output CSV file (optional, prints to stdout if not provided)');
|
|
68
|
+
console.log('');
|
|
69
|
+
console.log('Options:');
|
|
70
|
+
console.log(' --delimiter=<char> CSV delimiter (default: ;)');
|
|
71
|
+
console.log(' --no-headers Do not include headers in output');
|
|
72
|
+
console.log(' --help Show this help message');
|
|
73
|
+
console.log(' --version Show version');
|
|
74
|
+
console.log('');
|
|
75
|
+
console.log('Examples:');
|
|
76
|
+
console.log(' # Convert data.json to data.csv with comma delimiter');
|
|
77
|
+
console.log(' node cli-tool.js data.json data.csv --delimiter=,');
|
|
78
|
+
console.log('');
|
|
79
|
+
console.log(' # Convert and print to console');
|
|
80
|
+
console.log(' node cli-tool.js data.json');
|
|
81
|
+
console.log('');
|
|
82
|
+
console.log(' # Convert without headers');
|
|
83
|
+
console.log(' node cli-tool.js data.json output.csv --no-headers');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Show version
|
|
87
|
+
function showVersion() {
|
|
88
|
+
import packageJson from "../package.json";
|
|
89
|
+
console.log(`jtcsv CLI Tool v${packageJson.version}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Read JSON file
|
|
93
|
+
function readJsonFile(filePath) {
|
|
94
|
+
try {
|
|
95
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
96
|
+
return JSON.parse(content);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
if (error.code === 'ENOENT') {
|
|
99
|
+
throw new Error(`File not found: ${filePath}`);
|
|
100
|
+
} else if (error instanceof SyntaxError) {
|
|
101
|
+
throw new Error(`Invalid JSON in file: ${filePath}`);
|
|
102
|
+
}
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Main function
|
|
108
|
+
async function main() {
|
|
109
|
+
const args = parseArgs();
|
|
110
|
+
|
|
111
|
+
if (args.help) {
|
|
112
|
+
showHelp();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (args.version) {
|
|
117
|
+
showVersion();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!args.input) {
|
|
122
|
+
console.error('Error: Input file is required');
|
|
123
|
+
showHelp();
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
// Read and validate input
|
|
129
|
+
console.log(`Reading ${args.input}...`);
|
|
130
|
+
const data = readJsonFile(args.input);
|
|
131
|
+
|
|
132
|
+
if (!Array.isArray(data)) {
|
|
133
|
+
throw new Error('JSON data must be an array of objects');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
console.log(`Found ${data.length} records`);
|
|
137
|
+
|
|
138
|
+
// Convert to CSV
|
|
139
|
+
const options = {
|
|
140
|
+
delimiter: args.delimiter,
|
|
141
|
+
includeHeaders: !args.noHeaders
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
if (args.output) {
|
|
145
|
+
// Save to file
|
|
146
|
+
console.log(`Converting to CSV with delimiter '${args.delimiter}'...`);
|
|
147
|
+
|
|
148
|
+
// Using saveAsCsv for better security
|
|
149
|
+
await saveAsCsv(data, args.output, options);
|
|
150
|
+
|
|
151
|
+
const stats = fs.statSync(args.output);
|
|
152
|
+
console.log(`✅ Successfully saved to ${args.output}`);
|
|
153
|
+
console.log(` File size: ${(stats.size / 1024).toFixed(2)} KB`);
|
|
154
|
+
console.log(` Records: ${data.length}`);
|
|
155
|
+
} else {
|
|
156
|
+
// Print to stdout
|
|
157
|
+
const csv = jsonToCsv(data, options);
|
|
158
|
+
console.log(csv);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error(`❌ Error: ${error.message}`);
|
|
163
|
+
|
|
164
|
+
if (error.message.includes('Directory traversal')) {
|
|
165
|
+
console.error(' Security violation: Attempted directory traversal');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Handle uncaught errors
|
|
173
|
+
process.on('uncaughtException', (error) => {
|
|
174
|
+
console.error('Uncaught error:', error.message);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Run if called directly
|
|
179
|
+
if (require.main === module) {
|
|
180
|
+
main();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export default { parseArgs, readJsonFile, showHelp, showVersion };
|
|
@@ -94,13 +94,27 @@ async function comprehensiveErrorHandling() {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
function getErrorTypeName(error) {
|
|
97
|
-
if (error instanceof ValidationError)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (error instanceof
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (error instanceof
|
|
97
|
+
if (error instanceof ValidationError) {
|
|
98
|
+
return 'ValidationError';
|
|
99
|
+
}
|
|
100
|
+
if (error instanceof SecurityError) {
|
|
101
|
+
return 'SecurityError';
|
|
102
|
+
}
|
|
103
|
+
if (error instanceof ParsingError) {
|
|
104
|
+
return 'ParsingError';
|
|
105
|
+
}
|
|
106
|
+
if (error instanceof FileSystemError) {
|
|
107
|
+
return 'FileSystemError';
|
|
108
|
+
}
|
|
109
|
+
if (error instanceof LimitError) {
|
|
110
|
+
return 'LimitError';
|
|
111
|
+
}
|
|
112
|
+
if (error instanceof ConfigurationError) {
|
|
113
|
+
return 'ConfigurationError';
|
|
114
|
+
}
|
|
115
|
+
if (error instanceof JtcsvError) {
|
|
116
|
+
return 'JtcsvError';
|
|
117
|
+
}
|
|
104
118
|
return 'UnknownError';
|
|
105
119
|
}
|
|
106
120
|
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Handling Examples for jtcsv
|
|
3
|
+
*
|
|
4
|
+
* This file demonstrates proper error handling patterns
|
|
5
|
+
* using jtcsv's typed error classes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
csvToJson,
|
|
10
|
+
jsonToCsv,
|
|
11
|
+
saveAsCsv,
|
|
12
|
+
readCsvAsJson,
|
|
13
|
+
// Error classes
|
|
14
|
+
JtcsvError,
|
|
15
|
+
ValidationError,
|
|
16
|
+
SecurityError,
|
|
17
|
+
ParsingError,
|
|
18
|
+
FileSystemError,
|
|
19
|
+
LimitError,
|
|
20
|
+
ConfigurationError,
|
|
21
|
+
CsvToJsonOptions,
|
|
22
|
+
JsonToCsvOptions,
|
|
23
|
+
SaveAsCsvOptions
|
|
24
|
+
} from 'jtcsv';
|
|
25
|
+
|
|
26
|
+
// =============================================================================
|
|
27
|
+
// Example 1: Basic Error Handling
|
|
28
|
+
// =============================================================================
|
|
29
|
+
|
|
30
|
+
function basicErrorHandling(): void {
|
|
31
|
+
console.log('\n=== Basic Error Handling ===\n');
|
|
32
|
+
|
|
33
|
+
// Invalid input type
|
|
34
|
+
try {
|
|
35
|
+
csvToJson(null as any);
|
|
36
|
+
} catch (error: unknown) {
|
|
37
|
+
if (error instanceof ValidationError) {
|
|
38
|
+
console.log('ValidationError caught:', error.message);
|
|
39
|
+
console.log('Error code:', error.code);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Malformed CSV
|
|
44
|
+
const malformedCsv = 'name,age\n"unclosed quote,25';
|
|
45
|
+
try {
|
|
46
|
+
csvToJson(malformedCsv);
|
|
47
|
+
} catch (error: unknown) {
|
|
48
|
+
if (error instanceof ParsingError) {
|
|
49
|
+
console.log('ParsingError caught:', error.message);
|
|
50
|
+
console.log('Line number:', (error as any).lineNumber);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// =============================================================================
|
|
56
|
+
// Example 2: Comprehensive Error Handling with Type Checks
|
|
57
|
+
// =============================================================================
|
|
58
|
+
|
|
59
|
+
async function comprehensiveErrorHandling(): Promise<void> {
|
|
60
|
+
console.log('\n=== Comprehensive Error Handling ===\n');
|
|
61
|
+
|
|
62
|
+
const operations = [
|
|
63
|
+
{
|
|
64
|
+
name: 'Parse invalid CSV',
|
|
65
|
+
action: () => csvToJson(12345 as any) // Not a string
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'Convert non-array to CSV',
|
|
69
|
+
action: () => jsonToCsv('not an array' as any)
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'Read non-existent file',
|
|
73
|
+
action: async () => await readCsvAsJson('./non-existent-file.csv')
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'Exceed row limit',
|
|
77
|
+
action: () => {
|
|
78
|
+
const csv = 'a,b\n' + '1,2\n'.repeat(100);
|
|
79
|
+
return csvToJson(csv, { maxRows: 5 });
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: 'Path traversal attempt',
|
|
84
|
+
action: async () => await saveAsCsv([], '../../../etc/passwd.csv')
|
|
85
|
+
}
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
for (const op of operations) {
|
|
89
|
+
try {
|
|
90
|
+
await op.action();
|
|
91
|
+
console.log(`${op.name}: Success (unexpected)`);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
const errorType = getErrorTypeName(error as Error);
|
|
94
|
+
console.log(`${op.name}: ${errorType} - ${(error as Error).message}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function getErrorTypeName(error: Error): string {
|
|
100
|
+
if (error instanceof ValidationError) {
|
|
101
|
+
return 'ValidationError';
|
|
102
|
+
}
|
|
103
|
+
if (error instanceof SecurityError) {
|
|
104
|
+
return 'SecurityError';
|
|
105
|
+
}
|
|
106
|
+
if (error instanceof ParsingError) {
|
|
107
|
+
return 'ParsingError';
|
|
108
|
+
}
|
|
109
|
+
if (error instanceof FileSystemError) {
|
|
110
|
+
return 'FileSystemError';
|
|
111
|
+
}
|
|
112
|
+
if (error instanceof LimitError) {
|
|
113
|
+
return 'LimitError';
|
|
114
|
+
}
|
|
115
|
+
if (error instanceof ConfigurationError) {
|
|
116
|
+
return 'ConfigurationError';
|
|
117
|
+
}
|
|
118
|
+
if (error instanceof JtcsvError) {
|
|
119
|
+
return 'JtcsvError';
|
|
120
|
+
}
|
|
121
|
+
return 'UnknownError';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// =============================================================================
|
|
125
|
+
// Example 3: Error Recovery Strategies
|
|
126
|
+
// =============================================================================
|
|
127
|
+
|
|
128
|
+
function errorRecoveryStrategies(): void {
|
|
129
|
+
console.log('\n=== Error Recovery Strategies ===\n');
|
|
130
|
+
|
|
131
|
+
// Strategy 1: Fallback to default delimiter
|
|
132
|
+
function parseWithFallback(csv: string): any[] {
|
|
133
|
+
const delimiters = [',', ';', '\t', '|'];
|
|
134
|
+
|
|
135
|
+
for (const delimiter of delimiters) {
|
|
136
|
+
try {
|
|
137
|
+
const result = csvToJson(csv, {
|
|
138
|
+
delimiter,
|
|
139
|
+
autoDetect: false
|
|
140
|
+
});
|
|
141
|
+
console.log(`Successfully parsed with delimiter: "${delimiter}"`);
|
|
142
|
+
return result;
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.log(`Failed with delimiter "${delimiter}": ${(error as Error).message}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
throw new Error('Could not parse CSV with any known delimiter');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const testCsv = 'name|age|city\nJohn|25|NYC\nJane|30|LA';
|
|
151
|
+
const result = parseWithFallback(testCsv);
|
|
152
|
+
console.log('Result:', result);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// =============================================================================
|
|
156
|
+
// Example 4: Batch Processing with Error Collection
|
|
157
|
+
// =============================================================================
|
|
158
|
+
|
|
159
|
+
async function batchProcessingWithErrorCollection(): Promise<void> {
|
|
160
|
+
console.log('\n=== Batch Processing with Error Collection ===\n');
|
|
161
|
+
|
|
162
|
+
const csvFiles = [
|
|
163
|
+
{ name: 'valid.csv', content: 'a,b\n1,2\n3,4' },
|
|
164
|
+
{ name: 'invalid.csv', content: 'a,b\n"unclosed' },
|
|
165
|
+
{ name: 'empty.csv', content: '' },
|
|
166
|
+
{ name: 'valid2.csv', content: 'x,y\n5,6' }
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
const results = {
|
|
170
|
+
successful: [] as Array<{ name: string; rowCount: number }>,
|
|
171
|
+
failed: [] as Array<{ name: string; error: string; errorType: string }>
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
for (const file of csvFiles) {
|
|
175
|
+
try {
|
|
176
|
+
const data = csvToJson(file.content);
|
|
177
|
+
results.successful.push({
|
|
178
|
+
name: file.name,
|
|
179
|
+
rowCount: data.length
|
|
180
|
+
});
|
|
181
|
+
} catch (error) {
|
|
182
|
+
results.failed.push({
|
|
183
|
+
name: file.name,
|
|
184
|
+
error: (error as Error).message,
|
|
185
|
+
errorType: getErrorTypeName(error as Error)
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
console.log('Processing Results:');
|
|
191
|
+
console.log('Successful:', results.successful);
|
|
192
|
+
console.log('Failed:', results.failed);
|
|
193
|
+
console.log(`\nSuccess rate: ${results.successful.length}/${csvFiles.length}`);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// =============================================================================
|
|
197
|
+
// Example 5: Custom Error Handler Wrapper
|
|
198
|
+
// =============================================================================
|
|
199
|
+
|
|
200
|
+
interface SafeParserOptions {
|
|
201
|
+
onError?: (error: Error) => void;
|
|
202
|
+
defaultValue?: any[];
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
interface SafeParseResult {
|
|
206
|
+
success: boolean;
|
|
207
|
+
data: any[];
|
|
208
|
+
error: {
|
|
209
|
+
type: string;
|
|
210
|
+
message: string;
|
|
211
|
+
code?: string;
|
|
212
|
+
} | null;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function createSafeParser(options: SafeParserOptions = {}) {
|
|
216
|
+
const { onError, defaultValue = [] } = options;
|
|
217
|
+
|
|
218
|
+
return function safeParse(csv: string, parseOptions: CsvToJsonOptions = {}): SafeParseResult {
|
|
219
|
+
try {
|
|
220
|
+
return {
|
|
221
|
+
success: true,
|
|
222
|
+
data: csvToJson(csv, parseOptions),
|
|
223
|
+
error: null
|
|
224
|
+
};
|
|
225
|
+
} catch (error) {
|
|
226
|
+
if (onError) {
|
|
227
|
+
onError(error as Error);
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
success: false,
|
|
231
|
+
data: defaultValue,
|
|
232
|
+
error: {
|
|
233
|
+
type: getErrorTypeName(error as Error),
|
|
234
|
+
message: (error as Error).message,
|
|
235
|
+
code: (error as any).code
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function customErrorHandlerDemo(): void {
|
|
243
|
+
console.log('\n=== Custom Error Handler ===\n');
|
|
244
|
+
|
|
245
|
+
const safeParse = createSafeParser({
|
|
246
|
+
onError: (error: Error) => {
|
|
247
|
+
console.log(`[Logger] Error occurred: ${error.message}`);
|
|
248
|
+
},
|
|
249
|
+
defaultValue: []
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// Test with valid CSV
|
|
253
|
+
const result1 = safeParse('a,b\n1,2');
|
|
254
|
+
console.log('Valid CSV result:', result1);
|
|
255
|
+
|
|
256
|
+
// Test with invalid CSV
|
|
257
|
+
const result2 = safeParse(null as any);
|
|
258
|
+
console.log('Invalid CSV result:', result2);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// =============================================================================
|
|
262
|
+
// Example 6: Async Error Handling with Retries
|
|
263
|
+
// =============================================================================
|
|
264
|
+
|
|
265
|
+
async function asyncWithRetries(): Promise<void> {
|
|
266
|
+
console.log('\n=== Async Error Handling with Retries ===\n');
|
|
267
|
+
|
|
268
|
+
async function readWithRetry(filePath: string, maxRetries = 3): Promise<any[]> {
|
|
269
|
+
let lastError: Error | undefined;
|
|
270
|
+
|
|
271
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
272
|
+
try {
|
|
273
|
+
console.log(`Attempt ${attempt}: Reading ${filePath}`);
|
|
274
|
+
const data = await readCsvAsJson(filePath);
|
|
275
|
+
return data;
|
|
276
|
+
} catch (error) {
|
|
277
|
+
lastError = error as Error;
|
|
278
|
+
console.log(`Attempt ${attempt} failed: ${(error as Error).message}`);
|
|
279
|
+
|
|
280
|
+
if (error instanceof FileSystemError) {
|
|
281
|
+
// File system errors might be transient
|
|
282
|
+
await new Promise(r => setTimeout(r, 100 * attempt));
|
|
283
|
+
} else if (error instanceof ValidationError) {
|
|
284
|
+
// Validation errors won't resolve with retry
|
|
285
|
+
throw error;
|
|
286
|
+
} else if (error instanceof SecurityError) {
|
|
287
|
+
// Security errors should not be retried
|
|
288
|
+
throw error;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
throw lastError;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
try {
|
|
297
|
+
await readWithRetry('./test-data.csv');
|
|
298
|
+
} catch (error) {
|
|
299
|
+
console.log(`All retries failed: ${(error as Error).message}`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// =============================================================================
|
|
304
|
+
// Example 7: Schema Validation Error Details
|
|
305
|
+
// =============================================================================
|
|
306
|
+
|
|
307
|
+
function schemaValidationErrors(): void {
|
|
308
|
+
console.log('\n=== Schema Validation Errors ===\n');
|
|
309
|
+
|
|
310
|
+
const schema = {
|
|
311
|
+
type: 'object',
|
|
312
|
+
required: ['name', 'age'],
|
|
313
|
+
properties: {
|
|
314
|
+
name: { type: 'string', minLength: 1 },
|
|
315
|
+
age: { type: 'number', minimum: 0, maximum: 150 }
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
const data = [
|
|
320
|
+
{ name: 'John', age: 25 },
|
|
321
|
+
{ name: '', age: 30 }, // Invalid: empty name
|
|
322
|
+
{ name: 'Jane', age: -5 }, // Invalid: negative age
|
|
323
|
+
{ name: 'Bob', age: 200 } // Invalid: age > 150
|
|
324
|
+
];
|
|
325
|
+
|
|
326
|
+
try {
|
|
327
|
+
jsonToCsv(data, { schema });
|
|
328
|
+
} catch (error: unknown) {
|
|
329
|
+
if (error instanceof ValidationError) {
|
|
330
|
+
console.log('Schema validation failed:');
|
|
331
|
+
console.log('Message:', error.message);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// =============================================================================
|
|
337
|
+
// Run All Examples
|
|
338
|
+
// =============================================================================
|
|
339
|
+
|
|
340
|
+
async function main(): Promise<void> {
|
|
341
|
+
console.log('jtcsv Error Handling Examples\n');
|
|
342
|
+
console.log('='.repeat(60));
|
|
343
|
+
|
|
344
|
+
basicErrorHandling();
|
|
345
|
+
await comprehensiveErrorHandling();
|
|
346
|
+
errorRecoveryStrategies();
|
|
347
|
+
await batchProcessingWithErrorCollection();
|
|
348
|
+
customErrorHandlerDemo();
|
|
349
|
+
await asyncWithRetries();
|
|
350
|
+
schemaValidationErrors();
|
|
351
|
+
|
|
352
|
+
console.log('\n' + '='.repeat(60));
|
|
353
|
+
console.log('All examples completed.');
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
main().catch(console.error);
|