Skip to content

Conversation

stuartmorgan-g
Copy link
Collaborator

The mustache_template package has been transferred to the flutter.dev publisher, so this imports it into our repository and updates it to follow repository conventions:

  • Fix/suppress analysis warnings
    • Some via dart fix, some manual
  • Add repo-level metadata
  • Update license check command to recognize this package
  • Add a temporary code-excerpt exclusion
  • Update pubspec.yaml metadata
  • Bump version to 2.0.1 to release the changes

mustache_template was itself a fork by a Flutter team member of the third-party mustache package, so the import is into third_party/packages/, updating the repo license check to recognize the license of this package.

The original code is quite old, and as a result still used a lot of implicit dynamic typing. Some of that that has been addressed in this import, but the trickier aspects have been left for future work, as converting from implicit dynamic typing to specified types has the potential for runtime regressions. (It's possible that even the more minor changes made here will cause regressions that will need fast-follow, but all the tests still pass, and the manual test/all.dart tests do not have any failures that were not present before making changes to the imported code).

Issues filed for future follow-up work:
flutter/flutter#174721
flutter/flutter#174722
flutter/flutter#174742

Pre-Review Checklist

Footnotes

  1. Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. 2 3

Copy link

google-cla bot commented Sep 2, 2025

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request imports the mustache_template package into the repository. The changes include updating repository metadata, license checks, and fixing some analysis warnings from the original, older codebase. My review focuses on improving code quality, fixing bugs, and ensuring consistency with modern Dart practices. I've found some critical issues like incorrect API definitions that would cause compilation errors and bugs where exceptions are created but not thrown. I've also found several medium-severity issues, including syntax errors in README examples, opportunities for code simplification, and improved type safety.

void render({Object? value}) {
_checkClosed();
if (_node is! SectionNode) {
_error('LambdaContext.render() can only be called on section tags.');

Choose a reason for hiding this comment

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

critical

The _error method returns a TemplateException, but it is not being thrown. This will lead to unexpected behavior as the function will complete without an error. The exception should be thrown.

Suggested change
_error('LambdaContext.render() can only be called on section tags.');
throw _error('LambdaContext.render() can only be called on section tags.');

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This definitely seems bad. It's a behavioral change so I'm not going to change it here, but I've added a TODO on these lines so that we don't forget.

Comment on lines +41 to +45
_error(
'LambdaContext.renderString() can only be called on section tags.',
);

Choose a reason for hiding this comment

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

critical

The _error method returns a TemplateException, but it is not being thrown here. This will lead to unexpected behavior as the function will implicitly return null instead of throwing an error. The exception should be thrown.

Suggested change
_error(
'LambdaContext.renderString() can only be called on section tags.',
);
throw _error(
'LambdaContext.renderString() can only be called on section tags.',
);

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

See previous comment.

Comment on lines +10 to +17
factory Template(
String source, {
bool lenient,
bool htmlEscapeValues,
String name,
PartialResolver? partialResolver,
String delimiters,
}) = t.Template.fromSource;

Choose a reason for hiding this comment

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

critical

The named parameters in this factory constructor are non-nullable and don't have default values or a required keyword, which will cause analysis errors in Dart 3. They should be updated to match the implementation in Template.fromSource, using default values and nullable types where appropriate.

Suggested change
factory Template(
String source, {
bool lenient,
bool htmlEscapeValues,
String name,
PartialResolver? partialResolver,
String delimiters,
}) = t.Template.fromSource;
factory Template(
String source, {
bool lenient = false,
bool htmlEscapeValues = true,
String? name,
PartialResolver? partialResolver,
String delimiters = '{{ }}',
}) = t.Template.fromSource;

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is weird, and looks like a mistake in the initial conversion to NNBD, but I'm not going to change it here.

throw _errorEof();
}
if (token.type != type) {
throw _error('Expected: $type found: ${token.type}.', _offset);

Choose a reason for hiding this comment

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

medium

The error is reported at _offset, which points to the position after the unexpected token. For a more accurate error location, it would be better to use token.start.

Suggested change
throw _error('Expected: $type found: ${token.type}.', _offset);
throw _error('Expected: $type found: ${token.type}.', token.start);

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not changing; could be done later.

node = null;

default:
throw Exception('Unreachable code');

Choose a reason for hiding this comment

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

medium

For unreachable code, it's more idiomatic in Dart to throw a StateError rather than a generic Exception.

Suggested change
throw Exception('Unreachable code');
throw StateError('Unreachable code');

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added TODO.

final Template? template =
partialResolver == null
? null
: (partialResolver!(partialName) as Template?);

Choose a reason for hiding this comment

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

medium

The cast as Template? is redundant here, as the expression partialResolver!(partialName) already evaluates to Template?.

Suggested change
: (partialResolver!(partialName) as Template?);
: partialResolver!(partialName);

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is due to some weird namespaced importing (there are two names for Template in this file) that I'm not going to try to unwind here.

// which contains the key name, this is object[name]. For other
// objects, this is object.name or object.name(). If no property
// by the given name exists, this method returns noSuchProperty.
Object? _getNamedProperty(dynamic object, dynamic name) {

Choose a reason for hiding this comment

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

medium

The name parameter is always a String since it comes from name.split('.'). It's better to type it as String instead of dynamic for better type safety and clarity.

Suggested change
Object? _getNamedProperty(dynamic object, dynamic name) {
Object? _getNamedProperty(dynamic object, String name) {

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This change does indeed appear to be safe, so I've made it.

if (ex is TemplateException) {
expect(ex.message, startsWith(VALUE_MISSING));
} else {
fail('Unexpecetd type: $ex');

Choose a reason for hiding this comment

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

medium

There is a typo in "Unexpecetd".

Suggested change
fail('Unexpecetd type: $ex');
fail('Unexpected type: $ex');

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed since it's test code.

@stuartmorgan-g
Copy link
Collaborator Author

I will get a CLA exemption once the PR is ready to land, since this is a third_party import.

@parlough
Copy link
Member

parlough commented Sep 3, 2025

Also, thanks for this import and filing the follow-up issues!

@stuartmorgan-g stuartmorgan-g force-pushed the mustache-template-import branch from ca20ab8 to a35fc7d Compare September 3, 2025 20:42
Fix violations of repo checks:
- Fix/suppress analysis warnings
  - Some via `dart fix`, some manual
- Add repo-level metadata
- Update license check command to recognize this package
- Add a temporary code-excerpt exclusion
- Update pubspec.yaml metadata
- Add METADATA file
- Bump version to 2.0.1 to release the changes
- Fix minor README issues
- Add TODOs for some areas that should be investigated in the future
@stuartmorgan-g stuartmorgan-g force-pushed the mustache-template-import branch from a35fc7d to cfe8bcd Compare September 3, 2025 20:50
@stuartmorgan-g stuartmorgan-g added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 4, 2025
@auto-submit auto-submit bot merged commit 98580c6 into flutter:main Sep 4, 2025
80 checks passed
@stuartmorgan-g stuartmorgan-g removed the autosubmit Merge PR when tree becomes green via auto submit App label Sep 4, 2025
@stuartmorgan-g
Copy link
Collaborator Author

stuartmorgan-g commented Sep 4, 2025

Argh, I didn't mean to autosubmit that. It was supposed to be a merge commit like most of our imports :( I realized my mistake slightly too late. This means we won't have full git history for this package.

I think it's probably not worth trying to unwind that though. In practice, since the history of the package is almost all >7 years old, it's probably not a big deal.

@stuartmorgan-g
Copy link
Collaborator Author

I'll try to leave my branch alive so that this PR can be used for looking into history of specific lines if we ever need to do that. There's also https://github.com/jonahwilliams/mustache, and https://github.com/xxgreg/mustache which is the original source in case Jonah's repo goes away at some point.

engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Sep 4, 2025
github-merge-queue bot pushed a commit to flutter/flutter that referenced this pull request Sep 4, 2025
flutter/packages@42bb347...98580c6

2025-09-04 stuartmorgan@google.com [mustache_template] Initial import
(flutter/packages#9944)
2025-09-04 69874219+WillBLogical@users.noreply.github.com
[google_maps_flutter_web] Omit styles when cloudMapId is set
(flutter/packages#9869)
2025-09-03 lukas.mirbt@hotmail.com [go_router_builder] Fix unnecessary
whitespace in generated `RelativeGoRouteData` (flutter/packages#9875)
2025-09-03 james@somethingwild.co.nz [google_maps_flutter_web] Stop
listening to map events when disposed (flutter/packages#9250)
2025-09-03 borisshishov@gmail.com [flutter_svg] loader buffer fix
(flutter/packages#9898)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC flutter-ecosystem@google.com on the revert to ensure that a
human
is aware of the problem.

To file a bug in Flutter:
https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
mboetger pushed a commit to mboetger/flutter that referenced this pull request Sep 18, 2025
…r#174943)

flutter/packages@42bb347...98580c6

2025-09-04 stuartmorgan@google.com [mustache_template] Initial import
(flutter/packages#9944)
2025-09-04 69874219+WillBLogical@users.noreply.github.com
[google_maps_flutter_web] Omit styles when cloudMapId is set
(flutter/packages#9869)
2025-09-03 lukas.mirbt@hotmail.com [go_router_builder] Fix unnecessary
whitespace in generated `RelativeGoRouteData` (flutter/packages#9875)
2025-09-03 james@somethingwild.co.nz [google_maps_flutter_web] Stop
listening to map events when disposed (flutter/packages#9250)
2025-09-03 borisshishov@gmail.com [flutter_svg] loader buffer fix
(flutter/packages#9898)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC flutter-ecosystem@google.com on the revert to ensure that a
human
is aware of the problem.

To file a bug in Flutter:
https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.