Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ class FirebaseDartConfigurationWrite {

FirebaseJsonWrites write() {
final outputFile = File(configurationFilePath);
if (outputFile.existsSync()) {
final updatedFileString = _updateExistingConfigurationFile(
outputFile,
);
if (outputFile.existsSync() && _isFlutterFireGeneratedFile(outputFile)) {
final updatedFileString = _updateExistingConfigurationFile(outputFile);
outputFile.writeAsStringSync(updatedFileString);
} else {
// File doesn't exist or wasn't generated by FlutterFire CLI
// (e.g. a placeholder file). Generate from scratch.
_writeHeader();
_writeClass();

Expand All @@ -69,9 +69,15 @@ class FirebaseDartConfigurationWrite {
return _firebaseJsonWrites();
}

String _updateExistingConfigurationFile(
File outputFile,
) {
/// Checks whether the existing file was generated by FlutterFire CLI
/// by looking for the CLI's header comment.
/// Returns false for placeholder or manually written files.
bool _isFlutterFireGeneratedFile(File file) {
final contents = file.readAsStringSync();
return contents.startsWith('// File generated by FlutterFire CLI.');
}
Comment on lines +72 to +78
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The current check for whether a file is generated by FlutterFire CLI is based on the presence of certain keywords. This might be brittle and could lead to false positives if a user's placeholder file happens to contain these keywords.

A more robust method would be to check for the specific comment header // File generated by FlutterFire CLI. that this tool adds to the beginning of every generated file. This is a much stronger and more reliable signal that the file was auto-generated.

  /// Checks whether the existing file was generated by FlutterFire CLI
  /// by looking for the header comment.
  /// Returns false for placeholder or manually written files.
  bool _isFlutterFireGeneratedFile(File file) {
    final contents = file.readAsStringSync();
    return contents.startsWith('// File generated by FlutterFire CLI.');
  }


String _updateExistingConfigurationFile(File outputFile) {
final fileConfigurationLines = outputFile.readAsLinesSync();

final optionsList = [
Expand All @@ -92,8 +98,9 @@ class FirebaseDartConfigurationWrite {
if (options == null) continue;

final configExists = fileConfigurationLines.any(
(line) => line
.contains('static const FirebaseOptions ${platform.toLowerCase()}'),
(line) => line.contains(
'static const FirebaseOptions ${platform.toLowerCase()}',
),
);
if (configExists) {
// find the indexes for start/end of existing platform configuration
Expand All @@ -118,10 +125,7 @@ class FirebaseDartConfigurationWrite {
// Insert the new platform configuration
fileConfigurationLines.insertAll(
startIndex - 1,
_buildFirebaseOptions(
options,
platform.toLowerCase(),
),
_buildFirebaseOptions(options, platform.toLowerCase()),
);
} else {
// remove `UnsupportedError` and write static const FirebaseOptions $platform
Expand All @@ -132,8 +136,9 @@ class FirebaseDartConfigurationWrite {
);
final unsupportedErrorLineIndex = startIndex + 1;

if (fileConfigurationLines[unsupportedErrorLineIndex]
.contains('UnsupportedError')) {
if (fileConfigurationLines[unsupportedErrorLineIndex].contains(
'UnsupportedError',
)) {
final endIndex = fileConfigurationLines.indexWhere(
(line) => line.contains(');'),
unsupportedErrorLineIndex,
Expand All @@ -150,18 +155,19 @@ class FirebaseDartConfigurationWrite {
: ' return ${platform.toLowerCase()};',
);
} else {
throw Exception('`UnsupportedError` not found in $platform');
throw Exception(
'Unable to update existing firebase_options.dart for platform '
'$platform. The file exists but does not match the expected '
'format. Delete the file and re-run `flutterfire configure`.',
);
}

final insertIndex = fileConfigurationLines.lastIndexOf('}');

// write the static property for the platform
fileConfigurationLines.insertAll(
insertIndex,
_buildFirebaseOptions(
options,
platform.toLowerCase(),
),
_buildFirebaseOptions(options, platform.toLowerCase()),
);
}
}
Expand All @@ -179,10 +185,7 @@ class FirebaseDartConfigurationWrite {
});
}

List<String> _buildFirebaseOptions(
FirebaseOptions options,
String platform,
) {
List<String> _buildFirebaseOptions(FirebaseOptions options, String platform) {
return <String>[
'',
' static const FirebaseOptions $platform = FirebaseOptions(',
Expand All @@ -196,10 +199,7 @@ class FirebaseDartConfigurationWrite {

FirebaseJsonWrites _firebaseJsonWrites() {
final relativePathConfigurationFile = replaceBackslash(
relative(
configurationFilePath,
from: flutterAppPath,
),
relative(configurationFilePath, from: flutterAppPath),
);

final keysToMap = [
Expand Down Expand Up @@ -238,56 +238,48 @@ class FirebaseDartConfigurationWrite {
}

void _writeHeader() {
_stringBuffer.writeAll(
<String>[
'// File generated by FlutterFire CLI.',
'// ignore_for_file: type=lint',
"import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;",
"import 'package:flutter/foundation.dart'",
' show defaultTargetPlatform, kIsWeb, TargetPlatform;',
'',
'/// Default [FirebaseOptions] for use with your Firebase apps.',
'///',
'/// Example:',
'/// ```dart',
"/// import '${basename(configurationFilePath)}';",
'/// // ...',
'/// await Firebase.initializeApp(',
'/// options: DefaultFirebaseOptions.currentPlatform,',
'/// );',
'/// ```',
'',
],
'\n',
);
_stringBuffer.writeAll(<String>[
'// File generated by FlutterFire CLI.',
'// ignore_for_file: type=lint',
"import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;",
"import 'package:flutter/foundation.dart'",
' show defaultTargetPlatform, kIsWeb, TargetPlatform;',
'',
'/// Default [FirebaseOptions] for use with your Firebase apps.',
'///',
'/// Example:',
'/// ```dart',
"/// import '${basename(configurationFilePath)}';",
'/// // ...',
'/// await Firebase.initializeApp(',
'/// options: DefaultFirebaseOptions.currentPlatform,',
'/// );',
'/// ```',
'',
], '\n');
}

void _writeClass() {
_stringBuffer.writeAll(
<String>[
'class DefaultFirebaseOptions {',
' static FirebaseOptions get currentPlatform {',
'',
],
'\n',
);
_stringBuffer.writeAll(<String>[
'class DefaultFirebaseOptions {',
' static FirebaseOptions get currentPlatform {',
'',
], '\n');
_writeCurrentPlatformWeb();
_stringBuffer.writeln(' switch (defaultTargetPlatform) {');
_writeCurrentPlatformSwitchAndroid();
_writeCurrentPlatformSwitchIos();
_writeCurrentPlatformSwitchMacos();
_writeCurrentPlatformSwitchWindows();
_writeCurrentPlatformSwitchLinux();
_stringBuffer.write(
'''
_stringBuffer.write('''
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
''',
);
''');
_writeFirebaseOptionsStatic(kWeb, webOptions);
_writeFirebaseOptionsStatic(kAndroid, androidOptions);
_writeFirebaseOptionsStatic(kIos, iosOptions);
Expand All @@ -299,23 +291,17 @@ class FirebaseDartConfigurationWrite {

void _writeFirebaseOptionsStatic(String platform, FirebaseOptions? options) {
if (options == null) return;
_stringBuffer.writeAll(
_buildFirebaseOptions(options, platform),
'\n',
);
_stringBuffer.writeAll(_buildFirebaseOptions(options, platform), '\n');
}

void _writeThrowUnsupportedForPlatform(String platform, String indentation) {
_stringBuffer.writeAll(
<String>[
'${indentation}throw UnsupportedError(',
"$indentation 'DefaultFirebaseOptions have not been configured for $platform - '",
"$indentation 'you can reconfigure this by running the FlutterFire CLI again.',",
'$indentation);',
'',
],
'\n',
);
_stringBuffer.writeAll(<String>[
'${indentation}throw UnsupportedError(',
"$indentation 'DefaultFirebaseOptions have not been configured for $platform - '",
"$indentation 'you can reconfigure this by running the FlutterFire CLI again.',",
'$indentation);',
'',
], '\n');
}

void _writeCurrentPlatformWeb() {
Expand Down
Loading