stateful-predicates
v1.0.2
Published
Bunch of stateful predicate wrappers. RxJS & Array.filter compliant.
Downloads
6
Maintainers
Readme
stateful-predicates
Carefully selected, minimalistic collection of predicate wrappers.stateful-predicates
bring new power to standard predicates, required by Array.filter, RxJS or other methods/libraries that use predicates.
Predicate list:
Example: Get an inside of a block documetation comment:
import {switchTrueFalse, nthElementAfter} from 'stateful-predicates';
// prettier-ignore
const linesInsideADocBlockComment = lines.filter(
switchTrueFalse(
nthElementAfter(1, // start to "return true" one line after a `/**`
s => /\/\*\*/i.test(s)
),
s => /\*\//i.test(s) // start to "return false" on a line with `*/`
)
);
see a complete example
stateful-predicates
library is all about predicates applied to elements of some list. That list is typically an iterable.
When a predicate is applied to an element, that predicate can either succeed on that element (i.e. match that element), or not.
Why to use
- No state variable mess as it uses closures to preserve the state.
- Functional programming friendly.
- Typed. With
d.ts
for Javascript. - Well tested. 100% code coverage.
Installation
$ npm install stateful-predicates
Usage
Typescript / ES module:
import * as SP from 'stateful-predicates';
Javascript / CommonJS:
const SP = require('stateful-predicates');
API
TPredicate
type TPredicate<T> = (value: T, index: number) => boolean;
Predicate is a function, that accepts some value and returns a boolean value, based on its condition.
It's something you can pass as callback to Array.filter or RxJS operators.
Almost every function of stateful-predicates
library accepts at least one TPredicate
argument and returns another TPredicate
value.
switchTrueFalse
function switchTrueFalse<T>(
predicateForTrue: TPredicate<T>,
predicateForFalse: TPredicate<T>
): TPredicate<T>;
Returns a predicate(value, index) P
that fulfills the following:
P
stays true "on and after"predicateForTrue
has succeeded on some elementP
becomes false again "on and after"predicateForFalse
has succeeded on some element that follows.
At the beginning,P
is false.P
is reusable: able to switch true/false multiple times.P
is greedy:
- switches to true on the first of consecutive elements
predicateForTrue
can succeed - switches to false on the first of consecutive elements
predicateForFalse
can succeed
Example:
const elementsBetweenZeroAndMinusOne = [2, 1, 0, 0, 5, 9, -1, -1, 7].filter(
switchTrueFalse(
x => x === 0,
x => x === -1
)
);
console.log(elementsBetweenZeroAndMinusOne);
//=> [ 0, 0, 5, 9 ]
nthElementAfter
function nthElementAfter<T>(
offset: number,
parentPredicate: TPredicate<T>
): TPredicate<T>;
Returns predicate(value, index) P
, that:
- returns true if its
parentPredicate
has "succeeded at element"offset
number of elements before.
Example:
const isThree = (x: number) => x === 3;
const secondElemsAfter3 = [2, 3, 0, 7, 4, 3, 5, -8].filter(
nthElementAfter(2, isThree)
);
console.log(secondElemsAfter3);
//=> [ 7, -8 ]
It kind of shifts (or delays) the succesful element evaluation.
P
is greedy: tries to succeed as soon as possible. If there are more elements within the "offset
range"parentPredicate
could succeed, they are not recognized.P
is repeatable: is ready to detect elements again as soon as it is at leastoffset
elements after its last detected element.
const result = [3, 2, 2, 2, 5, 1].map(nthElementAfter(1, x => x === 2));
console.log(result);
//=> [ false, false, true, false, true, false ]
nthMatch
function nthMatch<T>(n: number, parentPredicate: TPredicate<T>): TPredicate<T>;
Returns predicate(value, index) P
, that:
- returns true if its
parentPredicate
has succeededn
times
Example:
const isEven = x => x % 2 === 0;
const secondMatchingElem = [2, 3, 5, 4, 8, 5, -8].filter(nthMatch(2, isEven));
console.log(secondMatchingElem);
//=> [ 4 ]`
onChange
function onChange<T>(parentPredicate: TPredicate<T>): TPredicate<T>;
Returns predicate(value, index) P
, that:
- returns true whenever its
parentPredicate
changes value - i.e. result ofparent predicate
differs fromP
's internal state.
At the begin, the internal state of P
is false.
Example:
const isThree = (x: number) => x === 3;
const changes = [2, 3, 3, 3, 4, 3, 5, -8].map(onChange(isThree));
console.log(changes);
//=> [ false, true, false, false, true, true, true, false ]
Complete Example
Show only documentation comments from a source code input text:
import {switchTrueFalse, nthElementAfter} from 'stateful-predicates';
const input = `
/**
* greaterThanOne
* @param x number value
* @returns true if x is greater than one, false otherwise
*/
*/
function greaterThanOne(x: number): boolean {
return x > 1;
}
/**
* An increment function
* @param x number value
* @returns that value incremented by one
*/
const inc = (x: number) => ++x;`;
const docCommentPredicate = () =>
switchTrueFalse<string>(
s => /\/\*\*/.test(s), // true at '/**' (begin-mark)
nthElementAfter(1, s => /\*\//.test(s)) // false after '*/' (end-mark)
);
// prettier-ignore
const onlyDocComments = input
.split('\n')
.filter(docCommentPredicate())
.join('\n');
console.log(onlyDocComments);
//=> /**
// * greaterThanOne
// * @param x number value
// * @returns true if x is greater than one, false otherwise
// */
// /**
// * An increment function
// * @param x number value
// * @returns that value incremented by one
// */