@edirect/template
v11.0.35
Published
TemplateModule is a library that provides methods to transform a payload based on a given template. The transformation includes mapping fields, applying transformers, setting default values and so on.
Downloads
539
Maintainers
Keywords
Readme
@edirect/template
TemplateModule is a library that provides methods to transform a payload based on a given template. The transformation includes mapping fields, applying transformers, setting default values and so on.
Installation
$ npm i --save @edirect/templateImport
import { TemplateModule } from './TemplateModule';Methods
Constructor
The TemplateModule class does not have a constructor.
setContext(context): void
Sets the context object to be used during the transformation.
setTemplate(template): void
Sets the template object that describes the transformation to be performed.
setTransformers(transformers: ITransformer): void
Sets the transformers to be used during the transformation.
setOptions(transformers: ITemplateOptions): void
Sets the options to be used during and after the transformation.
verifyTransformer(transformer: ITransformer, methodName: string): boolean
Verifies if a given transformer method exists.
runTransformer(transformer: string, value?: unknown): unknown | null
Runs a transformer on a given value.
- transformer - The name of the transformer to be used.
- value - The value to be transformed.
checkValue(value: any): boolean
Checks if a given value is not null, undefined, or an empty string.
setValueByCondition(object, key: string, value: unknown)
Sets a value in an object after verify using the checkValue() method.
- object - The object to be modified.
- key - The key of the value to be set.
- value - The value to be set.
transformPayload<T, U>(obj: T, template = this.template): U
Transforms a payload object on a given template.
Simple example
import { TemplateModule } from '@edirect/template';
const template = {
edirect_firstname: 'subscriber.firstName',
edirect_lastname: 'subscriber.lastName',
};
const dataSource = {
subscriber: {
firstName: 'template',
lastName: 'service',
},
};
const templateModule = new TemplateModule();
templateModule.setTemplate(template);
const result = templateModule.transformPayload(dataSource);
console.log(result);
// {
// edirect_firstname: "template",
// edirect_lastname: "service",
// }Example with transformers
First of all, what's a transformer?
A transformer is a way to handle values with more detail and freedom.
For example:
- Mapping
- Validation
- Formatting
- Business rules
- and so on ...
Each transformer receives two parameters:
value: specific value that you want to handlecontext: all context (payload) that you can use to build any logical
To map a value that you'd like to use some transformer feature, you can use these options:
fields: it's an array with a data source path, and the first value that is found will be used.transformer: it's a JS function, where you receive value and context as parameters and have all freedom to handle and return a valuedefaultValueit'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.
File name: baseTransformers.ts
import { ITransformer, ITransformerParams } from "@edirect/template";
const upperCase = ({ value }: ITransformerParams): string | null => {
return value ? String(value).toUpperCase() : null;
};
const fullName = ({ context }: ITransformerParams): string | null => {
try {
const { firstName, lastName } = context.subscriber;
return `${firstName} ${lastName}`;
} catch (error) {
return null;
}
};
const transformers: ITransformer = {
upperCase,
fullName,
};
export default transformers;File name: index.ts
import { TemplateModule } from '@edirect/template';
import baseTransformers from './baseTransformers';
const template = {
edirect_firstname: {
fields: ['firstName', 'subscriber.firstName'],
transformer: 'upperCase',
defaultValue: 'First Name - Default',
},
edirect_lastname: {
fields: ['lastName', 'subscriber.lastName'],
},
edirect_fullname: {
transformer: 'fullName',
},
edirect_phone: {
fields: ['phoneNumber', 'subscriber.phoneNumber'],
defaultValue: '999999999',
},
timeZone: {
defaultValue: 'Time zone in Porto (GMT+1)',
},
};
const dataSource = {
subscriber: {
firstName: 'template',
lastName: 'service',
},
};
const templateModule = new TemplateModule();
templateModule.setTemplate(template);
templateModule.setContext(dataSource);
templateModule.setTransformers(baseTransformers);
const result = templateModule.transformPayload(dataSource);
console.log(result);
// {
// edirect_firstname: "TEMPLATE",
// edirect_lastname: "service",
// edirect_fullname: "template service",
// edirect_phone: "999999999",
// timeZone: "Time zone in Porto (GMT+1)",
// }Example with nested object + transformers
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.
File name: baseTransformers.ts
import { ITransformer, ITransformerParams } from "@edirect/template";
const upperCase = ({ value }: ITransformerParams): string | null => {
return value ? String(value).toUpperCase() : null;
};
const transformers: ITransformer = {
upperCase,
};
export default transformers;File name: index.ts
import { TemplateModule } from '@edirect/template';
import baseTransformers from './baseTransformers';
const template = {
order: {
date: 'order.date',
value: 'order.value',
subscriber: {
name: 'sub.name',
phone: 'sub.phone',
email: {
fields: ['email', 'sub.email'],
},
address: {
street: 'sub.add.stt',
number: 'sub.add.num',
city: {
fields: ['sub.add.city'],
transformer: 'upperCase',
},
state: {
fields: ['sub.add.stt'],
transformer: 'upperCase',
},
zip: {
fields: ['sub.add.zip'],
defaultValue: '0000-000',
},
},
},
},
};
const dataSource = {
order: {
value: 1000.0,
date: '2000-01-01',
},
sub: {
name: 'name-test',
phone: '999999999',
email: '[email protected]',
add: {
st: 'st-test',
num: 100,
city: 'city-test',
stt: 'state-test',
zip: 'zip-test',
},
},
};
const templateModule = new TemplateModule();
templateModule.setTemplate(template);
templateModule.setContext(dataSource);
templateModule.setTransformers(baseTransformers);
const result = templateModule.transformPayload(dataSource);
console.log(result);
// {
// order: {
// date: "2000-01-01",
// value: 1000,
// subscriber: {
// name: "name-test",
// phone: "999999999",
// email: "[email protected]",
// address: {
// street: "state-test",
// number: 100,
// city: "CITY-TEST",
// state: "STATE-TEST",
// zip: "zip-test",
// },
// },
// },
// }Example with arrays + transformers
Note: When it comes to arrays mapper, we need to have in mind that is required use this two keys: arraySource and arrayTemplate.
arraySource: source path where the engine will seek the information to mapperarrayTemplate: template that will be used for each object within the array
File name: baseTransformers.ts
import { ITransformer, ITransformerParams } from "@edirect/template";
const upperCase = ({ value }: ITransformerParams): string | null => {
return value ? String(value).toUpperCase() : null;
};
const transformers: ITransformer = {
upperCase,
};
export default transformers;File name: index.ts
import { TemplateModule } from '@edirect/template';
import baseTransformers from './baseTransformers';
const template = {
quote: {
orders: {
arraySource: 'order',
arrayTemplate: {
value: 'value',
date: 'date',
products: {
arraySource: 'products',
arrayTemplate: {
id: 'id',
value: 'value',
description: {
fields: ['description'],
transformer: 'upperCase',
defaultValue: 'Default description',
},
categories: 'categories',
},
},
},
},
},
};
const dataSource = {
order: [
{
value: 1000.0,
date: '2000-01-01',
products: [
{
id: 'id-test-1',
value: 1000,
description: 'description-test 1',
categories: ['category-1'],
},
{
id: 'id-test-2',
value: 2000,
description: 'description-test 2',
categories: ['category-1', 'category-2'],
},
{
id: 'id-test-3',
value: 3000,
categories: ['category-1', 'category-2', 'category-3'],
},
],
},
],
};
const templateModule = new TemplateModule();
templateModule.setTemplate(template);
templateModule.setContext(dataSource);
templateModule.setTransformers(baseTransformers);
const result = templateModule.transformPayload(dataSource);
console.log(result);
//{
// quote: {
// orders: [
// {
// value: 1000,
// date: "2000-01-01",
// products: [
// {
// id: "id-test-1",
// value: 1000,
// description: "DESCRIPTION-TEST 1",
// categories: ["category-1"],
// },
// {
// id: "id-test-2",
// value: 2000,
// description: "DESCRIPTION-TEST 2",
// categories: ["category-1", "category-2"],
// },
// {
// id: "id-test-3",
// value: 3000,
// description: "Default description",
// categories: ["category-1", "category-2", "category-3"],
// },
// ],
// },
// ],
// },
// }Example with arrays + ignoreIndexs
Note: When it comes to arrays mapper, we need to have in mind that is required use this two keys: arraySource and arrayTemplate.
arraySource: source path where the engine will seek the information to mapperarrayTemplate: template that will be used for each object within the arrayignoreIndexs: array with the index position that must be ignore
File name: baseTransformers.ts
import { ITransformer, ITransformerParams } from "@edirect/template";
const upperCase = ({ value }: ITransformerParams): string | null => {
return value ? String(value).toUpperCase() : null;
};
const transformers: ITransformer = {
upperCase,
};
export default transformers;File name: index.ts
import { TemplateModule } from '@edirect/template';
import baseTransformers from './baseTransformers';
const template = {
quote: {
orders: {
arraySource: 'order',
arrayTemplate: {
value: 'value',
date: 'date',
products: {
arraySource: 'products',
arrayTemplate: {
id: 'id',
value: 'value',
description: {
fields: ['description'],
transformer: 'upperCase',
defaultValue: 'Default description',
},
categories: 'categories',
},
ignoreIndexs: [0],
},
},
},
},
};
const dataSource = {
order: [
{
value: 1000.0,
date: '2000-01-01',
products: [
{
id: 'id-test-1',
value: 1000,
description: 'description-test 1',
categories: ['category-1'],
},
{
id: 'id-test-2',
value: 2000,
description: 'description-test 2',
categories: ['category-1', 'category-2'],
},
{
id: 'id-test-3',
value: 3000,
categories: ['category-1', 'category-2', 'category-3'],
},
],
},
],
};
const templateModule = new TemplateModule();
templateModule.setTemplate(template);
templateModule.setContext(dataSource);
templateModule.setTransformers(baseTransformers);
const result = templateModule.transformPayload(dataSource);
console.log(result);
//{
// quote: {
// orders: [
// {
// value: 1000,
// date: "2000-01-01",
// products: [
// {
// id: "id-test-2",
// value: 2000,
// description: "DESCRIPTION-TEST 2",
// categories: ["category-1", "category-2"],
// },
// {
// id: "id-test-3",
// value: 3000,
// description: "Default description",
// categories: ["category-1", "category-2", "category-3"],
// },
// ],
// },
// ],
// },
// }Template example with transformer + transformerParams
File name: baseTransformers.ts
import { ITransformer, ITransformerParams } from "@edirect/template";
const concat = (
{ value }: ITransformerParams,
...itensToConcat: string[]
): string => {
const arrayToConcat = [value, ...itensToConcat];
return arrayToConcat.join("");
};
const concatWithSeparator = (
{ value }: ITransformerParams,
separator: string,
...itensToConcat: string[]
): string => {
const arrayToConcat = [value, ...itensToConcat];
return arrayToConcat.join(separator);
};
const transformers: ITransformer = {
concat,
concatWithSeparator,
};
export default transformers;File name: index.ts
import { TemplateModule } from '@edirect/template';
import baseTransformers from './baseTransformers';
const template = {
status: 'status',
concatenated_result: {
fields: ['lead_id'],
transformer: 'concat',
transformerParams: [
'-',
'${person_number}',
'/',
'${person_number2}',
'_',
'${person_number3}',
],
},
concatenated_result2: {
fields: ['lead_id'],
transformer: 'concatWithSeparator',
transformerParams: [
'-',
'${person_number}',
'${person_number2}',
'${person_number3}',
],
},
};
const dataSource = {
status: true,
lead_id: 'FR-14af3f',
person_number: 123,
person_number2: 456,
person_number3: 789,
};
const templateModule = new TemplateModule();
templateModule.setTemplate(template);
templateModule.setContext(dataSource);
templateModule.setTransformers(baseTransformers);
const result = templateModule.transformPayload(dataSource);
console.log(result);
// {
// status: true,
// concatenated_result: "FR-14af3f-123/456_789",
// concatenated_result2: "FR-14af3f-123-456-789"
// }Template example with transformer + transformerParams + complexParams
File name: baseTransformers.ts
import { ITransformer, ITransformerParams } from "@edirect/template";
const translator = ({ value }: ITransformerParams, translateDict: Record<string, string>): string => {
const translated = translateDict.?[value];
if (!translated) return null;
return translated;
};
const transformers: ITransformer = {
translator,
};
export default transformers;File name: index.ts
import { TemplateModule } from '@edirect/template';
import baseTransformers from './baseTransformers';
const template = {
status: {
fields: ['status'],
transformer: 'translator',
transformerParams: [
{
ERROR: 'ERROR',
RECHAZADA: 'REJECTED',
},
],
},
};
const dataSource = {
status: 'RECHAZADA',
};
const templateModule = new TemplateModule();
templateModule.setTemplate(template);
templateModule.setContext(dataSource);
templateModule.setTransformers(baseTransformers);
const result = templateModule.transformPayload(dataSource);
console.log(result);
// {
// status: "REJECTED",
// }Example with Sequential Transformers
The library now supports applying multiple transformers sequentially to a single field. This is particularly useful for more complex transformations that require multiple steps.
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.
File name: baseTransformers.ts
import { ITransformer, ITransformerParams } from "@edirect/template";
const findKeyInArrayGetField = (
{ value, context }: ITransformerParams,
key: string,
valueToFind: string,
field: string,
transformer: any,
...params: any
): any | null => {
const listToFind = findKeyInArray({ value }, key, valueToFind);
if (typeof transformer !== "undefined") {
value = _.get(listToFind, field, null);
let transformerParams = params;
if (field === "#") {
transformerParams = [];
for (const fieldItem of params) {
let item = fieldItem;
if (fieldItem.includes("#")) {
item = _.get(listToFind, fieldItem.replace(/\#\{(.*)\}/, "$1"), null);
}
transformerParams.push(item);
}
}
if (typeof baseTransformers[transformer] !== "undefined") {
return baseTransformers[transformer]({ value, context }, ...transformerParams);
}
}
return _.get(listToFind, field, null);
};
const calculateAgeByBirthdate = ({ value }: ITransformerParams, ...formatDate: string[]): string | null => {
if (!value) return null;
if (!formatDate.length) formatDate.push("dd/MM/yyyy");
for (const format of formatDate) {
const date = parse(value, format, new Date());
if (isValid(date)) {
return differenceInYears(new Date(), date).toString();
}
}
return null;
};
const transformers: ITransformer = {
findKeyInArrayGetField,
calculateAgeByBirthdate
};
export default transformers;File name: index.ts
import { TemplateModule } from '@edirect/template';
import baseTransformers from './baseTransformers';
const template = {
age: {
transformers: [
{
fields: ['data.externalReferences'],
transformer: 'findKeyInArrayGetField',
transformerParams: ['type', 'birthDate', 'value'],
},
{
transformer: 'calculateAgeByBirthdate',
transformerParams: ["yyyy-MM-dd'T'HH:mm:ss.SSSXXX"],
},
],
},
};
const dataSource = {
data: {
externalReferences: [
{
type: 'randomKey',
value: 'randomValue',
},
{
type: 'birthDate',
value: '1995-12-27T15:22:32.511+00:00',
},
],
},
};
const templateModule = new TemplateModule();
templateModule.setTemplate(template);
templateModule.setContext(dataSource);
templateModule.setTransformers(baseTransformers);
const result = templateModule.transformPayload(dataSource);
console.log(result);
// {
// age: "29"
// }In this example:
- The first transformer (
findKeyInArrayGetField) extracts the birthdate value from the array of external references - The second transformer (
calculateAgeByBirthdate) calculates the age from the birthdate
The transformers are applied sequentially, with each one receiving the result of the previous transformation as its input value.
Example with DynamicArrayMapper in transformers array
The library now supports using DynamicArrayMapper as an element in the transformers array. This allows you to dynamically process arrays within a transformation sequence.
File name: baseTransformers.ts
import { ITransformer, ITransformerParams } from "@edirect/template";
const addAdditionalDriver = ({ context, value }: ITransformerParams): any => {
if (!value || (value as any[]).length === 0) {
return;
}
const drivers: any[] = value;
const result = drivers.reduce((acc, driver) => {
acc.push(driver);
const type = driver.type;
if (type === "ID") {
const newDriver = cloneDeep(driver);
newDriver.type = "ND";
acc.push(newDriver);
}
return acc;
}, []);
return result;
};
const transformers: ITransformer = {
addAdditionalDriver,
};
export default transformers;File name: index.ts
import { TemplateModule } from "@edirect/template";
import baseTransformers from "./baseTransformers";
const data = {
drivers: [
{value: '[email protected]', type:"ID" },
{value: '1234567890', type:"ND" },
{value: '123 Main St, City, Country', type:"ND" }
]
};
const template = {
userInfo: {
name: {
transformers: [
{
"fields": [
"drivers"
],
"transformer": "addAdditionalDriver"
},
arraySource: 'drivers',
{
arrayTemplate: {
contactType: 'type',
contactValue: {
fields: ['value'],
transformer: 'upperCase',
allowNull: false
}
}
}
]
},
}
};
const templateModule = new TemplateModule();
templateModule.setTemplate(template);
templateModule.setTransformers(baseTransformers);
templateModule.setContext(data);
const result = templateModule.transformPayload(data);
console.log(JSON.stringify(result, null, 2));
/*
Expected output:
{
"userInfo": {
"name": [
{
"contactType": "ID",
"contactValue": "[email protected]"
},
{
"contactType": "ND",
"contactValue": "[email protected]"
},
{
"contactType": "ND",
"contactValue": "1234567890"
},
{
"contactType": "ND",
"contactValue": "123 MAIN ST, CITY, COUNTRY"
}
]
}
}
*/In this example:
- We have a regular transformer that capitalizes the user's name
- The second transformer in the sequence is a DynamicArrayMapper that processes the contacts array
- The result is a transformed array of contact information
You can also combine DynamicArrayMapper with subsequent transformers:
const templateWithMultipleTransformers = {
contactInfo: {
transformers: [
// DynamicArrayMapper to process contacts
{
arraySource: 'contacts',
arrayTemplate: {
type: 'type',
value: 'value',
},
},
// Format phone numbers in the array
{
fields: ['1.value'], // Access the phone number (index 1 in the array)
transformer: 'formatPhone',
allowNull: false,
},
],
},
};This combination allows for powerful and flexible data transformations.
Example inferring types to transformPayload
import { TemplateModule } from '@edirect/template';
interface DataSource {
subscriber: {
firstName: string;
lastName: string;
};
}
interface TransformedData {
edirect_firstname: string;
edirect_lastname: string;
}
function transformData(dataSource: DataSource): TransformedData {
const template = {
edirect_firstname: 'subscriber.firstName',
edirect_lastname: 'subscriber.lastName',
};
const templateModule = new TemplateModule();
templateModule.setTemplate(template);
return templateModule.transformPayload<TransformedData>(dataSource);
}
const dataSource = {
subscriber: {
firstName: 'template',
lastName: 'service',
},
};
console.log(transformData(dataSource));
// {
// edirect_firstname: "template",
// edirect_lastname: "service",
// }Example with Options
Options:
- omitEmptyFields?: boolean;
import { TemplateModule } from '@edirect/template';
const template = {
edirect_firstname: 'subscriber.firstName',
edirect_lastname: 'subscriber.lastName',
edirect_age: 'subscriber.age',
};
const dataSource = {
subscriber: {
firstName: 'template',
lastName: 'service',
age: '',
},
};
const options = { omitEmptyFields: true };
const templateModule = new TemplateModule();
templateModule.setTemplate(template);
templateModule.setOptions(options);
const result = templateModule.transformPayload(dataSource);
console.log(result);
// {
// edirect_firstname: "template",
// edirect_lastname: "service",
// }Example using simple arrays
import { TemplateModule } from '@edirect/template';
const template = {
emails: {
arraySource: 'subscriber.emails',
simpleArray: true,
arrayTemplate: {
type: {
defaultValue: 'personal',
},
value: 'value',
},
},
};
const dataSource = {
subscriber: {
emails: ['[email protected]', '[email protected]'],
},
};
const templateModule = new TemplateModule();
templateModule.setTemplate(template);
const result = templateModule.transformPayload(dataSource);
console.log(result);
/*
{
"emails": [
{
"type": "personal",
"value": "[email protected]"
},
{
"type": "personal",
"value": "[email protected]"
}
]
}
*/