diff --git a/.gitignore b/.gitignore index 4b2f4de9..cb72fb0e 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,6 @@ gradlew.bat .project .classpath .settings + +# FVM Version Cache +.fvm/ \ No newline at end of file diff --git a/third_party/packages/mustache_template/README.md b/third_party/packages/mustache_template/README.md index cf4dab61..7175bda2 100644 --- a/third_party/packages/mustache_template/README.md +++ b/third_party/packages/mustache_template/README.md @@ -7,34 +7,47 @@ 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'} - ]}); +/// The main entrypoint for the example app. +void main() { + exampleUsage(); + nestedPaths(); + partialsExample(); + lambdasExample(); +} - print(output); +/// Demonstrates basic usage of mustache templates. +void exampleUsage() { + const String source = ''' + {{# names }} +
{{ lastname }}, {{ firstname }}
+ {{/ names }} + {{^ names }} +
No names.
+ {{/ names }} + {{! I am a comment. }} + '''; + + final Template 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. -The Template contstructor allows passing a name, this name will be used in error messages. When working with a number of templates, it is important to pass a name so that the error messages specify which template caused the error. +The Template constructor allows passing a name, this name will be used in error messages. When working with a number of templates, it is important to pass a name so that the error messages specify which template caused the error. By default all output from `{{variable}}` tags is html escaped, this behaviour can be changed by passing htmlEscapeValues : false to the Template constructor. You can also use a `{{{triple mustache}}}` tag, or a unescaped variable tag `{{&unescaped}}`, the output from these tags is not escaped. @@ -53,65 +66,80 @@ 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'}}); +/// Demonstrates how to access nested map properties. +void nestedPaths() { + final Template template = Template('The author is {{ author.name }}'); + final String output = template.renderString({ + 'author': {'name': 'Greg Lowe'}, + }); + print(output); +} ``` ## Partials - example usage + ```dart - -var partial = Template('{{ foo }}', name: 'partial'); - -var resolver = (String name) { - if (name == 'partial-name') { // Name of partial tag. - return partial; - } -}; - -var t = Template('{{> partial-name }}', partialResolver: resolver); - -var output = t.renderString({'foo': 'bar'}); // bar - +/// Demonstrates the usage of partials with a custom resolver. +void partialsExample() { + final Template partial = Template('{{ foo }}', name: 'partial'); + + Template? resolver(String name) { + if (name == 'partial-name') { + // Name of partial tag. + return partial; + } + return null; + } + + final Template t = Template('{{> partial-name }}', partialResolver: resolver); + + final String output = t.renderString({'foo': 'bar'}); + print(output); // 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 +/// Demonstrates various usages of lambdas, including hidden sections and lambda contexts. +void lambdasExample() { + // Simple lambda + final Template t1 = Template('{{# foo }}inner{{/ foo }}'); + Object lambda1(Object? _) => 'bar'; + print(t1.renderString({'foo': lambda1})); // bar + + // Lambda returning text for a hidden section + final Template t2 = Template('{{# foo }}hidden{{/ foo }}'); + Object lambda2(Object? _) => 'shown'; + print(t2.renderString({'foo': lambda2})); // shown + + // Lambda Context + final Template t3 = Template('{{# foo }}oi{{/ foo }}'); + Object lambda3(LambdaContext ctx) => + '${ctx.renderString().toUpperCase()}'; + print(t3.renderString({'foo': lambda3})); // OI + + // Lambda Context with variables + final Template t4 = Template('{{# foo }}{{bar}}{{/ foo }}'); + Object lambda4(LambdaContext ctx) => + '${ctx.renderString().toUpperCase()}'; + print(t4.renderString( + {'foo': lambda4, 'bar': 'pub'})); // PUB + + // Lambda Context re-parsing source + final Template t5 = Template('{{# foo }}{{bar}}{{/ foo }}'); + Object lambda5(LambdaContext ctx) => + ctx.renderSource('${ctx.source} {{cmd}}'); + print(t5.renderString({ + 'foo': lambda5, + 'bar': 'pub', + 'cmd': 'build', + })); // pub build +} ``` -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 -``` +In the last lambda 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. 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 00000000..1e7559f1 --- /dev/null +++ b/third_party/packages/mustache_template/example/lib/main.dart @@ -0,0 +1,110 @@ +// Copyright 2026 The Flutter Authors. All rights reserved. +// 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 + +// #docregion example_usage +import 'package:mustache_template/mustache_template.dart'; + +/// The main entrypoint for the example app. +void main() { + exampleUsage(); + nestedPaths(); + partialsExample(); + lambdasExample(); +} + +/// Demonstrates basic usage of mustache templates. +void exampleUsage() { + const String source = ''' + {{# names }} +
{{ lastname }}, {{ firstname }}
+ {{/ names }} + {{^ names }} +
No names.
+ {{/ names }} + {{! I am a comment. }} + '''; + + final Template template = Template(source, name: 'template-filename.html'); + + final String output = template.renderString({ + 'names': >[ + {'firstname': 'Greg', 'lastname': 'Lowe'}, + {'firstname': 'Bob', 'lastname': 'Johnson'}, + ], + }); + + print(output); +} +// #enddocregion example_usage + +// #docregion nested_paths +/// Demonstrates how to access nested map properties. +void nestedPaths() { + final Template template = Template('The author is {{ author.name }}'); + final String output = template.renderString({ + 'author': {'name': 'Greg Lowe'}, + }); + print(output); +} +// #enddocregion nested_paths + +// #docregion partials +/// Demonstrates the usage of partials with a custom resolver. +void partialsExample() { + final Template partial = Template('{{ foo }}', name: 'partial'); + + Template? resolver(String name) { + if (name == 'partial-name') { + // Name of partial tag. + return partial; + } + return null; + } + + final Template t = Template('{{> partial-name }}', partialResolver: resolver); + + final String output = t.renderString({'foo': 'bar'}); + print(output); // bar +} +// #enddocregion partials + +// #docregion lambdas +/// Demonstrates various usages of lambdas, including hidden sections and lambda contexts. +void lambdasExample() { + // Simple lambda + final Template t1 = Template('{{# foo }}inner{{/ foo }}'); + Object lambda1(Object? _) => 'bar'; + print(t1.renderString({'foo': lambda1})); // bar + + // Lambda returning text for a hidden section + final Template t2 = Template('{{# foo }}hidden{{/ foo }}'); + Object lambda2(Object? _) => 'shown'; + print(t2.renderString({'foo': lambda2})); // shown + + // Lambda Context + final Template t3 = Template('{{# foo }}oi{{/ foo }}'); + Object lambda3(LambdaContext ctx) => + '${ctx.renderString().toUpperCase()}'; + print(t3.renderString({'foo': lambda3})); // OI + + // Lambda Context with variables + final Template t4 = Template('{{# foo }}{{bar}}{{/ foo }}'); + Object lambda4(LambdaContext ctx) => + '${ctx.renderString().toUpperCase()}'; + print(t4.renderString( + {'foo': lambda4, 'bar': 'pub'})); // PUB + + // Lambda Context re-parsing source + final Template t5 = Template('{{# foo }}{{bar}}{{/ foo }}'); + Object lambda5(LambdaContext ctx) => + ctx.renderSource('${ctx.source} {{cmd}}'); + print(t5.renderString({ + 'foo': lambda5, + 'bar': 'pub', + 'cmd': 'build', + })); // pub build +} +// #enddocregion lambdas 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..4607a973 --- /dev/null +++ b/third_party/packages/mustache_template/example/pubspec.yaml @@ -0,0 +1,13 @@ +name: mustache_template_example +description: Example app for the mustache_template package. +publish_to: 'none' + +environment: + sdk: ^3.10.0 + +dependencies: + mustache_template: + path: ../ + +dev_dependencies: + lints: ^3.0.0