Skip to content
Open
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
2 changes: 2 additions & 0 deletions pkgs/markdown/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## 7.3.1-wip

* Preserve metadata passed to fenced code blocks as
`data-metadata` on the created `pre` element.
* Update the README link to the markdown playground
(https://dart-lang.github.io/tools).
* Update `package:web` API references in the example.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ class FencedCodeBlockSyntax extends BlockSyntax {

@override
Node parse(BlockParser parser) {
final openingFence = _FenceMatch.fromMatch(pattern.firstMatch(
escapePunctuation(parser.current.content),
)!);
final openingFence = _FenceMatch.fromMatch(
pattern.firstMatch(escapePunctuation(parser.current.content))!,
);

var text = parseChildLines(
parser,
Expand All @@ -39,16 +39,31 @@ class FencedCodeBlockSyntax extends BlockSyntax {
text = '$text\n';
}

final (languageString, metadataString) = openingFence.languageAndMetadata;

final code = Element.text('code', text);
if (openingFence.hasLanguage) {
var language = decodeHtmlCharacters(openingFence.language);
if (parser.document.encodeHtml) {
language = escapeHtmlAttribute(language);
}
code.attributes['class'] = 'language-$language';
if (languageString != null) {
final processedLanguage = _processAttribute(languageString,
encodeHtml: parser.document.encodeHtml);
code.attributes['class'] = 'language-$processedLanguage';
}

final pre = Element('pre', [code]);
if (metadataString != null) {
final processedMetadata = _processAttribute(metadataString,
encodeHtml: parser.document.encodeHtml);
pre.attributes['data-metadata'] = processedMetadata;
}

return Element('pre', [code]);
return pre;
}

static String _processAttribute(String value, {bool encodeHtml = false}) {
final decodedValue = decodeHtmlCharacters(value);
if (encodeHtml) {
return escapeHtmlAttribute(decodedValue);
}
return decodedValue;
}

@override
Expand Down Expand Up @@ -144,12 +159,30 @@ class _FenceMatch {
// https://spec.commonmark.org/0.30/#info-string.
final String info;

// The first word of the info string is typically used to specify the language
// of the code sample,
// https://spec.commonmark.org/0.30/#example-143.
String get language => info.split(' ').first;
/// Returns the language and remaining metadata from the [info] string.
///
/// The language is the first word of the info string,
/// to match the (unspecified, but typical) behavior of CommonMark parsers,
/// as suggested in https://spec.commonmark.org/0.30/#example-143.
///
/// The metadata is any remaining part of the info string after the language.
(String? language, String? metadata) get languageAndMetadata {
if (info.isEmpty) {
return (null, null);
}

bool get hasInfo => info.isNotEmpty;
// We assume the info string is trimmed already.
final firstSpaceIndex = info.indexOf(' ');
if (firstSpaceIndex == -1) {
// If there is no space, the whole string is the language.
return (info, null);
}

bool get hasLanguage => language.isNotEmpty;
return (
info.substring(0, firstSpaceIndex),
info.substring(firstSpaceIndex + 1),
);
}

bool get hasInfo => info.isNotEmpty;
}
4 changes: 2 additions & 2 deletions pkgs/markdown/test/common_mark/fenced_code_blocks.unit
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ def foo(x)
end
~~~~~~~
<<<
<pre><code class="language-ruby">def foo(x)
<pre data-metadata="startline=3 $%@#$"><code class="language-ruby">def foo(x)
return 3
end
</code></pre>
Expand All @@ -234,7 +234,7 @@ foo</p>
foo
~~~
<<<
<pre><code class="language-aa">foo
<pre data-metadata="``` ~~~"><code class="language-aa">foo
</code></pre>
>>> Fenced code blocks - 147
```
Expand Down
4 changes: 2 additions & 2 deletions pkgs/markdown/test/gfm/fenced_code_blocks.unit
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ def foo(x)
end
~~~~~~~
<<<
<pre><code class="language-ruby">def foo(x)
<pre data-metadata="startline=3 $%@#$"><code class="language-ruby">def foo(x)
return 3
end
</code></pre>
Expand All @@ -234,7 +234,7 @@ foo</p>
foo
~~~
<<<
<pre><code class="language-aa">foo
<pre data-metadata="``` ~~~"><code class="language-aa">foo
</code></pre>
>>> Fenced code blocks - 117
```
Expand Down
24 changes: 24 additions & 0 deletions pkgs/markdown/test/original/fenced_code_block.unit
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,27 @@
<<<
<pre><code>'foo'
</code></pre>
>>> with basic metadata string
```dart meta
code
```

<<<
<pre data-metadata="meta"><code class="language-dart">code
</code></pre>
>>> with characters to escape
```dart title="main.dart"
code
```

<<<
<pre data-metadata="title=&quot;main.dart&quot;"><code class="language-dart">code
</code></pre>
>>> with HTML character reference
```dart &#124;
code
```

<<<
<pre data-metadata="|"><code class="language-dart">code
</code></pre>