Skip to content

Commit d4b7f60

Browse files
authored
Properly handle errors originating from included files when compileDebug is enabled (#3269)
1 parent d6f0615 commit d4b7f60

File tree

6 files changed

+98
-30
lines changed

6 files changed

+98
-30
lines changed

packages/pug-runtime/index.js

+10-6
Original file line numberDiff line numberDiff line change
@@ -247,18 +247,22 @@ function pug_rethrow(err, filename, lineno, str) {
247247
err.message += ' on line ' + lineno;
248248
throw err;
249249
}
250+
var context, lines, start, end;
250251
try {
251-
str = str || require('fs').readFileSync(filename, 'utf8');
252+
str = str || require('fs').readFileSync(filename, {encoding: 'utf8'});
253+
context = 3;
254+
lines = str.split('\n');
255+
start = Math.max(lineno - context, 0);
256+
end = Math.min(lines.length, lineno + context);
252257
} catch (ex) {
258+
err.message +=
259+
' - could not read from ' + filename + ' (' + ex.message + ')';
253260
pug_rethrow(err, null, lineno);
261+
return;
254262
}
255-
var context = 3,
256-
lines = str.split('\n'),
257-
start = Math.max(lineno - context, 0),
258-
end = Math.min(lines.length, lineno + context);
259263

260264
// Error context
261-
var context = lines
265+
context = lines
262266
.slice(start, end)
263267
.map(function(line, i) {
264268
var curr = i + start + 1;

packages/pug-runtime/test/index.test.js

+47
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,50 @@ addTest('style', function(style) {
221221
expect(style({foo: 'bar'})).toBe('foo:bar;');
222222
expect(style({foo: 'bar', baz: 'bash'})).toBe('foo:bar;baz:bash;');
223223
});
224+
225+
describe('rethrow', () => {
226+
it('should rethrow error', () => {
227+
const err = new Error();
228+
try {
229+
runtime.rethrow(err, 'foo.pug', 3);
230+
} catch (e) {
231+
expect(e).toBe(err);
232+
return;
233+
}
234+
235+
throw new Error('expected rethrow to throw');
236+
});
237+
238+
it('should rethrow error with str', () => {
239+
const err = new Error();
240+
try {
241+
runtime.rethrow(err, 'foo.pug', 3, 'hello world');
242+
} catch (e) {
243+
expect(e).toBe(err);
244+
expect(e.message.trim()).toBe(
245+
`
246+
foo.pug:3
247+
1| hello world`.trim()
248+
);
249+
return;
250+
}
251+
252+
throw new Error('expected rethrow to throw');
253+
});
254+
255+
it('should handle bad arguments gracefully', () => {
256+
const err = new Error('hello world');
257+
const str = {not: 'a string'};
258+
try {
259+
runtime.rethrow(err, 'foo.pug', 3, str);
260+
} catch (e) {
261+
expect(e).toBe(err);
262+
expect(e.message).toBe(
263+
'hello world - could not read from foo.pug (str.split is not a function) on line 3'
264+
);
265+
return;
266+
}
267+
268+
throw new Error('expected rethrow to throw');
269+
});
270+
});

packages/pug/lib/index.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,9 @@ function compileBody(str, options) {
164164
contents = load.read(filename, loadOptions);
165165
}
166166

167-
debug_sources[filename] = contents;
167+
debug_sources[filename] = Buffer.isBuffer(contents)
168+
? contents.toString('utf8')
169+
: contents;
168170
return contents;
169171
},
170172
});

packages/pug/test/__snapshots__/pug.test.js.snap

+26-22
Original file line numberDiff line numberDiff line change
@@ -56,31 +56,35 @@ exports[`pug .compileClient() should support module syntax in pug.compileClient(
5656
return c !== r ? s + a.substring(c, r) : s;
5757
}
5858
var pug_match_html = /[\\"&<>]/;
59-
function pug_rethrow(n, e, t, r) {
60-
if (!(n instanceof Error)) throw n;
61-
if (!((\\"undefined\\" == typeof window && e) || r))
62-
throw ((n.message += \\" on line \\" + t), n);
59+
function pug_rethrow(e, n, r, t) {
60+
if (!(e instanceof Error)) throw e;
61+
if (!((\\"undefined\\" == typeof window && n) || t))
62+
throw ((e.message += \\" on line \\" + r), e);
63+
var o, a, i, s;
6364
try {
64-
r = r || require(\\"fs\\").readFileSync(e, \\"utf8\\");
65-
} catch (e) {
66-
pug_rethrow(n, null, t);
65+
(t = t || require(\\"fs\\").readFileSync(n, { encoding: \\"utf8\\" })),
66+
(o = 3),
67+
(a = t.split(\\"\\\\n\\")),
68+
(i = Math.max(r - o, 0)),
69+
(s = Math.min(a.length, r + o));
70+
} catch (t) {
71+
return (
72+
(e.message += \\" - could not read from \\" + n + \\" (\\" + t.message + \\")\\"),
73+
void pug_rethrow(e, null, r)
74+
);
6775
}
68-
var a = 3,
69-
i = r.split(\\"\\\\n\\"),
70-
o = Math.max(t - a, 0),
71-
h = Math.min(i.length, t + a),
72-
a = i
73-
.slice(o, h)
74-
.map(function(n, e) {
75-
var r = e + o + 1;
76-
return (r == t ? \\" > \\" : \\" \\") + r + \\"| \\" + n;
77-
})
78-
.join(\\"\\\\n\\");
79-
n.path = e;
76+
(o = a
77+
.slice(i, s)
78+
.map(function(e, n) {
79+
var t = n + i + 1;
80+
return (t == r ? \\" > \\" : \\" \\") + t + \\"| \\" + e;
81+
})
82+
.join(\\"\\\\n\\")),
83+
(e.path = n);
8084
try {
81-
n.message = (e || \\"Pug\\") + \\":\\" + t + \\"\\\\n\\" + a + \\"\\\\n\\\\n\\" + n.message;
82-
} catch (n) {}
83-
throw n;
85+
e.message = (n || \\"Pug\\") + \\":\\" + r + \\"\\\\n\\" + o + \\"\\\\n\\\\n\\" + e.message;
86+
} catch (e) {}
87+
throw e;
8488
}
8589
function template(locals) {
8690
var pug_html = \\"\\",

packages/pug/test/error.reporting.test.js

+12
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,19 @@ describe('error reporting', function() {
8080
expect(err.message).toMatch(/[\\\/]include.locals.error.pug:2/);
8181
expect(err.message).toMatch(/foo\(/);
8282
});
83+
84+
it('handles compileDebug option properly', function() {
85+
var err = getFileError(
86+
__dirname + '/fixtures/compile.with.include.locals.error.pug',
87+
{
88+
compileDebug: true,
89+
}
90+
);
91+
expect(err.message).toMatch(/[\\\/]include.locals.error.pug:2/);
92+
expect(err.message).toMatch(/foo is not a function/);
93+
});
8394
});
95+
8496
describe('with a layout (without block) with an include (syntax)', function() {
8597
it('includes detail of where the error was thrown including the filename', function() {
8698
var err = getFileError(

packages/pug/test/pug.test.js

-1
Original file line numberDiff line numberDiff line change
@@ -1243,7 +1243,6 @@ describe('pug', function() {
12431243
__dirname + '/temp/input-compileModuleFileClient.js',
12441244
fn
12451245
);
1246-
var expected = '<div class="bar">baz</div>';
12471246
var fn = require(__dirname + '/temp/input-compileModuleFileClient.js');
12481247
expect(fn({foo: 'baz'})).toBe('<div class="bar">baz</div>');
12491248
});

0 commit comments

Comments
 (0)