updateSharedHubBinding function

String updateSharedHubBinding(
  1. String source, {
  2. required String binding,
  3. required String tag,
})

共有hubだけを新しいmigrationで追加し、既存データDOの履歴を維持する。

Implementation

String updateSharedHubBinding(String source,
    {required String binding, required String tag}) {
  if (!RegExp(r"^[A-Za-z_][A-Za-z0-9_]*$").hasMatch(binding) || tag.isEmpty) {
    throw ArgumentError("共有hubのbinding/tagが不正です。");
  }
  final pattern = RegExp(
      r'"durable_objects"\s*:\s*\{\s*"bindings"\s*:\s*(\[[\s\S]*?\])\s*\}');
  final match = pattern.firstMatch(source);
  if (match == null) {
    throw StateError("先にDO bindingを生成してください。");
  }
  final bindings = jsonDecode(match.group(1)!) as List;
  final existing = bindings.where((e) => e["name"] == binding);
  if (existing.any((e) =>
      e["class_name"] != "MasamuneSharedHub" || e["script_name"] != null)) {
    throw StateError("共有hubのbindingが競合しています。");
  }
  if (existing.isEmpty) {
    bindings.add({"name": binding, "class_name": "MasamuneSharedHub"});
  }
  source = source.replaceRange(match.start, match.end,
      '"durable_objects":{"bindings":${jsonEncode(bindings)}}');
  final found = _doArrayProperty(source, "migrations");
  final migrations = found?.value ?? <dynamic>[];
  final desired = {
    "tag": tag,
    "new_sqlite_classes": ["MasamuneSharedHub"]
  };
  final same = migrations.where((e) => e["tag"] == tag);
  if (same.any((e) => jsonEncode(e) != jsonEncode(desired))) {
    throw StateError("共有hub migration tagが競合しています。");
  }
  if (same.isEmpty) {
    if (migrations.any((e) => (e["new_sqlite_classes"] as List? ?? [])
        .contains("MasamuneSharedHub"))) {
      throw StateError("共有hub classは別tagで登録済みです。");
    }
    migrations.add(desired);
  }
  final property = '"migrations":${jsonEncode(migrations)}';
  return found == null
      ? source.replaceFirst("{", "{$property,")
      : source.replaceRange(found.start, found.end, property);
}