gemfedwiki

gemini fedwiki proxy
git clone git://jb55.com/gemfedwiki
Log | Files | Refs | README

commit 4e759ecf7cdf23d3a40a1a3b963fd88b230d5f13
parent 532d9c2f058f5ba84a83831f4768493bd5ae93ec
Author: William Casarin <jb55@jb55.com>
Date:   Wed, 27 Oct 2021 22:27:52 -0700

revamp link parsing

Diffstat:
Mindex.js | 101++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 92 insertions(+), 9 deletions(-)

diff --git a/index.js b/index.js @@ -7,14 +7,88 @@ function slugify(text) return text.replace(/\s/g, '-').replace(/[^A-Za-z0-9-]/g, '').toLowerCase() } -function parse_links(text) +function consume_until(cursor, c) { + for (; cursor.pos < cursor.str.length; cursor.pos++) { + if (cursor.str[cursor.pos] == c[0]) + return true + } + return false +} + +function pull_char(cursor) +{ + if (cursor.pos >= cursor.str.length) + return null + return cursor.str[cursor.pos++] +} + +function consume_char(cursor, match) +{ + return pull_char(cursor) === match[0] +} + +function parse_slug_link(cursor, links, root, start) +{ + let i = cursor.pos + if (!consume_until(cursor, ']')) return false + const name = cursor.str.slice(i, cursor.pos) + const url = `${root}/${slugify(name)}` + if (!consume_char(cursor, ']')) return false + if (!consume_char(cursor, ']')) return false + const orig = cursor.str.slice(start, cursor.pos) + links.push({name, url, orig}) + return true +} + +function consume_whitespace(cursor) +{ + for (; cursor.pos < cursor.str.length; cursor.pos++) { + if (cursor.str[cursor.pos] !== ' ') + return; + } +} + +function parse_link(cursor, links, root) +{ + let c, i, url, name, start + + start = cursor.pos + + if (!consume_char(cursor, "[")) + return false + + if ((c = pull_char(cursor)) && c == '[') + return parse_slug_link(cursor, links, root, start) + + cursor.pos-- + consume_whitespace(cursor) + i = cursor.pos + + if (!consume_until(cursor, " ")) return false + url = cursor.str.slice(i, cursor.pos++) + i = cursor.pos + + if (!consume_until(cursor, "]")) return false + name = cursor.str.slice(i, cursor.pos++).trim() + + const orig = cursor.str.slice(start, cursor.pos) + + links.push({ name, url, orig }) + return true +} + +function parse_links(text, root) +{ + let cursor = {pos: 0, str: text} let links = [] - const matches = text.matchAll(/\[\[([^\]]+)\]\]/g) - for (const match of matches) { - const name = match[1] - const slug = slugify(name) - links.push({slug, name}) + + for (; cursor.pos < cursor.str.length;) { + if (!consume_until(cursor, "[")) + return links + + if (!parse_link(cursor, links, root)) + return links } return links @@ -22,19 +96,28 @@ function parse_links(text) function process_item(root, lines, item) { + let first = true; + let i = 0 + if (item.type === 'paragraph' || item.type === 'markdown' || item.type === 'html') { const text = item.text.trim() - const links = parse_links(text) + const links = parse_links(text, root) lines.push('') lines.push(text) + i = lines.length-1 if (links.length !== 0) lines.push('') - for (const {slug, name} of links) { - lines.push(`=> ${root}/${slug} ${name}`) + for (const {url, name, orig} of links) { + lines[i] = lines[i].replace(orig, name) + if (lines[i] === name) + // just remove it if it's the same as the link + lines.splice(i, 2) + lines.push(`=> ${url} ${name}`) } + } }