diff --git a/lib/highlight.js b/lib/highlight.js index f0856e03..132004d3 100644 --- a/lib/highlight.js +++ b/lib/highlight.js @@ -3,7 +3,6 @@ const hljs = require('highlight.js'); const stripIndent = require('strip-indent'); const alias = require('../highlight_alias.json'); -const escapeHTML = require('./escape_html'); function highlightUtil(str, options = {}) { if (typeof str !== 'string') throw new TypeError('str must be a string!'); @@ -101,49 +100,40 @@ function highlight(str, options) { let { lang } = options; const { autoDetect = false } = options; - if (!lang && autoDetect) { + if (lang) { + lang = lang.toLowerCase(); + } else if (autoDetect) { const result = hljs.highlightAuto(str); - if (result.relevance > 0 && result.language) lang = result.language; + return closeTags(result); } - if (!lang) { - lang = 'plain'; + if (!lang || !alias.aliases[lang]) { + lang = 'plaintext'; } - const result = { - value: escapeHTML(str), - language: lang.toLowerCase() - }; - - if (result.language === 'plain') { - return result; - } - - if (!alias.aliases[result.language]) { - result.language = 'plain'; - return result; - } + const res = hljs.highlight(str, { + language: lang, + ignoreIllegals: true + }); - return tryHighlight(str, result.language) || result; + return closeTags(res); } -function tryHighlight(str, lang) { - try { - const matching = str.match(/(\r?\n)/); - const separator = matching ? matching[1] : ''; - const lines = matching ? str.split(separator) : [str]; - let result = hljs.highlight(lang, lines.shift()); - let html = result.value; - while (lines.length > 0) { - result = hljs.highlight(lang, lines.shift(), false, result.top); - html += separator + result.value; - } - - result.value = html; - return result; - } catch (err) { +// https://github.com/hexojs/hexo-util/issues/10 +function closeTags(res) { + const tokenStack = []; - } + res.value = res.value.split('\n').map(line => { + const prepend = tokenStack.map(token => ``).join(''); + const matches = line.matchAll(/(|<\/span>)/g); + for (const match of matches) { + if (match[0] === '') tokenStack.shift(); + else tokenStack.unshift(match[2]); + } + const append = ''.repeat(tokenStack.length); + return prepend + line + append; + }).join('\n'); + return res; } module.exports = highlightUtil; diff --git a/lib/prism.js b/lib/prism.js index 9bac50e1..7201f2ca 100644 --- a/lib/prism.js +++ b/lib/prism.js @@ -67,7 +67,7 @@ function PrismUtil(str, options = {}) { } = options; // To be consistent with highlight.js - const language = lang === 'plain' || lang === 'none' ? 'none' : lang; + const language = lang === 'plaintext' || lang === 'none' ? 'none' : lang; const preTagClassArr = []; const preTagAttrArr = []; diff --git a/package.json b/package.json index 84a91a6b..25a94cac 100644 --- a/package.json +++ b/package.json @@ -47,12 +47,12 @@ "camel-case": "^4.0.0", "cross-spawn": "^7.0.0", "deepmerge": "^4.2.2", - "highlight.js": "^10.0.0", + "highlight.js": "^10.7.1", "htmlparser2": "^6.0.0", "prismjs": "^1.17.1", "strip-indent": "^3.0.0" }, "engines": { - "node": ">=10.13.0" + "node": ">=12.4.0" } } diff --git a/test/highlight.spec.js b/test/highlight.spec.js index 5990e0f6..86442389 100644 --- a/test/highlight.spec.js +++ b/test/highlight.spec.js @@ -12,7 +12,7 @@ const testJson = { const testString = JSON.stringify(testJson, null, ' '); -const start = '
'; +const start = '
'; const end = '
'; const gutterStart = '
';
@@ -37,7 +37,9 @@ function code(str, lang) {
   let data;
 
   if (lang) {
-    data = hljs.highlight(lang.toLowerCase(), str);
+    data = hljs.highlight(str, {
+      language: lang.toLowerCase()
+    });
   } else if (lang === null) {
     data = {value: str};
   } else {
@@ -93,7 +95,7 @@ describe('highlight', () => {
   it('wrap: false (without hljs, without lang)', done => {
     const result = highlight(testString, {gutter: false, wrap: false});
     result.should.eql([
-      '
',
+      '
',
       entities.encode(testString),
       '
' ].join('')); @@ -103,7 +105,7 @@ describe('highlight', () => { it('wrap: false (with hljs, without lang)', done => { const result = highlight(testString, {gutter: false, wrap: false, hljs: true}); result.should.eql([ - '
',
+      '
',
       entities.encode(testString),
       '
' ].join('')); @@ -115,7 +117,9 @@ describe('highlight', () => { hljs.configure({classPrefix: ''}); result.should.eql([ '
',
-      hljs.highlight('json', testString).value,
+      hljs.highlight(testString, {
+        language: 'json'
+      }).value,
       '
' ].join('')); validateHtmlAsync(result, done); @@ -126,7 +130,9 @@ describe('highlight', () => { hljs.configure({classPrefix: 'hljs-'}); result.should.eql([ '
',
-      hljs.highlight('json', testString).value,
+      hljs.highlight(testString, {
+        language: 'json'
+      }).value,
       '
' ].join('')); validateHtmlAsync(result, done); @@ -137,7 +143,9 @@ describe('highlight', () => { hljs.configure({classPrefix: 'hljs-'}); result.should.eql([ '
',
-      hljs.highlight('json', testString).value.replace('{', '{'),
+      hljs.highlight(testString, {
+        language: 'json'
+      }).value.replace('{', '{'),
       '
' ].join('')); validateHtmlAsync(result, done); @@ -148,7 +156,9 @@ describe('highlight', () => { hljs.configure({classPrefix: 'hljs-'}); result.should.eql([ '
',
-      hljs.highlight('json', testString).value,
+      hljs.highlight(testString, {
+        language: 'json'
+      }).value,
       '\n
' ].join('')); validateHtmlAsync(result, done); @@ -199,7 +209,7 @@ describe('highlight', () => { }); result.should.eql([ - `
${caption}
`, + `
${caption}
`, gutter(1, 4), code(testString), end @@ -218,7 +228,7 @@ describe('highlight', () => { result.should.eql([ '
',
       `
${caption}
`, - '', + '', entities.encode(testString), '
' ].join('')); @@ -252,7 +262,9 @@ describe('highlight', () => { result.should.eql([ '
',
       spaces,
-      hljs.highlight('json', testString).value,
+      hljs.highlight(testString, {
+        language: 'json'
+      }).value,
       '
' ].join('')); validateHtmlAsync(result, done);