diff --git a/lib/extend/tag.js b/lib/extend/tag.js index 3ad227dc0b..1b167565c1 100644 --- a/lib/extend/tag.js +++ b/lib/extend/tag.js @@ -1,7 +1,7 @@ 'use strict'; const { stripIndent } = require('hexo-util'); -const { cyan } = require('chalk'); +const { cyan, magenta, red } = require('chalk'); const { Environment } = require('nunjucks'); const Promise = require('bluebird'); const placeholder = '\uFFFC'; @@ -129,7 +129,7 @@ const LINES_OF_CONTEXT = 5; const getContext = (lines, errLine, location, type) => { const message = [ - location + ' ' + type, + location + ' ' + red(type), cyan(' ===== Context Dump ====='), cyan(' === (line number probably different from source) ===') ]; @@ -158,14 +158,17 @@ const getContext = (lines, errLine, location, type) => { * @param {string} str string input for Nunjucks * @return {Error} New error object with embedded context */ -const formatNunjucksError = (err, input) => { +const formatNunjucksError = (err, input, source = '') => { const match = err.message.match(/Line (\d+), Column \d+/); if (!match) return err; const errLine = parseInt(match[1], 10); if (isNaN(errLine)) return err; // trim useless info from Nunjucks Error - const splited = err.message.replace('(unknown path)', '').split('\n'); + const splited = err.message.replace('(unknown path)', () => { + if (source) return magenta(source); + return ''; + }).split('\n'); const e = new Error(); e.name = 'Nunjucks Error'; @@ -222,12 +225,15 @@ class Tag { if (env.hasExtension(name)) env.removeExtension(name); } - render(str, options, callback) { + render(str, options = {}, callback) { if (!callback && typeof options === 'function') { callback = options; options = {}; } + // Get path of post from source + const source = options.source ? options.source : ''; + const cache = []; const escapeContent = str => ``; @@ -235,7 +241,7 @@ class Tag { str = str.replace(/
[\s\S]*?<\/code><\/pre>/gm, escapeContent);
 
     return Promise.fromCallback(cb => { this.env.renderString(str, options, cb); })
-      .catch(err => Promise.reject(formatNunjucksError(err, str)))
+      .catch(err => Promise.reject(formatNunjucksError(err, str, source)))
       .then(result => result.replace(rPlaceholder, (_, index) => cache[index]))
       .asCallback(callback);
   }
diff --git a/test/scripts/extend/tag_errors.js b/test/scripts/extend/tag_errors.js
index 5f408e4548..1b616f2cfc 100644
--- a/test/scripts/extend/tag_errors.js
+++ b/test/scripts/extend/tag_errors.js
@@ -102,4 +102,26 @@ describe('Tag Errors', () => {
       assertNunjucksError(err, 2, 'expected variable end');
     }
   });
+
+  it('source file path', async () => {
+    const source = '_posts/hello-world.md';
+    const tag = new Tag();
+
+    tag.register('test',
+      (args, content) => {},
+      { ends: true });
+
+    const body = [
+      '{% test %}',
+      '  {{docker ps -aq | map docker inspect -f "{{.Name}} {{.Mounts}}"}}',
+      '{% endtest %}'
+    ].join('\n');
+
+    try {
+      // Add { source } as option
+      await tag.render(body, { source });
+    } catch (err) {
+      err.message.should.contains(source);
+    }
+  });
 });