zig-pug 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +288 -221
- package/binding.gyp +5 -8
- package/index.js +11 -33
- package/index.mjs +192 -0
- package/package.json +32 -24
package/README.md
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
# zig-pug
|
|
2
2
|
|
|
3
|
-
High-performance Pug template engine powered by Zig and mujs
|
|
3
|
+
High-performance Pug template engine powered by Zig and mujs.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/zig-pug)
|
|
6
|
-
[](https://github.com/carlos-sweb/zig-pug/blob/main/LICENSE)
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
10
|
+
- ✅ **Pug syntax** - Tags, attributes, classes, IDs
|
|
11
|
+
- ✅ **JavaScript expressions** - ES5.1 interpolation powered by mujs
|
|
12
|
+
- ✅ **Full UTF-8 support** - Emoji 🎉, accents (á é ñ ü), all Unicode
|
|
13
|
+
- ✅ **Documentation comments** - `//!` for file metadata (ignored by parser)
|
|
14
|
+
- ✅ **Conditionals** - if/else/unless
|
|
15
|
+
- ✅ **Mixins** - Reusable components
|
|
16
|
+
- ✅ **Dual package** - CommonJS (`require`) and ES Modules (`import`)
|
|
17
|
+
- ✅ **Bun.js compatible** - 2-5x faster than Node.js
|
|
18
|
+
- ⚡ **Native performance** - Written in Zig, compiled to native code
|
|
19
|
+
- 🔋 **Zero dependencies** - Only Zig and embedded mujs
|
|
20
|
+
- 🌍 **i18n ready** - Spanish, Portuguese, French, German, and more
|
|
17
21
|
|
|
18
22
|
## Installation
|
|
19
23
|
|
|
@@ -21,326 +25,389 @@ High-performance Pug template engine powered by Zig and mujs - Native N-API addo
|
|
|
21
25
|
npm install zig-pug
|
|
22
26
|
```
|
|
23
27
|
|
|
24
|
-
|
|
28
|
+
**Requirements:**
|
|
29
|
+
- Node.js >= 14.0.0
|
|
30
|
+
- C/C++ compiler (GCC, Clang, or MSVC)
|
|
31
|
+
- Python (for node-gyp)
|
|
32
|
+
|
|
33
|
+
The addon will compile automatically during installation.
|
|
25
34
|
|
|
26
35
|
## Quick Start
|
|
27
36
|
|
|
28
|
-
|
|
29
|
-
const { compile } = require('zig-pug');
|
|
37
|
+
### Simple API
|
|
30
38
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
39
|
+
**CommonJS (Node.js):**
|
|
40
|
+
```javascript
|
|
41
|
+
const zigpug = require('zig-pug');
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
const html = zigpug.compile('p Hello #{name}!', { name: 'World' });
|
|
44
|
+
console.log(html);
|
|
45
|
+
// <p>Hello World!</p>
|
|
38
46
|
```
|
|
39
47
|
|
|
40
|
-
|
|
48
|
+
**ES Modules (Node.js, Bun):**
|
|
49
|
+
```javascript
|
|
50
|
+
import { compile } from 'zig-pug';
|
|
41
51
|
|
|
42
|
-
|
|
52
|
+
const html = compile('p Hello #{name}!', { name: 'World' });
|
|
53
|
+
console.log(html);
|
|
54
|
+
// <p>Hello World!</p>
|
|
55
|
+
```
|
|
43
56
|
|
|
44
|
-
|
|
57
|
+
### Object-Oriented API
|
|
45
58
|
|
|
59
|
+
**CommonJS (Node.js):**
|
|
46
60
|
```javascript
|
|
47
|
-
const {
|
|
61
|
+
const { PugCompiler } = require('zig-pug');
|
|
62
|
+
|
|
63
|
+
const compiler = new PugCompiler();
|
|
64
|
+
compiler
|
|
65
|
+
.set('title', 'My Page')
|
|
66
|
+
.set('version', 1.5)
|
|
67
|
+
.setBool('isDev', false);
|
|
48
68
|
|
|
49
|
-
const html = compile('
|
|
50
|
-
console.log(html);
|
|
69
|
+
const html = compiler.compile('h1 #{title}');
|
|
70
|
+
console.log(html);
|
|
71
|
+
// <h1>My Page</h1>
|
|
51
72
|
```
|
|
52
73
|
|
|
53
|
-
**
|
|
54
|
-
|
|
55
|
-
|
|
74
|
+
**ES Modules (Node.js, Bun):**
|
|
75
|
+
```javascript
|
|
76
|
+
import { PugCompiler } from 'zig-pug';
|
|
56
77
|
|
|
57
|
-
|
|
78
|
+
const compiler = new PugCompiler();
|
|
79
|
+
compiler
|
|
80
|
+
.set('title', 'My Page')
|
|
81
|
+
.set('version', 1.5)
|
|
82
|
+
.setBool('isDev', false);
|
|
58
83
|
|
|
59
|
-
|
|
84
|
+
const html = compiler.compile('h1 #{title}');
|
|
85
|
+
console.log(html);
|
|
86
|
+
// <h1>My Page</h1>
|
|
87
|
+
```
|
|
60
88
|
|
|
61
|
-
|
|
89
|
+
### Express Integration
|
|
62
90
|
|
|
63
91
|
```javascript
|
|
64
|
-
const
|
|
92
|
+
const express = require('express');
|
|
93
|
+
const zigpug = require('zig-pug');
|
|
94
|
+
const fs = require('fs');
|
|
95
|
+
|
|
96
|
+
const app = express();
|
|
97
|
+
|
|
98
|
+
// Load template once at startup
|
|
99
|
+
const homeTemplate = fs.readFileSync('./views/home.pug', 'utf-8');
|
|
65
100
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
101
|
+
app.get('/', (req, res) => {
|
|
102
|
+
const html = zigpug.compile(homeTemplate, {
|
|
103
|
+
title: 'Home',
|
|
104
|
+
user: req.user
|
|
105
|
+
});
|
|
106
|
+
res.send(html);
|
|
69
107
|
});
|
|
108
|
+
|
|
109
|
+
app.listen(3000);
|
|
70
110
|
```
|
|
71
111
|
|
|
72
|
-
|
|
73
|
-
- `filename` (string): Path to Pug template file
|
|
74
|
-
- `variables` (object, optional): Variables to interpolate
|
|
112
|
+
## Bun.js Support
|
|
75
113
|
|
|
76
|
-
|
|
114
|
+
zig-pug works seamlessly with Bun, the ultra-fast JavaScript runtime:
|
|
77
115
|
|
|
78
|
-
|
|
116
|
+
```bash
|
|
117
|
+
bun install zig-pug
|
|
118
|
+
bun run app.js
|
|
119
|
+
```
|
|
79
120
|
|
|
80
|
-
|
|
121
|
+
**Performance:** Bun is 2-5x faster than Node.js for template compilation.
|
|
81
122
|
|
|
82
|
-
|
|
83
|
-
const { ZigPugCompiler } = require('zig-pug');
|
|
123
|
+
See [examples/bun/](https://github.com/carlos-sweb/zig-pug/tree/main/examples/bun) for complete examples.
|
|
84
124
|
|
|
85
|
-
|
|
125
|
+
## Pug Syntax
|
|
86
126
|
|
|
87
|
-
|
|
88
|
-
compiler.setString('name', 'Alice');
|
|
89
|
-
compiler.setNumber('age', 30);
|
|
90
|
-
compiler.setBool('premium', true);
|
|
127
|
+
### Tags and Attributes
|
|
91
128
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
129
|
+
```pug
|
|
130
|
+
div.container
|
|
131
|
+
h1#title Hello World
|
|
132
|
+
p.text(data-id="123") Content
|
|
133
|
+
a(href="/" target="_blank") Link
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### JavaScript Interpolation
|
|
98
137
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
138
|
+
```pug
|
|
139
|
+
p Hello #{name}!
|
|
140
|
+
p Age: #{age + 1}
|
|
141
|
+
p Email: #{email.toLowerCase()}
|
|
142
|
+
p Status: #{age >= 18 ? 'Adult' : 'Minor'}
|
|
143
|
+
p Max: #{Math.max(10, 20)}
|
|
102
144
|
```
|
|
103
145
|
|
|
104
|
-
**
|
|
105
|
-
- `
|
|
106
|
-
- `
|
|
107
|
-
-
|
|
108
|
-
- `
|
|
109
|
-
- `setVariables(obj)` - Set multiple variables from object
|
|
110
|
-
- `compile(template)` - Compile template with current variables
|
|
111
|
-
- `render(template, variables)` - Set variables and compile in one call
|
|
146
|
+
**Supported JavaScript (ES5.1):**
|
|
147
|
+
- String methods: `toLowerCase()`, `toUpperCase()`, `split()`, etc.
|
|
148
|
+
- Math: `Math.max()`, `Math.min()`, `Math.random()`, etc.
|
|
149
|
+
- Operators: `+`, `-`, `*`, `/`, `%`, `&&`, `||`, `?:`
|
|
150
|
+
- Object/Array access: `obj.prop`, `arr[0]`, `arr.length`
|
|
112
151
|
|
|
113
|
-
###
|
|
152
|
+
### Conditionals
|
|
114
153
|
|
|
115
|
-
|
|
154
|
+
```pug
|
|
155
|
+
if isLoggedIn
|
|
156
|
+
p Welcome back!
|
|
157
|
+
else
|
|
158
|
+
p Please log in
|
|
116
159
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
console.log(version()); // 0.2.0
|
|
160
|
+
unless isAdmin
|
|
161
|
+
p Access denied
|
|
120
162
|
```
|
|
121
163
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
### Tags
|
|
164
|
+
### Mixins
|
|
125
165
|
|
|
126
166
|
```pug
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
span.class-name#id-name Text content
|
|
130
|
-
```
|
|
167
|
+
mixin button(text)
|
|
168
|
+
button.btn= text
|
|
131
169
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
<p>Hello, World!</p>
|
|
135
|
-
<span class="class-name" id="id-name">Text content</span>
|
|
136
|
-
</div>
|
|
170
|
+
+button('Click me')
|
|
171
|
+
+button('Submit')
|
|
137
172
|
```
|
|
138
173
|
|
|
139
|
-
###
|
|
174
|
+
### UTF-8 & Unicode Support
|
|
175
|
+
|
|
176
|
+
Full support for international characters, emoji, and symbols:
|
|
140
177
|
|
|
141
178
|
```pug
|
|
142
|
-
|
|
143
|
-
|
|
179
|
+
//! File: index.pug
|
|
180
|
+
//! Author: Carlos
|
|
181
|
+
doctype html
|
|
182
|
+
html(lang="es")
|
|
183
|
+
head
|
|
184
|
+
title #{titulo}
|
|
185
|
+
body
|
|
186
|
+
h1 ¡Bienvenido! 🎉
|
|
187
|
+
|
|
188
|
+
section.español
|
|
189
|
+
p.información Información sobre José y María
|
|
190
|
+
p#descripción Este párrafo tiene ID con acento
|
|
191
|
+
|
|
192
|
+
section.português
|
|
193
|
+
h2 Programação em português
|
|
194
|
+
p Características: ã, õ, ç
|
|
195
|
+
|
|
196
|
+
section.français
|
|
197
|
+
h2 Génération française
|
|
198
|
+
p Avec é, è, ê, ç
|
|
199
|
+
|
|
200
|
+
footer
|
|
201
|
+
p © 2025 - Creado con zig-pug 🚀
|
|
144
202
|
```
|
|
145
203
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
204
|
+
**Supported everywhere:**
|
|
205
|
+
- ✅ Text content: `p José, María, Ángel`
|
|
206
|
+
- ✅ Class names: `.información .português`
|
|
207
|
+
- ✅ ID attributes: `#descripción #größe`
|
|
208
|
+
- ✅ Comments: `// útil para depuración`
|
|
209
|
+
- ✅ Emoji: `h1 Hello 🎉 🚀 ✨`
|
|
210
|
+
- ✅ Symbols: `p © ™ € £ ¥`
|
|
211
|
+
|
|
212
|
+
### Documentation Comments
|
|
150
213
|
|
|
151
|
-
|
|
214
|
+
Use `//!` for file metadata that won't appear in output:
|
|
152
215
|
|
|
153
216
|
```pug
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
217
|
+
//! Template: homepage.pug
|
|
218
|
+
//! Author: John Doe
|
|
219
|
+
//! Version: 1.0
|
|
220
|
+
//! Description: Main landing page
|
|
221
|
+
doctype html
|
|
222
|
+
html
|
|
223
|
+
body
|
|
224
|
+
// Regular comment (appears in --pretty mode)
|
|
225
|
+
//- Code comment (never appears)
|
|
157
226
|
```
|
|
158
227
|
|
|
159
|
-
|
|
228
|
+
| Syntax | Name | In HTML? | Use Case |
|
|
229
|
+
|--------|------|----------|----------|
|
|
230
|
+
| `//!` | Documentation | ❌ Never | File metadata, notes |
|
|
231
|
+
| `//` | Buffered | ✅ Dev mode | Development debugging |
|
|
232
|
+
| `//-` | Unbuffered | ❌ Never | Code comments |
|
|
160
233
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
<p>Premium: true</p>
|
|
165
|
-
```
|
|
234
|
+
## API Reference
|
|
235
|
+
|
|
236
|
+
### `compile(template, data)`
|
|
166
237
|
|
|
167
|
-
|
|
238
|
+
Compile a template with data.
|
|
239
|
+
|
|
240
|
+
**Parameters:**
|
|
241
|
+
- `template` (string) - Pug template source
|
|
242
|
+
- `data` (object) - Variables to interpolate
|
|
168
243
|
|
|
169
|
-
|
|
244
|
+
**Returns:** (string) Compiled HTML
|
|
170
245
|
|
|
171
246
|
```javascript
|
|
172
|
-
const html = compile(
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
|
|
247
|
+
const html = zigpug.compile(
|
|
248
|
+
'p Hello #{name}!',
|
|
249
|
+
{ name: 'Alice' }
|
|
250
|
+
);
|
|
176
251
|
```
|
|
177
252
|
|
|
178
|
-
###
|
|
253
|
+
### `PugCompiler`
|
|
179
254
|
|
|
180
|
-
|
|
255
|
+
Reusable compiler with state.
|
|
181
256
|
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
257
|
+
```javascript
|
|
258
|
+
const { PugCompiler } = require('zig-pug');
|
|
259
|
+
|
|
260
|
+
const compiler = new PugCompiler();
|
|
261
|
+
compiler.set('key', 'value'); // String/Number
|
|
262
|
+
compiler.setBool('flag', true); // Boolean
|
|
188
263
|
|
|
189
|
-
|
|
190
|
-
<br />
|
|
191
|
-
<hr />
|
|
192
|
-
<img src="logo.png" />
|
|
193
|
-
<input type="text" />
|
|
264
|
+
const html = compiler.compile(template);
|
|
194
265
|
```
|
|
195
266
|
|
|
196
|
-
|
|
267
|
+
**Methods:**
|
|
268
|
+
- `set(key, value)` - Set string or number variable
|
|
269
|
+
- `setBool(key, value)` - Set boolean variable
|
|
270
|
+
- `compile(template)` - Compile template with current variables
|
|
197
271
|
|
|
198
|
-
###
|
|
272
|
+
### `version()`
|
|
273
|
+
|
|
274
|
+
Get zig-pug version.
|
|
199
275
|
|
|
200
276
|
```javascript
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const app = express();
|
|
277
|
+
console.log(zigpug.version()); // "0.2.0"
|
|
278
|
+
```
|
|
204
279
|
|
|
205
|
-
|
|
206
|
-
const html = compileFile('./views/index.pug', {
|
|
207
|
-
title: 'Home Page',
|
|
208
|
-
user: req.user
|
|
209
|
-
});
|
|
210
|
-
res.send(html);
|
|
211
|
-
});
|
|
280
|
+
## Platform Support
|
|
212
281
|
|
|
213
|
-
|
|
214
|
-
```
|
|
282
|
+
### Supported Platforms
|
|
215
283
|
|
|
216
|
-
|
|
284
|
+
- ✅ **Linux** (x64, ARM64)
|
|
285
|
+
- ✅ **macOS** (x64, Apple Silicon)
|
|
286
|
+
- ✅ **Windows** (x64)
|
|
287
|
+
- ✅ **Bun.js** (all platforms)
|
|
217
288
|
|
|
218
|
-
|
|
219
|
-
const Koa = require('koa');
|
|
220
|
-
const { compileFile } = require('zig-pug');
|
|
221
|
-
const app = new Koa();
|
|
222
|
-
|
|
223
|
-
app.use(async ctx => {
|
|
224
|
-
const html = compileFile('./views/index.pug', {
|
|
225
|
-
title: 'Home Page',
|
|
226
|
-
path: ctx.path
|
|
227
|
-
});
|
|
228
|
-
ctx.body = html;
|
|
229
|
-
});
|
|
289
|
+
### Termux/Android
|
|
230
290
|
|
|
231
|
-
|
|
232
|
-
```
|
|
291
|
+
The addon compiles on Termux but cannot be loaded due to Android namespace restrictions. Use the standalone CLI binary instead:
|
|
233
292
|
|
|
234
|
-
|
|
293
|
+
```bash
|
|
294
|
+
# Install Zig
|
|
295
|
+
pkg install zig
|
|
235
296
|
|
|
236
|
-
|
|
237
|
-
|
|
297
|
+
# Clone and build
|
|
298
|
+
git clone https://github.com/yourusername/zig-pug
|
|
299
|
+
cd zig-pug
|
|
300
|
+
zig build
|
|
238
301
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
fetch(req) {
|
|
242
|
-
const html = compile('h1 Hello from Bun!');
|
|
243
|
-
return new Response(html, {
|
|
244
|
-
headers: { 'Content-Type': 'text/html' }
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
});
|
|
302
|
+
# Use CLI
|
|
303
|
+
./zig-out/bin/zig-pug template.pug
|
|
248
304
|
```
|
|
249
305
|
|
|
306
|
+
See [docs/TERMUX.md](https://github.com/yourusername/zig-pug/blob/main/docs/TERMUX.md) for details.
|
|
307
|
+
|
|
250
308
|
## Performance
|
|
251
309
|
|
|
252
|
-
|
|
310
|
+
### Benchmark
|
|
253
311
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
- **Lightweight**: No heavy dependencies
|
|
258
|
-
- **Fast startup**: mujs has minimal overhead
|
|
312
|
+
```javascript
|
|
313
|
+
const iterations = 10000;
|
|
314
|
+
const start = Date.now();
|
|
259
315
|
|
|
260
|
-
|
|
316
|
+
for (let i = 0; i < iterations; i++) {
|
|
317
|
+
zigpug.compile(template, data);
|
|
318
|
+
}
|
|
261
319
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
-
|
|
265
|
-
|
|
320
|
+
const elapsed = Date.now() - start;
|
|
321
|
+
console.log(`${iterations} in ${elapsed}ms`);
|
|
322
|
+
// ~100-250k ops/sec depending on runtime
|
|
323
|
+
```
|
|
266
324
|
|
|
267
|
-
|
|
325
|
+
### Tips
|
|
268
326
|
|
|
269
|
-
|
|
327
|
+
1. **Reuse PugCompiler** - Faster than creating new context each time
|
|
328
|
+
2. **Pre-load templates** - Read files once at startup
|
|
329
|
+
3. **Use Bun.js** - 2-5x faster than Node.js
|
|
270
330
|
|
|
271
|
-
|
|
331
|
+
## Examples
|
|
272
332
|
|
|
273
|
-
|
|
274
|
-
- Zig 0.15+
|
|
275
|
-
- Python 3
|
|
276
|
-
- C compiler (gcc/clang)
|
|
333
|
+
See the [examples](https://github.com/yourusername/zig-pug/tree/main/examples) directory:
|
|
277
334
|
|
|
278
|
-
|
|
335
|
+
- **Node.js**: `examples/nodejs/`
|
|
336
|
+
- **Bun.js**: `examples/bun/`
|
|
337
|
+
- **Express**: `examples/nodejs/05-express-integration.js`
|
|
279
338
|
|
|
280
|
-
|
|
339
|
+
## Documentation
|
|
281
340
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
341
|
+
- **[Getting Started](https://github.com/yourusername/zig-pug/blob/main/docs/GETTING-STARTED.md)**
|
|
342
|
+
- **[Node.js Integration](https://github.com/yourusername/zig-pug/blob/main/docs/NODEJS-INTEGRATION.md)**
|
|
343
|
+
- **[Pug Syntax Reference](https://github.com/yourusername/zig-pug/blob/main/docs/PUG-SYNTAX.md)**
|
|
344
|
+
- **[API Reference](https://github.com/yourusername/zig-pug/blob/main/docs/API-REFERENCE.md)**
|
|
285
345
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
346
|
+
## Troubleshooting
|
|
347
|
+
|
|
348
|
+
### Installation fails
|
|
349
|
+
|
|
350
|
+
**Error:** `node-gyp rebuild` fails
|
|
289
351
|
|
|
290
|
-
|
|
352
|
+
**Solution:** Install build tools:
|
|
291
353
|
|
|
292
354
|
```bash
|
|
293
|
-
#
|
|
294
|
-
|
|
295
|
-
npm run example # Run example
|
|
355
|
+
# Ubuntu/Debian
|
|
356
|
+
sudo apt-get install build-essential python3
|
|
296
357
|
|
|
297
|
-
#
|
|
298
|
-
|
|
299
|
-
|
|
358
|
+
# macOS
|
|
359
|
+
xcode-select --install
|
|
360
|
+
|
|
361
|
+
# Windows
|
|
362
|
+
npm install --global windows-build-tools
|
|
300
363
|
```
|
|
301
364
|
|
|
302
|
-
|
|
365
|
+
### Module not found
|
|
303
366
|
|
|
304
|
-
|
|
367
|
+
**Error:** `Cannot find module 'zig-pug'`
|
|
305
368
|
|
|
306
|
-
|
|
369
|
+
**Solution:** Rebuild the addon:
|
|
307
370
|
|
|
371
|
+
```bash
|
|
372
|
+
cd node_modules/zig-pug
|
|
373
|
+
npm run build
|
|
308
374
|
```
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
│ N-API Addon (binding.c) │
|
|
317
|
-
│ - JavaScript API wrapper │
|
|
318
|
-
└────────────┬────────────────────────────────┘
|
|
319
|
-
│ FFI calls
|
|
320
|
-
↓
|
|
321
|
-
┌─────────────────────────────────────────────┐
|
|
322
|
-
│ libzigpug.so (Zig + mujs) │
|
|
323
|
-
│ - Tokenizer → Parser → Compiler → HTML │
|
|
324
|
-
└─────────────────────────────────────────────┘
|
|
325
|
-
```
|
|
375
|
+
|
|
376
|
+
### Compilation errors
|
|
377
|
+
|
|
378
|
+
If you encounter compilation errors, please [open an issue](https://github.com/yourusername/zig-pug/issues) with:
|
|
379
|
+
- Your OS and version
|
|
380
|
+
- Node.js version (`node --version`)
|
|
381
|
+
- Complete error output
|
|
326
382
|
|
|
327
383
|
## Contributing
|
|
328
384
|
|
|
329
|
-
Contributions are welcome! Please
|
|
385
|
+
Contributions are welcome! Please:
|
|
386
|
+
|
|
387
|
+
1. Fork the repository
|
|
388
|
+
2. Create a feature branch
|
|
389
|
+
3. Make your changes
|
|
390
|
+
4. Run tests: `npm test`
|
|
391
|
+
5. Submit a pull request
|
|
330
392
|
|
|
331
393
|
## License
|
|
332
394
|
|
|
333
|
-
MIT License - see [LICENSE](LICENSE) for details.
|
|
395
|
+
MIT License - see [LICENSE](https://github.com/yourusername/zig-pug/blob/main/LICENSE) for details.
|
|
396
|
+
|
|
397
|
+
## Credits
|
|
398
|
+
|
|
399
|
+
- **[Pug](https://pugjs.org/)** - Original inspiration
|
|
400
|
+
- **[Zig](https://ziglang.org/)** - Programming language
|
|
401
|
+
- **[mujs](https://mujs.com/)** - Embedded JavaScript engine
|
|
402
|
+
- **[Artifex Software](https://artifex.com/)** - Creators of mujs
|
|
334
403
|
|
|
335
404
|
## Links
|
|
336
405
|
|
|
337
|
-
-
|
|
338
|
-
-
|
|
339
|
-
-
|
|
340
|
-
-
|
|
406
|
+
- **GitHub**: https://github.com/yourusername/zig-pug
|
|
407
|
+
- **npm**: https://www.npmjs.com/package/zig-pug
|
|
408
|
+
- **Issues**: https://github.com/yourusername/zig-pug/issues
|
|
409
|
+
- **Documentation**: https://github.com/yourusername/zig-pug#readme
|
|
341
410
|
|
|
342
|
-
|
|
411
|
+
---
|
|
343
412
|
|
|
344
|
-
|
|
345
|
-
- Powered by [Zig](https://ziglang.org/) and [mujs](https://mujs.com/)
|
|
346
|
-
- Inspired by the original [Pug](https://pugjs.org/) template engine
|
|
413
|
+
Made with ❤️ using Zig 0.15.2 and mujs
|
package/binding.gyp
CHANGED
|
@@ -3,25 +3,22 @@
|
|
|
3
3
|
{
|
|
4
4
|
"target_name": "zigpug",
|
|
5
5
|
"sources": [
|
|
6
|
-
"binding.c"
|
|
6
|
+
"binding.c",
|
|
7
|
+
"vendor/mujs/one.c"
|
|
7
8
|
],
|
|
8
9
|
"include_dirs": [
|
|
9
10
|
"include",
|
|
10
|
-
"
|
|
11
|
+
"vendor/mujs"
|
|
11
12
|
],
|
|
12
13
|
"libraries": [
|
|
13
|
-
"-L<(module_root_dir)",
|
|
14
|
-
"-lzigpug",
|
|
15
14
|
"-lm"
|
|
16
15
|
],
|
|
17
16
|
"cflags": [
|
|
18
|
-
"-std=c99"
|
|
17
|
+
"-std=c99",
|
|
18
|
+
"-DHAVE_STRLCPY=0"
|
|
19
19
|
],
|
|
20
20
|
"defines": [
|
|
21
21
|
"NAPI_VERSION=8"
|
|
22
|
-
],
|
|
23
|
-
"ldflags": [
|
|
24
|
-
"-Wl,-rpath,'$$ORIGIN'"
|
|
25
22
|
]
|
|
26
23
|
}
|
|
27
24
|
]
|
package/index.js
CHANGED
|
@@ -3,32 +3,12 @@
|
|
|
3
3
|
* Powered by Zig and mujs
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const fs = require('fs');
|
|
9
|
-
|
|
10
|
-
// Try to find precompiled binary first, fallback to development build
|
|
11
|
-
let binding;
|
|
12
|
-
try {
|
|
13
|
-
const binding_path = binary.find(path.resolve(path.join(__dirname, './package.json')));
|
|
14
|
-
binding = require(binding_path);
|
|
15
|
-
} catch (err) {
|
|
16
|
-
// Fallback to development build location
|
|
17
|
-
const dev_path = path.join(__dirname, 'build', 'Release', 'zigpug.node');
|
|
18
|
-
if (fs.existsSync(dev_path)) {
|
|
19
|
-
binding = require(dev_path);
|
|
20
|
-
} else {
|
|
21
|
-
throw new Error(
|
|
22
|
-
'zig-pug native addon not found. ' +
|
|
23
|
-
'Please build it with: cd .. && zig build node'
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
6
|
+
const binding = require('./build/Release/zigpug.node');
|
|
27
7
|
|
|
28
8
|
/**
|
|
29
|
-
*
|
|
9
|
+
* PugCompiler class - High-level API for compiling Pug templates
|
|
30
10
|
*/
|
|
31
|
-
class
|
|
11
|
+
class PugCompiler {
|
|
32
12
|
constructor() {
|
|
33
13
|
this.context = binding.createContext();
|
|
34
14
|
if (!this.context) {
|
|
@@ -40,7 +20,7 @@ class ZigPugCompiler {
|
|
|
40
20
|
* Set a string variable in the template context
|
|
41
21
|
* @param {string} key - Variable name
|
|
42
22
|
* @param {string} value - String value
|
|
43
|
-
* @returns {
|
|
23
|
+
* @returns {PugCompiler} - Returns this for chaining
|
|
44
24
|
*/
|
|
45
25
|
setString(key, value) {
|
|
46
26
|
if (typeof key !== 'string') {
|
|
@@ -61,7 +41,7 @@ class ZigPugCompiler {
|
|
|
61
41
|
* Set a number variable in the template context
|
|
62
42
|
* @param {string} key - Variable name
|
|
63
43
|
* @param {number} value - Number value
|
|
64
|
-
* @returns {
|
|
44
|
+
* @returns {PugCompiler} - Returns this for chaining
|
|
65
45
|
*/
|
|
66
46
|
setNumber(key, value) {
|
|
67
47
|
if (typeof key !== 'string') {
|
|
@@ -82,7 +62,7 @@ class ZigPugCompiler {
|
|
|
82
62
|
* Set a boolean variable in the template context
|
|
83
63
|
* @param {string} key - Variable name
|
|
84
64
|
* @param {boolean} value - Boolean value
|
|
85
|
-
* @returns {
|
|
65
|
+
* @returns {PugCompiler} - Returns this for chaining
|
|
86
66
|
*/
|
|
87
67
|
setBool(key, value) {
|
|
88
68
|
if (typeof key !== 'string') {
|
|
@@ -103,7 +83,7 @@ class ZigPugCompiler {
|
|
|
103
83
|
* Set a variable (automatically detects type)
|
|
104
84
|
* @param {string} key - Variable name
|
|
105
85
|
* @param {string|number|boolean} value - Value of any supported type
|
|
106
|
-
* @returns {
|
|
86
|
+
* @returns {PugCompiler} - Returns this for chaining
|
|
107
87
|
*/
|
|
108
88
|
set(key, value) {
|
|
109
89
|
if (typeof value === 'string') {
|
|
@@ -120,7 +100,7 @@ class ZigPugCompiler {
|
|
|
120
100
|
/**
|
|
121
101
|
* Set multiple variables from an object
|
|
122
102
|
* @param {Object} variables - Object with key-value pairs
|
|
123
|
-
* @returns {
|
|
103
|
+
* @returns {PugCompiler} - Returns this for chaining
|
|
124
104
|
*/
|
|
125
105
|
setVariables(variables) {
|
|
126
106
|
if (typeof variables !== 'object' || variables === null) {
|
|
@@ -171,7 +151,7 @@ class ZigPugCompiler {
|
|
|
171
151
|
* @returns {string} - Compiled HTML
|
|
172
152
|
*/
|
|
173
153
|
function compile(template, variables = {}) {
|
|
174
|
-
const compiler = new
|
|
154
|
+
const compiler = new PugCompiler();
|
|
175
155
|
return compiler.render(template, variables);
|
|
176
156
|
}
|
|
177
157
|
|
|
@@ -196,10 +176,8 @@ function version() {
|
|
|
196
176
|
}
|
|
197
177
|
|
|
198
178
|
module.exports = {
|
|
199
|
-
|
|
179
|
+
PugCompiler,
|
|
200
180
|
compile,
|
|
201
181
|
compileFile,
|
|
202
|
-
version
|
|
203
|
-
// Backward compatibility alias
|
|
204
|
-
PugCompiler: ZigPugCompiler
|
|
182
|
+
version
|
|
205
183
|
};
|
package/index.mjs
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zig-pug - Pug template engine for Node.js (ES Module version)
|
|
3
|
+
* Powered by Zig and mujs
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { createRequire } from 'module';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
import { dirname } from 'path';
|
|
9
|
+
import { readFileSync } from 'fs';
|
|
10
|
+
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = dirname(__filename);
|
|
13
|
+
const require = createRequire(import.meta.url);
|
|
14
|
+
|
|
15
|
+
const binding = require('./build/Release/zigpug.node');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* PugCompiler class - High-level API for compiling Pug templates
|
|
19
|
+
*/
|
|
20
|
+
export class PugCompiler {
|
|
21
|
+
constructor() {
|
|
22
|
+
this.context = binding.createContext();
|
|
23
|
+
if (!this.context) {
|
|
24
|
+
throw new Error('Failed to create zig-pug context');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Set a string variable in the template context
|
|
30
|
+
* @param {string} key - Variable name
|
|
31
|
+
* @param {string} value - String value
|
|
32
|
+
* @returns {PugCompiler} - Returns this for chaining
|
|
33
|
+
*/
|
|
34
|
+
setString(key, value) {
|
|
35
|
+
if (typeof key !== 'string') {
|
|
36
|
+
throw new TypeError('Key must be a string');
|
|
37
|
+
}
|
|
38
|
+
if (typeof value !== 'string') {
|
|
39
|
+
throw new TypeError('Value must be a string');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const success = binding.setString(this.context, key, value);
|
|
43
|
+
if (!success) {
|
|
44
|
+
throw new Error(`Failed to set string variable: ${key}`);
|
|
45
|
+
}
|
|
46
|
+
return this;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Set a number variable in the template context
|
|
51
|
+
* @param {string} key - Variable name
|
|
52
|
+
* @param {number} value - Number value
|
|
53
|
+
* @returns {PugCompiler} - Returns this for chaining
|
|
54
|
+
*/
|
|
55
|
+
setNumber(key, value) {
|
|
56
|
+
if (typeof key !== 'string') {
|
|
57
|
+
throw new TypeError('Key must be a string');
|
|
58
|
+
}
|
|
59
|
+
if (typeof value !== 'number') {
|
|
60
|
+
throw new TypeError('Value must be a number');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const success = binding.setNumber(this.context, key, Math.floor(value));
|
|
64
|
+
if (!success) {
|
|
65
|
+
throw new Error(`Failed to set number variable: ${key}`);
|
|
66
|
+
}
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Set a boolean variable in the template context
|
|
72
|
+
* @param {string} key - Variable name
|
|
73
|
+
* @param {boolean} value - Boolean value
|
|
74
|
+
* @returns {PugCompiler} - Returns this for chaining
|
|
75
|
+
*/
|
|
76
|
+
setBool(key, value) {
|
|
77
|
+
if (typeof key !== 'string') {
|
|
78
|
+
throw new TypeError('Key must be a string');
|
|
79
|
+
}
|
|
80
|
+
if (typeof value !== 'boolean') {
|
|
81
|
+
throw new TypeError('Value must be a boolean');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const success = binding.setBool(this.context, key, value);
|
|
85
|
+
if (!success) {
|
|
86
|
+
throw new Error(`Failed to set boolean variable: ${key}`);
|
|
87
|
+
}
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Set a variable (automatically detects type)
|
|
93
|
+
* @param {string} key - Variable name
|
|
94
|
+
* @param {string|number|boolean} value - Value of any supported type
|
|
95
|
+
* @returns {PugCompiler} - Returns this for chaining
|
|
96
|
+
*/
|
|
97
|
+
set(key, value) {
|
|
98
|
+
if (typeof value === 'string') {
|
|
99
|
+
return this.setString(key, value);
|
|
100
|
+
} else if (typeof value === 'number') {
|
|
101
|
+
return this.setNumber(key, value);
|
|
102
|
+
} else if (typeof value === 'boolean') {
|
|
103
|
+
return this.setBool(key, value);
|
|
104
|
+
} else {
|
|
105
|
+
throw new TypeError(`Unsupported value type for key "${key}": ${typeof value}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Set multiple variables from an object
|
|
111
|
+
* @param {Object} variables - Object with key-value pairs
|
|
112
|
+
* @returns {PugCompiler} - Returns this for chaining
|
|
113
|
+
*/
|
|
114
|
+
setVariables(variables) {
|
|
115
|
+
if (typeof variables !== 'object' || variables === null) {
|
|
116
|
+
throw new TypeError('Variables must be an object');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
120
|
+
this.set(key, value);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Compile a Pug template to HTML
|
|
128
|
+
* @param {string} template - Pug template string
|
|
129
|
+
* @returns {string} - Compiled HTML
|
|
130
|
+
*/
|
|
131
|
+
compile(template) {
|
|
132
|
+
if (typeof template !== 'string') {
|
|
133
|
+
throw new TypeError('Template must be a string');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const html = binding.compile(this.context, template);
|
|
137
|
+
if (!html) {
|
|
138
|
+
throw new Error('Failed to compile template');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return html;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Compile a template with variables in one call
|
|
146
|
+
* @param {string} template - Pug template string
|
|
147
|
+
* @param {Object} variables - Variables to set before compiling
|
|
148
|
+
* @returns {string} - Compiled HTML
|
|
149
|
+
*/
|
|
150
|
+
render(template, variables = {}) {
|
|
151
|
+
this.setVariables(variables);
|
|
152
|
+
return this.compile(template);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Convenience function to compile a template with variables
|
|
158
|
+
* @param {string} template - Pug template string
|
|
159
|
+
* @param {Object} variables - Variables for the template
|
|
160
|
+
* @returns {string} - Compiled HTML
|
|
161
|
+
*/
|
|
162
|
+
export function compile(template, variables = {}) {
|
|
163
|
+
const compiler = new PugCompiler();
|
|
164
|
+
return compiler.render(template, variables);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Convenience function to compile a template from a file
|
|
169
|
+
* @param {string} filename - Path to the Pug template file
|
|
170
|
+
* @param {Object} variables - Variables for the template
|
|
171
|
+
* @returns {string} - Compiled HTML
|
|
172
|
+
*/
|
|
173
|
+
export function compileFile(filename, variables = {}) {
|
|
174
|
+
const template = readFileSync(filename, 'utf8');
|
|
175
|
+
return compile(template, variables);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Get the zig-pug version
|
|
180
|
+
* @returns {string} - Version string
|
|
181
|
+
*/
|
|
182
|
+
export function version() {
|
|
183
|
+
return binding.version();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Default export for compatibility
|
|
187
|
+
export default {
|
|
188
|
+
PugCompiler,
|
|
189
|
+
compile,
|
|
190
|
+
compileFile,
|
|
191
|
+
version
|
|
192
|
+
};
|
package/package.json
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zig-pug",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "High-performance Pug template engine powered by Zig and mujs
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "High-performance Pug template engine powered by Zig and mujs. Native N-API addon with ES5.1 JavaScript support, full UTF-8 (emoji, accents), documentation comments (//!), and fast compilation. Compatible with Node.js and Bun.",
|
|
5
|
+
"type": "commonjs",
|
|
5
6
|
"main": "index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./index.mjs",
|
|
10
|
+
"require": "./index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
6
13
|
"scripts": {
|
|
7
|
-
"install": "node-
|
|
8
|
-
"build": "
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"clean": "node-gyp clean && rm -rf ../zig-out/nodejs lib/binding",
|
|
13
|
-
"test": "LD_LIBRARY_PATH=../zig-out/nodejs:$LD_LIBRARY_PATH node test/test.js",
|
|
14
|
-
"example": "LD_LIBRARY_PATH=../zig-out/nodejs:$LD_LIBRARY_PATH node example.js",
|
|
15
|
-
"package": "node-pre-gyp package",
|
|
16
|
-
"upload": "node-pre-gyp publish",
|
|
17
|
-
"upload:github": "node scripts/upload-binary.js",
|
|
14
|
+
"install": "node-gyp rebuild",
|
|
15
|
+
"build": "node-gyp configure build",
|
|
16
|
+
"rebuild": "node-gyp rebuild",
|
|
17
|
+
"clean": "node-gyp clean",
|
|
18
|
+
"test": "node test/test.js",
|
|
18
19
|
"prepublishOnly": "npm run build"
|
|
19
20
|
},
|
|
20
21
|
"keywords": [
|
|
@@ -40,11 +41,22 @@
|
|
|
40
41
|
"view-engine",
|
|
41
42
|
"express",
|
|
42
43
|
"jade",
|
|
43
|
-
"haml"
|
|
44
|
+
"haml",
|
|
45
|
+
"utf-8",
|
|
46
|
+
"utf8",
|
|
47
|
+
"unicode",
|
|
48
|
+
"emoji",
|
|
49
|
+
"i18n",
|
|
50
|
+
"internationalization",
|
|
51
|
+
"multilingual",
|
|
52
|
+
"spanish",
|
|
53
|
+
"portuguese",
|
|
54
|
+
"french",
|
|
55
|
+
"german"
|
|
44
56
|
],
|
|
45
57
|
"author": {
|
|
46
|
-
"name": "
|
|
47
|
-
"url": "https://github.com/carlos-sweb"
|
|
58
|
+
"name": "zig-pug contributors",
|
|
59
|
+
"url": "https://github.com/carlos-sweb/zig-pug/graphs/contributors"
|
|
48
60
|
},
|
|
49
61
|
"license": "MIT",
|
|
50
62
|
"repository": {
|
|
@@ -59,23 +71,19 @@
|
|
|
59
71
|
"engines": {
|
|
60
72
|
"node": ">=14.0.0"
|
|
61
73
|
},
|
|
62
|
-
"dependencies": {
|
|
63
|
-
"@mapbox/node-pre-gyp": "^1.0.11"
|
|
64
|
-
},
|
|
74
|
+
"dependencies": {},
|
|
65
75
|
"devDependencies": {
|
|
66
|
-
"node-gyp": "^10.0.0"
|
|
67
|
-
"aws-sdk": "^2.1691.0"
|
|
76
|
+
"node-gyp": "^10.0.0"
|
|
68
77
|
},
|
|
69
78
|
"gypfile": true,
|
|
70
79
|
"binary": {
|
|
71
80
|
"module_name": "zigpug",
|
|
72
|
-
"module_path": "./
|
|
73
|
-
"remote_path": "./{version}",
|
|
74
|
-
"package_name": "{module_name}-v{version}-{node_abi}-{platform}-{arch}.tar.gz",
|
|
81
|
+
"module_path": "./build/Release/",
|
|
75
82
|
"host": "https://github.com/carlos-sweb/zig-pug/releases/download/"
|
|
76
83
|
},
|
|
77
84
|
"files": [
|
|
78
85
|
"index.js",
|
|
86
|
+
"index.mjs",
|
|
79
87
|
"binding.c",
|
|
80
88
|
"binding.gyp",
|
|
81
89
|
"common.gypi",
|