Skip to content

nikostoulas/metamorphosi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

metamorphosi

Node.js module that is used to transform input - $ or $1 - jsons based on templates

Syntax

Builder

const { getTransform } = require('metamorphosi');
const transform = getTransform(template, options);
transform($, $1);

Parameters

template a template is given as parameter. The possible values are described bellow in Template possible values

options? an object containing

  • dropValues? (default: [null, undefined, '']), Values that will be dropped from output
  • cb? (default x => x) a tranformating function that will be used in all output values.

Return

a function that when given two inputs will tranform them and produced 1 output based on the template

Transform with all options

const {transform} = require('metamorphosi');
const transform(template, options)

The builder given is a convenient wrapper of the above method to easily reuse it with the same template and options.

Parameters

template a template is given as parameter. The possible values are described bellow in Template possible values

options an object containing

  • dropValues? (default: [null, undefined, '']), Values that will be dropped from output
  • cb? (default x => x) a tranformating function that will be used in all output values.
  • $ the input to be tranformed
  • $1 a second input to be transformed

Return

tranformed inputs based on the template and $, $1. The output type is very similar to the template given

Usage

const {getTransform} = require('metamorphosi');

/** A template example */
const template = {
  simpleString:'string ',
  simpleNumber: 100,
  simpleBoolean: true,
  simpleArray: [1,2,3],
  path: '$.a.b.c',
  'arrayTransformed[$.array]': { a: '$.b', index: '$.$index', parentValue: '$..a.b.c', array: '$.$array'},
  simpleObject: {
    pathFromAlternativeInput: '$1.a.b'
  }
}

/** a cb example */
function cb(input){
  if(typeof input ==='string') return input.trim();
  return input;
}

/**
* The default dropValues used if not overwritten.
* - Any value in this array will be removed.
* - Empty arrays will be removed
* - Empty objects will also be removed
*/
const dropValues = [null, undefined, ''];
const transform = getTransform(template, {dropValues, cb})

> transform({a:{b:{c:' a value '}}, array: [{b: ' test '}, {b: 'another test'}]}, {a:{b:'alternative value '}})
/* {
  "simpleString": "string",
  "simpleNumber": 100,
  "simpleBoolean": true,
  "simpleArray": [1, 2, 3],
  "path": "a value",
  "arrayTransformed": [
    {
      "a": "test",
      "index": 0,
      "parentValue": "a value",
      "array": [{"b": " test "}, {"b": "another test"}]
    },
    {
      "a": "another test",
      "index": 1,
      "parentValue": "a value",
       "array": [{"b": " test "}, {"b": "another test"}]
    }
  ],
  "simpleObject": {
    "pathFromAlternativeInput": "alternative value"
  }
}
*/

// This is the same as
const {transform} = require('template-transformer');

transform(template, {
  dropValues,
  cb,
  $:{a:{b:{c:' a value '}}, array: [{b: ' test '},
  $1:{b: 'another test'}
});

// getTrasform is usefull if you need to use trasform many times as it reuses
// the same template, options

Template possible values

As seen in the respective types the template can have 7 different type of values:

LITERAL_NUMBER

A literal number in the template will always be preserved in the resulting output

eg:

transform(1, {}); //1

unless it exists in dropValues

eg:

transform(0, { dropValues: [0] }); // undefined

LITERAL_STRING

Similarly a literal string will be always preserved. By default empty string are always dropped:

eg:

transform('foo', {}); // 'foo'
transform('', {}); // undefined
transform('', { dropValues: [] }); // ''

LITERAL_BOOLEAN

Similarly the use of boolean values are preserved no matter the input

eg:

transform(true, {}); // true
transform(false, {}); // false

JSON_PATH

With the use of $ or $1 you can access any value from the given json

eg:

transform('$.foo.bar', { $: { foo: { bar: 'value' } } }); // 'value'

// accessing arrays:
transform('$.foo.0.bar', { $: { foo: [{ bar: 'value' }] } }); // 'value'

OBJECT

All the above examples are pretty simple. Getting a literal value or a single value by accessing an input would be pretty simple without a module. The power of this module is with tranforming to objects. The values of a key can be any of the values of a template including another object. There are 5 differnt types of keys that can exist in an object template:

SIMPLE

A simple string key

eg:

transform({ value: '$.foo' }, { $: { foo: 'bar' } }); // { value: 'bar' }

TYPE_ARRAY

One common need is to iterate an inputs array and create a different array in the output.

eg:

transform({ 'value[$.foo]': '$.0' }, { $: { foo: ['bar', 'foo'] } }); // { value: [ 'b', 'f' ] }

DUPLICATE

There is a common need to create an array from 2 or more sources from the input json. To address this need you can use keys suffixed with .$1-9

eg:

transform(
  { 'value.$1': ['a', 'b'], 'value[$.foo].$2': '$.0', 'value.$3': '$.array' },
  { $: { foo: ['bar', 'foo'], array: ['c', 'd'] } }
); // { value: [ 'a', 'b', 'b', 'f', 'c', 'd' ] }

Note however that if a duplicate key value is not an array, this will overwrite the previous array with a non array

TEMPLATE

You can use a key value from the input

eg:

transform({ ['$.foo']: 'foo' }, { $: { foo: 'bar' } }); // { bar: 'foo' }

IF

Sometimes you don't want an object to be included if some keys are missing. This is easily accomplished using the $if key

eg:

transform({ ['$.foo']: 'foo', a: '$.bar', $if: ['a'] }, { $: { foo: 'bar' } }); // undefined
transform({ ['$.foo']: 'foo', a: '$.bar', $if: ['a'] }, { $: { foo: 'bar', bar: 'bar' } }); // { bar: 'foo', a: 'bar' }

In addition to keys, the $\if array can contain functions. If at least one function returns false, the object won't be included in the final result.

eg:

transform({ ['$.foo']: 'foo', a: '$.bar', $if: [$ => false] }, { $: { foo: 'bar' } }); // undefined
transform({ ['$.foo']: 'foo', a: '$.bar', $if: [$ => $.bar.length > 0] }, { $: { foo: 'bar', bar: 'bar' } }); // { bar: 'foo', a: 'bar' }
transform({ ['$.foo']: 'foo', a: '$.bar', $if: [(_, $1) => !$1.erase] }, { $: { foo: 'bar', bar: 'bar' }, $1: { erase: true } }); // undefined

KEEP

Sometimes you want an object to be included even if it is empty. By default metamorphosi will drop empty objects. If you want to keep empty objects you can use the $keep:true special key.

eg:

transform({ $keep:true }, { }); // {}

Keep can also be used inside arrays to ensure that if the array is empty after the transformation, it is not removed from the end result

eg:

transform({ a: ['$keep', undefined, null] }, { }); // {a: []} 

ARRAY

As seen in some examples of object you can directly use arrays as deplates. The values of the array can be a valid template value

eg:

transform([1, '1', true, () => 'function', '$.foo', { foo: '$.foo' }, ['array']], { $: { foo: 'bar' } }); // [ 1, '1', true, 'function', 'bar', { foo: 'bar' } ]

FUNCTION

You can also use callbacks that take as an input ($,$1)

eg:

transform($ => $.foo, { $: { foo: 'bar' } }); // 'bar'

Error Handling

All errors are cought by the library. Even in JSON paths (eg null pointer exceptions) or errors in Function callbacks. In cases an error occurs the template will resolve into an undefined value that will be removed (Unless dropValues is overwritten).

$1

Sometimes it is useful to have a second maybe configuration object that can impact the output. An example can be when transforming an api response eg. $ and want to use some configuration eg. $1 to differentiate the output.

About

This work was inspired by jsonpath-object-transform and my work @Workable. More than 6 years of experience transforming jsons using templates and code resulted in this module. It tries to solve most common issues and difficulties people have when working with templates. This module concept was initially developed during my flight to Brussels from Athens and back.


About

Node.js module that is used to transform jsons based on templates

Resources

Stars

Watchers

Forks

Packages

No packages published