forked from cory/tildefriends
		
	
		
			
				
	
	
		
			95 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			95 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| function textNode(text) {
 | |
| 	const node = new commonmark.Node('text', undefined);
 | |
| 	node.literal = text;
 | |
| 	return node;
 | |
| }
 | |
| 
 | |
| function linkNode(text, link) {
 | |
| 	const linkNode = new commonmark.Node('link', undefined);
 | |
| 	if (link.startsWith('#')) {
 | |
| 		linkNode.destination = `#${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');
 | |
| 
 | |
| 	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 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);
 | |
| 
 | |
| 	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) {
 | |
| 				split(nodes)
 | |
| 					.reverse()
 | |
| 					.forEach((newNode) => {
 | |
| 						nodes[0].insertAfter(newNode);
 | |
| 					});
 | |
| 
 | |
| 				nodes.forEach((n) => n.unlink());
 | |
| 				nodes = [];
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (nodes.length > 0) {
 | |
| 		split(nodes)
 | |
| 			.reverse()
 | |
| 			.forEach((newNode) => {
 | |
| 				nodes[0].insertAfter(newNode);
 | |
| 			});
 | |
| 		nodes.forEach((n) => n.unlink());
 | |
| 	}
 | |
| 
 | |
| 	return parsed;
 | |
| }
 |