stateful-predicates v1.0.2
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.tsfor Javascript. - Well tested. 100% code coverage.
Installation
$ npm install stateful-predicatesUsage
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:
Pstays true "on and after"predicateForTruehas succeeded on some elementPbecomes false again "on and after"predicateForFalsehas succeeded on some element that follows.
At the beginning,Pis false.Pis reusable: able to switch true/false multiple times.Pis greedy:
- switches to true on the first of consecutive elements
predicateForTruecan succeed - switches to false on the first of consecutive elements
predicateForFalsecan 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
parentPredicatehas "succeeded at element"offsetnumber 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.
Pis greedy: tries to succeed as soon as possible. If there are more elements within the "offsetrange"parentPredicatecould succeed, they are not recognized.Pis repeatable: is ready to detect elements again as soon as it is at leastoffsetelements 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
parentPredicatehas succeededntimes
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
parentPredicatechanges value - i.e. result ofparent predicatediffers 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
// */