Skip to content

Latest commit

 

History

History
589 lines (538 loc) · 29.2 KB

TODO.md

File metadata and controls

589 lines (538 loc) · 29.2 KB

Todo - High Priority

  • use this to pass captures and next, then arity opt is just an optimisation
  • have a trust: boolean option instead of strict? Since it's more about whether methods are trusted to comply
  • decide: captures gets all matches, even anon ones as [0], [1], etc (like express req.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)

Todo - Medium Priority

  • rename Configuration to Settings? 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
  • 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)

Todo - Unassigned Priority

  • 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
  • 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
  • export a Multimethod type (or family thereof)
    • or not, it's just a straightforward function signature, nothing special added
  • address UnhandledPromiseRejectionWarning in test/**/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 no toDiscriminant given, the default toDiscriminant uses it
  • new option allowNulls - mms should reject null args unless this is explicitly set to true
  • 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 in fatal-error.ts

Audits to do:

  • consistent British English spelling
  • consistent code style & quality
  • functionality & test converage
  • perforance & benchmarks
  • all errors and warnings (eg validation, codegen, etc)

Notes on future support for pattern symbols/operators/literals

  • use URI ref: https://tools.ietf.org/html/rfc3986

  • TODO: char pool yet to classify:

    • unallocated: % ^ | $ ' " ( ) + , ; was: - [ ] URI reserved chars: : ? # [ ] @ ! $ & ' ( ) + , ; = - [ ] Others: % ^ ~ < > " |
  • 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
    • {...} / {**} 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) or my( )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: $ ;
  • 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
    • CONSIDER FUTURE SUPPORT - valid identifier chars:
      • \ U+3035

      • ? U+097D

      • U+A41A

        • U+1540
      • ! ǃ U+01C3

      • ^ U+18D4

      • ~ U+1C7B

      • ' ʼ U+02BC

      • " ˮ U+02EE

      • ˋ` U+02CB

      • % 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

Capturing syntax review ideas

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'),
}

Done

  • 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 to Predicate 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 out captures / 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 to ALL
      • add/fix tests
    • update EulerDiagram
      • use new intersect
      • fix broken tests
      • handle among predicates
    • 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
  • more predicate tests:
    • parsing a predicate string
      • alternation with not currently allowed
      • overlapping alternations
      • subset/superset alternations
    • 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'
  • 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 in identifier
    • 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
  • 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, and callHandler 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?
  • 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 with npm run bench
    • simplify under dirs /test
  • 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
    • ensure benchmarks have not suffered
  • 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 and moreSpecific function in code/comments
      • simplify code that previously used tiebreak stuff, if/where possible
    • 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 the debug 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 remove strictChecks option
  • 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
  • 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

Done (older)

  • 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