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.
Files changed (246) hide show
  1. package/README.md +204 -115
  2. package/bin/jtcsv.ts +2612 -0
  3. package/browser.d.ts +142 -0
  4. package/dist/benchmark.js +446 -0
  5. package/dist/benchmark.js.map +1 -0
  6. package/dist/bin/jtcsv.js +1940 -0
  7. package/dist/bin/jtcsv.js.map +1 -0
  8. package/dist/csv-to-json.js +1262 -0
  9. package/dist/csv-to-json.js.map +1 -0
  10. package/dist/errors.js +291 -0
  11. package/dist/errors.js.map +1 -0
  12. package/dist/eslint.config.js +147 -0
  13. package/dist/eslint.config.js.map +1 -0
  14. package/dist/index-core.js +95 -0
  15. package/dist/index-core.js.map +1 -0
  16. package/dist/index.js +93 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/json-save.js +229 -0
  19. package/dist/json-save.js.map +1 -0
  20. package/dist/json-to-csv.js +576 -0
  21. package/dist/json-to-csv.js.map +1 -0
  22. package/dist/jtcsv-core.cjs.js +1736 -0
  23. package/dist/jtcsv-core.cjs.js.map +1 -0
  24. package/dist/jtcsv-core.esm.js +1708 -0
  25. package/dist/jtcsv-core.esm.js.map +1 -0
  26. package/dist/jtcsv-core.umd.js +1742 -0
  27. package/dist/jtcsv-core.umd.js.map +1 -0
  28. package/dist/jtcsv-full.cjs.js +2241 -0
  29. package/dist/jtcsv-full.cjs.js.map +1 -0
  30. package/dist/jtcsv-full.esm.js +2209 -0
  31. package/dist/jtcsv-full.esm.js.map +1 -0
  32. package/dist/jtcsv-full.umd.js +2247 -0
  33. package/dist/jtcsv-full.umd.js.map +1 -0
  34. package/dist/jtcsv-workers.esm.js +768 -0
  35. package/dist/jtcsv-workers.esm.js.map +1 -0
  36. package/dist/jtcsv-workers.umd.js +782 -0
  37. package/dist/jtcsv-workers.umd.js.map +1 -0
  38. package/dist/jtcsv.cjs.js +1996 -2048
  39. package/dist/jtcsv.cjs.js.map +1 -1
  40. package/dist/jtcsv.esm.js +1992 -2048
  41. package/dist/jtcsv.esm.js.map +1 -1
  42. package/dist/jtcsv.umd.js +2157 -2209
  43. package/dist/jtcsv.umd.js.map +1 -1
  44. package/dist/plugins/express-middleware/index.js +350 -0
  45. package/dist/plugins/express-middleware/index.js.map +1 -0
  46. package/dist/plugins/fastify-plugin/index.js +315 -0
  47. package/dist/plugins/fastify-plugin/index.js.map +1 -0
  48. package/dist/plugins/hono/index.js +111 -0
  49. package/dist/plugins/hono/index.js.map +1 -0
  50. package/dist/plugins/nestjs/index.js +112 -0
  51. package/dist/plugins/nestjs/index.js.map +1 -0
  52. package/dist/plugins/nuxt/index.js +53 -0
  53. package/dist/plugins/nuxt/index.js.map +1 -0
  54. package/dist/plugins/remix/index.js +133 -0
  55. package/dist/plugins/remix/index.js.map +1 -0
  56. package/dist/plugins/sveltekit/index.js +155 -0
  57. package/dist/plugins/sveltekit/index.js.map +1 -0
  58. package/dist/plugins/trpc/index.js +136 -0
  59. package/dist/plugins/trpc/index.js.map +1 -0
  60. package/dist/run-demo.js +49 -0
  61. package/dist/run-demo.js.map +1 -0
  62. package/dist/src/browser/browser-functions.js +193 -0
  63. package/dist/src/browser/browser-functions.js.map +1 -0
  64. package/dist/src/browser/core.js +123 -0
  65. package/dist/src/browser/core.js.map +1 -0
  66. package/dist/src/browser/csv-to-json-browser.js +353 -0
  67. package/dist/src/browser/csv-to-json-browser.js.map +1 -0
  68. package/dist/src/browser/errors-browser.js +219 -0
  69. package/dist/src/browser/errors-browser.js.map +1 -0
  70. package/dist/src/browser/extensions/plugins.js +106 -0
  71. package/dist/src/browser/extensions/plugins.js.map +1 -0
  72. package/dist/src/browser/extensions/workers.js +66 -0
  73. package/dist/src/browser/extensions/workers.js.map +1 -0
  74. package/dist/src/browser/index.js +140 -0
  75. package/dist/src/browser/index.js.map +1 -0
  76. package/dist/src/browser/json-to-csv-browser.js +225 -0
  77. package/dist/src/browser/json-to-csv-browser.js.map +1 -0
  78. package/dist/src/browser/streams.js +340 -0
  79. package/dist/src/browser/streams.js.map +1 -0
  80. package/dist/src/browser/workers/csv-parser.worker.js +264 -0
  81. package/dist/src/browser/workers/csv-parser.worker.js.map +1 -0
  82. package/dist/src/browser/workers/worker-pool.js +338 -0
  83. package/dist/src/browser/workers/worker-pool.js.map +1 -0
  84. package/dist/src/core/delimiter-cache.js +196 -0
  85. package/dist/src/core/delimiter-cache.js.map +1 -0
  86. package/dist/src/core/node-optimizations.js +279 -0
  87. package/dist/src/core/node-optimizations.js.map +1 -0
  88. package/dist/src/core/plugin-system.js +399 -0
  89. package/dist/src/core/plugin-system.js.map +1 -0
  90. package/dist/src/core/transform-hooks.js +348 -0
  91. package/dist/src/core/transform-hooks.js.map +1 -0
  92. package/dist/src/engines/fast-path-engine-new.js +262 -0
  93. package/dist/src/engines/fast-path-engine-new.js.map +1 -0
  94. package/dist/src/engines/fast-path-engine.js +671 -0
  95. package/dist/src/engines/fast-path-engine.js.map +1 -0
  96. package/dist/src/errors.js +18 -0
  97. package/dist/src/errors.js.map +1 -0
  98. package/dist/src/formats/ndjson-parser.js +332 -0
  99. package/dist/src/formats/ndjson-parser.js.map +1 -0
  100. package/dist/src/formats/tsv-parser.js +230 -0
  101. package/dist/src/formats/tsv-parser.js.map +1 -0
  102. package/dist/src/index-with-plugins.js +259 -0
  103. package/dist/src/index-with-plugins.js.map +1 -0
  104. package/dist/src/types/index.js +3 -0
  105. package/dist/src/types/index.js.map +1 -0
  106. package/dist/src/utils/bom-utils.js +267 -0
  107. package/dist/src/utils/bom-utils.js.map +1 -0
  108. package/dist/src/utils/encoding-support.js +77 -0
  109. package/dist/src/utils/encoding-support.js.map +1 -0
  110. package/dist/src/utils/schema-validator.js +609 -0
  111. package/dist/src/utils/schema-validator.js.map +1 -0
  112. package/dist/src/utils/transform-loader.js +281 -0
  113. package/dist/src/utils/transform-loader.js.map +1 -0
  114. package/dist/src/utils/validators.js +40 -0
  115. package/dist/src/utils/validators.js.map +1 -0
  116. package/dist/src/utils/zod-adapter.js +144 -0
  117. package/dist/src/utils/zod-adapter.js.map +1 -0
  118. package/dist/src/web-server/index.js +648 -0
  119. package/dist/src/web-server/index.js.map +1 -0
  120. package/dist/src/workers/csv-multithreaded.js +211 -0
  121. package/dist/src/workers/csv-multithreaded.js.map +1 -0
  122. package/dist/src/workers/csv-parser.worker.js +179 -0
  123. package/dist/src/workers/csv-parser.worker.js.map +1 -0
  124. package/dist/src/workers/worker-pool.js +228 -0
  125. package/dist/src/workers/worker-pool.js.map +1 -0
  126. package/dist/stream-csv-to-json.js +665 -0
  127. package/dist/stream-csv-to-json.js.map +1 -0
  128. package/dist/stream-json-to-csv.js +389 -0
  129. package/dist/stream-json-to-csv.js.map +1 -0
  130. package/examples/advanced/conditional-transformations.ts +446 -0
  131. package/examples/advanced/csv-parser.worker.ts +89 -0
  132. package/examples/advanced/nested-objects-example.ts +306 -0
  133. package/examples/advanced/performance-optimization.ts +504 -0
  134. package/examples/advanced/run-demo-server.ts +116 -0
  135. package/examples/advanced/web-worker-usage.html +874 -0
  136. package/examples/async-multithreaded-example.ts +335 -0
  137. package/examples/cli-advanced-usage.md +290 -0
  138. package/examples/{cli-batch-processing.js → cli-batch-processing.ts} +38 -38
  139. package/examples/{cli-tool.js → cli-tool.ts} +5 -8
  140. package/examples/{error-handling.js → error-handling.ts} +356 -324
  141. package/examples/{express-api.js → express-api.ts} +161 -164
  142. package/examples/{large-dataset-example.js → large-dataset-example.ts} +201 -182
  143. package/examples/{ndjson-processing.js → ndjson-processing.ts} +456 -434
  144. package/examples/{plugin-excel-exporter.js → plugin-excel-exporter.ts} +6 -7
  145. package/examples/react-integration.tsx +637 -0
  146. package/examples/{schema-validation.js → schema-validation.ts} +2 -2
  147. package/examples/simple-usage.ts +194 -0
  148. package/examples/{streaming-example.js → streaming-example.ts} +12 -12
  149. package/index.d.ts +187 -18
  150. package/package.json +75 -81
  151. package/plugins.d.ts +37 -0
  152. package/schema.d.ts +103 -0
  153. package/src/browser/browser-functions.ts +402 -0
  154. package/src/browser/core.ts +152 -0
  155. package/src/browser/csv-to-json-browser.d.ts +3 -0
  156. package/src/browser/csv-to-json-browser.ts +494 -0
  157. package/src/browser/{errors-browser.js → errors-browser.ts} +305 -197
  158. package/src/browser/extensions/plugins.ts +93 -0
  159. package/src/browser/extensions/workers.ts +39 -0
  160. package/src/browser/globals.d.ts +5 -0
  161. package/src/browser/index.ts +192 -0
  162. package/src/browser/json-to-csv-browser.d.ts +3 -0
  163. package/src/browser/json-to-csv-browser.ts +338 -0
  164. package/src/browser/streams.ts +403 -0
  165. package/src/browser/workers/{csv-parser.worker.js → csv-parser.worker.ts} +3 -3
  166. package/src/browser/workers/{worker-pool.js → worker-pool.ts} +51 -30
  167. package/src/core/delimiter-cache.ts +320 -0
  168. package/src/core/{node-optimizations.js → node-optimizations.ts} +448 -407
  169. package/src/core/plugin-system.ts +588 -0
  170. package/src/core/transform-hooks.ts +566 -0
  171. package/src/engines/{fast-path-engine-new.js → fast-path-engine-new.ts} +11 -2
  172. package/src/engines/{fast-path-engine.js → fast-path-engine.ts} +79 -53
  173. package/src/errors.ts +1 -0
  174. package/src/formats/{ndjson-parser.js → ndjson-parser.ts} +24 -16
  175. package/src/formats/{tsv-parser.js → tsv-parser.ts} +18 -17
  176. package/src/{index-with-plugins.js → index-with-plugins.ts} +381 -357
  177. package/src/types/index.ts +275 -0
  178. package/src/utils/bom-utils.ts +373 -0
  179. package/src/utils/encoding-support.ts +155 -0
  180. package/src/utils/{schema-validator.js → schema-validator.ts} +814 -589
  181. package/src/utils/transform-loader.ts +389 -0
  182. package/src/utils/validators.ts +35 -0
  183. package/src/utils/zod-adapter.ts +280 -0
  184. package/src/web-server/{index.js → index.ts} +19 -19
  185. package/src/workers/csv-multithreaded.ts +310 -0
  186. package/src/workers/csv-parser.worker.ts +227 -0
  187. package/src/workers/worker-pool.ts +409 -0
  188. package/bin/jtcsv.js +0 -2462
  189. package/csv-to-json.js +0 -688
  190. package/errors.js +0 -208
  191. package/examples/simple-usage.js +0 -282
  192. package/index.js +0 -68
  193. package/json-save.js +0 -254
  194. package/json-to-csv.js +0 -526
  195. package/plugins/README.md +0 -91
  196. package/plugins/express-middleware/README.md +0 -64
  197. package/plugins/express-middleware/example.js +0 -136
  198. package/plugins/express-middleware/index.d.ts +0 -114
  199. package/plugins/express-middleware/index.js +0 -360
  200. package/plugins/express-middleware/package.json +0 -52
  201. package/plugins/fastify-plugin/index.js +0 -406
  202. package/plugins/fastify-plugin/package.json +0 -55
  203. package/plugins/hono/README.md +0 -28
  204. package/plugins/hono/index.d.ts +0 -12
  205. package/plugins/hono/index.js +0 -36
  206. package/plugins/hono/package.json +0 -35
  207. package/plugins/nestjs/README.md +0 -35
  208. package/plugins/nestjs/index.d.ts +0 -25
  209. package/plugins/nestjs/index.js +0 -77
  210. package/plugins/nestjs/package.json +0 -37
  211. package/plugins/nextjs-api/README.md +0 -57
  212. package/plugins/nextjs-api/examples/ConverterComponent.jsx +0 -386
  213. package/plugins/nextjs-api/examples/api-convert.js +0 -69
  214. package/plugins/nextjs-api/index.js +0 -387
  215. package/plugins/nextjs-api/package.json +0 -63
  216. package/plugins/nextjs-api/route.js +0 -371
  217. package/plugins/nuxt/README.md +0 -24
  218. package/plugins/nuxt/index.js +0 -21
  219. package/plugins/nuxt/package.json +0 -35
  220. package/plugins/nuxt/runtime/composables/useJtcsv.js +0 -6
  221. package/plugins/nuxt/runtime/plugin.js +0 -6
  222. package/plugins/remix/README.md +0 -26
  223. package/plugins/remix/index.d.ts +0 -16
  224. package/plugins/remix/index.js +0 -62
  225. package/plugins/remix/package.json +0 -35
  226. package/plugins/sveltekit/README.md +0 -28
  227. package/plugins/sveltekit/index.d.ts +0 -17
  228. package/plugins/sveltekit/index.js +0 -54
  229. package/plugins/sveltekit/package.json +0 -33
  230. package/plugins/trpc/README.md +0 -25
  231. package/plugins/trpc/index.d.ts +0 -7
  232. package/plugins/trpc/index.js +0 -32
  233. package/plugins/trpc/package.json +0 -34
  234. package/src/browser/browser-functions.js +0 -219
  235. package/src/browser/csv-to-json-browser.js +0 -700
  236. package/src/browser/index.js +0 -113
  237. package/src/browser/json-to-csv-browser.js +0 -309
  238. package/src/browser/streams.js +0 -393
  239. package/src/core/delimiter-cache.js +0 -186
  240. package/src/core/plugin-system.js +0 -476
  241. package/src/core/transform-hooks.js +0 -350
  242. package/src/errors.js +0 -26
  243. package/src/utils/transform-loader.js +0 -205
  244. package/stream-csv-to-json.js +0 -542
  245. package/stream-json-to-csv.js +0 -464
  246. /package/examples/{web-workers-advanced.js → web-workers-advanced.ts} +0 -0
@@ -1,324 +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
- const {
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
- } = require('jtcsv');
22
-
23
- // =============================================================================
24
- // Example 1: Basic Error Handling
25
- // =============================================================================
26
-
27
- function basicErrorHandling() {
28
- console.log('\n=== Basic Error Handling ===\n');
29
-
30
- // Invalid input type
31
- try {
32
- csvToJson(null);
33
- } catch (error) {
34
- if (error instanceof ValidationError) {
35
- console.log('ValidationError caught:', error.message);
36
- console.log('Error code:', error.code);
37
- }
38
- }
39
-
40
- // Malformed CSV
41
- const malformedCsv = 'name,age\n"unclosed quote,25';
42
- try {
43
- csvToJson(malformedCsv);
44
- } catch (error) {
45
- if (error instanceof ParsingError) {
46
- console.log('ParsingError caught:', error.message);
47
- console.log('Line number:', error.lineNumber);
48
- }
49
- }
50
- }
51
-
52
- // =============================================================================
53
- // Example 2: Comprehensive Error Handling with Type Checks
54
- // =============================================================================
55
-
56
- async function comprehensiveErrorHandling() {
57
- console.log('\n=== Comprehensive Error Handling ===\n');
58
-
59
- const operations = [
60
- {
61
- name: 'Parse invalid CSV',
62
- action: () => csvToJson(12345) // Not a string
63
- },
64
- {
65
- name: 'Convert non-array to CSV',
66
- action: () => jsonToCsv('not an array')
67
- },
68
- {
69
- name: 'Read non-existent file',
70
- action: async () => await readCsvAsJson('./non-existent-file.csv')
71
- },
72
- {
73
- name: 'Exceed row limit',
74
- action: () => {
75
- const csv = 'a,b\n' + '1,2\n'.repeat(100);
76
- return csvToJson(csv, { maxRows: 5 });
77
- }
78
- },
79
- {
80
- name: 'Path traversal attempt',
81
- action: async () => await saveAsCsv([], '../../../etc/passwd.csv')
82
- }
83
- ];
84
-
85
- for (const op of operations) {
86
- try {
87
- await op.action();
88
- console.log(`${op.name}: Success (unexpected)`);
89
- } catch (error) {
90
- const errorType = getErrorTypeName(error);
91
- console.log(`${op.name}: ${errorType} - ${error.message}`);
92
- }
93
- }
94
- }
95
-
96
- function getErrorTypeName(error) {
97
- if (error instanceof ValidationError) return 'ValidationError';
98
- if (error instanceof SecurityError) return 'SecurityError';
99
- if (error instanceof ParsingError) return 'ParsingError';
100
- if (error instanceof FileSystemError) return 'FileSystemError';
101
- if (error instanceof LimitError) return 'LimitError';
102
- if (error instanceof ConfigurationError) return 'ConfigurationError';
103
- if (error instanceof JtcsvError) return 'JtcsvError';
104
- return 'UnknownError';
105
- }
106
-
107
- // =============================================================================
108
- // Example 3: Error Recovery Strategies
109
- // =============================================================================
110
-
111
- function errorRecoveryStrategies() {
112
- console.log('\n=== Error Recovery Strategies ===\n');
113
-
114
- // Strategy 1: Fallback to default delimiter
115
- function parseWithFallback(csv) {
116
- const delimiters = [',', ';', '\t', '|'];
117
-
118
- for (const delimiter of delimiters) {
119
- try {
120
- const result = csvToJson(csv, {
121
- delimiter,
122
- autoDetect: false
123
- });
124
- console.log(`Successfully parsed with delimiter: "${delimiter}"`);
125
- return result;
126
- } catch (error) {
127
- console.log(`Failed with delimiter "${delimiter}": ${error.message}`);
128
- }
129
- }
130
- throw new Error('Could not parse CSV with any known delimiter');
131
- }
132
-
133
- const testCsv = 'name|age|city\nJohn|25|NYC\nJane|30|LA';
134
- const result = parseWithFallback(testCsv);
135
- console.log('Result:', result);
136
- }
137
-
138
- // =============================================================================
139
- // Example 4: Batch Processing with Error Collection
140
- // =============================================================================
141
-
142
- async function batchProcessingWithErrorCollection() {
143
- console.log('\n=== Batch Processing with Error Collection ===\n');
144
-
145
- const csvFiles = [
146
- { name: 'valid.csv', content: 'a,b\n1,2\n3,4' },
147
- { name: 'invalid.csv', content: 'a,b\n"unclosed' },
148
- { name: 'empty.csv', content: '' },
149
- { name: 'valid2.csv', content: 'x,y\n5,6' }
150
- ];
151
-
152
- const results = {
153
- successful: [],
154
- failed: []
155
- };
156
-
157
- for (const file of csvFiles) {
158
- try {
159
- const data = csvToJson(file.content);
160
- results.successful.push({
161
- name: file.name,
162
- rowCount: data.length
163
- });
164
- } catch (error) {
165
- results.failed.push({
166
- name: file.name,
167
- error: error.message,
168
- errorType: getErrorTypeName(error)
169
- });
170
- }
171
- }
172
-
173
- console.log('Processing Results:');
174
- console.log('Successful:', results.successful);
175
- console.log('Failed:', results.failed);
176
- console.log(`\nSuccess rate: ${results.successful.length}/${csvFiles.length}`);
177
- }
178
-
179
- // =============================================================================
180
- // Example 5: Custom Error Handler Wrapper
181
- // =============================================================================
182
-
183
- function createSafeParser(options = {}) {
184
- const { onError, defaultValue = [] } = options;
185
-
186
- return function safeParse(csv, parseOptions = {}) {
187
- try {
188
- return {
189
- success: true,
190
- data: csvToJson(csv, parseOptions),
191
- error: null
192
- };
193
- } catch (error) {
194
- if (onError) {
195
- onError(error);
196
- }
197
- return {
198
- success: false,
199
- data: defaultValue,
200
- error: {
201
- type: getErrorTypeName(error),
202
- message: error.message,
203
- code: error.code
204
- }
205
- };
206
- }
207
- };
208
- }
209
-
210
- function customErrorHandlerDemo() {
211
- console.log('\n=== Custom Error Handler ===\n');
212
-
213
- const safeParse = createSafeParser({
214
- onError: (error) => {
215
- console.log(`[Logger] Error occurred: ${error.message}`);
216
- },
217
- defaultValue: []
218
- });
219
-
220
- // Test with valid CSV
221
- const result1 = safeParse('a,b\n1,2');
222
- console.log('Valid CSV result:', result1);
223
-
224
- // Test with invalid CSV
225
- const result2 = safeParse(null);
226
- console.log('Invalid CSV result:', result2);
227
- }
228
-
229
- // =============================================================================
230
- // Example 6: Async Error Handling with Retries
231
- // =============================================================================
232
-
233
- async function asyncWithRetries() {
234
- console.log('\n=== Async Error Handling with Retries ===\n');
235
-
236
- async function readWithRetry(filePath, maxRetries = 3) {
237
- let lastError;
238
-
239
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
240
- try {
241
- console.log(`Attempt ${attempt}: Reading ${filePath}`);
242
- const data = await readCsvAsJson(filePath);
243
- return data;
244
- } catch (error) {
245
- lastError = error;
246
- console.log(`Attempt ${attempt} failed: ${error.message}`);
247
-
248
- if (error instanceof FileSystemError) {
249
- // File system errors might be transient
250
- await new Promise(r => setTimeout(r, 100 * attempt));
251
- } else if (error instanceof ValidationError) {
252
- // Validation errors won't resolve with retry
253
- throw error;
254
- } else if (error instanceof SecurityError) {
255
- // Security errors should not be retried
256
- throw error;
257
- }
258
- }
259
- }
260
-
261
- throw lastError;
262
- }
263
-
264
- try {
265
- await readWithRetry('./test-data.csv');
266
- } catch (error) {
267
- console.log(`All retries failed: ${error.message}`);
268
- }
269
- }
270
-
271
- // =============================================================================
272
- // Example 7: Schema Validation Error Details
273
- // =============================================================================
274
-
275
- function schemaValidationErrors() {
276
- console.log('\n=== Schema Validation Errors ===\n');
277
-
278
- const schema = {
279
- type: 'object',
280
- required: ['name', 'age'],
281
- properties: {
282
- name: { type: 'string', minLength: 1 },
283
- age: { type: 'number', minimum: 0, maximum: 150 }
284
- }
285
- };
286
-
287
- const data = [
288
- { name: 'John', age: 25 },
289
- { name: '', age: 30 }, // Invalid: empty name
290
- { name: 'Jane', age: -5 }, // Invalid: negative age
291
- { name: 'Bob', age: 200 } // Invalid: age > 150
292
- ];
293
-
294
- try {
295
- jsonToCsv(data, { schema });
296
- } catch (error) {
297
- if (error instanceof ValidationError) {
298
- console.log('Schema validation failed:');
299
- console.log('Message:', error.message);
300
- }
301
- }
302
- }
303
-
304
- // =============================================================================
305
- // Run All Examples
306
- // =============================================================================
307
-
308
- async function main() {
309
- console.log('jtcsv Error Handling Examples\n');
310
- console.log('='.repeat(60));
311
-
312
- basicErrorHandling();
313
- await comprehensiveErrorHandling();
314
- errorRecoveryStrategies();
315
- await batchProcessingWithErrorCollection();
316
- customErrorHandlerDemo();
317
- await asyncWithRetries();
318
- schemaValidationErrors();
319
-
320
- console.log('\n' + '='.repeat(60));
321
- console.log('All examples completed.');
322
- }
323
-
324
- main().catch(console.error);
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);