blob: 8720ff0d3933f7abd81294872230350fa12d33d3 [file] [log] [blame]
library markdown.src.document;
import 'ast.dart';
import 'block_parser.dart';
import 'extension_set.dart';
import 'inline_parser.dart';
/// Maintains the context needed to parse a Markdown document.
class Document {
final Map<String, Link> refLinks = {};
Iterable<BlockSyntax> blockSyntaxes;
Iterable<InlineSyntax> inlineSyntaxes;
ExtensionSet extensionSet;
Resolver linkResolver;
Resolver imageLinkResolver;
Document(
{Iterable<BlockSyntax> blockSyntaxes,
Iterable<InlineSyntax> inlineSyntaxes,
ExtensionSet extensionSet,
this.linkResolver,
this.imageLinkResolver}) {
this.extensionSet = extensionSet ?? ExtensionSet.commonMark;
this.blockSyntaxes = new Set()
..addAll(blockSyntaxes ?? [])
..addAll(this.extensionSet.blockSyntaxes);
this.inlineSyntaxes = new Set()
..addAll(inlineSyntaxes ?? [])
..addAll(this.extensionSet.inlineSyntaxes);
}
/// Parses [lines] for reference links, adding them to [refLinks] and
/// replaces their source lines with blank lines.
parseRefLinks(List<String> lines) {
// This is a hideous regex. It matches:
// [id]: http:foo.com "some title"
// Where there may whitespace in there, and where the title may be in
// single quotes, double quotes, or parentheses.
var indent = r'^[ ]{0,3}'; // Leading indentation.
var id = r'\[([^\]]+)\]'; // Reference id in [brackets].
var quote = r'"[^"]+"'; // Title in "double quotes".
var apos = r"'[^']+'"; // Title in 'single quotes'.
var paren = r"\([^)]+\)"; // Title in (parentheses).
var pattern =
new RegExp('$indent$id:\\s+(\\S+)\\s*($quote|$apos|$paren|)\\s*\$');
for (var i = 0; i < lines.length; i++) {
var match = pattern.firstMatch(lines[i]);
if (match != null) {
// Parse the link.
var id = match[1];
var url = match[2];
var title = match[3];
if (title == '') {
// No title.
title = null;
} else {
// Remove "", '', or ().
title = title.substring(1, title.length - 1);
}
// References are case-insensitive.
id = id.toLowerCase();
refLinks[id] = new Link(id, url, title);
// Remove it from the output. We replace it with a blank line which will
// get consumed by later processing.
lines[i] = '';
}
}
}
/// Parses the given [lines] of Markdown to a series of AST nodes.
List<Node> parseLines(List<String> lines) {
var parser = new BlockParser(lines, this);
var blocks = <Node>[];
while (!parser.isDone) {
for (var syntax in parser.blockSyntaxes) {
if (syntax.canParse(parser)) {
var block = syntax.parse(parser);
if (block != null) blocks.add(block);
break;
}
}
}
return blocks;
}
/// Parses the given inline Markdown [text] to a series of AST nodes.
List<Node> parseInline(String text) => new InlineParser(text, this).parse();
}
class Link {
final String id;
final String url;
final String title;
Link(this.id, this.url, this.title);
}