Support Markdown lists
This commit is contained in:
		
							parent
							
								
									301eaaf98d
								
							
						
					
					
						commit
						90f84950d2
					
				
					 24 changed files with 307 additions and 88 deletions
				
			
		|  | @ -46,9 +46,9 @@ public class GrammarGraphMLParser implements GraphMLParser { | |||
|     } | ||||
| 
 | ||||
|     private Node processNodeElem(final ParseTree nodeElem) { | ||||
|         final String id = extractAttribute(nodeElem.child("tag:node"), "id"); | ||||
|         final String id = extractAttribute(nodeElem.getChild("tag:node"), "id"); | ||||
| 
 | ||||
|         final Map<String, String> data = nodeElem.child("content").getChildren() | ||||
|         final Map<String, String> data = nodeElem.getChild("content").getChildren() | ||||
|                 .stream() | ||||
|                 .map(this::extractDataElemContent) | ||||
|                 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); | ||||
|  | @ -57,11 +57,11 @@ public class GrammarGraphMLParser implements GraphMLParser { | |||
|     } | ||||
| 
 | ||||
|     private Edge processEdgeElem(final ParseTree edgeElem) { | ||||
|         final String id = extractAttribute(edgeElem.child("tag:edge"), "id"); | ||||
|         final String source = extractAttribute(edgeElem.child("tag:edge"), "source"); | ||||
|         final String target = extractAttribute(edgeElem.child("tag:edge"), "target"); | ||||
|         final String id = extractAttribute(edgeElem.getChild("tag:edge"), "id"); | ||||
|         final String source = extractAttribute(edgeElem.getChild("tag:edge"), "source"); | ||||
|         final String target = extractAttribute(edgeElem.getChild("tag:edge"), "target"); | ||||
| 
 | ||||
|         final Map<String, String> data = edgeElem.child("content").getChildren() | ||||
|         final Map<String, String> data = edgeElem.getChild("content").getChildren() | ||||
|                 .stream() | ||||
|                 .map(this::extractDataElemContent) | ||||
|                 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); | ||||
|  | @ -70,16 +70,16 @@ public class GrammarGraphMLParser implements GraphMLParser { | |||
|     } | ||||
| 
 | ||||
|     private Map.Entry<String, String> extractDataElemContent(final ParseTree dataElem) { | ||||
|         final var attribute = extractAttribute(dataElem.child("tag:data"), "key"); | ||||
|         final var content = dataElem.child(1).getText(); | ||||
|         final var attribute = extractAttribute(dataElem.getChild("tag:data"), "key"); | ||||
|         final var content = dataElem.getChild(1).getText(); | ||||
|         return Map.entry(attribute, content); | ||||
|     } | ||||
| 
 | ||||
|     private String extractAttribute(final ParseTree tag, final String attributeKey) { | ||||
|         return tag.child("attributes").getChildren() | ||||
|         return tag.getChild("attributes").getChildren() | ||||
|                 .stream() | ||||
|                 .filter(a -> a.child(0).getText().equals(attributeKey)) | ||||
|                 .map(a -> a.child(1).getText()) | ||||
|                 .filter(a -> a.getChild(0).getText().equals(attributeKey)) | ||||
|                 .map(a -> a.getChild(1).getText()) | ||||
|                 .findFirst() | ||||
|                 .orElseThrow(); | ||||
|     } | ||||
|  |  | |||
|  | @ -7,21 +7,68 @@ import static com.albertoventurini.parsley.grammar.rules.Rules.*; | |||
| 
 | ||||
| public class MarkdownGrammar extends Grammar { | ||||
| 
 | ||||
|     private final char NEWLINE = '\n'; | ||||
| 
 | ||||
|     private final char BOLD_DELIMITER = '*'; | ||||
| 
 | ||||
|     private final char ITALIC_DELIMITER = '_'; | ||||
| 
 | ||||
|     private final Rule h1 = sequence( | ||||
|             character('#'), | ||||
|             takeWhile(c -> c != '\n') | ||||
|     ); | ||||
|             takeWhile(c -> c != NEWLINE).as("text") | ||||
|     ).as("h1"); | ||||
| 
 | ||||
|     private final Rule h2 = sequence( | ||||
|             string("##"), | ||||
|             takeWhile(c -> c != NEWLINE).as("text") | ||||
|     ).as("h2"); | ||||
| 
 | ||||
|     private final Rule h3 = sequence( | ||||
|             string("###"), | ||||
|             takeWhile(c -> c != NEWLINE).as("text") | ||||
|     ).as("h3"); | ||||
| 
 | ||||
|     private final Rule headers = sequence(oneOf(h3, h2, h1), zeroOrMore(character(NEWLINE))); | ||||
| 
 | ||||
|     private final Rule plainText = takeWhile(c -> | ||||
|             c != NEWLINE | ||||
|             && c != BOLD_DELIMITER | ||||
|             && c != ITALIC_DELIMITER | ||||
|     ).as("text"); | ||||
| 
 | ||||
|     private final Rule bold = sequence( | ||||
|             character(BOLD_DELIMITER), | ||||
|             takeWhile(c -> c != NEWLINE && c != BOLD_DELIMITER).as("bold"), | ||||
|             character(BOLD_DELIMITER) | ||||
|     ).as("boldWrapper"); | ||||
| 
 | ||||
|     private final Rule italic = sequence( | ||||
|             character(ITALIC_DELIMITER), | ||||
|             takeWhile(c -> c != NEWLINE && c != ITALIC_DELIMITER).as("italic"), | ||||
|             character(ITALIC_DELIMITER) | ||||
|     ).as("italicWrapper"); | ||||
| 
 | ||||
|     private final Rule text = oneOf( | ||||
|             bold, | ||||
|             italic, | ||||
|             plainText); | ||||
| 
 | ||||
|     private final Rule paragraph = sequence( | ||||
|             character('\n'), | ||||
|             takeWhile(c -> c != '\n') | ||||
|     ); | ||||
|             oneOrMore(text).as("paragraph"), | ||||
|             zeroOrMore(character(NEWLINE)) | ||||
|     ).as("paragraphWrapper"); | ||||
| 
 | ||||
|     private final Rule element = oneOf(h1, paragraph); | ||||
|     private final Rule listItem = sequence( | ||||
|             oneOf(string("* "), string("- ")), | ||||
|             takeWhile(c -> c != NEWLINE).as("listItem"), | ||||
|             character(NEWLINE) | ||||
|     ).as("listItemWrapper"); | ||||
| 
 | ||||
|     private final Rule elements = sequence(element); | ||||
|     private final Rule list = sequence(oneOrMore(listItem).as("list"), zeroOrMore(character(NEWLINE))); | ||||
| 
 | ||||
|     private final Rule document = zeroOrMore(elements); | ||||
|     private final Rule element = oneOf(headers, list, paragraph); | ||||
| 
 | ||||
|     private final Rule document = zeroOrMore(element); | ||||
| 
 | ||||
|     @Override | ||||
|     public Rule startRule() { | ||||
|  | @ -32,4 +79,9 @@ public class MarkdownGrammar extends Grammar { | |||
|     protected Rule commentRule() { | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected boolean whitespace(final char c) { | ||||
|         return c != '\n' && Character.isWhitespace(c); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,13 +0,0 @@ | |||
| package com.albertoventurini.parsley.examples.graphml; | ||||
| 
 | ||||
| import com.albertoventurini.parsley.examples.markdown.MarkdownGrammar; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| public class MarkdownGrammarTest { | ||||
| 
 | ||||
|     @Test | ||||
|     public void markdownGrammar_withH1AndParagraph_shouldParse() { | ||||
|         final MarkdownGrammar grammar = new MarkdownGrammar(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,73 @@ | |||
| package com.albertoventurini.parsley.examples.markdown; | ||||
| 
 | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.*; | ||||
| 
 | ||||
| public class MarkdownGrammarTest { | ||||
| 
 | ||||
|     private final MarkdownGrammar grammar = new MarkdownGrammar(); | ||||
| 
 | ||||
|     @Test | ||||
|     public void shouldParseH1() { | ||||
|         final var parseResult = grammar.parse("# hello world"); | ||||
| 
 | ||||
|         assertTrue(parseResult.isPresent()); | ||||
|         assertEquals("# hello world", parseResult.get().getText()); | ||||
|         assertTrue(parseResult.get().getFirstDescendantByName("h1").isPresent()); | ||||
|         assertEquals("# hello world", parseResult.get().getFirstDescendantByName("h1").get().getText()); | ||||
|         assertTrue(parseResult.get().getFirstDescendantByName("text").isPresent()); | ||||
|         assertEquals("hello world", parseResult.get().getFirstDescendantByName("text").get().getText()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void shouldParseH2() { | ||||
|         final var parseResult = grammar.parse("## hello world"); | ||||
| 
 | ||||
|         assertTrue(parseResult.isPresent()); | ||||
|         assertEquals("## hello world", parseResult.get().getText()); | ||||
|         assertTrue(parseResult.get().getFirstDescendantByName("h2").isPresent()); | ||||
|         assertEquals("## hello world", parseResult.get().getFirstDescendantByName("h2").get().getText()); | ||||
|         assertNotNull(parseResult.get().getFirstDescendantByName("text")); | ||||
|         assertTrue(parseResult.get().getFirstDescendantByName("text").isPresent()); | ||||
|         assertEquals("hello world", parseResult.get().getFirstDescendantByName("text").get().getText()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void shouldParseParagraph() { | ||||
|         final var parseResult = grammar.parse("hello world"); | ||||
| 
 | ||||
|         assertTrue(parseResult.isPresent()); | ||||
|         assertEquals("hello world", parseResult.get().getText()); | ||||
|         assertTrue(parseResult.get().getFirstDescendantByName("paragraph").isPresent()); | ||||
|         assertEquals("hello world", parseResult.get().getFirstDescendantByName("paragraph").get().getText()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void shouldParseParagraphWithBoldText() { | ||||
|         final var parseResult = grammar.parse("hello world   *bold text*  normal text"); | ||||
| 
 | ||||
|         assertTrue(parseResult.isPresent()); | ||||
|         assertTrue(parseResult.get().getFirstDescendantByName("paragraph").isPresent()); | ||||
|         assertEquals(3, parseResult.get().getFirstDescendantByName("paragraph").get().getChildren().size()); | ||||
|         assertEquals("bold text", parseResult.get().getFirstDescendantByName("bold").get().getText()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void shouldParseList() { | ||||
|         final var parseResult = grammar.parse("hello world\n" + | ||||
|                 "\n" + | ||||
|                 "* first item\n" + | ||||
|                 "* second item\n" + | ||||
|                 ""); | ||||
| 
 | ||||
|         assertTrue(parseResult.isPresent()); | ||||
|         assertTrue(parseResult.get().getFirstDescendantByName("paragraph").isPresent()); | ||||
|         assertEquals("hello world", parseResult.get().getFirstDescendantByName("paragraph").get().getText()); | ||||
|         assertTrue(parseResult.get().getFirstDescendantByName("list").isPresent()); | ||||
|         assertEquals(2, parseResult.get().getFirstDescendantByName("list").get().getChildren().size()); | ||||
|         assertEquals("first item", parseResult.get().getFirstDescendantByName("list").get().getChildren().get(0).getFirstDescendantByName("listItem").get().getText()); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue