Merge pull request #94 from SpiritLevel/master

Further tidy up of api link parsing and testing
This commit is contained in:
Daniel Hensby 2016-01-24 12:24:56 +00:00
commit f70d5fde0a
3 changed files with 74 additions and 48 deletions

View File

@ -12,11 +12,6 @@ class DocumentationParser
const CODE_BLOCK_BACKTICK = 1; const CODE_BLOCK_BACKTICK = 1;
const CODE_BLOCK_COLON = 2; const CODE_BLOCK_COLON = 2;
/**
* @var string Format string for api urls. See rewrite_api_links().
*/
public static $api_link_base = 'http://api.silverstripe.org/search/lookup/?q=%s&version=%s&module=%s';
/** /**
* @var array * @var array
*/ */
@ -299,49 +294,73 @@ class DocumentationParser
* (6) [Title](api:DataObject->populateDefaults()) gets re-written to * (6) [Title](api:DataObject->populateDefaults()) gets re-written to
* <a href="https://api.silverstripe.org/search/lookup/?q=DataObject::populateDefaults()&version=2.4&module=framework">Title</a> * <a href="https://api.silverstripe.org/search/lookup/?q=DataObject::populateDefaults()&version=2.4&module=framework">Title</a>
* *
* The markdown parser gets confused by the extra pair of parentheses in links of the form [DataObject](api:DataObject->populateDefaults()) so * The above api links can be enclosed in backticks.
*
* The markdown parser gets confused by the extra pair of parentheses in links of the form [DataObject](api:DataObject->populateDefaults()) so
* all links are re-written as html markup instead of markdown [Title](url). This also prevents other markdown parsing problems. * all links are re-written as html markup instead of markdown [Title](url). This also prevents other markdown parsing problems.
* *
* @param String $md * @param String $md
* @param DocumentationPage $page * @param DocumentationPage $page
* @return String * @return String
*/ */
public static function rewrite_api_links($md, $page) public static function rewrite_api_links($markdown, $doc_page)
{ {
$version = $doc_page->getVersion();
$module = $doc_page->getEntity()->getKey();
// define regexs of the api links to be parsed (note: do not include backticks)
$regexs = array( $regexs = array(
'title_and_method' => '\[(.*?)\]\(api:(.*?\(\))\)', // title_and_method handles case (6) and must precede title_remaining 'title_and_method' => '# \[ ([^\]]*) \] \( api: ([^\)]*\(\)) \) #x', // title_and_method = (6) (must be first)
'title_remaining' => '\[(.*?)\]\(api:(.*?)\)', // title_and_remaining handles cases (4) and (5) 'title_remaining' => '# \[ ([^\]]*) \] \( api: ([^\)]*) \) #x', // title_and_remaining = (4) and (5)
'no_title' => '\[api:(.*?)\]' // no_title handles cases (1),(2) and (3) 'no_title' => '# \[ api: ([^\]]*) \] #x' // no_title = (1),(2) and (3)
); );
foreach($regexs as $regex_type => $regex) { // define output format for parsing api links without backticks into html
$link_regex = '/ `? '. $regex . ' `? /x'; $html_format = '<a href="http://api.silverstripe.org/search/lookup/?q=%s&version=%s&module=%s">%s</a>';
preg_match_all($link_regex, $md, $links);
// parse api links without backticks into html
foreach($regexs as $type => $regex) {
preg_match_all($regex, $markdown, $links);
if($links) { if($links) {
foreach($links[0] as $i => $match) { foreach($links[0] as $i => $match) {
if( $regex_type === 'no_title' ){ if($type === 'no_title'){
$title = $links[1][$i]; $title = $links[1][$i];
$link = $links[1][$i]; $link = $links[1][$i];
// change backticked links to avoid being parsed in the same way as non-backticked links
$markdown = str_replace('`'.$match.'`','SS'.$link.'SS',$markdown);
} else { } else {
$title = $links[1][$i]; $title = $links[1][$i];
$link = $links[2][$i]; $link = $links[2][$i];
// change backticked links to avoid being parsed in the same way as non-backticked links
$markdown = str_replace('`'.$match.'`','XX'.$title.'YY'.$link.'ZZ',$markdown);
} }
$url = sprintf( $html = sprintf($html_format, $link, $version, $module, $title);
self::$api_link_base, $markdown = str_replace($match,$html,$markdown);
$link,
$page->getVersion(),
$page->getEntity()->getKey()
);
$md = str_replace(
$match,
sprintf('<a href="%s">%s</a>', $url, $title),
$md
);
} }
} }
} }
return $md;
// recover backticked links with no titles
preg_match_all('#SS(.*)?SS#', $markdown, $links);
if($links) {
foreach($links[0] as $i => $match) {
$link = $links[1][$i];
$markdown = str_replace($match,'`[api:'.$link.']`',$markdown);
}
}
// recover backticked links with titles
preg_match_all('#XX(.*)?YY(.*)?ZZ#', $markdown, $links);
if($links) {
foreach($links[0] as $i => $match) {
$title = $links[1][$i];
$link = $links[2][$i];
$markdown = str_replace($match,'`['.$title.'](api:'.$link.')`',$markdown);
}
}
return $markdown;
} }

View File

@ -196,12 +196,7 @@ HTML;
'[link: http](http://silverstripe.org)', '[link: http](http://silverstripe.org)',
$result $result
); );
$this->assertContains(
'[link: api](api:DataObject)',
$result
);
$result = DocumentationParser::rewrite_relative_links( $result = DocumentationParser::rewrite_relative_links(
$this->subPage->getMarkdown(), $this->subPage->getMarkdown(),
$this->subPage $this->subPage
@ -325,21 +320,28 @@ HTML;
$page_version = $this->page->getVersion(); $page_version = $this->page->getVersion();
// expected url format resulting from rewriting api shortcode links // expected url format resulting from rewriting api shortcode links
$url_format = '<a href="http://api.silverstripe.org/search/lookup/?q=%s&version='.$page_version.'&module=documentationparsertest">%s</a>'; $html_format = '<a href="http://api.silverstripe.org/search/lookup/?q=%s&version='.$page_version.'&module=documentationparsertest">%s</a>';
// test cases: api shortcode references and the expected urls resulting from rewriting them // test cases: non-backtick enclosed api links and the expected html resulting from rewriting them
// note that api links enclosed in backticks are left unchanged
$test_cases = array( $test_cases = array(
array('[api:DataObject]', sprintf($url_format,'DataObject','DataObject')), array('`[api:DataObject]`','`[api:DataObject]`'),
array('[api:DataObject::$defaults]',sprintf($url_format,'DataObject::$defaults','DataObject::$defaults')), array('`[api:DataObject::$defaults]`','`[api:DataObject::$defaults]`'),
array('[api:DataObject::populateDefaults()]',sprintf($url_format,'DataObject::populateDefaults()','DataObject::populateDefaults()')), array('`[api:DataObject::populateDefaults()]`','`[api:DataObject::populateDefaults()]`'),
array('[Title](api:DataObject)',sprintf($url_format,'DataObject','Title')), array('`[Title](api:DataObject)`','`[Title](api:DataObject)`'),
array('[Title](api:DataObject::$defaults)',sprintf($url_format,'DataObject::$defaults','Title')), array('`[Title](api:DataObject::$defaults)`','`[Title](api:DataObject::$defaults)`'),
array('[Title](api:DataObject::populateDefaults())',sprintf($url_format,'DataObject::populateDefaults()','Title')) array('`[Title](api:DataObject::populateDefaults())`','`[Title](api:DataObject::populateDefaults())`'),
array('[api:DataObject]', sprintf($html_format,'DataObject','DataObject')),
array('[api:DataObject::$defaults]',sprintf($html_format,'DataObject::$defaults','DataObject::$defaults')),
array('[api:DataObject::populateDefaults()]',sprintf($html_format,'DataObject::populateDefaults()','DataObject::populateDefaults()')),
array('[Title](api:DataObject)',sprintf($html_format,'DataObject','Title')),
array('[Title](api:DataObject::$defaults)',sprintf($html_format,'DataObject::$defaults','Title')),
array('[Title](api:DataObject::populateDefaults())',sprintf($html_format,'DataObject::populateDefaults()','Title'))
); );
foreach($test_cases as $test_case) { foreach($test_cases as $test_case) {
$expected_api_url = $test_case[1]; $expected_html = $test_case[1];
$this->assertContains($expected_api_url,$parsed_page); $this->assertContains($expected_html,$parsed_page);
} }
} }

View File

@ -8,14 +8,19 @@ test
[link: subfolder page](subfolder/subpage) [link: subfolder page](subfolder/subpage)
[link: with anchor](/test#anchor) [link: with anchor](/test#anchor)
[link: http](http://silverstripe.org) [link: http](http://silverstripe.org)
[link: api](api:DataObject)
[api:DataObject] `[Title](api:DataObject)`
[api:DataObject::$defaults] `[Title](api:DataObject::$defaults)`
[api:DataObject::populateDefaults()] `[Title](api:DataObject::populateDefaults())`
`[api:DataObject]`
`[api:DataObject::$defaults]`
`[api:DataObject::populateDefaults()]`
[Title](api:DataObject) [Title](api:DataObject)
[Title](api:DataObject::$defaults) [Title](api:DataObject::$defaults)
[Title](api:DataObject::populateDefaults()) [Title](api:DataObject::populateDefaults())
[api:DataObject]
[api:DataObject::$defaults]
[api:DataObject::populateDefaults()]
:::php :::php
code block code block