@vlr/razor
v2.0.4
Published
Second order generator, made for generation of source code in TS/JS/CS languages
Downloads
5
Readme
@vlr/razor
Template engine, implemented as second order generator, i.e. generator of generators.
Usually template engines work by following formula:
const Output = F(template, data);
Given that one template is most of the time used with a lot of data objects, this function can be transformed into one-argument function by partial application. Like this:
// this is a function that takes two-argument function
// and returns partially applied one-argument function
const partial = (F, template) => { return (data) => F(template, data); }
// partially applied function is "cached" in variable
const Fpartial = partial(F, template);
// same result as in first example
Output1 = Fpartial(data1);
Output2 = Fpartial(data2);
Then, usually template engines are offering to do sort of precompilation instead of partially applied function. This gives a bit of optimization to the process.
And Razor, instead of precompilation, generates a code that would concatenate strings to produce an output, i.e. will work as first-order code generator.
Hence the definition - razor is a second order generator.
Terminology
This library, template engine or second-order generator, is called "razor" throughout this readme.
Output of razor's work, i.e. first order generator is called "generator".
Output of generator's work will simply be called an "output".
Usage and Options
Razor is designed to be used as a transformation function that transforms one string into another string. Template into source code of generator. Simplest way to use it is within gulp task, along with gulp-transform plugin, or any other plugin of choice
import { transform } from "@vlr/gulp-transform";
import { generate } from "@vlr/razor";
export function runRazor(): NodeJS.ReadWriteStream {
const src = "./" + settings.src;
const razorFiles = src + "/**/*.rzr";
return gulp.src(razorFiles)
.pipe(transform(file => (
{
...file,
contents: generate(file.contents),
extension: ".ts"
})))
.pipe(gulp.dest(src));
}
Razor options
3 options can be specified to razor.
const options = {
quotes: "\"", // or "'"
linefeed: "\n", // or "\r\n", "\r",
language: "ts" // or "js", "cs"
}
Quotes is the character to be used when generator imports from the export part of the razor library.
Language is the programming language in which source code of generator will be made. C-sharp will not be supported in first release. Default is ts.
Linefeed is the symbol to be used in source code of generator. Default is unix linefeed.
Generator options
2 options can be specified to generator.
const options = {
quotes: "\"", // or "'"
linefeed: "\n", // or "\r\n", "\r"
}
Linefeed is the symbol to be printed to output.
Quotes is the symbol to be printed to output in place of all unescaped quotes and apostrophes. If this option is not provided, output will contain the symbol from the template.
Key symbol and escapes
Razor uses "@" or "at" symbol as key symbol as it is amongst the most rarely used symbols in source code.
Also it is used as an escape symbol paired like this:
@} - output will contain } at that position
@" - output will contain " at that position, regardless of "quotes" option
@' - the same as previous, but with apostrophe
Configuration
There are 2 configurations that can only be provided at the start of the template.
@import { MyData } from "./myFile"
@define myEntity(data: MyData)
First will be put into generator as is.
Second is a definition of generator function. "Options" parameter will be added trailing your parameters.
Generator is then to be called like that
const output = myEntity.generate(data, options);
If definition is not provided, then default "generator" name will be used
Razor mnemonics
Expression
// template
public class @data.name { }
// output, given that data.name contained word "MyClass"
public class MyClass { }
Explicit expression
Sometimes part of the word needs to be specified
// template
public class My@(data.name)Class { }
// output, guess what data.name contains
public class MyWonderfulClass { }
Injection
This is useful for adding some manual code to generator.
// template
@{ const employee = data.employee; }
console.log("@employee.name @employee.age");
// output
console.log("Peter 20");
Conditional clause
Depending on contents of data object, insides will appear in output or not.
// template
console.log(@if(data.enoughExperience) {"SeniorDev"} else {"Junior"});
// alternative template
@if(data.enoughExperience){
console.log("SeniorDev");
} else {
console.log("Junior");
}
Enumeration clause
Produces one line of the output per enumerated item.
// template
@for(let item in data.items){
console.log("@item.name");
}
// output
console.log("item1");
console.log("item2");
Escaped brace
If you need to produce a brace inside enumeration or conditional clauses.
// template
@for(let item in data.items){
for(let user of users){
console.log("@item.name");
@}
}
// output
for(let user of users){
console.log("item1");
}
for(let user of users){
console.log("item2");
}
Cascading
When you have 2 generators, there is an operator to call one from another, this will also support indentation, unlike using it as expression
// template1
@define t1(item)
console.log("@item.name 1");
console.log("@item.name 2");
// template2
// notice long indent here
@import { t1 } from "./template1"
@for(let item of data.items){
@[t1(item)]
}
// output
console.log("item1 1");
console.log("item1 2");
console.log("item2 1");
console.log("item2 2");