92 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			92 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | 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; | ||
|  | } |