diff --git a/packages/glow/src/glow.js b/packages/glow/src/glow.js index 46ff3fd1..040d39d2 100644 --- a/packages/glow/src/glow.js +++ b/packages/glow/src/glow.js @@ -39,6 +39,9 @@ const HTML_TAGS = [ // line comment { tag: 'sup', re: /# .+/ }, + + // inline comment + { tag: 'sup', re: /\/\*.*?\*\//g }, { tag: 'label', re: /\[([a-z\-]+)/g, lang: ['md', 'toml'], shift: true }, @@ -223,7 +226,7 @@ export function renderRow(row, lang, mark=true) { // comment start & end -const COMMENT = [/(\/\*|^ *{# ||'''|=end)$/] +const COMMENT = [/(\/\*|^ *{# ||'''|=end)/] export function parseSyntax(lines, lang, prefix = true) { const [comm_start, comm_end] = COMMENT @@ -232,16 +235,20 @@ export function parseSyntax(lines, lang, prefix = true) { // multi-line comment let comment - function endComment() { - html.push({ comment }) + function endComment(partial) { + html.push({ comment, partial }) comment = null } - lines.forEach((line, i) => { + for (let i = 0; i < lines.length; i++) { + let line = lines[i] if (!comment) { - if (comm_start.test(line)) { + const start_comm = comm_start.exec(line) + const end_comm = comm_end.exec(line) + if (start_comm && start_comm.index === 0 && (!end_comm || line.length === end_comm.index + end_comm[0].length)) { + // entire line is a complete comment OR the beginning of a block comment comment = [line] - if (comm_end.test(line) && line?.trim() != "'''") endComment() + if (end_comm && line?.trim() != "'''") endComment() } else { // highlighted line @@ -258,11 +265,20 @@ export function parseSyntax(lines, lang, prefix = true) { } } else { - comment.push(line) - if (comm_end.test(line)) endComment() + const end_comm = comm_end.exec(line) + if (end_comm) { + const end = end_comm.index + end_comm[0].length + const [before, after] = [line.slice(0, end), line.slice(end)] + comment.push(before) + endComment(!!after.length) + if (after) { + lines.splice(i + 1, 0, after) + } + } else { + comment.push(line) + } } - }) - + } return html } @@ -280,24 +296,30 @@ export function glow(str, opts = { prefix: true, mark: true }) { if (!lang && lines[0][0] == '<') lang = 'html' const html = [] + let is_partial = false function push(line) { - html.push(opts.numbered ? elem('span', line) : line) + if (is_partial) html[html.length - 1] = html[html.length - 1] + line + else html.push(line) + is_partial = false } parseSyntax(lines, lang, opts.prefix).forEach(function(block) { - let { line, comment, wrap } = block - + let { line, comment, wrap, partial } = block + // EOL comment if (comment) { - return comment.forEach(el => push(elem('sup', encode(el)))) - + comment.forEach(el => push(elem('sup', encode(el)))) + is_partial = partial + return + } else { line = renderRow(line, lang, opts.mark) } - + if (wrap) line = elem(wrap, line) push(line) + is_partial = partial }) - return `${html.join(NL)}` + return `${html.map(el => opts.numbered ? elem('span', el) : el).join(NL)}` } diff --git a/packages/glow/test/glow.test.js b/packages/glow/test/glow.test.js index 13002d59..116f6225 100644 --- a/packages/glow/test/glow.test.js +++ b/packages/glow/test/glow.test.js @@ -1,4 +1,4 @@ -import { parseRow, renderRow, parseSyntax } from '../src/glow.js' +import { glow, parseRow, renderRow, parseSyntax } from '../src/glow.js' test('HTML', () => { const row = '
' @@ -39,6 +39,23 @@ test('parse JS comment', () => { expect(blocks[2].comment[0]).toEqual('/*') }) +test('parse TS inline comment', () => { + const html = renderRow('const colors: Record = {};') + expect(html).toInclude('Record</* name */ string, /* hex */ string>') +}) + + +test('parse block comment with content after comment-end', () => { + const result = glow(`/* +hello +*/ world`, 'js') + expect(result).toEqual('/*\nhello\n*/ world') +}) + +test('parse inline comment with content after end', () => { + const result = glow(`/* this is a line comment */ const foo = 2;`, 'js') + expect(result).toEqual('/* this is a line comment */ const foo = 2;') +}) /* prefix and mark */ test('disable mark', () => {