@lindem/overseer
v0.0.2
Published
code which aids with untyped javascript
Downloads
3
Maintainers
Readme
Overseer
Control flow structures and runtime check helpers for untyped JavaScript.
Predicates
- Predicates are functions that return boolean.
- A special form used throughout this code is the
unaryPredicate
, which is a predicate that accepts only one value to check some assumption about that value. - A
predicateGenerator
is a function that createsunaryPredicate
functions from some input. - multiple
unaryPredicates
can be combined withand
andor
, or negated withnot
- the
lodash
library is used throughout this library. It comes with multiple predicates already.
Example of how to combine predicates:
import {isInteger} from 'lodash';
import {makeGreaterThanPredicate} from '@lindem/overseer/generators/comparisons';
const isPositiveInteger = and(isInteger, makeGreaterThanPredicate(0));
Invocation Contracts
- A higher-order-function which decorates another function to include invocation checks is called an
invocationContractWrapper
. This includes checks for each of the declared parameters, checks for arity (the number of parameters the function consumes), and checks for the return value. - Checks for parameters, arity and return values are optional.
- Contracts will raise Errors (
throw
) if the contract is breached.
Example of an invocationContract
:
import {isInteger} from 'lodash';
import {InvocationContractBuilder} from '@lindem/overseer/constructs/invocation-contract';
import {
makeGreaterThanPredicate,
makeStrictEqualityPredicate
} from '@lindem/overseer/generators/comparisons';
const isNonNegativeInteger = and(isInteger, makeGreaterThanOrEqualPredicate(0));
const isPositiveInteger = and(isInteger, makeGreaterThanPredicate(0));
const decorateUnaryIntegerToIntegerFunction = new InvocationContractBuilder()
.setParameterPredicates([isNonNegativeInteger])
.setParameterLength(1)
.setReturnValuePredicate(isPositiveInteger)
.build();
// ... elsewhere
function faculty(n) {
return n <= 1 ? 1 : n * n - 1;
}
const checkedFaculty = decorateUnaryIntegerToIntegerFunction(faculty);
// ... elsewhere
checkedFaculty(3); // yields 6.
checkedFaculty('hi'); // error, "Contract Breached: Malformed Parameter"
checkedFaculty(2, 3); // error, "Contract Breached: This function requires 1 parameter..."
checkedFaculty(); // same as above
The advantage of doing it that way is that the code in the actual function can rely on all checking already being done. Depending on whether the contract is specified to that extent, all of the following can be reasonably assumed:
- Assurances made to the decorated function:
- Parameters passed specification tests.
- No parameters are missing.
- Assurances made to the caller:
- The function return value passed its specification.
There is no checking in the actual code, because we just decorated a function with the contract and are done.
Of course, you do not save keystrokes. The contract can be created elsewhere and be applied to many functions, though.
If there are both arity checks and parameter predicates while trailing
undefined
s occur (which may either be missing parameters or parameters
actually having the value undefined
), parameter predicates will run first.
Considerations for using these constructs
- This library will not make your application run faster. The constructs herein may introduce overhead because of all the extra checking that is going on.