fix: add scoped error logging for lexer/parser errors

- Add std.log.scoped(.pugz) to template.zig and view_engine.zig
- Log detailed error info (code, line, column, message) when parsing fails
- Log template path context in ViewEngine on parse errors
- Remove debug print from lexer, use proper scoped logging instead
- Move benchmarks, docs, examples, playground, tests out of src/ to project root
- Update build.zig and documentation paths accordingly
- Bump version to 0.3.1
This commit is contained in:
2026-01-25 17:10:02 +05:30
parent 9d3b729c6c
commit aaf6a1af2d
1148 changed files with 57 additions and 330 deletions

View File

@@ -0,0 +1,301 @@
'use strict';
var assert = require('assert');
var utils = require('util');
var attrs = require('../');
var options;
function test(input, expected, locals) {
var opts = options;
locals = locals || {};
locals.pug = locals.pug || require('pug-runtime');
it(
utils.inspect(input).replace(/\n/g, '') + ' => ' + utils.inspect(expected),
function() {
var src = attrs(input, opts);
var localKeys = Object.keys(locals).sort();
var output = Function(
localKeys.join(', '),
'return (' + src + ');'
).apply(
null,
localKeys.map(function(key) {
return locals[key];
})
);
if (opts.format === 'html') {
expect(output).toBe(expected);
} else {
expect(output).toEqual(expected);
}
}
);
}
function withOptions(opts, fn) {
describe('options: ' + utils.inspect(opts), function() {
options = opts;
fn();
});
}
withOptions(
{
terse: true,
format: 'html',
runtime: function(name) {
return 'pug.' + name;
},
},
function() {
test([], '');
test([{name: 'foo', val: 'false', mustEscape: true}], '');
test([{name: 'foo', val: 'true', mustEscape: true}], ' foo');
test([{name: 'foo', val: false, mustEscape: true}], '');
test([{name: 'foo', val: true, mustEscape: true}], ' foo');
test([{name: 'foo', val: 'foo', mustEscape: true}], '', {foo: false});
test([{name: 'foo', val: 'foo', mustEscape: true}], ' foo', {foo: true});
test([{name: 'foo', val: '"foo"', mustEscape: true}], ' foo="foo"');
test(
[
{name: 'foo', val: '"foo"', mustEscape: true},
{name: 'bar', val: '"bar"', mustEscape: true},
],
' foo="foo" bar="bar"'
);
test([{name: 'foo', val: 'foo', mustEscape: true}], ' foo="fooo"', {
foo: 'fooo',
});
test(
[
{name: 'foo', val: 'foo', mustEscape: true},
{name: 'bar', val: 'bar', mustEscape: true},
],
' foo="fooo" bar="baro"',
{foo: 'fooo', bar: 'baro'}
);
test(
[{name: 'style', val: '{color: "red"}', mustEscape: true}],
' style="color:red;"'
);
test(
[{name: 'style', val: '{color: color}', mustEscape: true}],
' style="color:red;"',
{color: 'red'}
);
test(
[
{name: 'class', val: '"foo"', mustEscape: true},
{name: 'class', val: '["bar", "baz"]', mustEscape: true},
],
' class="foo bar baz"'
);
test(
[
{name: 'class', val: '{foo: foo}', mustEscape: true},
{name: 'class', val: '["bar", "baz"]', mustEscape: true},
],
' class="foo bar baz"',
{foo: true}
);
test(
[
{name: 'class', val: '{foo: foo}', mustEscape: true},
{name: 'class', val: '["bar", "baz"]', mustEscape: true},
],
' class="bar baz"',
{foo: false}
);
test(
[
{name: 'class', val: 'foo', mustEscape: true},
{name: 'class', val: '"<str>"', mustEscape: true},
],
' class="&lt;foo&gt; &lt;str&gt;"',
{foo: '<foo>'}
);
test(
[
{name: 'foo', val: '"foo"', mustEscape: true},
{name: 'class', val: '["bar", "baz"]', mustEscape: true},
],
' class="bar baz" foo="foo"'
);
test(
[
{name: 'class', val: '["bar", "baz"]', mustEscape: true},
{name: 'foo', val: '"foo"', mustEscape: true},
],
' class="bar baz" foo="foo"'
);
test([{name: 'foo', val: '"<foo>"', mustEscape: false}], ' foo="<foo>"');
test(
[{name: 'foo', val: '"<foo>"', mustEscape: true}],
' foo="&lt;foo&gt;"'
);
test([{name: 'foo', val: 'foo', mustEscape: false}], ' foo="<foo>"', {
foo: '<foo>',
});
test([{name: 'foo', val: 'foo', mustEscape: true}], ' foo="&lt;foo&gt;"', {
foo: '<foo>',
});
}
);
withOptions(
{
terse: false,
format: 'html',
runtime: function(name) {
return 'pug.' + name;
},
},
function() {
test([{name: 'foo', val: 'false', mustEscape: true}], '');
test([{name: 'foo', val: 'true', mustEscape: true}], ' foo="foo"');
test([{name: 'foo', val: false, mustEscape: true}], '');
test([{name: 'foo', val: true, mustEscape: true}], ' foo="foo"');
test([{name: 'foo', val: 'foo', mustEscape: true}], '', {foo: false});
test([{name: 'foo', val: 'foo', mustEscape: true}], ' foo="foo"', {
foo: true,
});
}
);
withOptions(
{
terse: true,
format: 'object',
runtime: function(name) {
return 'pug.' + name;
},
},
function() {
test([], {});
test([{name: 'foo', val: 'false', mustEscape: true}], {foo: false});
test([{name: 'foo', val: 'true', mustEscape: true}], {foo: true});
test([{name: 'foo', val: false, mustEscape: true}], {foo: false});
test([{name: 'foo', val: true, mustEscape: true}], {foo: true});
test(
[{name: 'foo', val: 'foo', mustEscape: true}],
{foo: false},
{foo: false}
);
test(
[{name: 'foo', val: 'foo', mustEscape: true}],
{foo: true},
{foo: true}
);
test([{name: 'foo', val: '"foo"', mustEscape: true}], {foo: 'foo'});
test(
[
{name: 'foo', val: '"foo"', mustEscape: true},
{name: 'bar', val: '"bar"', mustEscape: true},
],
{foo: 'foo', bar: 'bar'}
);
test(
[{name: 'foo', val: 'foo', mustEscape: true}],
{foo: 'fooo'},
{foo: 'fooo'}
);
test(
[
{name: 'foo', val: 'foo', mustEscape: true},
{name: 'bar', val: 'bar', mustEscape: true},
],
{foo: 'fooo', bar: 'baro'},
{foo: 'fooo', bar: 'baro'}
);
test([{name: 'style', val: '{color: "red"}', mustEscape: true}], {
style: 'color:red;',
});
test(
[{name: 'style', val: '{color: color}', mustEscape: true}],
{style: 'color:red;'},
{color: 'red'}
);
test(
[
{name: 'class', val: '"foo"', mustEscape: true},
{name: 'class', val: '["bar", "baz"]', mustEscape: true},
],
{class: 'foo bar baz'}
);
test(
[
{name: 'class', val: '{foo: foo}', mustEscape: true},
{name: 'class', val: '["bar", "baz"]', mustEscape: true},
],
{class: 'foo bar baz'},
{foo: true}
);
test(
[
{name: 'class', val: '{foo: foo}', mustEscape: true},
{name: 'class', val: '["bar", "baz"]', mustEscape: true},
],
{class: 'bar baz'},
{foo: false}
);
test(
[
{name: 'class', val: 'foo', mustEscape: true},
{name: 'class', val: '"<str>"', mustEscape: true},
],
{class: '&lt;foo&gt; &lt;str&gt;'},
{foo: '<foo>'}
);
test(
[
{name: 'foo', val: '"foo"', mustEscape: true},
{name: 'class', val: '["bar", "baz"]', mustEscape: true},
],
{class: 'bar baz', foo: 'foo'}
);
test(
[
{name: 'class', val: '["bar", "baz"]', mustEscape: true},
{name: 'foo', val: '"foo"', mustEscape: true},
],
{class: 'bar baz', foo: 'foo'}
);
test([{name: 'foo', val: '"<foo>"', mustEscape: false}], {foo: '<foo>'});
test([{name: 'foo', val: '"<foo>"', mustEscape: true}], {
foo: '&lt;foo&gt;',
});
test(
[{name: 'foo', val: 'foo', mustEscape: false}],
{foo: '<foo>'},
{foo: '<foo>'}
);
test(
[{name: 'foo', val: 'foo', mustEscape: true}],
{foo: '&lt;foo&gt;'},
{foo: '<foo>'}
);
}
);
withOptions(
{
terse: false,
format: 'object',
runtime: function(name) {
return 'pug.' + name;
},
},
function() {
test([{name: 'foo', val: 'false', mustEscape: true}], {foo: false});
test([{name: 'foo', val: 'true', mustEscape: true}], {foo: true});
test([{name: 'foo', val: false, mustEscape: true}], {foo: false});
test([{name: 'foo', val: true, mustEscape: true}], {foo: true});
test(
[{name: 'foo', val: 'foo', mustEscape: true}],
{foo: false},
{foo: false}
);
test(
[{name: 'foo', val: 'foo', mustEscape: true}],
{foo: true},
{foo: true}
);
}
);