jael3 10.0.0
jael3: ^10.0.0 copied to clipboard
A simple server-side HTML templating engine for Dart. Comparable to Blade or Liquid.
Jael 3 #
A simple server-side HTML templating engine for Dart.
Installation #
In your pubspec.yaml:
dependencies:
jael3: ^10.0.0
Usage #
The core jael3 package exports classes for parsing Jael templates, an AST library, and a Renderer class that generates HTML on-the-fly.
import 'package:belatuk_code_buffer/belatuk_code_buffer.dart';
import 'package:belatuk_symbol_table/belatuk_symbol_table.dart';
import 'package:jael3/jael3.dart' as jael;
void myFunction() {
const template = '''
<html>
<body>
<h1>Hello</h1>
<img src=profile['avatar']>
</body>
</html>
''';
var buf = CodeBuffer();
var document = jael.parseDocument(template, sourceUrl: 'test.jael', asDSX: false);
var scope = SymbolTable(values: {
'profile': {
'avatar': 'thosakwe.png',
}
});
const jael.Renderer().render(document, buf, scope);
print(buf);
}
Pre-processing (i.e. handling of blocks and includes) is handled by package:jael3_preprocessor..
Members of values #
{{ user.name }} reads the member name of user, of the first of these that has it:
- the
memberResolvergiven toRenderer.render(angel3_jaelgives one that reads the members through the app's reflector); - a key of a
Map(a key wins over a member ofMap:{{ m.length }}of{'length': 1}is1); - a common member of a core type: of
String,IterableandList,Map,MapEntry,numandint,DateTimeandDuration, such aslength,first,join,toUpperCase,toInt,toStringAsFixedoryear; - a key of the value's
toJson(), as of an@serializablemodel.
jael3 does not use dart:mirrors, so a getter of another class is read only through a memberResolver, which returns noMember for those it does not know, or toJson():
const jael.Renderer().render(
document,
buf,
scope,
memberResolver: (target, name) => switch ((target, name)) {
(User u, 'name') => u.name,
(User u, 'isAdmin') => u.isAdmin,
_ => jael.noMember,
},
);
The toJson() of a value is called once in a render, for all its members. As in Dart, first, last and single of an empty list throw: test isEmpty first, as in <p if=items.isNotEmpty>{{ items.first }}</p>.
With strictResolution: false, an unknown member, or a member of null, is null, as an unknown name is; otherwise it throws a NoSuchMethodError.
Expressions #
?.makes the rest of a chainnullif its target is:{{ user?.name.length }},{{ user?.greet() }}and{{ user?.tags[0] }}arenullifuseris.- The operators are
*,/,%,+,-,<,<=,>,>=,==,!=,&&,||,??,!and? :.&&,||and??compute their right side only if needed. WithstrictResolution: false,!,&&and||take onlytrueas true. - Map literals,
{'a': 1, key: value}, and calls with named arguments,{{ pad('x', width: 3) }}, are supported.
Migrating from 9.x to 10.0.0 #
The breaking changes of each release are listed in the CHANGELOG. Those of 10.0.0 that may need changes in an app:
- No
dart:mirrors:{{ a.b }}readsbfrom thememberResolvergiven toRenderer.render, a key of aMap, a common member of a core type, or a key of the value'stoJson(). Getters of other classes need amemberResolveror atoJson(); see Members of values.angel3_jaelgives a resolver of the app's reflector. newis removed (NewExpression,TokenType.$new), as it could never be parsed. Put a function that makes the value in the scope instead.strictResolution: falsemakes an unknown member, or a member ofnull,null.readMembertakesresolveras a named parameter, and the newtryReadMemberreturnsnoMemberfor a member it does not know.