Skip to content

Commit

Permalink
v 0.3.0 (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
f3ath committed May 10, 2022
1 parent b450ac1 commit e2e5661
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 84 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/dart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest

container:
image: google/dart:latest
image: dart:stable

steps:
- uses: actions/checkout@v2
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.3.0] - 2022-05-09
### Added
- Basic support of nested lists

### Changed
- Bumped markdown dependency to 5.0.0
- Renamed Printable to Renderable

## [0.2.3] - 2021-12-28
### Added
- Optional configurable line break sequence
Expand Down Expand Up @@ -57,6 +65,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Initial library version

[0.3.0]: https://github.com/f3ath/marker/compare/0.2.3...0.3.0
[0.2.3]: https://github.com/f3ath/marker/compare/0.2.2...0.2.3
[0.2.2]: https://github.com/f3ath/marker/compare/0.2.1...0.2.2
[0.2.1]: https://github.com/f3ath/marker/compare/0.2.0...0.2.1
Expand Down
2 changes: 1 addition & 1 deletion lib/marker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ String render(Iterable<md.Node> nodes,
for (final node in nodes) {
node.accept(builder);
}
return (builder.root.print(context) +
return (builder.root.render(context) +
context.references.join(context.lineBreak))
.trim();
}
10 changes: 5 additions & 5 deletions lib/src/ast/node.dart
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import 'package:marker/src/ast/context.dart';
import 'package:marker/src/ast/printable.dart';
import 'package:marker/src/ast/renderable.dart';
import 'package:marker/src/ast/text.dart';

/// The base rendering tree node.
class Node implements Printable {
class Node implements Renderable {
/// Node's children
final List<Printable> children = [];
final List<Renderable> children = [];

/// Attributes are copied from the corresponding parsed tree
/// during tree building.
final Map<String, String> attributes = {};

/// Renders all children and returns concatenated output.
@override
String print(Context context) =>
children.map((node) => node.print(context)).join();
String render(Context context) =>
children.map((node) => node.render(context)).join();

/// Adds a child text node
void addText(String text) {
Expand Down
4 changes: 2 additions & 2 deletions lib/src/ast/printable.dart → lib/src/ast/renderable.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:marker/src/ast/context.dart';

/// The base interface for the rendering tree nodes.
abstract class Printable {
abstract class Renderable {
/// Renders the node into markdown according to [context].
String print(Context context);
String render(Context context);
}
6 changes: 3 additions & 3 deletions lib/src/ast/text.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import 'package:marker/src/ast/context.dart';
import 'package:marker/src/ast/printable.dart';
import 'package:marker/src/ast/renderable.dart';

class Text implements Printable {
class Text implements Renderable {
Text(this.text);

final String text;

/// Escapes common markdown special characters if those could be
/// misinterpreted.
@override
String print(Context context) => text
String render(Context context) => text
// dot after a number in the beginning of the string is a list item
.replaceAllMapped(RegExp(r'^(\d+)\. '), (m) => '${m[1]}\\. ')
// Special markdown chars: emphasis, strikethrough, table cell, links
Expand Down
17 changes: 9 additions & 8 deletions lib/src/flavors/changelog.dart
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
import 'package:marker/ast.dart';
import 'package:marker/src/ast/printable.dart';
import 'package:marker/src/ast/renderable.dart';
import 'package:marker/src/flavors/original.dart';

/// Changelog uses a special kind of implicit links inside H2
class Release extends Node {
@override
String print(Context context) =>
String render(Context context) =>
'## ' +
children
.map((node) => node is Link ? _ReleaseLink(node) : node)
.map((node) => node.print(context))
.map((node) => node is Link ? _Link(node) : node)
.map((node) => node.render(context))
.join() +
context.lineBreak;
}

class _ReleaseLink implements Printable {
_ReleaseLink(this._link);
class _Link implements Renderable {
_Link(this._link);

final Link _link;

@override
String print(Context context) {
final innerText = '[${_link.children.map((e) => e.print(context)).join()}]';
String render(Context context) {
final innerText =
'[${_link.children.map((e) => e.render(context)).join()}]';
var href = _link.attributes['href']!;
final title = _link.attributes['title'];
if (title != null) href += ' "$title"';
Expand Down
154 changes: 94 additions & 60 deletions lib/src/flavors/original.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:convert';

import 'package:marker/ast.dart';

/// This is an implementation of the original markdown
Expand All @@ -8,82 +10,105 @@ class Header extends Node {
final int level;

@override
String print(Context context) =>
'#' * level + ' ${super.print(context)}' + context.lineBreak;
String render(Context context) =>
'#' * level + ' ${super.render(context)}' + context.lineBreak;
}

class Paragraph extends Node {
@override
String print(Context context) => super.print(context) + context.lineBreak * 2;
String render(Context context) =>
super.render(context) + context.lineBreak * 2;
}

class LineBreak extends Node {
@override
String print(Context context) => ' ' + context.lineBreak;
String render(Context context) => ' ' + context.lineBreak;
}

class BlockQuote extends Node {
@override
String print(Context context) =>
String render(Context context) =>
super
.print(context)
.render(context)
.trim()
.split(context.lineBreak)
.map((line) => ('> ' + line).trim())
.join(context.lineBreak) +
.addLinePrefix('> ', context.lineBreak, trim: true) +
context.lineBreak * 2;
}

class UnorderedList extends Node {
@override
String print(Context context) =>
children.map((node) => '- ${node.print(context)}').join() +
String render(Context context) =>
children.map((node) => '- ${node.render(context)}').join() +
context.lineBreak;
}

class OrderedList extends Node {
@override
String print(Context context) =>
String render(Context context) =>
children
.asMap()
.entries
.map((e) => '${e.key + 1}. ${e.value.print(context)}')
.map((e) => '${e.key + 1}. ${e.value.render(context)}')
.join() +
context.lineBreak;
}

class ListItem extends Node {
@override
String print(Context context) {
if (children.isNotEmpty && _isBlock(children.first)) {
return children
.map((node) {
if (node is BlockQuote) {
return ' ' +
node
.print(context)
.split(context.lineBreak)
.join(context.lineBreak + ' ');
}
if (node is Pre) {
// A code block in a list gets 3 spaces
// despite the standard requiring 4.
// @see https://daringfireball.net/projects/markdown/syntax#list
// So we have to compensate here.
return ' ' * 3 +
node
.print(context)
.split(context.lineBreak)
.join(context.lineBreak + ' ' * 3);
}
return ' ' * 4 + node.print(context).trim();
})
.join(context.lineBreak * 2)
.trim() +
context.lineBreak * 2;
String render(Context context) {
if (children.isNotEmpty) {
if (_isBlock(children.first)) {
return _renderBlockChildren(context);
}
}
return super.print(context) + context.lineBreak;
return children
.map((node) {
if (node is OrderedList || node is UnorderedList) {
// We have a sublist. It must be separated from the previous
// text node and from other block elements.
final indent = (node is UnorderedList) ? 2 : 4;
return context.lineBreak +
node
.render(context)
.addLinePrefix(' ' * indent, context.lineBreak) +
context.lineBreak;
}
return node.render(context);
})
.join()
.trim() +
context.lineBreak;
}

String _renderBlockChildren(Context context) =>
children
.map((node) {
if (node is BlockQuote) {
return node
.render(context)
.addLinePrefix(' ' * 4, context.lineBreak);
}
if (node is Pre) {
// A code block in a list gets 3 spaces
// despite the standard requiring 4.
// @see https://daringfireball.net/projects/markdown/syntax#list
// So we have to compensate here.
return node
.render(context)
.addLinePrefix(' ' * 3, context.lineBreak);
}
return ' ' * 4 + node.render(context).trim();
})
.join(context.lineBreak * 2)
.trim() +
context.lineBreak * 2;

bool _isBlock(node) =>
node is Header ||
node is Paragraph ||
node is BlockQuote ||
node is OrderedList ||
node is UnorderedList;
}

class Pre extends Node {}
Expand All @@ -92,26 +117,30 @@ class Code extends Node {
final _buf = StringBuffer();

@override
String print(Context context) {
String render(Context context) {
final text = _buf.toString();
if (text.contains(context.lineBreak)) {
return ' ' * 4 +
text.split(context.lineBreak).join(context.lineBreak + ' ' * 4);
return text.addLinePrefix(' ' * 4, context.lineBreak);
}
var fencing = 1;
while (text.contains('`' * fencing)) {
fencing++;
} // Figure out the fencing length
return '`' * fencing + text + '`' * fencing;
final fencing = _detectFencing(text);
return fencing + text + fencing;
}

@override
void addText(String text) => _buf.write(text);

String _detectFencing(String text) {
var fencing = '';
do {
fencing += '`';
} while (text.contains(fencing));
return fencing;
}
}

class HorizontalRule extends Node {
@override
String print(Context context) => '---' + context.lineBreak;
String render(Context context) => '---' + context.lineBreak;
}

class Emphasis extends Node {
Expand All @@ -120,13 +149,13 @@ class Emphasis extends Node {
final String mark;

@override
String print(Context context) => '$mark${super.print(context)}$mark';
String render(Context context) => '$mark${super.render(context)}$mark';
}

class Link extends Node {
@override
String print(Context context) {
final innerText = '[${super.print(context)}]';
String render(Context context) {
final innerText = '[${super.render(context)}]';
var href = attributes['href']!;
if (attributes.containsKey('title')) {
href += ' "${attributes['title']}"';
Expand All @@ -143,7 +172,7 @@ class Link extends Node {

class Image extends Node {
@override
String print(Context context) {
String render(Context context) {
var src = attributes['src']!;
if (attributes.containsKey('title')) {
src += ' "${attributes['title']}"';
Expand All @@ -160,9 +189,14 @@ class Image extends Node {

int _id = 1; // id generator for images and links

bool _isBlock(node) =>
node is Header ||
node is Paragraph ||
node is BlockQuote ||
node is OrderedList ||
node is UnorderedList;
extension _StringExt on String {
static const _splitter = LineSplitter();

/// Adds [prefix] to all lines in the string.
addLinePrefix(String prefix, String lineBreak, {bool trim = false}) =>
_splitter
.convert(this)
.map((_) => prefix + _)
.map((_) => trim ? _.trim() : _)
.join(lineBreak);
}
7 changes: 3 additions & 4 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: marker
description: A renderer (printer) for the markdown library. Renders the parsed AST back into markdown.
version: 0.2.3
version: 0.3.0
homepage: https://github.com/f3ath/marker

cider:
Expand All @@ -9,14 +9,13 @@ cider:
diff: https://github.com/f3ath/marker/compare/%from%...%to%

environment:
sdk: '>=2.15.1 <3.0.0'
sdk: '>=2.16.2 <3.0.0'

dependencies:
markdown: ^4.0.0
markdown: ^5.0.0

dev_dependencies:
test: ^1.16.0
lints: ^1.0.1
coverage: ^1.0.1
check_coverage: ^0.0.1
cider: ^0.1.1
Loading

0 comments on commit e2e5661

Please sign in to comment.