@edirect/template 11.0.45 → 11.0.46

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.
package/dist/README.md ADDED
@@ -0,0 +1,1115 @@
1
+ # @edirect/template
2
+
3
+ `@edirect/template` is a flexible library for transforming payloads based on declarative templates. It supports mapping fields, applying custom transformers, setting default values, handling nested objects, and working with arrays.
4
+
5
+ ## Features
6
+
7
+ - Declarative template-based payload transformation
8
+ - Custom transformer functions for mapping, validation, formatting, and business rules
9
+ - Support for nested objects and arrays
10
+ - Default values and context-aware mapping
11
+ - Sequential transformers and transformer parameters
12
+
13
+ ---
14
+
15
+ ## Installation
16
+
17
+ ```sh
18
+ pnpm add @edirect/template
19
+ # or
20
+ npm install @edirect/template
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ Import the module:
26
+
27
+ ```js
28
+ import { TemplateModule } from '@edirect/template';
29
+ ```
30
+
31
+ ## API
32
+
33
+ ### Constructor
34
+
35
+ The `TemplateModule` class can be instantiated directly:
36
+
37
+ ```js
38
+ const templateModule = new TemplateModule();
39
+ ```
40
+
41
+ ### setContext(context: object): void
42
+
43
+ Sets the context object to be used during transformation.
44
+
45
+ ### setTemplate(template: object): void
46
+
47
+ Sets the template object that describes the transformation to be performed.
48
+
49
+ ### setTransformers(transformers: ITransformer): void
50
+
51
+ Sets the transformers to be used during the transformation.
52
+
53
+ ### setOptions(options: ITemplateOptions): void
54
+
55
+ Sets options to be used during and after the transformation.
56
+
57
+ ### verifyTransformer(transformer: ITransformer, methodName: string): boolean
58
+
59
+ Verifies if a given transformer method exists.
60
+
61
+ ### runTransformer(transformer: string, value?: unknown): unknown | null
62
+
63
+ Runs a transformer on a given value.
64
+
65
+ - `transformer`: The name of the transformer to use
66
+ - `value`: The value to be transformed
67
+
68
+ ### checkValue(value: any): boolean
69
+
70
+ Checks if a given value is not null, undefined, or an empty string.
71
+
72
+ ### setValueByCondition(object, key: string, value: unknown)
73
+
74
+ Sets a value in an object after verifying with `checkValue()`.
75
+
76
+ - `object`: The object to modify
77
+ - `key`: The key to set
78
+ - `value`: The value to set
79
+
80
+ ### transformPayload<T, U>(obj: T, template = this.template): U
81
+
82
+ Transforms a payload object using the provided template.
83
+
84
+ ## Simple Example
85
+
86
+ ```javascript
87
+ import { TemplateModule } from '@edirect/template';
88
+
89
+ const template = {
90
+ edirect_firstname: 'subscriber.firstName',
91
+ edirect_lastname: 'subscriber.lastName',
92
+ };
93
+
94
+ const dataSource = {
95
+ subscriber: {
96
+ firstName: 'template',
97
+ lastName: 'service',
98
+ },
99
+ };
100
+
101
+ const templateModule = new TemplateModule();
102
+ templateModule.setTemplate(template);
103
+
104
+ const result = templateModule.transformPayload(dataSource);
105
+
106
+ console.log(result);
107
+
108
+ // {
109
+ // edirect_firstname: "template",
110
+ // edirect_lastname: "service",
111
+ // }
112
+ ```
113
+
114
+ ## Example with Transformers
115
+
116
+ #### First of all, what's a transformer?
117
+
118
+ A transformer is a way to handle values with more detail and freedom.
119
+
120
+ For example:
121
+
122
+ - Mapping
123
+ - Validation
124
+ - Formatting
125
+ - Business rules
126
+ - and so on ...
127
+
128
+ Each transformer receives two parameters:
129
+
130
+ - `value`: specific value that you want to handle
131
+ - `context`: all context (payload) that you can use to build any logical
132
+
133
+ To map a value that you'd like to use some transformer feature, you can use these options:
134
+
135
+ - `fields`: it's an array with a data source path, and the first value that is found will be used.
136
+ - `transformer`: it's a JS function, where you receive value and context as parameters and have all freedom to handle and return a value
137
+ - `defaultValue` it's an option if the engine doesn't find any value in the fields data source array or the transformer doesn't return a value.
138
+
139
+ ##### File name: baseTransformers.ts
140
+
141
+ ```javascript
142
+ import { ITransformer, ITransformerParams } from "@edirect/template";
143
+
144
+ const upperCase = ({ value }: ITransformerParams): string | null => {
145
+ return value ? String(value).toUpperCase() : null;
146
+ };
147
+
148
+ const fullName = ({ context }: ITransformerParams): string | null => {
149
+ try {
150
+ const { firstName, lastName } = context.subscriber;
151
+ return `${firstName} ${lastName}`;
152
+ } catch (error) {
153
+ return null;
154
+ }
155
+ };
156
+
157
+ const transformers: ITransformer = {
158
+ upperCase,
159
+ fullName,
160
+ };
161
+
162
+ export default transformers;
163
+ ```
164
+
165
+ ##### File name: index.ts
166
+
167
+ ```javascript
168
+ import { TemplateModule } from '@edirect/template';
169
+ import baseTransformers from './baseTransformers';
170
+
171
+ const template = {
172
+ edirect_firstname: {
173
+ fields: ['firstName', 'subscriber.firstName'],
174
+ transformer: 'upperCase',
175
+ defaultValue: 'First Name - Default',
176
+ },
177
+ edirect_lastname: {
178
+ fields: ['lastName', 'subscriber.lastName'],
179
+ },
180
+ edirect_fullname: {
181
+ transformer: 'fullName',
182
+ },
183
+ edirect_phone: {
184
+ fields: ['phoneNumber', 'subscriber.phoneNumber'],
185
+ defaultValue: '999999999',
186
+ },
187
+ timeZone: {
188
+ defaultValue: 'Time zone in Porto (GMT+1)',
189
+ },
190
+ };
191
+
192
+ const dataSource = {
193
+ subscriber: {
194
+ firstName: 'template',
195
+ lastName: 'service',
196
+ },
197
+ };
198
+
199
+ const templateModule = new TemplateModule();
200
+
201
+ templateModule.setTemplate(template);
202
+ templateModule.setContext(dataSource);
203
+ templateModule.setTransformers(baseTransformers);
204
+
205
+ const result = templateModule.transformPayload(dataSource);
206
+ console.log(result);
207
+
208
+ // {
209
+ // edirect_firstname: "TEMPLATE",
210
+ // edirect_lastname: "service",
211
+ // edirect_fullname: "template service",
212
+ // edirect_phone: "999999999",
213
+ // timeZone: "Time zone in Porto (GMT+1)",
214
+ // }
215
+ ```
216
+
217
+ ## Example with Nested Object + Transformers
218
+
219
+ `Note`: the transformer notation uses three keys to identify an object as being a transformer: fields, transformer, and defaultValue, if there are at least 1 of these keys, the engine will consider the object as being a transformer, on the other hand, if there isn't, the engine will consider as a nested object to mapper all information.
220
+
221
+ ##### File name: baseTransformers.ts
222
+
223
+ ```javascript
224
+ import { ITransformer, ITransformerParams } from "@edirect/template";
225
+
226
+ const upperCase = ({ value }: ITransformerParams): string | null => {
227
+ return value ? String(value).toUpperCase() : null;
228
+ };
229
+
230
+ const transformers: ITransformer = {
231
+ upperCase,
232
+ };
233
+
234
+ export default transformers;
235
+ ```
236
+
237
+ ##### File name: index.ts
238
+
239
+ ```javascript
240
+ import { TemplateModule } from '@edirect/template';
241
+ import baseTransformers from './baseTransformers';
242
+
243
+ const template = {
244
+ order: {
245
+ date: 'order.date',
246
+ value: 'order.value',
247
+ subscriber: {
248
+ name: 'sub.name',
249
+ phone: 'sub.phone',
250
+ email: {
251
+ fields: ['email', 'sub.email'],
252
+ },
253
+ address: {
254
+ street: 'sub.add.stt',
255
+ number: 'sub.add.num',
256
+ city: {
257
+ fields: ['sub.add.city'],
258
+ transformer: 'upperCase',
259
+ },
260
+ state: {
261
+ fields: ['sub.add.stt'],
262
+ transformer: 'upperCase',
263
+ },
264
+ zip: {
265
+ fields: ['sub.add.zip'],
266
+ defaultValue: '0000-000',
267
+ },
268
+ },
269
+ },
270
+ },
271
+ };
272
+
273
+ const dataSource = {
274
+ order: {
275
+ value: 1000.0,
276
+ date: '2000-01-01',
277
+ },
278
+ sub: {
279
+ name: 'name-test',
280
+ phone: '999999999',
281
+ email: 'template.service@bolltech.io',
282
+ add: {
283
+ st: 'st-test',
284
+ num: 100,
285
+ city: 'city-test',
286
+ stt: 'state-test',
287
+ zip: 'zip-test',
288
+ },
289
+ },
290
+ };
291
+
292
+ const templateModule = new TemplateModule();
293
+
294
+ templateModule.setTemplate(template);
295
+ templateModule.setContext(dataSource);
296
+ templateModule.setTransformers(baseTransformers);
297
+
298
+ const result = templateModule.transformPayload(dataSource);
299
+ console.log(result);
300
+
301
+ // {
302
+ // order: {
303
+ // date: "2000-01-01",
304
+ // value: 1000,
305
+ // subscriber: {
306
+ // name: "name-test",
307
+ // phone: "999999999",
308
+ // email: "template.service@bolltech.io",
309
+ // address: {
310
+ // street: "state-test",
311
+ // number: 100,
312
+ // city: "CITY-TEST",
313
+ // state: "STATE-TEST",
314
+ // zip: "zip-test",
315
+ // },
316
+ // },
317
+ // },
318
+ // }
319
+ ```
320
+
321
+ ## Example with Arrays + Transformers
322
+
323
+ `Note`: When it comes to arrays mapper, we need to have in mind that is required use this two keys: arraySource and arrayTemplate.
324
+
325
+ - `arraySource`: source path where the engine will seek the information to mapper
326
+ - `arrayTemplate`: template that will be used for each object within the array
327
+
328
+ ##### File name: baseTransformers.ts
329
+
330
+ ```javascript
331
+ import { ITransformer, ITransformerParams } from "@edirect/template";
332
+
333
+ const upperCase = ({ value }: ITransformerParams): string | null => {
334
+ return value ? String(value).toUpperCase() : null;
335
+ };
336
+
337
+ const transformers: ITransformer = {
338
+ upperCase,
339
+ };
340
+
341
+ export default transformers;
342
+ ```
343
+
344
+ ##### File name: index.ts
345
+
346
+ ```javascript
347
+ import { TemplateModule } from '@edirect/template';
348
+ import baseTransformers from './baseTransformers';
349
+
350
+ const template = {
351
+ quote: {
352
+ orders: {
353
+ arraySource: 'order',
354
+ arrayTemplate: {
355
+ value: 'value',
356
+ date: 'date',
357
+ products: {
358
+ arraySource: 'products',
359
+ arrayTemplate: {
360
+ id: 'id',
361
+ value: 'value',
362
+ description: {
363
+ fields: ['description'],
364
+ transformer: 'upperCase',
365
+ defaultValue: 'Default description',
366
+ },
367
+ categories: 'categories',
368
+ },
369
+ },
370
+ },
371
+ },
372
+ },
373
+ };
374
+
375
+ const dataSource = {
376
+ order: [
377
+ {
378
+ value: 1000.0,
379
+ date: '2000-01-01',
380
+ products: [
381
+ {
382
+ id: 'id-test-1',
383
+ value: 1000,
384
+ description: 'description-test 1',
385
+ categories: ['category-1'],
386
+ },
387
+ {
388
+ id: 'id-test-2',
389
+ value: 2000,
390
+ description: 'description-test 2',
391
+ categories: ['category-1', 'category-2'],
392
+ },
393
+ {
394
+ id: 'id-test-3',
395
+ value: 3000,
396
+ categories: ['category-1', 'category-2', 'category-3'],
397
+ },
398
+ ],
399
+ },
400
+ ],
401
+ };
402
+
403
+ const templateModule = new TemplateModule();
404
+
405
+ templateModule.setTemplate(template);
406
+ templateModule.setContext(dataSource);
407
+ templateModule.setTransformers(baseTransformers);
408
+
409
+ const result = templateModule.transformPayload(dataSource);
410
+ console.log(result);
411
+
412
+ //{
413
+ // quote: {
414
+ // orders: [
415
+ // {
416
+ // value: 1000,
417
+ // date: "2000-01-01",
418
+ // products: [
419
+ // {
420
+ // id: "id-test-1",
421
+ // value: 1000,
422
+ // description: "DESCRIPTION-TEST 1",
423
+ // categories: ["category-1"],
424
+ // },
425
+ // {
426
+ // id: "id-test-2",
427
+ // value: 2000,
428
+ // description: "DESCRIPTION-TEST 2",
429
+ // categories: ["category-1", "category-2"],
430
+ // },
431
+ // {
432
+ // id: "id-test-3",
433
+ // value: 3000,
434
+ // description: "Default description",
435
+ // categories: ["category-1", "category-2", "category-3"],
436
+ // },
437
+ // ],
438
+ // },
439
+ // ],
440
+ // },
441
+ // }
442
+ ```
443
+
444
+ ## Example with Arrays + ignoreIndexs
445
+
446
+ `Note`: When it comes to arrays mapper, we need to have in mind that is required use this two keys: arraySource and arrayTemplate.
447
+
448
+ - `arraySource`: source path where the engine will seek the information to mapper
449
+ - `arrayTemplate`: template that will be used for each object within the array
450
+ - `ignoreIndexs`: array with the index position that must be ignore
451
+
452
+ ##### File name: baseTransformers.ts
453
+
454
+ ```javascript
455
+ import { ITransformer, ITransformerParams } from "@edirect/template";
456
+
457
+ const upperCase = ({ value }: ITransformerParams): string | null => {
458
+ return value ? String(value).toUpperCase() : null;
459
+ };
460
+
461
+ const transformers: ITransformer = {
462
+ upperCase,
463
+ };
464
+
465
+ export default transformers;
466
+ ```
467
+
468
+ ##### File name: index.ts
469
+
470
+ ```javascript
471
+ import { TemplateModule } from '@edirect/template';
472
+ import baseTransformers from './baseTransformers';
473
+
474
+ const template = {
475
+ quote: {
476
+ orders: {
477
+ arraySource: 'order',
478
+ arrayTemplate: {
479
+ value: 'value',
480
+ date: 'date',
481
+ products: {
482
+ arraySource: 'products',
483
+ arrayTemplate: {
484
+ id: 'id',
485
+ value: 'value',
486
+ description: {
487
+ fields: ['description'],
488
+ transformer: 'upperCase',
489
+ defaultValue: 'Default description',
490
+ },
491
+ categories: 'categories',
492
+ },
493
+ ignoreIndexs: [0],
494
+ },
495
+ },
496
+ },
497
+ },
498
+ };
499
+
500
+ const dataSource = {
501
+ order: [
502
+ {
503
+ value: 1000.0,
504
+ date: '2000-01-01',
505
+ products: [
506
+ {
507
+ id: 'id-test-1',
508
+ value: 1000,
509
+ description: 'description-test 1',
510
+ categories: ['category-1'],
511
+ },
512
+ {
513
+ id: 'id-test-2',
514
+ value: 2000,
515
+ description: 'description-test 2',
516
+ categories: ['category-1', 'category-2'],
517
+ },
518
+ {
519
+ id: 'id-test-3',
520
+ value: 3000,
521
+ categories: ['category-1', 'category-2', 'category-3'],
522
+ },
523
+ ],
524
+ },
525
+ ],
526
+ };
527
+
528
+ const templateModule = new TemplateModule();
529
+
530
+ templateModule.setTemplate(template);
531
+ templateModule.setContext(dataSource);
532
+ templateModule.setTransformers(baseTransformers);
533
+
534
+ const result = templateModule.transformPayload(dataSource);
535
+ console.log(result);
536
+
537
+ //{
538
+ // quote: {
539
+ // orders: [
540
+ // {
541
+ // value: 1000,
542
+ // date: "2000-01-01",
543
+ // products: [
544
+ // {
545
+ // id: "id-test-2",
546
+ // value: 2000,
547
+ // description: "DESCRIPTION-TEST 2",
548
+ // categories: ["category-1", "category-2"],
549
+ // },
550
+ // {
551
+ // id: "id-test-3",
552
+ // value: 3000,
553
+ // description: "Default description",
554
+ // categories: ["category-1", "category-2", "category-3"],
555
+ // },
556
+ // ],
557
+ // },
558
+ // ],
559
+ // },
560
+ // }
561
+ ```
562
+
563
+ ## Example: Transformer + transformerParams
564
+
565
+ ##### File name: baseTransformers.ts
566
+
567
+ ```javascript
568
+ import { ITransformer, ITransformerParams } from "@edirect/template";
569
+
570
+ const concat = (
571
+ { value }: ITransformerParams,
572
+ ...itensToConcat: string[]
573
+ ): string => {
574
+ const arrayToConcat = [value, ...itensToConcat];
575
+ return arrayToConcat.join("");
576
+ };
577
+
578
+ const concatWithSeparator = (
579
+ { value }: ITransformerParams,
580
+ separator: string,
581
+ ...itensToConcat: string[]
582
+ ): string => {
583
+ const arrayToConcat = [value, ...itensToConcat];
584
+ return arrayToConcat.join(separator);
585
+ };
586
+
587
+ const transformers: ITransformer = {
588
+ concat,
589
+ concatWithSeparator,
590
+ };
591
+
592
+ export default transformers;
593
+ ```
594
+
595
+ ##### File name: index.ts
596
+
597
+ ```javascript
598
+ import { TemplateModule } from '@edirect/template';
599
+ import baseTransformers from './baseTransformers';
600
+
601
+ const template = {
602
+ status: 'status',
603
+ concatenated_result: {
604
+ fields: ['lead_id'],
605
+ transformer: 'concat',
606
+ transformerParams: [
607
+ '-',
608
+ '${person_number}',
609
+ '/',
610
+ '${person_number2}',
611
+ '_',
612
+ '${person_number3}',
613
+ ],
614
+ },
615
+ concatenated_result2: {
616
+ fields: ['lead_id'],
617
+ transformer: 'concatWithSeparator',
618
+ transformerParams: [
619
+ '-',
620
+ '${person_number}',
621
+ '${person_number2}',
622
+ '${person_number3}',
623
+ ],
624
+ },
625
+ };
626
+
627
+ const dataSource = {
628
+ status: true,
629
+ lead_id: 'FR-14af3f',
630
+ person_number: 123,
631
+ person_number2: 456,
632
+ person_number3: 789,
633
+ };
634
+
635
+ const templateModule = new TemplateModule();
636
+
637
+ templateModule.setTemplate(template);
638
+ templateModule.setContext(dataSource);
639
+ templateModule.setTransformers(baseTransformers);
640
+
641
+ const result = templateModule.transformPayload(dataSource);
642
+ console.log(result);
643
+
644
+ // {
645
+ // status: true,
646
+ // concatenated_result: "FR-14af3f-123/456_789",
647
+ // concatenated_result2: "FR-14af3f-123-456-789"
648
+ // }
649
+ ```
650
+
651
+ ## Example: Transformer + transformerParams + complexParams
652
+
653
+ ##### File name: baseTransformers.ts
654
+
655
+ ```javascript
656
+ import { ITransformer, ITransformerParams } from "@edirect/template";
657
+
658
+ const translator = ({ value }: ITransformerParams, translateDict: Record<string, string>): string => {
659
+ const translated = translateDict.?[value];
660
+ if (!translated) return null;
661
+ return translated;
662
+ };
663
+
664
+ const transformers: ITransformer = {
665
+ translator,
666
+ };
667
+
668
+ export default transformers;
669
+ ```
670
+
671
+ ##### File name: index.ts
672
+
673
+ ```javascript
674
+ import { TemplateModule } from '@edirect/template';
675
+ import baseTransformers from './baseTransformers';
676
+
677
+ const template = {
678
+ status: {
679
+ fields: ['status'],
680
+ transformer: 'translator',
681
+ transformerParams: [
682
+ {
683
+ ERROR: 'ERROR',
684
+ RECHAZADA: 'REJECTED',
685
+ },
686
+ ],
687
+ },
688
+ };
689
+
690
+ const dataSource = {
691
+ status: 'RECHAZADA',
692
+ };
693
+
694
+ const templateModule = new TemplateModule();
695
+
696
+ templateModule.setTemplate(template);
697
+ templateModule.setContext(dataSource);
698
+ templateModule.setTransformers(baseTransformers);
699
+
700
+ const result = templateModule.transformPayload(dataSource);
701
+ console.log(result);
702
+
703
+ // {
704
+ // status: "REJECTED",
705
+ // }
706
+ ```
707
+
708
+ ## Example: Sequential Transformers
709
+
710
+ The library now supports applying multiple transformers sequentially to a single field. This is particularly useful for more complex transformations that require multiple steps.
711
+
712
+ Each transformer in the sequence will receive the output of the previous transformer as its input value. The `allowNull` property of the last transformer in the sequence determines whether null values are allowed in the final output.
713
+
714
+ ##### File name: baseTransformers.ts
715
+
716
+ ```javascript
717
+ import { ITransformer, ITransformerParams } from "@edirect/template";
718
+
719
+ const findKeyInArrayGetField = (
720
+ { value, context }: ITransformerParams,
721
+ key: string,
722
+ valueToFind: string,
723
+ field: string,
724
+ transformer: any,
725
+ ...params: any
726
+ ): any | null => {
727
+ const listToFind = findKeyInArray({ value }, key, valueToFind);
728
+ if (typeof transformer !== "undefined") {
729
+ value = _.get(listToFind, field, null);
730
+ let transformerParams = params;
731
+ if (field === "#") {
732
+ transformerParams = [];
733
+ for (const fieldItem of params) {
734
+ let item = fieldItem;
735
+ if (fieldItem.includes("#")) {
736
+ item = _.get(listToFind, fieldItem.replace(/\#\{(.*)\}/, "$1"), null);
737
+ }
738
+ transformerParams.push(item);
739
+ }
740
+ }
741
+ if (typeof baseTransformers[transformer] !== "undefined") {
742
+ return baseTransformers[transformer]({ value, context }, ...transformerParams);
743
+ }
744
+ }
745
+ return _.get(listToFind, field, null);
746
+ };
747
+
748
+ const calculateAgeByBirthdate = ({ value }: ITransformerParams, ...formatDate: string[]): string | null => {
749
+ if (!value) return null;
750
+
751
+ if (!formatDate.length) formatDate.push("dd/MM/yyyy");
752
+
753
+ for (const format of formatDate) {
754
+ const date = parse(value, format, new Date());
755
+ if (isValid(date)) {
756
+ return differenceInYears(new Date(), date).toString();
757
+ }
758
+ }
759
+ return null;
760
+ };
761
+
762
+ const transformers: ITransformer = {
763
+ findKeyInArrayGetField,
764
+ calculateAgeByBirthdate
765
+ };
766
+
767
+ export default transformers;
768
+ ```
769
+
770
+ ##### File name: index.ts
771
+
772
+ ```javascript
773
+ import { TemplateModule } from '@edirect/template';
774
+ import baseTransformers from './baseTransformers';
775
+
776
+ const template = {
777
+ age: {
778
+ transformers: [
779
+ {
780
+ fields: ['data.externalReferences'],
781
+ transformer: 'findKeyInArrayGetField',
782
+ transformerParams: ['type', 'birthDate', 'value'],
783
+ },
784
+ {
785
+ transformer: 'calculateAgeByBirthdate',
786
+ transformerParams: ["yyyy-MM-dd'T'HH:mm:ss.SSSXXX"],
787
+ },
788
+ ],
789
+ },
790
+ };
791
+
792
+ const dataSource = {
793
+ data: {
794
+ externalReferences: [
795
+ {
796
+ type: 'randomKey',
797
+ value: 'randomValue',
798
+ },
799
+ {
800
+ type: 'birthDate',
801
+ value: '1995-12-27T15:22:32.511+00:00',
802
+ },
803
+ ],
804
+ },
805
+ };
806
+
807
+ const templateModule = new TemplateModule();
808
+
809
+ templateModule.setTemplate(template);
810
+ templateModule.setContext(dataSource);
811
+ templateModule.setTransformers(baseTransformers);
812
+
813
+ const result = templateModule.transformPayload(dataSource);
814
+ console.log(result);
815
+
816
+ // {
817
+ // age: "29"
818
+ // }
819
+ ```
820
+
821
+ In this example:
822
+
823
+ 1. The first transformer (`findKeyInArrayGetField`) extracts the birthdate value from the array of external references
824
+ 2. The second transformer (`calculateAgeByBirthdate`) calculates the age from the birthdate
825
+
826
+ The transformers are applied sequentially, with each one receiving the result of the previous transformation as its input value.
827
+
828
+ ### Example with DynamicArrayMapper in transformers array
829
+
830
+ The library now supports using DynamicArrayMapper as an element in the transformers array. This allows you to dynamically process arrays within a transformation sequence.
831
+
832
+ ##### File name: baseTransformers.ts
833
+
834
+ ```javascript
835
+ import { ITransformer, ITransformerParams } from "@edirect/template";
836
+
837
+ const addAdditionalDriver = ({ context, value }: ITransformerParams): any => {
838
+ if (!value || (value as any[]).length === 0) {
839
+ return;
840
+ }
841
+ const drivers: any[] = value;
842
+ const result = drivers.reduce((acc, driver) => {
843
+ acc.push(driver);
844
+ const type = driver.type;
845
+ if (type === "ID") {
846
+ const newDriver = cloneDeep(driver);
847
+ newDriver.type = "ND";
848
+ acc.push(newDriver);
849
+ }
850
+ return acc;
851
+ }, []);
852
+
853
+ return result;
854
+ };
855
+
856
+ const transformers: ITransformer = {
857
+ addAdditionalDriver,
858
+ };
859
+
860
+ export default transformers;
861
+ ```
862
+
863
+ ##### File name: index.ts
864
+
865
+ ```javascript
866
+ import { TemplateModule } from "@edirect/template";
867
+ import baseTransformers from "./baseTransformers";
868
+
869
+ const data = {
870
+ drivers: [
871
+ {value: 'john.doe@example.com', type:"ID" },
872
+ {value: '1234567890', type:"ND" },
873
+ {value: '123 Main St, City, Country', type:"ND" }
874
+ ]
875
+ };
876
+
877
+ const template = {
878
+ userInfo: {
879
+ name: {
880
+ transformers: [
881
+ {
882
+ "fields": [
883
+ "drivers"
884
+ ],
885
+ "transformer": "addAdditionalDriver"
886
+ },
887
+ arraySource: 'drivers',
888
+ {
889
+ arrayTemplate: {
890
+ contactType: 'type',
891
+ contactValue: {
892
+ fields: ['value'],
893
+ transformer: 'upperCase',
894
+ allowNull: false
895
+ }
896
+ }
897
+ }
898
+ ]
899
+ },
900
+ }
901
+ };
902
+
903
+ const templateModule = new TemplateModule();
904
+ templateModule.setTemplate(template);
905
+ templateModule.setTransformers(baseTransformers);
906
+ templateModule.setContext(data);
907
+
908
+ const result = templateModule.transformPayload(data);
909
+ console.log(JSON.stringify(result, null, 2));
910
+
911
+ /*
912
+ Expected output:
913
+ {
914
+ "userInfo": {
915
+ "name": [
916
+ {
917
+ "contactType": "ID",
918
+ "contactValue": "JOHN.DOE@EXAMPLE.COM"
919
+ },
920
+ {
921
+ "contactType": "ND",
922
+ "contactValue": "JOHN.DOE@EXAMPLE.COM"
923
+ },
924
+ {
925
+ "contactType": "ND",
926
+ "contactValue": "1234567890"
927
+ },
928
+ {
929
+ "contactType": "ND",
930
+ "contactValue": "123 MAIN ST, CITY, COUNTRY"
931
+ }
932
+ ]
933
+ }
934
+ }
935
+ */
936
+ ```
937
+
938
+ In this example:
939
+
940
+ 1. We have a regular transformer that capitalizes the user's name
941
+ 2. The second transformer in the sequence is a DynamicArrayMapper that processes the contacts array
942
+ 3. The result is a transformed array of contact information
943
+
944
+ You can also combine DynamicArrayMapper with subsequent transformers:
945
+
946
+ ```javascript
947
+ const templateWithMultipleTransformers = {
948
+ contactInfo: {
949
+ transformers: [
950
+ // DynamicArrayMapper to process contacts
951
+ {
952
+ arraySource: 'contacts',
953
+ arrayTemplate: {
954
+ type: 'type',
955
+ value: 'value',
956
+ },
957
+ },
958
+ // Format phone numbers in the array
959
+ {
960
+ fields: ['1.value'], // Access the phone number (index 1 in the array)
961
+ transformer: 'formatPhone',
962
+ allowNull: false,
963
+ },
964
+ ],
965
+ },
966
+ };
967
+ ```
968
+
969
+ This combination allows for powerful and flexible data transformations.
970
+
971
+ ### Example inferring types to transformPayload
972
+
973
+ ```typescript
974
+ import { TemplateModule } from '@edirect/template';
975
+
976
+ interface DataSource {
977
+ subscriber: {
978
+ firstName: string;
979
+ lastName: string;
980
+ };
981
+ }
982
+
983
+ interface TransformedData {
984
+ edirect_firstname: string;
985
+ edirect_lastname: string;
986
+ }
987
+
988
+ function transformData(dataSource: DataSource): TransformedData {
989
+ const template = {
990
+ edirect_firstname: 'subscriber.firstName',
991
+ edirect_lastname: 'subscriber.lastName',
992
+ };
993
+
994
+ const templateModule = new TemplateModule();
995
+ templateModule.setTemplate(template);
996
+
997
+ return templateModule.transformPayload<TransformedData>(dataSource);
998
+ }
999
+
1000
+ const dataSource = {
1001
+ subscriber: {
1002
+ firstName: 'template',
1003
+ lastName: 'service',
1004
+ },
1005
+ };
1006
+
1007
+ console.log(transformData(dataSource));
1008
+
1009
+ // {
1010
+ // edirect_firstname: "template",
1011
+ // edirect_lastname: "service",
1012
+ // }
1013
+ ```
1014
+
1015
+ ### Example with Options
1016
+
1017
+ Options:
1018
+
1019
+ - omitEmptyFields?: boolean;
1020
+
1021
+ ```js
1022
+ import { TemplateModule } from '@edirect/template';
1023
+
1024
+ const template = {
1025
+ edirect_firstname: 'subscriber.firstName',
1026
+ edirect_lastname: 'subscriber.lastName',
1027
+ edirect_age: 'subscriber.age',
1028
+ };
1029
+
1030
+ const dataSource = {
1031
+ subscriber: {
1032
+ firstName: 'template',
1033
+ lastName: 'service',
1034
+ age: '',
1035
+ },
1036
+ };
1037
+
1038
+ const options = { omitEmptyFields: true };
1039
+
1040
+ const templateModule = new TemplateModule();
1041
+ templateModule.setTemplate(template);
1042
+ templateModule.setOptions(options);
1043
+
1044
+ const result = templateModule.transformPayload(dataSource);
1045
+
1046
+ console.log(result);
1047
+
1048
+ // {
1049
+ // edirect_firstname: "template",
1050
+ // edirect_lastname: "service",
1051
+ // }
1052
+ ```
1053
+
1054
+ ## Example: Simple Arrays
1055
+
1056
+ ## Configuration & Environment Variables
1057
+
1058
+ `@edirect/template` is a pure JavaScript/TypeScript library and does not require any environment variables by default. However, if your custom transformers or templates depend on environment-specific values, you can inject them via your application context or configuration system.
1059
+
1060
+ For example, you can pass environment variables into the context:
1061
+
1062
+ ```js
1063
+ const context = {
1064
+ ...process.env,
1065
+ // other context values
1066
+ };
1067
+ templateModule.setContext(context);
1068
+ ```
1069
+
1070
+ **Note:** Never commit sensitive credentials to version control. Use environment variables or secure secrets management as appropriate for your application.
1071
+
1072
+ ```js
1073
+ import { TemplateModule } from '@edirect/template';
1074
+
1075
+ const template = {
1076
+ emails: {
1077
+ arraySource: 'subscriber.emails',
1078
+ simpleArray: true,
1079
+ arrayTemplate: {
1080
+ type: {
1081
+ defaultValue: 'personal',
1082
+ },
1083
+ value: 'value',
1084
+ },
1085
+ },
1086
+ };
1087
+
1088
+ const dataSource = {
1089
+ subscriber: {
1090
+ emails: ['johndoe@example.com', 'janedoe@example.com'],
1091
+ },
1092
+ };
1093
+
1094
+ const templateModule = new TemplateModule();
1095
+ templateModule.setTemplate(template);
1096
+
1097
+ const result = templateModule.transformPayload(dataSource);
1098
+
1099
+ console.log(result);
1100
+
1101
+ /*
1102
+ {
1103
+ "emails": [
1104
+ {
1105
+ "type": "personal",
1106
+ "value": "johndoe@example.com"
1107
+ },
1108
+ {
1109
+ "type": "personal",
1110
+ "value": "janedoe@example.com"
1111
+ }
1112
+ ]
1113
+ }
1114
+ */
1115
+ ```