From d802c1287efe19b0de87a5894c719b04130b9fb6 Mon Sep 17 00:00:00 2001 From: kevmoo Date: Mon, 4 May 2026 09:37:54 -0700 Subject: [PATCH 1/2] fix: allow the latest pkg:analyzer Requires bumping the min SDK to Dart 3.11 Remove a now-deprecated analysis option --- CHANGELOG.md | 2 + analysis_options.yaml | 1 - lib/builder.dart | 87 ++++++++++++++------------------------- lib/src/builder/spec.dart | 20 ++++----- pubspec.yaml | 4 +- 5 files changed, 46 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5f54f8..dea59a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ - Add `runFunctions` as the primary API. - Deprecate `fireUp` in favor of `runFunctions`. +- Require `analyzer: ^13.0.0`. +- Require `sdk: ^3.11.0`. ## 0.5.2 diff --git a/analysis_options.yaml b/analysis_options.yaml index 57ff921..9f94bb9 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -50,5 +50,4 @@ linter: - sort_constructors_first - sort_unnamed_constructors_first - unnecessary_ignore - - use_if_null_to_convert_nulls_to_bools - use_string_buffers diff --git a/lib/builder.dart b/lib/builder.dart index 539fb88..8ef9274 100644 --- a/lib/builder.dart +++ b/lib/builder.dart @@ -389,7 +389,7 @@ class _FirebaseFunctionsVisitor extends RecursiveAstVisitor { } } else { final nameArg = args.first; - final paramName = _extractStringLiteral(nameArg); + final paramName = _extractStringLiteral(nameArg as Expression?); if (paramName != null) { // Map variable name to actual param name _variableToParamName[variable.name.lexeme] = paramName; @@ -835,11 +835,7 @@ class _FirebaseFunctionsVisitor extends RecursiveAstVisitor { InstanceCreationExpression node, String fieldName, ) { - final arg = node.argumentList.arguments - .whereType() - .where((e) => e.name.label.name == fieldName) - .map((e) => e.expression) - .firstOrNull; + final arg = node.findNamedArg(fieldName); if (arg is! SetOrMapLiteral || !arg.isMap) return null; @@ -861,21 +857,17 @@ class _FirebaseFunctionsVisitor extends RecursiveAstVisitor { Map? _extractTaskQueueRetryConfig( InstanceCreationExpression node, ) { - final retryConfigArg = node.argumentList.arguments - .whereType() - .where((e) => e.name.label.name == 'retryConfig') - .map((e) => e.expression) - .firstOrNull; + final retryConfigArg = node.findNamedArg('retryConfig'); if (retryConfigArg is! InstanceCreationExpression) return null; final config = {}; for (final arg in retryConfigArg.argumentList.arguments) { - if (arg is! NamedExpression) continue; + if (arg is! NamedArgument) continue; - final fieldName = arg.name.label.name; - final value = _extractRetryConfigValue(arg.expression); + final fieldName = arg.name.lexeme; + final value = _extractRetryConfigValue(arg.argumentExpression); if (value != null) { config[fieldName] = value; } @@ -888,21 +880,17 @@ class _FirebaseFunctionsVisitor extends RecursiveAstVisitor { Map? _extractTaskQueueRateLimits( InstanceCreationExpression node, ) { - final rateLimitsArg = node.argumentList.arguments - .whereType() - .where((e) => e.name.label.name == 'rateLimits') - .map((e) => e.expression) - .firstOrNull; + final rateLimitsArg = node.findNamedArg('rateLimits'); if (rateLimitsArg is! InstanceCreationExpression) return null; final config = {}; for (final arg in rateLimitsArg.argumentList.arguments) { - if (arg is! NamedExpression) continue; + if (arg is! NamedArgument) continue; - final fieldName = arg.name.label.name; - final value = _extractRetryConfigValue(arg.expression); + final fieldName = arg.name.lexeme; + final value = _extractRetryConfigValue(arg.argumentExpression); if (value != null) { config[fieldName] = value; } @@ -913,11 +901,7 @@ class _FirebaseFunctionsVisitor extends RecursiveAstVisitor { /// Extracts timeZone from ScheduleOptions. String? _extractSchedulerTimeZone(InstanceCreationExpression node) { - final timeZoneArg = node.argumentList.arguments - .whereType() - .where((e) => e.name.label.name == 'timeZone') - .map((e) => e.expression) - .firstOrNull; + final timeZoneArg = node.findNamedArg('timeZone'); if (timeZoneArg is InstanceCreationExpression) { // TimeZone('America/New_York') @@ -931,21 +915,17 @@ class _FirebaseFunctionsVisitor extends RecursiveAstVisitor { /// Extracts RetryConfig from ScheduleOptions. Map? _extractRetryConfig(InstanceCreationExpression node) { - final retryConfigArg = node.argumentList.arguments - .whereType() - .where((e) => e.name.label.name == 'retryConfig') - .map((e) => e.expression) - .firstOrNull; + final retryConfigArg = node.findNamedArg('retryConfig'); if (retryConfigArg is! InstanceCreationExpression) return null; final config = {}; for (final arg in retryConfigArg.argumentList.arguments) { - if (arg is! NamedExpression) continue; + if (arg is! NamedArgument) continue; - final fieldName = arg.name.label.name; - final value = _extractRetryConfigValue(arg.expression); + final fieldName = arg.name.lexeme; + final value = _extractRetryConfigValue(arg.argumentExpression); if (value != null) { config[fieldName] = value; } @@ -969,11 +949,7 @@ class _FirebaseFunctionsVisitor extends RecursiveAstVisitor { /// Extracts a boolean field from an InstanceCreationExpression. bool? _extractBoolField(InstanceCreationExpression node, String fieldName) { - final arg = node.argumentList.arguments - .whereType() - .where((e) => e.name.label.name == fieldName) - .map((e) => e.expression) - .firstOrNull; + final arg = node.findNamedArg(fieldName); if (arg is BooleanLiteral) { return arg.value; @@ -1019,7 +995,7 @@ class _FirebaseFunctionsVisitor extends RecursiveAstVisitor { } /// Common logic for extracting parameter definitions from arguments. - void _extractParamFromArgs(NodeList args, String functionName) { + void _extractParamFromArgs(NodeList args, String functionName) { if (args.isEmpty) return; String? paramName; @@ -1053,7 +1029,7 @@ class _FirebaseFunctionsVisitor extends RecursiveAstVisitor { } else { // Standard parameter definitions: defineXxx('NAME', [ParamOptions]) final nameArg = args.first; - paramName = _extractStringLiteral(nameArg); + paramName = _extractStringLiteral(nameArg as Expression?); // Second argument is optional ParamOptions (not used for secrets) if (args.length > 1 && args[1] is InstanceCreationExpression) { @@ -1100,11 +1076,7 @@ class _FirebaseFunctionsVisitor extends RecursiveAstVisitor { /// Extracts the defaultValue field. Object? _extractDefaultValue(InstanceCreationExpression node) { - final defaultValueArg = node.argumentList.arguments - .whereType() - .where((e) => e.name.label.name == 'defaultValue') - .map((e) => e.expression) - .firstOrNull; + final defaultValueArg = node.findNamedArg('defaultValue'); if (defaultValueArg == null) return null; @@ -1116,22 +1088,27 @@ class _FirebaseFunctionsVisitor extends RecursiveAstVisitor { InstanceCreationExpression node, String fieldName, ) { - final arg = node.argumentList.arguments - .whereType() - .where((e) => e.name.label.name == fieldName) - .map((e) => e.expression) - .firstOrNull; + final arg = node.findNamedArg(fieldName); return _extractStringLiteral(arg); } } +extension on InstanceCreationExpression { + /// Finds a named argument in a method invocation. + Expression? findNamedArg(String name) => argumentList.arguments + .whereType() + .where((e) => e.name.lexeme == name) + .map((e) => e.argumentExpression) + .firstOrNull; +} + extension on MethodInvocation { /// Finds a named argument in a method invocation. Expression? findNamedArg(String name) => argumentList.arguments - .whereType() - .where((e) => e.name.label.name == name) - .map((e) => e.expression) + .whereType() + .where((e) => e.name.lexeme == name) + .map((e) => e.argumentExpression) .firstOrNull; String? extractLiteralForArg(String name) => diff --git a/lib/src/builder/spec.dart b/lib/src/builder/spec.dart index 3bb9cdb..63f8fdc 100644 --- a/lib/src/builder/spec.dart +++ b/lib/src/builder/spec.dart @@ -112,10 +112,10 @@ class EndpointSpec { final result = {}; for (final arg in options!.argumentList.arguments) { - if (arg is! NamedExpression) continue; + if (arg is! NamedArgument) continue; - final name = arg.name.label.name; - final expr = arg.expression; + final name = arg.name.lexeme; + final expr = arg.argumentExpression; // Helper to reduce boilerplate: only adds to map if value exists void add(String key, dynamic Function(Expression expr) func) { @@ -186,7 +186,7 @@ class EndpointSpec { // Check if it's Memory.expression() - generate CEL from expression if (expression.constructorName.name?.name == 'expression') { return _extractCelExpression( - expression.argumentList.arguments.firstOrNull, + expression.argumentList.arguments.firstOrNull as Expression?, ); } @@ -197,7 +197,7 @@ class EndpointSpec { // Extract literal value: Memory(MemoryOption.mb256) or Memory(.mb256) final args = expression.argumentList.arguments; - final enumName = _extractEnumValueName(args.firstOrNull); + final enumName = _extractEnumValueName(args.firstOrNull as Expression?); if (enumName != null) return _memoryOptionToInt(enumName); return null; @@ -256,7 +256,7 @@ class EndpointSpec { // Extract literal value: Region(SupportedRegion.usCentral1) or Region(.usCentral1) final args = expression.argumentList.arguments; - final enumName = _extractEnumValueName(args.firstOrNull); + final enumName = _extractEnumValueName(args.firstOrNull as Expression?); if (enumName != null) { final regionString = _regionEnumToString(enumName); return regionString != null ? [regionString] : null; @@ -373,7 +373,7 @@ class EndpointSpec { if (expression is! InstanceCreationExpression) return null; final args = expression.argumentList.arguments; - final enumName = _extractEnumValueName(args.firstOrNull); + final enumName = _extractEnumValueName(args.firstOrNull as Expression?); if (enumName != null) { return switch (enumName) { 'privateRangesOnly' => 'PRIVATE_RANGES_ONLY', @@ -390,7 +390,7 @@ class EndpointSpec { if (expression is! InstanceCreationExpression) return null; final args = expression.argumentList.arguments; - final enumName = _extractEnumValueName(args.firstOrNull); + final enumName = _extractEnumValueName(args.firstOrNull as Expression?); if (enumName != null) { return switch (enumName) { 'allowAll' => 'ALLOW_ALL', @@ -506,8 +506,8 @@ class EndpointSpec { // Extract the two arguments final args = expression.argumentList.arguments; if (args.length >= 2) { - final trueValue = _extractLiteralValue(args[0]); - final falseValue = _extractLiteralValue(args[1]); + final trueValue = _extractLiteralValue(args[0] as Expression); + final falseValue = _extractLiteralValue(args[1] as Expression); if (trueValue != null && falseValue != null) { return '{{ params.$paramName ? $trueValue : $falseValue }}'; } diff --git a/pubspec.yaml b/pubspec.yaml index 016ddd5..8f4ae09 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,7 +20,7 @@ version: 0.6.0-wip repository: https://github.com/firebase/firebase-functions-dart environment: - sdk: ^3.9.0 + sdk: ^3.11.0 workspace: - example/https @@ -39,7 +39,7 @@ workspace: - test/fixtures/dart_reference dependencies: - analyzer: '>=10.0.1 <13.0.0' + analyzer: ^13.0.0 build: ^4.0.4 dart_jsonwebtoken: ^3.2.0 firebase_admin_sdk: ^0.5.0 From d3bf7d37c81fb2f8860def1e0a7782ce4c457172 Mon Sep 17 00:00:00 2001 From: kevmoo Date: Mon, 4 May 2026 09:42:52 -0700 Subject: [PATCH 2/2] one step better --- lib/builder.dart | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/builder.dart b/lib/builder.dart index 8ef9274..67e6a2d 100644 --- a/lib/builder.dart +++ b/lib/builder.dart @@ -1094,22 +1094,23 @@ class _FirebaseFunctionsVisitor extends RecursiveAstVisitor { } } -extension on InstanceCreationExpression { +extension on ArgumentList { /// Finds a named argument in a method invocation. - Expression? findNamedArg(String name) => argumentList.arguments + Expression? findNamedArg(String name) => arguments .whereType() .where((e) => e.name.lexeme == name) .map((e) => e.argumentExpression) .firstOrNull; } +extension on InstanceCreationExpression { + /// Finds a named argument in a method invocation. + Expression? findNamedArg(String name) => argumentList.findNamedArg(name); +} + extension on MethodInvocation { /// Finds a named argument in a method invocation. - Expression? findNamedArg(String name) => argumentList.arguments - .whereType() - .where((e) => e.name.lexeme == name) - .map((e) => e.argumentExpression) - .firstOrNull; + Expression? findNamedArg(String name) => argumentList.findNamedArg(name); String? extractLiteralForArg(String name) => _extractStringLiteral(findNamedArg(name));