jtcsv 2.2.8 → 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 +1 -0
  64. package/json-to-csv.js +160 -18
  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,640 @@
1
+ /**
2
+ * Schema Validation Examples for jtcsv
3
+ *
4
+ * jtcsv supports JSON Schema validation for ensuring
5
+ * data integrity during CSV/JSON conversions.
6
+ */
7
+
8
+ const {
9
+ jsonToCsv,
10
+ csvToJson,
11
+ ValidationError
12
+ } = await import("jtcsv");
13
+
14
+ // =============================================================================
15
+ // Example 1: Basic Schema Validation
16
+ // =============================================================================
17
+
18
+ function basicSchemaValidation() {
19
+ console.log('\n=== Basic Schema Validation ===\n');
20
+
21
+ // Define schema for user data
22
+ const userSchema = {
23
+ type: 'object',
24
+ required: ['name', 'email'],
25
+ properties: {
26
+ name: {
27
+ type: 'string',
28
+ minLength: 1,
29
+ maxLength: 100
30
+ },
31
+ email: {
32
+ type: 'string',
33
+ pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'
34
+ },
35
+ age: {
36
+ type: 'number',
37
+ minimum: 0,
38
+ maximum: 150
39
+ }
40
+ }
41
+ };
42
+
43
+ // Valid data
44
+ const validUsers = [
45
+ { name: 'John Doe', email: 'john@example.com', age: 30 },
46
+ { name: 'Jane Smith', email: 'jane@test.org', age: 25 }
47
+ ];
48
+
49
+ try {
50
+ const csv = jsonToCsv(validUsers, { schema: userSchema });
51
+ console.log('Valid data converted successfully:');
52
+ console.log(csv);
53
+ } catch (error) {
54
+ console.log('Unexpected error:', error.message);
55
+ }
56
+
57
+ // Invalid data
58
+ const invalidUsers = [
59
+ { name: '', email: 'john@example.com', age: 30 }, // Empty name
60
+ { name: 'Jane', email: 'invalid-email', age: -5 } // Bad email, negative age
61
+ ];
62
+
63
+ try {
64
+ jsonToCsv(invalidUsers, { schema: userSchema });
65
+ } catch (error) {
66
+ if (error instanceof ValidationError) {
67
+ console.log('\nValidation failed (expected):');
68
+ console.log('Error:', error.message);
69
+ }
70
+ }
71
+ }
72
+
73
+ // =============================================================================
74
+ // Example 2: Complex Nested Schema
75
+ // =============================================================================
76
+
77
+ function nestedSchemaValidation() {
78
+ console.log('\n=== Nested Schema Validation ===\n');
79
+
80
+ const orderSchema = {
81
+ type: 'object',
82
+ required: ['orderId', 'customer', 'total'],
83
+ properties: {
84
+ orderId: {
85
+ type: 'string',
86
+ pattern: '^ORD-[0-9]{6}$' // Format: ORD-123456
87
+ },
88
+ customer: {
89
+ type: 'object',
90
+ required: ['name', 'email'],
91
+ properties: {
92
+ name: { type: 'string', minLength: 1 },
93
+ email: { type: 'string' }
94
+ }
95
+ },
96
+ items: {
97
+ type: 'array',
98
+ minItems: 1,
99
+ items: {
100
+ type: 'object',
101
+ required: ['sku', 'quantity'],
102
+ properties: {
103
+ sku: { type: 'string' },
104
+ quantity: { type: 'number', minimum: 1 }
105
+ }
106
+ }
107
+ },
108
+ total: {
109
+ type: 'number',
110
+ minimum: 0
111
+ },
112
+ status: {
113
+ type: 'string',
114
+ enum: ['pending', 'processing', 'shipped', 'delivered']
115
+ }
116
+ }
117
+ };
118
+
119
+ const orders = [
120
+ {
121
+ orderId: 'ORD-123456',
122
+ customer: { name: 'John Doe', email: 'john@example.com' },
123
+ items: [
124
+ { sku: 'PROD-001', quantity: 2 },
125
+ { sku: 'PROD-002', quantity: 1 }
126
+ ],
127
+ total: 149.99,
128
+ status: 'processing'
129
+ }
130
+ ];
131
+
132
+ try {
133
+ const csv = jsonToCsv(orders, {
134
+ schema: orderSchema,
135
+ delimiter: ','
136
+ });
137
+ console.log('Order with nested data converted:');
138
+ console.log(csv);
139
+ } catch (error) {
140
+ console.log('Error:', error.message);
141
+ }
142
+ }
143
+
144
+ // =============================================================================
145
+ // Example 3: Schema with Custom Formats
146
+ // =============================================================================
147
+
148
+ function customFormatSchema() {
149
+ console.log('\n=== Custom Format Schema ===\n');
150
+
151
+ const eventSchema = {
152
+ type: 'object',
153
+ required: ['eventId', 'timestamp', 'eventType'],
154
+ properties: {
155
+ eventId: {
156
+ type: 'string',
157
+ pattern: '^EVT-[A-Z0-9]{8}$' // EVT-XXXXXXXX
158
+ },
159
+ timestamp: {
160
+ type: 'string',
161
+ pattern: '^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z$' // ISO 8601
162
+ },
163
+ eventType: {
164
+ type: 'string',
165
+ enum: ['click', 'view', 'purchase', 'signup', 'login', 'logout']
166
+ },
167
+ userId: {
168
+ type: 'string',
169
+ pattern: '^USR-\\d{6}$' // Optional but must match if present
170
+ },
171
+ metadata: {
172
+ type: 'object' // Allow any object structure
173
+ }
174
+ }
175
+ };
176
+
177
+ const events = [
178
+ {
179
+ eventId: 'EVT-A1B2C3D4',
180
+ timestamp: '2024-01-15T10:30:00.123Z',
181
+ eventType: 'purchase',
182
+ userId: 'USR-000123',
183
+ metadata: { productId: 'PRD-001', amount: 99.99 }
184
+ },
185
+ {
186
+ eventId: 'EVT-E5F6G7H8',
187
+ timestamp: '2024-01-15T10:31:00Z',
188
+ eventType: 'view',
189
+ metadata: { page: '/products', duration: 45 }
190
+ }
191
+ ];
192
+
193
+ try {
194
+ const csv = jsonToCsv(events, { schema: eventSchema });
195
+ console.log('Events validated and converted:');
196
+ console.log(csv);
197
+ } catch (error) {
198
+ console.log('Error:', error.message);
199
+ }
200
+ }
201
+
202
+ // =============================================================================
203
+ // Example 4: Array Validation
204
+ // =============================================================================
205
+
206
+ function arraySchemaValidation() {
207
+ console.log('\n=== Array Schema Validation ===\n');
208
+
209
+ const surveySchema = {
210
+ type: 'object',
211
+ required: ['respondentId', 'answers'],
212
+ properties: {
213
+ respondentId: {
214
+ type: 'number',
215
+ minimum: 1
216
+ },
217
+ answers: {
218
+ type: 'array',
219
+ minItems: 5,
220
+ maxItems: 10,
221
+ items: {
222
+ type: 'number',
223
+ minimum: 1,
224
+ maximum: 5 // Rating 1-5
225
+ }
226
+ },
227
+ comments: {
228
+ type: 'string',
229
+ maxLength: 500
230
+ }
231
+ }
232
+ };
233
+
234
+ const surveyResponses = [
235
+ {
236
+ respondentId: 1,
237
+ answers: [5, 4, 3, 5, 4],
238
+ comments: 'Great experience!'
239
+ },
240
+ {
241
+ respondentId: 2,
242
+ answers: [3, 3, 4, 4, 5, 4],
243
+ comments: ''
244
+ }
245
+ ];
246
+
247
+ try {
248
+ const csv = jsonToCsv(surveyResponses, { schema: surveySchema });
249
+ console.log('Survey responses validated:');
250
+ console.log(csv);
251
+ } catch (error) {
252
+ console.log('Error:', error.message);
253
+ }
254
+
255
+ // Test with invalid data
256
+ console.log('\nTesting invalid survey data:');
257
+ const invalidSurvey = [
258
+ {
259
+ respondentId: 1,
260
+ answers: [5, 4, 6, 5, 4], // 6 is out of range (max 5)
261
+ comments: 'Test'
262
+ }
263
+ ];
264
+
265
+ try {
266
+ jsonToCsv(invalidSurvey, { schema: surveySchema });
267
+ } catch (error) {
268
+ console.log('Validation error (expected):', error.message);
269
+ }
270
+ }
271
+
272
+ // =============================================================================
273
+ // Example 5: Conditional Schema (oneOf/anyOf)
274
+ // =============================================================================
275
+
276
+ function conditionalSchema() {
277
+ console.log('\n=== Conditional Schema ===\n');
278
+
279
+ // Schema where payment method determines required fields
280
+ const paymentSchema = {
281
+ type: 'object',
282
+ required: ['paymentId', 'method', 'amount'],
283
+ properties: {
284
+ paymentId: { type: 'string' },
285
+ method: {
286
+ type: 'string',
287
+ enum: ['credit_card', 'bank_transfer', 'crypto']
288
+ },
289
+ amount: {
290
+ type: 'number',
291
+ minimum: 0.01
292
+ },
293
+ // Credit card fields
294
+ cardLast4: {
295
+ type: 'string',
296
+ pattern: '^\\d{4}$'
297
+ },
298
+ // Bank transfer fields
299
+ bankAccount: {
300
+ type: 'string'
301
+ },
302
+ // Crypto fields
303
+ walletAddress: {
304
+ type: 'string',
305
+ pattern: '^0x[a-fA-F0-9]{40}$'
306
+ }
307
+ }
308
+ };
309
+
310
+ const payments = [
311
+ {
312
+ paymentId: 'PAY-001',
313
+ method: 'credit_card',
314
+ amount: 99.99,
315
+ cardLast4: '1234'
316
+ },
317
+ {
318
+ paymentId: 'PAY-002',
319
+ method: 'bank_transfer',
320
+ amount: 500.00,
321
+ bankAccount: 'GB82WEST12345698765432'
322
+ },
323
+ {
324
+ paymentId: 'PAY-003',
325
+ method: 'crypto',
326
+ amount: 250.00,
327
+ walletAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f8e21d'
328
+ }
329
+ ];
330
+
331
+ try {
332
+ const csv = jsonToCsv(payments, { schema: paymentSchema });
333
+ console.log('Payments validated:');
334
+ console.log(csv);
335
+ } catch (error) {
336
+ console.log('Error:', error.message);
337
+ }
338
+ }
339
+
340
+ // =============================================================================
341
+ // Example 6: Schema for Type Coercion Hints
342
+ // =============================================================================
343
+
344
+ function typeCoercionSchema() {
345
+ console.log('\n=== Schema for Type Hints ===\n');
346
+
347
+ // Schema that helps with proper type handling
348
+ const productSchema = {
349
+ type: 'object',
350
+ properties: {
351
+ sku: { type: 'string' },
352
+ name: { type: 'string' },
353
+ price: { type: 'number' },
354
+ quantity: { type: 'integer' },
355
+ isAvailable: { type: 'boolean' },
356
+ tags: {
357
+ type: 'array',
358
+ items: { type: 'string' }
359
+ },
360
+ dimensions: {
361
+ type: 'object',
362
+ properties: {
363
+ width: { type: 'number' },
364
+ height: { type: 'number' },
365
+ depth: { type: 'number' }
366
+ }
367
+ }
368
+ }
369
+ };
370
+
371
+ const products = [
372
+ {
373
+ sku: 'LAPTOP-001',
374
+ name: 'Pro Laptop 15"',
375
+ price: 1299.99,
376
+ quantity: 50,
377
+ isAvailable: true,
378
+ tags: ['electronics', 'computers', 'portable'],
379
+ dimensions: { width: 35.5, height: 1.8, depth: 24.0 }
380
+ }
381
+ ];
382
+
383
+ const csv = jsonToCsv(products, {
384
+ schema: productSchema,
385
+ delimiter: ','
386
+ });
387
+ console.log('Product with type hints:');
388
+ console.log(csv);
389
+ }
390
+
391
+ // =============================================================================
392
+ // Example 7: Validation Error Details
393
+ // =============================================================================
394
+
395
+ function validationErrorDetails() {
396
+ console.log('\n=== Validation Error Details ===\n');
397
+
398
+ const strictSchema = {
399
+ type: 'object',
400
+ additionalProperties: false, // No extra fields allowed
401
+ required: ['id', 'name', 'email', 'role'],
402
+ properties: {
403
+ id: {
404
+ type: 'integer',
405
+ minimum: 1
406
+ },
407
+ name: {
408
+ type: 'string',
409
+ minLength: 2,
410
+ maxLength: 50
411
+ },
412
+ email: {
413
+ type: 'string',
414
+ pattern: '^[^@]+@[^@]+\\.[^@]+$'
415
+ },
416
+ role: {
417
+ type: 'string',
418
+ enum: ['admin', 'user', 'guest']
419
+ }
420
+ }
421
+ };
422
+
423
+ // Data with multiple validation errors
424
+ const invalidData = [
425
+ {
426
+ id: 0, // Error: minimum is 1
427
+ name: 'A', // Error: minLength is 2
428
+ email: 'invalid', // Error: doesn't match pattern
429
+ role: 'superuser', // Error: not in enum
430
+ extra: 'field' // Error: additionalProperties false
431
+ }
432
+ ];
433
+
434
+ try {
435
+ jsonToCsv(invalidData, { schema: strictSchema });
436
+ } catch (error) {
437
+ if (error instanceof ValidationError) {
438
+ console.log('Multiple validation errors detected:');
439
+ console.log('Message:', error.message);
440
+ console.log('Code:', error.code);
441
+ }
442
+ }
443
+ }
444
+
445
+ // =============================================================================
446
+ // Example 8: Schema Validation with CSV Input
447
+ // =============================================================================
448
+
449
+ function schemaValidationOnCsvInput() {
450
+ console.log('\n=== Schema Validation on CSV Input ===\n');
451
+
452
+ const csv = `id,name,score,passed
453
+ 1,Alice,95,true
454
+ 2,Bob,87,true
455
+ 3,Charlie,45,false
456
+ 4,Diana,invalid,true`; // 'invalid' should be a number
457
+
458
+ // First parse CSV
459
+ const data = csvToJson(csv, {
460
+ parseNumbers: true,
461
+ parseBooleans: true
462
+ });
463
+
464
+ console.log('Parsed data:');
465
+ data.forEach(row => {
466
+ console.log(` ${row.name}: score=${row.score} (${typeof row.score})`);
467
+ });
468
+
469
+ // Now validate
470
+ const scoreSchema = {
471
+ type: 'object',
472
+ properties: {
473
+ id: { type: 'number' },
474
+ name: { type: 'string' },
475
+ score: { type: 'number', minimum: 0, maximum: 100 },
476
+ passed: { type: 'boolean' }
477
+ }
478
+ };
479
+
480
+ // Validate each row
481
+ console.log('\nValidation results:');
482
+ data.forEach((row, i) => {
483
+ const isValid = typeof row.score === 'number' &&
484
+ row.score >= 0 && row.score <= 100;
485
+ console.log(` Row ${i + 1} (${row.name}): ${isValid ? 'Valid' : 'Invalid'}`);
486
+ });
487
+ }
488
+
489
+ // =============================================================================
490
+ // Example 9: Reusable Schema Definitions
491
+ // =============================================================================
492
+
493
+ function reusableSchemaDefinitions() {
494
+ console.log('\n=== Reusable Schema Definitions ===\n');
495
+
496
+ // Common field definitions
497
+ const commonFields = {
498
+ id: { type: 'integer', minimum: 1 },
499
+ createdAt: { type: 'string' },
500
+ updatedAt: { type: 'string' }
501
+ };
502
+
503
+ const addressSchema = {
504
+ type: 'object',
505
+ required: ['street', 'city', 'country'],
506
+ properties: {
507
+ street: { type: 'string' },
508
+ city: { type: 'string' },
509
+ postalCode: { type: 'string' },
510
+ country: { type: 'string', minLength: 2, maxLength: 2 } // ISO country code
511
+ }
512
+ };
513
+
514
+ // Customer schema using common fields
515
+ const customerSchema = {
516
+ type: 'object',
517
+ required: ['id', 'name', 'email'],
518
+ properties: {
519
+ ...commonFields,
520
+ name: { type: 'string', minLength: 1 },
521
+ email: { type: 'string' },
522
+ phone: { type: 'string' },
523
+ billingAddress: addressSchema,
524
+ shippingAddress: addressSchema
525
+ }
526
+ };
527
+
528
+ const customers = [
529
+ {
530
+ id: 1,
531
+ name: 'John Doe',
532
+ email: 'john@example.com',
533
+ phone: '+1-555-1234',
534
+ billingAddress: {
535
+ street: '123 Main St',
536
+ city: 'New York',
537
+ postalCode: '10001',
538
+ country: 'US'
539
+ },
540
+ shippingAddress: {
541
+ street: '456 Oak Ave',
542
+ city: 'Brooklyn',
543
+ postalCode: '11201',
544
+ country: 'US'
545
+ },
546
+ createdAt: '2024-01-15T10:00:00Z',
547
+ updatedAt: '2024-01-15T10:00:00Z'
548
+ }
549
+ ];
550
+
551
+ try {
552
+ const csv = jsonToCsv(customers, { schema: customerSchema });
553
+ console.log('Customer data validated with reusable schema:');
554
+ console.log(csv);
555
+ } catch (error) {
556
+ console.log('Error:', error.message);
557
+ }
558
+ }
559
+
560
+ // =============================================================================
561
+ // Example 10: Schema Factory Pattern
562
+ // =============================================================================
563
+
564
+ function schemaFactoryPattern() {
565
+ console.log('\n=== Schema Factory Pattern ===\n');
566
+
567
+ // Schema factory for different entity types
568
+ const createEntitySchema = (entityType, customProperties = {}) => ({
569
+ type: 'object',
570
+ required: ['id', 'type', 'name'],
571
+ properties: {
572
+ id: { type: 'integer', minimum: 1 },
573
+ type: { type: 'string', enum: [entityType] },
574
+ name: { type: 'string', minLength: 1 },
575
+ description: { type: 'string' },
576
+ active: { type: 'boolean' },
577
+ metadata: { type: 'object' },
578
+ ...customProperties
579
+ }
580
+ });
581
+
582
+ // Create specific schemas
583
+ const productSchema = createEntitySchema('product', {
584
+ price: { type: 'number', minimum: 0 },
585
+ sku: { type: 'string', pattern: '^[A-Z]{3}-\\d{4}$' },
586
+ category: { type: 'string' }
587
+ });
588
+
589
+ const serviceSchema = createEntitySchema('service', {
590
+ hourlyRate: { type: 'number', minimum: 0 },
591
+ duration: { type: 'integer', minimum: 1 },
592
+ availability: { type: 'string', enum: ['available', 'busy', 'unavailable'] }
593
+ });
594
+
595
+ console.log('Product schema created:', Object.keys(productSchema.properties));
596
+ console.log('Service schema created:', Object.keys(serviceSchema.properties));
597
+
598
+ // Validate data
599
+ const product = {
600
+ id: 1,
601
+ type: 'product',
602
+ name: 'Widget Pro',
603
+ price: 29.99,
604
+ sku: 'WGT-0001',
605
+ category: 'widgets',
606
+ active: true
607
+ };
608
+
609
+ try {
610
+ const csv = jsonToCsv([product], { schema: productSchema });
611
+ console.log('\nProduct validated successfully');
612
+ } catch (error) {
613
+ console.log('Error:', error.message);
614
+ }
615
+ }
616
+
617
+ // =============================================================================
618
+ // Run All Examples
619
+ // =============================================================================
620
+
621
+ async function main() {
622
+ console.log('jtcsv Schema Validation Examples');
623
+ console.log('='.repeat(60));
624
+
625
+ basicSchemaValidation();
626
+ nestedSchemaValidation();
627
+ customFormatSchema();
628
+ arraySchemaValidation();
629
+ conditionalSchema();
630
+ typeCoercionSchema();
631
+ validationErrorDetails();
632
+ schemaValidationOnCsvInput();
633
+ reusableSchemaDefinitions();
634
+ schemaFactoryPattern();
635
+
636
+ console.log('\n' + '='.repeat(60));
637
+ console.log('All schema validation examples completed.');
638
+ }
639
+
640
+ main().catch(console.error);