diff --git a/script/configs/temp_exclude_excerpt.yaml b/script/configs/temp_exclude_excerpt.yaml
index 2dd229b184cf..3d39abc136bb 100644
--- a/script/configs/temp_exclude_excerpt.yaml
+++ b/script/configs/temp_exclude_excerpt.yaml
@@ -7,6 +7,5 @@
# https://github.com/flutter/flutter/issues/102679
- espresso
- in_app_purchase/in_app_purchase
-- mustache_template
- pointer_interceptor
- quick_actions/quick_actions
diff --git a/third_party/packages/mustache_template/CHANGELOG.md b/third_party/packages/mustache_template/CHANGELOG.md
index 67f53c1a8fc9..5d58f3bb4bdd 100644
--- a/third_party/packages/mustache_template/CHANGELOG.md
+++ b/third_party/packages/mustache_template/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.0.4
+
+* Adds a runnable example app and refreshes README code samples.
+
## 2.0.3
* Updates minimum supported SDK version to Flutter 3.35/Dart 3.9.
diff --git a/third_party/packages/mustache_template/README.md b/third_party/packages/mustache_template/README.md
index 7602c2755160..469fca64a40c 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,34 @@ See the [mustache manual](http://mustache.github.com/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);
+void main() {
+ const source = '''
+{{# names }}
+ {{ lastname }}, {{ firstname }}
+{{/ names }}
+{{^ names }}
+ No names.
+{{/ names }}
+{{! I am a comment. }}
+''';
+
+ final template = Template(source, name: 'template-filename.html');
+
+ final String output = template.renderString({
+ 'names': [
+ {'firstname': 'Greg', 'lastname': 'Lowe'},
+ {'firstname': 'Bob', 'lastname': 'Johnson'},
+ ],
+ });
+
+ print(output);
}
+
```
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 +60,75 @@ 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 t = Template('{{ author.name }}');
+final output = t.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') {
+ // Name of partial tag.
+ return partial;
+ }
+ return null;
};
-var t = Template('{{> partial-name }}', partialResolver: resolver);
-
-var output = t.renderString({'foo': 'bar'}); // bar
+final t = Template('{{> partial-name }}', partialResolver: resolver);
+final output = t.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
+final t = Template('{{# foo }}{{/ foo }}');
+final lambda = (_) => 'bar';
+final output = t.renderString({'foo': lambda}); // bar
```
+
```dart
-var t = Template('{{# foo }}oi{{/ foo }}');
-var lambda = (LambdaContext ctx) => '${ctx.renderString().toUpperCase()}';
-t.renderString({'foo': lambda}); // OI
+final t = Template('{{# foo }}hidden{{/ foo }}');
+final lambda = (_) => 'shown';
+final output = t.renderString({'foo': lambda}); // shown
```
+
```dart
-var t = Template('{{# foo }}{{bar}}{{/ foo }}');
-var lambda = (LambdaContext ctx) => '${ctx.renderString().toUpperCase()}';
-t.renderString({'foo': lambda, 'bar': 'pub'}); // PUB
+final t = Template('{{# foo }}oi{{/ foo }}');
+final lambda = (LambdaContext ctx) =>
+ '${ctx.renderString().toUpperCase()}';
+final output = 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
+final t = Template('{{# foo }}{{bar}}{{/ foo }}');
+final lambda = (LambdaContext ctx) =>
+ '${ctx.renderString().toUpperCase()}';
+final output = t.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 t = Template('{{# foo }}{{bar}}{{/ foo }}');
+final lambda = (LambdaContext ctx) =>
+ ctx.renderSource('${ctx.source} {{cmd}}');
+final output = t.renderString({
+ 'foo': lambda,
+ 'bar': 'pub',
+ 'cmd': 'build',
+}); // pub build
```
diff --git a/third_party/packages/mustache_template/example/lib/main.dart b/third_party/packages/mustache_template/example/lib/main.dart
new file mode 100644
index 000000000000..e5b237e9b501
--- /dev/null
+++ b/third_party/packages/mustache_template/example/lib/main.dart
@@ -0,0 +1,56 @@
+// Copyright 2013 The Flutter Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ignore_for_file: avoid_print, prefer_function_declarations_over_variables
+
+// #docregion ExampleUsage
+import 'package:mustache_template/mustache_template.dart';
+
+void main() {
+ // #enddocregion ExampleUsage
+ print('=== Basic Template ===');
+
+ // Basic template rendering with sections and inverted sections.
+ // #docregion ExampleUsage
+ const source = '''
+{{# names }}
+ {{ lastname }}, {{ firstname }}
+{{/ names }}
+{{^ names }}
+ No names.
+{{/ names }}
+{{! I am a comment. }}
+''';
+
+ final template = Template(source, name: 'template-filename.html');
+
+ final String output = template.renderString({
+ 'names': [
+ {'firstname': 'Greg', 'lastname': 'Lowe'},
+ {'firstname': 'Bob', 'lastname': 'Johnson'},
+ ],
+ });
+
+ print(output);
+ // #enddocregion ExampleUsage
+
+ // Nested paths
+ final nested = Template('{{ author.name }}');
+ print('=== Nested Paths ===');
+ print(
+ nested.renderString({
+ 'author': {'name': 'Greg Lowe'},
+ }),
+ );
+
+ // Lambdas
+ final lambdaTemplate = Template('{{# transform }}hello{{/ transform }}');
+ final String Function(LambdaContext) lambda = (LambdaContext ctx) =>
+ ctx.renderString().toUpperCase();
+ print('=== Lambdas ===');
+ print(lambdaTemplate.renderString({'transform': lambda}));
+ // #docregion ExampleUsage
+}
+
+// #enddocregion ExampleUsage
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 000000000000..793d80186698
--- /dev/null
+++ b/third_party/packages/mustache_template/example/lib/readme_excerpts.dart
@@ -0,0 +1,93 @@
+// Copyright 2013 The Flutter Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file exists solely to host compiled excerpts for README.md, and is not
+// intended for use as an actual example application.
+
+// ignore_for_file: avoid_print, public_member_api_docs, unreachable_from_main
+// ignore_for_file: prefer_function_declarations_over_variables
+// ignore_for_file: specify_nonobvious_local_variable_types
+
+import 'package:mustache_template/mustache_template.dart';
+
+String nestedPathsExample() {
+ // #docregion NestedPaths
+ final t = Template('{{ author.name }}');
+ final output = t.renderString({
+ 'author': {'name': 'Greg Lowe'},
+ });
+ // #enddocregion NestedPaths
+ return output;
+}
+
+String partialsExample() {
+ // #docregion Partials
+ final partial = Template('{{ foo }}', name: 'partial');
+
+ final resolver = (String name) {
+ if (name == 'partial-name') {
+ // Name of partial tag.
+ return partial;
+ }
+ return null;
+ };
+
+ final t = Template('{{> partial-name }}', partialResolver: resolver);
+
+ final output = t.renderString({'foo': 'bar'}); // bar
+ // #enddocregion Partials
+ return output;
+}
+
+String lambdaSimpleExample() {
+ // #docregion LambdaSimple
+ final t = Template('{{# foo }}{{/ foo }}');
+ final lambda = (_) => 'bar';
+ final output = t.renderString({'foo': lambda}); // bar
+ // #enddocregion LambdaSimple
+ return output;
+}
+
+String lambdaShownExample() {
+ // #docregion LambdaShown
+ final t = Template('{{# foo }}hidden{{/ foo }}');
+ final lambda = (_) => 'shown';
+ final output = t.renderString({'foo': lambda}); // shown
+ // #enddocregion LambdaShown
+ return output;
+}
+
+String lambdaRenderExample() {
+ // #docregion LambdaRender
+ final t = Template('{{# foo }}oi{{/ foo }}');
+ final lambda = (LambdaContext ctx) =>
+ '${ctx.renderString().toUpperCase()}';
+ final output = t.renderString({'foo': lambda}); // OI
+ // #enddocregion LambdaRender
+ return output;
+}
+
+String lambdaRenderBarExample() {
+ // #docregion LambdaRenderBar
+ final t = Template('{{# foo }}{{bar}}{{/ foo }}');
+ final lambda = (LambdaContext ctx) =>
+ '${ctx.renderString().toUpperCase()}';
+ final output = t.renderString({'foo': lambda, 'bar': 'pub'}); // PUB
+ // #enddocregion LambdaRenderBar
+ return output;
+}
+
+String lambdaRenderSourceExample() {
+ // #docregion LambdaRenderSource
+ final t = Template('{{# foo }}{{bar}}{{/ foo }}');
+ final lambda = (LambdaContext ctx) =>
+ ctx.renderSource('${ctx.source} {{cmd}}');
+ final output = t.renderString({
+ 'foo': lambda,
+ 'bar': 'pub',
+ 'cmd': 'build',
+ }); // pub build
+ // #enddocregion LambdaRenderSource
+ return output;
+}
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 000000000000..3dcf29ef1dc0
--- /dev/null
+++ b/third_party/packages/mustache_template/example/pubspec.yaml
@@ -0,0 +1,10 @@
+name: mustache_template_example
+description: Example app for mustache_template package.
+publish_to: none
+
+environment:
+ sdk: ^3.9.0
+
+dependencies:
+ mustache_template:
+ path: ../
diff --git a/third_party/packages/mustache_template/pubspec.yaml b/third_party/packages/mustache_template/pubspec.yaml
index 264e0ee0c4d4..8a8bdeae8b94 100644
--- a/third_party/packages/mustache_template/pubspec.yaml
+++ b/third_party/packages/mustache_template/pubspec.yaml
@@ -2,7 +2,7 @@ name: mustache_template
description: A templating library that implements the Mustache template specification
repository: https://github.com/flutter/packages/tree/main/third_party/packages/mustache_template
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+mustache_template%22
-version: 2.0.3
+version: 2.0.4
environment:
sdk: ^3.9.0
diff --git a/third_party/packages/mustache_template/test/all.dart b/third_party/packages/mustache_template/test/all.dart
index 0e7d0e4cbb20..e50e87f1585a 100644
--- a/third_party/packages/mustache_template/test/all.dart
+++ b/third_party/packages/mustache_template/test/all.dart
@@ -1,8 +1,10 @@
+import 'example_test.dart' as example;
import 'mustache_specs.dart' as specs;
import 'mustache_test.dart' as test;
import 'parser_test.dart' as parser;
void main() {
+ example.main();
specs.main();
test.main();
parser.main();
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 000000000000..091c5127f64d
--- /dev/null
+++ b/third_party/packages/mustache_template/test/example_test.dart
@@ -0,0 +1,44 @@
+// ignore_for_file: avoid_relative_lib_imports
+
+import 'package:test/test.dart';
+
+import '../example/lib/main.dart' as example_app;
+import '../example/lib/readme_excerpts.dart' as readme_excerpts;
+
+void main() {
+ group('Example app', () {
+ test('example app runs without error', () {
+ expect(example_app.main, returnsNormally);
+ });
+ });
+
+ group('README excerpts', () {
+ test('nested paths example renders the nested value', () {
+ expect(readme_excerpts.nestedPathsExample(), equals('Greg Lowe'));
+ });
+
+ test('partials example renders the partial output', () {
+ expect(readme_excerpts.partialsExample(), equals('bar'));
+ });
+
+ test('simple lambda example renders the replacement text', () {
+ expect(readme_excerpts.lambdaSimpleExample(), equals('bar'));
+ });
+
+ test('lambda block example renders the alternate text', () {
+ expect(readme_excerpts.lambdaShownExample(), equals('shown'));
+ });
+
+ test('lambda render example uppercases the section body', () {
+ expect(readme_excerpts.lambdaRenderExample(), equals('OI'));
+ });
+
+ test('lambda render with context data includes the variable value', () {
+ expect(readme_excerpts.lambdaRenderBarExample(), equals('PUB'));
+ });
+
+ test('lambda renderSource example reparses in the current context', () {
+ expect(readme_excerpts.lambdaRenderSourceExample(), equals('pub build'));
+ });
+ });
+}