diff --git a/.gitignore b/.gitignore index 4b2f4de9..ecc9d0ad 100644 --- a/.gitignore +++ b/.gitignore @@ -59,4 +59,4 @@ gradlew.bat .project .classpath -.settings +.settings \ No newline at end of file diff --git a/third_party/packages/mustache_template/CHANGELOG.md b/third_party/packages/mustache_template/CHANGELOG.md index ed2daa26..a52bf907 100644 --- a/third_party/packages/mustache_template/CHANGELOG.md +++ b/third_party/packages/mustache_template/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.6 + +* Adds an example app. + ## 2.0.5 * Updates metadata for move to https://github.com/flutter/core-packages. diff --git a/third_party/packages/mustache_template/README.md b/third_party/packages/mustache_template/README.md index cf4dab61..b6730979 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,34 +9,32 @@ 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 }} + +```dart + 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); -} + {{/ names }} + {{^ names }} +
No names.
+ {{/ names }} + {{! I am a comment. }} + '''; + + var template = Template(source, name: 'template-filename.html'); + + String 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. -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 +53,56 @@ 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'}}); + var template = Template('{{ author.name }}'); + String output = template.renderString({ + 'author': {'name': 'Greg Lowe'} + }); ``` ## Partials - example usage + ```dart + var partial = Template('{{ foo }}', name: 'partial'); -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); + Template? resolver(String name) { + if (name == 'partial-name') { + // Name of partial tag. + return partial; + } + return null; + } -var output = t.renderString({'foo': 'bar'}); // bar + var t = Template('{{> partial-name }}', partialResolver: resolver); + String output = t.renderString({'foo': '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 + // Simple lambda + var t1 = Template('{{# foo }}inner{{/ foo }}'); + Object lambda1(Object? _) => 'bar'; + + // Lambda returning text for a hidden section + var t2 = Template('{{# foo }}hidden{{/ foo }}'); + Object lambda2(Object? _) => 'shown'; + + // Lambda Context + var t3 = Template('{{# foo }}oi{{/ foo }}'); + Object lambda3(LambdaContext ctx) => '${ctx.renderString().toUpperCase()}'; + + // Lambda Context with variables + var t4 = Template('{{# foo }}{{bar}}{{/ foo }}'); + Object lambda4(LambdaContext ctx) => '${ctx.renderString().toUpperCase()}'; + + // Lambda Context re-parsing source + var t5 = Template('{{# foo }}{{bar}}{{/ foo }}'); + Object lambda5(LambdaContext ctx) => ctx.renderSource('${ctx.source} {{cmd}}'); ``` -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..e1c57493 --- /dev/null +++ b/third_party/packages/mustache_template/example/lib/main.dart @@ -0,0 +1,102 @@ +// 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 + +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 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); +} + +/// Demonstrates how to access nested map properties. +void nestedPaths() { + final template = Template('The author is {{ author.name }}'); + final String output = template.renderString({ + 'author': {'name': 'Greg Lowe'}, + }); + print(output); +} + +/// Demonstrates the usage of partials with a custom resolver. +void partialsExample() { + final partial = Template('{{ foo }}', name: 'partial'); + + Template? resolver(String name) { + if (name == 'partial-name') { + // Name of partial tag. + return partial; + } + return null; + } + + final t = Template('{{> partial-name }}', partialResolver: resolver); + + final String output = t.renderString({'foo': 'bar'}); + print(output); // bar +} + +/// Demonstrates various usages of lambdas, including hidden sections and lambda contexts. +void lambdasExample() { + // Simple lambda + final t1 = Template('{{# foo }}inner{{/ foo }}'); + Object lambda1(Object? _) => 'bar'; + print(t1.renderString({'foo': lambda1})); // bar + + // Lambda returning text for a hidden section + final t2 = Template('{{# foo }}hidden{{/ foo }}'); + Object lambda2(Object? _) => 'shown'; + print(t2.renderString({'foo': lambda2})); // shown + + // Lambda Context + final t3 = Template('{{# foo }}oi{{/ foo }}'); + Object lambda3(LambdaContext ctx) => + '${ctx.renderString().toUpperCase()}'; + print(t3.renderString({'foo': lambda3})); // OI + + // Lambda Context with variables + final 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 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 +} 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..19ca3063 --- /dev/null +++ b/third_party/packages/mustache_template/example/lib/readme_excerpts.dart @@ -0,0 +1,116 @@ +// 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. + +// 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 +// ignore_for_file: omit_local_variable_types +// ignore_for_file: strict_raw_type +// ignore_for_file: prefer_final_locals + +import 'package:mustache_template/mustache_template.dart'; + +/// Example for basic usage of a mustache template. +void exampleUsageSnippet() { + // #docregion example_usage + var source = ''' + {{# names }} +
{{ lastname }}, {{ firstname }}
+ {{/ names }} + {{^ names }} +
No names.
+ {{/ names }} + {{! I am a comment. }} + '''; + + var template = Template(source, name: 'template-filename.html'); + + String output = template.renderString({ + 'names': >[ + {'firstname': 'Greg', 'lastname': 'Lowe'}, + {'firstname': 'Bob', 'lastname': 'Johnson'} + ] + }); + // #enddocregion example_usage + + print(output); +} + +/// Example for rendering nested paths in a template. +void nestedPathsSnippet() { + // #docregion nested_paths + var template = Template('{{ author.name }}'); + String output = template.renderString({ + 'author': {'name': 'Greg Lowe'} + }); + // #enddocregion nested_paths + print(output); +} + +/// Example for using partials. +void partialsSnippet() { + // #docregion partials + var partial = Template('{{ foo }}', name: 'partial'); + + Template? resolver(String name) { + if (name == 'partial-name') { + // Name of partial tag. + return partial; + } + return null; + } + + var t = Template('{{> partial-name }}', partialResolver: resolver); + + String output = t.renderString({'foo': 'bar'}); + // #enddocregion partials + print(output); // bar +} + +/// Example for using lambdas in a template. +void lambdasSnippet() { + // #docregion lambdas + // Simple lambda + var t1 = Template('{{# foo }}inner{{/ foo }}'); + Object lambda1(Object? _) => 'bar'; + // #enddocregion lambdas + print(t1.renderString({'foo': lambda1})); // bar + + // #docregion lambdas + // Lambda returning text for a hidden section + var t2 = Template('{{# foo }}hidden{{/ foo }}'); + Object lambda2(Object? _) => 'shown'; + // #enddocregion lambdas + print(t2.renderString({'foo': lambda2})); // shown + + // #docregion lambdas + // Lambda Context + var t3 = Template('{{# foo }}oi{{/ foo }}'); + Object lambda3(LambdaContext ctx) => + '${ctx.renderString().toUpperCase()}'; + // #enddocregion lambdas + print(t3.renderString({'foo': lambda3})); // OI + + // #docregion lambdas + // Lambda Context with variables + var t4 = Template('{{# foo }}{{bar}}{{/ foo }}'); + Object lambda4(LambdaContext ctx) => + '${ctx.renderString().toUpperCase()}'; + // #enddocregion lambdas + print(t4.renderString( + {'foo': lambda4, 'bar': 'pub'})); // PUB + + // #docregion lambdas + // Lambda Context re-parsing source + var t5 = Template('{{# foo }}{{bar}}{{/ foo }}'); + Object lambda5(LambdaContext ctx) => + ctx.renderSource('${ctx.source} {{cmd}}'); + // #enddocregion lambdas + print(t5.renderString({ + 'foo': lambda5, + 'bar': 'pub', + 'cmd': 'build' + })); // pub build +} 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..404141e4 --- /dev/null +++ b/third_party/packages/mustache_template/example/pubspec.yaml @@ -0,0 +1,11 @@ +name: mustache_template_example +description: Example app for the mustache_template package. +publish_to: 'none' + +environment: + sdk: ^3.10.0 + +dependencies: + mustache_template: + path: ../ + diff --git a/third_party/packages/mustache_template/lib/src/lambda_context.dart b/third_party/packages/mustache_template/lib/src/lambda_context.dart index 18136377..3dc54e06 100644 --- a/third_party/packages/mustache_template/lib/src/lambda_context.dart +++ b/third_party/packages/mustache_template/lib/src/lambda_context.dart @@ -26,14 +26,16 @@ class LambdaContext implements m.LambdaContext { } TemplateException _error(String msg) { - return TemplateException(msg, _renderer.templateName, _renderer.source, _node.start); + return TemplateException( + msg, _renderer.templateName, _renderer.source, _node.start); } @override String renderString({Object? value}) { _checkClosed(); if (_node is! SectionNode) { - throw _error('LambdaContext.renderString() can only be called on section tags.'); + throw _error( + 'LambdaContext.renderString() can only be called on section tags.'); } final sink = StringBuffer(); _renderSubtree(sink, value); @@ -53,7 +55,8 @@ class LambdaContext implements m.LambdaContext { void render({Object? value}) { _checkClosed(); if (_node is! SectionNode) { - throw _error('LambdaContext.render() can only be called on section tags.'); + throw _error( + 'LambdaContext.render() can only be called on section tags.'); } _renderSubtree(_renderer.sink, value); } diff --git a/third_party/packages/mustache_template/lib/src/node.dart b/third_party/packages/mustache_template/lib/src/node.dart index a6a208c2..b5961eeb 100644 --- a/third_party/packages/mustache_template/lib/src/node.dart +++ b/third_party/packages/mustache_template/lib/src/node.dart @@ -39,7 +39,8 @@ class TextNode extends Node { } class VariableNode extends Node { - VariableNode(this.name, int start, int end, {this.escape = true}) : super(start, end); + VariableNode(this.name, int start, int end, {this.escape = true}) + : super(start, end); final String name; final bool escape; @@ -52,9 +53,10 @@ class VariableNode extends Node { } class SectionNode extends Node { - SectionNode(this.name, int start, int end, this.delimiters, {this.inverse = false}) - : contentStart = end, - super(start, end); + SectionNode(this.name, int start, int end, this.delimiters, + {this.inverse = false}) + : contentStart = end, + super(start, end); final String name; final String delimiters; diff --git a/third_party/packages/mustache_template/lib/src/parser.dart b/third_party/packages/mustache_template/lib/src/parser.dart index e92378e6..c24dff2f 100644 --- a/third_party/packages/mustache_template/lib/src/parser.dart +++ b/third_party/packages/mustache_template/lib/src/parser.dart @@ -6,7 +6,8 @@ import 'scanner.dart'; import 'template_exception.dart'; import 'token.dart'; -List parse(String source, bool lenient, String? templateName, String delimiters) { +List parse( + String source, bool lenient, String? templateName, String delimiters) { final parser = Parser(source, templateName, delimiters, lenient: lenient); return parser.parse(); } @@ -35,12 +36,13 @@ class TagType { } class Parser { - Parser(String source, String? templateName, String delimiters, {bool lenient = false}) - : _source = source, - _templateName = templateName, - _delimiters = delimiters, - _lenient = lenient, - _scanner = Scanner(source, templateName, delimiters); + Parser(String source, String? templateName, String delimiters, + {bool lenient = false}) + : _source = source, + _templateName = templateName, + _delimiters = delimiters, + _lenient = lenient, + _scanner = Scanner(source, templateName, delimiters); final String _source; final bool _lenient; @@ -137,7 +139,8 @@ class Parser { return token != null && token.type == type ? _read() : null; } - TemplateException _errorEof() => _error('Unexpected end of input.', _source.length - 1); + TemplateException _errorEof() => + _error('Unexpected end of input.', _source.length - 1); TemplateException _error(String msg, int offset) => TemplateException(msg, _templateName, _source, offset); @@ -227,11 +230,14 @@ class Parser { // standalone line. while (_peek() != null) { _readIf(TokenType.lineEnd, eofOk: true); - final Token? precedingWhitespace = _readIf(TokenType.whitespace, eofOk: true); - final String indent = precedingWhitespace == null ? '' : precedingWhitespace.value; + final Token? precedingWhitespace = + _readIf(TokenType.whitespace, eofOk: true); + final String indent = + precedingWhitespace == null ? '' : precedingWhitespace.value; final Tag? tag = _readTag(); final Node? tagNode = _createNodeFromTag(tag, partialIndent: indent); - final Token? followingWhitespace = _readIf(TokenType.whitespace, eofOk: true); + final Token? followingWhitespace = + _readIf(TokenType.whitespace, eofOk: true); const standaloneTypes = [ TagType.openSection, @@ -281,7 +287,9 @@ class Parser { // If EOF or any another token then return null. Tag? _readTag() { final Token? t = _peek(); - if (t == null || (t.type != TokenType.changeDelimiter && t.type != TokenType.openDelimiter)) { + if (t == null || + (t.type != TokenType.changeDelimiter && + t.type != TokenType.openDelimiter)) { return null; } else if (t.type == TokenType.changeDelimiter) { _read(); @@ -318,7 +326,9 @@ class Parser { // TODOsplit up names here instead of during render. // Also check that they are valid token types. final list = []; - for (Token? t = _peek(); t != null && t.type != TokenType.closeDelimiter; t = _peek()) { + for (Token? t = _peek(); + t != null && t.type != TokenType.closeDelimiter; + t = _peek()) { _read(); list.add(t); } @@ -363,7 +373,8 @@ class Parser { case TagType.openSection: case TagType.openInverseSection: final inverse = tag.type == TagType.openInverseSection; - node = SectionNode(tag.name, tag.start, tag.end, _currentDelimiters, inverse: inverse); + node = SectionNode(tag.name, tag.start, tag.end, _currentDelimiters, + inverse: inverse); case TagType.variable: case TagType.unescapedVariable: diff --git a/third_party/packages/mustache_template/lib/src/renderer.dart b/third_party/packages/mustache_template/lib/src/renderer.dart index 2226bf16..b100df77 100644 --- a/third_party/packages/mustache_template/lib/src/renderer.dart +++ b/third_party/packages/mustache_template/lib/src/renderer.dart @@ -23,40 +23,40 @@ class Renderer extends Visitor { ) : _stack = List.from(stack); Renderer.partial(Renderer ctx, Template partial, String indent) - : this( - ctx.sink, - ctx._stack, - ctx.lenient, - ctx.htmlEscapeValues, - ctx.partialResolver, - ctx.templateName, - ctx.indent + indent, - partial.source, - ); + : this( + ctx.sink, + ctx._stack, + ctx.lenient, + ctx.htmlEscapeValues, + ctx.partialResolver, + ctx.templateName, + ctx.indent + indent, + partial.source, + ); Renderer.subtree(Renderer ctx, StringSink sink) - : this( - sink, - ctx._stack, - ctx.lenient, - ctx.htmlEscapeValues, - ctx.partialResolver, - ctx.templateName, - ctx.indent, - ctx.source, - ); + : this( + sink, + ctx._stack, + ctx.lenient, + ctx.htmlEscapeValues, + ctx.partialResolver, + ctx.templateName, + ctx.indent, + ctx.source, + ); Renderer.lambda(Renderer ctx, String source, String indent, StringSink sink) - : this( - sink, - ctx._stack, - ctx.lenient, - ctx.htmlEscapeValues, - ctx.partialResolver, - ctx.templateName, - ctx.indent + indent, - source, - ); + : this( + sink, + ctx._stack, + ctx.lenient, + ctx.htmlEscapeValues, + ctx.partialResolver, + ctx.templateName, + ctx.indent + indent, + source, + ); final StringSink sink; final List _stack; @@ -195,7 +195,8 @@ class Renderer extends Visitor { if (lenient) { _renderWithValue(node, null); } else { - throw error('Value was missing for inverse section: ${node.name}.', node); + throw error( + 'Value was missing for inverse section: ${node.name}.', node); } } else if (value is Function) { // Do nothing. @@ -295,7 +296,12 @@ class Renderer extends Visitor { var startIndex = 0; var i = 0; for (final int c in s.runes) { - if (c == _AMP || c == _LT || c == _GT || c == _QUOTE || c == _APOS || c == _FORWARD_SLASH) { + if (c == _AMP || + c == _LT || + c == _GT || + c == _QUOTE || + c == _APOS || + c == _FORWARD_SLASH) { buffer.write(s.substring(startIndex, i)); buffer.write(_htmlEscapeMap[c]); startIndex = i + 1; diff --git a/third_party/packages/mustache_template/lib/src/scanner.dart b/third_party/packages/mustache_template/lib/src/scanner.dart index 00eabe77..1415781b 100644 --- a/third_party/packages/mustache_template/lib/src/scanner.dart +++ b/third_party/packages/mustache_template/lib/src/scanner.dart @@ -6,8 +6,8 @@ import 'token.dart'; class Scanner { Scanner(String source, this._templateName, String? delimiters) - : _source = source, - _itr = source.runes.iterator { + : _source = source, + _itr = source.runes.iterator { if (source == '') { _c = _EOF; } else { @@ -27,7 +27,8 @@ class Scanner { _closeDelimiterInner = delimiters.codeUnits[3]; _closeDelimiter = delimiters.codeUnits[4]; } else { - throw TemplateException('Invalid delimiter string $delimiters', null, null, null); + throw TemplateException( + 'Invalid delimiter string $delimiters', null, null, null); } } @@ -133,7 +134,8 @@ class Scanner { final int c = _read(); if (c == _EOF) { - throw TemplateException('Unexpected end of input', _templateName, _source, _offset - 1); + throw TemplateException( + 'Unexpected end of input', _templateName, _source, _offset - 1); } if (c != expectedCharCode) { throw TemplateException( @@ -150,7 +152,8 @@ class Scanner { void _append(TokenType type, String value, int start, int end) => _tokens.add(Token(type, value, start, end)); - bool _isWhitespace(int c) => const [_SPACE, _TAB, _NEWLINE, _RETURN].contains(c); + bool _isWhitespace(int c) => + const [_SPACE, _TAB, _NEWLINE, _RETURN].contains(c); // Scan text. This adds text tokens, line end tokens, and whitespace // tokens for whitespace at the beginning of a line. This is because the diff --git a/third_party/packages/mustache_template/lib/src/template.dart b/third_party/packages/mustache_template/lib/src/template.dart index 4da713a0..aff8457e 100644 --- a/third_party/packages/mustache_template/lib/src/template.dart +++ b/third_party/packages/mustache_template/lib/src/template.dart @@ -14,11 +14,11 @@ class Template implements m.Template { String? name, m.PartialResolver? partialResolver, String delimiters = '{{ }}', - }) : _nodes = parser.parse(source, lenient, name, delimiters), - _lenient = lenient, - _htmlEscapeValues = htmlEscapeValues, - _name = name, - _partialResolver = partialResolver; + }) : _nodes = parser.parse(source, lenient, name, delimiters), + _lenient = lenient, + _htmlEscapeValues = htmlEscapeValues, + _name = name, + _partialResolver = partialResolver; @override final String source; diff --git a/third_party/packages/mustache_template/lib/src/template_exception.dart b/third_party/packages/mustache_template/lib/src/template_exception.dart index 35f16ddd..2789676f 100644 --- a/third_party/packages/mustache_template/lib/src/template_exception.dart +++ b/third_party/packages/mustache_template/lib/src/template_exception.dart @@ -57,7 +57,9 @@ class TemplateException implements m.TemplateException { } _isUpdated = true; - if (source == null || offset == null || (offset! < 0 || offset! > source!.length)) { + if (source == null || + offset == null || + (offset! < 0 || offset! > source!.length)) { return; } diff --git a/third_party/packages/mustache_template/pubspec.yaml b/third_party/packages/mustache_template/pubspec.yaml index ebc4ca9d..f73bbfd5 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/core-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.5 +version: 2.0.6 environment: sdk: ^3.10.0 diff --git a/third_party/packages/mustache_template/test/feature_test.dart b/third_party/packages/mustache_template/test/feature_test.dart index 3ba8937e..3d7dcee6 100644 --- a/third_party/packages/mustache_template/test/feature_test.dart +++ b/third_party/packages/mustache_template/test/feature_test.dart @@ -7,26 +7,31 @@ const String BAD_TAG_NAME = 'Unless in lenient mode, tags may only contain'; const String VALUE_MISSING = 'Value was missing'; const String UNCLOSED_TAG = 'Unclosed tag'; -Template parse(String source, {bool lenient = false}) => Template(source, lenient: lenient); +Template parse(String source, {bool lenient = false}) => + Template(source, lenient: lenient); void main() { group('Basic', () { test('Variable', () { - final String output = parse('_{{var}}_').renderString({'var': 'bob'}); + final String output = + parse('_{{var}}_').renderString({'var': 'bob'}); expect(output, equals('_bob_')); }); test('Comment', () { - final String output = parse('_{{! i am a\n comment ! }}_').renderString({}); + final String output = parse('_{{! i am a\n comment ! }}_') + .renderString({}); expect(output, equals('__')); }); test('Emoji', () { - final String output = parse('Hello! 🖖👍🏽\nBye! 🏳️‍🌈').renderString({}); + final String output = parse('Hello! 🖖👍🏽\nBye! 🏳️‍🌈') + .renderString({}); expect(output, equals('Hello! 🖖👍🏽\nBye! 🏳️‍🌈')); }); }); group('Section', () { test('Map', () { - final String output = parse('{{#section}}_{{var}}_{{/section}}').renderString( + final String output = + parse('{{#section}}_{{var}}_{{/section}}').renderString( >{ 'section': {'var': 'bob'}, }, @@ -34,7 +39,8 @@ void main() { expect(output, equals('_bob_')); }); test('List', () { - final String output = parse('{{#section}}_{{var}}_{{/section}}').renderString( + final String output = + parse('{{#section}}_{{var}}_{{/section}}').renderString( >>{ 'section': >[ {'var': 'bob'}, @@ -57,7 +63,8 @@ void main() { expect(output, equals('')); }); test('Invalid value', () { - final Exception? ex = renderFail('{{#section}}_{{var}}_{{/section}}', { + final Exception? ex = + renderFail('{{#section}}_{{var}}_{{/section}}', { 'section': 42, }); if (ex is TemplateException) { @@ -82,66 +89,73 @@ void main() { }); test('Nested', () { - final String output = - parse( - '{{#section}}.{{var}}.{{#nested}}_{{nestedvar}}_{{/nested}}.{{/section}}', - ).renderString(>{ - 'section': { - 'var': 'bob', - 'nested': >[ - {'nestedvar': 'jim'}, - {'nestedvar': 'sally'}, - ], - }, - }); + final String output = parse( + '{{#section}}.{{var}}.{{#nested}}_{{nestedvar}}_{{/nested}}.{{/section}}', + ).renderString(>{ + 'section': { + 'var': 'bob', + 'nested': >[ + {'nestedvar': 'jim'}, + {'nestedvar': 'sally'}, + ], + }, + }); expect(output, equals('.bob._jim__sally_.')); }); test('Whitespace in section tags', () { expect( - parse('{{#foo.bar}}oi{{/foo.bar}}').renderString(>{ + parse('{{#foo.bar}}oi{{/foo.bar}}') + .renderString(>{ 'foo': {'bar': true}, }), equals('oi'), ); expect( - parse('{{# foo.bar}}oi{{/foo.bar}}').renderString(>{ + parse('{{# foo.bar}}oi{{/foo.bar}}') + .renderString(>{ 'foo': {'bar': true}, }), equals('oi'), ); expect( - parse('{{#foo.bar }}oi{{/foo.bar}}').renderString(>{ + parse('{{#foo.bar }}oi{{/foo.bar}}') + .renderString(>{ 'foo': {'bar': true}, }), equals('oi'), ); expect( - parse('{{# foo.bar }}oi{{/foo.bar}}').renderString(>{ + parse('{{# foo.bar }}oi{{/foo.bar}}') + .renderString(>{ 'foo': {'bar': true}, }), equals('oi'), ); expect( - parse('{{#foo.bar}}oi{{/ foo.bar}}').renderString(>{ + parse('{{#foo.bar}}oi{{/ foo.bar}}') + .renderString(>{ 'foo': {'bar': true}, }), equals('oi'), ); expect( - parse('{{#foo.bar}}oi{{/foo.bar }}').renderString(>{ + parse('{{#foo.bar}}oi{{/foo.bar }}') + .renderString(>{ 'foo': {'bar': true}, }), equals('oi'), ); expect( - parse('{{#foo.bar}}oi{{/ foo.bar }}').renderString(>{ + parse('{{#foo.bar}}oi{{/ foo.bar }}') + .renderString(>{ 'foo': {'bar': true}, }), equals('oi'), ); expect( - parse('{{# foo.bar }}oi{{/ foo.bar }}').renderString(>{ + parse('{{# foo.bar }}oi{{/ foo.bar }}') + .renderString(>{ 'foo': {'bar': true}, }), equals('oi'), @@ -176,30 +190,40 @@ void main() { }); test('Odd whitespace in tags', () { - void render(String source, dynamic values, dynamic output) => - expect(parse(source, lenient: true).renderString(values), equals(output)); + void render(String source, dynamic values, dynamic output) => expect( + parse(source, lenient: true).renderString(values), equals(output)); render('{{\t# foo}}oi{{\n/foo}}', {'foo': true}, 'oi'); - render('{{ # # foo }} {{ oi }} {{ / # foo }}', >>{ - '# foo': >[ - {'oi': 'OI!'}, - ], - }, ' OI! '); - - render('{{ #foo }} {{ oi }} {{ /foo }}', >>{ - 'foo': >[ - {'oi': 'OI!'}, - ], - }, ' OI! '); - - render('{{\t#foo }} {{ oi }} {{ /foo }}', >>{ - 'foo': >[ - {'oi': 'OI!'}, - ], - }, ' OI! '); + render( + '{{ # # foo }} {{ oi }} {{ / # foo }}', + >>{ + '# foo': >[ + {'oi': 'OI!'}, + ], + }, + ' OI! '); + + render( + '{{ #foo }} {{ oi }} {{ /foo }}', + >>{ + 'foo': >[ + {'oi': 'OI!'}, + ], + }, + ' OI! '); + + render( + '{{\t#foo }} {{ oi }} {{ /foo }}', + >>{ + 'foo': >[ + {'oi': 'OI!'}, + ], + }, + ' OI! '); - render('{{{ #foo }}} {{{ /foo }}}', {'#foo': 1, '/foo': 2}, '1 2'); + render('{{{ #foo }}} {{{ /foo }}}', {'#foo': 1, '/foo': 2}, + '1 2'); // Invalid - I'm ok with that for now. // render( @@ -217,16 +241,21 @@ void main() { }); test('Sigils in tag names in lenient mode', () { - void render(String source, dynamic values, dynamic output) => - expect(parse(source, lenient: true).renderString(values), equals(output)); + void render(String source, dynamic values, dynamic output) => expect( + parse(source, lenient: true).renderString(values), equals(output)); // Even in lenient mode, tag names may not be a single sigil // character. - expect(() => parse('{{#}}', lenient: true), throwsA(isA())); - expect(() => parse('{{>}}', lenient: true), throwsA(isA())); - expect(() => parse('{{&}}', lenient: true), throwsA(isA())); - expect(() => parse('{{/}}', lenient: true), throwsA(isA())); - expect(() => parse('{{^}}', lenient: true), throwsA(isA())); + expect(() => parse('{{#}}', lenient: true), + throwsA(isA())); + expect(() => parse('{{>}}', lenient: true), + throwsA(isA())); + expect(() => parse('{{&}}', lenient: true), + throwsA(isA())); + expect(() => parse('{{/}}', lenient: true), + throwsA(isA())); + expect(() => parse('{{^}}', lenient: true), + throwsA(isA())); // >a means 'a partial named "a"', not a variable named ">a", // and in lenient mode the missing partial should fail silently @@ -256,7 +285,8 @@ void main() { group('Inverse Section', () { test('Map', () { - final String output = parse('{{^section}}_{{var}}_{{/section}}').renderString( + final String output = + parse('{{^section}}_{{var}}_{{/section}}').renderString( >{ 'section': {'var': 'bob'}, }, @@ -264,7 +294,8 @@ void main() { expect(output, equals('')); }); test('List', () { - final String output = parse('{{^section}}_{{var}}_{{/section}}').renderString( + final String output = + parse('{{^section}}_{{var}}_{{/section}}').renderString( >>{ 'section': >[ {'var': 'bob'}, @@ -287,11 +318,13 @@ void main() { expect(output, equals('_ok_')); }); test('Invalid value', () { - final Exception? ex = renderFail('{{^section}}_{{var}}_{{/section}}', { + final Exception? ex = + renderFail('{{^section}}_{{var}}_{{/section}}', { 'section': 42, }); expect(ex is TemplateException, isTrue); - expect((ex! as TemplateException).message, startsWith(BAD_VALUE_INV_SECTION)); + expect((ex! as TemplateException).message, + startsWith(BAD_VALUE_INV_SECTION)); }); test('Invalid value - lenient mode', () { final String output = parse( @@ -310,42 +343,50 @@ void main() { group('Html escape', () { test('Escape at start', () { - final String output = parse('_{{var}}_').renderString({'var': '&.'}); + final String output = + parse('_{{var}}_').renderString({'var': '&.'}); expect(output, equals('_&._')); }); test('Escape at end', () { - final String output = parse('_{{var}}_').renderString({'var': '.&'}); + final String output = + parse('_{{var}}_').renderString({'var': '.&'}); expect(output, equals('_.&_')); }); test('&', () { - final String output = parse('_{{var}}_').renderString({'var': '&'}); + final String output = + parse('_{{var}}_').renderString({'var': '&'}); expect(output, equals('_&_')); }); test('<', () { - final String output = parse('_{{var}}_').renderString({'var': '<'}); + final String output = + parse('_{{var}}_').renderString({'var': '<'}); expect(output, equals('_<_')); }); test('>', () { - final String output = parse('_{{var}}_').renderString({'var': '>'}); + final String output = + parse('_{{var}}_').renderString({'var': '>'}); expect(output, equals('_>_')); }); test('"', () { - final String output = parse('_{{var}}_').renderString({'var': '"'}); + final String output = + parse('_{{var}}_').renderString({'var': '"'}); expect(output, equals('_"_')); }); test("'", () { - final String output = parse('_{{var}}_').renderString({'var': "'"}); + final String output = + parse('_{{var}}_').renderString({'var': "'"}); expect(output, equals('_'_')); }); test('/', () { - final String output = parse('_{{var}}_').renderString({'var': '/'}); + final String output = + parse('_{{var}}_').renderString({'var': '/'}); expect(output, equals('_/_')); }); }); @@ -419,23 +460,27 @@ void main() { group('Lenient', () { test('Odd section name', () { - final String output = parse(r'{{#section$%$^%}}_{{var}}_{{/section$%$^%}}', lenient: true) - .renderString(>{ - r'section$%$^%': {'var': 'bob'}, - }); + final String output = + parse(r'{{#section$%$^%}}_{{var}}_{{/section$%$^%}}', lenient: true) + .renderString(>{ + r'section$%$^%': {'var': 'bob'}, + }); expect(output, equals('_bob_')); }); test('Odd variable name', () { - final String output = parse(r'{{#section}}_{{var$%$^%}}_{{/section}}', lenient: true) - .renderString(>{ - 'section': {r'var$%$^%': 'bob'}, - }); + final String output = + parse(r'{{#section}}_{{var$%$^%}}_{{/section}}', lenient: true) + .renderString(>{ + 'section': {r'var$%$^%': 'bob'}, + }); expect(output, equals('_bob_')); }); test('Null variable', () { - final String output = parse(r'{{#section}}_{{var}}_{{/section}}', lenient: true).renderString( + final String output = + parse(r'{{#section}}_{{var}}_{{/section}}', lenient: true) + .renderString( >{ 'section': {'var': null}, }, @@ -454,11 +499,13 @@ void main() { group('Escape tags', () { test('{{{ ... }}}', () { - final String output = parse('{{{blah}}}').renderString({'blah': '&'}); + final String output = + parse('{{{blah}}}').renderString({'blah': '&'}); expect(output, equals('&')); }); test('{{& ... }}', () { - final String output = parse('{{{blah}}}').renderString({'blah': '&'}); + final String output = + parse('{{{blah}}}').renderString({'blah': '&'}); expect(output, equals('&')); }); }); @@ -536,7 +583,10 @@ void main() { {'content': 'Y', 'nodes': []}, ], }, - {'root': '{{>node}}', 'node': '{{content}}<{{#nodes}}{{>node}}{{/nodes}}>'}, + { + 'root': '{{>node}}', + 'node': '{{content}}<{{#nodes}}{{>node}}{{/nodes}}>' + }, 'root', lenient: true, ); @@ -556,7 +606,10 @@ void main() { test('standalone indentation', () { final String output = partialTest( {'content': '<\n->'}, - {'root': '\\\n {{>partial}}\n/\n', 'partial': '|\n{{{content}}}\n|\n'}, + { + 'root': '\\\n {{>partial}}\n/\n', + 'partial': '|\n{{{content}}}\n|\n' + }, 'root', lenient: true, ); @@ -565,15 +618,24 @@ void main() { }); group('Lambdas', () { - void lambdaTest({required String template, dynamic lambda, dynamic output}) => - expect(parse(template).renderString({'lambda': lambda}), equals(output)); + void lambdaTest( + {required String template, dynamic lambda, dynamic output}) => + expect( + parse(template).renderString({'lambda': lambda}), + equals(output)); test('basic', () { - lambdaTest(template: 'Hello, {{lambda}}!', lambda: (_) => 'world', output: 'Hello, world!'); + lambdaTest( + template: 'Hello, {{lambda}}!', + lambda: (_) => 'world', + output: 'Hello, world!'); }); test('escaping', () { - lambdaTest(template: '<{{lambda}}{{{lambda}}}', lambda: (_) => '>', output: '<>>'); + lambdaTest( + template: '<{{lambda}}{{{lambda}}}', + lambda: (_) => '>', + output: '<>>'); }); test('sections', () { @@ -586,7 +648,10 @@ void main() { test('inverted sections truthy', () { const template = '<{{^lambda}}{{static}}{{/lambda}}>'; - final values = {'lambda': (_) => false, 'static': 'static'}; + final values = { + 'lambda': (_) => false, + 'static': 'static' + }; const output = '<>'; expect(parse(template).renderString(values), equals(output)); }); @@ -629,7 +694,8 @@ void main() { //function() { return "|planet| => {{planet}}" } final values = { 'planet': 'world', - 'lambda': (LambdaContext ctx) => ctx.renderSource('|planet| => {{planet}}'), + 'lambda': (LambdaContext ctx) => + ctx.renderSource('|planet| => {{planet}}'), }; const output = 'Hello, (|planet| => world)!'; @@ -668,7 +734,10 @@ void main() { test('LambdaContext.lookup closed', () { final t = Template('{{ foo }}'); LambdaContext? lc2; - t.renderString({'foo': (LambdaContext lc) => lc2 = lc, 'bar': 'jim'}); + t.renderString({ + 'foo': (LambdaContext lc) => lc2 = lc, + 'bar': 'jim' + }); expect(lc2, isNotNull); expect(() => lc2?.lookup('foo'), throwsException); }); @@ -784,7 +853,8 @@ void main() { const template = '<{{#markdown}}{{content}}{{/markdown}}>'; final values = { 'markdown': (LambdaContext ctx) { - return ctx.renderSource(ctx.source, value: {'content': 'oi!'}); + return ctx.renderSource(ctx.source, + value: {'content': 'oi!'}); }, }; const output = ''; @@ -794,7 +864,8 @@ void main() { test('LambdaContext renderString on non-section throws', () { final t = Template('{{ foo }}'); expect( - () => t.renderString({'foo': (LambdaContext lc) => lc.renderString()}), + () => t.renderString( + {'foo': (LambdaContext lc) => lc.renderString()}), throwsA(isA()), ); }); @@ -823,7 +894,8 @@ Exception? renderFail(String source, Object values) { } } -void expectFail(Exception? ex, int? line, int? column, [String? msgStartsWith]) { +void expectFail(Exception? ex, int? line, int? column, + [String? msgStartsWith]) { if (ex is! TemplateException) { fail('Unexpected type: $ex'); } diff --git a/third_party/packages/mustache_template/test/mustache_specs.dart b/third_party/packages/mustache_template/test/mustache_specs.dart index 4d7bc5c6..5f0902c9 100644 --- a/third_party/packages/mustache_template/test/mustache_specs.dart +++ b/third_party/packages/mustache_template/test/mustache_specs.dart @@ -10,7 +10,8 @@ import 'package:test/test.dart'; import 'specs/specs.dart'; -String render(String source, dynamic values, {required String? Function(String) partial}) { +String render(String source, dynamic values, + {required String? Function(String) partial}) { late Template? Function(String) resolver; resolver = (String name) { final String? source = partial(name); @@ -32,10 +33,10 @@ void defineTests(List unsupportedSpecs) { } void _defineGroupFromFile(String filename, String text) { - final Map jsondata = (json.decode(text) as Map) - .cast(); - final List> tests = (jsondata['tests']! as List) - .cast>(); + final Map jsondata = + (json.decode(text) as Map).cast(); + final List> tests = + (jsondata['tests']! as List).cast>(); filename = filename.substring(filename.lastIndexOf('/') + 1); group('Specs of $filename', () { for (final t in tests) { @@ -44,8 +45,10 @@ void _defineGroupFromFile(String filename, String text) { testDescription.write(t['desc']); final template = t['template']! as String; final Object? data = t['data']; - final String templateOneline = template.replaceAll('\n', r'\n').replaceAll('\r', r'\r'); - final reason = StringBuffer("Could not render right '''$templateOneline'''"); + final String templateOneline = + template.replaceAll('\n', r'\n').replaceAll('\r', r'\r'); + final reason = + StringBuffer("Could not render right '''$templateOneline'''"); final Object? expected = t['expected']; final partials = t['partials'] as Map?; String? partial(String name) { @@ -65,7 +68,8 @@ void _defineGroupFromFile(String filename, String text) { } test( testDescription.toString(), - () => expect(render(template, data, partial: partial), expected, reason: reason.toString()), + () => expect(render(template, data, partial: partial), expected, + reason: reason.toString()), ); } }); @@ -89,14 +93,16 @@ String Function(LambdaContext) wrapLambda(Object? Function(Object?) f) => Map lambdas = { 'Interpolation': wrapLambda((Object? t) => 'world'), 'Interpolation - Expansion': wrapLambda((Object? t) => '{{planet}}'), - 'Interpolation - Alternate Delimiters': wrapLambda((Object? t) => '|planet| => {{planet}}'), + 'Interpolation - Alternate Delimiters': + wrapLambda((Object? t) => '|planet| => {{planet}}'), 'Interpolation - Multiple Calls': wrapLambda( _dummyCallableWithState(), ), //function() { return (g=(function(){return this})()).calls=(g.calls||0)+1 } 'Escaping': wrapLambda((Object? t) => '>'), 'Section': wrapLambda((Object? txt) => txt == '{{x}}' ? 'yes' : 'no'), 'Section - Expansion': wrapLambda((Object? txt) => '$txt{{planet}}$txt'), - 'Section - Alternate Delimiters': wrapLambda((Object? txt) => '$txt{{planet}} => |planet|$txt'), + 'Section - Alternate Delimiters': + wrapLambda((Object? txt) => '$txt{{planet}} => |planet|$txt'), 'Section - Multiple Calls': wrapLambda((Object? t) => '__${t}__'), 'Inverted Section': wrapLambda((Object? txt) => false), }; diff --git a/third_party/packages/mustache_template/test/parser_test.dart b/third_party/packages/mustache_template/test/parser_test.dart index 6e1ab0b5..67db6d61 100644 --- a/third_party/packages/mustache_template/test/parser_test.dart +++ b/third_party/packages/mustache_template/test/parser_test.dart @@ -162,7 +162,8 @@ void main() { SectionNode('foo', 3, 11, '{{ }}'), TextNode('ghi', 22, 25), ]); - expectNodes((nodes[1] as SectionNode).children, [TextNode('def', 11, 14)]); + expectNodes( + (nodes[1] as SectionNode).children, [TextNode('def', 11, 14)]); }); test('parse section standalone tag whitespace', () { @@ -174,11 +175,13 @@ void main() { SectionNode('foo', 4, 12, '{{ }}'), TextNode('ghi', 26, 29), ]); - expectNodes((nodes[1] as SectionNode).children, [TextNode('def\n', 13, 17)]); + expectNodes((nodes[1] as SectionNode).children, + [TextNode('def\n', 13, 17)]); }); test('parse section standalone tag whitespace consecutive', () { - const source = 'abc\n{{#foo}}\ndef\n{{/foo}}\n{{#foo}}\ndef\n{{/foo}}\nghi'; + const source = + 'abc\n{{#foo}}\ndef\n{{/foo}}\n{{#foo}}\ndef\n{{/foo}}\nghi'; final parser = Parser(source, 'foo', '{{ }}'); final List nodes = parser.parse(); expectNodes(nodes, [ @@ -187,15 +190,18 @@ void main() { SectionNode('foo', 26, 34, '{{ }}'), TextNode('ghi', 48, 51), ]); - expectNodes((nodes[1] as SectionNode).children, [TextNode('def\n', 13, 17)]); + expectNodes((nodes[1] as SectionNode).children, + [TextNode('def\n', 13, 17)]); }); test('parse section standalone tag whitespace on first line', () { const source = ' {{#foo}} \ndef\n{{/foo}}\nghi'; final parser = Parser(source, 'foo', '{{ }}'); final List nodes = parser.parse(); - expectNodes(nodes, [SectionNode('foo', 2, 10, '{{ }}'), TextNode('ghi', 26, 29)]); - expectNodes((nodes[0] as SectionNode).children, [TextNode('def\n', 13, 17)]); + expectNodes(nodes, + [SectionNode('foo', 2, 10, '{{ }}'), TextNode('ghi', 26, 29)]); + expectNodes((nodes[0] as SectionNode).children, + [TextNode('def\n', 13, 17)]); }); test('parse section standalone tag whitespace on last line', () { @@ -203,7 +209,8 @@ void main() { final parser = Parser(source, 'foo', '{{ }}'); final List nodes = parser.parse(); expectNodes(nodes, [SectionNode('foo', 0, 8, '{{ }}')]); - expectNodes((nodes[0] as SectionNode).children, [TextNode('def\n', 8, 12)]); + expectNodes( + (nodes[0] as SectionNode).children, [TextNode('def\n', 8, 12)]); }); test('parse variable newline', () { @@ -226,7 +233,8 @@ void main() { SectionNode('foo', 5, 13, '{{ }}'), TextNode('ghi', 27, 30), ]); - expectNodes((nodes[1] as SectionNode).children, [TextNode('def\n', 14, 18)]); + expectNodes((nodes[1] as SectionNode).children, + [TextNode('def\n', 14, 18)]); }); test('parse whitespace', () { @@ -257,7 +265,8 @@ void main() { TextNode('>', 31, 32), ]); expect((nodes[1] as SectionNode).delimiters, equals('| |')); - expectNodes((nodes[1] as SectionNode).children, [TextNode('-', 21, 22)]); + expectNodes( + (nodes[1] as SectionNode).children, [TextNode('-', 21, 22)]); }); test('corner case strict', () { @@ -367,9 +376,15 @@ void main() { bool nodeEqual(Node a, Node b) { if (a is TextNode) { - return b is TextNode && a.text == b.text && a.start == b.start && a.end == b.end; + return b is TextNode && + a.text == b.text && + a.start == b.start && + a.end == b.end; } else if (a is VariableNode && b is VariableNode) { - return a.name == b.name && a.escape == b.escape && a.start == b.start && a.end == b.end; + return a.name == b.name && + a.escape == b.escape && + a.start == b.start && + a.end == b.end; } else if (a is SectionNode && b is SectionNode) { return a.name == b.name && a.delimiters == b.delimiters && @@ -384,7 +399,10 @@ bool nodeEqual(Node a, Node b) { } bool tokenEqual(Token a, Token b) { - return a.type == b.type && a.value == b.value && a.start == b.start && a.end == b.end; + return a.type == b.type && + a.value == b.value && + a.start == b.start && + a.end == b.end; } void expectTokens(List a, List b) { diff --git a/third_party/packages/mustache_template/tool/download_spec.dart b/third_party/packages/mustache_template/tool/download_spec.dart index 15ff4afc..ae9e07f1 100644 --- a/third_party/packages/mustache_template/tool/download_spec.dart +++ b/third_party/packages/mustache_template/tool/download_spec.dart @@ -22,10 +22,10 @@ Future main(List args) async { tmpSpecPath, ]); - final String headHash = - ((await _runGit(packageRoot.path, ['-C', tmpSpecPath, 'rev-parse', 'HEAD'])).stdout - as String) - .trim(); + final String headHash = ((await _runGit(packageRoot.path, + ['-C', tmpSpecPath, 'rev-parse', 'HEAD'])) + .stdout as String) + .trim(); final String utcNow = _formatUtcSecond(DateTime.now().toUtc()); @@ -35,9 +35,12 @@ Future main(List args) async { await testSpecsDir.create(recursive: true); final clonedSpecs = Directory(_join(tmpSpecPath, 'specs')); - final List jsonFiles = - clonedSpecs.listSync().whereType().where((File f) => f.path.endsWith('.json')).toList() - ..sort((File a, File b) => a.path.compareTo(b.path)); + final List jsonFiles = clonedSpecs + .listSync() + .whereType() + .where((File f) => f.path.endsWith('.json')) + .toList() + ..sort((File a, File b) => a.path.compareTo(b.path)); final exports = StringBuffer(); final mapEntries = StringBuffer(); @@ -99,7 +102,8 @@ String _join(String a, String b, [String? c]) { return [a, b, if (c != null) c].join(sep); } -Future _runGit(String workingDirectory, List arguments) async { +Future _runGit( + String workingDirectory, List arguments) async { final ProcessResult result = await Process.run( 'git', arguments,