- use
this
to pass captures and next, thenarity
opt is just an optimisation - have a
trust: boolean
option instead ofstrict
? Since it's more about whether methods are trusted to comply - decide:
captures
gets all matches, even anon ones as[0]
,[1]
, etc (like expressreq.params
) - rename CONTINUE --> FALLTHROUGH ?? Compare implications of terms...
- if two ambiguous cases have the same handler, then make that NOT ambiguous...
- can't in general because they may fall back to different handlers
- but if we know there are no fallbacks, the cases are def not ambiguous
- need a marker (like the
meta
function) or option indicating no fallbacks- per method? or per multimethod?
- idea: support second handler qualifier (first is meta vs nonmeta): cascading vs non-cascading (can/t fallback)
- which one requires explicit qualifier? Probably cascading since it has more complex behaviour
- name?
cascade
,casc
,try
,step
,option
, bid, best, first, race, partial, part, test, layer,cont
- memoise: auto-clear on future tick
- validation: can a method chain be empty? i.e., a pattern associated with 0 methods?
- it might be useful if it effectively works like a no-op.
- check if it indeed does work like this at present, or otherwise how it can be made to do so
- example: routist @allow on a pattern that exists only for permissions (ir has no handler)
- it might be useful if it effectively works like a no-op.
- rename
Configuration
toSettings
? Or leave it? - validation: check for unrecognised options
- export an
extend
function that takes a MM and a method table and returns a new multimethod- use
super
in chains to control overriding behaviour w.r.t. original MM - makes a new method table from the two given ones and returns a new multimethod with the extended method table
- original multimethod is unchanged
- new multimethod gets same config as given one
- method chains support explicit relative specificity with
'super'
- explicit method specificity is required, otherwise throws an 'ambiguous' error
- add tests for all of above
- use
- support even more special characters in patterns
- Address code quality in /src
- Rationalise file structure under /src
- Reasonable breakdown of functions
- JSDoc comments for all exports
- Descriptive inline comments so someone can understand the inner workings
- Write better README
- TOC
- Rationale / motivating example - problem, solution
- Installing
- Usage example
- Further Details
- patterns
- options / configuration
- method table: specificity, chains, NEXT, meta-methods, etc
- Improve unit test coverage
- add basic tests for correct arg passing for variadic, nullary, unary, binary and ternary MMs
- Early MM validation errors:
- illegal chain (regular handlers before meta handlers)
- ambiguous rules
- arity mismatch
- TODO: more checks...
- MM dispatch results:
- regular rules only
- overlapping rules
- catch-all meta rule
- chain of regular rules
- catch-all metarule chain
- mixed chain
- limited metarule
- misc rules
- TODO: more cases...
- investigate and fix UMD errors when compression is enabled in uglifyjs.
- support numeric discriminant matching for very fast dispatch scenarios (like my C++/C# MMs did)
- pattern
|
operator: determine future pathway for relaxing some/all of the current restrictions- can mix alternation and named captures, however:
- capture names must be unique within a pattern
- upon successfully matching a pattern against a string, some names may be absent in the
captures
hash
- can mix alternation and named captures, however:
- document current restrictions w.r.t
|
alternation operator in patterns:- a pattern cannot have both alternation and named captures
- in a normalised pattern, no alternative is a subset of any other alternative (they are removed)
- in a normalised pattern, alternatives are arranged in lexicographical order
- describe the ordering in unambiguous/locale-invariant terms. ANS: uses
Array#sort
default comparer
- describe the ordering in unambiguous/locale-invariant terms. ANS: uses
- export a
Multimethod
type (or family thereof)- or not, it's just a straightforward function signature, nothing special added
- address
UnhandledPromiseRejectionWarning
intest/**/multimethod.ts
(see TODO comments there) - use
benchmark.js
for benchmarks/perf tests - address inefficiencies in how
intersect.ts
is coded (eg use memoisation, early deduping, etc) - new option
toType: Function
- if provided and notoDiscriminant
given, the defaulttoDiscriminant
uses it - new option
allowNulls
- mms should rejectnull
args unless this is explicitly set totrue
- support simplified MM creation: accept method table directly instead of inside
methods
prop. - strict mode: if fixed arity, check number of arguments passed to discriminant is correct
- review fatalError module again: 1. don't use ALL_CAPS, how best to export? c.f. TypeScript internals...
- add sticky copyright comment at top of multimethods.min.js
- test in real IE11 browser
- get rid of nasty TypeScript '!' non-null assertions in code
- Use consistent British English spelling (-ise vs -ize)
- docs/comments/tests: get rid of refs to address, request, response (now discriminant, parameters/arguments, return value/result)
- Multimethod - fix up all terminology
- src code props, vars, fns, exports, filenames, etc
- src code comments
- README - glossary, descriptions, etc
- revise/revamp method function validation
- MAIN AIM: to ensure pattern captures stay synced with their methods, and error early if not, with opt-outs
- validate method function.length.
- the
captures
param:- if object destructuring is used, require 1:1 correspondence to captured names
- if object destructuring is used, either account for or don't support prop renaming (which??? depends how easy/hard)
- if object destructuring is NOT used:
- disallow under some 'strict checking' option?
- if the pattern has named captures, then method length must include the
captures
param - if the pattern has NO named captures, then method length must exclude the
captures
param
- move TODO list(s) to separate github issues
- Multimethods are immutable.
- document that multimethods are immutable and why. e.g. can emit fast code for them.
- check code - ensure no mutating operations on multimethods
- doc/explain NEXT - this is an imperative return value of what MM should do next, not a declaration of what just happened in current handler.
- Fix terminology in code and comments
- executor --> implementation, behaviour, case, effective handler, override, overload, subfunction, method, form, shape, mode
- no such thing as a metarule, only a meta-handler
- UNHANDLED --> CONTINUE
- dispatch
- selector
- executor
- next --> forward/fwd
- rule
- pattern (rename from
pattern
in code/codegen/comments) - regular handler (rename from
method
in code/codegen/comments) - meta handler (rename from
method
in code/codegen/comments) - ruleset
- TODO: fix meta() function
- should detect whether used as a wrapper function around a handler, or as a property decorator
- remove dep on
util.format
infatal-error.ts
- consistent British English spelling
- consistent code style & quality
- functionality & test converage
- perforance & benchmarks
- all errors and warnings (eg validation, codegen, etc)
-
use URI ref: https://tools.ietf.org/html/rfc3986
-
TODO: char pool yet to classify:
- unallocated:
% ^ | $ ' " ( ) + , ;
was: - [ ] URI reserved chars:: ? # [ ] @ ! $ & ' ( ) + , ; =
- [ ] Others:% ^ ~ < > " |
- unallocated:
-
support pattern 'type' indicators - eg binary patterns like
*100*10
, and maybe more future ones -
treat the following as literal match characters:
-
a-z A-Z 0-9 <space> _ / - . : < > @ !
(already supported) -
~
(unreserved in URIs - so may commonly appear in URLs) -
? = & #
(commonly appear in URIs as delimiters) -
[ ]
(also used in some URI schemes according to RFC3986#1.1.2) -
+
is this always unescaped to space? The RFC lists it as a reserved demiliter
-
-
TODO: revise whether to treat the following as literal match characters. List pros/cons
- (already supported)
-
TODO: Implement the following operators:
-
*
wildcard -
...
/**
globstar- TODO: change back to
**
? Pros: One less special char. Cons: Ambiguous? - Use single unicode 'letter' char for
**
: U+156Fᕯ
- TODO: change back to
-
{...}
/{**}
wildcard/globstar named capture
-
-
TODO: Reserve the following characters for future use:
-
( ) |
-
TODO: union/or:
|
? -
TODO: alternatives
(abc|def|123)
-
TODO: zero or one
(abc?)
-
TODO: escape sequence
('$30?!')
or("it's")
or(u0213)
ormy( )site
(literal space) -
general reserve: ``
-
-
TODO: Reserve the following characters to be always illegal in patterns (unless escaped):
- doc why to have this:
- so client have a few special characters for augmenting patterns for their own use. They can safely manipulate/strip out these chars knowing they cannot possibly be part of the pattern
- for safely putting other props in same hash as rules, eg
$toDiscriminant
or similar
- TODO:
$ ;
- doc why to have this:
-
TODO: Support escape sequences for any character as follows:
- TODO: ...
-
TODO: special rules for spaces?
-
TODO: check out unicode 'VAI' for many interesting symbol-like characters eg:
ꗬ ꗈ ꕹ ꕤ ꕢ ꖜ ꗷ ꗤ
-
TODO: doc use of special chars in emitted MM code
-
ᐟ
(U+141F) to differentiate otherwise-equivalent identifiers -
ː
(U+02D0) to visually separate parts of an identifier - SUPPORT ADDED ALREADY - valid identifier chars:
- M
Ɱ
U+04CE - \s
ˑ
U+02D1 (for space) -
ӿ
U+04FF
- **
ᕯ
U+156F - /
Ⳇ
U+2CC6 -
ᅳ
U+FFDA
- .
ˌ
U+02CC - :
ː
U+02D0 - <
ᐸ
U+1438 -
ᐳ
U+1433 - @
ဇ
U+1007 - |
ǀ
U+01C0 - ∅
Ø
U+00D8
- M
- CONSIDER FUTURE SUPPORT - valid identifier chars:
-
\
〵
U+3035 -
?
ॽ
U+097D -
ᕀ
U+1540
-
!
ǃ
U+01C3 -
^
ᣔ
U+18D4 -
~
ᱻ
U+1C7B -
'
ʼ
U+02BC -
"
ˮ
U+02EE -
-
%
ꕑ
U+A551 any better one? -
,
ˏ
U+02CF any better one? -
;
ꓼ
U+A4FC any better one? -
=
ꘌ
U+A60C any better one? -
none found for:
( ) [ ] { } &
-
-
/foo/b(ar|az)/quux
<-- real parentheses
/foo/bᑕar|azᑐ/quux
/foo/bᒥar|az/quux
/foo/bᒪar|azᒧ/quux
/foo/bᒻar|azᒽ/quux
/foo/bᔪar|azᔨ/quux
/foo/bᕮar|azᕭ/quux
/foo/bᕳar|azᕲ/quux
/foo/bᖱar|azᖲ/quux
/foo/bᗕar|azᗒ/quux
/foo/bᗧar|azᗤ/quux
/foo/bᗭar|azᗪ/quux
/foo/bᗴar|azᗱ/quux
/foo/bᘳar|azᘰ/quux
/foo/bᢰar|azᢱ/quux
/foo/bᢱar|azᢰ/quux
/foo/bᐊar|azᐅ/quux
/foo/bᗏar|azᗌ/quux
/foo/bᕙar|azᕗ/quux
/foo/bᦷar|azᦡ/quux
/foo/bꀯar|azꡳ /quux
<-- not too bad?
/foo/b𐡋ar|az𐡐/quux
but the right bracket is double-width PITA U+10C23
/foo/bꉔar|az𐰣/quux
but the right bracket is double-width PITA U+10C23
(1 * (2 + 3)) / 4
ᐊ1 * ᐊ2 + 3ᐅᐅ / 4
ꀯ1 * ꀯ2 + 3ꡳꡳ / 4
ᑘ0FA4
ᑘ0FA4
𐩧
(U+10A67) bad handling in VSCode - double width
𐰣
(U+10C23) " "
i have spaces
i( )have( )spaces
i[ ]have[ ]spaces
i+have+spaces
literal [+] sign
it(')s about time
it[']s about time
GET http://blah.com
GET [ ] http://blah.com
GET+http://blah.com
http://app.co[#]some-id
http://app.co/things?item=t[[100]]
(ab*c|a*bc)def
Pattern Special Chars:
-
Literal Match:
/ ? ; : @ & = + $ ,
- _ .
-
Reserve for operators:
* ... { } | [ ] ! ^ ( ) \ ~ `
-
Questionable
- Unicode char literals
- Unicode escape sequences
< > " '
- whitespace:
\s \t \r \n
etc #
used for URL fragments%
used for encoding
-
Likely operators to be added to pattern syntax: union mega-sep mega-glob list of alternatives not
NB: general idea is to decouple named captures from wildcard/globstar operators
// NB: syntax highlighting would make any of these more acceptable. Write a vscode extension?
var routes = {
// The basic pattern with no captures
'/employees/*/bank-accts/*': staticFiles('path'),
// 'capture' operator, both as prefix and postfix, using various delimiters: <>, {}, ::, "", [], __
// prefix: clearly states that we are naming the next thing, esp if 'the next thing' is long
// postfix: keeps emphasis on the pattern, names are appended and sorta de-emphasised
'/employees/<empId>*/bank-accts/<acctId>*': staticFiles('path'),
'/employees/*<empId>/bank-accts/*<acctId>': staticFiles('path'),
'/employees/{empId}*/bank-accts/{acctId}*': staticFiles('path'),
'/employees/*{empId}/bank-accts/*{acctId}': staticFiles('path'),
'/employees/:empId:*/bank-accts/:acctId:*': staticFiles('path'),
'/employees/*:empId:/bank-accts/*:acctId:': staticFiles('path'),
'/employees/"empId"*/bank-accts/"acctId"*': staticFiles('path'),
'/employees/*"empId"/bank-accts/*"acctId"': staticFiles('path'),
'/employees/[empId]*/bank-accts/[acctId]*': staticFiles('path'),
'/employees/*[empId]/bank-accts/*[acctId]': staticFiles('path'),
'/employees/_empId_*/bank-accts/_acctId_*': staticFiles('path'),
'/employees/*_empId_/bank-accts/*_acctId_': staticFiles('path'),
// better or worse to allow non-significant whitespace?
'/ employees / *<empId> / bank-accts / *<acctId>': staticFiles('path'),
'/ employees / empId:* / bank-accts / acctId:*': staticFiles('path'),
'/ employees / *:empId / bank-accts / *:acctId': staticFiles('path'),
'/employees/ *:empId /bank-accts/ *:acctId': staticFiles('path'),
'/employees/ (*:empId) /bank-accts/ (*:acctId)': staticFiles('path'),
// 'capture' operator with implicit closing delimiter
'/employees/(*:empId)/bank-accts/(*:acctId)': staticFiles('path'), // ends because of closing parens
'/employees/*:empId/bank-accts/*:acctId': staticFiles('path'), // ends after last alphanum (ie, the next '/')
// Same ideas, different pattern...
'/(c*t)<word>': staticFiles('path'), // postfix with both delimiters...
'/(c*t){word}': staticFiles('path'),
'/(c*t):word:': staticFiles('path'),
'/(c*t)"word"': staticFiles('path'),
'/(c*t)[word]': staticFiles('path'),
'/(c*t):word': staticFiles('path'), // fine, unambiguous - : matches single preceding thing
'/(c*t:word)': staticFiles('path'), // sorta ok, but need rules about how much of preceding thing gets captured
'/c*t:word': staticFiles('path'), // as above, but less clear: Would the '/' be captured or not? Intuition: no it wouldn't.
'/word:(c*t)': staticFiles('path'), // prefix instead...
'/(word:c*t)': staticFiles('path'),
'/word:c*t': staticFiles('path'),
'/[word]c*t': staticFiles('path'),
// Positional captures - no names here - they should be documented elsewhere (but then they might get out of sync with predicate)
'/employees/{*}/bank-accts/{*}': staticFiles('path'),
'/{c*t}': staticFiles('path'),
'/employees/[*]/bank-accts/[*]': staticFiles('path'),
'/[c*t]': staticFiles('path'),
'/employees/*^1/bank-accts/*^2': staticFiles('path'),
'/(c*t)^1': staticFiles('path'),
'/employees/*¹/bank-accts/*²': staticFiles('path'),
'/(c*t)¹': staticFiles('path'),
'/employees/*ᵉᵐᵖⁱᵈ/bank-accts/*ᵃᶜᶜᵗⁱᵈ': staticFiles('path'), // fun fact: all latin letters except 'q' have lowercase superscript forms in unicode.
'/(c*t)ʷᵒʳᵈ': staticFiles('path'),
}
-
EulerDiagram
-->Taxonomy
-
EulerSet
-->Taxon
-
predicate
-->pattern
- minimal doc comments / cleanup in ED
- surface
unreachable
in mm creation options - support
|
alternation operator in predicates- refactor predicate code:
-
dsl-parser.ts
/parsePredicateString
- no longer exported
- just checks the source string; doesn't work out identifier parts or captures
-
toPredicate
- parses the source just to ensure it is valid; casts it toPredicate
without modification -
toNormalPredicate
- assumes a valid predicate; applies normalisation transforms -
toIdentifierParts
- assumes a valid predicate; normalises and applies identifier transforms -
toMatchFunction
- assumes a valid predicate; works outcaptures
/captureNames
as an internal function -
hasNamedCaptures
- assumes a valid predicate and returns a boolean
-
- update parsing/normalisation logic
- overlapping and disjoint alternatives are allowed; in normal form they are arranged in lexicographic order
- subset/superset alternatives - the subset is removed in the normal form
-
intersect
already does subset removal and lexicographical ordering - factor this out into one place
- reinstate
∅
to mean the predicate that matches no strings (not even the empty string)- add grammar/parser support
- ensure handled properly everywhere in
set-theory/predicates
) - ensure handled properly everywhere in
set-theory/sets
) - while we are at it, rename
ANY
toALL
- add/fix tests
- update
EulerDiagram
- use new
intersect
- fix broken tests
- handle
∅
among predicates
- use new
- fix broken tests
- extend
intersect()
- return an alternation predicate instead of an array of predicates
- handle
∅
predicate as input
- enforce current restrictions:
- a predicate cannot have both alternation and named captures
- alternatives within a predicate must be mutually-disjoint
- in a normalised predicate, alternatives are arranged in lexicographical order using
Array#sort
default cmpr
- extend peg grammar
- extend AST
- extend
toMatchFunction()
- one regex per alternative
- refactor predicate code:
- more predicate tests:
- parsing a predicate string
- alternation with
∅
not currently allowed - overlapping alternations
- subset/superset alternations
- alternation with
- matching a predicate against a string
- overlapping alternations
- subset/superset alternations
- intersecting two predicates
- disjoint alternations
- overlapping alternations
- subset/superset alternations
- comparing a predicate with its normal form
- rename this test?
- [-] overlapping alternations
- subset/superset alternations
- constructing a predicate instance
- remove this file; subsume under 'parsing a predicate string'
- parsing a predicate string
- implement
async: false
option properly, with tests- assert method result is not promise-like in thunks (strict mode)
- document strict vs non-strict behaviour (extra checks vs trusts you to conform to options you specified)
- add tests
- implement
async: true
option properly, with tests- assert method result is promise-like in thunks (strict mode)
- assert that method does not synchronously throw
- document strict vs non-strict behaviour (extra checks vs trusts you to conform to options you specified)
- document reliance on global
Promise.resolve(...)
when{strict: true, async: true}
and a method throws - add tests
- use
Ɱ0
,Ɱ1
, etc for mm funcion names - support more special characters in predicates
- switch globstar from
...
/…
to**
/ᕯ
- don't allow
ᕯ
in Predicate or NormalPredicate (use**
). It should only appear inidentifier
- ensure predicate chars are whitelisted, not blacklisted, to avoid potential regex exploits
- add support initially for:
:<>
- remove all refs to
∅
in codebase and tests and mds
- switch globstar from
- add a good default implementation for
toDiscriminant
- fix buggy emit for isMatch and getCaptures lines (see comment there in code)
- tidy up the method/dispatcher instrumentation code
-
multimethods.min.js
: test that the bundle actually works the same in a browser - ensure UMD file is working in Chrome, Firefox and Edge
- override mm's
toString()
to give mm source code, and remove EMIT debug logging - build system: use webpack to create a UMD file of the library (eg so can use in browser)
- get it working
- minify the bundle
- rename dist dirs:
release
-->commonjs
,bundle
-->umd
- do all in single build step (fix npm scripts)
- build system: integrate tslint
- TODO: revise codegen
- move all
isMatch
,getCaptures
, andcallHandler
vars to one place at the end of emit - fix dispatchFunction (see TODOs on lines 56-57 of
generate-dispatch-function.ts
) - always output codegen in debug mode
- investigate: can it be made more understandable/idiomatic?
- remove unnecessary .toStrings on predicates (which are simply strings at runtime, but tagged at compile-time)
- investigate: can the source 'stitching together' be made more template-like?
- move all
- do proper emit for the dispatch function - currently it is hardcoded to unary arity.
- put it through same emit steps as executor template function
- make a templates dir and put templates in there?
- add option
strictChecks: boolean
- add note for future addition: this option may be expanded to allow for specific strict checks
- current uses of
util.warn
become errors iff strictChecks is true, else no error/warning issued. - remove all
warn
-related stuff from codebase
- add an
fatalError.ts
file listing all possible errors with a short code and a description with {0} holes- use these codes when throwing errors (via helper)
- improve the 'MM contains conflicts' error message. i.e., what does it mean? How to fix it?
- MM has no catch-all handler, so some calls may no be dispatchable. To resolve this problem, define a handler for the predicate '...'
- MM has ambiguities, so some calls may not be dispatchable. To resolve this problem, define handlers for the predicates(s) ${...}
- split unit tests from perf work.
- perf moves to
/extras/bench
, call withnpm run bench
- simplify under dirs
/test
- perf moves to
- emit to
/dist/release
,/dist/test
,/dist/extras
- Ensure runtime support for ES5 envs without perf loss
- remove
emitES5
option - Don't use ES6 libs in
/src
(but can use them in/test
and/extras
) - Downlevel ES6 language features
/src
(but not in/test
and/extras
) - Ensure 'templates' contain no ES6 to begin with, to avoid surprise behaviour with 'macro' subtitutions
- carefully audit all generated code for possible ES6 usage:
- arrow functions
- rest/spread
- ES6 runtime - Promise, Symbol, string functions, etc
- other - check&whitelist every line to rule out anything missed above
- EXCEPTIONS (supported even in IE11):
- let/const
- Map & Set basic usage
- Object.setPrototypeOf
- carefully audit all generated code for possible ES6 usage:
- ensure benchmarks have not suffered
- remove
- UNHANDLED --> FALLBACK
- export the default FALLBACK sentinel value
- replace refs everywhere
- fix 'unhandled' option
- explain in README what FALLBACK sentinel means (imperative, not declarative)
- what happens when last handler returns FALLBACK?
- FALLBACK should not be observable to clients; it is an internal dispatch imperative
- throw an unhandled dispatch error (new case in
fatalErrors.ts
)
- TODO: Helper(s) to compose handlers manually
- permit listing regular handlers in an array ('chain')
- permit listing metahandlers in an array ('chain')
- permit mixing metahandlers and regular handlers in an array ('chain')
- implement special ordering laws and validate them
- ambiguity is now an error - there is no tieBreak fn (apart from metarule vs rule)
- remove all references to
tiebreak
andmoreSpecific
function in code/comments - simplify code that previously used tiebreak stuff, if/where possible
- remove all references to
- remove predicate comment support - they were not really 'comments' since they affected semantics
- enforce 'meta-handlers before regular-handlers in chains' convention. Early error if not.
- explain in docs that this simplifies reading of chains as having left-to-right execution order
- revise FALLBACK
- change to CONTINUE
- don't allow overriding; remove from MMOptions (check this will work with routist first)
- add
debug
logging using thedebug
module- replaces
trace
option. Remove that. - use npm
debug
module to sent all debug/trace messages- why not events? ANS: They are node.js-specific.
- remove 'trace' code from executor function; replace with wrapper functions on all handlers when in debug mode
- turn
strictChecks
checks into debug warnings and removestrictChecks
option
- replaces
- export a
validate(mm): void
function that does strict checking and throws a list of errors on failure- remove the
strictChecks
option - move what were the strict checks into the validate function
- remove the
- SKIPPED: Use/support ES6
class
syntax for defining multimethods- SKIPPED: MM = static class, you call the constructor, not an instance
- SKIPPED: prevent instantiation
- SKIPPED: allow calling the class ctor like a function (no
new
)- is this even permitted with ES6 classes? Ans: NO
- SKIPPED: MM = static class, you call the constructor, not an instance
- switch stricter tsconfig flags back on (eg strictNullChecks, noImplicitAny)
- Do some V8 profiling/analysis. list possible optimisations.
- indexOf (in make-match-method.js) takes ~30% of time - try rewriting
- the (unoptimizable) generator function housing the perf test loop takes ~20% of time (remove it)
- [-] do try this --> splitting selector function into multiple small functions (one per non-leaf node in taxonomy)
- others?
- official logo - cactus in yellow box. c.f. 'JS' and 'then' logos
- enfore max line length <= 120 chars
- get whole lib working in ES5 mode (currently there are runtime errors due to reliance on ES6 runtime features in source)
- rename Pattern (class/type) to Predicate, and patternSource (arg/var) to pattern
- update all affected file/folder names
- update all affected names of exports/imports/vars/functions
- update all references in comments
- update all tests including test names
- predicates: divide evaluation into two methods ('evaluate' and 'capture')?
- use arrow functions in executor template then downlevel them.
- arrange all src/multimethod files & exports more nicely
- [-] rename 'route' in WithRoute to 'matchedRules'
- ensure codegen uses no ES6 features when emitES5 option is set
- arrow functions
- let/const
- rest/spread
- builtins
- other?
- provide a default UNHANDLED value in the library.
- [-] Users can optionally override it in MM options
- replace all void 0 with undefined
- README - remove TODO lists into separate files (or into github issue(s)?)
- Multimethod: conflicts... (tiebreak / disambiguate / ambiguity)
- Multimethod: getDiscriminant --> toDiscriminant
- Multimethod: address --> discriminant
-
Multimethod: Rule --> Method - Multimethod: Rule#test --> Method#predicate
- Multimethod: support any/all arities
- remove global 'warnings' option - should be a per-multimethod option (or have both? local override + fallback to global)
- mockable log methods (warn, error) - unit tests can mock these
- Multimethod options
- specify fixed arity (0=variadic) - this is used to generate efficient calls via eval
- getDiscriminant is passed all args that are passed to Multimethod
- RuleSet: change to UNHANDLED sentinel value instead of null
- RuleSet: allow UNHANDLED value to be specified as an option
- transpile to /dist or /built directory and npmignore src/
- more pegjs to devDeps and make PEG compilation a build step
- change {...rest} to {**rest} / {…rest} for consistency?
- change ** to ...?
- rename Taxonomy --> TxonomyNode? Need to make clear each instance fundamentally represents a node, and a bunch of them form a graph
- decouple address from Request
- add Pattern#intersect, update all call sites (just make-taxonomy)
- create Taxonomy class and/or add /src/taxonomy/index.ts
- improve taxonomy test coverage
- asyncify Handler#execute
- still need
isPromise
? If not, remove it :( Otherwise find a use for it. - add npmignore
- use @types, remove typings