Consolidate markdown linkification, and add support for authors, blobs, and messages.

This commit is contained in:
Cory McWilliams 2024-04-04 00:18:39 +01:00
parent e50144bd34
commit 4c8d24c319
5 changed files with 68 additions and 158 deletions

View File

@ -1,5 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "🐌",
"previous": "&Xs1X5TzLCk6KVr+5IDc80JAHYxJyoD10cXKBUYpFqWQ=.sha256"
"previous": "&0WzpczDOhxawXBY8fAPMQWwOuF8bVRO+cMJJTxBpYOQ=.sha256"
}

View File

@ -1,90 +1,94 @@
function textNode(text) {
const node = new commonmark.Node("text", undefined);
node.literal = text;
return node;
const node = new commonmark.Node('text', undefined);
node.literal = text;
return node;
}
function linkNode(text, link) {
const linkNode = new commonmark.Node("link", undefined);
linkNode.destination = `#q=${encodeURIComponent(link)}`;
linkNode.appendChild(textNode(text));
return linkNode;
const linkNode = new commonmark.Node('link', undefined);
if (link.startsWith('#')) {
linkNode.destination = `#q=${encodeURIComponent(link)}`;
} else {
linkNode.destination = link;
}
linkNode.appendChild(textNode(text));
return linkNode;
}
function splitMatches(text, regexp) {
// Regexp must be sticky.
regexp = new RegExp(regexp, "gm");
// Regexp must be sticky.
regexp = new RegExp(regexp, 'gm');
let i = 0;
const result = [];
let i = 0;
const result = [];
let match = regexp.exec(text);
while (match) {
const matchText = match[0];
let match = regexp.exec(text);
while (match) {
const matchText = match[0];
if (match.index > i) {
result.push([text.substring(i, match.index), false]);
}
if (match.index > i) {
result.push([text.substring(i, match.index), false]);
}
result.push([matchText, true]);
i = match.index + matchText.length;
result.push([matchText, true]);
i = match.index + matchText.length;
match = regexp.exec(text);
}
match = regexp.exec(text);
}
if (i < text.length) {
result.push([text.substring(i, text.length), false]);
}
if (i < text.length) {
result.push([text.substring(i, text.length), false]);
}
return result;
return result;
}
const regex = new RegExp("(?<!\\w)#[\\w-]+");
const regex = new RegExp('(?:https?://[^ ]+[^ .,])|(?:(?<!\\w)#[\\w-]+)|(?:@[A-Za-z0-9+/]+=.ed25519)|(?:[%&][A-Za-z0-9+/]+=.sha256)');
function split(textNodes) {
const text = textNodes.map(n => n.literal).join("");
const parts = splitMatches(text, regex);
const text = textNodes.map((n) => n.literal).join('');
const parts = splitMatches(text, regex);
return parts.map(part => {
if (part[1]) {
return linkNode(part[0], part[0]);
} else {
return textNode(part[0]);
}
});
return parts.map((part) => {
if (part[1]) {
return linkNode(part[0], part[0]);
} else {
return textNode(part[0]);
}
});
}
export function transform(parsed) {
const walker = parsed.walker();
let event;
const walker = parsed.walker();
let event;
let nodes = [];
while ((event = walker.next())) {
const node = event.node;
if (event.entering && node.type === "text") {
nodes.push(node);
} else {
if (nodes.length > 0) {
split(nodes)
.reverse()
.forEach(newNode => {
nodes[0].insertAfter(newNode);
});
let nodes = [];
while ((event = walker.next())) {
const node = event.node;
if (event.entering && node.type === 'text') {
nodes.push(node);
} else {
if (nodes.length > 0) {
split(nodes)
.reverse()
.forEach((newNode) => {
nodes[0].insertAfter(newNode);
});
nodes.forEach(n => n.unlink());
nodes = [];
}
}
}
nodes.forEach((n) => n.unlink());
nodes = [];
}
}
}
if (nodes.length > 0) {
split(nodes)
.reverse()
.forEach(newNode => {
nodes[0].insertAfter(newNode);
});
nodes.forEach(n => n.unlink());
}
if (nodes.length > 0) {
split(nodes)
.reverse()
.forEach((newNode) => {
nodes[0].insertAfter(newNode);
});
nodes.forEach((n) => n.unlink());
}
return parsed;
return parsed;
}

View File

@ -1,91 +0,0 @@
function textNode(text) {
const node = new commonmark.Node("text", undefined);
node.literal = text;
return node;
}
function linkNode(text, url) {
const urlNode = new commonmark.Node("link", undefined);
urlNode.destination = url;
urlNode.appendChild(textNode(text));
return urlNode;
}
function splitMatches(text, regexp) {
// Regexp must be sticky.
regexp = new RegExp(regexp, "gm");
let i = 0;
const result = [];
let match = regexp.exec(text);
while (match) {
const matchText = match[0];
if (match.index > i) {
result.push([text.substring(i, match.index), false]);
}
result.push([matchText, true]);
i = match.index + matchText.length;
match = regexp.exec(text);
}
if (i < text.length) {
result.push([text.substring(i, text.length), false]);
}
return result;
}
const urlRegexp = new RegExp("https?://[^ ]+[^ .,]");
function splitURLs(textNodes) {
const text = textNodes.map(n => n.literal).join("");
const parts = splitMatches(text, urlRegexp);
return parts.map(part => {
if (part[1]) {
return linkNode(part[0], part[0]);
} else {
return textNode(part[0]);
}
});
}
export function transform(parsed) {
const walker = parsed.walker();
let event;
let nodes = [];
while ((event = walker.next())) {
const node = event.node;
if (event.entering && node.type === "text") {
nodes.push(node);
} else {
if (nodes.length > 0) {
splitURLs(nodes)
.reverse()
.forEach(newNode => {
nodes[0].insertAfter(newNode);
});
nodes.forEach(n => n.unlink());
nodes = [];
}
}
}
if (nodes.length > 0) {
splitURLs(nodes)
.reverse()
.forEach(newNode => {
nodes[0].insertAfter(newNode);
});
nodes.forEach(n => n.unlink());
}
return parsed;
}

View File

@ -17,7 +17,6 @@
</script>
<script src="filesaver.min.js"></script>
<script src="commonmark.min.js"></script>
<script src="commonmark-linkify.js" type="module"></script>
<script src="commonmark-hashtag.js" type="module"></script>
<script src="script.js" type="module"></script>
</body>

View File

@ -1,4 +1,3 @@
import * as linkify from './commonmark-linkify.js';
import * as hashtagify from './commonmark-hashtag.js';
function image(node, entering) {
@ -67,7 +66,6 @@ export function markdown(md) {
writer.image = image;
let parsed = reader.parse(md || '');
parsed = hashtagify.transform(parsed);
parsed = linkify.transform(parsed);
let walker = parsed.walker();
let event, node;
while ((event = walker.next())) {