0.2.1 • Published 6 years ago

zangetsu v0.2.1

Weekly downloads
3
License
MIT
Repository
github
Last release
6 years ago

Zangetsu (斬月, Slaying Moon) is a sword used by the character Ichigo Kurosaki in the Bleach series.

GitHub license npm version Build Status Coverage Status

$ yarn add zangetsu

Mutable & Immutable

This library exposes two namespaces: Mutable and Immutable. Use Immutable if you need to produce a new object. Mutable - to modify existing one.

import { Immutable } from 'zangetsu';
...
let foo = {foo: 'Foo'};
let bar = {bar: 'Bar'};
let fooBar = Immutable.compose(foo).append(bar);
assert(fooBar !== foo); // different objects
import { Mutable } from 'zangetsu';
...
let foo = {foo: 'Foo'};
let bar = {bar: 'Bar'};
let fooBar = Mutable.compose(foo).append(bar);
assert(fooBar === foo); // fooBar and foo hold same reference. In other words foo is not { foo: 'Foo' } any more.

console.log(foo);       // will print out { foo: 'Foo', bar: 'Bar' }

Declarative Syntax

This library can extend objects with additional fields, remove fields with projection operator $ and do it as a part of logical branching (if, elseif and else):

import { Immutable } from 'zangetsu';
...
Immutable
    // compose a new object
    .compose({
        hello: 'World!'
    })

    // extend with another object
    .append({
        alice: 'Alice'
    })

    // extend if condition is satisfied
    .if(hasFoo && hasBar, {
        foo: 'Foo',
        bar: 'Bar'
    })

    // or if another condition is satisfied
    .elseif(hasFoo, {
        foo: 'Foo'
    })

    // the chain could be long and it will stay readable
    .elseif(hasBar, {
        bar: 'Bar'
    })

    .else({
        noFooNoBar: 'NoFooNoBar'
    })
    
    // build projections to filter fields
    .$({
        hello: false,
        alice: false,
        foo: true,
        bar: true,
        noFooNoBar: true
    })

    // return the result
    .val();
hasFoo \ hasBartruefalse
true{ foo: 'Foo', bar: 'Bar' }{ foo: 'Foo' }
false{ bar: 'Bar' }{ noFooNoBar: 'NoFooNoBar' }

Real Life Example

Suppose you need to compose an HTTP request to upload a file to a server. You decided to set content type based on a file extension and apply gzip for javascript and css files.

import { Immutable } from 'zangetsu';
...
const createRequest = (payload: any, fileExt: string) => 
    Immutable
        .compose({
            body: { ...payload }
        }).if(fileExt === 'js', {
            contentType: 'text/javascript'
        }).elseif(fileExt === 'css', {
            contentType: 'text/css'
        }).else({
            contentType: 'application/octet-stream'
        }).if(['js', 'css'].includes(fileExt), {
            encoding: 'gzip'
        }).val();

API

MethodDescription
compose(a)Creates a wrapper for a given object a.
append(b)Appends an object b to the context a.
if(condition, b)Appends a given object b to the context `a if and only if the condition is satisfied.
elseif(condition, c)Appends a given object c to the context a if and only if the condition is satisfied and all previous conditions were falsy.
else(d)Appends a given object d to the context a if all previous conditions were falsy.
$(projection)Creates a projection of a context object a and returns only true fields.
val()Simply returns the context object a.
export interface IComposer<A> {

    append<B>(b: B): IComposer<A & B>;

    if<B>(condition: boolean, b: B): IComposer<A | (A & B)>;

    elseif<C>(condition: boolean, c: C): IComposer<A | (A & C)>

    else<D>(d: D): IComposer<A | (A & D)>;

    $(projection: {[K in keyof A]: Boolean}): IComposer<{[K in keyof A]: A[K] }>;

    val(): A;
}

License

MIT

0.2.1

6 years ago

0.2.0

6 years ago

0.1.1

6 years ago

0.1.0

6 years ago

0.0.1

6 years ago