
Neutral Web Template System
Neutral is a web application template system, designed to work with any programming language (language-agnostic) via IPC and natively as library/crate in Rust.
In the examples, we use exactly the same template for both Rust and PHP:
Safe
Neutral is developed in Rust, one of the most secure programming languages. It does not have access to the application's data; it cannot do so because it is designed this way. It implements security mechanisms like "allow," which prevent arbitrary files from being loaded into templates.
Which is not
It is not a programming language, but a markup language, it does not modify data, only its representation.
It is NOT possible:
- Logical operator: varname == varname
- Mathematical operators: varname + varname
- Assignment operators: varname = 1
Features
It allows you to create templates compatible with any system and any programming language.
- Safe
- Language-agnostic
- Modular
- Parameterizable
- Parse files
- Embed files
- Localization
- Loops: for and each
- Snippets
- Nesting, grouping and wrapping
- Redirections: HTTP y JavaScript
- Exit with error: 403, 404, 503, ...
- Comments
Localization
Neutral provides powerful and easy-to-use translation utilities... define the translation in a JSON:
"locale":
Now you can use:
{:trans; Hello :}
Actually you can always use "trans" because if there is no translation it returns the text.
Bif layout (Build-in function)
.-- open bif
| .-- bif name
| | .-- name separator
| | | .-- params
| | | | .-- params/code separatos
| | | | | .-- code
| | | | | | .-- close bif
| | | | | | |
v v v v v v v
-- ----- - ------- -- ----- --
{:snippet; varname >> ... :}
------------------------------
^ ----------------
| ^
| |
| `-- source
`-- Build-in function
Bif example:
{:filled; varname >>
Hello!
:}
Neutral is based on Bifs with block structure, we call the set of nested Bifs of the same level a block:
.-- {:coalesce;
| {:code;
| {:code; ... :}
| {:code; ... :}
Block --> | {:code; ... :}
| :}
| {:code;
| {:code; ... :}
| :}
`-- :}
{:coalesce;
.------ {:code;
| {:code; ... :}
Block --> | {:code; ... :}
| {:code; ... :}
`------ :}
.------ {:code;
Block --> | {:code; ... :}
`------ :}
:}
Short circuit at block level, if varname is not defined, the following ">>" is not evaluated:
{:defined; varname >>
{:code;
{:code;
...
:}
:}
:}
By design all Bifs can be nested and there can be a Bif anywhere in another Bif except in the name.
Data
The data is defined in a JSON:
"data":
And they are displayed with the bif {:; ... :} (var)
Simple variable:
{:;hello:}
Arrays with the "->" operator
{:;array->hello:}
Snippets
Snippet is a tool that can be used in a similar way to a function, it defines a snippet:
{:snippet; name >>
Any content here, including other snippet.
:}
From then on you can invoke it like this:
{:snippet; name :}
Template example
{:*
comment
*:}
{:locale; locale.json :}
{:include; theme-snippets.ntpl :}
{:trans; Site title :}
{:snippet; current-theme:head :}
{:snippet; current-theme:body_begin :}
{:snippet; current-theme:body-content :}
{:snippet; current-theme:body-footer :}
Native use (Rust)
You need two things, a template file and a json schema:
let schema = json!({
"config": {
"comments": "remove"
},
"inherit": {
"locale": {
"current": "en",
"trans": {
"en": {
"Hello nts": "Hello",
"ref:greeting-nts": "Hello"
},
"es": {
"Hello nts": "Hola",
"ref:greeting-nts": "Hola"
},
"de": {
"Hello nts": "Hallo",
"ref:greeting-nts": "Hallo"
},
"fr": {
"Hello nts": "Bonjour",
"ref:greeting-nts": "Bonjour"
},
"el": {
"Hello nts": "Γεια σας",
"ref:greeting-nts": "Γεια σας"
}
}
}
},
"data": {
"web-site-name": "MySite",
"varname": "value",
"true": true,
"false": false,
"hello": "hello",
"zero": "0",
"one": "1",
"spaces": " ",
"empty": "",
"null": null,
"emptyarr": [],
"array": {
"true": true,
"false": false,
"hello": "hello",
"zero": "0",
"one": "1",
"spaces": " ",
"empty": "",
"null": null
}
}
});
Template file.ntpl:
{:;web-site-name:}
In Rust:
let template = Template::from_file_value("file.ntpl", schema).unwrap();
let content = template.render();
// e.g.: 200
let status_code = template.get_status_code();
// e.g.: OK
let status_text = template.get_status_text();
// empty if no error
let status_param = template.get_status_param();
// act accordingly at this point according to your framework