mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 04:51:31 +08:00 
			
		
		
		
	feat(export/markdown): basic support for admonitions
This commit is contained in:
		
							parent
							
								
									b1e3ea4c80
								
							
						
					
					
						commit
						6d67e69e2f
					
				| @ -103,4 +103,94 @@ describe("Markdown export", () => { | ||||
|         expect(markdownExportService.toMarkdown(html)).toBe(html); | ||||
|     }); | ||||
| 
 | ||||
|     it("exports admonitions properly", () => { | ||||
|         const html = trimIndentation`\ | ||||
|             <p> | ||||
|                 Before | ||||
|             </p> | ||||
|             <aside class="admonition note"> | ||||
|                 <p> | ||||
|                     This is a note. | ||||
|                 </p> | ||||
|             </aside> | ||||
|             <aside class="admonition tip"> | ||||
|                 <p> | ||||
|                     This is a tip. | ||||
|                 </p> | ||||
|             </aside> | ||||
|             <aside class="admonition important"> | ||||
|                 <p> | ||||
|                     This is a very important information. | ||||
|                 </p> | ||||
|                 <figure class="table"> | ||||
|                     <table> | ||||
|                         <tbody> | ||||
|                             <tr> | ||||
|                                 <td> | ||||
|                                     1 | ||||
|                                 </td> | ||||
|                                 <td> | ||||
|                                     2 | ||||
|                                 </td> | ||||
|                             </tr> | ||||
|                             <tr> | ||||
|                                 <td> | ||||
|                                     3 | ||||
|                                 </td> | ||||
|                                 <td> | ||||
|                                     4 | ||||
|                                 </td> | ||||
|                             </tr> | ||||
|                         </tbody> | ||||
|                     </table> | ||||
|                 </figure> | ||||
|             </aside> | ||||
|             <aside class="admonition caution"> | ||||
|                 <p> | ||||
|                     This is a caution. | ||||
|                 </p> | ||||
|             </aside> | ||||
|             <aside class="admonition warning"> | ||||
|                 <h2> | ||||
|                     Title goes here | ||||
|                 </h2> | ||||
|                 <p> | ||||
|                     This is a warning. | ||||
|                 </p> | ||||
|             </aside> | ||||
|             <p> | ||||
|                 After | ||||
|             </p> | ||||
|         `;
 | ||||
| 
 | ||||
|         const space = " ";  // editor config trimming space.
 | ||||
|         const expected = trimIndentation`\ | ||||
|             Before | ||||
| 
 | ||||
|             > [!NOTE] | ||||
|             > This is a note. | ||||
| 
 | ||||
|             > [!TIP] | ||||
|             > This is a tip. | ||||
| 
 | ||||
|             > [!IMPORTANT] | ||||
|             > This is a very important information. | ||||
|             >${space} | ||||
|             > |     |     | | ||||
|             > | --- | --- | | ||||
|             > | 1   | 2   | | ||||
|             > | 3   | 4   | | ||||
| 
 | ||||
|             > [!CAUTION] | ||||
|             > This is a caution. | ||||
| 
 | ||||
|             > [!WARNING] | ||||
|             > ## Title goes here | ||||
|             >${space} | ||||
|             > This is a warning. | ||||
| 
 | ||||
|             After`;
 | ||||
|         expect(markdownExportService.toMarkdown(html)).toBe(expected); | ||||
|     }); | ||||
| 
 | ||||
| }); | ||||
|  | ||||
| @ -31,6 +31,7 @@ function toMarkdown(content: string) { | ||||
|         // Filter is heavily based on: https://github.com/mixmark-io/turndown/issues/274#issuecomment-458730974
 | ||||
|         instance.addRule("fencedCodeBlock", fencedCodeBlockFilter); | ||||
|         instance.addRule("img", buildImageFilter()); | ||||
|         instance.addRule("admonition", buildAdmonitionFilter()); | ||||
|         instance.use(turndownPluginGfm.gfm); | ||||
|         instance.keep([ "kbd" ]); | ||||
|     } | ||||
| @ -100,6 +101,57 @@ function buildImageFilter() { | ||||
|     return imageFilter; | ||||
| } | ||||
| 
 | ||||
| function buildAdmonitionFilter() { | ||||
|     const admonitionTypeMappings: Record<string, string> = { | ||||
|         note: "NOTE", | ||||
|         tip: "TIP", | ||||
|         important: "IMPORTANT", | ||||
|         caution: "CAUTION", | ||||
|         warning: "WARNING" | ||||
|     }; | ||||
| 
 | ||||
|     const defaultAdmonitionType = admonitionTypeMappings.note; | ||||
| 
 | ||||
|     function parseAdmonitionType(_node: Node) { | ||||
|         if (!("getAttribute" in _node)) { | ||||
|             return defaultAdmonitionType; | ||||
|         } | ||||
| 
 | ||||
|         const node = _node as Element; | ||||
|         const classList = node.getAttribute("class")?.split(" ") ?? []; | ||||
| 
 | ||||
|         for (const className of classList) { | ||||
|             if (className === "admonition") { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             const mappedType = admonitionTypeMappings[className]; | ||||
|             if (mappedType) { | ||||
|                 return mappedType; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return defaultAdmonitionType; | ||||
|     } | ||||
| 
 | ||||
|     const admonitionFilter: TurndownService.Rule = { | ||||
|         filter(node, options) { | ||||
|             return node.nodeName === "ASIDE" && node.classList.contains("admonition"); | ||||
|         }, | ||||
|         replacement(content, node) { | ||||
|             // Parse the admonition type.
 | ||||
|             const admonitionType = parseAdmonitionType(node); | ||||
| 
 | ||||
|             content = content.replace(/^\n+|\n+$/g, ''); | ||||
|             content = content.replace(/^/gm, '> '); | ||||
|             content = `> [!${admonitionType}]\n` + content; | ||||
| 
 | ||||
|             return "\n\n" + content + "\n\n"; | ||||
|         } | ||||
|     } | ||||
|     return admonitionFilter; | ||||
| } | ||||
| 
 | ||||
| export default { | ||||
|     toMarkdown | ||||
| }; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran