Skip to content

Commit e67d811

Browse files
authored
Merge pull request #1 from UrbanMonastics/main
Update the Parser with more tests
2 parents cd65b59 + dd846a0 commit e67d811

20 files changed

+304
-39
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Source Parser in PHP
22
[![Build Status](https://travis-ci.com/UrbanMonastics/SourceParser.svg)](https://travis-ci.com/UrbanMonastics/SourceParser)
3+
[![Total Downloads](https://poser.pugx.org/urbanmonastics/sourceparser/d/total.svg)](https://packagist.org/packages/urbanmonastics/sourceparser)
4+
[![Version](https://poser.pugx.org/urbanmonastics/sourceparser/v/stable.svg)](https://packagist.org/packages/urbanmonastics/sourceparser)
5+
[![License](https://poser.pugx.org/urbanmonastics/sourceparser/license.svg)](https://packagist.org/packages/urbanmonastics/sourceparser)
36

47
A Fast Markdown Parser extended for Liturgy in PHP. This is a formatting library for the specific styling and formats of the Source Texts available from Urban Monastics.
58

@@ -82,10 +85,18 @@ These texts may need to be used in various formats and contexts. There are going
8285

8386
### Methods
8487

88+
* **setSafeMode( *bool* )** default: false
89+
When enabled will ensure that output cannot execute code.
90+
* **setStrictMode( *bool* )** default: false
91+
When enabled it requires headers not start with a space....
8592
* **setBreaksEnabled( *bool* )** default: false
8693
When enabled it will transform new line markers `\n` into `<br>`.
8794
* **setMarkupEscaped( *bool* )** default: false
8895
When enabled it will escape any existing HTML syntax within the documents.
96+
* **setUrlsLinked( *bool* )**
97+
When enabled it will convert inline URL strings into clickable links.
98+
* **setPreserveIndentations( *bool* )** default: false
99+
When enabled this will convert any tabs (set of 4 spaces) into four double spaces wrapped in a span. Enabling this will disable tabbing for code blocks.
89100
* **setLiturgicalElements( *bool* )** default: false
90101
When enabled the standard Markdown will be supplemented with liturgical elements. See Extending Markdown above for additions
91102
* **setLiturgicalHTML( *bool* )** default: true
@@ -121,6 +132,9 @@ To make it easier to develop and build out the SourceParser we have setup a loca
121132
# To stop/shutdown the container
122133
./docker/stop.sh
123134

135+
# To run the PHPUnit tests in /test/SourceParserTest.php
136+
./docker/phpunit.sh
137+
124138
# To attach to the running container
125139
./docker/attach.sh
126140

SourceParser.php

Lines changed: 119 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public function line( $text, $nonNestables = array() ){
5858
protected $urlsLinked = true; // Convert any URL into a link
5959
protected $safeMode = false; // How strict are we about raw HTML code
6060
protected $strictMode;
61+
protected $preserveIndentations = false; // Do we add spacers to perserve indentations
6162
protected $liturgicalElements = false; // Look for liturgical elements in the text
6263
protected $liturgicalHTML = true; // Do we wrap liturgical elements in HTML tags
6364
protected $suppressAlleluia = false; // Do we remove the word Alleluia from the text
@@ -173,6 +174,17 @@ function setUrlsLinked($urlsLinked){
173174
return $this;
174175
}
175176

177+
public function setPreserveIndentations(bool $preserveIndentations){
178+
$this->preserveIndentations = $preserveIndentations;
179+
180+
if( $preserveIndentations )
181+
$this->unmarkedBlockTypes = array();
182+
else
183+
$this->unmarkedBlockTypes = array('Code');
184+
185+
return $this;
186+
}
187+
176188
public function setLiturgicalElements(bool $liturgicalElements){
177189
$this->liturgicalElements = $liturgicalElements;
178190

@@ -277,6 +289,25 @@ protected function linesElements(array $lines){
277289

278290
$text = $indent > 0 ? substr($line, $indent) : $line;
279291

292+
if( $this->preserveIndentations && $indent >= 4 ){
293+
$tabs = floor( $indent / 4 );
294+
295+
do{
296+
if( $tabs >= 2 && $this->liturgicalHTML ){
297+
$text = '<span class="spacer-tab-x2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>' . $text;
298+
$tabs = $tabs - 2;
299+
}else{
300+
if( $this->liturgicalHTML )
301+
$text = '<span class="spacer-tab">&nbsp;&nbsp;&nbsp;&nbsp;</span>' . $text;
302+
else
303+
$text = '&nbsp;&nbsp;&nbsp;&nbsp;' . $text;
304+
305+
--$tabs;
306+
}
307+
}
308+
while( $tabs > 0 );
309+
}
310+
280311
# ~
281312

282313
$Line = array('body' => $line, 'indent' => $indent, 'text' => $text);
@@ -1141,6 +1172,10 @@ protected function lineElements($text, $nonNestables = array()){
11411172

11421173
$Excerpt = array('text' => $excerpt, 'context' => $text);
11431174

1175+
if( !array_key_exists( $marker, $ActiveInlineTypes ) || !is_array( $ActiveInlineTypes[$marker] ) ){
1176+
$ActiveInlineTypes[$marker] = array();
1177+
}
1178+
11441179
foreach($ActiveInlineTypes[$marker] as $inlineType){
11451180
# check to see if the current inline type is nestable in the current context
11461181

@@ -1647,14 +1682,16 @@ protected function blockLiturgicalIntercession( $Line, array $CurrentBlock = nul
16471682
'marker' => $element,
16481683
),
16491684
'element' => array(
1650-
'name' => 'section',
1651-
'attributes' => array(
1652-
'class' => 'intercession'
1653-
),
1685+
'name' => 'p',
16541686
'elements' => array(),
16551687
),
16561688
);
16571689

1690+
if( $this->liturgicalHTML ){
1691+
$Block['element']['name'] = 'section';
1692+
$Block['element']['attributes']['class'] = 'intercession';
1693+
}
1694+
16581695
// $Block['element']['elements'][] =
16591696
$this->blockLiturgicalIntercessionFormat( $element, $Text, $Block );
16601697

@@ -1682,12 +1719,15 @@ protected function blockLiturgicalIntercessionFormat( $Element, $Text, &$BlockRe
16821719
}
16831720

16841721

1722+
$Text = trim( $Text );
1723+
1724+
16851725
if( $Type == 'introduction'){
16861726
$Elements = array(
16871727
array(
16881728
'handler' => array(
16891729
'function' => 'lineElements',
1690-
'argument' => ' ' . $Text,
1730+
'argument' => $Text,
16911731
'destination' => 'elements',
16921732
),
16931733
)
@@ -1696,30 +1736,31 @@ protected function blockLiturgicalIntercessionFormat( $Element, $Text, &$BlockRe
16961736
}else if ( $Type == 'response' ){
16971737
$Elements = array(
16981738
array(
1699-
'name' => 'span',
1739+
// 'name' => 'span',
17001740
'rawHtml' => '&nbsp;&nbsp;&nbsp;&nbsp;',
17011741
'allowRawHtmlInSafeMode' => true,
1702-
'attributes' => array(
1703-
'class' => 'spacer',
1704-
),
1742+
// 'attributes' => array(
1743+
// 'class' => 'spacer',
1744+
// ),
17051745
),
17061746
array(
1747+
'name' => 'em',
17071748
'handler' => array(
17081749
'function' => 'lineElements',
17091750
'argument' => $Text,
17101751
'destination' => 'elements',
17111752
),
17121753
)
17131754
);
1755+
1756+
if( $this->liturgicalHTML ){
1757+
$Elements[0]['name'] = 'span';
1758+
$Elements[0]['attributes']['class'] = 'spacer';
1759+
unset( $Elements[1]['name'] );
1760+
}
1761+
17141762
}else if ( $Type == 'part1' ){
17151763
$Elements = array(
1716-
// array(
1717-
// 'name' => 'span',
1718-
// 'text' => ' ',
1719-
// 'attributes' => array(
1720-
// 'class' => 'spacer',
1721-
// ),
1722-
// ),
17231764
array(
17241765
'handler' => array(
17251766
'function' => 'lineElements',
@@ -1731,13 +1772,12 @@ protected function blockLiturgicalIntercessionFormat( $Element, $Text, &$BlockRe
17311772
}else if ( $Type == 'part2' ){
17321773
$Elements = array(
17331774
array(
1734-
'name' => 'span',
1775+
// 'name' => 'span',
17351776
'rawHtml' => '&nbsp;&nbsp;&nbsp;&nbsp;– ',
17361777
'allowRawHtmlInSafeMode' => true,
1737-
// 'text' =>
1738-
'attributes' => array(
1739-
'class' => 'spacer',
1740-
),
1778+
// 'attributes' => array(
1779+
// 'class' => 'spacer',
1780+
// ),
17411781
),
17421782
array(
17431783
'handler' => array(
@@ -1747,30 +1787,60 @@ protected function blockLiturgicalIntercessionFormat( $Element, $Text, &$BlockRe
17471787
),
17481788
)
17491789
);
1790+
1791+
if( $this->liturgicalHTML ){
1792+
$Elements[0]['name'] = 'span';
1793+
$Elements[0]['attributes']['class'] = 'spacer';
1794+
unset( $Elements[1]['name'] );
1795+
}
17501796
}
17511797

1752-
$ThisBlock = array(
1753-
'name' => 'div',
1754-
'attributes' => array(
1755-
'class' => 'part-' . $Type,
1756-
),
1757-
'elements' => $Elements
1758-
);
1798+
1799+
1800+
if( $this->liturgicalHTML ){
1801+
$ThisBlock = array(
1802+
'name' => 'div',
1803+
'attributes' => array(
1804+
'class' => 'part-' . $Type,
1805+
),
1806+
'elements' => $Elements
1807+
);
1808+
}else{
1809+
$ThisBlock = $Elements;
1810+
$ThisBlock[] = array('name' => 'br');
1811+
}
17591812

17601813
if ( $Type == 'response' ){
17611814
$this->intercessionResponse = $ThisBlock;
17621815
}
17631816

1764-
$BlockReference['element']['elements'][] = $ThisBlock;
1817+
1818+
1819+
if( $this->liturgicalHTML ){
1820+
$BlockReference['element']['elements'][] = $ThisBlock;
1821+
}else{
1822+
foreach( $ThisBlock as $a ){
1823+
$BlockReference['element']['elements'][] = $a;
1824+
}
1825+
}
1826+
1827+
1828+
// var_dump( $BlockReference );
17651829

17661830
if( $Type == 'part2' ){
17671831
// Add the Response again
1768-
$BlockReference['element']['elements'][] = $this->intercessionResponse;
1832+
// $BlockReference['element']['elements'][] = $this->intercessionResponse;
1833+
if( $this->liturgicalHTML ){
1834+
$BlockReference['element']['elements'][] = $this->intercessionResponse;
1835+
}else{
1836+
foreach( $this->intercessionResponse as $a ){
1837+
$BlockReference['element']['elements'][] = $a;
1838+
}
1839+
}
17691840
}
17701841

17711842

17721843
return;
1773-
// return $Elements;
17741844
}
17751845

17761846
protected function blockLiturgicalIntercessionContinue($Line, array $CurrentBlock){
@@ -1789,6 +1859,18 @@ protected function blockLiturgicalIntercessionContinue($Line, array $CurrentBloc
17891859

17901860
}
17911861

1862+
protected function blockLiturgicalIntercessionComplete(array $CurrentBlock){
1863+
// Remove the trailing <br> from the non-HTML version
1864+
if( $this->liturgicalHTML == false ){
1865+
$Elements = count( $CurrentBlock['element']['elements'] );
1866+
if( $CurrentBlock['element']['elements'][ $Elements - 1]['name'] == 'br'){
1867+
unset( $CurrentBlock['element']['elements'][$Elements-1] );
1868+
}
1869+
}
1870+
1871+
return $CurrentBlock;
1872+
}
1873+
17921874
protected function inlineLiturgicalCross($Excerpt){
17931875
$Element = array(
17941876
'rawHtml' => "&#10011;",
@@ -1805,7 +1887,7 @@ protected function inlineLiturgicalCross($Excerpt){
18051887
$extent = 0;
18061888
$remainder = $Excerpt['text'];
18071889

1808-
if( preg_match('/\[\+\]/', $remainder, $matches) ){
1890+
if( preg_match('/^\[\+\]/', $remainder, $matches) ){
18091891
$extent += strlen($matches[0]);
18101892
$remainder = substr($remainder, $extent);
18111893
}else{
@@ -1821,7 +1903,7 @@ protected function inlineLiturgicalCross($Excerpt){
18211903

18221904
protected function inlineLiturgicalMidpoint( $Excerpt ){
18231905
$Element = array(
1824-
'rawHtml' => "*",
1906+
'text' => " *", // Include the space to ensure it always has a space to the left (multiple spaces will collapse)
18251907
// 'allowRawHtmlInSafeMode' => true,
18261908
);
18271909
if( $this->liturgicalHTML ){
@@ -1834,7 +1916,7 @@ protected function inlineLiturgicalMidpoint( $Excerpt ){
18341916
$extent = 0;
18351917
$remainder = $Excerpt['text'];
18361918

1837-
if( preg_match('/\[\*\]/', $remainder, $matches) ){
1919+
if( preg_match('/^\[\*\]/', $remainder, $matches) ){
18381920
$extent += strlen($matches[0]);
18391921
$remainder = substr($remainder, $extent);
18401922
}else{
@@ -1850,7 +1932,7 @@ protected function inlineLiturgicalMidpoint( $Excerpt ){
18501932

18511933
protected function inlineLiturgicalDagger( $Excerpt ){
18521934
$Element = array(
1853-
'rawHtml' => "&#8224;",
1935+
'rawHtml' => " &#8224;", // Include the space to ensure it always has a space to the left (multiple spaces will collapse)
18541936
'allowRawHtmlInSafeMode' => true,
18551937
);
18561938
if( $this->liturgicalHTML ){
@@ -1863,7 +1945,7 @@ protected function inlineLiturgicalDagger( $Excerpt ){
18631945
$extent = 0;
18641946
$remainder = $Excerpt['text'];
18651947

1866-
if( preg_match('/\[t\]/', $remainder, $matches) ){
1948+
if( preg_match('/^\[t\]/', $remainder, $matches) ){
18671949
$extent += strlen($matches[0]);
18681950
$remainder = substr($remainder, $extent);
18691951
}else{
@@ -1922,7 +2004,7 @@ protected function inlineOverUnderLine( $Excerpt ){
19222004
$extent = 0;
19232005
$remainder = $Excerpt['text'];
19242006

1925-
if( preg_match('/^_‾|‾_((.|\n)*?)_‾|‾_/u', $remainder, $matches) ){
2007+
if( preg_match('/^(?:_‾|‾_)((.|\n)*?)(?:‾_|_‾)/u', $remainder, $matches) ){
19262008
$extent += strlen($matches[0]);
19272009
$remainder = substr($remainder, $extent);
19282010
$Element['text'] = $matches[1];
@@ -1932,8 +2014,6 @@ protected function inlineOverUnderLine( $Excerpt ){
19322014
$remainder = substr($remainder, $extent);
19332015
$Element['text'] = $matches[1];
19342016
$Element['attributes']['class'] = 'text-overline';
1935-
1936-
// }else if( preg_match('/^_((.|\n)*?)_/', $remainder, $matches) ){
19372017
}else if ( preg_match('/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', $remainder, $matches) ){
19382018
$extent += strlen($matches[0]);
19392019
$remainder = substr($remainder, $extent);

docker/phpunit.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/bash
2+
3+
# run the PHPUnit tests
4+
docker exec -it textformater_nginx_php ./vendor/bin/phpunit --testdox test

test/SourceParserTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ function test_($test, $dir)
5353
$this->SourceParser->setSafeMode(substr($test, 0, 3) === 'xss');
5454
$this->SourceParser->setStrictMode(substr($test, 0, 6) === 'strict');
5555

56+
// Add support for Liturgical Elements
57+
$this->SourceParser->setLiturgicalElements(substr($test, 0, 7) === 'liturgy');
58+
$this->SourceParser->setPreserveIndentations(substr($test, 0, 11) === 'indentation');
59+
$this->SourceParser->setLiturgicalHTML( strpos($test, '_lesstags_') === false );
60+
5661
$actualMarkup = $this->SourceParser->text( $markdown );
5762

5863
$this->assertEquals($expectedMarkup, $actualMarkup, "This Test: " . $test );
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<p>Normal level text that is flush,<br />
2+
with a second line flush as well.<br />
3+
&nbsp;&nbsp;&nbsp;&nbsp;Now this is indented<br />
4+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;This is even more indented. Like way to much!<br />
5+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AND HOW!</p>
6+
<p>&nbsp;&nbsp;&nbsp;&nbsp;This will be rendered as code. Since it's indented alone. But yea, you can indent things.<br />
7+
In any number of ways.<br />
8+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;It just looks at the start of the line for sets of spaces or tabs.</p>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Normal level text that is flush,
2+
with a second line flush as well.
3+
Now this is indented
4+
This is even more indented. Like way to much!
5+
AND HOW!
6+
7+
This will be rendered as code. Since it's indented alone. But yea, you can indent things.
8+
In any number of ways.
9+
It just looks at the start of the line for sets of spaces or tabs.

0 commit comments

Comments
 (0)