Hi, most of the README, is or was generated with AI, lots of the code too, or definitely with help.
Just that you know.
I became a bit of a pug lover ... :) the dog ;) , and needed a Typescript validation. Pug was new to me. Node as well, I have been a long time in Javascript ... I am getting older. But so, Typescript was new as well, and I fell a bit in love with Typescript, Pug, and Node/npm.
So basically, this is a Node npm package, that parses pug templates ... to see if what you're using is validly typed (scripted).
Which means if you change your code ... the program will check if everything in your pugs is still consistent. Lots of updates are possible; this is a working version that was handy for me ... so I stopped there a bit. Also not working on the project anymore where I was using it. Once I'm back there I will ... continue to improve.
I also created a simple VS-extension so you can (at least) click through on the import links above in the page to go to the classes/interfaces you defined. Might make that public as well later ...
Kr, Sam 2025-07-31
pug-ts-check
is a static TypeScript checker for Pug templates. It performs offline analysis of your .pug
views to ensure that the locals and mixin arguments match their expected TypeScript types.
When rendering Pug templates in a Node.js/Express app, mismatches between what's passed and what the view expects often lead to runtime errors.
pug-ts-check
solves this by:
- π§ Analyzing your
.pug
files statically - π οΈ Validating expected
locals
andmixin
arguments - π§Ύ Generating a shared
viewlocals.d.ts
file - π§ Improving development experience (autocomplete, hover, etc.)
- β Preventing bugs before runtime
π§Ό This is a static development tool only. It does not run at runtime and does not modify your compiled templates.
npm install pug-ts-check --save-dev
npm install pug-ts-check --save-dev
These patches are NOT required for pug-ts-check
to work - the tool can analyze your templates without them. However, the patches ARE required for your Pug templates to compile correctly when you add TypeScript annotations like //@import
and typed mixin parameters.
pug-ts-check
reads your .pug
files and validates the TypeScript annotations, but when you actually render your templates (in development or production), standard Pug will fail to compile templates with:
//@
comments beforeextends
statements- Typed mixin parameters like
mixin card(title: string, count?: number)
Without patches: β Your templates won't compile
With patches: β
Your templates compile normally + get type checking
-
Install dependencies:
npm install pug-ts-check --save-dev npm install patch-package --save-dev npm install pug@^3.0.2 pug-code-gen@^3.0.3 pug-linker@^4.0.0
-
Copy patch files:
cp node_modules/pug-ts-check/patches/*.patch ./patches/
-
Apply patches:
npx patch-package
-
Auto-apply on install:
// Add to your package.json scripts: "postinstall": "patch-package"
Patch 1: Comment Support (pug-linker
)
- Problem: Pug doesn't allow comments before or at the same level as
extends
nodes - Solution: Allow
//@
comments in extended templates (beforeextends
) - Result: Your
//@import
and//@expect
comments work in extended templates
Note: These comments currently get included in the final HTML render - this might be changed in future.
Patch 2: Typed Mixin Support (pug-code-gen
)
- Problem: Pug can't handle TypeScript syntax in mixin parameters
- Solution: Strip TypeScript annotations from mixins during compilation
- Example:
mixin card(title: string, count?: number)
βmixin card(title, count)
- Result: You can write typed mixins that both compile AND get type-checked
Both patches ensure that when you add TypeScript annotations, the Pug compiler doesn't freak out and can still generate HTML. The pug-ts-check
tool works with or without patches, but your templates need the patches to actually render.
π Detailed instructions: See patches/README.md
We are working on providing pre-patched Pug packages or a patch automation tool to eliminate this manual step.
Current Status:
Planned: β
Automated patch application or pre-patched packages
{
"tmpDir": "./src/.tmp",
"projectPath": "../../srv/apps/string-portrait/code/",
"pugPaths": ["./src/views"],
"logLevel": "info",
"viewsRoot": "./src/views",
"typesPath": "./src/types"
}
or e.g.
{
"tmpDir": "./src/.tmp",
"projectPath": "./",
"pugPaths": ["./views"],
"logLevel": "info",
"viewsRoot": "./views",
"typesPath": "./types"
}
Field | Description |
---|---|
tmpDir |
Temporary directory used for generated .ts files |
projectPath |
Path to your app's tsconfig.json (needed for type resolution) |
pugPaths |
One or more directories where .pug files live |
logLevel |
Logging verbosity (info , warn , error , debug ) |
viewsRoot |
Base directory for resolving included views (typically views folder) |
typesPath |
Where viewlocals.d.ts will be generated |
Use //@
comments to describe what the view expects:
//@ import type { User, Cart } from '../types/models.js'
//@ expect { user: User, cart: Cart }
extends layout
block content
+orderOverview(cart, user)
p Welcome #{user.name} to your order history!
You can add type-safe mixin definitions as well:
//@ import type { Cart } from '../types/models.js'
//@ import type { User } from '../types/models.js'
//@ expect {}
mixin orderOverview(cart: Cart, user: User)
ul
each item in cart.items
li= item.product.name + ' - ' + item.quantity + ' pcs'
if cart.items.length > 0
p Total items: #{cart.items.length}
else
p Your cart is empty.
The checker verifies all usages of +orderOverview(...)
and enforces correct argument types.
npx pug-ts-check
npx pug-ts-check [path] [options]
Flag | Description |
---|---|
[path] |
File or folder to analyze (optional) |
--watch |
Re-run when .pug files change |
--verbose |
Show detailed output |
--silent |
Suppress logs |
--tmpDir <dir> |
Override temp directory |
--projectPath |
Path to tsconfig.json |
--pugTsConfig |
Use alternative config file (default: pug.tsconfig.json ) |
After running, you'll get a file like:
// src/types/viewlocals.d.ts
declare namespace ViewLocals {
interface Index { title: string }
interface CartHistory { user: User; cart: Cart }
...
}
Use this for type safety in your controllers.
To enforce view-local types at runtime, you can extend Express's res
object with a typedRender
helper.
Create a file like express.d.ts
in your project:
import "express";
declare module "express-serve-static-core" {
interface Response {
typedRender<K extends keyof ViewLocals>(
view: K,
locals: ViewLocals[K]
): void;
}
}
In your app setup code (e.g. app.ts
):
app.use((req, res, next) => {
res.typedRender = function(view, locals) {
return res.render(view, locals);
};
next();
});
You now get full type safety when rendering views:
res.typedRender("pages/home", {
user: currentUser,
cart: currentCart
});
project-root/
βββ src/
β βββ views/ # Pug templates
β βββ types/
β β βββ viewlocals.d.ts # Generated typings
β βββ .tmp/ # Temp output (safe to ignore)
βββ pug.tsconfig.json # Static checker config
βββ tsconfig.json # TypeScript config
- β Static TypeScript checking for Pug views
- β
Typed
locals
and mixin parameters - β
Autogenerated
viewlocals.d.ts
- β Watch mode for live feedback
- β Simple CLI integration
- β
IDE-friendly annotations (
//@ import
,//@ expect
)
MIT License - see LICENSE file for details.
Created with β€οΈ to bring modern type safety to template rendering.
Contributions, suggestions, and integrations welcome!