1<?php 2 3namespace Dokuwiki\Plugin\Commonmark; 4 5use League\CommonMark\Environment\Environment; 6use League\CommonMark\Parser\MarkdownParser; 7use Dokuwiki\Plugin\Commonmark\Extension\CommonmarkToDokuwikiExtension; 8use Dokuwiki\Plugin\Commonmark\Extension\FootnoteToDokuwikiExtension; 9use League\CommonMark\Extension\Strikethrough\StrikethroughExtension; 10use Dokuwiki\Plugin\Commonmark\Extension\TableExtension; 11use League\CommonMark\Extension\FrontMatter\FrontMatterExtension; 12use League\CommonMark\Extension\FrontMatter\Output\RenderedContentWithFrontMatter; 13 14class Commonmark { 15 public static function RendtoDW($markdown, $frontmatter_tag = 'off', $render_softbreaks = 0): array { 16 // heading info 17 $headingInfo = []; 18 19 // create environment 20 $environment = self::createDWEnvironment($render_softbreaks); 21 22 // create parser 23 $parser = new MarkdownParser($environment); 24 // create Dokuwiki Renderer 25 $DWRenderer = new DWRenderer($environment); 26 27 # separate frontmatter and main text 28 $FMresult = self::ExtractFrontmatter($markdown); 29 $frontmatter = $FMresult->getFrontMatter(); 30 $markdownOnly = $FMresult->getContent(); 31 $tagStr = ''; # initialize tag string 32 //print_r($frontmatter); 33 34 # extract tags only 35 if(!empty($frontmatter) && gettype($frontmatter) == "array") { // frontmatter must be array if valid 36 if (array_key_exists('tags', $frontmatter)) { 37 $tags = $frontmatter['tags']; 38 $tagStr = "{{tag>"; 39 foreach ($tags as $tag) { 40 $tagStr = $tagStr. "\"". $tag. "\" "; 41 } 42 $tagStr = $tagStr. "}}"; 43 } 44 } 45 46 // pre-processing: convert slash inside wikilink to colon & image wikilinks 47 $markdownOnly = self::ParseDokuwikiWikilinks($markdownOnly); 48 $document = $parser->parse($markdownOnly); 49 $renderResult = $DWRenderer->renderNode($document); 50 foreach ($document->iterator() as $node) { 51 if($node instanceof \League\CommonMark\Extension\CommonMark\Node\Block\Heading) { 52 // collect inline text recursively 53 $collectInlineText = function($node) use (&$collectInlineText) { 54 $text = ''; 55 for ($child = $node->firstChild(); $child !== null; $child = $child->next()) { 56 if (method_exists($child, 'getLiteral')) { 57 $text .= $child->getLiteral(); 58 } else { 59 // recurse into nested inline nodes (strong, emphasis, etc.) 60 $text .= $collectInlineText($child); 61 } 62 } 63 return $text; 64 }; 65 66 $first = $node->firstChild(); 67 if ($first === null) { 68 $headingName = ''; 69 } elseif($first instanceof \League\CommonMark\Extension\CommonMark\Node\Inline\Link) { 70 // set headingName as [[<Url>|<text>]] 71 // link URL and its inner text (may contain nested inlines) 72 $linkText = $collectInlineText($first); 73 $headingName = '[[' . $first->getUrl() . '|' . $linkText . ']]'; 74 } else { 75 // collect all inline text inside the heading 76 $headingName = $collectInlineText($node); 77 } 78 79 $headingInfo[$headingName] = array( 80 'level' => $node->getLevel(), 81 'startline' => $node->getStartLine(), 82 'endline' => $node->getEndLine() 83 ); 84 } 85 } 86 87 if($frontmatter_tag == 'off') { 88 return array('text'=>$renderResult, 'heading'=>$headingInfo); 89 } elseif($frontmatter_tag == 'upper') { 90 return array('text'=>$tagStr."\n\n".$renderResult, 'heading'=>$headingInfo); 91 //return $tagStr."\n\n".$renderResult; 92 } else { 93 return array('text'=>$renderResult."\n\n".$tagStr, 'heading'=>$headingInfo); 94 //return $renderResult."\n\n".$tagStr; 95 } 96 } 97 98 // Temporary implementation: separate method for frontmatter extraction 99 // Since some parsed frontmatter info must be included in main text, it should be merged 100 public static function ExtractFrontmatter($markdown) { 101 $frontMatterExtension = new FrontMatterExtension(); 102 $result = $frontMatterExtension->getFrontMatterParser()->parse($markdown); 103 104 return $result; 105 } 106 107 // replace slash in MD wikilink to colon to match DW syntax 108 public static function ParseDokuwikiWikilinks($text) { 109 $pattern = "/(?:\[\[\b|(?!^)\G)[^\/|\]]*\K\/+/"; 110 $result = preg_replace($pattern, ":", $text); 111 $pattern = "/!\[\[(.*)\]\]/"; 112 $result = preg_replace($pattern, '{{$1}}', $result); 113 return $result; 114 } 115 116 public static function createDWEnvironment($render_softbreaks): Environment { 117 $config = [ 118 'html_input' => 'allow', 119 'commonmark' => ['hard_break'=> "\\\\ "] 120 ]; 121 if ($render_softbreaks) { 122 $config['renderer']['soft_break'] = $config['commonmark']['hard_break']; 123 } 124 125 $environment = new Environment($config); 126 $environment->addExtension(new CommonMarkToDokuWikiExtension()); 127 $environment->addExtension(new FootnoteToDokuwikiExtension()); 128 $environment->addExtension(new StrikethroughExtension()); 129 $environment->addExtension(new TableExtension()); 130 $environment->addExtension(new FrontMatterExtension()); 131 132 return $environment; 133 } 134} 135 136?> 137