HomeDocumentation

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}