Skip to content
This repository was archived by the owner on Feb 24, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@
`indicatorForCheckedCheckBox`, and `indicatorForUncheckedCheckBox`.
* **Breaking change**: Removed `BlockHtmlSyntax`, `BlockTagBlockHtmlSyntax`,
`LongBlockHtmlSyntax`, and `OtherTagBlockHtmlSyntax`.
* **Breaking change**: Change the `line` properties of type `String` to `Line`.
* **Breaking change**: Change the `lines` properties of type `List<String>` to
`List<Line>`.
* Add a new syntax `HtmlBlockSyntax` to parse HTML blocks.
* Add a new syntax `DecodeHtmlSyntax` to decode HTML entity and numeric
character references.
* Add a new syntax `SoftLineBreakSyntax` to remove the single space before the
line ending.
* Add a new syntax `EscapeHtmlSyntax` to encode (`"`), (`<`), (`>`) and (`&`).
* Add an option `caseSensitive` to `TextSyntax`.
* Add a new public method `parse(String text)` for `Document`.
* Add a new public method `parseLineList(List<Line> text)` for `Document`.
* Add a new type: `Line`.

## 6.0.1

Expand Down
1 change: 1 addition & 0 deletions lib/markdown.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,6 @@ export 'src/inline_syntaxes/link_syntax.dart';
export 'src/inline_syntaxes/soft_line_break_syntax.dart';
export 'src/inline_syntaxes/strikethrough_syntax.dart';
export 'src/inline_syntaxes/text_syntax.dart';
export 'src/line.dart';

const version = packageVersion;
13 changes: 7 additions & 6 deletions lib/src/block_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ import 'block_syntaxes/paragraph_syntax.dart';
import 'block_syntaxes/setext_header_syntax.dart';
import 'block_syntaxes/unordered_list_syntax.dart';
import 'document.dart';
import 'line.dart';

/// Maintains the internal state needed to parse a series of lines into blocks
/// of Markdown suitable for further inline parsing.
class BlockParser {
final List<String> lines;
final List<Line> lines;

/// The Markdown document this parser is parsing.
final Document document;
Expand Down Expand Up @@ -63,10 +64,10 @@ class BlockParser {
}

/// Gets the current line.
String get current => lines[_pos];
Line get current => lines[_pos];

/// Gets the line after the current one or `null` if there is none.
String? get next {
Line? get next {
// Don't read past the end.
if (_pos >= lines.length - 1) return null;
return lines[_pos + 1];
Expand All @@ -78,7 +79,7 @@ class BlockParser {
/// `peek(0)` is equivalent to [current].
///
/// `peek(1)` is equivalent to [next].
String? peek(int linesAhead) {
Line? peek(int linesAhead) {
if (linesAhead < 0) {
throw ArgumentError('Invalid linesAhead: $linesAhead; must be >= 0.');
}
Expand All @@ -100,13 +101,13 @@ class BlockParser {
/// Gets whether or not the current line matches the given pattern.
bool matches(RegExp regex) {
if (isDone) return false;
return regex.hasMatch(current);
return regex.hasMatch(current.content);
}

/// Gets whether or not the next line matches the given pattern.
bool matchesNext(RegExp regex) {
if (next == null) return false;
return regex.hasMatch(next!);
return regex.hasMatch(next!.content);
}

List<Node> parseLines() {
Expand Down
11 changes: 6 additions & 5 deletions lib/src/block_syntaxes/block_syntax.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import '../ast.dart';
import '../block_parser.dart';
import '../line.dart';

abstract class BlockSyntax {
const BlockSyntax();
Expand All @@ -14,19 +15,19 @@ abstract class BlockSyntax {
bool canEndBlock(BlockParser parser) => true;

bool canParse(BlockParser parser) {
return pattern.hasMatch(parser.current);
return pattern.hasMatch(parser.current.content);
}

Node? parse(BlockParser parser);

List<String?> parseChildLines(BlockParser parser) {
List<Line?> parseChildLines(BlockParser parser) {
// Grab all of the lines that form the block element.
final childLines = <String?>[];
final childLines = <Line?>[];

while (!parser.isDone) {
final match = pattern.firstMatch(parser.current);
final match = pattern.firstMatch(parser.current.content);
if (match == null) break;
childLines.add(match[1]);
childLines.add(parser.current);
parser.advance();
}

Expand Down
21 changes: 11 additions & 10 deletions lib/src/block_syntaxes/blockquote_syntax.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import '../ast.dart';
import '../block_parser.dart';
import '../charcode.dart';
import '../line.dart';
import '../patterns.dart';
import '../util.dart';
import 'block_syntax.dart';
Expand All @@ -19,32 +20,32 @@ class BlockquoteSyntax extends BlockSyntax {
const BlockquoteSyntax();

@override
List<String> parseChildLines(BlockParser parser) {
List<Line> parseChildLines(BlockParser parser) {
// Grab all of the lines that form the blockquote, stripping off the ">".
final childLines = <String>[];
final childLines = <Line>[];

while (!parser.isDone) {
final currentLine = parser.current;
final match = pattern.firstMatch(parser.current);
final match = pattern.firstMatch(parser.current.content);
if (match != null) {
// A block quote marker consists of a `>` together with an optional
// following space of indentation, see
// https://spec.commonmark.org/0.30/#block-quote-marker.
final markerStart = match.match.indexOf('>');
int markerEnd;
if (currentLine.length > 1) {
if (currentLine.content.length > 1) {
var hasSpace = false;
// Check if there is a following space if the marker is not at the end
// of this line.
if (markerStart < currentLine.length - 1) {
final nextChar = currentLine.codeUnitAt(markerStart + 1);
if (markerStart < currentLine.content.length - 1) {
final nextChar = currentLine.content.codeUnitAt(markerStart + 1);
hasSpace = nextChar == $tab || nextChar == $space;
}
markerEnd = markerStart + (hasSpace ? 2 : 1);
} else {
markerEnd = markerStart + 1;
}
childLines.add(currentLine.substring(markerEnd));
childLines.add(Line(currentLine.content.substring(markerEnd)));
parser.advance();
continue;
}
Expand All @@ -59,10 +60,10 @@ class BlockquoteSyntax extends BlockSyntax {
final otherMatched =
parser.blockSyntaxes.firstWhere((s) => s.canParse(parser));
if ((otherMatched is ParagraphSyntax &&
lastLine.isNotEmpty &&
!codeFencePattern.hasMatch(lastLine)) ||
!lastLine.isBlankLine &&
!codeFencePattern.hasMatch(lastLine.content)) ||
(otherMatched is CodeBlockSyntax &&
!indentPattern.hasMatch(lastLine))) {
!indentPattern.hasMatch(lastLine.content))) {
childLines.add(parser.current);
parser.advance();
} else {
Expand Down
19 changes: 10 additions & 9 deletions lib/src/block_syntaxes/code_block_syntax.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import '../ast.dart';
import '../block_parser.dart';
import '../line.dart';
import '../patterns.dart';
import '../util.dart';
import 'block_syntax.dart';
Expand All @@ -19,21 +20,21 @@ class CodeBlockSyntax extends BlockSyntax {
const CodeBlockSyntax();

@override
List<String?> parseChildLines(BlockParser parser) {
final childLines = <String?>[];
List<Line> parseChildLines(BlockParser parser) {
final childLines = <Line>[];

while (!parser.isDone) {
final isBlankLine = parser.current.isBlank;
final isBlankLine = parser.current.isBlankLine;
if (isBlankLine && _shouldEnd(parser)) {
break;
}

if (!isBlankLine &&
childLines.isNotEmpty &&
pattern.hasMatch(parser.current) != true) {
pattern.hasMatch(parser.current.content) != true) {
break;
}
childLines.add(parser.current.dedent().text);
childLines.add(Line(parser.current.content.dedent().text));

parser.advance();
}
Expand All @@ -46,9 +47,9 @@ class CodeBlockSyntax extends BlockSyntax {
final childLines = parseChildLines(parser);

// The Markdown tests expect a trailing newline.
childLines.add('');
childLines.add(Line(''));

var content = childLines.join('\n');
var content = childLines.map((e) => e.content).join('\n');
if (parser.document.encodeHtml) {
content = escapeHtml(content);
}
Expand All @@ -67,12 +68,12 @@ class CodeBlockSyntax extends BlockSyntax {

// It does not matter how many blank lines between chunks:
// https://spec.commonmark.org/0.30/#example-111
if (nextLine.isBlank) {
if (nextLine.isBlankLine) {
i++;
continue;
}

return pattern.hasMatch(nextLine) == false;
return pattern.hasMatch(nextLine.content) == false;
}
}
}
2 changes: 1 addition & 1 deletion lib/src/block_syntaxes/dummy_block_syntax.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class DummyBlockSyntax extends BlockSyntax {
final childLines = <String>[];

while (!BlockSyntax.isAtBlockEnd(parser)) {
childLines.add(parser.current);
childLines.add(parser.current.content);
parser.advance();
}

Expand Down
7 changes: 4 additions & 3 deletions lib/src/block_syntaxes/fenced_blockquote_syntax.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import '../ast.dart';
import '../block_parser.dart';
import '../line.dart';
import '../patterns.dart';
import 'block_syntax.dart';

Expand All @@ -15,12 +16,12 @@ class FencedBlockquoteSyntax extends BlockSyntax {
RegExp get pattern => blockquoteFencePattern;

@override
List<String> parseChildLines(BlockParser parser) {
final childLines = <String>[];
List<Line> parseChildLines(BlockParser parser) {
final childLines = <Line>[];
parser.advance();

while (!parser.isDone) {
final match = pattern.hasMatch(parser.current);
final match = pattern.hasMatch(parser.current.content);
if (!match) {
childLines.add(parser.current);
parser.advance();
Expand Down
17 changes: 10 additions & 7 deletions lib/src/block_syntaxes/fenced_code_block_syntax.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import '../ast.dart';
import '../block_parser.dart';
import '../line.dart';
import '../patterns.dart';
import '../util.dart';
import 'block_syntax.dart';
Expand All @@ -20,14 +21,14 @@ class FencedCodeBlockSyntax extends BlockSyntax {
@override
Node parse(BlockParser parser) {
final openingFence = _FenceMatch.fromMatch(pattern.firstMatch(
escapePunctuation(parser.current),
escapePunctuation(parser.current.content),
)!);

var text = parseChildLines(
parser,
openingFence.marker,
openingFence.indent,
).join('\n');
).map((e) => e.content).join('\n');

if (parser.document.encodeHtml) {
text = escapeHtml(text);
Expand All @@ -54,26 +55,28 @@ class FencedCodeBlockSyntax extends BlockSyntax {
}

@override
List<String> parseChildLines(
List<Line> parseChildLines(
BlockParser parser, [
String openingMarker = '',
int indent = 0,
]) {
final childLines = <String>[];
final childLines = <Line>[];

parser.advance();

_FenceMatch? closingFence;
while (!parser.isDone) {
final match = pattern.firstMatch(parser.current);
final match = pattern.firstMatch(parser.current.content);
closingFence = match == null ? null : _FenceMatch.fromMatch(match);

// Closing code fences cannot have info strings:
// https://spec.commonmark.org/0.30/#example-147
if (closingFence == null ||
!closingFence.marker.startsWith(openingMarker) ||
closingFence.hasInfo) {
childLines.add(_removeIndentation(parser.current, indent));
childLines.add(
Line(_removeIndentation(parser.current.content, indent)),
);
parser.advance();
} else {
parser.advance();
Expand All @@ -85,7 +88,7 @@ class FencedCodeBlockSyntax extends BlockSyntax {
// https://spec.commonmark.org/0.30/#example-128
if (closingFence == null &&
childLines.isNotEmpty &&
childLines.last.trim().isEmpty) {
childLines.last.isBlankLine) {
childLines.removeLast();
}

Expand Down
9 changes: 6 additions & 3 deletions lib/src/block_syntaxes/header_syntax.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class HeaderSyntax extends BlockSyntax {

@override
Node parse(BlockParser parser) {
final match = pattern.firstMatch(parser.current)!;
final match = pattern.firstMatch(parser.current.content)!;
final matchedText = match[0]!;
final openMarker = match[1]!;
final closeMarker = match[2];
Expand All @@ -26,10 +26,13 @@ class HeaderSyntax extends BlockSyntax {

String? content;
if (closeMarker == null) {
content = parser.current.substring(openMarkerEnd);
content = parser.current.content.substring(openMarkerEnd);
} else {
final closeMarkerStart = matchedText.lastIndexOf(closeMarker);
content = parser.current.substring(openMarkerEnd, closeMarkerStart);
content = parser.current.content.substring(
openMarkerEnd,
closeMarkerStart,
);
}
content = content.trim();

Expand Down
Loading