import { createMap } from "./util" ; export interface Delegate { contextEntered ? ( context , route ) : void ; willAddRoute ? ( context , route ) : string ; } export type Opaque = { } | void | null | undefined ; export interface Route { path : string ; handler : Opaque ; queryParams ? : string [ ] ; } export interface RouteRecognizer { delegate : Delegate | undefined ; add ( routes ) : void ; } export interface MatchCallback { ( match ) : void ; } export interface MatchDSL { ( path ) : ToDSL ; ( path , callback ) : void ; } export interface ToDSL { to ( name , callback ? ) : void ; } class Target implements ToDSL { path : string ; matcher : Matcher ; delegate : Delegate | undefined ; constructor ( path , matcher , delegate ) { this . path = path ; this . matcher = matcher ; this . delegate = delegate ; } to ( target , callback ) { let delegate = this . delegate ; if ( delegate && delegate . willAddRoute ) { target = delegate . willAddRoute ( this . matcher . target , target ) ; } this . matcher . add ( this . path , target ) ; if ( callback ) { if ( callback . length === 0 ) { throw new Error ( "You must have an argument in the function passed to `to`" ) ; } this . matcher . addChild ( this . path , target , callback , this . delegate ) ; } } } export class Matcher { routes : { [ path ] : string | undefined ; } ; children : { [ path ] : Matcher | undefined ; } ; target : string | undefined ; constructor ( target ? ) { this . routes = createMap < string > ( ) ; this . children = createMap < Matcher > ( ) ; this . target = target ; } add ( path , target ) { this . routes [ path ] = target ; } addChild ( path , target , callback , delegate ) { let matcher = new Matcher ( target ) ; this . children [ path ] = matcher ; let match = generateMatch ( path , matcher , delegate ) ; if ( delegate && delegate . contextEntered ) { delegate . contextEntered ( target , match ) ; } callback ( match ) ; } } function generateMatch ( startingPath , matcher , delegate ) { function match ( path ) ; function match ( path , callback ) ; function match ( path , callback ? ) { let fullPath = startingPath + path ; if ( callback ) { callback ( generateMatch ( fullPath , matcher , delegate ) ) ; } else { return new Target ( fullPath , matcher , delegate ) ; } } ; return match ; }