jtcsv 3.0.0 → 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 (258) hide show
  1. package/README.md +205 -146
  2. package/bin/jtcsv.ts +280 -202
  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 +336 -7
  23. package/dist/jtcsv-core.cjs.js.map +1 -1
  24. package/dist/jtcsv-core.esm.js +336 -7
  25. package/dist/jtcsv-core.esm.js.map +1 -1
  26. package/dist/jtcsv-core.umd.js +336 -7
  27. package/dist/jtcsv-core.umd.js.map +1 -1
  28. package/dist/jtcsv-full.cjs.js +336 -7
  29. package/dist/jtcsv-full.cjs.js.map +1 -1
  30. package/dist/jtcsv-full.esm.js +336 -7
  31. package/dist/jtcsv-full.esm.js.map +1 -1
  32. package/dist/jtcsv-full.umd.js +336 -7
  33. package/dist/jtcsv-full.umd.js.map +1 -1
  34. package/dist/jtcsv-workers.esm.js +9 -0
  35. package/dist/jtcsv-workers.esm.js.map +1 -1
  36. package/dist/jtcsv-workers.umd.js +9 -0
  37. package/dist/jtcsv-workers.umd.js.map +1 -1
  38. package/dist/jtcsv.cjs.js +1998 -2092
  39. package/dist/jtcsv.cjs.js.map +1 -1
  40. package/dist/jtcsv.esm.js +1994 -2092
  41. package/dist/jtcsv.esm.js.map +1 -1
  42. package/dist/jtcsv.umd.js +2157 -2251
  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/{src → dist/src}/web-server/index.js +251 -286
  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 +2 -2
  131. package/examples/advanced/performance-optimization.ts +2 -2
  132. package/examples/cli-advanced-usage.md +2 -0
  133. package/examples/cli-tool.ts +1 -1
  134. package/examples/large-dataset-example.ts +2 -2
  135. package/examples/simple-usage.ts +2 -2
  136. package/examples/streaming-example.ts +1 -1
  137. package/index.d.ts +186 -15
  138. package/package.json +43 -108
  139. package/plugins.d.ts +37 -0
  140. package/schema.d.ts +103 -0
  141. package/src/browser/csv-to-json-browser.ts +233 -3
  142. package/src/browser/errors-browser.ts +45 -28
  143. package/src/browser/json-to-csv-browser.ts +81 -5
  144. package/src/browser/streams.ts +73 -6
  145. package/src/core/delimiter-cache.ts +21 -11
  146. package/src/core/plugin-system.ts +343 -155
  147. package/src/core/transform-hooks.ts +20 -12
  148. package/src/engines/fast-path-engine.ts +48 -32
  149. package/src/errors.ts +1 -72
  150. package/src/formats/ndjson-parser.ts +6 -0
  151. package/src/formats/tsv-parser.ts +6 -0
  152. package/src/types/index.ts +21 -1
  153. package/src/utils/validators.ts +35 -0
  154. package/src/web-server/index.ts +1 -1
  155. package/bin/jtcsv.js +0 -2532
  156. package/csv-to-json.js +0 -711
  157. package/errors.js +0 -394
  158. package/examples/advanced/conditional-transformations.js +0 -446
  159. package/examples/advanced/csv-parser.worker.js +0 -89
  160. package/examples/advanced/nested-objects-example.js +0 -306
  161. package/examples/advanced/performance-optimization.js +0 -504
  162. package/examples/advanced/run-demo-server.js +0 -116
  163. package/examples/cli-batch-processing.js +0 -38
  164. package/examples/cli-tool.js +0 -183
  165. package/examples/error-handling.js +0 -338
  166. package/examples/express-api.js +0 -164
  167. package/examples/large-dataset-example.js +0 -182
  168. package/examples/ndjson-processing.js +0 -434
  169. package/examples/plugin-excel-exporter.js +0 -406
  170. package/examples/schema-validation.js +0 -640
  171. package/examples/simple-usage.js +0 -282
  172. package/examples/streaming-example.js +0 -418
  173. package/examples/web-workers-advanced.js +0 -28
  174. package/index.js +0 -82
  175. package/json-save.js +0 -255
  176. package/json-to-csv.js +0 -668
  177. package/plugins/README.md +0 -91
  178. package/plugins/express-middleware/README.md +0 -83
  179. package/plugins/express-middleware/example.js +0 -135
  180. package/plugins/express-middleware/example.ts +0 -135
  181. package/plugins/express-middleware/index.d.ts +0 -114
  182. package/plugins/express-middleware/index.js +0 -512
  183. package/plugins/express-middleware/index.ts +0 -557
  184. package/plugins/express-middleware/package.json +0 -52
  185. package/plugins/fastify-plugin/index.js +0 -404
  186. package/plugins/fastify-plugin/index.ts +0 -443
  187. package/plugins/fastify-plugin/package.json +0 -55
  188. package/plugins/hono/README.md +0 -28
  189. package/plugins/hono/index.d.ts +0 -12
  190. package/plugins/hono/index.js +0 -36
  191. package/plugins/hono/index.ts +0 -226
  192. package/plugins/hono/package.json +0 -35
  193. package/plugins/nestjs/README.md +0 -35
  194. package/plugins/nestjs/index.d.ts +0 -25
  195. package/plugins/nestjs/index.js +0 -77
  196. package/plugins/nestjs/index.ts +0 -201
  197. package/plugins/nestjs/package.json +0 -37
  198. package/plugins/nextjs-api/README.md +0 -57
  199. package/plugins/nextjs-api/examples/ConverterComponent.jsx +0 -386
  200. package/plugins/nextjs-api/examples/ConverterComponent.tsx +0 -386
  201. package/plugins/nextjs-api/examples/api-convert.js +0 -67
  202. package/plugins/nextjs-api/examples/api-convert.ts +0 -67
  203. package/plugins/nextjs-api/index.js +0 -387
  204. package/plugins/nextjs-api/index.tsx +0 -339
  205. package/plugins/nextjs-api/package.json +0 -63
  206. package/plugins/nextjs-api/route.js +0 -370
  207. package/plugins/nextjs-api/route.ts +0 -370
  208. package/plugins/nuxt/README.md +0 -24
  209. package/plugins/nuxt/index.js +0 -21
  210. package/plugins/nuxt/index.ts +0 -94
  211. package/plugins/nuxt/package.json +0 -35
  212. package/plugins/nuxt/runtime/composables/useJtcsv.js +0 -6
  213. package/plugins/nuxt/runtime/composables/useJtcsv.ts +0 -100
  214. package/plugins/nuxt/runtime/plugin.js +0 -6
  215. package/plugins/nuxt/runtime/plugin.ts +0 -71
  216. package/plugins/remix/README.md +0 -26
  217. package/plugins/remix/index.d.ts +0 -16
  218. package/plugins/remix/index.js +0 -62
  219. package/plugins/remix/index.ts +0 -260
  220. package/plugins/remix/package.json +0 -35
  221. package/plugins/sveltekit/README.md +0 -28
  222. package/plugins/sveltekit/index.d.ts +0 -17
  223. package/plugins/sveltekit/index.js +0 -54
  224. package/plugins/sveltekit/index.ts +0 -301
  225. package/plugins/sveltekit/package.json +0 -33
  226. package/plugins/trpc/README.md +0 -25
  227. package/plugins/trpc/index.d.ts +0 -7
  228. package/plugins/trpc/index.js +0 -32
  229. package/plugins/trpc/index.ts +0 -267
  230. package/plugins/trpc/package.json +0 -34
  231. package/src/browser/browser-functions.js +0 -219
  232. package/src/browser/core.js +0 -92
  233. package/src/browser/csv-to-json-browser.js +0 -722
  234. package/src/browser/errors-browser.js +0 -212
  235. package/src/browser/extensions/plugins.js +0 -92
  236. package/src/browser/extensions/workers.js +0 -39
  237. package/src/browser/index.js +0 -113
  238. package/src/browser/json-to-csv-browser.js +0 -319
  239. package/src/browser/streams.js +0 -403
  240. package/src/browser/workers/csv-parser.worker.js +0 -377
  241. package/src/browser/workers/worker-pool.js +0 -527
  242. package/src/core/delimiter-cache.js +0 -200
  243. package/src/core/node-optimizations.js +0 -408
  244. package/src/core/plugin-system.js +0 -494
  245. package/src/core/transform-hooks.js +0 -350
  246. package/src/engines/fast-path-engine-new.js +0 -338
  247. package/src/engines/fast-path-engine.js +0 -844
  248. package/src/errors.js +0 -26
  249. package/src/formats/ndjson-parser.js +0 -467
  250. package/src/formats/tsv-parser.js +0 -339
  251. package/src/index-with-plugins.js +0 -378
  252. package/src/utils/bom-utils.js +0 -259
  253. package/src/utils/encoding-support.js +0 -124
  254. package/src/utils/schema-validator.js +0 -594
  255. package/src/utils/transform-loader.js +0 -205
  256. package/src/utils/zod-adapter.js +0 -170
  257. package/stream-csv-to-json.js +0 -560
  258. package/stream-json-to-csv.js +0 -465
@@ -1,205 +0,0 @@
1
- /**
2
- * Transform Loader Utility
3
- *
4
- * Utility for loading and applying transform functions from JavaScript files
5
- */
6
-
7
- const fs = require('fs');
8
- const path = require('path');
9
- const vm = require('vm');
10
-
11
- const {
12
- ValidationError,
13
- SecurityError,
14
- ConfigurationError
15
- } = require('../errors');
16
-
17
- /**
18
- * Validates transform function
19
- * @private
20
- */
21
- function validateTransformFunction(fn) {
22
- if (typeof fn !== 'function') {
23
- throw new ValidationError('Transform must export a function');
24
- }
25
-
26
- // Check function arity (should accept 1-2 parameters)
27
- const functionString = fn.toString();
28
- const paramMatch = functionString.match(/\(([^)]*)\)/);
29
- if (paramMatch) {
30
- const params = paramMatch[1].split(',').map(p => p.trim()).filter(p => p);
31
- if (params.length === 0 || params.length > 2) {
32
- throw new ValidationError('Transform function should accept 1-2 parameters: (row, index)');
33
- }
34
- }
35
-
36
- return true;
37
- }
38
-
39
- /**
40
- * Loads transform function from a JavaScript file
41
- *
42
- * @param {string} transformPath - Path to JavaScript file with transform function
43
- * @returns {Function} Transform function
44
- *
45
- * @example
46
- * // transform.js
47
- * module.exports = function(row, index) {
48
- * return { ...row, processed: true, index };
49
- * };
50
- *
51
- * // Usage
52
- * const transform = loadTransform('./transform.js');
53
- * const result = transform({ id: 1, name: 'John' }, 0);
54
- */
55
- function loadTransform(transformPath) {
56
- if (!transformPath || typeof transformPath !== 'string') {
57
- throw new ValidationError('Transform path must be a string');
58
- }
59
-
60
- // Validate file path
61
- const safePath = path.resolve(transformPath);
62
-
63
- // Prevent directory traversal
64
- const normalizedPath = path.normalize(transformPath);
65
- if (normalizedPath.includes('..') ||
66
- /\\\.\.\\|\/\.\.\//.test(transformPath) ||
67
- transformPath.startsWith('..') ||
68
- transformPath.includes('/..')) {
69
- throw new SecurityError('Directory traversal detected in transform file path');
70
- }
71
-
72
- // Check file exists and has .js extension
73
- if (!fs.existsSync(safePath)) {
74
- throw new ValidationError(`Transform file not found: ${transformPath}`);
75
- }
76
-
77
- if (!safePath.toLowerCase().endsWith('.js')) {
78
- throw new ValidationError('Transform file must have .js extension');
79
- }
80
-
81
- try {
82
- // Read and evaluate the transform file in a safe context
83
- const transformCode = fs.readFileSync(safePath, 'utf8');
84
-
85
- // Create a safe context with limited access
86
- const sandbox = {
87
- console,
88
- require,
89
- module: { exports: {} },
90
- exports: {},
91
- __filename: safePath,
92
- __dirname: path.dirname(safePath),
93
- Buffer,
94
- process: {
95
- env: process.env,
96
- cwd: process.cwd,
97
- platform: process.platform
98
- }
99
- };
100
-
101
- // Create a context and run the code
102
- const context = vm.createContext(sandbox);
103
- const script = new vm.Script(transformCode, { filename: safePath });
104
- script.runInContext(context);
105
-
106
- // Get the exported function
107
- const transformFn = context.module.exports || context.exports;
108
-
109
- // Handle default export for ES6 modules
110
- const finalTransform = transformFn.default || transformFn;
111
-
112
- // Validate the transform function
113
- validateTransformFunction(finalTransform);
114
-
115
- return finalTransform;
116
- } catch (error) {
117
- if (error instanceof ValidationError || error instanceof SecurityError) {
118
- throw error;
119
- }
120
-
121
- if (error.code === 'EACCES') {
122
- throw new SecurityError(`Permission denied reading transform file: ${transformPath}`);
123
- }
124
-
125
- throw new ValidationError(`Failed to load transform function: ${error.message}`);
126
- }
127
- }
128
-
129
- /**
130
- * Creates a transform hook for use with csvToJson/jsonToCsv hooks system
131
- *
132
- * @param {string|Function} transform - Transform function or path to transform file
133
- * @returns {Function} Transform hook function
134
- */
135
- function createTransformHook(transform) {
136
- let transformFn;
137
-
138
- if (typeof transform === 'string') {
139
- // Load transform from file
140
- transformFn = loadTransform(transform);
141
- } else if (typeof transform === 'function') {
142
- // Use provided function
143
- validateTransformFunction(transform);
144
- transformFn = transform;
145
- } else {
146
- throw new ValidationError('Transform must be a function or a path to a JavaScript file');
147
- }
148
-
149
- // Return a hook function compatible with hooks.perRow
150
- return function (row, index, context) {
151
- try {
152
- return transformFn(row, index);
153
- } catch (error) {
154
- // Log error but don't crash - return original row
155
- console.error(`Transform error at row ${index}: ${error.message}`);
156
- if (process.env.NODE_ENV === 'development') {
157
- console.error(error.stack);
158
- }
159
- return row;
160
- }
161
- };
162
- }
163
-
164
- /**
165
- * Applies transform to data array
166
- *
167
- * @param {Array} data - Array of data to transform
168
- * @param {string|Function} transform - Transform function or path to transform file
169
- * @returns {Array} Transformed data
170
- */
171
- function applyTransform(data, transform) {
172
- if (!Array.isArray(data)) {
173
- throw new ValidationError('Data must be an array');
174
- }
175
-
176
- const transformHook = createTransformHook(transform);
177
-
178
- return data.map((row, index) => {
179
- return transformHook(row, index, { operation: 'applyTransform' });
180
- });
181
- }
182
-
183
- /**
184
- * Creates a TransformHooks instance with transform function
185
- *
186
- * @param {string|Function} transform - Transform function or path to transform file
187
- * @returns {TransformHooks} TransformHooks instance
188
- */
189
- function createTransformHooksWithTransform(transform) {
190
- const { TransformHooks } = require('../core/transform-hooks');
191
- const hooks = new TransformHooks();
192
-
193
- const transformHook = createTransformHook(transform);
194
- hooks.perRow(transformHook);
195
-
196
- return hooks;
197
- }
198
-
199
- module.exports = {
200
- loadTransform,
201
- createTransformHook,
202
- applyTransform,
203
- createTransformHooksWithTransform,
204
- validateTransformFunction
205
- };
@@ -1,170 +0,0 @@
1
- /**
2
- * Zod adapter for JTCSV schema validation.
3
- *
4
- * Provides integration with Zod schemas for CSV validation.
5
- *
6
- * @example
7
- * const { z } = require('zod');
8
- * const { createZodValidationHook } = require('./zod-adapter');
9
- *
10
- * const schema = z.object({
11
- * name: z.string().min(1),
12
- * age: z.number().int().min(0).max(150),
13
- * email: z.string().email()
14
- * });
15
- *
16
- * const validationHook = createZodValidationHook(schema);
17
- *
18
- * // Use with csvToJson
19
- * const data = await csvToJson(csv, {
20
- * hooks: { perRow: validationHook }
21
- * });
22
- */
23
-
24
- const { ValidationError } = require('../errors');
25
-
26
- /**
27
- * Creates a validation hook from a Zod schema.
28
- *
29
- * @param {import('zod').ZodSchema} zodSchema - Zod schema instance
30
- * @param {Object} options - Validation options
31
- * @param {boolean} options.coerce - Whether to coerce values according to Zod's coerce (default: true)
32
- * @param {string} options.mode - 'strict' (throw on first error) or 'collect' (collect all errors)
33
- * @returns {Function} Validation hook compatible with JTCSV hooks.perRow
34
- */
35
- function createZodValidationHook(zodSchema, options = {}) {
36
- const { coerce = true, mode = 'strict' } = options;
37
-
38
- // Check if Zod is available
39
- let zod;
40
- try {
41
- zod = require('zod');
42
- } catch (error) {
43
- throw new Error(
44
- 'Zod is not installed. Please install zod: npm install zod'
45
- );
46
- }
47
-
48
- // Ensure the passed schema is a Zod schema
49
- if (!zodSchema || typeof zodSchema.safeParse !== 'function') {
50
- throw new ValidationError('Provided schema is not a valid Zod schema');
51
- }
52
-
53
- // Return hook function
54
- return function (row, index, context) {
55
- try {
56
- const result = zodSchema.safeParse(row);
57
-
58
- if (!result.success) {
59
- const errors = result.error.errors;
60
- const firstError = errors[0];
61
- const path = firstError.path.join('.');
62
- const message = firstError.message;
63
-
64
- if (mode === 'strict') {
65
- throw new ValidationError(
66
- `Row ${index + 1}: ${path ? `Field "${path}": ` : ''}${message}`
67
- );
68
- } else {
69
- // In collect mode, we attach errors to row metadata
70
- // For simplicity, we still throw but could be extended
71
- console.warn(`Row ${index + 1}: ${path ? `Field "${path}": ` : ''}${message}`);
72
- return row;
73
- }
74
- }
75
-
76
- // Return validated (and possibly coerced) data
77
- return result.data;
78
- } catch (error) {
79
- if (error instanceof ValidationError) {
80
- throw error;
81
- }
82
- // Unexpected error - log and return original row
83
- console.error(`Zod validation error at row ${index}: ${error.message}`);
84
- if (process.env.NODE_ENV === 'development') {
85
- console.error(error.stack);
86
- }
87
- return row;
88
- }
89
- };
90
- }
91
-
92
- /**
93
- * Creates a Yup validation hook.
94
- *
95
- * @param {import('yup').Schema} yupSchema - Yup schema instance
96
- * @param {Object} options - Validation options
97
- * @returns {Function} Validation hook
98
- */
99
- function createYupValidationHook(yupSchema, options = {}) {
100
- const { abortEarly = false, stripUnknown = true } = options;
101
-
102
- // Check if Yup is available
103
- let yup;
104
- try {
105
- yup = require('yup');
106
- } catch (error) {
107
- throw new Error(
108
- 'Yup is not installed. Please install yup: npm install yup'
109
- );
110
- }
111
-
112
- if (!yupSchema || typeof yupSchema.validate !== 'function') {
113
- throw new ValidationError('Provided schema is not a valid Yup schema');
114
- }
115
-
116
- return async function (row, index, context) {
117
- try {
118
- const validated = await yupSchema.validate(row, { abortEarly, stripUnknown });
119
- return validated;
120
- } catch (error) {
121
- if (error.name === 'ValidationError') {
122
- throw new ValidationError(`Row ${index + 1}: ${error.message}`);
123
- }
124
- console.error(`Yup validation error at row ${index}: ${error.message}`);
125
- return row;
126
- }
127
- };
128
- }
129
-
130
- /**
131
- * Higher-order function that creates a csvToJson wrapper with schema validation.
132
- *
133
- * @param {import('zod').ZodSchema|import('yup').Schema} schema - Zod or Yup schema
134
- * @param {Object} adapterOptions - Adapter-specific options
135
- * @returns {Function} Function that takes csv and options, returns validated data
136
- */
137
- function createValidatedParser(schema, adapterOptions = {}) {
138
- const { library = 'zod', ...options } = adapterOptions;
139
-
140
- let validationHook;
141
- if (library === 'zod') {
142
- validationHook = createZodValidationHook(schema, options);
143
- } else if (library === 'yup') {
144
- validationHook = createYupValidationHook(schema, options);
145
- } else {
146
- throw new ValidationError(`Unsupported validation library: ${library}`);
147
- }
148
-
149
- return async function (csv, parseOptions = {}) {
150
- const { csvToJson } = require('../index');
151
- const hooks = parseOptions.hooks || {};
152
- // Merge validation hook with existing perRow hook
153
- const existingPerRow = hooks.perRow;
154
- hooks.perRow = function (row, index, context) {
155
- let validated = row;
156
- if (existingPerRow) {
157
- validated = existingPerRow(validated, index, context);
158
- }
159
- return validationHook(validated, index, context);
160
- };
161
-
162
- return csvToJson(csv, { ...parseOptions, hooks });
163
- };
164
- }
165
-
166
- module.exports = {
167
- createZodValidationHook,
168
- createYupValidationHook,
169
- createValidatedParser
170
- };