Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion script/configs/temp_exclude_excerpt.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 6 additions & 0 deletions third_party/packages/mustache_template/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
## 2.0.4

* Adds an `example/` app with runnable usage samples.
* Updates README examples to use excerpt-managed snippets.
* Adds unit tests for README code excerpts under `example/test/`.
* Moves excerpt sources to `example/lib/readme_excerpts.dart`.
* Fixes the simple lambda README example to use `{{ foo }}` instead of an
invalid unclosed section tag.
* Fixes a broken README link to the Mustache manual.

## 2.0.3
Expand Down
15 changes: 14 additions & 1 deletion third_party/packages/mustache_template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

A Dart library to parse and render [mustache templates](https://mustache.github.io/).

See the [mustache manual](https://mustache.github.io/mustache.5.html) for detailed usage information.
See the [mustache manual](http://mustache.github.com/mustache.5.html) for detailed usage information.

This library passes all [mustache specification](https://github.com/mustache/spec/tree/master/specs) tests.

Expand Down Expand Up @@ -46,11 +46,24 @@ By default all output from `{{variable}}` tags is html escaped, this behaviour c

* During rendering, if no map key or object member which matches the tag name is found, then a TemplateException will be thrown.

```dart
try {
Template('{{missing}}').renderString({});
} on TemplateException catch (e) {
// Strict mode (default): missing keys throw when rendering.
}
```

### Lenient mode

* Tag names may use any characters.
* During rendering, if no map key or object member which matches the tag name is found, then silently ignore and output nothing.

```dart
final t = Template('{{missing}}', lenient: true);
final String output = t.renderString({}); // ''
```

## Nested paths

```dart
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// This file hosts README code excerpts (see README.md) and is imported by the
// example runner and excerpt tests.

// ignore_for_file: public_member_api_docs

import 'package:mustache_template/mustache_template.dart';

String basicRenderExample() {
// #docregion BasicRender
var source = '''
{{# names }}
<div>{{ lastname }}, {{ firstname }}</div>
{{/ names }}
{{^ names }}
<div>No names.</div>
{{/ names }}
{{! I am a comment. }}
''';

var template = Template(source, name: 'names-template');
var output = template.renderString(<String, Object>{
'names': <Map<String, String>>[
<String, String>{'firstname': 'Greg', 'lastname': 'Lowe'},
<String, String>{'firstname': 'Bob', 'lastname': 'Johnson'},
],
});
// #enddocregion BasicRender
return output;
}

String nestedPathsExample() {
// #docregion NestedPaths
var t = Template('{{ author.name }}');
var output = t.renderString(<String, Object>{
'author': {'name': 'Greg Lowe'},
});
// #enddocregion NestedPaths
return output;
}

String partialsExample() {
// #docregion Partials
var partial = Template('{{ foo }}', name: 'partial');
Template resolver(String name) {
if (name == 'partial-name') {
return partial;
}
throw StateError('Unknown partial: $name');
}

var t = Template('{{> partial-name }}', partialResolver: resolver);
var output = t.renderString({'foo': 'bar'}); // bar
// #enddocregion Partials
return output;
}

String lambdaSimpleExample() {
// #docregion LambdaSimpleValue
var t = Template('{{ foo }}');

var lambda = (_) => 'bar';

var output = t.renderString({'foo': lambda}); // bar
// #enddocregion LambdaSimpleValue
return output;
}

String lambdaShownExample() {
// #docregion LambdaSectionReplacement
var t = Template('{{# foo }}hidden{{/ foo }}');
var lambda = (_) => 'shown';

var output = t.renderString({'foo': lambda}); // shown
// #enddocregion LambdaSectionReplacement
return output;
}

String lambdaRenderExample() {
// #docregion LambdaRenderString
var t = Template('{{# foo }}{{bar}}{{/ foo }}');
var lambda = (LambdaContext context) =>
'<b>${context.renderString().toUpperCase()}</b>';

var output = t.renderString({'foo': lambda,
'bar': 'pub',
}); // <b>PUB</b>
// #enddocregion LambdaRenderString
return output;
}

String lambdaRenderSourceExample() {
// #docregion LambdaRenderSource
var t = Template('{{# foo }}{{bar}}{{/ foo }}');
var lambda = (LambdaContext ctx) =>
'<b>${ctx.renderString().toUpperCase()}</b>';

var output = t.renderString({'foo': lambda,
'bar': 'pub',
}); // <b>PUB</b>
// #enddocregion LambdaRenderSource
return output;
}

String strictModeBehaviorExample() {
// #docregion StrictMode
try {
Template('{{missing}}').renderString({});
return 'No exception thrown (unexpected)';
} on TemplateException catch (e) {
return 'Strict mode exception: ${e.runtimeType}';
}
// #enddocregion StrictMode
}

String lenientModeBehaviorExample() {
// #docregion LenientMode
final t = Template('{{missing}}', lenient: true);
final String output = t.renderString({}); // ''
// #enddocregion LenientMode
return output;
}
15 changes: 15 additions & 0 deletions third_party/packages/mustache_template/example/main.dart
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file should probably be under example/bin/main.dart.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wouldn't show up on pub if we do that (see https://dart.dev/tools/pub/package-layout#examples). If we want a bin entrypoint it would need to be a thin wrapper around lib/main.dart.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL!

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// ignore_for_file: avoid_print

import 'package:mustache_template_example/readme_excerpts.dart';

void main() {
print(basicRenderExample());
print(nestedPathsExample());
print(partialsExample());
print(lambdaSimpleExample());
print(lambdaShownExample());
print(lambdaRenderExample());
print(lambdaRenderSourceExample());
print(strictModeBehaviorExample());
print(lenientModeBehaviorExample());
}
12 changes: 12 additions & 0 deletions third_party/packages/mustache_template/example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: mustache_template_example
publish_to: none

environment:
sdk: ^3.9.0

dependencies:
mustache_template:
path: ../

dev_dependencies:
test: ^1.16.5
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// ignore_for_file: avoid_relative_lib_imports

import 'dart:async';

import 'package:mustache_template_example/readme_excerpts.dart'
as readme_excerpts;
import 'package:test/test.dart';

import '../main.dart' as example_app;

void main() {
group('Example app', () {
test('example app runs without error', () {
expect(
() => runZoned<void>(
() => example_app.main(),
zoneSpecification: ZoneSpecification(
print: (Zone self, ZoneDelegate parent, Zone zone, String line) {},
),
),
returnsNormally,
);
});
});

group('README excerpts', () {
test('basic render example includes rendered names', () {
final String out = readme_excerpts.basicRenderExample();
expect(out, contains('Lowe, Greg'));
expect(out, contains('Johnson, Bob'));
});

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('<b>PUB</b>'));
});

test('lambda renderSource example uppercases the section body', () {
expect(
readme_excerpts.lambdaRenderSourceExample(), equals('<b>PUB</b>'));
});

test('strict mode throws for missing keys', () {
expect(
readme_excerpts.strictModeBehaviorExample(),
contains('Strict mode exception'),
);
});

test('lenient mode renders empty for missing keys', () {
expect(readme_excerpts.lenientModeBehaviorExample(), isEmpty);
});
});
}