Dart 2 update for pkg:jael

This commit is contained in:
Tobe O 2018-11-02 20:16:03 -04:00
parent 4abfc0a582
commit 4a77c6982d
16 changed files with 168 additions and 60 deletions

View file

@ -1,2 +1,3 @@
analyzer: analyzer:
strong-mode: true strong-mode:
implicit-casts: false

0
angel_jael/mono_pkg.yaml Normal file
View file

View file

@ -1,17 +1,17 @@
name: angel_jael name: angel_jael
version: 1.0.3 version: 2.0.0
description: Angel support for the Jael templating engine. description: Angel support for the Jael templating engine.
author: Tobe O <thosakwe@gmail.com> author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/jael/tree/master/jael homepage: https://github.com/angel-dart/jael/tree/master/jael
environment: environment:
sdk: ">=1.19.0 <=2.0.0" sdk: ">=2.0.0-dev <=3.0.0"
dependencies: dependencies:
angel_framework: ^1.0.0-dev angel_framework: ^2.0.0-alpha
code_buffer: ^1.0.0 code_buffer: ^1.0.0
file: ^2.0.0 file: ^5.0.0
jael: ^1.0.0-alpha jael: ^1.0.0-alpha
jael_preprocessor: ^1.0.0-alpha jael_preprocessor: ^1.0.0-alpha
symbol_table: ^1.0.0 symbol_table: ^2.0.0
dev_dependencies: dev_dependencies:
angel_test: ^1.1.0-alpha angel_test: ^2.0.0-alpha
test: ^0.12.0 test: ^1.0.0

View file

@ -1,5 +1,9 @@
# 2.0.0
* Dart 2 updates.
* Remove usage of `package:dart2_constant`.
# 1.0.6+1 # 1.0.6+1
* Ensure `<element>` pass attributes. * Ensure `<element>` passes attributes.
# 1.0.6 # 1.0.6
* Add `index-as` to `for-each`. * Add `index-as` to `for-each`.

View file

@ -1,5 +1,5 @@
import 'dart:convert';
import 'package:code_buffer/code_buffer.dart'; import 'package:code_buffer/code_buffer.dart';
import 'package:dart2_constant/convert.dart';
import 'package:symbol_table/symbol_table.dart'; import 'package:symbol_table/symbol_table.dart';
import 'ast/ast.dart'; import 'ast/ast.dart';
import 'text/parser.dart'; import 'text/parser.dart';
@ -54,8 +54,8 @@ class Renderer {
buf buf
..writeln('<li>') ..writeln('<li>')
..indent() ..indent()
..writeln('<b>$type:</b> ${error.span.start.toolString}: ${error ..writeln(
.message}') '<b>$type:</b> ${error.span.start.toolString}: ${error.message}')
..writeln('<br>') ..writeln('<br>')
..writeln( ..writeln(
'<span style="color: red;">' + '<span style="color: red;">' +

View file

@ -68,8 +68,10 @@ class Parser {
StringLiteral implicitString() { StringLiteral implicitString() {
if (next(TokenType.string)) { if (next(TokenType.string)) {
return prefixParselets[TokenType.string].parse(this, _current) as StringLiteral; return prefixParselets[TokenType.string].parse(this, _current)
} /*else if (next(TokenType.text)) { as StringLiteral;
}
/*else if (next(TokenType.text)) {
}*/ }*/
@ -264,8 +266,7 @@ class Parser {
if (tagName2.name != tagName.name) { if (tagName2.name != tagName.name) {
errors.add(new JaelError( errors.add(new JaelError(
JaelErrorSeverity.error, JaelErrorSeverity.error,
'Mismatched closing tags. Expected "${tagName.span 'Mismatched closing tags. Expected "${tagName.span.text}"; got "${tagName2.name}" instead.',
.text}"; got "${tagName2.name}" instead.',
lt2.span)); lt2.span));
return null; return null;
} }

0
jael/mono_pkg.yaml Normal file
View file

View file

@ -1,16 +1,15 @@
name: jael name: jael
version: 1.0.6+1 version: 2.0.0
description: A simple server-side HTML templating engine for Dart. description: A simple server-side HTML templating engine for Dart.
author: Tobe O <thosakwe@gmail.com> author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/jael/tree/master/jael homepage: https://github.com/angel-dart/jael/tree/master/jael
environment: environment:
sdk: ">=1.19.0 <=2.0.0" sdk: ">=2.0.0-dev <=3.0.0"
dependencies: dependencies:
charcode: ^1.0.0 charcode: ^1.0.0
code_buffer: ^1.0.0 code_buffer: ^1.0.0
dart2_constant: ^1.0.0
source_span: ^1.0.0 source_span: ^1.0.0
string_scanner: ^1.0.0 string_scanner: ^1.0.0
symbol_table: ^1.0.0 symbol_table: ^2.0.0
dev_dependencies: dev_dependencies:
test: ^0.12.0 test: ^1.0.0

View file

@ -18,13 +18,16 @@ void main() {
var html = render(template, {'sqrt': sqrt}); var html = render(template, {'sqrt': sqrt});
print(html); print(html);
expect(html, ''' expect(
html,
'''
<div> <div>
<div> <div>
The square root of 16 is 4. The square root of 16 is 4.
</div> </div>
</div> </div>
'''.trim()); '''
.trim());
}); });
test('render into explicit tag name', () { test('render into explicit tag name', () {
@ -40,13 +43,16 @@ void main() {
var html = render(template, {'sqrt': sqrt}); var html = render(template, {'sqrt': sqrt});
print(html); print(html);
expect(html, ''' expect(
html,
'''
<div> <div>
<span> <span>
The square root of 16 is 4. The square root of 16 is 4.
</span> </span>
</div> </div>
'''.trim()); '''
.trim());
}); });
test('pass attributes', () { test('pass attributes', () {
@ -62,13 +68,16 @@ void main() {
var html = render(template, {'sqrt': sqrt}); var html = render(template, {'sqrt': sqrt});
print(html); print(html);
expect(html, ''' expect(
html,
'''
<div> <div>
<div foo="bar" baz="quux"> <div foo="bar" baz="quux">
The square root of 16 is 4. The square root of 16 is 4.
</div> </div>
</div> </div>
'''.trim()); '''
.trim());
}); });
test('render without tag name', () { test('render without tag name', () {
@ -84,12 +93,15 @@ void main() {
var html = render(template, {'sqrt': sqrt}); var html = render(template, {'sqrt': sqrt});
print(html); print(html);
expect(html, ''' expect(
html,
'''
<div> <div>
The square root of 16 is 4. The square root of 16 is 4.
</div> </div>
'''.trim()); '''
.trim());
}); });
} }

View file

@ -21,7 +21,7 @@ main() {
try { try {
document = jael.parseDocument(template, sourceUrl: 'test.jl'); document = jael.parseDocument(template, sourceUrl: 'test.jl');
scope = new SymbolTable(values: { scope = new SymbolTable<dynamic>(values: {
'csrf_token': 'foo', 'csrf_token': 'foo',
'profile': { 'profile': {
'avatar': 'thosakwe.png', 'avatar': 'thosakwe.png',
@ -67,7 +67,7 @@ main() {
var buf = new CodeBuffer(); var buf = new CodeBuffer();
//jael.scan(template, sourceUrl: 'test.jl').tokens.forEach(print); //jael.scan(template, sourceUrl: 'test.jl').tokens.forEach(print);
var document = jael.parseDocument(template, sourceUrl: 'test.jl'); var document = jael.parseDocument(template, sourceUrl: 'test.jl');
var scope = new SymbolTable(values: { var scope = new SymbolTable<dynamic>(values: {
'pokemon': const _Pokemon('Darkrai', 'Dark'), 'pokemon': const _Pokemon('Darkrai', 'Dark'),
}); });
@ -107,7 +107,7 @@ main() {
var buf = new CodeBuffer(); var buf = new CodeBuffer();
var document = jael.parseDocument(template, sourceUrl: 'test.jl'); var document = jael.parseDocument(template, sourceUrl: 'test.jl');
var scope = new SymbolTable(values: { var scope = new SymbolTable<dynamic>(values: {
'starters': starters, 'starters': starters,
}); });
@ -152,7 +152,7 @@ main() {
var buf = new CodeBuffer(); var buf = new CodeBuffer();
var document = jael.parseDocument(template, sourceUrl: 'test.jl'); var document = jael.parseDocument(template, sourceUrl: 'test.jl');
var scope = new SymbolTable(values: { var scope = new SymbolTable<dynamic>(values: {
'starters': starters, 'starters': starters,
}); });
@ -300,7 +300,7 @@ main() {
var buf = new CodeBuffer(); var buf = new CodeBuffer();
var document = jael.parseDocument(template, sourceUrl: 'test.jl'); var document = jael.parseDocument(template, sourceUrl: 'test.jl');
var scope = new SymbolTable(values: { var scope = new SymbolTable<dynamic>(values: {
'account': new _Account(isDisabled: true), 'account': new _Account(isDisabled: true),
}); });
@ -327,7 +327,7 @@ main() {
var buf = new CodeBuffer(); var buf = new CodeBuffer();
var document = jael.parseDocument(template, sourceUrl: 'test.jl'); var document = jael.parseDocument(template, sourceUrl: 'test.jl');
var scope = new SymbolTable(values: { var scope = new SymbolTable<dynamic>(values: {
'account': new _Account(isDisabled: null), 'account': new _Account(isDisabled: null),
}); });

View file

@ -83,7 +83,8 @@ main() {
<script aria-label="script"> <script aria-label="script">
window.alert('a string'); window.alert('a string');
</script> </script>
'''.trim(), '''
.trim(),
sourceUrl: 'test.jl', sourceUrl: 'test.jl',
).tokens; ).tokens;
tokens.forEach(print); tokens.forEach(print);

View file

@ -1,2 +1,3 @@
analyzer: analyzer:
strong-mode: true strong-mode:
implicit-casts: false

View file

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:collection'; import 'dart:collection';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:jael/jael.dart'; import 'package:jael/jael.dart';
import 'package:symbol_table/symbol_table.dart';
/// Modifies a Jael document. /// Modifies a Jael document.
typedef FutureOr<Document> Patcher(Document document, typedef FutureOr<Document> Patcher(Document document,
@ -18,6 +19,7 @@ Future<Document> resolve(Document document, Directory currentDirectory,
// Resolve all includes... // Resolve all includes...
var includesResolved = var includesResolved =
await resolveIncludes(document, currentDirectory, onError); await resolveIncludes(document, currentDirectory, onError);
var patched = var patched =
await applyInheritance(includesResolved, currentDirectory, onError); await applyInheritance(includesResolved, currentDirectory, onError);
@ -68,26 +70,63 @@ Future<Document> applyInheritance(Document document, Directory currentDirectory,
// by filling in blocks. // by filling in blocks.
document = chain.removeFirst(); document = chain.removeFirst();
var blocks = new SymbolTable<Element>();
while (chain.isNotEmpty) { while (chain.isNotEmpty) {
var child = chain.removeFirst(); var child = chain.removeFirst();
var blocks = extractBlockDeclarations(child.root, onError); var scope = blocks;
extractBlockDeclarations(scope, child.root, onError);
var blocksExpanded = var blocksExpanded =
await expandBlocks(document.root, blocks, currentDirectory, onError); await expandBlocks(document.root, blocks, currentDirectory, onError);
if (blocksExpanded == null) {
// This in itself is a block; expand it.
// TODO: Ambiguous
}
document = document =
new Document(child.doctype ?? document.doctype, blocksExpanded); new Document(child.doctype ?? document.doctype, blocksExpanded);
} }
// Fill in any remaining blocks // Fill in any remaining blocks
var blocksExpanded = var blocksExpanded =
await expandBlocks(document.root, {}, currentDirectory, onError); await expandBlocks(document.root, blocks, currentDirectory, onError);
return new Document(document.doctype, blocksExpanded); return new Document(document.doctype, blocksExpanded);
} }
} }
List<Element> allBlocksRecursive(Element element) {
var out = <Element>[];
for (var e in element.children) {
if (e is Element && e.tagName.name == 'block') {
out.add(e);
}
}
for (var child in element.children) {
if (child is Element) {
var childBlocks = allBlocksRecursive(child);
out.addAll(childBlocks);
//
// if (childBlocks.isNotEmpty) {
// print('<<<\n${child.span.highlight()}');
//
// for (var b in childBlocks) {
// print('!!!!\n${b.span.highlight()}');
// }
// }
}
}
return out; //out.reversed.toList();
}
/// Extracts any `block` declarations. /// Extracts any `block` declarations.
Map<String, Element> extractBlockDeclarations( void extractBlockDeclarations(SymbolTable<Element> blocks, Element element,
Element element, void onError(JaelError error)) { void onError(JaelError error)) {
Map<String, Element> blocks = {}; //var blockElements = allBlocksRecursive(element);
var blockElements = var blockElements =
element.children.where((e) => e is Element && e.tagName.name == 'block'); element.children.where((e) => e is Element && e.tagName.name == 'block');
@ -104,11 +143,9 @@ Map<String, Element> extractBlockDeclarations(
nameAttr.span)); nameAttr.span));
} else { } else {
var name = (nameAttr.value as StringLiteral).value; var name = (nameAttr.value as StringLiteral).value;
blocks[name] = blockElement; blocks.assign(name, blockElement);
} }
} }
return blocks;
} }
/// Finds the name of the parent template. /// Finds the name of the parent template.
@ -134,8 +171,10 @@ String getParent(Document document, void onError(JaelError error)) {
} }
/// Replaces any `block` tags within the element. /// Replaces any `block` tags within the element.
Future<Element> expandBlocks(Element element, Map<String, Element> blocks, Future<Element> expandBlocks(Element element, SymbolTable<Element> blockss,
Directory currentDirectory, void onError(JaelError error)) async { Directory currentDirectory, void onError(JaelError error)) async {
var blocks = blockss.createChild();
if (element is SelfClosingElement) if (element is SelfClosingElement)
return element; return element;
else if (element is RegularElement) { else if (element is RegularElement) {
@ -166,10 +205,11 @@ Future<Element> expandBlocks(Element element, Map<String, Element> blocks,
var name = (nameAttr.value as StringLiteral).value; var name = (nameAttr.value as StringLiteral).value;
Iterable<ElementChild> children; Iterable<ElementChild> children;
if (!blocks.containsKey(name)) { if (blocks.resolve(name) == null) {
print('Hm what? $name');
children = child.children; children = child.children;
} else { } else {
children = blocks[name].children; children = blocks.resolve(name).value.children;
} }
expanded.addAll(children); expanded.addAll(children);
@ -184,21 +224,62 @@ Future<Element> expandBlocks(Element element, Map<String, Element> blocks,
} }
// Resolve all includes... // Resolve all includes...
expanded = await Future.wait(expanded.map((c) { var out = <ElementChild>[];
if (c is! Element) return new Future.value(c);
return expandBlocks(c, blocks, currentDirectory, onError);
}));
return new RegularElement( for (var c in expanded) {
if (c is Element) {
var blocksExpanded =
await expandBlocks(c, blocks, currentDirectory, onError);
var nameAttr = c.attributes
.firstWhere((a) => a.name == 'name', orElse: () => null);
var name = (nameAttr?.value is StringLiteral)
? ((nameAttr.value as StringLiteral).value)
: null;
if (name == null) {
out.add(blocksExpanded);
} else {
// This element itself resolved to a block; expand it.
out.addAll(blocks.resolve(name)?.value?.children ?? <ElementChild>[]);
}
} else {
out.add(c);
}
}
var finalElement = new RegularElement(
element.lt, element.lt,
element.tagName, element.tagName,
element.attributes, element.attributes,
element.gt, element.gt,
expanded, out,
element.lt2, element.lt2,
element.slash, element.slash,
element.tagName2, element.tagName2,
element.gt2); element.gt2);
// If THIS element is a block, it needs to be expanded as well.
if (element.tagName.name == 'block') {
var nameAttr = element.attributes
.firstWhere((a) => a.name == 'name', orElse: () => null);
if (nameAttr == null) {
onError(new JaelError(JaelErrorSeverity.warning,
'Missing "name" attribute in "block" tag.', element.span));
} else if (nameAttr.value is! StringLiteral) {
onError(new JaelError(
JaelErrorSeverity.warning,
'The "name" attribute in an "block" tag must be a string literal.',
nameAttr.span));
}
var name = (nameAttr.value as StringLiteral).value;
print('def $name');
blockss.assign(name, finalElement);
return null;
} else {
return finalElement;
}
} else { } else {
throw new UnsupportedError( throw new UnsupportedError(
'Unsupported element type: ${element.runtimeType}'); 'Unsupported element type: ${element.runtimeType}');

View file

View file

@ -6,7 +6,7 @@ homepage: https://github.com/angel-dart/jael/tree/master/jael_processor
environment: environment:
sdk: ">=1.19.0 <=2.0.0" sdk: ">=1.19.0 <=2.0.0"
dependencies: dependencies:
file: ^2.0.0 file: ^5.0.0
jael: ^1.0.0-alpha jael: ^1.0.0-alpha
dev_dependencies: dev_dependencies:
test: ^0.12.0 test: ^0.12.0

View file

@ -29,11 +29,19 @@ main() {
// e.jl // e.jl
fileSystem.file('e.jl').writeAsStringSync( fileSystem.file('e.jl').writeAsStringSync(
'<extend src="c.jl"><block name="greeting">Angel <block name="name">default</block></block></extend>'); '<extend src="c.jl"><block name="greeting">Angel <b><block name="name">default</block></b></block></extend>');
// e.jl // fox.jl
fileSystem.file('f.jl').writeAsStringSync( fileSystem.file('fox.jl').writeAsStringSync(
'<extend src="e.jl"><block name="name">framework</block></extend>'); '<block name="dance">The name is <block name="name"></block></block>');
// trot.jl
fileSystem.file('trot.jl').writeAsStringSync(
'<extend src="fox.jl"><block name="name">CONGA <i><block name="exclaim">YEAH</block></i></block></extend>');
// foxtrot.jl
fileSystem.file('foxtrot.jl').writeAsStringSync(
'<extend src="trot.jl"><block name="exclaim">framework</block></extend>');
}); });
test('blocks are replaced or kept', () async { test('blocks are replaced or kept', () async {
@ -87,7 +95,7 @@ main() {
}); });
test('blocks within blocks', () async { test('blocks within blocks', () async {
var file = fileSystem.file('f.jl'); var file = fileSystem.file('foxtrot.jl');
var original = jael.parseDocument(await file.readAsString(), var original = jael.parseDocument(await file.readAsString(),
sourceUrl: file.uri, onError: (e) => throw e); sourceUrl: file.uri, onError: (e) => throw e);
var processed = await jael.resolve( var processed = await jael.resolve(