@activix/spec-pattern
TypeScript icon, indicating that this package has built-in type declarations

1.1.2 • Public • Published

spec-pattern

Implementation of the Specification Pattern for JavaScript and TypeScript.

Useful for building complex filters or rules in a easy way.

No external dependencies. Fully tested. Adopts semantic versioning. Forks are welcome!

Build Status

Install

$ npm install spec-pattern --save

Examples

A simple Between rule

import { Between } from 'spec-pattern';

let rules = new Between( 1, 3 );

console.log( rules.isSatisfiedBy( 2 ) ); // true

A little more complex Between rule

import { Between } from 'spec-pattern';

let rules = new Between( 1, 3 )
   .or( new Between( 6, 9 ) );

console.log( rules.isSatisfiedBy( 2 ) ); // true
console.log( rules.isSatisfiedBy( 7 ) ); // true
console.log( rules.isSatisfiedBy( 5 ) ); // false

Composing rules

import { Between, In, GreaterThan } from 'spec-pattern';

let rules = new Between( 1, 3 )
   .or( new Between( 6, 9 ) )
   .or( new In( [ 11, 25, 31 ] )
   .or( new GreaterThan( 50 ) );

console.log( rules.isSatisfiedBy( 2 ) ); // true
console.log( rules.isSatisfiedBy( 7 ) ); // true
console.log( rules.isSatisfiedBy( 5 ) ); // false
console.log( rules.isSatisfiedBy( 11 ) ); // true
console.log( rules.isSatisfiedBy( 50 ) ); // false
console.log( rules.isSatisfiedBy( 51 ) ); // true

Not only numbers

import { StartsWith, Contains } from 'spec-pattern';

let rules = new StartsWith( 'Hello' )
    .andNot( new Contains( 'world' ) );

console.log( rules.isSatisfiedBy( 'Hello Bob' ) ); // true
console.log( rules.isSatisfiedBy( 'Hello world' ) ); // false
import { LengthBetween, EqualTo } from 'spec-pattern';

let rules = new LengthBetween( 2, 5 )
    .andNot( new EqualTo( 'Hello' ) );

console.log( rules.isSatisfiedBy( '' ) ); // false
console.log( rules.isSatisfiedBy( 'Hi' ) ); // true
console.log( rules.isSatisfiedBy( 'Hello' ) ); // false
console.log( rules.isSatisfiedBy( 'Howdy' ) ); // true
console.log( rules.isSatisfiedBy( 'Hello world' ) ); // false

Available classes

  • EqualTo( value: any )
  • GreaterThan( value: any )
  • GreaterThanOrEqualTo( value: any )
  • LessThan( value: any )
  • LessThanOrEqualTo( value: any )
  • Between( min: any, max: any )
  • In( values: array )
  • StartsWith( value: string, ignoreCase: boolean = false )
  • EndsWith( value: string, ignoreCase: boolean = false )
  • Contains( value: string, ignoreCase: boolean = false )
  • LengthBetween( min: any, max: any )
  • Matches( regex: RegExp )

All these classes extend the abstract class Composite, which in turn implements the interface Spec:

interface Spec< T > {

    isSatisfiedBy( candidate: T ): boolean;

    and( other: Spec< T > ): Spec< T >;

    andNot( other: Spec< T > ): Spec< T >;

    or( other: Spec< T > ): Spec< T >;

    orNot( other: Spec< T > ): Spec< T >;

    not(): Spec< T >;
}

Creating your own class

Creating your own class is very easy. Just extends abstract class Composite_, like in the following example. Of course, you can also extend one of the aforementioned classes or implement the interface Spec_ (but why reinventing the wheel, right?).

Let's create a class DifferentFrom_ ...

...in TypeScript:

import { Composite } from 'spec-pattern';

export class DifferentFrom< T > extends Composite< T > {

    constructor( private _value: T ) {
        super();
    }

    isSatisfiedBy( candidate: T ): boolean {
        return this._value != candidate;
    }

    toString(): string {
        return 'different from ' + this._value;
    }
}

...or in JavaScript 6+:

import { Composite } from 'spec-pattern';

class DifferentFrom extends Composite {

    constructor( value ) {
        this._value = value;
    }

    isSatisfiedBy( candidate ) {
        return this._value != candidate;
    }

    toString() {
        return 'different from ' + this._value;
    }
}

...or in JavaScript 5+:

var Composite  = require( 'spec-pattern' ).Composite;

function DifferentFrom( value ) {

    Composite.call( this ); // super()

    this._value = value;

    this.isSatisfiedBy = function ( candidate ) {
        return this._value != candidate;
    };

    this.toString = function() {
        return 'different from ' + this._value;
    };
}

DifferentFrom.prototype = Object.create( Composite.prototype );
DifferentFrom.prototype.constructor = DifferentFrom;

That's it! Just three methods: constructor, isSatisfiedBy, and toString().

License

MIT © Thiago Delgado Pinto

Dependencies (0)

    Dev Dependencies (4)

    Package Sidebar

    Install

    npm i @activix/spec-pattern

    Weekly Downloads

    2

    Version

    1.1.2

    License

    MIT

    Unpacked Size

    64.2 kB

    Total Files

    21

    Last publish

    Collaborators

    • philippe-tellier
    • jdeslauriers
    • alexandrepilon
    • alexa.
    • dgaudet
    • vinnygambiny