Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(glow): handle inline /* ... */ comment #465

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 39 additions & 17 deletions packages/glow/src/glow.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 },

Expand Down Expand Up @@ -223,7 +226,7 @@ export function renderRow(row, lang, mark=true) {


// comment start & end
const COMMENT = [/(\/\*|^ *{# |<!--|'''|=begin)/, /(\*\/|#}|-->|'''|=end)$/]
const COMMENT = [/(\/\*|^ *{# |<!--|'''|=begin)/, /(\*\/|#}|-->|'''|=end)/]

export function parseSyntax(lines, lang, prefix = true) {
const [comm_start, comm_end] = COMMENT
Expand All @@ -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
Expand All @@ -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
}
Expand All @@ -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 `<code language="${lang || '*'}">${html.join(NL)}</code>`
return `<code language="${lang || '*'}">${html.map(el => opts.numbered ? elem('span', el) : el).join(NL)}</code>`
}
19 changes: 18 additions & 1 deletion packages/glow/test/glow.test.js
Original file line number Diff line number Diff line change
@@ -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 = '<div class="hello">'
Expand Down Expand Up @@ -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</* name */ string, /* hex */ string> = {};')
expect(html).toInclude('Record<i>&lt;</i><sup>/* name */</sup> <strong>string</strong><i>,</i> <sup>/* hex */</sup> <strong>string</strong><i>&gt;</i>')
})


test('parse block comment with content after comment-end', () => {
const result = glow(`/*
hello
*/ world`, 'js')
expect(result).toEqual('<code language=\"js\"><sup>/*</sup>\n<sup>hello</sup>\n<sup>*/</sup> world</code>')
})

test('parse inline comment with content after end', () => {
const result = glow(`/* this is a line comment */ const foo = 2;`, 'js')
expect(result).toEqual('<code language=\"js\"><sup>/* this is a line comment */</sup> <strong>const</strong> <b>foo</b> <i>=</i> <em>2</em><i>;</i></code>')
})

/* prefix and mark */
test('disable mark', () => {
Expand Down