mergeMagicInto static method
Merges Magic into existingSource.
@param existingSource Current contents of lib/main.dart.
@param appName Title-Cased app name (extracted from pubspec).
@param configImports Import statements for each magic config file
(e.g. "import 'config/app.dart';").
@param configFactories Factory expressions for Magic.init's
configFactories: list (e.g. '() => appConfig').
@return Transformed source with Magic injected.
@throws FormatException When main() is not async.
@throws StateError When the source has no runApp( call.
Implementation
static String mergeMagicInto(
String existingSource, {
required String appName,
required List<String> configImports,
required List<String> configFactories,
}) {
// 1. Reject sync main() with an actionable message naming both alternatives.
if (_asyncMainPattern.firstMatch(existingSource) == null) {
throw FormatException(
'main() must be async to use Magic. Convert: '
'`void main() async { ... }` then re-run install --preserve. '
'To replace entirely, use --force.',
);
}
var result = existingSource;
// 2. Add imports (Magic + Wind + each configImport) idempotently. Each
// call to injectBeforeAnchor returns the source unchanged when the
// snippet is already present, so re-runs do not duplicate.
const magicImport = "import 'package:magic/magic.dart';";
const windImport = "import 'package:fluttersdk_wind/fluttersdk_wind.dart';";
const flutterMaterialAnchor = "import 'package:flutter/material.dart'";
result = MainDartEditor.injectBeforeAnchor(
source: result,
anchor: flutterMaterialAnchor,
snippet: '$magicImport\n',
);
result = MainDartEditor.injectBeforeAnchor(
source: result,
anchor: flutterMaterialAnchor,
snippet: '$windImport\n',
);
for (final imp in configImports) {
result = MainDartEditor.injectBeforeAnchor(
source: result,
anchor: flutterMaterialAnchor,
snippet: '$imp\n',
);
}
// 3. Inject `await Magic.init(...)` immediately after the `main() async {`
// line. Skip when an existing call is already present (idempotency).
if (!result.contains('await Magic.init(')) {
result = _injectMagicInitAfterMainOpen(result, configFactories);
}
// 4. Wrap `runApp(X)` with `MagicApplication(child: X, appName: '...')`.
// Skip when MagicApplication already wraps the call (idempotency).
if (!result.contains('MagicApplication(')) {
result = _wrapRunAppWithMagicApplication(result, appName);
}
return result;
}