Language

This integration test describes the full capabilities of the language in detail.

{namespace my.app.namespace}#Namespace##Template files begin with a namespace and end with a .xjs extension.##If you instantiate the compiler with global=>true (default), then#you can call window.my.app.namespace in a browser, or in the global scope#of where your template is executed. You can optionally set global=>false, in#this case, X would return an object, and the namespaces would be assigned to#said object.##Whitespace isn't allowed before a namespace declaration. The idea is to enforce#A coding style.#Comments##This is a comment. Comments in X borrow from shell scripting.#Import##You may use imports to combine other template files. When you import another#file, all of the templates in that file are added to the resulting namespace#specified by the compiler options (global namespace or a newly returned#namespace object). None of the variables defined in an imported file are#available in an importing file.##You can specify a relative path I.E. ../../file.xjs, or an absolute path I.E.#/file.xjs. This example is using relative path. Relative paths are always#relative to the document declaring the import statement, so profile_sample.xjs#is a sibling file in the parent directory of the current file.{import profile_sample.xjs}#GlobalVariable##This is a global variable. Only templates within this file have access to it.{var boo 5}#VariableAssignment##Variables don't need to have an assigned value. Variables may only be#initialized. Compile time errors will occur if a reference is found to a#variable that hasn't been declared, or if an attempt is made to declare a#variable more than once. Variables without a value are undefined.{var zamboni}#undefined value FOREVER!#Referencing Variables##Variables must be declared before they may be referenced. Now that we've#declared 'boo', it can be referenced. References begin with the '@' symbol.{var zoo @boo}#GlobalVariable Types##Global variables, unlike variables that appear within a template, are limited#to the following types and expressions:#numbers{var coo 1}{var cooo 0x4a09}{var coooo 1.345}{var coooo9 1.345e-1234}#strings{var doo 'string'}{var dooo "string"}#null, and booleans{var woo null}{var eooo true}{var eoooo false}#expressions#X allows most ECMAScript operators to appear in expression statements. The#value of any variable may be derived form a short-circuited expression.#The following is a valid expression:{var wooo 1 ||
(typeof 2 === 'number' && ~~3 && !@woo) &&
#comments ending with \n are#considered white space everywhere!!!
(((('nested parens'||'not nested'))))#etc.}#Can you guess what the value of @wooo is now?#Operators##The following operators (separated by space), are directly output to the#compiled result. The precedence is exactly what it is in ECMAScript, and is#not given in any intentional order herein:##Logical:#== === != !== || && < <= > >=##Mathmatical:#+ - % * /##Unary:#typeof !!! ~~~##Parenthetical:#(((expression)))##Templates##You may define as many templates as you wish within a file. Templates are#assigned to the namespace declared in their file. Templates end up as methods#within their namespace, so in the case of wow (assuming the namespace is#applied globally, you would call it like this:#my.app.namespace.wow(data, params);{template wow}{/template}#As you can see, wow doesn't do very much. wow2 prints: Hello!{template wow2}
Hello!
{/template}#ContextSelector##When calling templates, the first parameter is the data, or context with which#the template uses for processing. Here are some valid context selectors:#{template contextSelectorTest}##Property Selectors#Property Selectors follow the same naming conventions that exist in#ECMAScript E.G. /[a-zA-Z_$][a-zA-Z_$0-9]*/. You may select any property by name#like this:{Tables}##To drill down:{tables.first.name}##If a property name is a reserved word or contains invalid characters, you may#use dynamic refinement like this:{['table-inventory']}##To driill down:{['table-inventory']['count']}##Mixing static and dynamic refinement:{tables['table-inventory'].first[0+4]}##Any valid expression is allowable inside dynamic refinement. The following is#perfectly valid:{tables[^encodeURIComponent('/////').replace('%2F', '')][@woo||2&&3===(3-5)]}##Current Context#The context at the template level is always the first argument do the template.#You can directly access the current context using one of the following#selectors:{.}{current()}##Global Context#Use the caret symbol to access global variables and functions. This makes#templates extremely flexible, and permits helpers to be accessed from any#template without a registration mechanism. Please give feedback on this#approach. Referencing globals is generally a bad practive, but to avoid#verbosity it is allowed.#Example:{^Date.now()}#print the current timestamp.##Functions. The following functions are built-ins and are reserved. Some of#them really only take on meaning inside foreach statements.##count(contextSelector)#Returns the number of items in an array or properties in an object.{count(.)}##name()#Outputs the name of the current item in a foreach loop. This may be a#number if iterating over an array, or a string if iterating over an object.{name()}##position()#Outputs the current index in the foreach loop. This may be random#when looping over properties in an object.{position()}##last()#Returns the highest possible index in the current iteration in a foreach#statement.{last()}#:P{/template}#Params##When calling templates, the second parameter represents the params you wish to#make available to your templates. In order to access params, you must declare#them at the top of your templates. Param values are the same as any other#template variable.{template params}{param foo}{param too 5}#if too isn't supplied, then the default is number 5.{/template}#Variables##Variables and Params within a template inherit the same rules that Global#Variables follow, and additionally allow context selectors.{template vars}{var foo1 .}{var foo2 ['5']}{/template}#Helpers##You can directly call any VariableReference, or ContextSelector in the same#way you would normal javascript methods / functions. I.E. @boo(5,4) &&#property.name[0](). See ContextSelector for an example of calling global#references I.E. {^call.my.helper()}#PrintStatement##To directly print the same type of values allowed for variables, you can wrap#the value in curly braces. Doing so outputs the value.##You can optionally modify the output with PrintModifiers. Valid PrintModifiers#are:#e: Disables XSS escaping.#E: Enables XSS escaping.{template print}{var greeting 'Top of the morning to ya!'}{@greeting}#output the value of greeting.{hello}#output the value of hello in the current context.{hello || hola}#If hello is falsey, output the value of hola.{^Date.now()}#Print the current timestamp. See ContextSelector#Example of PrintModifiers{hello |e}#disable XSS escaping{hello |E}#enable XSS escaping{/template}#InputTokens##Any value between } and { in a template will be output. Certain values must#be escaped with the '\' character. The following characters need to be escaped#as input tokens: # and {. An unescaped '#' results in a comment that is#considered to be space. An unescaped '{' that does not appear as a valid#opening tag results in a compile time error.{template inputTokens}
<h1>A header</h1>
#Escaped comment.
{
{/template}#If##If statements allow for control flow within a template. To facilitate else if,#and else, continuation statements of the form {:elif} and {:else} are used.#Note that {:elif} and {:else} are optional.{template IF}{if someValue}#Do something{:elif anotherValue}#Do something else{:elif anotherValue||anyExpression}#Do something else yet again.{:else}#Otherwise{/if}{/template}#Foreach##You can loop over arrays and objects using foreach. Foreach establishes a new#context, so the item you iterate over becomes the new value of '.' and#'current()'.{template foreach}{foreach person}{age}{/foreach}{/template}#Sort##Must appear as the first statement within a foreach. Sorting items does NOT#affect the original object. You can sort on any context selector to control#the ordering of items. The sort algorithm used (for ascending and descending#sorts), is guaranteed to preserve an item's index while sorting.##The following types of sort are allowed:#asc desc rand##The following sort modifiers may be applied to "asc" and "desc":##i Makes the sort case-insensitive.#c Shifts lowercase items leftward where possible.#C Shifts uppercase items leftward where possible.#n Shifts numbers leftward.#{template sort}{foreach person}{sort hobbies.favorite |asc}{/foreach}{foreach person}#This sort statement does the following:##1. Sort persons by their favorite hobby#2. Hobbies are sorted case insensitively ascendingly.#3. Uppercase hobbies are then promoted upward.{sort hobbies.favorite |asc|iC}
My name is: {name()}{/foreach}{foreach person}#multiple sorts allowed!{sort hobbies.favorite |asc}{sort hobbies.name |desc}
Show all of me: {.}{/foreach}{/template}#Text##To avoid excessive escaping on InputTokens, you can use the text statement.{template text}{text}
'
#'{{/text}{/template}#Log##Use console.log under the hood. By default logs are removed. You must#configure the compiler accordingly if you wish to use log statements.{template log}{log 5}{/template}#Render##To render a template within the current namespace, do this:{template renderTemplateFromSameNamespace}#partial is declared below{render partial/}{/template}##You can render any template defined in an imported file, or the#current file. If the imported file defines a namespace different than the#importing file, then you must use the full path to the namespace I.E.{template renderTemplateFromAnImportedFileWithADifferentNamespace}{render sample.buildProfile/}{/template}##otherwise you can supply the short form for any template defined in the current#namespace. Compile time checking will insure that the desired template has#been declared.##To set the context, declare a second argument in the render statement I.E.{template setContextOnRenderExample}#This changes the context of partial to "fred"{render partial fred/}.
{/template}##Prints: I'm a partial5 when rendered from renderPartial.{template partial}{param foo}
I'm a partial{@foo}.
{/template}##You can also pass params to other templates, in addition to changing the#context with the render statement.{template renderPartial}{render partial/}{render partial}{param foo 5}{/render}{/template}