Last active
August 26, 2016 19:51
-
-
Save ciscoheat/6b95e09f851b28ea3db9dc87314cca9f to your computer and use it in GitHub Desktop.
Typesafe web routes with Haxe in less than 100 lines
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Code for this article: | |
// https://github.com/ciscoheat/mithril-hx/wiki/Typesafe-web-routes-with-Haxe-in-less-than-100-lines | |
#if macro | |
import haxe.Serializer; | |
import haxe.Unserializer; | |
import haxe.macro.Context; | |
import haxe.macro.Expr; | |
import sys.io.File; | |
using StringTools; | |
using Lambda; | |
private typedef RouteList = Array<Array<String>>; | |
private typedef RouteCalls = Map<{min: Int, max: Int, file: String}, Array<String>>; | |
#end | |
class Routes | |
{ | |
#if macro | |
static var isInit = false; | |
static var file = 'routes.txt'; | |
static var definedRoutes(default, null) : RouteList; | |
static var calledRoutes(default, null) : RouteCalls; | |
static function testCalledRoutes() { | |
// Load routes if they haven't been defined, else save the current routes | |
// this enables the class to work on both server and client. | |
if(definedRoutes.length == 0) | |
definedRoutes = cast Unserializer.run(File.getContent(file)); | |
else | |
File.saveContent(file, Serializer.run(definedRoutes)); | |
var joinedRoutes = definedRoutes.map(function(a) return a.join('/')); | |
for (pos in calledRoutes.keys()) { | |
var route = calledRoutes.get(pos); | |
var matched = joinedRoutes.has(route.join('/')); | |
if (!matched) | |
Context.error('Route not found', Context.makePosition(pos)); | |
} | |
} | |
static function init() { | |
isInit = true; | |
definedRoutes = new RouteList(); | |
calledRoutes = new RouteCalls(); | |
Context.onAfterGenerate(testCalledRoutes); | |
} | |
#end | |
macro public static function defineRoute(route : String) : Expr { | |
if (!isInit) init(); | |
var array = route.split('/'); | |
if (array[0].length == 0) array.shift(); | |
function mapRoute(a : Array<String>) { | |
definedRoutes.push(a.map(function(s) return s.startsWith(':') ? '' : s)); | |
} | |
mapRoute(array); | |
while (array.length > 0 && array[array.length - 1].endsWith('?')) { | |
array.pop(); | |
mapRoute(array); | |
} | |
return macro $v{route}; | |
} | |
macro public static function callRoute(values : Array<Expr>) : Expr { | |
if (!isInit) init(); | |
var route = values.map(function(e) return switch(e.expr) { | |
case EConst(CString(s)): s; | |
case _: ''; | |
}); | |
if (route[0].length == 0) route.shift(); | |
calledRoutes.set(Context.getPosInfos(Context.currentPos()), route); | |
return macro '/' + $a{values}.join('/'); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment