Merge pull request dart-lang/markdown#8 from kevmoo/master
A bunch of cleanup
diff --git a/pkgs/markdown/lib/markdown.dart b/pkgs/markdown/lib/markdown.dart
index 33d7c37..f127450 100644
--- a/pkgs/markdown/lib/markdown.dart
+++ b/pkgs/markdown/lib/markdown.dart
@@ -5,116 +5,8 @@
/// Parses text in a markdown-like format and renders to HTML.
library markdown;
-// TODO(rnystrom): Use "package:" URL (#4968).
-part 'src/markdown/ast.dart';
-part 'src/markdown/block_parser.dart';
-part 'src/markdown/html_renderer.dart';
-part 'src/markdown/inline_parser.dart';
-
-typedef Node Resolver(String name);
-
-/// Converts the given string of markdown to HTML.
-String markdownToHtml(String markdown, {inlineSyntaxes, linkResolver,
- bool inlineOnly: false}) {
- final document = new Document(inlineSyntaxes: inlineSyntaxes,
- linkResolver: linkResolver);
-
- if (inlineOnly) {
- return renderToHtml(document.parseInline(markdown));
- } else {
- // Replace windows line endings with unix line endings, and split.
- final lines = markdown.replaceAll('\r\n','\n').split('\n');
- document.parseRefLinks(lines);
- final blocks = document.parseLines(lines);
- return renderToHtml(blocks);
- }
-}
-
-/// Replaces `<`, `&`, and `>`, with their HTML entity equivalents.
-String escapeHtml(String html) {
- return html.replaceAll('&', '&')
- .replaceAll('<', '<')
- .replaceAll('>', '>');
-}
-
-/// Maintains the context needed to parse a markdown document.
-class Document {
- final Map<String, Link> refLinks;
- List<InlineSyntax> inlineSyntaxes;
- Resolver linkResolver;
-
- Document({this.inlineSyntaxes, this.linkResolver})
- : refLinks = <String, Link>{};
-
- 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.
- final indent = r'^[ ]{0,3}'; // Leading indentation.
- final id = r'\[([^\]]+)\]'; // Reference id in [brackets].
- final quote = r'"[^"]+"'; // Title in "double quotes".
- final apos = r"'[^']+'"; // Title in 'single quotes'.
- final paren = r"\([^)]+\)"; // Title in (parentheses).
- final pattern = new RegExp(
- '$indent$id:\\s+(\\S+)\\s*($quote|$apos|$paren|)\\s*\$');
-
- for (int i = 0; i < lines.length; i++) {
- final 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] = '';
- }
- }
- }
-
- /// Parse the given [lines] of markdown to a series of AST nodes.
- List<Node> parseLines(List<String> lines) {
- final parser = new BlockParser(lines, this);
-
- final blocks = [];
- while (!parser.isDone) {
- for (final syntax in BlockSyntax.syntaxes) {
- if (syntax.canParse(parser)) {
- final block = syntax.parse(parser);
- if (block != null) blocks.add(block);
- break;
- }
- }
- }
-
- return blocks;
- }
-
- /// Takes a string of raw text and processes all inline markdown tags,
- /// returning a list of AST nodes. For example, given ``"*this **is** a*
- /// `markdown`"``, returns:
- /// `<em>this <strong>is</strong> a</em> <code>markdown</code>`.
- 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);
-}
+export 'src/ast.dart';
+export 'src/block_parser.dart';
+export 'src/document.dart';
+export 'src/html_renderer.dart';
+export 'src/inline_parser.dart';
diff --git a/pkgs/markdown/lib/src/markdown/ast.dart b/pkgs/markdown/lib/src/ast.dart
similarity index 96%
rename from pkgs/markdown/lib/src/markdown/ast.dart
rename to pkgs/markdown/lib/src/ast.dart
index c966cea..befd75e 100644
--- a/pkgs/markdown/lib/src/markdown/ast.dart
+++ b/pkgs/markdown/lib/src/ast.dart
@@ -2,7 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of markdown;
+library markdown.ast;
+
+typedef Node Resolver(String name);
/// Base class for any AST item. Roughly corresponds to Node in the DOM. Will
/// be either an Element or Text.
diff --git a/pkgs/markdown/lib/src/markdown/block_parser.dart b/pkgs/markdown/lib/src/block_parser.dart
similarity index 92%
rename from pkgs/markdown/lib/src/markdown/block_parser.dart
rename to pkgs/markdown/lib/src/block_parser.dart
index d163e9c..c34f7db 100644
--- a/pkgs/markdown/lib/src/markdown/block_parser.dart
+++ b/pkgs/markdown/lib/src/block_parser.dart
@@ -2,7 +2,11 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of markdown;
+library markdown.block_parser;
+
+import 'ast.dart';
+import 'document.dart';
+import 'util.dart';
/// The line contains only whitespace or is empty.
final _RE_EMPTY = new RegExp(r'^([ \t]*)$');
@@ -51,26 +55,26 @@
final Document document;
/// Index of the current line.
- int pos;
+ int _pos;
BlockParser(this.lines, this.document)
- : pos = 0;
+ : _pos = 0;
/// Gets the current line.
- String get current => lines[pos];
+ String get current => lines[_pos];
/// Gets the line after the current one or `null` if there is none.
String get next {
// Don't read past the end.
- if (pos >= lines.length - 1) return null;
- return lines[pos + 1];
+ if (_pos >= lines.length - 1) return null;
+ return lines[_pos + 1];
}
void advance() {
- pos++;
+ _pos++;
}
- bool get isDone => pos >= lines.length;
+ bool get isDone => _pos >= lines.length;
/// Gets whether or not the current line matches the given pattern.
bool matches(RegExp regex) {
@@ -88,28 +92,21 @@
abstract class BlockSyntax {
/// Gets the collection of built-in block parsers. To turn a series of lines
/// into blocks, each of these will be tried in turn. Order matters here.
- static List<BlockSyntax> get syntaxes {
- // Lazy initialize.
- if (_syntaxes == null) {
- _syntaxes = [
- new EmptyBlockSyntax(),
- new BlockHtmlSyntax(),
- new SetextHeaderSyntax(),
- new HeaderSyntax(),
- new CodeBlockSyntax(),
- new FencedCodeBlockSyntax(),
- new BlockquoteSyntax(),
- new HorizontalRuleSyntax(),
- new UnorderedListSyntax(),
- new OrderedListSyntax(),
- new ParagraphSyntax()
- ];
- }
+ static const List<BlockSyntax> syntaxes = const[
+ const EmptyBlockSyntax(),
+ const BlockHtmlSyntax(),
+ const SetextHeaderSyntax(),
+ const HeaderSyntax(),
+ const CodeBlockSyntax(),
+ const FencedCodeBlockSyntax(),
+ const BlockquoteSyntax(),
+ const HorizontalRuleSyntax(),
+ const UnorderedListSyntax(),
+ const OrderedListSyntax(),
+ const ParagraphSyntax()
+ ];
- return _syntaxes;
- }
-
- static List<BlockSyntax> _syntaxes;
+ const BlockSyntax();
/// Gets the regex used to identify the beginning of this block, if any.
RegExp get pattern => null;
@@ -146,6 +143,8 @@
class EmptyBlockSyntax extends BlockSyntax {
RegExp get pattern => _RE_EMPTY;
+ const EmptyBlockSyntax();
+
Node parse(BlockParser parser) {
parser.advance();
@@ -156,6 +155,9 @@
/// Parses setext-style headers.
class SetextHeaderSyntax extends BlockSyntax {
+
+ const SetextHeaderSyntax();
+
bool canParse(BlockParser parser) {
// Note: matches *next* line, not the current one. We're looking for the
// underlining after this line.
@@ -178,6 +180,8 @@
class HeaderSyntax extends BlockSyntax {
RegExp get pattern => _RE_HEADER;
+ const HeaderSyntax();
+
Node parse(BlockParser parser) {
final match = pattern.firstMatch(parser.current);
parser.advance();
@@ -191,6 +195,8 @@
class BlockquoteSyntax extends BlockSyntax {
RegExp get pattern => _RE_BLOCKQUOTE;
+ const BlockquoteSyntax();
+
Node parse(BlockParser parser) {
final childLines = parseChildLines(parser);
@@ -205,6 +211,8 @@
class CodeBlockSyntax extends BlockSyntax {
RegExp get pattern => _RE_INDENT;
+ const CodeBlockSyntax();
+
List<String> parseChildLines(BlockParser parser) {
final childLines = <String>[];
@@ -249,7 +257,11 @@
class FencedCodeBlockSyntax extends BlockSyntax {
RegExp get pattern => _RE_CODE;
- List<String> parseChildLines(BlockParser parser, String endBlock) {
+ const FencedCodeBlockSyntax();
+
+ List<String> parseChildLines(BlockParser parser, [String endBlock]) {
+ if(endBlock == null) endBlock = '';
+
final childLines = <String>[];
parser.advance();
while (!parser.isDone) {
@@ -285,16 +297,14 @@
}
return element;
}
-
- void _addElementAttributes(Element element) {
-
- }
}
/// Parses horizontal rules like `---`, `_ _ _`, `* * *`, etc.
class HorizontalRuleSyntax extends BlockSyntax {
RegExp get pattern => _RE_HR;
+ const HorizontalRuleSyntax();
+
Node parse(BlockParser parser) {
final match = pattern.firstMatch(parser.current);
parser.advance();
@@ -317,6 +327,8 @@
bool get canEndBlock => false;
+ const BlockHtmlSyntax();
+
Node parse(BlockParser parser) {
final childLines = [];
@@ -343,6 +355,8 @@
String get listTag;
+ const ListSyntax();
+
Node parse(BlockParser parser) {
final items = <ListItem>[];
var childLines = <String>[];
@@ -485,18 +499,24 @@
class UnorderedListSyntax extends ListSyntax {
RegExp get pattern => _RE_UL;
String get listTag => 'ul';
+
+ const UnorderedListSyntax();
}
/// Parses ordered lists.
class OrderedListSyntax extends ListSyntax {
RegExp get pattern => _RE_OL;
String get listTag => 'ol';
+
+ const OrderedListSyntax();
}
/// Parses paragraphs of regular text.
class ParagraphSyntax extends BlockSyntax {
bool get canEndBlock => false;
+ const ParagraphSyntax();
+
bool canParse(BlockParser parser) => true;
Node parse(BlockParser parser) {
diff --git a/pkgs/markdown/lib/src/document.dart b/pkgs/markdown/lib/src/document.dart
new file mode 100644
index 0000000..7ed01ca
--- /dev/null
+++ b/pkgs/markdown/lib/src/document.dart
@@ -0,0 +1,87 @@
+library markdown.document;
+
+import 'ast.dart';
+import 'block_parser.dart';
+import 'inline_parser.dart';
+
+/// Maintains the context needed to parse a markdown document.
+class Document {
+ final Map<String, Link> refLinks;
+ List<InlineSyntax> inlineSyntaxes;
+ Resolver linkResolver;
+
+ Document({this.inlineSyntaxes, this.linkResolver})
+ : refLinks = <String, Link>{};
+
+ 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.
+ final indent = r'^[ ]{0,3}'; // Leading indentation.
+ final id = r'\[([^\]]+)\]'; // Reference id in [brackets].
+ final quote = r'"[^"]+"'; // Title in "double quotes".
+ final apos = r"'[^']+'"; // Title in 'single quotes'.
+ final paren = r"\([^)]+\)"; // Title in (parentheses).
+ final pattern = new RegExp(
+ '$indent$id:\\s+(\\S+)\\s*($quote|$apos|$paren|)\\s*\$');
+
+ for (int i = 0; i < lines.length; i++) {
+ final 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] = '';
+ }
+ }
+ }
+
+ /// Parse the given [lines] of markdown to a series of AST nodes.
+ List<Node> parseLines(List<String> lines) {
+ final parser = new BlockParser(lines, this);
+
+ final blocks = [];
+ while (!parser.isDone) {
+ for (final syntax in BlockSyntax.syntaxes) {
+ if (syntax.canParse(parser)) {
+ final block = syntax.parse(parser);
+ if (block != null) blocks.add(block);
+ break;
+ }
+ }
+ }
+
+ return blocks;
+ }
+
+ /// Takes a string of raw text and processes all inline markdown tags,
+ /// returning a list of AST nodes. For example, given ``"*this **is** a*
+ /// `markdown`"``, returns:
+ /// `<em>this <strong>is</strong> a</em> <code>markdown</code>`.
+ 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);
+}
diff --git a/pkgs/markdown/lib/src/markdown/html_renderer.dart b/pkgs/markdown/lib/src/html_renderer.dart
similarity index 70%
rename from pkgs/markdown/lib/src/markdown/html_renderer.dart
rename to pkgs/markdown/lib/src/html_renderer.dart
index 5494394..97b900b 100644
--- a/pkgs/markdown/lib/src/markdown/html_renderer.dart
+++ b/pkgs/markdown/lib/src/html_renderer.dart
@@ -2,7 +2,27 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of markdown;
+library markdown.html_renderer;
+
+import 'ast.dart';
+import 'document.dart';
+
+/// Converts the given string of markdown to HTML.
+String markdownToHtml(String markdown, {inlineSyntaxes, linkResolver,
+ bool inlineOnly: false}) {
+ var document = new Document(inlineSyntaxes: inlineSyntaxes,
+ linkResolver: linkResolver);
+
+ if (inlineOnly) {
+ return renderToHtml(document.parseInline(markdown));
+ } else {
+ // Replace windows line endings with unix line endings, and split.
+ var lines = markdown.replaceAll('\r\n','\n').split('\n');
+ document.parseRefLinks(lines);
+ var blocks = document.parseLines(lines);
+ return renderToHtml(blocks);
+ }
+}
String renderToHtml(List<Node> nodes) => new HtmlRenderer().render(nodes);
diff --git a/pkgs/markdown/lib/src/markdown/inline_parser.dart b/pkgs/markdown/lib/src/inline_parser.dart
similarity index 98%
rename from pkgs/markdown/lib/src/markdown/inline_parser.dart
rename to pkgs/markdown/lib/src/inline_parser.dart
index d141659..392ca69 100644
--- a/pkgs/markdown/lib/src/markdown/inline_parser.dart
+++ b/pkgs/markdown/lib/src/inline_parser.dart
@@ -2,7 +2,11 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of markdown;
+library markdown.inline_parser;
+
+import 'ast.dart';
+import 'document.dart';
+import 'util.dart';
/// Maintains the internal state needed to parse inline span elements in
/// markdown.
diff --git a/pkgs/markdown/lib/src/util.dart b/pkgs/markdown/lib/src/util.dart
new file mode 100644
index 0000000..a6d52de
--- /dev/null
+++ b/pkgs/markdown/lib/src/util.dart
@@ -0,0 +1,8 @@
+library markdown.util;
+
+/// Replaces `<`, `&`, and `>`, with their HTML entity equivalents.
+String escapeHtml(String html) {
+ return html.replaceAll('&', '&')
+ .replaceAll('<', '<')
+ .replaceAll('>', '>');
+}
diff --git a/pkgs/markdown/pubspec.yaml b/pkgs/markdown/pubspec.yaml
index 331513f..cb5bc77 100644
--- a/pkgs/markdown/pubspec.yaml
+++ b/pkgs/markdown/pubspec.yaml
@@ -1,7 +1,9 @@
name: markdown
-version: 0.5.0
+version: 0.5.1-dev
author: Dart Team <misc@dartlang.org>
description: A library for converting markdown to HTML.
homepage: https://github.com/dpeek/dart-markdown
+environment:
+ sdk: '>=1.0.0 <2.0.0'
dev_dependencies:
- unittest: any
+ unittest: '>=0.9.0 <0.11.0'
diff --git a/pkgs/markdown/test/markdown_test.dart b/pkgs/markdown/test/markdown_test.dart
index 91019fe..3c4564b 100644
--- a/pkgs/markdown/test/markdown_test.dart
+++ b/pkgs/markdown/test/markdown_test.dart
@@ -6,9 +6,7 @@
library markdownTests;
import 'package:unittest/unittest.dart';
-
-// TODO(rnystrom): Use "package:" URL (#4968).
-import '../lib/markdown.dart';
+import 'package:markdown/markdown.dart';
/// Most of these tests are based on observing how showdown behaves:
/// http://softwaremaniacs.org/playground/showdown-highlight/
@@ -961,7 +959,7 @@
return lines.join('\n');
}
-validate(String description, String markdown, String html,
+void validate(String description, String markdown, String html,
{bool verbose: false, inlineSyntaxes, linkResolver,
bool inlineOnly: false}) {
test(description, () {
@@ -976,19 +974,18 @@
// Remove trailing newline.
html = html.substring(0, html.length - 1);
- print('FAIL: $description');
- print(' expect: ${html.replaceAll("\n", "\n ")}');
- print(' actual: ${result.replaceAll("\n", "\n ")}');
- print('');
- }
+ var sb = new StringBuffer();
+ sb.writeln('Expected: ${html.replaceAll("\n", "\n ")}');
+ sb.writeln(' Actual: ${result.replaceAll("\n", "\n ")}');
- expect(passed, isTrue, verbose: verbose);
+ fail(sb.toString());
+ }
});
}
/// Does a loose comparison of the two strings of HTML. Ignores differences in
/// newlines and indentation.
-compareOutput(String a, String b) {
+bool compareOutput(String a, String b) {
int i = 0;
int j = 0;