Skip to content
This repository was archived by the owner on Feb 24, 2025. It is now read-only.

Implement AlertBlockSyntax using BlockquoteSyntax #585

Closed
wants to merge 1 commit into from
Closed
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
1 change: 0 additions & 1 deletion lib/markdown.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import 'src/version.dart';

export 'src/ast.dart';
export 'src/block_parser.dart';
export 'src/block_syntaxes/alert_block_syntax.dart';
export 'src/block_syntaxes/block_syntax.dart';
export 'src/block_syntaxes/blockquote_syntax.dart';
export 'src/block_syntaxes/code_block_syntax.dart';
Expand Down
110 changes: 0 additions & 110 deletions lib/src/block_syntaxes/alert_block_syntax.dart

This file was deleted.

62 changes: 62 additions & 0 deletions lib/src/block_syntaxes/blockquote_syntax.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,65 @@ class BlockquoteSyntax extends BlockSyntax {
return Element('blockquote', children);
}
}

/// Parses GitHub Alerts blocks.
///
/// See also: https://docs.github.com/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts
class AlertBlockSyntax extends BlockSyntax {
@override
RegExp get pattern => alertPattern;

const AlertBlockSyntax();

@override
List<Line> parseChildLines(BlockParser parser) {
return const BlockquoteSyntax().parseChildLines(parser);
}

@override
Node parse(BlockParser parser) {
// Parse the alert type from the first line.
final type =
pattern.firstMatch(parser.current.content)!.group(1)!.toLowerCase();

final childLines = parseChildLines(parser);
// Until we've parse all the child lines, we can't actually know if this is
// a blockquote containing `[!note]` or if this is an alert-block.
//
// This is because `> [!note]` is not a valid alert-block!
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this is not a valid alert block? because it is empty?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know, that's how it behaves on github :D

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But is it the emptiness that makes it invalid, or some other property?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example of the empty case

-----------
> [!note]
-----------

[!note]


Example of the non-empty case

-----------
> [!note]
> Hello world
-----------

Note

Hello world


Conclusion

If we have > [!note] it's not a special block. But if it's:

  • Followed by text that wants to belong to the previous paragraph, then it is. OR
  • Followed by lines like > ... indicating that whatever is there belongs inside the blockquote, then it also is special.

Otherwise, it's not special, just a normal blockquote.

Notice that > foo\nbar is the same as > foo\n> bar, the line that follows is considered to be a paragraph continuation of the previous line, so the blockquote continues.

So yes, as far as I can see, it's emptiness that decides it. Even if you have > [!note]\n> it'll still not be rendered as a special alert-block.

final isBlockquote = childLines.length <= 1;

if (!isBlockquote) {
// Always remove the first line, this is the line that contained the type.
childLines.removeAt(0);
}

// Recursively parse the contents of the blockquote.
final children = BlockParser(childLines, parser.document).parseLines(
// The setext heading underline cannot be a lazy continuation line in a
// block quote.
// https://spec.commonmark.org/0.30/#example-93
disabledSetextHeading: BlockquoteSyntax._lazyContinuation,
parentSyntax: this,
);

if (isBlockquote) {
return Element('blockquote', children);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is ugly, but I don't see a better way, unless we make BlockquoteSyntax do everything.

I suppose we could in theory make BlockquoteSyntax check if AlertBlockSyntax is enabled by doing:`

final isAlertSyntaxEnabled = parser.document.blockSyntaxes.any(
  (s) => s is AlertBlockSyntax,
);

If we could give AlertBlockSyntax a factory singleton constructor we could do:

final isAlertSyntaxEnabled = parser.document.blockSyntaxes.contains(
  const AlertBlockSyntax(),
);

If inside BlockquoteSyntax we had isAlertSyntaxEnabled then it could implement both. Ofcourse this would mean that enabling AlertBlockSyntax wouldn't work without enabling BlockquoteSyntax.
I'm not sure why we should ever allow such configuration, we surely don't intent to test it, but that's how the package is structured.


The point with implementing alert-syntax inside BlockquoteSyntax is that alert-syntax is really a post-processing step for blockquote. But I don't really see how package:markdown has the facilities to post-processing.

}

// Mapping the alert title text.
const typeTextMap = {
'note': 'Note',
'tip': 'Tip',
'important': 'Important',
'caution': 'Caution',
'warning': 'Warning',
};
final titleText = typeTextMap[type]!;
final titleElement = Element('p', [Text(titleText)])
..attributes['class'] = 'markdown-alert-title';
final elementClass = 'markdown-alert markdown-alert-$type';
return Element('div', [titleElement, ...children])
..attributes['class'] = elementClass;
}
}
2 changes: 1 addition & 1 deletion lib/src/extension_set.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'block_syntaxes/alert_block_syntax.dart';
import 'block_syntaxes/block_syntax.dart';
import 'block_syntaxes/blockquote_syntax.dart';
import 'block_syntaxes/fenced_code_block_syntax.dart';
import 'block_syntaxes/footnote_def_syntax.dart';
import 'block_syntaxes/header_with_id_syntax.dart';
Expand Down
9 changes: 9 additions & 0 deletions test/extensions/alert_extension.unit
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,12 @@ Additional markdown text.
with two lines.</p>
</div>
<p>Additional markdown text.</p>
>>> #584
> [!CAUTION]
>
> some warning
<<<
<div class="markdown-alert markdown-alert-caution">
<p class="markdown-alert-title">Caution</p>
<p>some warning</p>
</div>
Loading