2021-05-15 10:45:39 +00:00
|
|
|
import 'package:angel3_framework/angel3_framework.dart';
|
2021-09-25 06:32:32 +00:00
|
|
|
import 'package:belatuk_code_buffer/belatuk_code_buffer.dart';
|
2017-09-30 23:01:30 +00:00
|
|
|
import 'package:file/file.dart';
|
2021-05-15 10:45:39 +00:00
|
|
|
import 'package:jael3/jael3.dart';
|
|
|
|
import 'package:jael3_preprocessor/jael3_preprocessor.dart';
|
2021-09-13 00:30:02 +00:00
|
|
|
import 'package:belatuk_symbol_table/belatuk_symbol_table.dart';
|
2017-09-30 23:01:30 +00:00
|
|
|
|
2017-10-01 03:14:44 +00:00
|
|
|
/// Configures an Angel server to use Jael to render templates.
|
|
|
|
///
|
2021-11-25 00:33:56 +00:00
|
|
|
/// To enable "minified" output, set minified to true
|
|
|
|
///
|
|
|
|
/// For custom HTML formating, you need to override the [createBuffer] parameter
|
|
|
|
/// with a function that returns a new instance of [CodeBuffer].
|
2017-10-02 16:12:51 +00:00
|
|
|
///
|
|
|
|
/// To apply additional transforms to parsed documents, provide a set of [patch] functions.
|
2024-10-12 10:35:14 +00:00
|
|
|
ProtevusConfigurer jael(Directory viewsDirectory,
|
2021-12-19 17:39:16 +00:00
|
|
|
{String fileExtension = '.jael',
|
2021-04-30 07:19:26 +00:00
|
|
|
bool strictResolution = false,
|
2021-12-19 17:39:16 +00:00
|
|
|
bool cacheViews = true,
|
2021-12-25 02:40:30 +00:00
|
|
|
Map<String, Document>? cache,
|
2021-11-25 00:33:56 +00:00
|
|
|
Iterable<Patcher> patch = const [],
|
2021-04-30 07:19:26 +00:00
|
|
|
bool asDSX = false,
|
2021-12-22 23:34:41 +00:00
|
|
|
bool minified = true,
|
2021-09-25 06:32:32 +00:00
|
|
|
CodeBuffer Function()? createBuffer}) {
|
2023-05-26 23:27:47 +00:00
|
|
|
var localCache = cache ?? <String, Document>{};
|
2021-12-19 17:39:16 +00:00
|
|
|
|
|
|
|
var bufferFunc = createBuffer ?? () => CodeBuffer();
|
|
|
|
|
|
|
|
if (minified) {
|
|
|
|
bufferFunc = () => CodeBuffer(space: '', newline: '');
|
2021-11-25 00:33:56 +00:00
|
|
|
}
|
2017-09-30 23:01:30 +00:00
|
|
|
|
2024-10-12 10:35:14 +00:00
|
|
|
return (Protevus app) async {
|
2021-04-30 07:19:26 +00:00
|
|
|
app.viewGenerator = (String name, [Map? locals]) async {
|
2017-09-30 23:01:30 +00:00
|
|
|
var errors = <JaelError>[];
|
2021-04-30 07:19:26 +00:00
|
|
|
Document? processed;
|
2017-10-01 03:14:44 +00:00
|
|
|
|
2021-12-25 02:40:30 +00:00
|
|
|
//var stopwatch = Stopwatch()..start();
|
2017-10-01 03:14:44 +00:00
|
|
|
|
2023-05-26 23:27:47 +00:00
|
|
|
if (cacheViews && localCache.containsKey(name)) {
|
|
|
|
processed = localCache[name];
|
2021-12-25 02:40:30 +00:00
|
|
|
} else {
|
|
|
|
processed = await _loadViewTemplate(viewsDirectory, name,
|
|
|
|
fileExtension: fileExtension, asDSX: asDSX, patch: patch);
|
2017-10-01 03:14:44 +00:00
|
|
|
|
2021-12-19 17:39:16 +00:00
|
|
|
if (cacheViews) {
|
2023-05-26 23:27:47 +00:00
|
|
|
localCache[name] = processed!;
|
2017-10-01 03:14:44 +00:00
|
|
|
}
|
2017-09-30 23:01:30 +00:00
|
|
|
}
|
2021-12-25 02:40:30 +00:00
|
|
|
//print('Time executed: ${stopwatch.elapsed.inMilliseconds}');
|
|
|
|
//stopwatch.stop();
|
2017-09-30 23:01:30 +00:00
|
|
|
|
2021-12-19 17:39:16 +00:00
|
|
|
var buf = bufferFunc();
|
2021-04-30 07:19:26 +00:00
|
|
|
var scope = SymbolTable(
|
|
|
|
values: locals?.keys.fold<Map<String, dynamic>>(<String, dynamic>{},
|
2018-07-15 20:41:43 +00:00
|
|
|
(out, k) => out..[k.toString()] = locals[k]) ??
|
|
|
|
<String, dynamic>{});
|
2017-09-30 23:01:30 +00:00
|
|
|
|
|
|
|
if (errors.isEmpty) {
|
|
|
|
try {
|
2021-04-30 07:19:26 +00:00
|
|
|
const Renderer().render(processed!, buf, scope,
|
2021-12-25 02:40:30 +00:00
|
|
|
strictResolution: strictResolution);
|
2017-09-30 23:01:30 +00:00
|
|
|
return buf.toString();
|
|
|
|
} on JaelError catch (e) {
|
|
|
|
errors.add(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-26 15:31:34 +00:00
|
|
|
Renderer.errorDocument(errors, buf..clear());
|
2017-09-30 23:01:30 +00:00
|
|
|
return buf.toString();
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
2021-12-25 02:40:30 +00:00
|
|
|
|
|
|
|
/// Preload all of Jael templates into a cache
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// To apply additional transforms to parsed documents, provide a set of [patch] functions.
|
|
|
|
Future<void> jaelTemplatePreload(
|
|
|
|
Directory viewsDirectory, Map<String, Document> cache,
|
|
|
|
{String fileExtension = '.jael',
|
|
|
|
bool asDSX = false,
|
|
|
|
Iterable<Patcher> patch = const []}) async {
|
|
|
|
await viewsDirectory.list(recursive: true).forEach((f) async {
|
|
|
|
if (f.basename.endsWith(fileExtension)) {
|
|
|
|
var name = f.basename.split(".");
|
|
|
|
if (name.length > 1) {
|
2021-12-25 02:54:16 +00:00
|
|
|
//print("View: ${name[0]}");
|
2021-12-25 02:40:30 +00:00
|
|
|
Document? processed = await _loadViewTemplate(viewsDirectory, name[0]);
|
|
|
|
if (processed != null) {
|
|
|
|
cache[name[0]] = processed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<Document?> _loadViewTemplate(Directory viewsDirectory, String name,
|
|
|
|
{String fileExtension = '.jael',
|
|
|
|
bool asDSX = false,
|
|
|
|
Iterable<Patcher> patch = const []}) async {
|
|
|
|
var errors = <JaelError>[];
|
|
|
|
Document? processed;
|
|
|
|
|
|
|
|
var file = viewsDirectory.childFile(name + fileExtension);
|
|
|
|
var contents = await file.readAsString();
|
|
|
|
var doc = parseDocument(contents,
|
|
|
|
sourceUrl: file.uri, asDSX: asDSX, onError: errors.add);
|
|
|
|
|
|
|
|
if (doc == null) {
|
2022-12-17 09:59:00 +00:00
|
|
|
throw ArgumentError("${file.basename} does not exists");
|
2021-12-25 02:40:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
processed =
|
|
|
|
await (resolve(doc, viewsDirectory, patch: patch, onError: errors.add));
|
|
|
|
} catch (e) {
|
|
|
|
// Ignore these errors, so that we can show syntax errors.
|
|
|
|
}
|
|
|
|
if (processed == null) {
|
2022-12-17 09:59:00 +00:00
|
|
|
throw ArgumentError("${file.basename} does not exists");
|
2021-12-25 02:40:30 +00:00
|
|
|
}
|
|
|
|
return processed;
|
|
|
|
}
|