validateLocal method
外部接続や依存変更の前にローカル適用の前提を検証します。
Implementation
Future<void> validateLocal(ExecContext context) async {
final firebase = context.yaml.getAsMap("firebase");
final flavor = context.flavorContext?.flavor.name ?? "prod";
final projectId = firebase.get("project_id", "");
final android =
File("android/app/src/katanaFirebase/$flavor/google-services.json");
final ios = File("ios/Runner/Firebase/$flavor/GoogleService-Info.plist");
final macos =
File("macos/Runner/Firebase/$flavor/GoogleService-Info.plist");
final options = File("lib/katana/firebase/$flavor/firebase_options.dart");
for (final file in [android, ios, macos, options]) {
if (!file.existsSync() ||
file.readAsStringSync().contains("KATANA FIREBASE STUB")) {
throw StateError("--local に必要な既存の Firebase 設定がありません: ${file.path}");
}
}
_validateFirebaseProject(
projectId: projectId,
googleServicesJson: android,
applePlists: [ios, macos]);
final jsonFile = File("firebase/firebase.json");
final config = jsonFile.existsSync()
? jsonDecode(jsonFile.readAsStringSync()) as Map
: {};
for (final service in [
"firestore",
"dataconnect",
"storage",
"hosting",
"functions"
]) {
if (firebase.getAsMap(service).get("enable", false) &&
!config.containsKey(service)) {
throw StateError("--local に必要な Firebase $service の初期設定がありません。");
}
}
final pubspec = loadYaml(File("pubspec.yaml").readAsStringSync()) as Map;
for (final section in ["dependencies", "dev_dependencies"]) {
validateLocalFlutterDependencies(
(pubspec[section] as Map? ?? {}).keys.cast<String>().toList(),
development: section == "dev_dependencies");
}
if (firebase.getAsMap("functions").get("enable", false)) {
final packageFile = File("firebase/functions/package.json");
final lockFile = File("firebase/functions/package-lock.json");
if (!packageFile.existsSync() || !lockFile.existsSync()) {
throw StateError(
"--local に必要な Functions の package.json / package-lock.json がありません。");
}
final package = jsonDecode(packageFile.readAsStringSync()) as Map;
final lock = jsonDecode(lockFile.readAsStringSync()) as Map;
final lockedRoot = (lock["packages"] as Map?)?[""] as Map?;
if (lockedRoot == null) {
throw StateError("--local は root package 情報を持つ既存の npm lock を必要とします。");
}
for (final section in [
"dependencies",
"devDependencies",
"optionalDependencies"
]) {
final declared = package[section] as Map? ?? {};
final locked = lockedRoot[section] as Map? ?? {};
if (declared.length != locked.length ||
declared.entries.any((e) => locked[e.key] != e.value)) {
throw StateError(
"Functions の $section と package-lock.json が不整合です。依存変更を承認・解決してから再実行してください。");
}
}
for (final name in [
"@mathrunet/masamune",
"jest",
"ts-jest",
"@types/jest",
"typescript",
"eslint"
]) {
if (!(package["dependencies"] as Map? ?? {}).containsKey(name) &&
!(package["devDependencies"] as Map? ?? {}).containsKey(name)) {
throw StateError("--local に必要な Functions 依存がありません: $name");
}
}
for (final name in ["eslint", "ts-jest"]) {
if (!File(
"firebase/functions/node_modules/.bin/$name${Platform.isWindows ? ".cmd" : ""}")
.existsSync()) {
throw StateError("--local に必要なローカル実行ファイルがありません: $name");
}
}
await command(
"Functions の導入済み依存を検証",
[
context.yaml.getAsMap("bin").get("npm", "npm"),
"ls",
"--offline",
"--all"
],
workingDirectory: "firebase/functions",
catchError: true,
failOnStderr: false);
}
}