Java library for parsing and rendering Markdown text according to the CommonMark specification
—
Complete Markdown parsing functionality that converts text input into a structured Abstract Syntax Tree (AST). The parser supports all CommonMark specification features with extensive configuration options for customization and extensibility.
Main parsing class that converts CommonMark text to AST nodes.
/**
* Parses input text to a tree of nodes.
* Thread-safe parser that can be reused across multiple parsing operations.
*/
public class Parser {
/**
* Create a new builder for configuring a Parser
* @return a builder instance
*/
public static Builder builder();
/**
* Parse the specified input text into a tree of nodes.
* This method is thread-safe (a new parser state is used for each invocation).
* @param input the text to parse - must not be null
* @return the root node (Document)
*/
public Node parse(String input);
/**
* Parse the specified reader into a tree of nodes. The caller is responsible for closing the reader.
* This method is thread-safe (a new parser state is used for each invocation).
* @param input the reader to parse - must not be null
* @return the root node (Document)
* @throws IOException when reading throws an exception
*/
public Node parseReader(Reader input) throws IOException;
}Usage Examples:
import org.commonmark.parser.Parser;
import org.commonmark.node.Node;
// Basic parsing
Parser parser = Parser.builder().build();
Node document = parser.parse("# Hello World\n\nThis is **bold** text.");
// Parse from file
try (FileReader reader = new FileReader("document.md")) {
Node document = parser.parseReader(reader);
}
// Parse with custom configuration
Parser customParser = Parser.builder()
.includeSourceSpans(IncludeSourceSpans.BLOCKS)
.build();
Node documentWithSpans = customParser.parse("# Heading");Builder class for configuring Parser instances with custom options and extensions.
/**
* Builder for configuring a Parser
*/
public static class Parser.Builder {
/**
* Build the configured Parser instance
* @return the configured Parser
*/
public Parser build();
/**
* Add extensions to use on this parser
* @param extensions extensions to use on this parser
* @return this builder
*/
public Builder extensions(Iterable<? extends Extension> extensions);
/**
* Describe the list of markdown features the parser will recognize and parse.
* By default, all CommonMark block types are enabled.
* @param enabledBlockTypes A set of block nodes the parser will parse
* @return this builder
*/
public Builder enabledBlockTypes(Set<Class<? extends Block>> enabledBlockTypes);
/**
* Whether to calculate source spans for nodes
* @param includeSourceSpans which kind of source spans should be included
* @return this builder
*/
public Builder includeSourceSpans(IncludeSourceSpans includeSourceSpans);
/**
* Add a custom block parser factory
* @param blockParserFactory a block parser factory implementation
* @return this builder
*/
public Builder customBlockParserFactory(BlockParserFactory blockParserFactory);
/**
* Add a custom delimiter processor
* @param delimiterProcessor a delimiter processor implementation
* @return this builder
*/
public Builder customDelimiterProcessor(DelimiterProcessor delimiterProcessor);
/**
* Add a post processor that runs after parsing
* @param postProcessor a post processor implementation
* @return this builder
*/
public Builder postProcessor(PostProcessor postProcessor);
/**
* Override the parser used for inline markdown processing
* @param inlineParserFactory an inline parser factory implementation
* @return this builder
*/
public Builder inlineParserFactory(InlineParserFactory inlineParserFactory);
}Usage Examples:
import org.commonmark.parser.Parser;
import org.commonmark.parser.IncludeSourceSpans;
import org.commonmark.node.*;
// Enable only specific block types
Set<Class<? extends Block>> enabledTypes = new HashSet<>(Arrays.asList(
Heading.class,
Paragraph.class,
ListBlock.class
));
Parser restrictedParser = Parser.builder()
.enabledBlockTypes(enabledTypes)
.build();
// Include source span information
Parser spanParser = Parser.builder()
.includeSourceSpans(IncludeSourceSpans.BLOCKS_AND_INLINES)
.build();
Node document = spanParser.parse("# Title");
List<SourceSpan> spans = document.getSourceSpans();
// Add custom post-processor
Parser processedParser = Parser.builder()
.postProcessor(new MyCustomPostProcessor())
.build();Configuration enums and interfaces for customizing parser behavior.
/**
* Configuration for including source span information
*/
public enum IncludeSourceSpans {
/** Do not include source spans */
NONE,
/** Include source spans on block nodes */
BLOCKS,
/** Include source spans on all nodes */
BLOCKS_AND_INLINES
}
/**
* Post-processes nodes after parsing
*/
public interface PostProcessor {
/**
* Process the document node after parsing is complete
* @param node the document node to process
* @return the processed node (may be the same or a new node)
*/
Node process(Node node);
}
/**
* Factory for creating inline parsers
*/
public interface InlineParserFactory {
/**
* Create an inline parser with the given context
* @param inlineParserContext the context for inline parsing
* @return an inline parser instance
*/
InlineParser create(InlineParserContext inlineParserContext);
}
/**
* Parser factory for a block node for determining when a block starts.
* Implementations should subclass AbstractBlockParserFactory instead of implementing this directly.
*/
public interface BlockParserFactory {
/**
* Try to start parsing a block at the current position
* @param state the current parser state
* @param matchedBlockParser the matched block parser
* @return a BlockStart if this factory can start a block, null otherwise
*/
BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser);
}
/**
* Custom delimiter processor for additional delimiters besides underscore and asterisk.
* Implementations must be thread-safe as the same instance may be used by multiple parsers.
*/
public interface DelimiterProcessor {
/**
* Get the character that marks the beginning of a delimited node
* @return the opening character, must not clash with built-in special characters
*/
char getOpeningCharacter();
/**
* Get the character that marks the ending of a delimited node
* @return the closing character, must not clash with built-in special characters
*/
char getClosingCharacter();
/**
* Minimum number of delimiter characters needed to activate this processor
* @return the minimum length, must be at least 1
*/
int getMinLength();
/**
* Process the delimiter runs
* @param openingRun the opening delimiter run
* @param closingRun the closing delimiter run
* @return how many delimiters were used; must not be greater than length of either opener or closer
*/
int process(DelimiterRun openingRun, DelimiterRun closingRun);
}Classes for handling source input and tracking source positions.
/**
* Represents a line from source input
*/
public class SourceLine {
/**
* Get the content of this source line
* @return the line content
*/
public CharSequence getContent();
/**
* Get the line number (0-based)
* @return the line number
*/
public int getLineIndex();
}
/**
* Set of source lines
*/
public class SourceLines {
/**
* Create an empty SourceLines
* @return empty SourceLines instance
*/
public static SourceLines empty();
/**
* Create SourceLines from a single line
* @param sourceLine the source line
* @return SourceLines containing the single line
*/
public static SourceLines of(SourceLine sourceLine);
/**
* Add a line to this SourceLines
* @param sourceLine the line to add
*/
public void addLine(SourceLine sourceLine);
/**
* Get all lines
* @return list of source lines
*/
public List<SourceLine> getLines();
/**
* Check if this SourceLines is empty
* @return true if empty
*/
public boolean isEmpty();
/**
* Get the combined content of all lines
* @return the content as a string
*/
public String getContent();
}
/**
* References a snippet of text from source input
*/
public class SourceSpan {
/**
* Create a source span
* @param lineIndex the line index (0-based)
* @param columnIndex the column index (0-based)
* @param length the length of the span
* @return the source span
*/
public static SourceSpan of(int lineIndex, int columnIndex, int length);
/**
* Get the line index
* @return the line index (0-based)
*/
public int getLineIndex();
/**
* Get the column index
* @return the column index (0-based)
*/
public int getColumnIndex();
/**
* Get the length of the span
* @return the length
*/
public int getLength();
}Usage Examples:
import org.commonmark.parser.SourceLine;
import org.commonmark.parser.SourceLines;
import org.commonmark.node.SourceSpan;
// Working with source spans
Parser parser = Parser.builder()
.includeSourceSpans(IncludeSourceSpans.BLOCKS_AND_INLINES)
.build();
Node document = parser.parse("# Heading\n\nParagraph with *emphasis*");
List<SourceSpan> documentSpans = document.getSourceSpans();
// Find all heading nodes and their source positions
document.accept(new AbstractVisitor() {
@Override
public void visit(Heading heading) {
List<SourceSpan> spans = heading.getSourceSpans();
for (SourceSpan span : spans) {
System.out.println("Heading at line " + span.getLineIndex() +
", column " + span.getColumnIndex());
}
super.visit(heading);
}
});Install with Tessl CLI
npx tessl i tessl/maven-org-commonmark--commonmark