From 83b21d5228df0fde40d8e83e8630c6967469a860 Mon Sep 17 00:00:00 2001 From: Mikhail Matiunin Date: Wed, 16 Jul 2025 12:12:05 +0400 Subject: [PATCH 1/2] test: add unit tests for URL parsing in markdown decoder --- test/parser/parser_test.dart | 65 ++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/test/parser/parser_test.dart b/test/parser/parser_test.dart index 3e6221f..0871ec7 100644 --- a/test/parser/parser_test.dart +++ b/test/parser/parser_test.dart @@ -117,6 +117,71 @@ void main() => group('Parse', () { ); }); + test('Urls', () { + var markdown = markdownDecoder.convert('[text](url)'); + expect( + markdown.text, + allOf( + isNotEmpty, + equals('text'), + ), + ); + expect( + markdown.blocks, + allOf( + isNotEmpty, + hasLength(equals(1)), + everyElement(isA()), + ), + ); + expect( + markdown.blocks.single, + isA().having( + (p) => p.spans, + 'spans', + allOf( + isNotEmpty, + hasLength(equals(1)), + everyElement(isA() + .having((s) => s.style, 'style', equals(MD$Style.link)) + .having((s) => s.extra, 'extra', containsPair('url', 'url'))), + ), + ), + ); + + // Should be with url: `url()` + markdown = markdownDecoder.convert('[text](url())'); + expect( + markdown.text, + allOf( + isNotEmpty, + equals('text'), + ), + ); + expect( + markdown.blocks, + allOf( + isNotEmpty, + hasLength(equals(1)), + everyElement(isA()), + ), + ); + expect( + markdown.blocks.single, + isA().having( + (p) => p.spans, + 'spans', + allOf( + isNotEmpty, + hasLength(equals(1)), + everyElement(isA() + .having((s) => s.style, 'style', equals(MD$Style.link)) + .having((s) => s.extra, 'extra', containsPair('url', 'url'))), + ), + ), + ); + }); + test('Empty input', () { expect(markdownDecoder.convert('').blocks, isEmpty); }); From c925805b3210f868808f7affb2470f4c370d0cfb Mon Sep 17 00:00:00 2001 From: Mikhail Matiunin Date: Wed, 16 Jul 2025 12:18:39 +0400 Subject: [PATCH 2/2] fix: update changelog for version 0.0.5 and improve URL parsing in markdown decoder --- CHANGELOG.md | 4 ++++ lib/src/parser.dart | 16 +++++++++++----- pubspec.yaml | 2 +- test/parser/parser_test.dart | 5 +++-- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06888f0..c8e9d84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.5 + +- **FIXED**: Fixed parsing url such as `[text](https://domain.com/path(with)brackets)`. + ## 0.0.4 - **CHANGED**: Improved link tap handling. diff --git a/lib/src/parser.dart b/lib/src/parser.dart index d35f6d5..0addd8e 100644 --- a/lib/src/parser.dart +++ b/lib/src/parser.dart @@ -326,15 +326,21 @@ List _parseInlineSpans(String text) { // find closing ')' var urlEnd = -1; - for (var k = urlIdx + 1; k < codes.length; k++) { + for (var k = urlIdx + 1, opens = 0; k < codes.length; k++) { final ck = codes[k]; if (ck == esc) { k++; - continue; + continue; // skip escaped char } - if (ck == url$end) { - urlEnd = k; - break; + if (ck == url$start) { + opens++; // count opening '(' + } else if (ck == url$end) { + if (opens > 0) { + opens--; // count closing ')' + } else { + urlEnd = k; // found the closing ')' + break; + } } } diff --git a/pubspec.yaml b/pubspec.yaml index 17cad6a..e7c17b6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,7 +8,7 @@ description: > Markdown library written in Dart. It can parse and display Markdown. -version: 0.0.4 +version: 0.0.5 homepage: https://github.com/DoctorinaAI/md repository: https://github.com/DoctorinaAI/md diff --git a/test/parser/parser_test.dart b/test/parser/parser_test.dart index 0871ec7..d4bba9d 100644 --- a/test/parser/parser_test.dart +++ b/test/parser/parser_test.dart @@ -150,7 +150,7 @@ void main() => group('Parse', () { ); // Should be with url: `url()` - markdown = markdownDecoder.convert('[text](url())'); + markdown = markdownDecoder.convert('[text](url(with)brackets)'); expect( markdown.text, allOf( @@ -176,7 +176,8 @@ void main() => group('Parse', () { hasLength(equals(1)), everyElement(isA() .having((s) => s.style, 'style', equals(MD$Style.link)) - .having((s) => s.extra, 'extra', containsPair('url', 'url'))), + .having((s) => s.extra, 'extra', + containsPair('url', 'url(with)brackets'))), ), ), );