configforge 1.0.0-beta.1 → 1.0.0-beta.10

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 (77) hide show
  1. package/README.md +574 -11
  2. package/dist/core/ConversionResult.d.ts +22 -0
  3. package/dist/core/ConversionResult.d.ts.map +1 -1
  4. package/dist/core/ConversionResult.js +44 -30
  5. package/dist/core/ConversionResult.js.map +1 -1
  6. package/dist/core/Converter.d.ts +40 -10
  7. package/dist/core/Converter.d.ts.map +1 -1
  8. package/dist/core/Converter.js +137 -29
  9. package/dist/core/Converter.js.map +1 -1
  10. package/dist/core/Mapper.d.ts +12 -0
  11. package/dist/core/Mapper.d.ts.map +1 -1
  12. package/dist/core/Mapper.js +155 -3
  13. package/dist/core/Mapper.js.map +1 -1
  14. package/dist/core/Pipeline.d.ts +42 -0
  15. package/dist/core/Pipeline.d.ts.map +1 -0
  16. package/dist/core/Pipeline.js +134 -0
  17. package/dist/core/Pipeline.js.map +1 -0
  18. package/dist/core/pipeline/PipelineBuilder.d.ts +67 -0
  19. package/dist/core/pipeline/PipelineBuilder.d.ts.map +1 -0
  20. package/dist/core/pipeline/PipelineBuilder.js +109 -0
  21. package/dist/core/pipeline/PipelineBuilder.js.map +1 -0
  22. package/dist/core/pipeline/PipelineSteps.d.ts +74 -0
  23. package/dist/core/pipeline/PipelineSteps.d.ts.map +1 -0
  24. package/dist/core/pipeline/PipelineSteps.js +298 -0
  25. package/dist/core/pipeline/PipelineSteps.js.map +1 -0
  26. package/dist/errors/ErrorCollector.d.ts +119 -0
  27. package/dist/errors/ErrorCollector.d.ts.map +1 -0
  28. package/dist/errors/ErrorCollector.js +197 -0
  29. package/dist/errors/ErrorCollector.js.map +1 -0
  30. package/dist/errors/ErrorContext.d.ts +168 -0
  31. package/dist/errors/ErrorContext.d.ts.map +1 -0
  32. package/dist/errors/ErrorContext.js +356 -0
  33. package/dist/errors/ErrorContext.js.map +1 -0
  34. package/dist/errors/ErrorRecovery.d.ts +91 -0
  35. package/dist/errors/ErrorRecovery.d.ts.map +1 -0
  36. package/dist/errors/ErrorRecovery.js +321 -0
  37. package/dist/errors/ErrorRecovery.js.map +1 -0
  38. package/dist/errors/ErrorReporter.d.ts +58 -0
  39. package/dist/errors/ErrorReporter.d.ts.map +1 -0
  40. package/dist/errors/ErrorReporter.js +262 -0
  41. package/dist/errors/ErrorReporter.js.map +1 -0
  42. package/dist/errors/ErrorTypes.d.ts +103 -0
  43. package/dist/errors/ErrorTypes.d.ts.map +1 -0
  44. package/dist/errors/ErrorTypes.js +125 -0
  45. package/dist/errors/ErrorTypes.js.map +1 -0
  46. package/dist/errors/SpecificErrors.d.ts +45 -0
  47. package/dist/errors/SpecificErrors.d.ts.map +1 -0
  48. package/dist/errors/SpecificErrors.js +124 -0
  49. package/dist/errors/SpecificErrors.js.map +1 -0
  50. package/dist/errors/SuggestionEngine.d.ts +63 -0
  51. package/dist/errors/SuggestionEngine.d.ts.map +1 -0
  52. package/dist/errors/SuggestionEngine.js +328 -0
  53. package/dist/errors/SuggestionEngine.js.map +1 -0
  54. package/dist/errors/index.d.ts +12 -0
  55. package/dist/errors/index.d.ts.map +1 -0
  56. package/dist/errors/index.js +39 -0
  57. package/dist/errors/index.js.map +1 -0
  58. package/dist/index.d.ts +3 -0
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +7 -2
  61. package/dist/index.js.map +1 -1
  62. package/dist/types/index.d.ts +8 -1
  63. package/dist/types/index.d.ts.map +1 -1
  64. package/dist/types/index.js.map +1 -1
  65. package/dist/validators/ValidatorRegistry.d.ts +55 -0
  66. package/dist/validators/ValidatorRegistry.d.ts.map +1 -0
  67. package/dist/validators/ValidatorRegistry.js +140 -0
  68. package/dist/validators/ValidatorRegistry.js.map +1 -0
  69. package/dist/validators/built-in.d.ts +93 -0
  70. package/dist/validators/built-in.d.ts.map +1 -0
  71. package/dist/validators/built-in.js +290 -0
  72. package/dist/validators/built-in.js.map +1 -0
  73. package/dist/validators/index.d.ts +4 -0
  74. package/dist/validators/index.d.ts.map +1 -0
  75. package/dist/validators/index.js +24 -0
  76. package/dist/validators/index.js.map +1 -0
  77. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # ConfigForge
2
2
 
3
- > Universal config converter framework with a fluent API
3
+ > A TypeScript library for converting, mapping, and transforming config data in JSON and YAML.
4
+
5
+ ConfigForge is a universal config converter library with a fluent API
4
6
 
5
7
  ConfigForge makes it easy to convert configuration files between different formats and structures. Just define your mappings and let ConfigForge handle the rest.
6
8
 
@@ -86,17 +88,123 @@ const converter = forge()
86
88
  })
87
89
  ```
88
90
 
89
- ### 4. Set Default Values
91
+ ### 4. Add Conditional Logic
92
+
93
+ ```javascript
94
+ // Function conditions - only apply when condition returns true
95
+ .when(source => source.user?.type === 'admin')
96
+ .map('user.permissions', 'adminPermissions')
97
+ .map('user.role', 'adminRole')
98
+ .end()
99
+
100
+ // String conditions - only apply when field exists and is truthy
101
+ .when('user.isActive')
102
+ .map('user.lastLogin', 'lastActiveLogin')
103
+ .end()
104
+ ```
105
+
106
+ ### 5. Merge Multiple Fields
90
107
 
91
108
  ```javascript
109
+ // Combine multiple source fields into one target field
110
+ .merge(['firstName', 'lastName'], 'fullName', (first, last) => `${first} ${last}`)
111
+
112
+ // Merge with transformation
113
+ .merge(['basePrice', 'tax'], 'totalPrice',
114
+ (price, tax) => price + tax,
115
+ total => `$${total.toFixed(2)}`
116
+ )
117
+
118
+ // Merge complex data
119
+ .merge(['user.profile', 'user.settings'], 'userInfo', (profile, settings) => ({
120
+ ...profile,
121
+ ...settings
122
+ }))
123
+ ```
124
+
125
+ ### 6. Set Default Values
126
+
127
+ ```javascript
128
+ // Set static default values
92
129
  .defaults({
93
130
  version: '1.0.0',
94
131
  enabled: true,
95
132
  environment: 'production'
96
133
  })
134
+
135
+ // Set dynamic default values using functions
136
+ .defaults({
137
+ timestamp: () => new Date().toISOString(),
138
+ id: () => `user_${Date.now()}`,
139
+ sessionId: () => Math.random().toString(36).substr(2, 9)
140
+ })
141
+ ```
142
+
143
+ ### 7. Add Lifecycle Hooks
144
+
145
+ ```javascript
146
+ // Before hooks - run before conversion starts
147
+ .before((sourceData) => {
148
+ console.log('Starting conversion...');
149
+ // Modify source data if needed
150
+ return {
151
+ ...sourceData,
152
+ processed: true
153
+ };
154
+ })
155
+
156
+ // After hooks - run after conversion completes
157
+ .after((targetData) => {
158
+ console.log('Conversion completed!');
159
+ // Add computed fields or modify target data
160
+ return {
161
+ ...targetData,
162
+ processedAt: new Date().toISOString(),
163
+ checksum: calculateChecksum(targetData)
164
+ };
165
+ })
166
+
167
+ // Multiple hooks execute in order
168
+ .before(validateInput)
169
+ .before(preprocessData)
170
+ .after(addMetadata)
171
+ .after(logResults)
172
+
173
+ // Async hooks are supported
174
+ .before(async (data) => {
175
+ const enrichedData = await fetchAdditionalData(data.userId);
176
+ return { ...data, ...enrichedData };
177
+ })
97
178
  ```
98
179
 
99
- ### 5. Convert Data
180
+ ### 8. Add Validation
181
+
182
+ ```javascript
183
+ const { validators } = require('configforge');
184
+
185
+ // Add field validation
186
+ .validate('email', validators.email)
187
+ .validate('age', validators.all(
188
+ validators.required,
189
+ validators.type('number'),
190
+ validators.range(18, 120)
191
+ ))
192
+ .validate('username', validators.all(
193
+ validators.required,
194
+ validators.minLength(3),
195
+ validators.pattern(/^[a-zA-Z0-9_]+$/, 'Only letters, numbers, and underscores allowed')
196
+ ))
197
+
198
+ // Custom validation with context
199
+ .validate('password', (value, context) => {
200
+ if (context.source.confirmPassword !== value) {
201
+ return 'Passwords do not match';
202
+ }
203
+ return validators.minLength(8)(value, context);
204
+ })
205
+ ```
206
+
207
+ ### 9. Convert Data
100
208
 
101
209
  ```javascript
102
210
  // Convert object data
@@ -227,7 +335,435 @@ console.log(result.data);
227
335
  // }
228
336
  ```
229
337
 
230
- ### Example 3: File Conversion
338
+ ### Example 3: Array Processing with forEach()
339
+
340
+ ```javascript
341
+ // Simple fruit inventory
342
+ const fruitData = {
343
+ storeId: 'STORE-001',
344
+ fruits: [
345
+ {
346
+ name: 'Apple',
347
+ color: 'red',
348
+ price: 1.5,
349
+ quantity: 100,
350
+ },
351
+ {
352
+ name: 'Banana',
353
+ color: 'yellow',
354
+ price: 0.75,
355
+ quantity: 80,
356
+ },
357
+ {
358
+ name: 'Orange',
359
+ color: 'orange',
360
+ price: 1.25,
361
+ quantity: 60,
362
+ },
363
+ ],
364
+ };
365
+
366
+ const converter = forge()
367
+ .from('inventory')
368
+ .to('catalog')
369
+ .map('storeId', 'storeId')
370
+ .forEach('fruits', (fruit, index) => {
371
+ return {
372
+ id: index + 1,
373
+ fruitName: fruit.name,
374
+ displayColor: fruit.color,
375
+ pricePerItem: fruit.price,
376
+ inStock: fruit.quantity,
377
+ totalValue: fruit.price * fruit.quantity,
378
+ isExpensive: fruit.price > 1.0,
379
+ };
380
+ });
381
+
382
+ const result = await converter.convert(fruitData);
383
+ console.log(result.data);
384
+ // {
385
+ // storeId: 'STORE-001',
386
+ // fruits: [
387
+ // {
388
+ // id: 1,
389
+ // fruitName: 'Apple',
390
+ // displayColor: 'red',
391
+ // pricePerItem: 1.50,
392
+ // inStock: 100,
393
+ // totalValue: 150,
394
+ // isExpensive: true
395
+ // },
396
+ // {
397
+ // id: 2,
398
+ // fruitName: 'Banana',
399
+ // displayColor: 'yellow',
400
+ // pricePerItem: 0.75,
401
+ // inStock: 80,
402
+ // totalValue: 60,
403
+ // isExpensive: false
404
+ // },
405
+ // // ... more fruits
406
+ // ]
407
+ // }
408
+ ```
409
+
410
+ ### Example 4: Conditional Mapping with when()
411
+
412
+ ```javascript
413
+ // Different types of pets need different mappings
414
+ const petData = {
415
+ type: 'dog',
416
+ name: 'Buddy',
417
+ age: 3,
418
+ dogInfo: {
419
+ breed: 'Golden Retriever',
420
+ tricks: ['sit', 'stay', 'fetch'],
421
+ },
422
+ catInfo: {
423
+ breed: 'Persian',
424
+ indoor: true,
425
+ },
426
+ birdInfo: {
427
+ species: 'Parrot',
428
+ canTalk: true,
429
+ },
430
+ };
431
+
432
+ const converter = forge()
433
+ .from('petData')
434
+ .to('petProfile')
435
+ .map('name', 'petName')
436
+ .map('age', 'petAge')
437
+ .map('type', 'animalType')
438
+
439
+ // Only map dog-specific info for dogs
440
+ .when(source => source.type === 'dog')
441
+ .map('dogInfo.breed', 'breed')
442
+ .map('dogInfo.tricks', 'knownTricks')
443
+ .end()
444
+
445
+ // Only map cat-specific info for cats
446
+ .when(source => source.type === 'cat')
447
+ .map('catInfo.breed', 'breed')
448
+ .map('catInfo.indoor', 'isIndoorCat')
449
+ .end()
450
+
451
+ // Only map bird-specific info for birds
452
+ .when(source => source.type === 'bird')
453
+ .map('birdInfo.species', 'species')
454
+ .map('birdInfo.canTalk', 'canSpeak')
455
+ .end();
456
+
457
+ const result = await converter.convert(petData);
458
+ console.log(result.data);
459
+ // {
460
+ // petName: 'Buddy',
461
+ // petAge: 3,
462
+ // animalType: 'dog',
463
+ // breed: 'Golden Retriever',
464
+ // knownTricks: ['sit', 'stay', 'fetch']
465
+ // }
466
+ ```
467
+
468
+ ### Example 5: Merge Multiple Fields with merge()
469
+
470
+ ```javascript
471
+ // Simple student report card
472
+ const studentData = {
473
+ student: {
474
+ firstName: 'Alice',
475
+ lastName: 'Smith',
476
+ },
477
+ grades: {
478
+ math: 85,
479
+ english: 92,
480
+ science: 78,
481
+ },
482
+ activities: ['soccer', 'chess', 'art'],
483
+ info: {
484
+ grade: '5th',
485
+ teacher: 'Ms. Johnson',
486
+ },
487
+ };
488
+
489
+ const converter = forge()
490
+ .from('report')
491
+ .to('summary')
492
+
493
+ // Merge student name fields
494
+ .merge(
495
+ ['student.firstName', 'student.lastName'],
496
+ 'studentName',
497
+ (first, last) => `${first} ${last}`
498
+ )
499
+
500
+ // Calculate total with transformation
501
+ .merge(
502
+ ['order.basePrice', 'order.tax', 'order.shipping'],
503
+ 'subtotal',
504
+ (base, tax, shipping) => base + tax + shipping
505
+ )
506
+
507
+ .merge(
508
+ ['order.basePrice', 'order.tax', 'order.shipping', 'order.discount'],
509
+ 'total',
510
+ (base, tax, shipping, discount) => base + tax + shipping - discount,
511
+ total => `$${total.toFixed(2)}`
512
+ ) // Transform to currency format
513
+
514
+ // Merge arrays and objects
515
+ .merge(['items', 'metadata'], 'orderSummary', (items, meta) => ({
516
+ itemCount: items.length,
517
+ items: items.join(', '),
518
+ ...meta,
519
+ }))
520
+
521
+ // Simple field mappings
522
+ .map('customer.email', 'billingEmail');
523
+
524
+ const result = await converter.convert(orderData);
525
+ console.log(result.data);
526
+ // {
527
+ // customerName: 'John Doe',
528
+ // subtotal: 121.49,
529
+ // total: '$106.49',
530
+ // orderSummary: {
531
+ // itemCount: 3,
532
+ // items: 'laptop, mouse, keyboard',
533
+ // orderDate: '2023-12-01',
534
+ // source: 'web'
535
+ // },
536
+ // billingEmail: 'john.doe@example.com'
537
+ // }
538
+ ```
539
+
540
+ ### Example 6: Data Validation
541
+
542
+ ```javascript
543
+ const { forge, validators } = require('configforge');
544
+
545
+ // User registration form data
546
+ const formData = {
547
+ personalInfo: {
548
+ firstName: 'John',
549
+ lastName: 'Doe',
550
+ email: 'john.doe@example.com',
551
+ age: 28,
552
+ },
553
+ accountInfo: {
554
+ username: 'johndoe123',
555
+ password: 'SecurePass123!',
556
+ confirmPassword: 'SecurePass123!',
557
+ },
558
+ preferences: {
559
+ newsletter: 'yes',
560
+ theme: 'dark',
561
+ language: 'en',
562
+ },
563
+ };
564
+
565
+ const converter = forge()
566
+ .from('form')
567
+ .to('user')
568
+ // Map fields
569
+ .merge(
570
+ ['personalInfo.firstName', 'personalInfo.lastName'],
571
+ 'fullName',
572
+ (first, last) => `${first} ${last}`
573
+ )
574
+ .map('personalInfo.email', 'email')
575
+ .map('personalInfo.age', 'age')
576
+ .map('accountInfo.username', 'username')
577
+ .map('accountInfo.password', 'password')
578
+ .map(
579
+ 'preferences.newsletter',
580
+ 'subscribeToNewsletter',
581
+ value => value === 'yes'
582
+ )
583
+ .map('preferences.theme', 'theme')
584
+ .map('preferences.language', 'language')
585
+
586
+ // Add validation rules
587
+ .validate(
588
+ 'fullName',
589
+ validators.all(
590
+ validators.required,
591
+ validators.minLength(2),
592
+ validators.maxLength(100)
593
+ )
594
+ )
595
+ .validate('email', validators.all(validators.required, validators.email))
596
+ .validate(
597
+ 'age',
598
+ validators.all(
599
+ validators.required,
600
+ validators.type('number'),
601
+ validators.range(13, 120)
602
+ )
603
+ )
604
+ .validate(
605
+ 'username',
606
+ validators.all(
607
+ validators.required,
608
+ validators.minLength(3),
609
+ validators.maxLength(20),
610
+ validators.pattern(
611
+ /^[a-zA-Z0-9_]+$/,
612
+ 'Username can only contain letters, numbers, and underscores'
613
+ )
614
+ )
615
+ )
616
+ .validate(
617
+ 'password',
618
+ validators.all(
619
+ validators.required,
620
+ validators.minLength(8),
621
+ validators.pattern(
622
+ /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/,
623
+ 'Password must contain lowercase, uppercase, and number'
624
+ )
625
+ )
626
+ )
627
+ .validate('theme', validators.oneOf(['light', 'dark', 'auto']))
628
+ .validate('language', validators.oneOf(['en', 'es', 'fr', 'de']))
629
+
630
+ // Custom validation
631
+ .validate('password', (value, context) => {
632
+ if (context.source.accountInfo.confirmPassword !== value) {
633
+ return 'Passwords do not match';
634
+ }
635
+ return true;
636
+ });
637
+
638
+ const result = await converter.convert(formData);
639
+
640
+ if (result.errors.length > 0) {
641
+ console.log('Validation errors:');
642
+ result.errors.forEach(error => {
643
+ console.log(`- ${error.path}: ${error.message}`);
644
+ });
645
+ } else {
646
+ console.log('User data is valid!');
647
+ console.log(result.data);
648
+ // {
649
+ // fullName: 'John Doe',
650
+ // email: 'john.doe@example.com',
651
+ // age: 28,
652
+ // username: 'johndoe123',
653
+ // password: 'SecurePass123!',
654
+ // subscribeToNewsletter: true,
655
+ // theme: 'dark',
656
+ // language: 'en'
657
+ // }
658
+ }
659
+ ```
660
+
661
+ ### Example 7: Defaults and Hooks
662
+
663
+ ```javascript
664
+ // Student data with missing fields
665
+ const studentData = {
666
+ student: {
667
+ firstName: 'Alice',
668
+ lastName: 'Smith',
669
+ // age is missing
670
+ },
671
+ grades: {
672
+ math: 85,
673
+ english: 92,
674
+ // science grade is missing
675
+ },
676
+ // activities array is missing
677
+ info: {
678
+ grade: '5th',
679
+ teacher: 'Ms. Johnson',
680
+ // school year is missing
681
+ },
682
+ };
683
+
684
+ const converter = forge()
685
+ .from('studentReport')
686
+ .to('completeProfile')
687
+
688
+ // Basic mappings
689
+ .map('student.firstName', 'firstName')
690
+ .map('student.lastName', 'lastName')
691
+ .map('student.age', 'age')
692
+ .map('grades.math', 'mathGrade')
693
+ .map('grades.english', 'englishGrade')
694
+ .map('grades.science', 'scienceGrade')
695
+ .map('activities', 'extracurriculars')
696
+ .map('info.grade', 'gradeLevel')
697
+ .map('info.teacher', 'teacher')
698
+ .map('info.schoolYear', 'academicYear')
699
+
700
+ // Set default values for missing fields
701
+ .defaults({
702
+ age: 10, // Default age for 5th graders
703
+ scienceGrade: 80, // Default science grade
704
+ extracurriculars: ['reading'], // Default activity
705
+ academicYear: () => {
706
+ // Dynamic default - current school year
707
+ const now = new Date();
708
+ const year = now.getFullYear();
709
+ const month = now.getMonth();
710
+ return month >= 8 ? `${year}-${year + 1}` : `${year - 1}-${year}`;
711
+ },
712
+ status: 'active',
713
+ lastUpdated: () => new Date().toISOString(),
714
+ })
715
+
716
+ // Add before hook to log conversion start
717
+ .before(data => {
718
+ console.log('🔄 Starting conversion...');
719
+ console.log(
720
+ `Processing student: ${data.student?.firstName} ${data.student?.lastName}`
721
+ );
722
+ return data; // Return the data unchanged
723
+ })
724
+
725
+ // Add after hook to calculate grade average
726
+ .after(data => {
727
+ console.log('✅ Conversion completed!');
728
+
729
+ // Create full name from first and last name
730
+ if (data.firstName && data.lastName) {
731
+ data.fullName = `${data.firstName} ${data.lastName}`;
732
+ }
733
+
734
+ // Calculate and add grade average
735
+ const { mathGrade, englishGrade, scienceGrade } = data;
736
+ if (mathGrade && englishGrade && scienceGrade) {
737
+ data.gradeAverage = Math.round(
738
+ (mathGrade + englishGrade + scienceGrade) / 3
739
+ );
740
+ console.log(`Calculated grade average: ${data.gradeAverage}`);
741
+ }
742
+
743
+ return data; // Return the modified data
744
+ });
745
+
746
+ const result = await converter.convert(studentData);
747
+ console.log(result.data);
748
+ // {
749
+ // firstName: 'Alice',
750
+ // lastName: 'Smith',
751
+ // mathGrade: 85,
752
+ // englishGrade: 92,
753
+ // gradeLevel: '5th',
754
+ // teacher: 'Ms. Johnson',
755
+ // age: 10,
756
+ // scienceGrade: 80,
757
+ // extracurriculars: ['reading'],
758
+ // academicYear: '2024-2025',
759
+ // status: 'active',
760
+ // lastUpdated: '2024-12-23T06:22:05.491Z',
761
+ // fullName: 'Alice Smith',
762
+ // gradeAverage: 86
763
+ // }
764
+ ```
765
+
766
+ ### Example 8: File Conversion
231
767
 
232
768
  ```javascript
233
769
  // Convert YAML file to JSON structure
@@ -248,11 +784,15 @@ await result.save('./config.json');
248
784
  ## 🎯 Key Features
249
785
 
250
786
  - ✅ **Simple API**: Just map fields and convert
787
+ - ✅ **Pipeline Architecture**: Robust internal processing with configurable steps and error handling
251
788
  - ✅ **No direct Mapper usage needed**: The `convert()` method handles everything
252
789
  - ✅ **Nested object support**: Use dot notation like `user.profile.name`
253
790
  - ✅ **Array access**: Use bracket notation like `items[0]`
254
791
  - ✅ **Transformations**: Transform values during mapping
792
+ - ✅ **Conditional mapping**: Use `when()` for conditional logic
793
+ - ✅ **Multi-field merging**: Use `merge()` to combine multiple sources into one target
255
794
  - ✅ **Default values**: Set fallback values
795
+ - ✅ **Comprehensive Error Handling**: Advanced error reporting with context and suggestions ⭐ NEW!
256
796
  - ✅ **File support**: Convert YAML, JSON files directly
257
797
  - ✅ **Statistics**: Get detailed conversion reports
258
798
  - ✅ **TypeScript**: Full type safety
@@ -264,16 +804,19 @@ await result.save('./config.json');
264
804
  - Basic field mapping with `map()`
265
805
  - Nested object and array access
266
806
  - Value transformations
267
- - Default values with `defaults()`
807
+ - **Default values with `defaults()`** ⭐ ENHANCED!
808
+ - **Array/object processing with `forEach()`**
809
+ - **Conditional mapping with `when()`**
810
+ - **Multi-field merging with `merge()`**
811
+ - **Field validation with `validate()`**
812
+ - **Lifecycle hooks with `before()` and `after()`** ⭐ NEW!
813
+ - **Advanced error handling and reporting system** ⭐ NEW!
268
814
  - File parsing (YAML, JSON)
269
815
  - Conversion statistics and reporting
270
- - Before/after hooks
816
+ - Async and sync conversion support
271
817
 
272
818
  **🚧 Coming Soon:**
273
819
 
274
- - Conditional mapping with `when()`
275
- - Array processing with `forEach()`
276
- - Field validation
277
820
  - CLI generation
278
821
  - Plugin system
279
822
 
@@ -283,9 +826,29 @@ await result.save('./config.json');
283
826
  2. **Use dot notation** for nested objects: `'user.profile.name'`
284
827
  3. **Use bracket notation** for arrays: `'items[0]'`, `'items[1]'`
285
828
  4. **Transform functions** get the value and context: `(value, ctx) => { ... }`
286
- 5. **Check `result.unmapped`** to see which fields weren't mapped
287
- 6. **Use `result.print()`** for a nice conversion report
829
+ 5. **Use conditional mapping** with `when()` for type-specific logic: `when(source => source.accountType === 'premium')`
830
+ 6. **Use merge()** to combine multiple fields: `merge(['field1', 'field2'], 'result', (a, b) => a + b)`
831
+ 7. **Use validation** to ensure data quality: `validate('email', validators.email)`
832
+ 8. **Combine validators** with `validators.all()` for multiple rules
833
+ 9. **Always call `.end()`** after conditional mappings to return to the main converter
834
+ 10. **Check `result.errors`** to see validation failures
835
+ 11. **Check `result.unmapped`** to see which fields weren't mapped
836
+ 12. **Use `result.print()`** for a nice conversion report
837
+ 13. **Use `defaults()`** to provide fallback values for missing fields: `defaults({ status: 'active' })`
838
+ 14. **Use function defaults** for dynamic values: `defaults({ timestamp: () => new Date().toISOString() })`
839
+ 15. **Use `before()` hooks** to preprocess source data before conversion
840
+ 16. **Use `after()` hooks** to postprocess target data after conversion
841
+ 17. **Hooks can be async** - just use `async (data) => { ... }` and they'll be awaited
842
+ 18. **Multiple hooks execute in order** - add as many as you need for complex workflows
843
+ 19. **Error handling provides helpful suggestions** - when field mapping fails, you'll get suggestions for similar field names
844
+ 20. **Errors include rich context** - see exactly where and why conversions failed with detailed error information
845
+ 21. **Use error categories** to filter and handle different types of errors (validation, mapping, parsing, etc.)
288
846
 
289
847
  ---
290
848
 
291
849
  That's it! ConfigForge makes config conversion simple and straightforward. No complex setup, no direct class manipulation - just define your mappings and convert.
850
+
851
+ ## License
852
+
853
+ This package is licensed under the **PolyForm Noncommercial License 1.0.0**.
854
+ See the [LICENSE](./LICENSE) file for full terms.
@@ -8,6 +8,8 @@ export declare class ConversionResultImpl implements ConversionResult {
8
8
  unmapped: string[];
9
9
  errors: ConfigForgeError[];
10
10
  stats: ConversionStats;
11
+ private errorCollector;
12
+ private errorReporter;
11
13
  constructor(data: any, warnings: Warning[] | undefined, unmapped: string[] | undefined, errors: ConfigForgeError[] | undefined, stats: ConversionStats);
12
14
  /**
13
15
  * Save the converted data to a file
@@ -25,6 +27,26 @@ export declare class ConversionResultImpl implements ConversionResult {
25
27
  * Pretty print conversion results to console
26
28
  */
27
29
  print(): void;
30
+ /**
31
+ * Get detailed error report
32
+ */
33
+ getErrorReport(format?: 'text' | 'json' | 'summary'): string;
34
+ /**
35
+ * Check if conversion was successful (no critical errors)
36
+ */
37
+ isSuccess(): boolean;
38
+ /**
39
+ * Get error summary
40
+ */
41
+ getErrorSummary(): string;
42
+ /**
43
+ * Get errors grouped by type
44
+ */
45
+ getErrorsByType(): Record<string, ConfigForgeError[]>;
46
+ /**
47
+ * Get warnings grouped by type
48
+ */
49
+ getWarningsByType(): Record<string, Warning[]>;
28
50
  /**
29
51
  * Get file extension from path
30
52
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ConversionResult.d.ts","sourceRoot":"","sources":["../../src/core/ConversionResult.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,OAAO,EACP,gBAAgB,EACjB,MAAM,UAAU,CAAC;AAIlB;;GAEG;AACH,qBAAa,oBAAqB,YAAW,gBAAgB;IAElD,IAAI,EAAE,GAAG;IACT,QAAQ,EAAE,OAAO,EAAE;IACnB,QAAQ,EAAE,MAAM,EAAE;IAClB,MAAM,EAAE,gBAAgB,EAAE;IAC1B,KAAK,EAAE,eAAe;gBAJtB,IAAI,EAAE,GAAG,EACT,QAAQ,EAAE,OAAO,EAAE,YAAK,EACxB,QAAQ,EAAE,MAAM,EAAE,YAAK,EACvB,MAAM,EAAE,gBAAgB,EAAE,YAAK,EAC/B,KAAK,EAAE,eAAe;IAG/B;;OAEG;IACG,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBvC;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;OAEG;IACH,MAAM,IAAI,MAAM;IAQhB;;OAEG;IACH,KAAK,IAAI,IAAI;IA2Db;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAKzB"}
1
+ {"version":3,"file":"ConversionResult.d.ts","sourceRoot":"","sources":["../../src/core/ConversionResult.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,OAAO,EACP,gBAAgB,EACjB,MAAM,UAAU,CAAC;AAKlB;;GAEG;AACH,qBAAa,oBAAqB,YAAW,gBAAgB;IAKlD,IAAI,EAAE,GAAG;IACT,QAAQ,EAAE,OAAO,EAAE;IACnB,QAAQ,EAAE,MAAM,EAAE;IAClB,MAAM,EAAE,gBAAgB,EAAE;IAC1B,KAAK,EAAE,eAAe;IAR/B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,aAAa,CAAgB;gBAG5B,IAAI,EAAE,GAAG,EACT,QAAQ,EAAE,OAAO,EAAE,YAAK,EACxB,QAAQ,EAAE,MAAM,EAAE,YAAK,EACvB,MAAM,EAAE,gBAAgB,EAAE,YAAK,EAC/B,KAAK,EAAE,eAAe;IAS/B;;OAEG;IACG,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBvC;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;OAEG;IACH,MAAM,IAAI,MAAM;IAQhB;;OAEG;IACH,KAAK,IAAI,IAAI;IAmCb;;OAEG;IACH,cAAc,CAAC,MAAM,GAAE,MAAM,GAAG,MAAM,GAAG,SAAkB,GAAG,MAAM;IAIpE;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,eAAe,IAAI,MAAM;IAIzB;;OAEG;IACH,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAIrD;;OAEG;IACH,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;IAI9C;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAKzB"}