Skip to content

Commit afffd9b

Browse files
committed
Support custom partial resolvers in Mustachio
1 parent b956fa3 commit afffd9b

File tree

6 files changed

+110
-51
lines changed

6 files changed

+110
-51
lines changed

lib/src/generator/templates.renderers.dart

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ String _simpleResolveErrorMessage(List<String> key, String type) =>
1616
'expose the properties of $type by adding it to the @Renderer '
1717
"annotation's 'visibleTypes' list";
1818

19-
String renderIndex(PackageTemplateData context, File file) {
19+
String renderIndex(PackageTemplateData context, File file,
20+
{PartialResolver partialResolver}) {
2021
try {
2122
var parser = MustachioParser(file.readAsStringSync());
22-
return _render_PackageTemplateData(context, parser.parse(), file);
23+
return _render_PackageTemplateData(context, parser.parse(), file,
24+
partialResolver: partialResolver);
2325
} on FileSystemException catch (e) {
2426
throw MustachioResolutionError(
2527
'FileSystemException when reading template "${file.path}": ${e.message}');
@@ -28,8 +30,9 @@ String renderIndex(PackageTemplateData context, File file) {
2830

2931
String _render_PackageTemplateData(
3032
PackageTemplateData context, List<MustachioNode> ast, File file,
31-
{RendererBase<Object> parent}) {
32-
var renderer = _Renderer_PackageTemplateData(context, parent, file);
33+
{RendererBase<Object> parent, PartialResolver partialResolver}) {
34+
var renderer = _Renderer_PackageTemplateData(context, parent, file,
35+
partialResolver: partialResolver);
3336
renderer.renderBlock(ast);
3437
return renderer.buffer.toString();
3538
}
@@ -201,8 +204,9 @@ class _Renderer_PackageTemplateData extends RendererBase<PackageTemplateData> {
201204
};
202205

203206
_Renderer_PackageTemplateData(
204-
PackageTemplateData context, RendererBase<Object> parent, File file)
205-
: super(context, parent, file);
207+
PackageTemplateData context, RendererBase<Object> parent, File file,
208+
{PartialResolver partialResolver})
209+
: super(context, parent, file, partialResolver: partialResolver);
206210

207211
@override
208212
Property<PackageTemplateData> getProperty(String key) {
@@ -215,8 +219,9 @@ class _Renderer_PackageTemplateData extends RendererBase<PackageTemplateData> {
215219
}
216220

217221
String _render_Object(Object context, List<MustachioNode> ast, File file,
218-
{RendererBase<Object> parent}) {
219-
var renderer = _Renderer_Object(context, parent, file);
222+
{RendererBase<Object> parent, PartialResolver partialResolver}) {
223+
var renderer =
224+
_Renderer_Object(context, parent, file, partialResolver: partialResolver);
220225
renderer.renderBlock(ast);
221226
return renderer.buffer.toString();
222227
}
@@ -241,8 +246,9 @@ class _Renderer_Object extends RendererBase<Object> {
241246
),
242247
};
243248

244-
_Renderer_Object(Object context, RendererBase<Object> parent, File file)
245-
: super(context, parent, file);
249+
_Renderer_Object(Object context, RendererBase<Object> parent, File file,
250+
{PartialResolver partialResolver})
251+
: super(context, parent, file, partialResolver: partialResolver);
246252

247253
@override
248254
Property<Object> getProperty(String key) {
@@ -256,8 +262,9 @@ class _Renderer_Object extends RendererBase<Object> {
256262

257263
String _render_TemplateData<T extends Documentable>(
258264
TemplateData<T> context, List<MustachioNode> ast, File file,
259-
{RendererBase<Object> parent}) {
260-
var renderer = _Renderer_TemplateData(context, parent, file);
265+
{RendererBase<Object> parent, PartialResolver partialResolver}) {
266+
var renderer = _Renderer_TemplateData(context, parent, file,
267+
partialResolver: partialResolver);
261268
renderer.renderBlock(ast);
262269
return renderer.buffer.toString();
263270
}
@@ -563,8 +570,9 @@ class _Renderer_TemplateData<T extends Documentable>
563570
};
564571

565572
_Renderer_TemplateData(
566-
TemplateData<T> context, RendererBase<Object> parent, File file)
567-
: super(context, parent, file);
573+
TemplateData<T> context, RendererBase<Object> parent, File file,
574+
{PartialResolver partialResolver})
575+
: super(context, parent, file, partialResolver: partialResolver);
568576

569577
@override
570578
Property<TemplateData<T>> getProperty(String key) {

lib/src/mustachio/renderer_base.dart

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,16 @@
44

55
import 'package:analyzer/file_system/file_system.dart';
66
import 'package:meta/meta.dart';
7+
import 'package:path/path.dart' as path;
78
import 'parser.dart';
89

10+
/// The signature of a partial resolver function.
11+
typedef PartialResolver = String Function(String path);
12+
13+
/// The signature of a generated render function.
14+
typedef Renderer<T> = String Function(T context, File file,
15+
{PartialResolver partialResolver});
16+
917
/// The base class for a generated Mustache renderer.
1018
abstract class RendererBase<T> {
1119
/// The context object which this renderer can render.
@@ -16,10 +24,23 @@ abstract class RendererBase<T> {
1624

1725
final File template;
1826

27+
final PartialResolver partialResolver;
28+
1929
/// The output buffer into which [context] is rendered, using a template.
2030
final buffer = StringBuffer();
2131

22-
RendererBase(this.context, this.parent, this.template);
32+
RendererBase(this.context, this.parent, this.template,
33+
{this.partialResolver});
34+
35+
path.Context get pathContext => template.provider.pathContext;
36+
37+
String _defaultResolver(String path) {
38+
var partialPath = pathContext.isAbsolute(path)
39+
? path
40+
: pathContext.join(template.parent.path, path);
41+
var file = template.provider.getFile(pathContext.normalize(partialPath));
42+
return file.readAsStringSync();
43+
}
2344

2445
void write(String text) => buffer.write(text);
2546

@@ -122,18 +143,15 @@ abstract class RendererBase<T> {
122143

123144
void partial(Partial node) {
124145
var key = node.key;
125-
var partialPath = template.provider.pathContext.isAbsolute(key)
126-
? key
127-
: template.provider.pathContext.join(template.parent.path, key);
128146
try {
129-
var file = template.provider
130-
.getFile(template.provider.pathContext.normalize(partialPath));
131-
var parser = MustachioParser(file.readAsStringSync());
147+
var partial = (partialResolver ?? _defaultResolver)(key);
148+
var parser = MustachioParser(partial);
132149
var ast = parser.parse();
133150
renderBlock(ast);
134151
} on FileSystemException catch (e) {
135152
throw MustachioResolutionError(
136-
'FileSystemException when reading partial "$key" found in template "${template.path}": ${e.message}');
153+
'FileSystemException when reading partial "$key" found in template '
154+
'"${template.path}": ${e.message}');
137155
}
138156
}
139157
}

test/mustachio/builder_test.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,8 @@ import 'package:mustachio/annotations.dart';
241241

242242
test('with a corresponding public API function', () async {
243243
expect(generatedContent,
244-
contains('String renderFoo<T>(Foo<T> context, File file)'));
244+
contains('String renderFoo<T>(Foo<T> context, File file,'));
245+
expect(generatedContent, contains('{PartialResolver partialResolver})'));
245246
});
246247

247248
test('with a corresponding render function', () async {

test/mustachio/foo.renderers.dart

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,21 @@ String _simpleResolveErrorMessage(List<String> key, String type) =>
1616
'expose the properties of $type by adding it to the @Renderer '
1717
"annotation's 'visibleTypes' list";
1818

19-
String renderFoo(Foo context, File file) {
19+
String renderFoo(Foo context, File file, {PartialResolver partialResolver}) {
2020
try {
2121
var parser = MustachioParser(file.readAsStringSync());
22-
return _render_Foo(context, parser.parse(), file);
22+
return _render_Foo(context, parser.parse(), file,
23+
partialResolver: partialResolver);
2324
} on FileSystemException catch (e) {
2425
throw MustachioResolutionError(
2526
'FileSystemException when reading template "${file.path}": ${e.message}');
2627
}
2728
}
2829

2930
String _render_Foo(Foo context, List<MustachioNode> ast, File file,
30-
{RendererBase<Object> parent}) {
31-
var renderer = Renderer_Foo(context, parent, file);
31+
{RendererBase<Object> parent, PartialResolver partialResolver}) {
32+
var renderer =
33+
Renderer_Foo(context, parent, file, partialResolver: partialResolver);
3234
renderer.renderBlock(ast);
3335
return renderer.buffer.toString();
3436
}
@@ -107,8 +109,9 @@ class Renderer_Foo extends RendererBase<Foo> {
107109
...Renderer_Object.propertyMap<CT_>(),
108110
};
109111

110-
Renderer_Foo(Foo context, RendererBase<Object> parent, File file)
111-
: super(context, parent, file);
112+
Renderer_Foo(Foo context, RendererBase<Object> parent, File file,
113+
{PartialResolver partialResolver})
114+
: super(context, parent, file, partialResolver: partialResolver);
112115

113116
@override
114117
Property<Foo> getProperty(String key) {
@@ -121,8 +124,9 @@ class Renderer_Foo extends RendererBase<Foo> {
121124
}
122125

123126
String _render_Object(Object context, List<MustachioNode> ast, File file,
124-
{RendererBase<Object> parent}) {
125-
var renderer = Renderer_Object(context, parent, file);
127+
{RendererBase<Object> parent, PartialResolver partialResolver}) {
128+
var renderer =
129+
Renderer_Object(context, parent, file, partialResolver: partialResolver);
126130
renderer.renderBlock(ast);
127131
return renderer.buffer.toString();
128132
}
@@ -147,8 +151,9 @@ class Renderer_Object extends RendererBase<Object> {
147151
),
148152
};
149153

150-
Renderer_Object(Object context, RendererBase<Object> parent, File file)
151-
: super(context, parent, file);
154+
Renderer_Object(Object context, RendererBase<Object> parent, File file,
155+
{PartialResolver partialResolver})
156+
: super(context, parent, file, partialResolver: partialResolver);
152157

153158
@override
154159
Property<Object> getProperty(String key) {
@@ -160,19 +165,21 @@ class Renderer_Object extends RendererBase<Object> {
160165
}
161166
}
162167

163-
String renderBar(Bar context, File file) {
168+
String renderBar(Bar context, File file, {PartialResolver partialResolver}) {
164169
try {
165170
var parser = MustachioParser(file.readAsStringSync());
166-
return _render_Bar(context, parser.parse(), file);
171+
return _render_Bar(context, parser.parse(), file,
172+
partialResolver: partialResolver);
167173
} on FileSystemException catch (e) {
168174
throw MustachioResolutionError(
169175
'FileSystemException when reading template "${file.path}": ${e.message}');
170176
}
171177
}
172178

173179
String _render_Bar(Bar context, List<MustachioNode> ast, File file,
174-
{RendererBase<Object> parent}) {
175-
var renderer = Renderer_Bar(context, parent, file);
180+
{RendererBase<Object> parent, PartialResolver partialResolver}) {
181+
var renderer =
182+
Renderer_Bar(context, parent, file, partialResolver: partialResolver);
176183
renderer.renderBlock(ast);
177184
return renderer.buffer.toString();
178185
}
@@ -249,8 +256,9 @@ class Renderer_Bar extends RendererBase<Bar> {
249256
...Renderer_Object.propertyMap<CT_>(),
250257
};
251258

252-
Renderer_Bar(Bar context, RendererBase<Object> parent, File file)
253-
: super(context, parent, file);
259+
Renderer_Bar(Bar context, RendererBase<Object> parent, File file,
260+
{PartialResolver partialResolver})
261+
: super(context, parent, file, partialResolver: partialResolver);
254262

255263
@override
256264
Property<Bar> getProperty(String key) {
@@ -262,19 +270,21 @@ class Renderer_Bar extends RendererBase<Bar> {
262270
}
263271
}
264272

265-
String renderBaz(Baz context, File file) {
273+
String renderBaz(Baz context, File file, {PartialResolver partialResolver}) {
266274
try {
267275
var parser = MustachioParser(file.readAsStringSync());
268-
return _render_Baz(context, parser.parse(), file);
276+
return _render_Baz(context, parser.parse(), file,
277+
partialResolver: partialResolver);
269278
} on FileSystemException catch (e) {
270279
throw MustachioResolutionError(
271280
'FileSystemException when reading template "${file.path}": ${e.message}');
272281
}
273282
}
274283

275284
String _render_Baz(Baz context, List<MustachioNode> ast, File file,
276-
{RendererBase<Object> parent}) {
277-
var renderer = Renderer_Baz(context, parent, file);
285+
{RendererBase<Object> parent, PartialResolver partialResolver}) {
286+
var renderer =
287+
Renderer_Baz(context, parent, file, partialResolver: partialResolver);
278288
renderer.renderBlock(ast);
279289
return renderer.buffer.toString();
280290
}
@@ -303,8 +313,9 @@ class Renderer_Baz extends RendererBase<Baz> {
303313
...Renderer_Object.propertyMap<CT_>(),
304314
};
305315

306-
Renderer_Baz(Baz context, RendererBase<Object> parent, File file)
307-
: super(context, parent, file);
316+
Renderer_Baz(Baz context, RendererBase<Object> parent, File file,
317+
{PartialResolver partialResolver})
318+
: super(context, parent, file, partialResolver: partialResolver);
308319

309320
@override
310321
Property<Baz> getProperty(String key) {

test/mustachio/renderer_test.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,24 @@ void main() {
323323
'Line 2 Partial Section Instance of \'Bar\''));
324324
});
325325

326+
test('Renderer renders a partial using a custom partial renderer', () {
327+
var barTemplate = getFile('/project/bar.mustache')
328+
..writeAsStringSync('Text {{#foo}}{{>_foo.mustache}}{{/foo}}');
329+
getFile('/project/_foo.mustache').writeAsStringSync('Partial {{s1}}');
330+
var bar = Bar()..foo = (Foo()..s1 = 'hello');
331+
String partialResolver(String path) {
332+
var partialPath = resourceProvider.pathContext.isAbsolute(path)
333+
? path
334+
: resourceProvider.pathContext.join('/project', path);
335+
var file = resourceProvider
336+
.getFile(resourceProvider.pathContext.normalize('_$partialPath'));
337+
return file.readAsStringSync();
338+
}
339+
340+
expect(renderBar(bar, barTemplate, partialResolver: partialResolver),
341+
equals('Text Partial hello'));
342+
});
343+
326344
test('Renderer throws when it cannot resolve a variable key', () {
327345
var fooTemplate = getFile('/project/foo.mustache')
328346
..writeAsStringSync('Text {{s2}}');

tool/mustachio/codegen_runtime_renderer.dart

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,11 @@ String _simpleResolveErrorMessage(List<String> key, String type) =>
215215
if (renderer.publicApiFunctionName != null) {
216216
_buffer.writeln('''
217217
String ${renderer.publicApiFunctionName}${renderer._typeParametersString}(
218-
$typeWithVariables context, File file) {
218+
$typeWithVariables context, File file, {PartialResolver partialResolver}) {
219219
try {
220220
var parser = MustachioParser(file.readAsStringSync());
221-
return ${renderer._renderFunctionName}(context, parser.parse(), file);
221+
return ${renderer._renderFunctionName}(
222+
context, parser.parse(), file, partialResolver: partialResolver);
222223
} on FileSystemException catch (e) {
223224
throw MustachioResolutionError(
224225
'FileSystemException when reading template "\${file.path}": \${e.message}');
@@ -231,8 +232,9 @@ String ${renderer.publicApiFunctionName}${renderer._typeParametersString}(
231232
_buffer.writeln('''
232233
String ${renderer._renderFunctionName}${renderer._typeParametersString}(
233234
$typeWithVariables context, List<MustachioNode> ast, File file,
234-
{RendererBase<Object> parent}) {
235-
var renderer = ${renderer._rendererClassName}(context, parent, file);
235+
{RendererBase<Object> parent, PartialResolver partialResolver}) {
236+
var renderer = ${renderer._rendererClassName}(
237+
context, parent, file, partialResolver: partialResolver);
236238
renderer.renderBlock(ast);
237239
return renderer.buffer.toString();
238240
}
@@ -247,8 +249,9 @@ class ${renderer._rendererClassName}${renderer._typeParametersString}
247249
// Write out the constructor.
248250
_buffer.writeln('''
249251
${renderer._rendererClassName}(
250-
$typeWithVariables context, RendererBase<Object> parent, File file)
251-
: super(context, parent, file);
252+
$typeWithVariables context, RendererBase<Object> parent, File file,
253+
{PartialResolver partialResolver})
254+
: super(context, parent, file, partialResolver: partialResolver);
252255
''');
253256
var propertyMapTypeArguments = renderer._typeArgumentsStringWith(typeName);
254257
var propertyMapName = 'propertyMap$propertyMapTypeArguments';

0 commit comments

Comments
 (0)