I’ve been doing quite a lot with Razor lately, namely still working on RazorEngine vNext, but also reading a lot of Andrew Nurse’s blog to understand what the Razor parser is doing under the hood.

Turns out, its an elegant synergy of two separate parsers, one which handles code, one which handles markup. The two parsers do a little dance, and the end result, is a series of code statements that write the content of your template/page/document to an output. This in turn is compiled into a class which is executed to obtain the end result.

Jazor (ahem), attempts to be a faithful implementation of the Razor syntax, but built purely in javascript. The general idea would be that you could declaratively use Razor syntax in your client side templates. Let’s have a quick look:

<script type="text/html" id="template01">
  <div>Hello @model.name, you are @model.getAge() year(s) old!</div>
</script>

Now, let’s breakdown how it works:

Synergistic ballet

Andrew aptly calls this “recursive ping-pong” (read his blog post here), its an elegant way of breaking down a text stream into a recursive set of calls to each parser. We start off at the very top level, and make an initial call to a markup parser; when the markup parser starts reading the content, it will do so until it reaches a valid transtion point, the “@” symbol (well, there is a little more to it than that, we have to take email address, and @@ escaping into consideration). Once a valid transition point is reached, the markup parser calls the code parser, which in turn attempts to read a code block (an expression, statement, etc.).

The way we do this with Jazor is we have our core object, the parser which wraps a codeParser and a markupParser. The parser makes a call to the markupParser to start reading the content. and the recursive little dance begins.

Generating code

Much like Razor, we start generating blocks of code which we will reassemble as part of our template execution. If we take our above example, Jazor will generate a literal block, followed by an expression, then a literal, another expression, and then a final literal, so:

"n <div>Hello "
model.name
", you are "
model.getAge()
" year(s) old!</div>n "

We need to transform this series of blocks into something runnable, thankfully, there is eval.

Return of eval

After we’ve done generating our template blocks, we assembly them back together as a function, which we can then eval, and run. We do this by writing the code that wraps the blocks. For the above example, the code we generate would look something like:

(function(model) {
    var r = []; 
    r.push("n <div>Hello "); 
    r.push(model.name); 
    r.push(", you are "); 
    r.push(model.getAge()); 
    r.push(" year(s) old!</div>n "); 
    return r.join(""); 
});

I’ve prettified the code for readability, but essentially we are writing a custom method, and then we evaluate that as a function object, which can be executed directly:

    var func = eval(tmp); // Where tmp is our generated function code.

Executing templates

You can start running templates using the global jazor object:

    var model = {
        name: "Matt",
        getAge: function() { return 27; }
    };
    var result = jazor.parse("Hello @model.name", model);

Alternatively, if you are using jQuery, you can use the $.fn.jazor method on your query object:

    var result = $("#template01").jazor(model);

What does Jazor support

In this initial 0.1.0, it is really just a preview, very much unfinished. Currently we have support for most Razor syntaxes, so we have:

Expressions

    @model.name

Code Blocks

    @{
        var name = "Matt";
    }

Explicit Expressions

    @(model.name)

Line parsing

    @: Hello World

if, for, with, while

    @for (var i in model) {
        Current: @i
    }

And we also have support for helper methods, e.g.:

    @helper writeAge(age) {
        <span>@age</span>
    }
    Hello @model.name, you are @writeAge(model.getAge()) year(s) old!

Helper methods are transformed into internal functions of our template function. E.g, the above would be transformed into:

(function(model) {
  function writeAge(age) {
    var hr = [];
    hr.push("n    <span>");
    hr.push(age);
    hr.push("</span>n");
    return hr.join("");
  }
  // etc....
});

This allows us to declaratively define template functions, just as Razor allows.

What’s missing

There is still quite a bit of work to do, bugs to iron out, one big glaring omission currently is support for else/else if statements, and the parser doesn’t really obey xml markup just yet, but for an initial release, I’m hoping its enough to get people interested. I’ll push it to github soon so you can start forking and hopefully get involved!

The script file is attached, remember, its an early work in progress! Let me know what you think :-)

jazor-dev.0.1.0.js

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)