Skip to content

ddoronin/zangetsu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Zangetsu (斬月, Slaying Moon)

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); // same object

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 using 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 \ hasBar true false
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 the file extension and apply gzip only if this is javascript or css.

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

Method Description
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

About

⚔️ Zangetsu (斬月, Slaying Moon) is a sword for javascript objects

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published