Package Exports
- morphmorph
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (morphmorph) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Morph Morph
Isomorphic transformations. Map, transform, filter, reduce, and morph your objects
Getting Started
$ npm i --save morphmorph
and then
const Mapper = require('morphmorph')
const mapper = new Mapper(/* [config] */)
const old = {
here: {
there: {
anywhere: 'Earth'
}
}
}
const mappings = [ 'here.there.anywhere:location' ]
const transformation = mapper.map(mappings, old)
// -> { location: 'Earth' }
Creating Transformations
Every transformation can be represented by a mapping passed in as the first parameter
to mapper.map()
. Mappings can either be of type String
or Object
. A mapping such as 'before:after'
is equivalent to: { field: 'before:after' }
Basic
const mappings = [
'before:after',
'egg:they.can.be.deeply.nested', // deeply nested target
'data.user.updated:updated' // deeply nested source
]
return mapper.map(mappings, obj)
Functions
When creating a mapping, if you pass a function as the type
parameter,
the function you passed will be called with the following properties to produce
the result:
const mapping = {
field: 'name',
type: function (value, mapping, options, sourceObj, targetObj) {
// value: the value grabbed from the source object
// mapping: this specific mapping
// options: config you specified by `new Mapper(options)`
// sourceObj: object you passed as mapper.map(mapping, sourceObj)
// targetObj: object you passed as mapper.map(m, sourceObj, targetObj). Default to `{}`
}
}
Arrays
You can also pass an Array of functions and MapLib
will perform a right-to-left
function composition:
const mapping = {
field: 'id:pin',
type: [
Number, // called last
v => v.substr(0, 4)
v => v.replace(/\D/g, '') // called first
]
}
mapper.map([mapping], { id: 'U1234342'}) // -> 1234
Function Compositions
If you want to do function compositions the traditional way, you can use Mapper.compose(...myFilterFunctions)
. Again it will be a right-to-left composition.
Reductions
By specifying your field
property as an array, you can reduce multiple values into a single one. The values will be included as the first parameter of your type
function. The target field is specified by the last mapping in your array
Example
const response = {
user: {
firstName: 'Mike',
lastName: 'Fix',
professionInfo: {
title: 'Mr',
occupation: 'Software Engineer'
}
}
}
const mapping = {
field: [
'user.firstName',
'user.lastName',
'user.professionInfo.title',
'user.professionInfo.occupation',
'description'
],
type: ([name1, name2, title, occ]) =>
`${title}. ${name1} ${name2} is a ${occ}`
}
mapper.map([mapping], response).description // -> 'Mr. Mike Fix is a Software Engineer'
Types
You can specify a type system by passing in the types
option:
const types = {
number: Number,
notNullString: v => (v || '')
}
const mapper = new Mapper({ types })
and then specify which type to use as a string for each mapping:
const mappings = [
{ field: 'haircolor', type: 'notNullString' },
{ field: 'daysRemaining': type: 'number' }
]
return mapper.map(mappings, hairSubscriptionResponse)
Note: each function in the type specification is passed the same parameters as the normal type functions
Config
You can pass in a config object to Mapper
to create your own mapping system:
Options
Field | Type | Default |
---|---|---|
types |
Object |
{} |
objDelimiter |
String |
"." |
mapDelimiter |
String |
":" |
preFilters |
Array |
[] |
postFilters |
Array |
[] |
Example
const mapper = new Mapper({
objDelimiter: '|',
mapDelimiter: '->',
types: { bool: Boolean },
preFilters: [ FILTER_NULL ],
postFilters: [ REMOVE_PASSWORD ]
// add other fields to your config here
})
Static methods
Mapper.get
Method used to grab a deeply nested field from an object.
const get = Mapper.get('key'/*, delimiter */)
const field = get({ key: true })
// -> true
Mapper.assign
Method used to apply a deeply nested field to an object.
const set = Mapper.assign('user.id'/*, delimiter */)
const targetObject = set({}, 1)
// -> { user: { id: 1 } }
Mapper.compose
Method used to apply function compositions
const fun1 = v => `${v}!`
const fun2 = v => v.toUpperCase()
const fun3 = String
const exclaim = Mapper.compose(fun1, fun2, fun3)
exclaim('hey') // -> HEY!
Bonus
Dependencies: None!
Size: <2KB gzipped
Examples
See /examples or test/index.spec.js
for many examples of how to use MorphMorph
.
Thanks
- Mostly Adequate Guide to Functional Programming for examples and reference implementations