Skip to content

Commit 03821e3

Browse files
authored
Mustachio: Implement partial rendering support (#2467)
Mustachio: Implement partial rendering support
1 parent 7c68375 commit 03821e3

File tree

7 files changed

+494
-216
lines changed

7 files changed

+494
-216
lines changed

lib/src/generator/templates.renderers.dart

Lines changed: 88 additions & 69 deletions
Large diffs are not rendered by default.

lib/src/mustachio/renderer_base.dart

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:analyzer/file_system/file_system.dart';
56
import 'package:meta/meta.dart';
67
import 'parser.dart';
78

@@ -13,10 +14,12 @@ abstract class RendererBase<T> {
1314
/// The renderer of the parent context, if any, otherwise `null`.
1415
final RendererBase parent;
1516

17+
final File template;
18+
1619
/// The output buffer into which [context] is rendered, using a template.
1720
final buffer = StringBuffer();
1821

19-
RendererBase(this.context, this.parent);
22+
RendererBase(this.context, this.parent, this.template);
2023

2124
void write(String text) => buffer.write(text);
2225

@@ -48,7 +51,7 @@ abstract class RendererBase<T> {
4851
throw MustachioResolutionError(
4952
"Failed to resolve '${e.name}' on ${e.contextType} while resolving "
5053
'${names.skip(1)} as a property chain on any types in the context '
51-
"chain: $contextChainString, after first resolving '${names.first}'"
54+
"chain: $contextChainString, after first resolving '${names.first}' "
5255
'to a property on $T');
5356
}
5457
} else if (parent != null) {
@@ -118,20 +121,33 @@ abstract class RendererBase<T> {
118121
}
119122

120123
void partial(Partial node) {
121-
// TODO(srawlins): Implement.
124+
var key = node.key;
125+
var partialPath = template.provider.pathContext.isAbsolute(key)
126+
? key
127+
: template.provider.pathContext.join(template.parent.path, key);
128+
try {
129+
var file = template.provider
130+
.getFile(template.provider.pathContext.normalize(partialPath));
131+
var parser = MustachioParser(file.readAsStringSync());
132+
var ast = parser.parse();
133+
renderBlock(ast);
134+
} on FileSystemException catch (e) {
135+
throw MustachioResolutionError(
136+
'FileSystemException when reading partial "$key" found in template "${template.path}": ${e.message}');
137+
}
122138
}
123139
}
124140

125-
String renderSimple(Object context, List<MustachioNode> ast,
141+
String renderSimple(Object context, List<MustachioNode> ast, File template,
126142
{RendererBase parent}) {
127-
var renderer = SimpleRenderer(context, parent);
143+
var renderer = SimpleRenderer(context, parent, template);
128144
renderer.renderBlock(ast);
129145
return renderer.buffer.toString();
130146
}
131147

132148
class SimpleRenderer extends RendererBase<Object> {
133-
SimpleRenderer(Object context, RendererBase<Object> parent)
134-
: super(context, parent);
149+
SimpleRenderer(Object context, RendererBase<Object> parent, File template)
150+
: super(context, parent, template);
135151

136152
@override
137153
Property<Object> getProperty(String key) => null;

test/mustachio/builder_test.dart

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ class Bar {}
143143
return self.getValue(c).toString();
144144
} else {
145145
throw MustachioResolutionError(
146-
\'Failed to resolve simple renderer use @visibleToMustache\');
146+
_simpleResolveErrorMessage(remainingNames, 'bool'));
147147
}
148148
},
149149
getBool: (CT_ c) => c.b1 == true,
@@ -161,15 +161,15 @@ class Bar {}
161161
return self.getValue(c).toString();
162162
} else {
163163
throw MustachioResolutionError(
164-
'Failed to resolve simple renderer use @visibleToMustache');
164+
_simpleResolveErrorMessage(remainingNames, 'List<int>'));
165165
}
166166
},
167167
isEmptyIterable: (CT_ c) => c.l1?.isEmpty ?? true,
168168
renderIterable:
169169
(CT_ c, RendererBase<CT_> r, List<MustachioNode> ast) {
170170
var buffer = StringBuffer();
171171
for (var e in c.l1) {
172-
buffer.write(renderSimple(e, ast, parent: r));
172+
buffer.write(renderSimple(e, ast, r.template, parent: r));
173173
}
174174
return buffer.toString();
175175
},
@@ -187,12 +187,12 @@ class Bar {}
187187
return self.getValue(c).toString();
188188
} else {
189189
throw MustachioResolutionError(
190-
'Failed to resolve simple renderer use @visibleToMustache');
190+
_simpleResolveErrorMessage(remainingNames, 'String'));
191191
}
192192
},
193193
isNullValue: (CT_ c) => c.s1 == null,
194194
renderValue: (CT_ c, RendererBase<CT_> r, List<MustachioNode> ast) {
195-
return renderSimple(c.s1, ast, parent: r);
195+
return renderSimple(c.s1, ast, r.template, parent: r);
196196
},
197197
),
198198
'''));
@@ -239,11 +239,16 @@ import 'package:mustachio/annotations.dart';
239239
generatedContent = utf8.decode(writer.assets[rendererAsset]);
240240
});
241241

242+
test('with a corresponding public API function', () async {
243+
expect(generatedContent,
244+
contains('String renderFoo<T>(Foo<T> context, File file)'));
245+
});
246+
242247
test('with a corresponding render function', () async {
243248
expect(
244249
generatedContent,
245250
contains(
246-
'String renderFoo<T>(Foo<T> context, List<MustachioNode> ast,'));
251+
'String _render_Foo<T>(Foo<T> context, List<MustachioNode> ast, File file,'));
247252
});
248253

249254
test('with a generic supertype type argument', () async {

test/mustachio/foo.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ class Foo {
1515
class Bar {
1616
Foo foo;
1717
String s2;
18+
Baz baz;
19+
bool l1;
1820
}
1921

2022
class Baz {

0 commit comments

Comments
 (0)