Security News
Fluent Assertions Faces Backlash After Abandoning Open Source Licensing
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Library to transform any Object / JSON to JavaScript Object Literals, and ES6 Class Objects. Help you scale your data processing
In many fields of mathematics, morphism refers to a structure-preserving map from one mathematical structure to another. A morphism f with source X and target Y is written f : X → Y. Thus a morphism is represented by an arrow from its source to its target.
https://en.wikipedia.org/wiki/Morphism
npm install --save morphism
import { morphism } from 'morphism';
// Source data coming from an API.
const source = {
foo: 'baz',
bar: ['bar', 'foo'],
baz: {
qux: 'bazqux'
}
};
// Target Class in which to morph the source data. (Optional)
class Destination {
foo = null;
bar = null;
bazqux = null;
}
// A structure-preserving object from a source data towards a target data.
const schema = {
foo: 'bar[1]', // Grab the property value by his path
bar: (iteratee, source, destination) => {
// Apply a Function on the current element
return iteratee.bar[0];
},
bazqux: {
// Apply a function on property value
path: 'baz.qux',
fn: (propertyValue, source) => {
return propertyValue;
}
}
};
const classObjects = morphism(schema, source, Destination);
// Destination {foo: "foo", bar: "bar", bazqux: "bazqux"}
const jsObjects = morphism(schema, source);
// Object {foo: "foo", bar: "bar", bazqux: "bazqux"}
We live in a era where we deal with mutiple data contracts coming from several sources (Rest API, Services, Raw JSON...). When it comes to transform multiple data contracts to match with your domain objects, it's common to create your objects with Object.assign
, new Object(sourceProperty1, sourceProperty2)
or by simply assigning each source properties to your destination. This can leads you to have your business logic spread all over the place.
Morphism
allows you to keep this business logic centralized and brings you a top-down view of your data transformation. When a contract change occurs, it helps to track the bug since you just need to refer to your schema
Morphism
comes with 3 artifacts to achieve your transformations:
A schema is an object-preserving map from one data structure to another.
The keys of the schema match the desired destination structure. Each value corresponds to an Action applied by Morphism when iterating over the input data.
You can use 4 kind of values in your schema:
ActionString
: A string that allows to perform a projection from a propertyActionSelector
: An Object that allows to perform a function over a source property's valueActionFunction
: A Function that allows to perform a function over source propertyActionAggregator
: An Array of Strings that allows to perform a function over source propertyimport { morphism } from 'morphism';
const input = {
foo: {
baz: 'value1'
}
};
const schema = {
bar: 'foo', // ActionString: Allows to perform a projection from a property
qux: ['foo', 'foo.baz'], // ActionAggregator: Allows to aggregate multiple properties
quux: (iteratee, source, destination) => {
// ActionFunction: Allows to perform a function over source property
return iteratee.foo;
},
corge: {
// ActionSelector: Allows to perform a function over a source property's value
path: 'foo.baz',
fn: (propertyValue, source) => {
return propertyValue;
}
}
};
morphism(schema, input);
// {
// "bar": {
// "baz": "value1"
// },
// "qux": {
// "foo": {
// "baz": "value1"
// }
// },
// "quux": {
// "baz": "value1"
// },
// "corge": "value1"
// }
You might want to enforce the keys provided in your schema using Typescript
. This is possible using a StrictSchema
. Doing so will require to map every field of the Target
type provided.
interface IFoo {
foo: string;
bar: number;
}
const schema: StrictSchema<IFoo> = { foo: 'qux', bar: () => 'test' };
const source = { qux: 'foo' };
const target = morphism(schema, source);
// {
// "foo": "qux",
// "bar": "test"
// }
The simplest way to use morphism is to import the currying function:
import { morphism } from 'morphism';
morphism
either outputs a mapping function or the transformed data depending on the usage:
morphism(schema: Schema, items?: any, type?: any): any
// Outputs a function when only a schema is provided
const fn = morphism(schema);
const result = fn(data);
// Outputs the transformed data when a schema and the source data are provided
const result = morphism(schema, data);
// Outputs the transformed data as an ES6 Class Object when a schema, the source data and an ES6 Class are provided
const result = morphism(schema, data, Foo);
// => Items in result are instance of Foo
Morphism comes along with an internal registry you can use to save your schema attached to a specific ES6 Class.
In order to use the registry, you might want to use the default export:
import Morphism from 'morphism';
All features available with the currying function are also available when using the mixin plus the internal registry:
// Currying Function
Morphism(schema: Schema, items?: any, type?: any): any
// Registry API
Morphism.register(type: any, schema?: Schema);
Morphism.map(type: any, data?: any);
Morphism.setMapper(type: any, schema: Schema);
Morphism.getMapper(type);
Morphism.deleteMapper(type);
Morphism.mappers
import { morphism } from 'morphism';
// Source data coming from an API.
const source = {
foo: 'baz',
bar: ['bar', 'foo'],
baz: {
qux: 'bazqux'
}
};
const schema = {
foo: 'foo', // Simple Projection
bazqux: 'baz.qux' // Grab a value from a deep path
};
morphism(schema, source);
//=> { foo: 'baz', bazqux: 'bazqux' }
import { morphism } from 'morphism';
// Source data coming from an API.
const source = {
foo: {
bar: 'bar'
}
};
let schema = {
barqux: {
path: 'foo.bar',
fn: value => `${value}qux` // Apply a function over the source property's value
}
};
morphism(schema, source);
//=> { barqux: 'barqux' }
import { morphism } from 'morphism';
// Source data coming from an API.
const source = {
foo: {
bar: 'bar'
}
};
let schema = {
bar: iteratee => {
// Apply a function over the source propery
return iteratee.foo.bar;
}
};
morphism(schema, source);
//=> { bar: 'bar' }
import { morphism } from 'morphism';
// Source data coming from an API.
const source = {
foo: 'foo',
bar: 'bar'
};
let schema = {
fooAndBar: ['foo', 'bar'] // Grab these properties into fooAndBar
};
morphism(schema, source);
//=> { fooAndBar: { foo: 'foo', bar: 'bar' } }
Register a mapper for a specific type. The schema is optional.
Morphism.register(type: any, schema?: Schema);
Map a collection of objects to the specified type
Morphism.map(type: any, data?: any);
Morphism.setMapper(type: any, schema: Schema);
Morphism.getMapper(type);
Morphism.deleteMapper(type);
Morphism.mappers;
MIT © Yann Renaudin
FAQs
Do not repeat anymore your objects transformations.
We found that morphism demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.