Allow resolving links that contain inline syntax. Fixes dart-lang/markdown#42. R=sethladd@google.com Review URL: https://codereview.chromium.org//1274753003 .
diff --git a/pkgs/markdown/.gitignore b/pkgs/markdown/.gitignore index aac1f4f..282c7f8 100644 --- a/pkgs/markdown/.gitignore +++ b/pkgs/markdown/.gitignore
@@ -1,3 +1,4 @@ +.idea .packages .pub packages
diff --git a/pkgs/markdown/CHANGELOG.md b/pkgs/markdown/CHANGELOG.md index a4e3606..5432376 100644 --- a/pkgs/markdown/CHANGELOG.md +++ b/pkgs/markdown/CHANGELOG.md
@@ -1,3 +1,7 @@ +## 0.7.2 + +* Allow resolving links that contain inline syntax (#42). + ## 0.7.1+3 * Updated homepage.
diff --git a/pkgs/markdown/lib/src/html_renderer.dart b/pkgs/markdown/lib/src/html_renderer.dart index b2d96e7..835c178 100644 --- a/pkgs/markdown/lib/src/html_renderer.dart +++ b/pkgs/markdown/lib/src/html_renderer.dart
@@ -60,8 +60,6 @@ buffer.write('<${element.tag}'); // Sort the keys so that we generate stable output. - // TODO(rnystrom): This assumes keys returns a fresh mutable - // collection. final attributeNames = element.attributes.keys.toList(); attributeNames.sort((a, b) => a.compareTo(b)); for (final name in attributeNames) {
diff --git a/pkgs/markdown/lib/src/inline_parser.dart b/pkgs/markdown/lib/src/inline_parser.dart index 7638cdd..c9cf98a 100644 --- a/pkgs/markdown/lib/src/inline_parser.dart +++ b/pkgs/markdown/lib/src/inline_parser.dart
@@ -280,13 +280,10 @@ if (isNullOrEmpty(match[1])) { if (linkResolver == null) return null; - // Only allow implicit links if the content is just text. - // TODO(rnystrom): Do we want to relax this? - if (state.children.any((child) => child is! Text)) return null; - // If there are multiple children, but they are all text, send the - // combined text to linkResolver. - var textToResolve = - state.children.fold('', (oldVal, child) => oldVal + child.text); + // Treat the contents as unparsed text even if they happen to match. This + // way, we can handle things like [LINK_WITH_UNDERSCORES] as a link and + // not get confused by the emphasis. + var textToResolve = parser.source.substring(state.endPos, parser.pos); // See if we have a resolver that will generate a link for us. resolved = true;
diff --git a/pkgs/markdown/pubspec.yaml b/pkgs/markdown/pubspec.yaml index 32c7931..9a86724 100644 --- a/pkgs/markdown/pubspec.yaml +++ b/pkgs/markdown/pubspec.yaml
@@ -1,5 +1,5 @@ name: markdown -version: 0.7.1+3 +version: 0.7.2-dev author: Dart Team <misc@dartlang.org> description: A library for converting markdown to HTML. homepage: https://github.com/dart-lang/markdown
diff --git a/pkgs/markdown/test/markdown_test.dart b/pkgs/markdown/test/markdown_test.dart index 8368b84..e2d1b40 100644 --- a/pkgs/markdown/test/markdown_test.dart +++ b/pkgs/markdown/test/markdown_test.dart
@@ -3,11 +3,14 @@ // BSD-style license that can be found in the LICENSE file. /// Unit tests for markdown. -library markdownTests; +library markdown.test.markdown_test; import 'package:unittest/unittest.dart'; + import 'package:markdown/markdown.dart'; +import 'utils.dart'; + /// Most of these tests are based on observing how showdown behaves: /// http://softwaremaniacs.org/playground/showdown-highlight/ void main() { @@ -949,7 +952,8 @@ }); group('Resolver', () { - var nyanResolver = (text) => new Text('~=[,,_${text}_,,]:3'); + nyanResolver(text) => new Text('~=[,,_${text}_,,]:3'); + validate('simple link resolver', ''' resolve [this] thing ''', ''' @@ -960,12 +964,17 @@ ''', ''' <p>resolve ~=[,,_this_,,]:3 thing</p> ''', imageLinkResolver: nyanResolver); + + validate('can resolve link containing inline tags', ''' + resolve [*star* _underline_] thing + ''', ''' + <p>resolve ~=[,,_*star* _underline__,,]:3 thing</p> + ''', linkResolver: nyanResolver); }); group('Custom inline syntax', () { - List<InlineSyntax> nyanSyntax = [ - new TextSyntax('nyan', sub: '~=[,,_,,]:3') - ]; + var nyanSyntax = [new TextSyntax('nyan', sub: '~=[,,_,,]:3')]; + validate('simple inline syntax', ''' nyan ''', ''' @@ -1022,90 +1031,3 @@ ''', inlineOnly: true); }); } - -/** - * Removes eight spaces of leading indentation from a multiline string. - * - * Note that this is very sensitive to how the literals are styled. They should - * be: - * ''' - * Text starts on own line. Lines up with subsequent lines. - * Lines are indented exactly 8 characters from the left margin.''' - * - * This does nothing if text is only a single line. - */ -// TODO(nweiz): Make this auto-detect the indentation level from the first -// non-whitespace line. -String cleanUpLiteral(String text) { - var lines = text.split('\n'); - if (lines.length <= 1) return text; - - for (var j = 0; j < lines.length; j++) { - if (lines[j].length > 8) { - lines[j] = lines[j].substring(8, lines[j].length); - } else { - lines[j] = ''; - } - } - - return lines.join('\n'); -} - -void validate(String description, String markdown, String html, - {List<InlineSyntax> inlineSyntaxes, - Resolver linkResolver, Resolver imageLinkResolver, - bool inlineOnly: false}) { - test(description, () { - markdown = cleanUpLiteral(markdown); - html = cleanUpLiteral(html); - - var result = markdownToHtml(markdown, - inlineSyntaxes: inlineSyntaxes, - linkResolver: linkResolver, - imageLinkResolver: imageLinkResolver, - inlineOnly: inlineOnly); - var passed = compareOutput(html, result); - - if (!passed) { - // Remove trailing newline. - html = html.substring(0, html.length - 1); - - var sb = new StringBuffer(); - sb.writeln('Expected: ${html.replaceAll("\n", "\n ")}'); - sb.writeln(' Actual: ${result.replaceAll("\n", "\n ")}'); - - fail(sb.toString()); - } - }); -} - -/// Does a loose comparison of the two strings of HTML. Ignores differences in -/// newlines and indentation. -bool compareOutput(String a, String b) { - int i = 0; - int j = 0; - - skipIgnored(String s, int i) { - // Ignore newlines. - while ((i < s.length) && (s[i] == '\n')) { - i++; - // Ignore indentation. - while ((i < s.length) && (s[i] == ' ')) i++; - } - - return i; - } - - while (true) { - i = skipIgnored(a, i); - j = skipIgnored(b, j); - - // If one string runs out of non-ignored strings, the other must too. - if (i == a.length) return j == b.length; - if (j == b.length) return i == a.length; - - if (a[i] != b[j]) return false; - i++; - j++; - } -}
diff --git a/pkgs/markdown/test/utils.dart b/pkgs/markdown/test/utils.dart new file mode 100644 index 0000000..73ad7ef --- /dev/null +++ b/pkgs/markdown/test/utils.dart
@@ -0,0 +1,94 @@ +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// 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. + +library markdown.test.utils; + +import 'package:unittest/unittest.dart'; + +import 'package:markdown/markdown.dart'; + +/// Removes eight spaces of leading indentation from a multiline string. +/// +/// Note that this is very sensitive to how the literals are styled. They should +/// be: +/// ''' +/// Text starts on own line. Lines up with subsequent lines. +/// Lines are indented exactly 8 characters from the left margin.''' +/// +/// This does nothing if text is only a single line. +// TODO(nweiz): Make this auto-detect the indentation level from the first +// non-whitespace line. +String cleanUpLiteral(String text) { + var lines = text.split('\n'); + if (lines.length <= 1) return text; + + for (var j = 0; j < lines.length; j++) { + if (lines[j].length > 8) { + lines[j] = lines[j].substring(8, lines[j].length); + } else { + lines[j] = ''; + } + } + + return lines.join('\n'); +} + +void validate(String description, String markdown, String html, + {List<InlineSyntax> inlineSyntaxes, + Resolver linkResolver, Resolver imageLinkResolver, + bool inlineOnly: false}) { + test(description, () { + markdown = cleanUpLiteral(markdown); + html = cleanUpLiteral(html); + + var result = markdownToHtml(markdown, + inlineSyntaxes: inlineSyntaxes, + linkResolver: linkResolver, + imageLinkResolver: imageLinkResolver, + inlineOnly: inlineOnly); + var passed = compareOutput(html, result); + + if (!passed) { + // Remove trailing newline. + html = html.substring(0, html.length - 1); + + var sb = new StringBuffer(); + sb.writeln('Expected: ${html.replaceAll("\n", "\n ")}'); + sb.writeln(' Actual: ${result.replaceAll("\n", "\n ")}'); + + fail(sb.toString()); + } + }); +} + +/// Does a loose comparison of the two strings of HTML. Ignores differences in +/// newlines and indentation. +bool compareOutput(String a, String b) { + int i = 0; + int j = 0; + + skipIgnored(String s, int i) { + // Ignore newlines. + while ((i < s.length) && (s[i] == '\n')) { + i++; + // Ignore indentation. + while ((i < s.length) && (s[i] == ' ')) i++; + } + + return i; + } + + while (true) { + i = skipIgnored(a, i); + j = skipIgnored(b, j); + + // If one string runs out of non-ignored strings, the other must too. + if (i == a.length) return j == b.length; + if (j == b.length) return i == a.length; + + if (a[i] != b[j]) return false; + i++; + j++; + } +}