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.
Files changed (140) hide show
  1. package/README.md +31 -1
  2. package/bin/jtcsv.js +891 -821
  3. package/bin/jtcsv.ts +2534 -0
  4. package/csv-to-json.js +168 -145
  5. package/dist/jtcsv-core.cjs.js +1407 -0
  6. package/dist/jtcsv-core.cjs.js.map +1 -0
  7. package/dist/jtcsv-core.esm.js +1379 -0
  8. package/dist/jtcsv-core.esm.js.map +1 -0
  9. package/dist/jtcsv-core.umd.js +1413 -0
  10. package/dist/jtcsv-core.umd.js.map +1 -0
  11. package/dist/jtcsv-full.cjs.js +1912 -0
  12. package/dist/jtcsv-full.cjs.js.map +1 -0
  13. package/dist/jtcsv-full.esm.js +1880 -0
  14. package/dist/jtcsv-full.esm.js.map +1 -0
  15. package/dist/jtcsv-full.umd.js +1918 -0
  16. package/dist/jtcsv-full.umd.js.map +1 -0
  17. package/dist/jtcsv-workers.esm.js +759 -0
  18. package/dist/jtcsv-workers.esm.js.map +1 -0
  19. package/dist/jtcsv-workers.umd.js +773 -0
  20. package/dist/jtcsv-workers.umd.js.map +1 -0
  21. package/dist/jtcsv.cjs.js +61 -19
  22. package/dist/jtcsv.cjs.js.map +1 -1
  23. package/dist/jtcsv.esm.js +61 -19
  24. package/dist/jtcsv.esm.js.map +1 -1
  25. package/dist/jtcsv.umd.js +61 -19
  26. package/dist/jtcsv.umd.js.map +1 -1
  27. package/errors.js +188 -2
  28. package/examples/advanced/conditional-transformations.js +446 -0
  29. package/examples/advanced/conditional-transformations.ts +446 -0
  30. package/examples/advanced/csv-parser.worker.js +89 -0
  31. package/examples/advanced/csv-parser.worker.ts +89 -0
  32. package/examples/advanced/nested-objects-example.js +306 -0
  33. package/examples/advanced/nested-objects-example.ts +306 -0
  34. package/examples/advanced/performance-optimization.js +504 -0
  35. package/examples/advanced/performance-optimization.ts +504 -0
  36. package/examples/advanced/run-demo-server.js +116 -0
  37. package/examples/advanced/run-demo-server.ts +116 -0
  38. package/examples/advanced/web-worker-usage.html +874 -0
  39. package/examples/async-multithreaded-example.ts +335 -0
  40. package/examples/cli-advanced-usage.md +288 -0
  41. package/examples/cli-batch-processing.ts +38 -0
  42. package/examples/cli-tool.js +0 -3
  43. package/examples/cli-tool.ts +183 -0
  44. package/examples/error-handling.js +21 -7
  45. package/examples/error-handling.ts +356 -0
  46. package/examples/express-api.js +0 -3
  47. package/examples/express-api.ts +164 -0
  48. package/examples/large-dataset-example.js +0 -3
  49. package/examples/large-dataset-example.ts +204 -0
  50. package/examples/ndjson-processing.js +1 -1
  51. package/examples/ndjson-processing.ts +456 -0
  52. package/examples/plugin-excel-exporter.js +3 -4
  53. package/examples/plugin-excel-exporter.ts +406 -0
  54. package/examples/react-integration.tsx +637 -0
  55. package/examples/schema-validation.ts +640 -0
  56. package/examples/simple-usage.js +254 -254
  57. package/examples/simple-usage.ts +194 -0
  58. package/examples/streaming-example.js +4 -5
  59. package/examples/streaming-example.ts +419 -0
  60. package/examples/web-workers-advanced.ts +28 -0
  61. package/index.d.ts +1 -3
  62. package/index.js +15 -1
  63. package/json-save.js +9 -3
  64. package/json-to-csv.js +168 -21
  65. package/package.json +69 -10
  66. package/plugins/express-middleware/README.md +21 -2
  67. package/plugins/express-middleware/example.js +3 -4
  68. package/plugins/express-middleware/example.ts +135 -0
  69. package/plugins/express-middleware/index.d.ts +1 -1
  70. package/plugins/express-middleware/index.js +270 -118
  71. package/plugins/express-middleware/index.ts +557 -0
  72. package/plugins/fastify-plugin/index.js +2 -4
  73. package/plugins/fastify-plugin/index.ts +443 -0
  74. package/plugins/hono/index.ts +226 -0
  75. package/plugins/nestjs/index.ts +201 -0
  76. package/plugins/nextjs-api/examples/ConverterComponent.tsx +386 -0
  77. package/plugins/nextjs-api/examples/api-convert.js +0 -2
  78. package/plugins/nextjs-api/examples/api-convert.ts +67 -0
  79. package/plugins/nextjs-api/index.tsx +339 -0
  80. package/plugins/nextjs-api/route.js +2 -3
  81. package/plugins/nextjs-api/route.ts +370 -0
  82. package/plugins/nuxt/index.ts +94 -0
  83. package/plugins/nuxt/runtime/composables/useJtcsv.ts +100 -0
  84. package/plugins/nuxt/runtime/plugin.ts +71 -0
  85. package/plugins/remix/index.js +1 -1
  86. package/plugins/remix/index.ts +260 -0
  87. package/plugins/sveltekit/index.js +1 -1
  88. package/plugins/sveltekit/index.ts +301 -0
  89. package/plugins/trpc/index.ts +267 -0
  90. package/src/browser/browser-functions.ts +402 -0
  91. package/src/browser/core.js +92 -0
  92. package/src/browser/core.ts +152 -0
  93. package/src/browser/csv-to-json-browser.d.ts +3 -0
  94. package/src/browser/csv-to-json-browser.js +36 -14
  95. package/src/browser/csv-to-json-browser.ts +264 -0
  96. package/src/browser/errors-browser.ts +303 -0
  97. package/src/browser/extensions/plugins.js +92 -0
  98. package/src/browser/extensions/plugins.ts +93 -0
  99. package/src/browser/extensions/workers.js +39 -0
  100. package/src/browser/extensions/workers.ts +39 -0
  101. package/src/browser/globals.d.ts +5 -0
  102. package/src/browser/index.ts +192 -0
  103. package/src/browser/json-to-csv-browser.d.ts +3 -0
  104. package/src/browser/json-to-csv-browser.js +13 -3
  105. package/src/browser/json-to-csv-browser.ts +262 -0
  106. package/src/browser/streams.js +12 -2
  107. package/src/browser/streams.ts +336 -0
  108. package/src/browser/workers/csv-parser.worker.ts +377 -0
  109. package/src/browser/workers/worker-pool.ts +548 -0
  110. package/src/core/delimiter-cache.js +22 -8
  111. package/src/core/delimiter-cache.ts +310 -0
  112. package/src/core/node-optimizations.ts +449 -0
  113. package/src/core/plugin-system.js +29 -11
  114. package/src/core/plugin-system.ts +400 -0
  115. package/src/core/transform-hooks.ts +558 -0
  116. package/src/engines/fast-path-engine-new.ts +347 -0
  117. package/src/engines/fast-path-engine.ts +854 -0
  118. package/src/errors.ts +72 -0
  119. package/src/formats/ndjson-parser.ts +469 -0
  120. package/src/formats/tsv-parser.ts +334 -0
  121. package/src/index-with-plugins.js +16 -9
  122. package/src/index-with-plugins.ts +395 -0
  123. package/src/types/index.ts +255 -0
  124. package/src/utils/bom-utils.js +259 -0
  125. package/src/utils/bom-utils.ts +373 -0
  126. package/src/utils/encoding-support.js +124 -0
  127. package/src/utils/encoding-support.ts +155 -0
  128. package/src/utils/schema-validator.js +19 -19
  129. package/src/utils/schema-validator.ts +819 -0
  130. package/src/utils/transform-loader.js +1 -1
  131. package/src/utils/transform-loader.ts +389 -0
  132. package/src/utils/zod-adapter.js +170 -0
  133. package/src/utils/zod-adapter.ts +280 -0
  134. package/src/web-server/index.js +10 -10
  135. package/src/web-server/index.ts +683 -0
  136. package/src/workers/csv-multithreaded.ts +310 -0
  137. package/src/workers/csv-parser.worker.ts +227 -0
  138. package/src/workers/worker-pool.ts +409 -0
  139. package/stream-csv-to-json.js +26 -8
  140. package/stream-json-to-csv.js +1 -0
@@ -0,0 +1,280 @@
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
+ import { ValidationError } from '../errors';
25
+
26
+ // Conditional imports for optional dependencies
27
+ type ZodSchema = any;
28
+ type YupSchema = any;
29
+
30
+ export interface ZodValidationOptions {
31
+ coerce?: boolean;
32
+ mode?: 'strict' | 'collect';
33
+ }
34
+
35
+ export interface YupValidationOptions {
36
+ abortEarly?: boolean;
37
+ stripUnknown?: boolean;
38
+ }
39
+
40
+ export interface ValidatedParserOptions {
41
+ library?: 'zod' | 'yup';
42
+ [key: string]: any;
43
+ }
44
+
45
+ export type RowHook = (row: any, index: number, context: any) => any | Promise<any>;
46
+
47
+ /**
48
+ * Creates a validation hook from a Zod schema.
49
+ *
50
+ * @param zodSchema - Zod schema instance
51
+ * @param options - Validation options
52
+ * @param options.coerce - Whether to coerce values according to Zod's coerce (default: true)
53
+ * @param options.mode - 'strict' (throw on first error) or 'collect' (collect all errors)
54
+ * @returns Validation hook compatible with JTCSV hooks.perRow
55
+ */
56
+ export function createZodValidationHook(
57
+ zodSchema: ZodSchema,
58
+ options: ZodValidationOptions = {}
59
+ ): RowHook {
60
+ const { coerce = true, mode = 'strict' } = options;
61
+
62
+ // Check if Zod is available
63
+ let zod: any;
64
+ try {
65
+ zod = require('zod');
66
+ } catch (error) {
67
+ throw new Error(
68
+ 'Zod is not installed. Please install zod: npm install zod'
69
+ );
70
+ }
71
+
72
+ // Ensure the passed schema is a Zod schema
73
+ if (!zodSchema || typeof zodSchema.safeParse !== 'function') {
74
+ throw new ValidationError('Provided schema is not a valid Zod schema');
75
+ }
76
+
77
+ // Return hook function
78
+ return function (row: any, index: number, context: any): any {
79
+ try {
80
+ const result = zodSchema.safeParse(row);
81
+
82
+ if (!result.success) {
83
+ const errors = result.error.errors;
84
+ const firstError = errors[0];
85
+ const path = firstError.path?.join('.') || '';
86
+ const message = firstError.message;
87
+
88
+ if (mode === 'strict') {
89
+ throw new ValidationError(
90
+ `Row ${index + 1}: ${path ? `Field "${path}": ` : ''}${message}`
91
+ );
92
+ } else {
93
+ // In collect mode, we attach errors to row metadata
94
+ // For simplicity, we still throw but could be extended
95
+ console.warn(`Row ${index + 1}: ${path ? `Field "${path}": ` : ''}${message}`);
96
+ return row;
97
+ }
98
+ }
99
+
100
+ // Return validated (and possibly coerced) data
101
+ return result.data;
102
+ } catch (error: any) {
103
+ if (error instanceof ValidationError) {
104
+ throw error;
105
+ }
106
+ // Unexpected error - log and return original row
107
+ console.error(`Zod validation error at row ${index}: ${error.message}`);
108
+ if (process.env['NODE_ENV'] === 'development') {
109
+ console.error(error.stack);
110
+ }
111
+ return row;
112
+ }
113
+ };
114
+ }
115
+
116
+ /**
117
+ * Creates a Yup validation hook.
118
+ *
119
+ * @param yupSchema - Yup schema instance
120
+ * @param options - Validation options
121
+ * @returns Validation hook
122
+ */
123
+ export function createYupValidationHook(
124
+ yupSchema: YupSchema,
125
+ options: YupValidationOptions = {}
126
+ ): RowHook {
127
+ const { abortEarly = false, stripUnknown = true } = options;
128
+
129
+ // Check if Yup is available
130
+ let yup: any;
131
+ try {
132
+ yup = require('yup');
133
+ } catch (error) {
134
+ throw new Error(
135
+ 'Yup is not installed. Please install yup: npm install yup'
136
+ );
137
+ }
138
+
139
+ if (!yupSchema || typeof yupSchema.validate !== 'function') {
140
+ throw new ValidationError('Provided schema is not a valid Yup schema');
141
+ }
142
+
143
+ return async function (row: any, index: number, context: any): Promise<any> {
144
+ try {
145
+ const validated = await yupSchema.validate(row, { abortEarly, stripUnknown });
146
+ return validated;
147
+ } catch (error: any) {
148
+ if (error.name === 'ValidationError') {
149
+ throw new ValidationError(`Row ${index + 1}: ${error.message}`);
150
+ }
151
+ console.error(`Yup validation error at row ${index}: ${error.message}`);
152
+ return row;
153
+ }
154
+ };
155
+ }
156
+
157
+ /**
158
+ * Higher-order function that creates a csvToJson wrapper with schema validation.
159
+ *
160
+ * @param schema - Zod or Yup schema
161
+ * @param adapterOptions - Adapter-specific options
162
+ * @returns Function that takes csv and options, returns validated data
163
+ */
164
+ export function createValidatedParser(
165
+ schema: ZodSchema | YupSchema,
166
+ adapterOptions: ValidatedParserOptions = {}
167
+ ): (csv: string, parseOptions?: any) => Promise<any[]> {
168
+ const { library = 'zod', ...options } = adapterOptions;
169
+
170
+ let validationHook: RowHook;
171
+ if (library === 'zod') {
172
+ validationHook = createZodValidationHook(schema as ZodSchema, options);
173
+ } else if (library === 'yup') {
174
+ validationHook = createYupValidationHook(schema as YupSchema, options);
175
+ } else {
176
+ throw new ValidationError(`Unsupported validation library: ${library}`);
177
+ }
178
+
179
+ return async function (csv: string, parseOptions: any = {}): Promise<any[]> {
180
+ const { csvToJson } = require('../index');
181
+ const hooks = parseOptions.hooks || {};
182
+ // Merge validation hook with existing perRow hook
183
+ const existingPerRow = hooks.perRow;
184
+ hooks.perRow = function (row: any, index: number, context: any): any {
185
+ let validated = row;
186
+ if (existingPerRow) {
187
+ validated = existingPerRow(validated, index, context);
188
+ }
189
+ return validationHook(validated, index, context);
190
+ };
191
+
192
+ return csvToJson(csv, { ...parseOptions, hooks });
193
+ };
194
+ }
195
+
196
+ /**
197
+ * Async version of createValidatedParser that uses worker threads for validation.
198
+ *
199
+ * @param schema - Zod or Yup schema
200
+ * @param adapterOptions - Adapter-specific options
201
+ * @returns Async function that validates CSV data in parallel
202
+ */
203
+ export function createAsyncValidatedParser(
204
+ schema: ZodSchema | YupSchema,
205
+ adapterOptions: ValidatedParserOptions = {}
206
+ ): (csv: string, parseOptions?: any) => Promise<any[]> {
207
+ const { library = 'zod', ...options } = adapterOptions;
208
+
209
+ return async function (csv: string, parseOptions: any = {}): Promise<any[]> {
210
+ const { csvToJson } = require('../index');
211
+ const { createWorkerPool } = require('../workers/worker-pool');
212
+
213
+ // Create worker pool for parallel validation
214
+ const pool = createWorkerPool({
215
+ workerCount: Math.min(4, require('os').cpus().length),
216
+ workerScript: require.resolve('./validation-worker.js')
217
+ });
218
+
219
+ try {
220
+ // Parse CSV without validation first
221
+ const data = await csvToJson(csv, parseOptions);
222
+
223
+ // Validate in parallel using worker pool
224
+ const validationPromises = data.map((row: any, index: number) =>
225
+ pool.execute({ row, index, schema, library, options })
226
+ );
227
+
228
+ const validatedRows = await Promise.all(validationPromises);
229
+ return validatedRows;
230
+ } finally {
231
+ await pool.terminate();
232
+ }
233
+ };
234
+ }
235
+
236
+ /**
237
+ * Creates a validation hook that works asynchronously with Zod schemas.
238
+ *
239
+ * @param zodSchema - Zod schema instance
240
+ * @param options - Validation options
241
+ * @returns Async validation hook
242
+ */
243
+ export function createAsyncZodValidationHook(
244
+ zodSchema: ZodSchema,
245
+ options: ZodValidationOptions = {}
246
+ ): RowHook {
247
+ const hook = createZodValidationHook(zodSchema, options);
248
+
249
+ return async function (row: any, index: number, context: any): Promise<any> {
250
+ // For async compatibility, wrap in Promise
251
+ return Promise.resolve(hook(row, index, context));
252
+ };
253
+ }
254
+
255
+ /**
256
+ * Creates a validation hook that works asynchronously with Yup schemas.
257
+ *
258
+ * @param yupSchema - Yup schema instance
259
+ * @param options - Validation options
260
+ * @returns Async validation hook
261
+ */
262
+ export function createAsyncYupValidationHook(
263
+ yupSchema: YupSchema,
264
+ options: YupValidationOptions = {}
265
+ ): RowHook {
266
+ const hook = createYupValidationHook(yupSchema, options);
267
+
268
+ return async function (row: any, index: number, context: any): Promise<any> {
269
+ return hook(row, index, context);
270
+ };
271
+ }
272
+
273
+ export default {
274
+ createZodValidationHook,
275
+ createYupValidationHook,
276
+ createValidatedParser,
277
+ createAsyncValidatedParser,
278
+ createAsyncZodValidationHook,
279
+ createAsyncYupValidationHook
280
+ };
@@ -126,7 +126,7 @@ async function handleValidate(req, res) {
126
126
  const { data, format } = body;
127
127
 
128
128
  let isValid = false;
129
- let errors = [];
129
+ const errors = [];
130
130
 
131
131
  if (format === 'json') {
132
132
  if (Array.isArray(data)) {
@@ -651,21 +651,21 @@ function startServer(options = {}) {
651
651
  const server = http.createServer(handleRequest);
652
652
 
653
653
  server.listen(port, host, () => {
654
- console.log(`\n🌐 JTCSV Web Server started!`);
654
+ console.log('\n🌐 JTCSV Web Server started!');
655
655
  console.log(`\nšŸ“ URL: http://${host}:${port}`);
656
- console.log(`\nšŸ“” API Endpoints:`);
657
- console.log(` POST /api/json-to-csv`);
658
- console.log(` POST /api/csv-to-json`);
659
- console.log(` POST /api/ndjson-to-csv`);
660
- console.log(` POST /api/csv-to-ndjson`);
661
- console.log(` POST /api/validate`);
662
- console.log(`\n✨ Press Ctrl+C to stop\n`);
656
+ console.log('\nšŸ“” API Endpoints:');
657
+ console.log(' POST /api/json-to-csv');
658
+ console.log(' POST /api/csv-to-json');
659
+ console.log(' POST /api/ndjson-to-csv');
660
+ console.log(' POST /api/csv-to-ndjson');
661
+ console.log(' POST /api/validate');
662
+ console.log('\n✨ Press Ctrl+C to stop\n');
663
663
  });
664
664
 
665
665
  server.on('error', (error) => {
666
666
  if (error.code === 'EADDRINUSE') {
667
667
  console.error(`\nāŒ Error: Port ${port} is already in use`);
668
- console.error(` Try a different port: jtcsv web --port=3001\n`);
668
+ console.error(' Try a different port: jtcsv web --port=3001\n');
669
669
  } else {
670
670
  console.error(`\nāŒ Server error: ${error.message}\n`);
671
671
  }