Skip to content
This repository has been archived by the owner on Sep 12, 2019. It is now read-only.

Commit

Permalink
Some cleanup based on tooling requirements (#19)
Browse files Browse the repository at this point in the history
* Add visitExpression to TemplateAstVisitor

* Add an example test to verify expressions in let

* Add visitor support for BananaAst and StarAst

* Expose parsing with tool-friendly origin ASTs
  • Loading branch information
matanlurey authored Jan 10, 2017
1 parent eb44422 commit 939afd8
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 17 deletions.
13 changes: 11 additions & 2 deletions lib/angular_ast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:meta/meta.dart';
export 'package:angular_ast/src/ast.dart'
show
AttributeAst,
BananaAst,
CommentAst,
ElementAst,
EmbeddedContentAst,
Expand All @@ -18,6 +19,7 @@ export 'package:angular_ast/src/ast.dart'
PropertyAst,
ReferenceAst,
StandaloneTemplateAst,
StarAst,
SyntheticTemplateAst,
TemplateAst,
TextAst;
Expand All @@ -31,6 +33,13 @@ export 'package:angular_ast/src/visitor.dart'
TemplateAstVisitor;

/// Returns [template] parsed as an abstract syntax tree.
List<TemplateAst> parse(String template, {@required String sourceUrl}) {
return const NgParser().parse(template, sourceUrl: sourceUrl);
List<TemplateAst> parse(
String template, {
@required String sourceUrl,
bool toolFriendlyAst: false,
}) {
final parser = toolFriendlyAst
? const NgParser(toolFriendlyAstOrigin: true)
: const NgParser();
return parser.parse(template, sourceUrl: sourceUrl);
}
30 changes: 29 additions & 1 deletion lib/src/ast/expression.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
// BSD-style license that can be found in the LICENSE file.

import 'package:analyzer/analyzer.dart' as analyzer;
import 'package:angular_ast/angular_ast.dart';
import 'package:angular_ast/src/expression/parser.dart';
import 'package:meta/meta.dart';
import 'package:source_span/src/span.dart';

/// Wraps a parsed Dart [Expression] as an Angular [ExpressionAst].
class ExpressionAst {
class ExpressionAst implements TemplateAst {
/// Dart expression.
final analyzer.Expression expression;

Expand Down Expand Up @@ -38,6 +40,32 @@ class ExpressionAst {
@override
int get hashCode => expression.hashCode;

@override
/*=R*/ accept/*<R, C>*/(TemplateAstVisitor/*<R, C>*/ visitor, [C context]) {
return visitor.visitExpression(this, context);
}

@override
NgToken get beginToken => null;

@override
List<StandaloneTemplateAst> get childNodes => const [];

@override
NgToken get endToken => null;

@override
bool get isParent => false;

@override
bool get isStandalone => false;

@override
bool get isSynthetic => true;

@override
SourceSpan get sourceSpan => null;

@override
String toString() => '$ExpressionAst {$expression}';
}
2 changes: 1 addition & 1 deletion lib/src/ast/sugar/banana.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ abstract class BananaAst implements TemplateAst {

@override
/*=R*/ accept/*<R, C>*/(TemplateAstVisitor/*<R, C>*/ visitor, [C context]) {
throw new UnimplementedError();
return visitor.visitBanana(this, context);
}

@override
Expand Down
2 changes: 1 addition & 1 deletion lib/src/ast/sugar/star.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ abstract class StarAst implements TemplateAst {

@override
/*=R*/ accept/*<R, C>*/(TemplateAstVisitor/*<R, C>*/ visitor, [C context]) {
throw new UnimplementedError();
return visitor.visitStar(this, context);
}

@override
Expand Down
13 changes: 13 additions & 0 deletions lib/src/visitor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ abstract class TemplateAstVisitor<R, C> {
/// Visits all attribute ASTs.
R visitAttribute(AttributeAst astNode, [C context]);

/// Visits all banana ASTs.
///
/// **NOTE**: When de-sugared, this will never occur in a template tree.
R visitBanana(BananaAst astNode, [C context]);

/// Visits all comment ASTs.
R visitComment(CommentAst astNode, [C context]);

Expand Down Expand Up @@ -45,6 +50,9 @@ abstract class TemplateAstVisitor<R, C> {
/// Visits all event ASTs.
R visitEvent(EventAst astNode, [C context]);

/// Visits all expression ASTs.
R visitExpression(ExpressionAst astNode, [C context]);

/// Visits all interpolation ASTs.
R visitInterpolation(InterpolationAst astNode, [C context]);

Expand All @@ -54,6 +62,11 @@ abstract class TemplateAstVisitor<R, C> {
/// Visits all reference ASTs.
R visitReference(ReferenceAst astNode, [C context]);

/// Visits all star ASTs.
///
/// **NOTE**: When de-sugared, this will never occur in a template tree.
R visitStar(StarAst astNode, [C context]);

/// Visits all text ASTs.
R visitText(TextAst astNode, [C context]);
}
31 changes: 20 additions & 11 deletions lib/src/visitors/humanizing.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:angular_ast/src/ast/attribute.dart';
import 'package:angular_ast/src/ast/comment.dart';
import 'package:angular_ast/src/ast/content.dart';
import 'package:angular_ast/src/ast/element.dart';
import 'package:angular_ast/src/ast/event.dart';
import 'package:angular_ast/src/ast/interpolation.dart';
import 'package:angular_ast/src/ast/property.dart';
import 'package:angular_ast/src/ast/reference.dart';
import 'package:angular_ast/src/ast/template.dart';
import 'package:angular_ast/src/ast/text.dart';
import 'package:angular_ast/src/visitor.dart';
import 'package:angular_ast/angular_ast.dart';

/// Provides a human-readable view of a template AST tree.
class HumanizingTemplateAstVisitor
Expand All @@ -28,6 +18,11 @@ class HumanizingTemplateAstVisitor
}
}

@override
String visitBanana(BananaAst astNode, [_]) {
return '[(${astNode.name})]="${astNode.field}"';
}

@override
String visitComment(CommentAst astNode, [_]) {
return '<!--${astNode.value}-->';
Expand Down Expand Up @@ -115,6 +110,11 @@ class HumanizingTemplateAstVisitor
return '(${astNode.name})="${astNode.expression.expression.toSource()}"';
}

@override
String visitExpression(ExpressionAst astNode, [_]) {
return astNode.expression.toSource();
}

@override
String visitInterpolation(InterpolationAst astNode, [_]) {
return '{{${astNode.expression.expression.toSource()}}}';
Expand All @@ -138,6 +138,15 @@ class HumanizingTemplateAstVisitor
}
}

@override
String visitStar(StarAst astNode, [_]) {
if (astNode.expression == null) {
return '*${astNode.name}';
} else {
return '*${astNode.name}="${visitExpression(astNode.expression)}"';
}
}

@override
String visitText(TextAst astNode, [_]) => astNode.value;
}
9 changes: 9 additions & 0 deletions lib/src/visitors/identity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ class IdentityTemplateAstVisitor<C>
@override
TemplateAst visitAttribute(AttributeAst astNode, [_]) => astNode;

@override
TemplateAst visitBanana(BananaAst astNode, [_]) => astNode;

@override
TemplateAst visitComment(CommentAst astNode, [_]) => astNode;

Expand All @@ -32,6 +35,9 @@ class IdentityTemplateAstVisitor<C>
@override
TemplateAst visitEvent(EventAst astNode, [_]) => astNode;

@override
TemplateAst visitExpression(ExpressionAst astNode, [_]) => astNode;

@override
TemplateAst visitInterpolation(InterpolationAst astNode, [_]) => astNode;

Expand All @@ -41,6 +47,9 @@ class IdentityTemplateAstVisitor<C>
@override
TemplateAst visitReference(ReferenceAst astNode, [_]) => astNode;

@override
TemplateAst visitStar(StarAst astNode, [_]) => astNode;

@override
TemplateAst visitText(TextAst astNode, [_]) => astNode;
}
20 changes: 20 additions & 0 deletions test/expression/micro/parser_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,26 @@ void main() {
);
});

test('should parse a let with a full Dart expression', () {
expect(
parse('ngFor', 'let x of items.where(filter)'),
new NgMicroAst(
assignments: [
new ReferenceAst('x'),
],
properties: [
new PropertyAst(
'ngForOf',
new ExpressionAst.parse(
'items.where(filter)',
sourceUrl: '/test/expression/micro/parser_test.dart#inline',
),
),
],
),
);
});

test('should parse a let/bind pair', () {
expect(
parse('ngFor', 'let item of items; trackBy: byId'),
Expand Down
17 changes: 16 additions & 1 deletion test/visitor_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,32 @@ import 'package:angular_ast/angular_ast.dart';
import 'package:test/test.dart';

void main() {
final visitor = const HumanizingTemplateAstVisitor();

test('should humanize a simple template', () {
final template = parse(
'<button [title]="aTitle">Hello {{name}}</button>',
sourceUrl: '/test/visitor_test.dart#inline',
);
final visitor = const HumanizingTemplateAstVisitor();
expect(
template.map((t) => t.accept(visitor)).join(''),
equalsIgnoringWhitespace(r'''
<button [title]="aTitle">Hello {{name}}</button>
'''),
);
});

test('should humanize a simple template *with* de-sugaring applied', () {
final template = parse(
'<widget *ngIf="someValue" [(value)]="value"></widget>',
sourceUrl: '/test/visitor_test.dart#inline',
toolFriendlyAst: false,
);
expect(
template.map((t) => t.accept(visitor)).join(''),
equalsIgnoringWhitespace(r'''
<template [ngIf]="someValue"><widget (valueChanged)="value = $event" [value]="value"></widget></template>
'''),
);
});
}

0 comments on commit 939afd8

Please sign in to comment.