1.1.10 • Published 5 months ago

@zacharygriffee/interface v1.1.10

Weekly downloads
-
License
MIT
Repository
-
Last release
5 months ago

z-interface

An Interface implementation for vanilla Javascript

An interface aim is to prohibit access to all resources by default, allowing access only through well-defined entry points, Wikipedia

Installation

npm install @zacharygriffee/interface --save

Import

import {Interface, canInterface, isInterface, SYMBOLS} from "@zacharygriffee/interface";

Usage examples

Create interface

// interfaces.js

// Use the 'design factory'
export const IName = Interface(
    ({Accessor}) => ({
        name: Accessor
    })
);

// Or import the symbols and use them in an object.
const {Get, Function} = SYMBOLS;

export const IAge = Interface({age: Get});
export const IWalk = Interface({walk: Function});
export const INameAndAge = Interface({
    IName, IAge
});
export const IFly = Interface({
    Fly: Get
});

Use Interface

Interface any object

// Create an object to interface
function createPerson(name, age) {
    return {
        get age() {
            return age;
        },
        set name(value) {
            name = value;
        },
        get name() {
            return name;
        },
        walk() {
            return this.name + " walking";
        },
        beamedUp() {
            return this.name + " beamed up";
        }
    }
}

const piccard = createPerson('Piccard', 42);

Use the interfaced (object | class instance)

import {
    IName,
    IAge,
    IWalk,
    INameAndAge,
    IFly
} from "./interfaces.js";

isInterface(IWalk);                             // true
canInterface(IWalk, piccard);                   // true
Interface.canInterface(IAge, piccard);          // true
canInterface(IFly, piccard);                    // false, Piccard needs the enterprise to fly.

const walker = IWalk(piccard);
const age = IAge(piccard);
const nameAndAge = INameAndAge(piccard);

// CAN
walker.walk();                                  // "Piccard walking'
age.age;                                        // 42
nameAndAge = "Captain Piccard";                 // sets the name of the interfaced instance
piccard.name;                                   // "Captain Piccard"
nameAndAge.age;                                 // 42

// CANNOT
const walkerAge = walker.age;                   // undefined, IWalk doesn't have access to age
walker.beamedUp();                              // throws 'function doesn't exist'
age.age = 12;                                   // IAge only has a getter, this will throw TypeError

API

Interface(designOrDesignFactory)

There are two ways to create an interface.

One | Design

import {SYMBOLS, Interface} from "@zacharygriffee/interface";

const {
    Get, Set, Accessor
} = SYMBOLS;

Interface({
    name: Accessor,     // The interface will have both get and set access.
    age: Get            // The interface will only have Get access to 'age' 
});

Two | Design Factory

Pass a function as first argument of Interface and use destructuring to access the SYMBOLS

import {Interface} from "@zacharygriffee/interface";

Interface(({Get, Accessor}) =>
    ({
        name: Accessor,
        age: Get
    })
);

// OR verbosely
Interface((SYMBOLS) => {
        return {
          name: SYMBOLS.Accessor,
          age: SYMBOLS.Get
        }
    }
);

Interface a target (Object | Class Instance)

const IName = Interface({name: SYMBOLS.Get});

let _name = "Captain Piccard";
const target = {
    get name() {
        return _name;
    },
    set name(val) {
        _name = val;
    }
};

const personName = IName(target);
personName.name; // Captain Piccard
personName.name = "Q"; // throws TypeError, interface doesn't implement setter.

bool = interface.canInterface(target)

Check if an interface can interface a target.

IWalk.canInterface(piccard);    // true

SYMBOLS

Let

The property can be anything of target. The interface can do anything with this property.

Get

The target must have a getter. The interface will only have read access to this property.

Set

The target must have a setter. The interface will only have write access to this property.

Accessor

The target must have both a getter and setter. The interface will have both read and write access.

Fluent

Same as accessor however it changes the property behavior to allow for chaining; useful with observables.

const piccard = INameAndAge(person);      // Assume name and age both are 'Fluent'
piccard.name("Captain Piccard").age(43);  // The set method returns the interface to chain.

piccard.name // Captain Piccard
piccard.age  // 43

// Example with rxjs
rx.of(piccard).pipe(
    rx.map(piccard => piccard.name("Captain Piccard")),
    rx.map(piccard => piccard.age(44))
);

Object

The property of target must be an object.

Array

The property of target must be an array.

Function

The property of target must be a function.

Async | Promise

The property of target must be thenable | async. value = Promise.resolve(42)

AsyncFunction

The property of target must be an async function. e.g. async imAsync() { /* do async things */ }

Observable

The property of target must be an observable. To satisfy, the target must have subscribe and lift function.

Observer

The property of target must be an observer. Either a standard function or an object containing at least one of these functions next, error, complete

Subject

The property of target must satisfy both observable and observer validations above.

Utilities

bool = Interface.isInterface(interface)

Check whether interface is an Interface made by z-interface.

bool = Interface.canInterface(interface, target)

Check whether 'target' can be interfaced by 'interface'.

Test it

npm test

Distributed under the MIT license. See LICENSE for more information.

1.1.10

5 months ago

1.1.9

5 months ago

1.1.8

6 months ago

1.1.6

6 months ago

1.1.5

6 months ago

1.1.4

6 months ago

1.1.3

6 months ago

1.1.2

6 months ago

1.1.1

6 months ago

1.1.0

6 months ago

1.0.6

6 months ago

1.0.5

6 months ago

1.0.4

6 months ago

1.0.3

6 months ago

1.0.2

6 months ago