An open API service indexing awesome lists of open source software.

https://github.com/bananaacid/pugps

Unleash Pug templates in PowerShell. A versatile CLI for HTML pipelines and a loyal View Engine for your Pode Server projects. 🐾
https://github.com/bananaacid/pugps

cli devops-tools html-generator jade-templates pode powershell pug pugjs view-engine

Last synced: 8 days ago
JSON representation

Unleash Pug templates in PowerShell. A versatile CLI for HTML pipelines and a loyal View Engine for your Pode Server projects. 🐾

Awesome Lists containing this project

README

          

# PugPS

**Unleash Pug templates in PowerShell. A versatile CLI for HTML pipelines and a loyal View Engine for your Pode Server projects. 🐾**

PugPS is a PowerShell-native implementation of the Pug (formerly Jade) templating engine. It allows you to write clean, indented templates and render them into HTML using PowerShell logic, variables, and functions (JavaScript logic is not supported).

---

## 📦 Installation

```powershell
Install-Module -name PugPS
```

*Latest version: https://github.com/BananaAcid/PugPS*

---

## ⭐ Examples and general documentation

The general [PugJS Language Reference](https://pugjs.org/language/attributes.html) applies. PowerShell specific usage is below.

How does Pug look like? See: https://html-to-pug.com/

---

## 🚀 Usage in Pode

To use PugPS as your view engine in a [Pode](https://badgerati.github.io/Pode/) server, import the module and initialize the engine within your `Start-PodeServer` block.

```powershell
Start-PodeServer {
# Import the view engine module
Import-Module PugPS

# Configure the engine
Set-PodeViewEnginePug -Extension 'pode.pug' -ErrorOutput 'text'
}
```

### `Set-PodeViewEnginePug` Parameters

| Parameter | Type | Req | Default | Description |
| :--- | :--- | :---: | :--- | :--- |
| **-Extension** | `string` | Yes | - | The default file extension to target (e.g., `pode.pug`). |
| **-BaseDir** | `string` | No | `""` | The root directory used to resolve absolute include/extend paths (starting with `/` or `\`). |
| **-Filters** | `sb\|string` | No | `$null` | The path to a `.ps1` filters file or a scriptblock containing filter functions. |
| **-Properties** | `bool` | No | `$true` | When `$true` (default), boolean attributes render as `attr`. When `$false`, `attr='attr'`. |
| **-VoidTagsSelfClosing** | `bool` | No | `$false` | When `$true`, standard void tags (like `img`, `br`) render as ``. |
| **-ContainerTagsSelfClosing** | `bool` | No | `$false` | When `$true`, empty container tags (like `div`) render as `

`. |
| **-KebabCaseHTML** | `bool` | No | `$true` | When `$true`, `CamelCase` tags in PUG are converted to `kebab-case`. |
| **-ErrorOutput** | `string` | No | `'rethrow'` | `'text'` returns HTML error; `'rethrow'` triggers the Pode error page. |
| **-ErrorContextRange** | `int` | No | `2` | Number of context lines to show before and after the error line. |
| **-NoCache** | `switch` | No | `$false` | When `$true`, the internal cache is not used. |

**Returns:** The converted and executed PUG as string.

---

## 💻 Usage as a CLI Tool

Use `Invoke-PUG` for automation, build pipelines, or one-off conversions.

```powershell
Import-Module PugPS

# Example 1: Convert a file with data and external filters
Invoke-PUG -Path .\test.pug -Data @{
Title = "Pug PowerShell"
Users = @(@{ Name = "Alice"; Role = "Admin" })
} -Filters .\helper.ps1

# Example 2: Pipe content directly with a scriptblock filter
@"
div
:MyFilter
Content
"@ | Invoke-PUG -Filters {
Function MyFilter {
param([Parameter(ValueFromPipeline=$true)]$text)
"$text"
}
}
```

### `Invoke-PUG` Parameters

| Parameter | Type | Req | Default | Description |
| :--- | :--- | :---: | :--- | :--- |
| **-Path** | `string` | Yes* | - | Path to Pug Template file (Mandatory if not using pipeline). |
| **-InputContent** | `string[]` | Yes* | - | The raw Pug template content (supports pipeline input). |
| **-Data** | `hashtable` | No | `@{}` | The data passed to the template as `$data`. |
| **-Filters** | `sb\|string` | No | `$null` | Path to filters file (ps1) or a scriptblock with filter functions. |
| **-Extension** | `string` | No | `'pug'` | The default file extension to use for included files. |
| **-BaseDir** | `string` | No | `""` | Root directory used to resolve absolute include/extend paths. |
| **-Properties** | `bool` | No | `$true` | If `$true`, boolean attributes render as `attr`. |
| **-VoidTagsSelfClosing** | `bool` | No | `$false` | If `$true`, void tags render with a self-closing slash. |
| **-ContainerTagsSelfClosing** | `bool` | No | `$false` | If `$true`, empty container tags render as self-closing. |
| **-KebabCaseHTML** | `bool` | No | `$true` | If `$true`, converts `CamelCase` tags to `kebab-case`. |
| **-ErrorContextRange** | `int` | No | `2` | Context lines to show before/after error line. |

**Returns:** The converted and executed PUG as string.

#### Note
`-InputContent` expects an array. Passing a single line into it, append a newline (`` `n ``).

Example:
```powershell
"div: b hi `n" | Invoke-pug
```

---

## 📝 Syntax Notes & Examples

### 1. PowerShell Control Flow
PugPS supports standard PowerShell logic using the `-` prefix.

```pug
- Foreach ($u in $data.Users)
li= $u.Name

- If ($a -eq $true)
li TRUE
- ElseIf ($a -eq $false)
li FALSE
- Else
li Unknown

- Switch ($data.Status)
- "active"
li User is Active
- "disabled"
li User is Locked
- default
li Status Unknown
```

#### NOTE: PugJS's Case, Conditionals, Iteration
- these can be done with `- Foreach`, `- If`, `- For` ... while keeping the PowerShell syntax (the PugJS specific implementation is not supported)
- https://pugjs.org/language/case.html
- https://pugjs.org/language/conditionals.html
- https://pugjs.org/language/iteration.html

### 2. Classes and Styles
PugPS handles PowerShell collections intelligently for clean attribute management.

* **Classes from Array:** Simple list output.
```pug
- $classes = "btn", "btn-primary"
button(class=$classes) //
```
* **Classes from Object:** Keys mapped to `$true` are included; `$false` are omitted.
```pug
- $classesObj = @{ active = $true; hidden = $false }
div(class=$classesObj) //


```
* **Styles from Object:** Keys in `camelCase` are automatically converted to `kebab-case`.
```pug
- $styles = @{ backgroundColor = "red"; borderRadius = "5px" }
div(style=$styles) //

```

### 3. Variables & Interpolation
* **Attribute Values:** These are PowerShell expressions. Double quotes `" "` expand variables; single quotes `' '` do not.
* **Content Interpolation:** Use `$( $var )` or `${ $var }` for raw content, and `#( $var )` or `#{ $var }` for escpaed HTML content. Preferred: use `$()` and `#()`.
* **Escaping:** To escape a dollar sign in content, use `\$` or `` `$ ``. (`\` and `` ` `` can be escaped as well.)

#### Examples
- `ps1 attr='$a'` var will not be parsed (singe quotes),
- `attr="$a"` var will be parsed (double quotes),
- `$attr=$a` var will be parsed (no quotes).

#### Note: Attributes with Code
For `body(class=$authenticated ? 'authed' : 'anon' ...)` and alike, you should use `body(class=$($authenticated ? 'authed' : 'anon') ...)` - wrapping the logic in `$()`

### 4. Filters
Filters trigger standard PowerShell functions. The nested content is passed via the pipeline. Params are used by their names, the multiline content is piped in as single string.

```pug
:MyFilter(paramname="value")
Content here is passed to the function
```

#### Filter
To access the pipeline value use the param `[Parameter(ValueFromPipeline=$true)]$text` (Content is passed as one single string, there is no need to collect lines or use $input)

```ps1
Function TestFN {
param(
$title,
[Parameter(ValueFromPipeline=$true)]$text
)

"

" $title + '
' + ($text ? $text : "-- no text --") + "
"
}
```

A filter can also be created inline in within the Pug (like using `- Function TestFN{...}`) or made available by the `-Filters` param.

### 5. Doctypes & XML
* **Shortcuts:** `5` (== html), `svg1.1`, `smil1`, `smil2`. And for the PugJS default ones [look them up here](https://pugjs.org/language/doctype.html)
* **Casing:** When using the XML doctype, `KebabCaseHTML` is automatically disabled to preserve XML casing.
* **XML Mode:** For XML types (plist, svg1.1, smil1, smil2, etc.), always include `doctype xml` first.

Example:
```pug
doctype xml
doctype plist
plist(version="1.0")
dict
...
```
**Note:** A specific doctype for SVG Tiny 1.1 and 1.2 is not recomended. Only use: `doctype xml`

### 6. Includes & Mixins & Template Inheritance (Extends)
Are supported as defined by PugJS.

- https://pugjs.org/language/includes.html
- https://pugjs.org/language/mixins.html
- https://pugjs.org/language/inheritance.html

---

## ⚙️ Manual Transpilation

If you need to generate the PowerShell script representation of a Pug file without immediately rendering it, use `Convert-PugToPowerShell`.

You need to save the module into your project first:
```powershell
Save-Module -Name PugPS -Path .\ # this creates a subfolder .\PugPS\1.1.0\
```

Then use it:

```powershell
. .\PugPS\1.0.0\parser.ps1
$psCode = Convert-PugToPowerShell -Path "template.pug" -KebabCaseHTML $true
```

### `Convert-PugToPowerShell` Parameters

| Parameter | Type | Req | Default | Description |
| :--- | :--- | :---: | :--- | :--- |
| **-Path** | `string` | Yes* | - | Path to Pug Template file (Mandatory if not using pipeline). |
| **-InputContent** | `string[]` | Yes* | - | The raw Pug template content (supports pipeline input). |
| **-Extension** | `string` | No | `'pug'` | Extension for included files. |
| **-BaseDir** | `string` | No | `""` | Root directory for absolute paths. |
| **-Properties** | `bool` | No | `$true` | Render boolean attributes as `attr`. |
| **-VoidTagsSelfClosing** | `bool` | No | `$false` | Render void tags with `/`. |
| **-ContainerTagsSelfClosing** | `bool` | No | `$false` | Render empty containers with `/`. |
| **-KebabCaseHTML** | `bool` | No | `$true` | Convert `CamelCase` tags to `kebab-case`. |
| **-ErrorContextRange** | `int` | No | `2` | Error context line count. |

**Returns:** PowerShell script block as string with param `-Data` for an input object. To get the html, use it like :
```powershell
$sb = [scriptblock]::Create($psCode)

$Data = @{
something = "to make available" # provies $Data.something to be used in PUG
}

$html = (& $sb -Data $Data)
```