The library exposes the @@extractor
and @@ignored
symbols which are used in the pattern matching protocol.
An object that implements pattern matching has a @@extractor
function which takes in two arguments, the value
of the thing to match, and previousExtracted
which is an object containing any previous extracted values.
It must return an object with a property matched
containing a boolean on whether a match was made and if it did, a property extracted
containing an object of extracted values.
The object can also have a boolean @@ignored
property.
This indicates that the pattern matching will ignore the value to match with, allowing for some optimizations.
The library also contains a Pattern
abstract class in the patterns
object for extending, containing utility methods.
When pattern constructors expect a pattern to be passed in, Pattern.patternOf
should be ran to ensure it has @@extractor
.
The method patternOf
takes in a value, and if it has @@extractor
, return it, otherwise:
- If the value is primitive, wrap it in an
EqualPattern
. - If the value is an array, pass it to
ArrayPattern
. - If the value is a
Map
, pass it toMapPattern
. - Otherwise, pass it to
ObjectPattern
.
For the last three cases, if the structure has the @@rest
symbol in it, it will be used as the rest pattern:
- For arrays, the last item must be
[@@rest, pattern]
. - For
Map
s, there must be an entry@@rest => pattern
. - For objects, there must be an entry
[@@rest]: pattern
.
Each branch of patternOf
has corresponding patternOfPrimitive
, patternOfArray
, patternOfMap
, and patternOfObject
methods.
The Pattern
class also has the methods test
and match
corresponding to the built-in tester
and matcher
functions.
Example of a custom pattern:
class NotEqualAndBindPattern extends Pattern {
constructor(value, id) {
super();
this.value = value;
this.id = id;
}
[extractor](value, previousExtracted) {
if (this.id in previousExtracted && !Object.is(value, previousExtracted[this.id])) {
return { matched: false };
}
return !Object.is(value, this.value)
? { matched: true, extracted: { [this.id]: value } }
: { matched: false };
}
}
// This object implements the protocol.
const pattern = new NotEqualAndBindPattern(10, 'x');
pattern[extractor](10, {})
→ { matched: false }
pattern[extractor](11, {})
→ { matched: true, extracted: { x: 11 } }
pattern[extractor](11, { x: 5 })
→ { matched: false }