Add support for pipes in templates #53

The goal is to be able to modify values of variables used in templates.
It enables future functionality such as escaping, inlining etc.

It adds support applying predefined pipes to variables. Pipes
can be applied to variable substitution in with and parameter
substitution expressions. They work in similar way to piping in Unix
where each pipe applied to the compiled result of pipe before.

It adds support for using pipes in `with` and parameter substitution
expressions. It also refactors how their regex is build to reuse more of
the logic by abstracting regex building into a new class.

Finally, it separates and extends documentation for templating.
This commit is contained in:
undergroundwires
2021-09-08 18:58:30 +01:00
parent 862914b06e
commit 4d7ff7edc5
30 changed files with 1112 additions and 207 deletions

View File

@@ -80,7 +80,7 @@
### `FunctionCall`
- Describes a single call to a function by optionally providing values to its parameters.
- 👀 See [parameter substitution](#parameter-substitution) for an example usage
- 👀 See [parameter substitution](./templating.md#parameter-substitution) for an example usage
#### `FunctionCall` syntax
@@ -100,73 +100,10 @@
### `Function`
- Functions allow re-usable code throughout the defined scripts.
- Functions are templates compiled by privacy.sexy and uses special [expressions](#expressions).
- Functions allow re-usable code throughout the defined scripts
- Functions are templates compiled by privacy.sexy and uses special expression expressions
- Functions can call other functions by defining `call` property instead of `code`
- 👀 See [parameter substitution](#parameter-substitution) for an example usage
#### Expressions
- Expressions are defined inside mustaches (double brackets, `{{` and `}}`)
- Expression syntax is inspired by [Go Templates](https://pkg.go.dev/text/template)
##### Parameter substitution
A simple function example
```yaml
function: EchoArgument
parameters:
- name: 'argument'
code: Hello {{ $argument }} !
```
It would print "Hello world" if it's called in a [script](#script) as following:
```yaml
script: Echo script
call:
function: EchoArgument
parameters:
argument: World
```
A function can call other functions such as:
```yaml
-
function: CallerFunction
parameters:
- name: 'value'
call:
function: EchoArgument
parameters:
argument: {{ $value }}
-
function: EchoArgument
parameters:
- name: 'argument'
code: Hello {{ $argument }} !
```
##### with
- Skips the block if the variable is absent or empty.
- Binds its context (`.`) value of provided argument for the parameter only if its value is provided.
- A block is defined as `{{ with $parameterName }} Parameter value is {{ . }} here {{ end }}`
- The parameters used for `with` condition should be declared as optional, otherwise `with` block becomes redundant.
- Example:
```yaml
function: FunctionThatOutputsConditionally
parameters:
- name: 'argument'
optional: true
code: |-
{{ with $argument }}
$argument's value is: {{ . }}
{{ end }}
```
- 👀 Read more on [Templating](./templating.md) for function expressions and [example usages](./templating.md#parameter-substitution)
#### `Function` syntax
@@ -177,7 +114,7 @@ A function can call other functions such as:
- ❗ Function names must be unique
- `parameters`: `[` ***[`FunctionParameter`](#FunctionParameter)*** `, ... ]`
- List of parameters that function code refers to.
- ❗ Must be defined to be able use in [`FunctionCall`](#functioncall) or [expressions](#expressions)
- ❗ Must be defined to be able use in [`FunctionCall`](#functioncall) or [expressions](./templating.md#expressions)
`code`: *`string`* (**required** if `call` is undefined)
- Batch file commands that will be executed
- 💡 If defined, best practice to also define `revertCode`
@@ -188,7 +125,7 @@ A function can call other functions such as:
- then `revertCode` should be doing `setx POWERSHELL_TELEMETRY_OPTOUT 0`
- `call`: ***[`FunctionCall`](#FunctionCall)*** | `[` ***[`FunctionCall`](#FunctionCall)*** `, ... ]` (may be **required**)
- A shared function or sequence of functions to call (called in order)
- The parameter values that are sent can use [expressions](#expressions)
- The parameter values that are sent can use [expressions](./templating.md#expressions)
- ❗ If not defined `code` must be defined
### `FunctionParameter`
@@ -200,7 +137,7 @@ A function can call other functions such as:
- `name`: *`string`* (**required**)
- Name of the parameters that the function has.
- Parameter names must be defined to be used in [expressions](#expressions).
- Parameter names must be defined to be used in [expressions](./templating.md#expressions).
- ❗ Parameter names must be unique and include alphanumeric characters only.
- `optional`: *`boolean`* (default: `false`)
- Specifies whether the caller [Script](#script) must provide any value for the parameter.
@@ -208,7 +145,7 @@ A function can call other functions such as:
- Otherwise it throws.
- 💡 Set it to `true` if a parameter is used conditionally;
- Or else set it to `false` for verbosity or do not define it as default value is `false` anyway.
- 💡 Can be used in conjunction with [`with` expression](#with).
- 💡 Can be used in conjunction with [`with` expression](./templating.md#with).
### `ScriptingDefinition`
@@ -220,7 +157,7 @@ A function can call other functions such as:
- 📖 See [ScriptingLanguage.ts](./../src/domain/ScriptingLanguage.ts) enumeration for allowed values.
- `startCode:` *`string`* (**required**)
- Code that'll be inserted on top of user created script.
- Global variables such as `$homepage`, `$version`, `$date` can be used using [parameter substitution](#parameter-substitution) code syntax such as `Welcome to {{ $homepage }}!`
- Global variables such as `$homepage`, `$version`, `$date` can be used using [parameter substitution](./templating.md#parameter-substitution) code syntax such as `Welcome to {{ $homepage }}!`
- `endCode:` *`string`* (**required**)
- Code that'll be inserted at the end of user created script.
- Global variables such as `$homepage`, `$version`, `$date` can be used using [parameter substitution](#parameter-substitution) code syntax such as `Welcome to {{ $homepage }}!`
- Global variables such as `$homepage`, `$version`, `$date` can be used using [parameter substitution](./templating.md#parameter-substitution) code syntax such as `Welcome to {{ $homepage }}!`

81
docs/templating.md Normal file
View File

@@ -0,0 +1,81 @@
# Templating
## Benefits of templating
- Generating scripts by sharing code to increase best-practice usage and maintainability.
- Creating self-contained scripts without depending on each other that can be easily shared.
- Use of pipes for writing cleaner code and letting pipes do dirty work.
## Expressions
- Expressions in the language are defined inside mustaches (double brackets, `{{` and `}}`).
- Expression syntax is inspired mainly by [Go Templates](https://pkg.go.dev/text/template).
## Syntax
### Parameter substitution
A simple function example:
```yaml
function: EchoArgument
parameters:
- name: 'argument'
code: Hello {{ $argument }} !
```
It would print "Hello world" if it's called in a [script](./collection-files.md#script) as following:
```yaml
script: Echo script
call:
function: EchoArgument
parameters:
argument: World
```
A function can call other functions such as:
```yaml
-
function: CallerFunction
parameters:
- name: 'value'
call:
function: EchoArgument
parameters:
argument: {{ $value }}
-
function: EchoArgument
parameters:
- name: 'argument'
code: Hello {{ $argument }} !
```
### with
- Skips the block if the variable is absent or empty.
- Binds its context (`.`) value of provided argument for the parameter if provided one.
- A block is defined as `{{ with $parameterName }} Parameter value is {{ . }} here {{ end }}`.
- The parameters used for `with` condition should be declared as optional, otherwise `with` block becomes redundant.
- Example:
```yaml
function: FunctionThatOutputsConditionally
parameters:
- name: 'argument'
optional: true
code: |-
{{ with $argument }}
Value is: {{ . }}
{{ end }}
```
### Pipes
- Pipes are set of functions available for handling text in privacy.sexy.
- Allows stacking actions one after another also known as "chaining".
- Just like [Unix pipelines](https://en.wikipedia.org/wiki/Pipeline_(Unix)), the concept is simple: each pipeline's output becomes the input of the following pipe.
- Pipes are provided and defined by the compiler and consumed by collection files.
- Pipes can be combined with [parameter substitution](#parameter-substitution) and [with](#with).
- ❗ Pipe names must be camelCase without any space or special characters.