commit 4e759ecf7cdf23d3a40a1a3b963fd88b230d5f13
parent 532d9c2f058f5ba84a83831f4768493bd5ae93ec
Author: William Casarin <jb55@jb55.com>
Date: Wed, 27 Oct 2021 22:27:52 -0700
revamp link parsing
Diffstat:
M | index.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}`)
}
+
}
}