Advanced General-Purpose Preprocessor
🐝 Direct includes from Github (versioned) and URLs
🐧 Flexible syntax (macros, loops, expressions, etc.)
🍄 Asset filters (escape, base64, custom)
🐠 Automatic un-indentation of nested blocks
🐥 Line control statements generation
🐸 Available as cli or as npm library
🐼 Extensible and embeddable via JS API
[![Build Status](https://travis-ci.org/myurasov/Pre.svg?branch=develop)](https://travis-ci.org/myurasov/Pre)
Directives start with @
symbol.
@set <variable:identifier> <value:expression>
@set <variable:identifier> = <value:expression>
Assigns a value of an expression to a variable.
Variables are defined in a global context.
Example:
Sets SOMEVAR
to 1:
@set SOMEVAR min(1, 2, 3)
@macro <name>(<arguments>) <body> @endmacro
@endmacro
can be replaced with @end
.
Defines a code region that can take it's own parameters. Macros are declared in a global scope. Macro parameters are only available within the macro scope and override global variables with the same name (but do not affect them).
Macros can be used:
-
via
@include
directive:@include macro(a, b, c)
-
inline:
@{macro(a, b, c)}
When macros are used inline:
- no line control statements are generated for the output inside the macro scope
- trailing newline is trimmed from macro output
Examples:
@macro some_macro(a, b, c) Hello, @{a}! Roses are @{b}, And violets are @{defined(c) ? c : "of undefined color"}. @end
Then some_macro
can be used as:
@include some_macro("username", "red")
which will produce:
Hello, username!
Roses are red,
And violets are of undefined color.
The same macro used inline:
[[[ @{some_macro("username", "red", "blue")} ]]]
will ouput:
[[[ Hello, username!
Roses are red,
And violets are blue. ]]]
Includes local file, external source or a macro.
@include <source:expression>
@include some_macro("username", 123)
@include "somefile.ext"
@include "http://example.com/file.ext"
@include "https://example.com/file.ext"
@include "github:<user>/<repo>/<path>[@<ref>]"
Where:
-
user
– user/organization name -
repo
– repository name -
ref
– git reference (branch name or tag, defaults to master)
Examples:
-
Head of the default branch
@include "github:electricimp/Promise/Promise.class.nut"
-
Head of the develop branch
@include "github:electricimp/Promise/Promise.class.nut@develop"
-
Tag v2.0.0:
@include "github:electricimp/Promise/Promise.class.nut@v2.0.0"
When using GitHub includes, authentication is optional, however:
- with authentication GitHub API provides much higher rate limits
- to access private repositories authentication is required
Apart from GitHub username you need to provide either a personal access token or password (which is less secure and not recommended). More info on how to provide those parameters is in usage section.
@include once <source:expression>
Acts the same as @include
but has no effect if source has already been included.
Macros are always included.
@{<expression>}
@{macro(a, b, c)}
Inserts the value of the enclosed expression or executes a macro.
Example:
@set name "Someone" Hello, @{name}, the result is: @{123 * 456}.
results in the following output:
Hello, Someone, the result is: 56088.
While-loop. loop variable is available in @while
loops.
@while <test:expression> // 0-based iteration counter: @{loop.index} // 1-based iteration counter: @{loop.iteration} @endwhile
@endwhile
can be replaced with @end
.
Loop that repeats a certain number of iterations. loop variable is available in @repeat
loops.
@repeat <times:expression> // 0-based iteration counter: @{loop.index} // 1-based iteration counter: @{loop.iteration} @endrepeat
@endrepeat
can be replaced with @end
.
Example:
@repeat 3 loop.iteration: @{loop.iteration} @end
outputs:
loop.iteration: 1
loop.iteration: 2
loop.iteration: 3
Conditional directive.
@if // consequent code @elseif <test:expression> // else if #1 code // ...more elseifs... @else // alternate code @endif
@endif
can be replaced with @end
.
Example:
@if __FILE__ == 'abc.ext' // include something @elseif __FILE__ == 'def.ext' // include something else @else // something completely different @endif
@error <message:expression>
Emits an error.
Example:
@if PLATFORM == "platform1" // platform 1 code @elseif PLATFORM == "platform2" // platform 2 code @elseif PLATFORM == "platform3" // platform 3 code @else @error "Platform is " + PLATFORM + " is unsupported" @endif
"Filter" |
operator allows to pass a value through any of supported functions.
@{<expression> | <filter>}
which is equivalent to:
@{<filter>(<expression>)}
Example:
// include external HTML to a string a = "@{include('index.html')|escape}" // include external binary file to a base64-encoded string b = "@{include('file.bin')|base64}"
Directives that have parameters allow usage of expression syntax.
For example:
@include <source:expression>
@set <variable:identifier> <value:expression>
@if <condition:expression>
@elseif <condition:expression>
-
@{<expression>}
(inline expressions)
The following types are supported in expressions:
-
numbers (eg:
1
,1E6
,1e-6
,1.567
) -
strings (eg:
"abc"
,'abc'
) null
true
false
Binary
|| && == != < > <= >= + - * / %
Unary
+ - !
somevar.member
somevar["member"]
([1, 2, 3])[1]
test ? consequent : alternate
- Variables defined by
@set
statements are available in expressions. - Undefined variables are evaluated as
null
. - Variable names can contain
$
,_
, latin letters and digits and can start only with a non-digit.
Line number (relative to the file in which this variable appears).
Example:
Hi from line @{__LINE__}!
Name of the file in which this variable appears.
Example:
Hi from file @{__FILE__}!
Absolute path (not including file name) to the file where this variable appears. Contains url for remote includes.
Example:
Hi from file @{__PATH__}!
Defined inside @while
and @repeat
loops.
Contains information about the current loop:
-
loop.index
– 0-indexed iteration counter -
loop.iteration
– 1-indexed iteration counter
Example:
@set myvar = 12 @while myvar > 9 @set myvar = myvar - 1 var: @{myvar} loop.index: @{loop.index} @end
outputs:
myvar: 11
loop.index: 0
myvar: 10
loop.index: 1
myvar: 9
loop.index: 2
-
defined(<variable_name>)
– returnstrue
if a variable is defined,false
otherwise. -
include(<source>)
– includes external source -
escape(<value>)
– escapes special characters in string (\b
,\f
,\n
,\r
,\t
,\
,'
,"
) -
base64(<value>)
– encodes value as base64 min(<numbers>)
max(<numbers>)
abs(<number>)
Lines starting with @
followed by space or a line break are treated as comments and not added to the output.
Example:
@ something about platform #1 @set PLATFORM "platform1"
Please note that Pre requires Node.js 4.0 and above.
-
As npm library:
npm i --save Pre
then
const Pre = require('Pre'); const pre = new Pre(); // (optional) provide GitHub credentials pre.machine.readers.github.username = "<usename>"; pre.machine.readers.github.token = "<personal access token>"; const output = pre.machine.execute(`@include "${inputFile}"`);
-
As CLI:
Pre provides
prprcss
command when installed globally:npm i -g Pre pre [-D<variable> <value>...] [-l] [--github-user <usename> --github-token <token>] [-l] <input_file>
where:
-
-l
– generate line control statements -
-D<variable> <value>
– define a variable -
--github-user
– GitHub username -
--github-token
– GitHub personal access token or password (not recommended)
-
SPEC_LOGLEVEL=<debug|info|warning|error> \
SPEC_GITHUB_USERNAME=<GitHub username> \
SPEC_GITHUB_TOKEN=<GitHub password/access token> \
npm test
MIT. Pre is a fork of Electric Imp's Builder licensed under MIT.
Mikhail Yurasov me@yurasov.me