Consolidate markdown linkification, and add support for authors, blobs, and messages.
This commit is contained in:
		| @@ -1,5 +1,5 @@ | ||||
| { | ||||
| 	"type": "tildefriends-app", | ||||
| 	"emoji": "🐌", | ||||
| 	"previous": "&Xs1X5TzLCk6KVr+5IDc80JAHYxJyoD10cXKBUYpFqWQ=.sha256" | ||||
| 	"previous": "&0WzpczDOhxawXBY8fAPMQWwOuF8bVRO+cMJJTxBpYOQ=.sha256" | ||||
| } | ||||
|   | ||||
| @@ -1,19 +1,23 @@ | ||||
| function textNode(text) { | ||||
|   const node = new commonmark.Node("text", undefined); | ||||
| 	const node = new commonmark.Node('text', undefined); | ||||
| 	node.literal = text; | ||||
| 	return node; | ||||
| } | ||||
|  | ||||
| function linkNode(text, link) { | ||||
|   const linkNode = new commonmark.Node("link", undefined); | ||||
| 	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 = new RegExp(regexp, 'gm'); | ||||
|  | ||||
| 	let i = 0; | ||||
| 	const result = []; | ||||
| @@ -39,13 +43,13 @@ function splitMatches(text, regexp) { | ||||
| 	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 text = textNodes.map((n) => n.literal).join(''); | ||||
| 	const parts = splitMatches(text, regex); | ||||
|  | ||||
|   return parts.map(part => { | ||||
| 	return parts.map((part) => { | ||||
| 		if (part[1]) { | ||||
| 			return linkNode(part[0], part[0]); | ||||
| 		} else { | ||||
| @@ -61,17 +65,17 @@ export function transform(parsed) { | ||||
| 	let nodes = []; | ||||
| 	while ((event = walker.next())) { | ||||
| 		const node = event.node; | ||||
|     if (event.entering && node.type === "text") { | ||||
| 		if (event.entering && node.type === 'text') { | ||||
| 			nodes.push(node); | ||||
| 		} else { | ||||
| 			if (nodes.length > 0) { | ||||
| 				split(nodes) | ||||
| 					.reverse() | ||||
|           .forEach(newNode => { | ||||
| 					.forEach((newNode) => { | ||||
| 						nodes[0].insertAfter(newNode); | ||||
| 					}); | ||||
|  | ||||
|         nodes.forEach(n => n.unlink()); | ||||
| 				nodes.forEach((n) => n.unlink()); | ||||
| 				nodes = []; | ||||
| 			} | ||||
| 		} | ||||
| @@ -80,10 +84,10 @@ export function transform(parsed) { | ||||
| 	if (nodes.length > 0) { | ||||
| 		split(nodes) | ||||
| 			.reverse() | ||||
|       .forEach(newNode => { | ||||
| 			.forEach((newNode) => { | ||||
| 				nodes[0].insertAfter(newNode); | ||||
| 			}); | ||||
|     nodes.forEach(n => n.unlink()); | ||||
| 		nodes.forEach((n) => n.unlink()); | ||||
| 	} | ||||
|  | ||||
| 	return parsed; | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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())) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user