platform/lib/angel_markdown.dart

69 lines
2.2 KiB
Dart
Raw Normal View History

2017-08-13 04:24:38 +00:00
import 'dart:async';
import 'dart:io';
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart';
import 'package:markdown/markdown.dart';
2017-08-13 19:42:29 +00:00
final RegExp _braces = new RegExp(r'@?{{(((\\})|([^}]))+)}}');
2017-08-13 04:24:38 +00:00
/// Configures an [Angel] instance to render Markdown templates from the specified [viewsDirectory].
///
/// The default [extension] is `.md`. To search for a different file extension, provide a new one.
/// By default, an [extensionSet] is provided that renders Github-flavored Markdown. This can also be overridden.
///
/// In many cases, Markdown content will be rendered within a larger [template] that styles the entire website.
/// To wrap generated Markdown content in a template, provide a function that accepts a generated HTML String,
/// and returns a String, or a `Future<String>`.
AngelConfigurer markdown(
Directory viewsDirectory, {
String extension,
ExtensionSet extensionSet,
FutureOr<String> template(String content, Map locals),
}) {
extension ??= '.md';
2017-08-13 19:42:29 +00:00
extensionSet ??= ExtensionSet.gitHub;
2017-08-13 04:24:38 +00:00
return (Angel app) async {
app.viewGenerator = (String name, [Map locals]) async {
var file =
new File.fromUri(viewsDirectory.uri.resolve('$name$extension'));
var contents = await file.readAsString();
contents = contents.replaceAllMapped(_braces, (m) {
var text = m[0];
if (text.startsWith('@')) {
// Raw braces
return text.substring(1);
} else {
var expr = m[1];
var split = expr.split('.');
var root = split[0];
if (!locals?.containsKey(root) == true)
throw new UnimplementedError(
'Expected a local named "$root", but none was provided. Expression text: "$text"');
return _resolveDotNotation(split, locals[root]).toString();
}
});
var html = markdownToHtml(contents, extensionSet: extensionSet);
if (template != null) html = await template(html, locals ?? {});
return html;
};
};
}
_resolveDotNotation(List<String> split, target) {
if (split.length == 1) return target;
InstanceMirror mirror = reflect(target);
for (int i = 1; i < split.length; i++) {
mirror = mirror.getField(new Symbol(split[i]));
}
return mirror.reflectee;
}