From 61ee2320d59897558160162f20efbb76db02dba9 Mon Sep 17 00:00:00 2001 From: HibaChamkhi Date: Wed, 10 Jun 2026 14:19:39 +0100 Subject: [PATCH 1/4] [mustache_template] Add example app and code excerpts --- .../packages/mustache_template/CHANGELOG.md | 1 + .../packages/mustache_template/README.md | 112 +++++++----------- .../example/lib/readme_excerpts.dart | 78 ++++++++++++ .../mustache_template/example/pubspec.yaml | 11 ++ .../mustache_template/test/example_test.dart | 61 ++++++++++ 5 files changed, 196 insertions(+), 67 deletions(-) create mode 100644 third_party/packages/mustache_template/example/lib/readme_excerpts.dart create mode 100644 third_party/packages/mustache_template/example/pubspec.yaml create mode 100644 third_party/packages/mustache_template/test/example_test.dart diff --git a/third_party/packages/mustache_template/CHANGELOG.md b/third_party/packages/mustache_template/CHANGELOG.md index ed2daa26..2300e9ef 100644 --- a/third_party/packages/mustache_template/CHANGELOG.md +++ b/third_party/packages/mustache_template/CHANGELOG.md @@ -2,6 +2,7 @@ * Updates metadata for move to https://github.com/flutter/core-packages. * Updates minimum supported SDK version to Flutter 3.38/Dart 3.10. +* Adds example app demonstrating basic templates, nested paths, partials, and lambdas. ## 2.0.4 diff --git a/third_party/packages/mustache_template/README.md b/third_party/packages/mustache_template/README.md index cf4dab61..f6f3c13c 100644 --- a/third_party/packages/mustache_template/README.md +++ b/third_party/packages/mustache_template/README.md @@ -1,3 +1,5 @@ + + # Mustache templates A Dart library to parse and render [mustache templates](https://mustache.github.io/). @@ -7,29 +9,25 @@ See the [mustache manual](https://mustache.github.io/mustache.5.html) for detail This library passes all [mustache specification](https://github.com/mustache/spec/tree/master/specs) tests. ## Example usage + + ```dart -import 'package:mustache_template/mustache_template.dart'; - -main() { - var source = ''' - {{# names }} -
{{ lastname }}, {{ firstname }}
- {{/ names }} - {{^ names }} -
No names.
- {{/ names }} - {{! I am a comment. }} - '''; - - var template = Template(source, name: 'template-filename.html'); - - var output = template.renderString({'names': [ - {'firstname': 'Greg', 'lastname': 'Lowe'}, - {'firstname': 'Bob', 'lastname': 'Johnson'} - ]}); - - print(output); -} +final source = ''' +{{# names }} +
{{ lastname }}, {{ firstname }}
+{{/ names }} +{{^ names }} +
No names.
+{{/ names }} +{{! I am a comment. }} +'''; +final template = Template(source, name: 'template-filename.html'); +final output = template.renderString({ + 'names': [ + {'firstname': 'Greg', 'lastname': 'Lowe'}, + {'firstname': 'Bob', 'lastname': 'Johnson'}, + ], +}); ``` A template is parsed when it is created, after parsing it can be rendered any number of times with different values. A TemplateException is thrown if there is a problem parsing or rendering the template. @@ -53,65 +51,45 @@ By default all output from `{{variable}}` tags is html escaped, this behaviour c ## Nested paths + ```dart - var t = Template('{{ author.name }}'); - var output = template.renderString({'author': {'name': 'Greg Lowe'}}); +final template = Template('{{ author.name }}'); +final output = template.renderString({'author': {'name': 'Greg Lowe'}}); ``` ## Partials - example usage + ```dart - -var partial = Template('{{ foo }}', name: 'partial'); - -var resolver = (String name) { - if (name == 'partial-name') { // Name of partial tag. - return partial; - } +final partial = Template('{{ foo }}', name: 'partial'); +final resolver = (String name) { + if (name == 'partial-name') { + return partial; + } + return null; }; - -var t = Template('{{> partial-name }}', partialResolver: resolver); - -var output = t.renderString({'foo': 'bar'}); // bar - +final template = Template('{{> partial-name }}', partialResolver: resolver); +final output = template.renderString({'foo': 'bar'}); // bar ``` ## Lambdas - example usage + ```dart -var t = Template('{{# foo }}'); -var lambda = (_) => 'bar'; -t.renderString({'foo': lambda}); // bar -``` - -```dart -var t = Template('{{# foo }}hidden{{/ foo }}'); -var lambda = (_) => 'shown'; -t.renderString('foo': lambda); // shown -``` - -```dart -var t = Template('{{# foo }}oi{{/ foo }}'); -var lambda = (LambdaContext ctx) => '${ctx.renderString().toUpperCase()}'; -t.renderString({'foo': lambda}); // OI -``` - -```dart -var t = Template('{{# foo }}{{bar}}{{/ foo }}'); -var lambda = (LambdaContext ctx) => '${ctx.renderString().toUpperCase()}'; -t.renderString({'foo': lambda, 'bar': 'pub'}); // PUB -``` - -```dart -var t = Template('{{# foo }}{{bar}}{{/ foo }}'); -var lambda = (LambdaContext ctx) => '${ctx.renderString().toUpperCase()}'; -t.renderString({'foo': lambda, 'bar': 'pub'}); // PUB +final template = Template('{{# foo }}{{bar}}{{/ foo }}'); +final lambda = + (LambdaContext ctx) => '${ctx.renderString().toUpperCase()}'; +final output = + template.renderString({'foo': lambda, 'bar': 'pub'}); // PUB ``` In the following example `LambdaContext.renderSource(source)` re-parses the source string in the current context, this is the default behaviour in many mustache implementations. Since re-parsing the content is slow, and often not required, this library makes this step optional. + ```dart -var t = Template('{{# foo }}{{bar}}{{/ foo }}'); -var lambda = (LambdaContext ctx) => ctx.renderSource(ctx.source + ' {{cmd}}'); -t.renderString({'foo': lambda, 'bar': 'pub', 'cmd': 'build'}); // pub build -``` +final template = Template('{{# foo }}{{bar}}{{/ foo }}'); +final lambda = + (LambdaContext ctx) => ctx.renderSource(ctx.source + ' {{cmd}}'); +final output = template + .renderString({'foo': lambda, 'bar': 'pub', 'cmd': 'build'}); // pub build +``` \ No newline at end of file diff --git a/third_party/packages/mustache_template/example/lib/readme_excerpts.dart b/third_party/packages/mustache_template/example/lib/readme_excerpts.dart new file mode 100644 index 00000000..91f22811 --- /dev/null +++ b/third_party/packages/mustache_template/example/lib/readme_excerpts.dart @@ -0,0 +1,78 @@ +// ignore_for_file: avoid_print + +import 'package:mustache_template/mustache_template.dart'; + +void renderBasicTemplate() { + // #docregion basic + final source = ''' +{{# names }} +
{{ lastname }}, {{ firstname }}
+{{/ names }} +{{^ names }} +
No names.
+{{/ names }} +{{! I am a comment. }} +'''; + final template = Template(source, name: 'template-filename.html'); + final output = template.renderString({ + 'names': [ + {'firstname': 'Greg', 'lastname': 'Lowe'}, + {'firstname': 'Bob', 'lastname': 'Johnson'}, + ], + }); + // #enddocregion basic + print(output); +} + +void renderNestedPaths() { + // #docregion nested + final template = Template('{{ author.name }}'); + final output = template.renderString({'author': {'name': 'Greg Lowe'}}); + // #enddocregion nested + print(output); +} + +void renderPartials() { + // #docregion partials + final partial = Template('{{ foo }}', name: 'partial'); + final resolver = (String name) { + if (name == 'partial-name') { + return partial; + } + return null; + }; + final template = Template('{{> partial-name }}', partialResolver: resolver); + final output = template.renderString({'foo': 'bar'}); // bar + // #enddocregion partials + print(output); +} + +void renderLambdaRenderString() { + // #docregion lambda-render-string + final template = Template('{{# foo }}{{bar}}{{/ foo }}'); + final lambda = + (LambdaContext ctx) => '${ctx.renderString().toUpperCase()}'; + final output = + template.renderString({'foo': lambda, 'bar': 'pub'}); // PUB + // #enddocregion lambda-render-string + print(output); +} + +void renderLambdaRenderSource() { + // #docregion lambda-render-source + final template = Template('{{# foo }}{{bar}}{{/ foo }}'); + final lambda = + (LambdaContext ctx) => ctx.renderSource(ctx.source + ' {{cmd}}'); + final output = template + .renderString({'foo': lambda, 'bar': 'pub', 'cmd': 'build'}); // pub build + // #enddocregion lambda-render-source + print(output); +} + +void main() { + renderBasicTemplate(); + renderNestedPaths(); + renderPartials(); + renderLambdaRenderString(); + renderLambdaRenderSource(); +} \ No newline at end of file diff --git a/third_party/packages/mustache_template/example/pubspec.yaml b/third_party/packages/mustache_template/example/pubspec.yaml new file mode 100644 index 00000000..4a95d972 --- /dev/null +++ b/third_party/packages/mustache_template/example/pubspec.yaml @@ -0,0 +1,11 @@ +name: mustache_template_examples +description: Example code for mustache_template usage +version: 0.0.1 +publish_to: none + +environment: + sdk: ^3.10.0 + +dependencies: + mustache_template: + path: ../ \ No newline at end of file diff --git a/third_party/packages/mustache_template/test/example_test.dart b/third_party/packages/mustache_template/test/example_test.dart new file mode 100644 index 00000000..d9d92aa2 --- /dev/null +++ b/third_party/packages/mustache_template/test/example_test.dart @@ -0,0 +1,61 @@ +import 'package:mustache_template/mustache_template.dart'; +import 'package:test/test.dart'; + +void main() { + test('renders basic list template', () { + final source = ''' +{{# names }} +
{{ lastname }}, {{ firstname }}
+{{/ names }} +{{^ names }} +
No names.
+{{/ names }} +'''; + final template = Template(source, name: 'template-filename.html'); + final output = template.renderString({ + 'names': [ + {'firstname': 'Greg', 'lastname': 'Lowe'}, + {'firstname': 'Bob', 'lastname': 'Johnson'}, + ], + }); + expect(output, contains('Lowe, Greg')); + expect(output, contains('Johnson, Bob')); + }); + + test('renders nested paths', () { + final template = Template('{{ author.name }}'); + final output = template.renderString({'author': {'name': 'Greg Lowe'}}); + expect(output, equals('Greg Lowe')); + }); + + test('renders partials', () { + final partial = Template('{{ foo }}', name: 'partial'); + final resolver = (String name) { + if (name == 'partial-name') { + return partial; + } + return null; + }; + final template = + Template('{{> partial-name }}', partialResolver: resolver); + final output = template.renderString({'foo': 'bar'}); + expect(output, equals('bar')); + }); + + test('renders lambda using renderString', () { + final template = Template('{{# foo }}{{bar}}{{/ foo }}'); + final lambda = + (LambdaContext ctx) => '${ctx.renderString().toUpperCase()}'; + final output = template.renderString({'foo': lambda, 'bar': 'pub'}); + expect(output, equals('PUB')); + }); + + test('renders lambda using renderSource', () { + final template = Template('{{# foo }}{{bar}}{{/ foo }}'); + final lambda = + (LambdaContext ctx) => ctx.renderSource(ctx.source + ' {{cmd}}'); + final output = + template.renderString({'foo': lambda, 'bar': 'pub', 'cmd': 'build'}); + expect(output, equals('pub build')); + }); +} \ No newline at end of file From e1a97df7e20e4b006b0e4120be8951ce3f33e344 Mon Sep 17 00:00:00 2001 From: HibaChamkhi Date: Wed, 10 Jun 2026 14:23:56 +0100 Subject: [PATCH 2/4] fix formatting --- .../example/lib/readme_excerpts.dart | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/third_party/packages/mustache_template/example/lib/readme_excerpts.dart b/third_party/packages/mustache_template/example/lib/readme_excerpts.dart index 91f22811..2e0ba5a1 100644 --- a/third_party/packages/mustache_template/example/lib/readme_excerpts.dart +++ b/third_party/packages/mustache_template/example/lib/readme_excerpts.dart @@ -27,7 +27,9 @@ void renderBasicTemplate() { void renderNestedPaths() { // #docregion nested final template = Template('{{ author.name }}'); - final output = template.renderString({'author': {'name': 'Greg Lowe'}}); + final output = template.renderString({ + 'author': {'name': 'Greg Lowe'}, + }); // #enddocregion nested print(output); } @@ -50,10 +52,8 @@ void renderPartials() { void renderLambdaRenderString() { // #docregion lambda-render-string final template = Template('{{# foo }}{{bar}}{{/ foo }}'); - final lambda = - (LambdaContext ctx) => '${ctx.renderString().toUpperCase()}'; - final output = - template.renderString({'foo': lambda, 'bar': 'pub'}); // PUB + final lambda = (LambdaContext ctx) => '${ctx.renderString().toUpperCase()}'; + final output = template.renderString({'foo': lambda, 'bar': 'pub'}); // PUB // #enddocregion lambda-render-string print(output); } @@ -61,10 +61,8 @@ void renderLambdaRenderString() { void renderLambdaRenderSource() { // #docregion lambda-render-source final template = Template('{{# foo }}{{bar}}{{/ foo }}'); - final lambda = - (LambdaContext ctx) => ctx.renderSource(ctx.source + ' {{cmd}}'); - final output = template - .renderString({'foo': lambda, 'bar': 'pub', 'cmd': 'build'}); // pub build + final lambda = (LambdaContext ctx) => ctx.renderSource(ctx.source + ' {{cmd}}'); + final output = template.renderString({'foo': lambda, 'bar': 'pub', 'cmd': 'build'}); // pub build // #enddocregion lambda-render-source print(output); } @@ -75,4 +73,4 @@ void main() { renderPartials(); renderLambdaRenderString(); renderLambdaRenderSource(); -} \ No newline at end of file +} From 4e5731b1628f75637ce9a6c0e129030ccbf63a08 Mon Sep 17 00:00:00 2001 From: HibaChamkhi Date: Wed, 10 Jun 2026 14:34:19 +0100 Subject: [PATCH 3/4] fix formatting --- .../example/lib/readme_excerpts.dart | 6 +++++- .../mustache_template/test/example_test.dart | 18 ++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/third_party/packages/mustache_template/example/lib/readme_excerpts.dart b/third_party/packages/mustache_template/example/lib/readme_excerpts.dart index 2e0ba5a1..01e0fc65 100644 --- a/third_party/packages/mustache_template/example/lib/readme_excerpts.dart +++ b/third_party/packages/mustache_template/example/lib/readme_excerpts.dart @@ -51,9 +51,11 @@ void renderPartials() { void renderLambdaRenderString() { // #docregion lambda-render-string - final template = Template('{{# foo }}{{bar}}{{/ foo }}'); + final templafinal lambda = te = Template('{{# foo }}{{bar}}{{/ foo }}'); + // lambda-render-string final lambda = (LambdaContext ctx) => '${ctx.renderString().toUpperCase()}'; final output = template.renderString({'foo': lambda, 'bar': 'pub'}); // PUB + final output = template.renderString({'foo': lambda, 'bar': 'pub'}); // PUB // #enddocregion lambda-render-string print(output); } @@ -61,8 +63,10 @@ void renderLambdaRenderString() { void renderLambdaRenderSource() { // #docregion lambda-render-source final template = Template('{{# foo }}{{bar}}{{/ foo }}'); + // lambda-render-source final lambda = (LambdaContext ctx) => ctx.renderSource(ctx.source + ' {{cmd}}'); final output = template.renderString({'foo': lambda, 'bar': 'pub', 'cmd': 'build'}); // pub build + final output = template.renderString({'foo': lambda, 'bar': 'pub', 'cmd': 'build'}); // pub build // #enddocregion lambda-render-source print(output); } diff --git a/third_party/packages/mustache_template/test/example_test.dart b/third_party/packages/mustache_template/test/example_test.dart index d9d92aa2..05502f14 100644 --- a/third_party/packages/mustache_template/test/example_test.dart +++ b/third_party/packages/mustache_template/test/example_test.dart @@ -24,7 +24,9 @@ void main() { test('renders nested paths', () { final template = Template('{{ author.name }}'); - final output = template.renderString({'author': {'name': 'Greg Lowe'}}); + final output = template.renderString({ + 'author': {'name': 'Greg Lowe'}, + }); expect(output, equals('Greg Lowe')); }); @@ -36,26 +38,22 @@ void main() { } return null; }; - final template = - Template('{{> partial-name }}', partialResolver: resolver); + final template = Template('{{> partial-name }}', partialResolver: resolver); final output = template.renderString({'foo': 'bar'}); expect(output, equals('bar')); }); test('renders lambda using renderString', () { final template = Template('{{# foo }}{{bar}}{{/ foo }}'); - final lambda = - (LambdaContext ctx) => '${ctx.renderString().toUpperCase()}'; + final lambda = (LambdaContext ctx) => '${ctx.renderString().toUpperCase()}'; final output = template.renderString({'foo': lambda, 'bar': 'pub'}); expect(output, equals('PUB')); }); test('renders lambda using renderSource', () { final template = Template('{{# foo }}{{bar}}{{/ foo }}'); - final lambda = - (LambdaContext ctx) => ctx.renderSource(ctx.source + ' {{cmd}}'); - final output = - template.renderString({'foo': lambda, 'bar': 'pub', 'cmd': 'build'}); + final lambda = (LambdaContext ctx) => ctx.renderSource(ctx.source + ' {{cmd}}'); + final output = template.renderString({'foo': lambda, 'bar': 'pub', 'cmd': 'build'}); expect(output, equals('pub build')); }); -} \ No newline at end of file +} From 14b6f85bbd3bc4143cf30ce28ec26525ebfecbd4 Mon Sep 17 00:00:00 2001 From: HibaChamkhi Date: Wed, 10 Jun 2026 14:37:45 +0100 Subject: [PATCH 4/4] fix corrupted readme_excerpts.dart --- .../mustache_template/example/lib/readme_excerpts.dart | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/third_party/packages/mustache_template/example/lib/readme_excerpts.dart b/third_party/packages/mustache_template/example/lib/readme_excerpts.dart index 01e0fc65..2e0ba5a1 100644 --- a/third_party/packages/mustache_template/example/lib/readme_excerpts.dart +++ b/third_party/packages/mustache_template/example/lib/readme_excerpts.dart @@ -51,11 +51,9 @@ void renderPartials() { void renderLambdaRenderString() { // #docregion lambda-render-string - final templafinal lambda = te = Template('{{# foo }}{{bar}}{{/ foo }}'); - // lambda-render-string + final template = Template('{{# foo }}{{bar}}{{/ foo }}'); final lambda = (LambdaContext ctx) => '${ctx.renderString().toUpperCase()}'; final output = template.renderString({'foo': lambda, 'bar': 'pub'}); // PUB - final output = template.renderString({'foo': lambda, 'bar': 'pub'}); // PUB // #enddocregion lambda-render-string print(output); } @@ -63,10 +61,8 @@ void renderLambdaRenderString() { void renderLambdaRenderSource() { // #docregion lambda-render-source final template = Template('{{# foo }}{{bar}}{{/ foo }}'); - // lambda-render-source final lambda = (LambdaContext ctx) => ctx.renderSource(ctx.source + ' {{cmd}}'); final output = template.renderString({'foo': lambda, 'bar': 'pub', 'cmd': 'build'}); // pub build - final output = template.renderString({'foo': lambda, 'bar': 'pub', 'cmd': 'build'}); // pub build // #enddocregion lambda-render-source print(output); }