jade-pug-expert
World-class Pug (Jade) templating: clean HTML generation, indentation-based syntax, mixins, blocks, inheritance, filters, and security. Use when creating or editing .pug/.jade files, converting HTML to Pug, or building Express/Node/Vue templates with Pug.
# Pug/Jade Expert (Verdensklasse .pug)
Dette skill sikrer **korrekt, vedligeholdelig og sikker** Pug-kode der kompilerer til valid HTML. Pug (tidligere Jade, fra 2015) er et whitespace-sensitivt template-sprog; alle referencer her er til **Pug 2+** (pugjs.org). Projekt-uafhængigt.
---
## 1. Når skal skillen bruges?
- Oprette eller redigere filer med endelse `.pug` eller `.jade` i **ethvert** projekt
- Konvertere HTML til Pug eller refaktorere eksisterende Pug-templates
- Bruge mixins, blocks, inheritance eller filters i Pug
- Integrere Pug med Express, Vue, Angular, eller anden Node/JS-stack
---
## 2. Pug-sproget – kort reference
**Kilde:** [pugjs.org](https://pugjs.org) (Node.js template engine; kompilerer til HTML).
### 2.1 Grundregler
- **Indentation** definerer struktur; ingen closing tags. Konsistent indentation (typisk 2 mellemrum) er påkrævet.
- **Default tag** er `div` – `.foo` og `#bar` er `div.foo` og `div#bar`.
- **Filendelse:** `.pug` (`.jade` er legacy).
### 2.2 Tags, id og class
```pug
doctype html
html(lang="en")
head
title= pageTitle
body
.container#main
h1 Hello
a.button(href="/") Link
```
- Attributter: `tag(attr="value")` eller `attr= jsExpression`. Flere: komma eller nye linjer.
- Class literal: `.classname`. ID literal: `#idname`. `div` kan udelades.
- Boolean attributes: `input(checked)` eller `input(checked=true)`.
### 2.3 Kode i templates
| Type | Syntax | Beskrivelse |
|-----------------|--------|-------------|
| Unbuffered | `-` | Kører JS, outputter ikke. Fx `- var x = 1` |
| Buffered | `=` | Evaluerer og outputter **escaped** (sikkert). Fx `p= user.name` |
| Unescaped | `!=` | Outputter **ikke** escaped – **kun til betroet indhold** (XSS-risiko). |
```pug
- var name = "World"
p= name
p Safe: #{name}
p Danger (only if trusted): !{rawHtml}
```
### 2.4 Interpolation
- **Escaped** i plain text: `#{expression}`.
- **Unescaped**: `!{expression}` – kun til betroet indhold.
- **Tag interpolation** (whitespace-respekt): `#[strong bold]` og `#[em text]` inde i tekst.
### 2.5 Plain text og whitespace
- **Inline:** Første ord er tag, resten er tekst: `p Hello world`.
- **Piped:** `|` i starten af linje = plain text (nyttigt til at styre whitespace).
- **Block:** `.` efter tag – alt indented indhold er raw (fx `script.` med JS).
- Pug **fjerner** whitespace mellem elementer; brug `|` eller tomme piped linjer for mellemrum.
### 2.6 Conditionals
```pug
if user
p Hello #{user.name}
else if anon
p Guest
else
p Welcome
unless user.isAnonymous
p Logged in as #{user.name}
```
### 2.7 Iteration
```pug
ul
each val, index in [1, 2, 3]
li= index + ': ' + val
else
li No items
ul
each val, key in { a: 1, b: 2 }
li= key + ': ' + val
```
- `for` er alias for `each`. `while` understøttes også.
### 2.8 Case
```pug
case orderStatus
when 'pending'
p Order is pending
when 'transit'
p Shipped
default
p Unknown
```
- Fall-through: udelad indhold i `when`; brug eksplicit `break` for at undgå output.
### 2.9 Mixins
- Genbrugelige blokke; kompileres til funktioner. Kan tage argumenter, default-værdier og rest-args.
```pug
mixin list(items)
ul
each item in items
li= item
+list(['A', 'B', 'C'])
```
- **Mixin block:** Indhold mellem mixin-kald sendes som `block`:
```pug
mixin card(title)
.card
h2= title
if block
block
else
p No content
+card("Title")
p Custom body
```
- **Mixin attributes:** Implicit `attributes`-objekt; brug `&attributes(attributes)` i mixin for at sprede dem. Værdier er escaped som standard; brug `!=` kun ved bevidst unescaped brug.
### 2.10 Template inheritance
- **Layout:** `block name` med valgfrit default-indhold.
- **Child:** `extends layout.pug`, derefter `block name` for at erstatte, eller `block append name` / `block prepend name`.
```pug
//- layout.pug
doctype html
html
head
block head
script(src='/vendor.js')
body
block content
//- page.pug
extends layout.pug
block head
script(src='/vendor.js')
script(src='/page.js')
block content
h1= title
```
- **Vigtigt:** I child må kun **named blocks** og **mixin-definitioner** stå på top-level ( ingen løse tags eller unbuffered code uden for blocks ). Variabler kan sættes i parent eller i et block i child.
### 2.11 Includes
- `include path` indsætter indhold af anden fil. Path relativ til aktuel fil; `.pug` tilføjes automatisk.
- Ikke-Pug-filer inkluderes som raw text. Filtered includes: `include:markdown-it article.md`.
### 2.12 Filters
- Andet sprog i Pug: `:filterName`. Fx `:markdown-it`, `:scss`, `:babel`. Options: `:markdown-it(linkify)`.
- **Compile-time:** Filters kører ved kompilering; ingen runtime-dynamik i filter-indhold.
- Nested: `:cdata-js:babel(presets=['es2015'])` – sidste filter anvendes først.
### 2.13 Attributter – avanceret
- **Style-objekt:** `div(style={color: 'red', background: 'blue'})`.
- **Class-array:** `a(class=classes)`. **Class-objekt:** `a(class={active: isActive})`.
- **&attributes:** Explode objekt til attributter: `div&attributes({ 'data-foo': 'bar' })`. Nyttigt i mixins.
### 2.14 Kommentarer
- **Buffered (output til HTML):** `// comment`.
- **Unbuffered (kun i Pug):** `//- comment`.
- Multiline: `//` eller `//-` med indented blok under.
---
## 3. Filstruktur og konventioner
- **Layout:** Én `layout.pug` med `block head`, `block content`, `block scripts` osv.; sider `extends layout.pug`.
- **Partials:** Fælles komponenter i fx `includes/` eller `components/`; `include` hvor det giver mening.
- **Mixins:** Saml i `mixins.pug` og inkludér, eller definér i layout så child-templates kan bruge dem.
- Verificer **altid** eksisterende filstier og block-navne i det aktuelle projekt – opfind ikke navne.
---
## 4. Best practices (verdensklasse)
### 4.1 Sikkerhed
- Brug **altid** `=` og `#{}` til bruger-/ekstern indhold (escaped).
- Brug `!=` og `!{}` **kun** til indhold der allerede er sanitized eller statisk; dokumentér hvorfor.
- Undgå at sætte brugerinput direkte i attributter uden escaping (Pug escaped normalt, men tænk på `href`, `src`, etc.).
### 4.2 DRY med mixins og blocks
- Gentagne UI-blokke (kort, knapper, formularfelter) → mixins med argumenter og evt. `block`.
- Fælles side-struktur → layout med blocks; child kun overskriver det nødvendige.
### 4.3 Indentation og læsbarhed
- Én konsistent indent (anbefaling: 2 mellemrum). Ingen mix af tabs og spaces.
- Lange attribut-lister: multiline med indent under tag.
### 4.4 Angular/Vue og specielle tegn
- Attributnavne med `()`, `[]` (fx `(click)`, `[src]`): brug quoted attr-navn eller komma: `div('(click)'='play()')` eller `div( (click)='play()' )` efter komma.
### 4.5 Whitespace-kontrol
- Brug `|` og tomme piped linjer til at indsætte mellemrum mellem tags.
- Brug `#[tag]` for inline-tags i sætninger så mellemrum respekteres.
---
## 5. Eksempler (optimerede mønstre)
### 5.1 Layout med blocks
```pug
//- layout.pug
doctype html
html(lang="en")
head
meta(charset="UTF-8")
title= title
block head
body
block content
block scripts
```
### 5.2 Mixin med default og block
```pug
mixin panel(title, collapsed = false)
.panel(class=collapsed ? 'collapsed' : '')
h3= title
if block
block
+panel("Info")
p Body text
```
### 5.3 Conditional classes og &attributes
```pug
mixin btn(label, type = "button")
button(type=type)&attributes(attributes)= label
+btn("Save")(class="btn btn-primary")
+btn("Cancel")(class="btn btn-secondary")
```
### 5.4 each med else
```pug
ul
each item in items
li= item.name
else
li No items
```
---
## 6. Do's og don'ts
**Gør:**
- Følg projektets eksisterende Pug-struktur og block-/mixin-navne.
- Brug escaped output (`=`, `#{}`) til alt bruger-/ekstern indhold.
- Hold mixins små og med tydelige argumenter; brug default-værdier hvor det giver mening.
- Brug `extends` + `block` til side-struktur i stedet for at duplikere layout.
- Tjek whitespace i output (især ved inline-tags) og brug `|` / `#[ ]` når nødvendigt.
**Undgå:**
- `!=` / `!{}` på brugerinput eller uden dokumentation.
- Top-level indhold i child-templates uden for blocks (Pug tillader det ikke ved `extends`).
- At opfinde filstier, block-navne eller mixin-navne – verificer i kodebasen.
- Magiske strenge eller duplikeret markup der kan være mixin/block.
---
## 7. Referencer
- Pug docs: https://pugjs.org
- Language reference: https://pugjs.org/language/attributes.html, code.html, mixins.html, inheritance.html, iteration.html, conditionals.html, filters.html
- API (Node): https://pugjs.org/api/getting-started.html
- Migration Jade → Pug 2: https://pugjs.org/api/migration-v2.html