// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// This file is generated, do not edit.
// File generated by pkgs/hooks/tool/generate_syntax.dart.
// Must be rerun when pkgs/code_assets/doc/schema/ is modified.

// ignore_for_file: unused_element, public_member_api_docs

import 'dart:io';

class AndroidCodeConfigSyntax extends JsonObjectSyntax {
  AndroidCodeConfigSyntax.fromJson(super.json, {super.path = const []})
    : super.fromJson();

  AndroidCodeConfigSyntax({required int targetNdkApi, super.path = const []})
    : super() {
    _targetNdkApi = targetNdkApi;
    json.sortOnKey();
  }

  int get targetNdkApi => _reader.get<int>('target_ndk_api');

  set _targetNdkApi(int value) {
    json.setOrRemove('target_ndk_api', value);
  }

  List<String> _validateTargetNdkApi() =>
      _reader.validate<int>('target_ndk_api');

  @override
  List<String> validate() => [...super.validate(), ..._validateTargetNdkApi()];

  @override
  String toString() => 'AndroidCodeConfigSyntax($json)';
}

class ArchitectureSyntax {
  final String name;

  const ArchitectureSyntax._(this.name);

  static const arm = ArchitectureSyntax._('arm');

  static const arm64 = ArchitectureSyntax._('arm64');

  static const ia32 = ArchitectureSyntax._('ia32');

  static const riscv32 = ArchitectureSyntax._('riscv32');

  static const riscv64 = ArchitectureSyntax._('riscv64');

  static const x64 = ArchitectureSyntax._('x64');

  static const List<ArchitectureSyntax> values = [
    arm,
    arm64,
    ia32,
    riscv32,
    riscv64,
    x64,
  ];

  static final Map<String, ArchitectureSyntax> _byName = {
    for (final value in values) value.name: value,
  };

  ArchitectureSyntax.unknown(this.name) : assert(!_byName.keys.contains(name));

  factory ArchitectureSyntax.fromJson(String name) {
    final knownValue = _byName[name];
    if (knownValue != null) {
      return knownValue;
    }
    return ArchitectureSyntax.unknown(name);
  }

  bool get isKnown => _byName[name] != null;

  @override
  String toString() => name;
}

class AssetSyntax extends JsonObjectSyntax {
  factory AssetSyntax.fromJson(
    Map<String, Object?> json, {
    List<Object> path = const [],
  }) {
    final result = AssetSyntax._fromJson(json, path: path);
    if (result.isNativeCodeAssetNew) {
      return result.asNativeCodeAssetNew;
    }
    return result;
  }

  AssetSyntax._fromJson(super.json, {super.path = const []}) : super.fromJson();

  AssetSyntax({required String? type, super.path = const []}) : super() {
    _type = type;
    json.sortOnKey();
  }

  String? get type => _reader.get<String?>('type');

  set _type(String? value) {
    json.setOrRemove('type', value);
  }

  List<String> _validateType() => _reader.validate<String?>('type');

  @override
  List<String> validate() => [...super.validate(), ..._validateType()];

  @override
  String toString() => 'AssetSyntax($json)';
}

class CCompilerConfigSyntax extends JsonObjectSyntax {
  CCompilerConfigSyntax.fromJson(super.json, {super.path = const []})
    : super.fromJson();

  CCompilerConfigSyntax({
    required Uri ar,
    required Uri cc,
    required Uri ld,
    required WindowsSyntax? windows,
    super.path = const [],
  }) : super() {
    _ar = ar;
    _cc = cc;
    _ld = ld;
    _windows = windows;
    json.sortOnKey();
  }

  Uri get ar => _reader.path$('ar');

  set _ar(Uri value) {
    json['ar'] = value.toFilePath();
  }

  List<String> _validateAr() => _reader.validatePath('ar');

  Uri get cc => _reader.path$('cc');

  set _cc(Uri value) {
    json['cc'] = value.toFilePath();
  }

  List<String> _validateCc() => _reader.validatePath('cc');

  Uri get ld => _reader.path$('ld');

  set _ld(Uri value) {
    json['ld'] = value.toFilePath();
  }

  List<String> _validateLd() => _reader.validatePath('ld');

  WindowsSyntax? get windows {
    final jsonValue = _reader.optionalMap('windows');
    if (jsonValue == null) return null;
    return WindowsSyntax.fromJson(jsonValue, path: [...path, 'windows']);
  }

  set _windows(WindowsSyntax? value) {
    json.setOrRemove('windows', value?.json);
  }

  List<String> _validateWindows() {
    final mapErrors = _reader.validate<Map<String, Object?>?>('windows');
    if (mapErrors.isNotEmpty) {
      return mapErrors;
    }
    return windows?.validate() ?? [];
  }

  @override
  List<String> validate() => [
    ...super.validate(),
    ..._validateAr(),
    ..._validateCc(),
    ..._validateLd(),
    ..._validateWindows(),
  ];

  @override
  String toString() => 'CCompilerConfigSyntax($json)';
}

class CodeConfigSyntax extends JsonObjectSyntax {
  CodeConfigSyntax.fromJson(super.json, {super.path = const []})
    : super.fromJson();

  CodeConfigSyntax({
    required AndroidCodeConfigSyntax? android,
    required CCompilerConfigSyntax? cCompiler,
    required IOSCodeConfigSyntax? iOS,
    required LinkModePreferenceSyntax linkModePreference,
    required MacOSCodeConfigSyntax? macOS,
    required ArchitectureSyntax targetArchitecture,
    required OSSyntax targetOs,
    super.path = const [],
  }) : super() {
    _android = android;
    _cCompiler = cCompiler;
    _iOS = iOS;
    _linkModePreference = linkModePreference;
    _macOS = macOS;
    _targetArchitecture = targetArchitecture;
    _targetOs = targetOs;
    json.sortOnKey();
  }

  AndroidCodeConfigSyntax? get android {
    final jsonValue = _reader.optionalMap('android');
    if (jsonValue == null) return null;
    return AndroidCodeConfigSyntax.fromJson(
      jsonValue,
      path: [...path, 'android'],
    );
  }

  set _android(AndroidCodeConfigSyntax? value) {
    json.setOrRemove('android', value?.json);
  }

  List<String> _validateAndroid() {
    final mapErrors = _reader.validate<Map<String, Object?>?>('android');
    if (mapErrors.isNotEmpty) {
      return mapErrors;
    }
    return android?.validate() ?? [];
  }

  CCompilerConfigSyntax? get cCompiler {
    final jsonValue = _reader.optionalMap('c_compiler');
    if (jsonValue == null) return null;
    return CCompilerConfigSyntax.fromJson(
      jsonValue,
      path: [...path, 'c_compiler'],
    );
  }

  set _cCompiler(CCompilerConfigSyntax? value) {
    json.setOrRemove('c_compiler', value?.json);
  }

  List<String> _validateCCompiler() {
    final mapErrors = _reader.validate<Map<String, Object?>?>('c_compiler');
    if (mapErrors.isNotEmpty) {
      return mapErrors;
    }
    return cCompiler?.validate() ?? [];
  }

  IOSCodeConfigSyntax? get iOS {
    final jsonValue = _reader.optionalMap('ios');
    if (jsonValue == null) return null;
    return IOSCodeConfigSyntax.fromJson(jsonValue, path: [...path, 'ios']);
  }

  set _iOS(IOSCodeConfigSyntax? value) {
    json.setOrRemove('ios', value?.json);
  }

  List<String> _validateIOS() {
    final mapErrors = _reader.validate<Map<String, Object?>?>('ios');
    if (mapErrors.isNotEmpty) {
      return mapErrors;
    }
    return iOS?.validate() ?? [];
  }

  LinkModePreferenceSyntax get linkModePreference {
    final jsonValue = _reader.get<String>('link_mode_preference');
    return LinkModePreferenceSyntax.fromJson(jsonValue);
  }

  set _linkModePreference(LinkModePreferenceSyntax value) {
    json['link_mode_preference'] = value.name;
  }

  List<String> _validateLinkModePreference() =>
      _reader.validate<String>('link_mode_preference');

  MacOSCodeConfigSyntax? get macOS {
    final jsonValue = _reader.optionalMap('macos');
    if (jsonValue == null) return null;
    return MacOSCodeConfigSyntax.fromJson(jsonValue, path: [...path, 'macos']);
  }

  set _macOS(MacOSCodeConfigSyntax? value) {
    json.setOrRemove('macos', value?.json);
  }

  List<String> _validateMacOS() {
    final mapErrors = _reader.validate<Map<String, Object?>?>('macos');
    if (mapErrors.isNotEmpty) {
      return mapErrors;
    }
    return macOS?.validate() ?? [];
  }

  ArchitectureSyntax get targetArchitecture {
    final jsonValue = _reader.get<String>('target_architecture');
    return ArchitectureSyntax.fromJson(jsonValue);
  }

  set _targetArchitecture(ArchitectureSyntax value) {
    json['target_architecture'] = value.name;
  }

  List<String> _validateTargetArchitecture() =>
      _reader.validate<String>('target_architecture');

  OSSyntax get targetOs {
    final jsonValue = _reader.get<String>('target_os');
    return OSSyntax.fromJson(jsonValue);
  }

  set _targetOs(OSSyntax value) {
    json['target_os'] = value.name;
  }

  List<String> _validateTargetOs() => _reader.validate<String>('target_os');

  @override
  List<String> validate() => [
    ...super.validate(),
    ..._validateAndroid(),
    ..._validateCCompiler(),
    ..._validateIOS(),
    ..._validateLinkModePreference(),
    ..._validateMacOS(),
    ..._validateTargetArchitecture(),
    ..._validateTargetOs(),
    ..._validateExtraRulesCodeConfig(),
  ];

  List<String> _validateExtraRulesCodeConfig() {
    final result = <String>[];
    if (_reader.tryTraverse(['target_os']) == 'android') {
      result.addAll(_reader.validate<Object>('android'));
    }
    if (_reader.tryTraverse(['target_os']) == 'ios') {
      result.addAll(_reader.validate<Object>('ios'));
    }
    if (_reader.tryTraverse(['target_os']) == 'macos') {
      result.addAll(_reader.validate<Object>('macos'));
    }
    if (_reader.tryTraverse(['target_os']) == 'windows') {
      final objectErrors = _reader.validate<Map<String, Object?>?>(
        'c_compiler',
      );
      result.addAll(objectErrors);
      if (objectErrors.isEmpty) {
        final jsonValue = _reader.get<Map<String, Object?>?>('c_compiler');
        if (jsonValue != null) {
          final reader = _JsonReader(jsonValue, [...path, 'c_compiler']);
          result.addAll(reader.validate<Object>('windows'));
        }
      }
    }
    return result;
  }

  @override
  String toString() => 'CodeConfigSyntax($json)';
}

class ConfigSyntax extends JsonObjectSyntax {
  ConfigSyntax.fromJson(super.json, {super.path = const []}) : super.fromJson();

  ConfigSyntax({
    required ConfigExtensionsSyntax? extensions,
    super.path = const [],
  }) : super() {
    this.extensions = extensions;
    json.sortOnKey();
  }

  ConfigExtensionsSyntax? get extensions {
    final jsonValue = _reader.optionalMap('extensions');
    if (jsonValue == null) return null;
    return ConfigExtensionsSyntax.fromJson(
      jsonValue,
      path: [...path, 'extensions'],
    );
  }

  set extensions(ConfigExtensionsSyntax? value) {
    json.setOrRemove('extensions', value?.json);
    json.sortOnKey();
  }

  List<String> _validateExtensions() {
    final mapErrors = _reader.validate<Map<String, Object?>?>('extensions');
    if (mapErrors.isNotEmpty) {
      return mapErrors;
    }
    return extensions?.validate() ?? [];
  }

  @override
  List<String> validate() => [...super.validate(), ..._validateExtensions()];

  @override
  String toString() => 'ConfigSyntax($json)';
}

class ConfigExtensionsSyntax extends JsonObjectSyntax {
  ConfigExtensionsSyntax.fromJson(super.json, {super.path = const []})
    : super.fromJson();

  ConfigExtensionsSyntax({
    required CodeConfigSyntax? codeAssets,
    super.path = const [],
  }) : super() {
    this.codeAssets = codeAssets;
    json.sortOnKey();
  }

  CodeConfigSyntax? get codeAssets {
    final jsonValue = _reader.optionalMap('code_assets');
    if (jsonValue == null) return null;
    return CodeConfigSyntax.fromJson(jsonValue, path: [...path, 'code_assets']);
  }

  set codeAssets(CodeConfigSyntax? value) {
    json.setOrRemove('code_assets', value?.json);
    json.sortOnKey();
  }

  List<String> _validateCodeAssets() {
    final mapErrors = _reader.validate<Map<String, Object?>?>('code_assets');
    if (mapErrors.isNotEmpty) {
      return mapErrors;
    }
    return codeAssets?.validate() ?? [];
  }

  @override
  List<String> validate() => [...super.validate(), ..._validateCodeAssets()];

  @override
  String toString() => 'ConfigExtensionsSyntax($json)';
}

class DeveloperCommandPromptSyntax extends JsonObjectSyntax {
  DeveloperCommandPromptSyntax.fromJson(super.json, {super.path = const []})
    : super.fromJson();

  DeveloperCommandPromptSyntax({
    required List<String> arguments,
    required Uri script,
    super.path = const [],
  }) : super() {
    _arguments = arguments;
    _script = script;
    json.sortOnKey();
  }

  List<String> get arguments => _reader.stringList('arguments');

  set _arguments(List<String> value) {
    json['arguments'] = value;
  }

  List<String> _validateArguments() => _reader.validateStringList('arguments');

  Uri get script => _reader.path$('script');

  set _script(Uri value) {
    json['script'] = value.toFilePath();
  }

  List<String> _validateScript() => _reader.validatePath('script');

  @override
  List<String> validate() => [
    ...super.validate(),
    ..._validateArguments(),
    ..._validateScript(),
  ];

  @override
  String toString() => 'DeveloperCommandPromptSyntax($json)';
}

class DynamicLoadingBundleLinkModeSyntax extends LinkModeSyntax {
  DynamicLoadingBundleLinkModeSyntax.fromJson(super.json, {super.path})
    : super._fromJson();

  DynamicLoadingBundleLinkModeSyntax({super.path = const []})
    : super(type: 'dynamic_loading_bundle');

  @override
  List<String> validate() => [...super.validate()];

  @override
  String toString() => 'DynamicLoadingBundleLinkModeSyntax($json)';
}

extension DynamicLoadingBundleLinkModeSyntaxExtension on LinkModeSyntax {
  bool get isDynamicLoadingBundleLinkMode => type == 'dynamic_loading_bundle';

  DynamicLoadingBundleLinkModeSyntax get asDynamicLoadingBundleLinkMode =>
      DynamicLoadingBundleLinkModeSyntax.fromJson(json, path: path);
}

class DynamicLoadingExecutableLinkModeSyntax extends LinkModeSyntax {
  DynamicLoadingExecutableLinkModeSyntax.fromJson(super.json, {super.path})
    : super._fromJson();

  DynamicLoadingExecutableLinkModeSyntax({super.path = const []})
    : super(type: 'dynamic_loading_executable');

  @override
  List<String> validate() => [...super.validate()];

  @override
  String toString() => 'DynamicLoadingExecutableLinkModeSyntax($json)';
}

extension DynamicLoadingExecutableLinkModeSyntaxExtension on LinkModeSyntax {
  bool get isDynamicLoadingExecutableLinkMode =>
      type == 'dynamic_loading_executable';

  DynamicLoadingExecutableLinkModeSyntax
  get asDynamicLoadingExecutableLinkMode =>
      DynamicLoadingExecutableLinkModeSyntax.fromJson(json, path: path);
}

class DynamicLoadingProcessLinkModeSyntax extends LinkModeSyntax {
  DynamicLoadingProcessLinkModeSyntax.fromJson(super.json, {super.path})
    : super._fromJson();

  DynamicLoadingProcessLinkModeSyntax({super.path = const []})
    : super(type: 'dynamic_loading_process');

  @override
  List<String> validate() => [...super.validate()];

  @override
  String toString() => 'DynamicLoadingProcessLinkModeSyntax($json)';
}

extension DynamicLoadingProcessLinkModeSyntaxExtension on LinkModeSyntax {
  bool get isDynamicLoadingProcessLinkMode => type == 'dynamic_loading_process';

  DynamicLoadingProcessLinkModeSyntax get asDynamicLoadingProcessLinkMode =>
      DynamicLoadingProcessLinkModeSyntax.fromJson(json, path: path);
}

class DynamicLoadingSystemLinkModeSyntax extends LinkModeSyntax {
  DynamicLoadingSystemLinkModeSyntax.fromJson(super.json, {super.path})
    : super._fromJson();

  DynamicLoadingSystemLinkModeSyntax({required Uri uri, super.path = const []})
    : super(type: 'dynamic_loading_system') {
    _uri = uri;
    json.sortOnKey();
  }

  /// Setup all fields for [DynamicLoadingSystemLinkModeSyntax] that are not in
  /// [LinkModeSyntax].
  void setup({required Uri uri}) {
    _uri = uri;
    json.sortOnKey();
  }

  Uri get uri => _reader.path$('uri');

  set _uri(Uri value) {
    json['uri'] = value.toFilePath();
  }

  List<String> _validateUri() => _reader.validatePath('uri');

  @override
  List<String> validate() => [...super.validate(), ..._validateUri()];

  @override
  String toString() => 'DynamicLoadingSystemLinkModeSyntax($json)';
}

extension DynamicLoadingSystemLinkModeSyntaxExtension on LinkModeSyntax {
  bool get isDynamicLoadingSystemLinkMode => type == 'dynamic_loading_system';

  DynamicLoadingSystemLinkModeSyntax get asDynamicLoadingSystemLinkMode =>
      DynamicLoadingSystemLinkModeSyntax.fromJson(json, path: path);
}

class IOSCodeConfigSyntax extends JsonObjectSyntax {
  IOSCodeConfigSyntax.fromJson(super.json, {super.path = const []})
    : super.fromJson();

  IOSCodeConfigSyntax({
    required String targetSdk,
    required int targetVersion,
    super.path = const [],
  }) : super() {
    _targetSdk = targetSdk;
    _targetVersion = targetVersion;
    json.sortOnKey();
  }

  String get targetSdk => _reader.get<String>('target_sdk');

  set _targetSdk(String value) {
    json.setOrRemove('target_sdk', value);
  }

  List<String> _validateTargetSdk() => _reader.validate<String>('target_sdk');

  int get targetVersion => _reader.get<int>('target_version');

  set _targetVersion(int value) {
    json.setOrRemove('target_version', value);
  }

  List<String> _validateTargetVersion() =>
      _reader.validate<int>('target_version');

  @override
  List<String> validate() => [
    ...super.validate(),
    ..._validateTargetSdk(),
    ..._validateTargetVersion(),
  ];

  @override
  String toString() => 'IOSCodeConfigSyntax($json)';
}

class LinkModeSyntax extends JsonObjectSyntax {
  factory LinkModeSyntax.fromJson(
    Map<String, Object?> json, {
    List<Object> path = const [],
  }) {
    final result = LinkModeSyntax._fromJson(json, path: path);
    if (result.isDynamicLoadingBundleLinkMode) {
      return result.asDynamicLoadingBundleLinkMode;
    }
    if (result.isDynamicLoadingExecutableLinkMode) {
      return result.asDynamicLoadingExecutableLinkMode;
    }
    if (result.isDynamicLoadingProcessLinkMode) {
      return result.asDynamicLoadingProcessLinkMode;
    }
    if (result.isDynamicLoadingSystemLinkMode) {
      return result.asDynamicLoadingSystemLinkMode;
    }
    if (result.isStaticLinkMode) {
      return result.asStaticLinkMode;
    }
    return result;
  }

  LinkModeSyntax._fromJson(super.json, {super.path = const []})
    : super.fromJson();

  LinkModeSyntax({required String type, super.path = const []}) : super() {
    _type = type;
    json.sortOnKey();
  }

  String get type => _reader.get<String>('type');

  set _type(String value) {
    json.setOrRemove('type', value);
  }

  List<String> _validateType() => _reader.validate<String>('type');

  @override
  List<String> validate() => [...super.validate(), ..._validateType()];

  @override
  String toString() => 'LinkModeSyntax($json)';
}

class LinkModePreferenceSyntax {
  final String name;

  const LinkModePreferenceSyntax._(this.name);

  static const dynamic = LinkModePreferenceSyntax._('dynamic');

  static const preferDynamic = LinkModePreferenceSyntax._('prefer_dynamic');

  static const preferStatic = LinkModePreferenceSyntax._('prefer_static');

  static const static = LinkModePreferenceSyntax._('static');

  static const List<LinkModePreferenceSyntax> values = [
    dynamic,
    preferDynamic,
    preferStatic,
    static,
  ];

  static final Map<String, LinkModePreferenceSyntax> _byName = {
    for (final value in values) value.name: value,
  };

  LinkModePreferenceSyntax.unknown(this.name)
    : assert(!_byName.keys.contains(name));

  factory LinkModePreferenceSyntax.fromJson(String name) {
    final knownValue = _byName[name];
    if (knownValue != null) {
      return knownValue;
    }
    return LinkModePreferenceSyntax.unknown(name);
  }

  bool get isKnown => _byName[name] != null;

  @override
  String toString() => name;
}

class MacOSCodeConfigSyntax extends JsonObjectSyntax {
  MacOSCodeConfigSyntax.fromJson(super.json, {super.path = const []})
    : super.fromJson();

  MacOSCodeConfigSyntax({required int targetVersion, super.path = const []})
    : super() {
    _targetVersion = targetVersion;
    json.sortOnKey();
  }

  int get targetVersion => _reader.get<int>('target_version');

  set _targetVersion(int value) {
    json.setOrRemove('target_version', value);
  }

  List<String> _validateTargetVersion() =>
      _reader.validate<int>('target_version');

  @override
  List<String> validate() => [...super.validate(), ..._validateTargetVersion()];

  @override
  String toString() => 'MacOSCodeConfigSyntax($json)';
}

class NativeCodeAssetEncodingSyntax extends JsonObjectSyntax {
  NativeCodeAssetEncodingSyntax.fromJson(super.json, {super.path = const []})
    : super.fromJson();

  NativeCodeAssetEncodingSyntax({
    required Uri? file,
    required String id,
    required LinkModeSyntax linkMode,
    super.path = const [],
  }) : super() {
    _file = file;
    _id = id;
    _linkMode = linkMode;
    json.sortOnKey();
  }

  Uri? get file => _reader.optionalPath('file');

  set _file(Uri? value) {
    json.setOrRemove('file', value?.toFilePath());
  }

  List<String> _validateFile() => _reader.validateOptionalPath('file');

  String get id => _reader.get<String>('id');

  set _id(String value) {
    json.setOrRemove('id', value);
  }

  List<String> _validateId() => _reader.validate<String>('id');

  LinkModeSyntax get linkMode {
    final jsonValue = _reader.map$('link_mode');
    return LinkModeSyntax.fromJson(jsonValue, path: [...path, 'link_mode']);
  }

  set _linkMode(LinkModeSyntax value) {
    json['link_mode'] = value.json;
  }

  List<String> _validateLinkMode() {
    final mapErrors = _reader.validate<Map<String, Object?>>('link_mode');
    if (mapErrors.isNotEmpty) {
      return mapErrors;
    }
    return linkMode.validate();
  }

  @override
  List<String> validate() => [
    ...super.validate(),
    ..._validateFile(),
    ..._validateId(),
    ..._validateLinkMode(),
    ..._validateExtraRulesNativeCodeAssetEncoding(),
  ];

  List<String> _validateExtraRulesNativeCodeAssetEncoding() {
    final result = <String>[];
    if ([
      'dynamic_loading_bundle',
      'static',
    ].contains(_reader.tryTraverse(['link_mode', 'type']))) {
      result.addAll(_reader.validate<Object>('file'));
    }
    return result;
  }

  @override
  String toString() => 'NativeCodeAssetEncodingSyntax($json)';
}

class NativeCodeAssetNewSyntax extends AssetSyntax {
  static const typeValue = 'code_assets/code';

  NativeCodeAssetNewSyntax.fromJson(super.json, {super.path})
    : super._fromJson();

  NativeCodeAssetNewSyntax({
    required NativeCodeAssetEncodingSyntax? encoding,
    super.path = const [],
  }) : super(type: 'code_assets/code') {
    _encoding = encoding;
    json.sortOnKey();
  }

  /// Setup all fields for [NativeCodeAssetNewSyntax] that are not in
  /// [AssetSyntax].
  void setup({required NativeCodeAssetEncodingSyntax? encoding}) {
    _encoding = encoding;
    json.sortOnKey();
  }

  NativeCodeAssetEncodingSyntax? get encoding {
    final jsonValue = _reader.optionalMap('encoding');
    if (jsonValue == null) return null;
    return NativeCodeAssetEncodingSyntax.fromJson(
      jsonValue,
      path: [...path, 'encoding'],
    );
  }

  set _encoding(NativeCodeAssetEncodingSyntax? value) {
    json.setOrRemove('encoding', value?.json);
  }

  List<String> _validateEncoding() {
    final mapErrors = _reader.validate<Map<String, Object?>?>('encoding');
    if (mapErrors.isNotEmpty) {
      return mapErrors;
    }
    return encoding?.validate() ?? [];
  }

  @override
  List<String> validate() => [...super.validate(), ..._validateEncoding()];

  @override
  String toString() => 'NativeCodeAssetNewSyntax($json)';
}

extension NativeCodeAssetNewSyntaxExtension on AssetSyntax {
  bool get isNativeCodeAssetNew => type == 'code_assets/code';

  NativeCodeAssetNewSyntax get asNativeCodeAssetNew =>
      NativeCodeAssetNewSyntax.fromJson(json, path: path);
}

class OSSyntax {
  final String name;

  const OSSyntax._(this.name);

  static const android = OSSyntax._('android');

  static const iOS = OSSyntax._('ios');

  static const linux = OSSyntax._('linux');

  static const macOS = OSSyntax._('macos');

  static const windows = OSSyntax._('windows');

  static const List<OSSyntax> values = [android, iOS, linux, macOS, windows];

  static final Map<String, OSSyntax> _byName = {
    for (final value in values) value.name: value,
  };

  OSSyntax.unknown(this.name) : assert(!_byName.keys.contains(name));

  factory OSSyntax.fromJson(String name) {
    final knownValue = _byName[name];
    if (knownValue != null) {
      return knownValue;
    }
    return OSSyntax.unknown(name);
  }

  bool get isKnown => _byName[name] != null;

  @override
  String toString() => name;
}

class StaticLinkModeSyntax extends LinkModeSyntax {
  StaticLinkModeSyntax.fromJson(super.json, {super.path}) : super._fromJson();

  StaticLinkModeSyntax({super.path = const []}) : super(type: 'static');

  @override
  List<String> validate() => [...super.validate()];

  @override
  String toString() => 'StaticLinkModeSyntax($json)';
}

extension StaticLinkModeSyntaxExtension on LinkModeSyntax {
  bool get isStaticLinkMode => type == 'static';

  StaticLinkModeSyntax get asStaticLinkMode =>
      StaticLinkModeSyntax.fromJson(json, path: path);
}

class WindowsSyntax extends JsonObjectSyntax {
  WindowsSyntax.fromJson(super.json, {super.path = const []})
    : super.fromJson();

  WindowsSyntax({
    required DeveloperCommandPromptSyntax? developerCommandPrompt,
    super.path = const [],
  }) : super() {
    _developerCommandPrompt = developerCommandPrompt;
    json.sortOnKey();
  }

  DeveloperCommandPromptSyntax? get developerCommandPrompt {
    final jsonValue = _reader.optionalMap('developer_command_prompt');
    if (jsonValue == null) return null;
    return DeveloperCommandPromptSyntax.fromJson(
      jsonValue,
      path: [...path, 'developer_command_prompt'],
    );
  }

  set _developerCommandPrompt(DeveloperCommandPromptSyntax? value) {
    json.setOrRemove('developer_command_prompt', value?.json);
  }

  List<String> _validateDeveloperCommandPrompt() {
    final mapErrors = _reader.validate<Map<String, Object?>?>(
      'developer_command_prompt',
    );
    if (mapErrors.isNotEmpty) {
      return mapErrors;
    }
    return developerCommandPrompt?.validate() ?? [];
  }

  @override
  List<String> validate() => [
    ...super.validate(),
    ..._validateDeveloperCommandPrompt(),
  ];

  @override
  String toString() => 'WindowsSyntax($json)';
}

class JsonObjectSyntax {
  final Map<String, Object?> json;

  final List<Object> path;

  _JsonReader get _reader => _JsonReader(json, path);

  JsonObjectSyntax({this.path = const []}) : json = {};

  JsonObjectSyntax.fromJson(this.json, {this.path = const []});

  List<String> validate() => [];
}

class _JsonReader {
  /// The JSON Object this reader is reading.
  final Map<String, Object?> json;

  /// The path traversed by readers of the surrounding JSON.
  ///
  /// Contains [String] property keys and [int] indices.
  ///
  /// This is used to give more precise error messages.
  final List<Object> path;

  _JsonReader(this.json, this.path);

  T get<T extends Object?>(String key) {
    final value = json[key];
    if (value is T) return value;
    throwFormatException(value, T, [key]);
  }

  List<String> validate<T extends Object?>(String key) {
    final value = json[key];
    if (value is T) return [];
    return [
      errorString(value, T, [key]),
    ];
  }

  List<T> list<T extends Object?>(String key) =>
      _castList<T>(get<List<Object?>>(key), key);

  List<String> validateList<T extends Object?>(String key) {
    final listErrors = validate<List<Object?>>(key);
    if (listErrors.isNotEmpty) {
      return listErrors;
    }
    return _validateListElements(get<List<Object?>>(key), key);
  }

  List<T>? optionalList<T extends Object?>(String key) =>
      switch (get<List<Object?>?>(key)?.cast<T>()) {
        null => null,
        final l => _castList<T>(l, key),
      };

  List<String> validateOptionalList<T extends Object?>(String key) {
    final listErrors = validate<List<Object?>?>(key);
    if (listErrors.isNotEmpty) {
      return listErrors;
    }
    final list = get<List<Object?>?>(key);
    if (list == null) {
      return [];
    }
    return _validateListElements(list, key);
  }

  /// [List.cast] but with [FormatException]s.
  List<T> _castList<T extends Object?>(List<Object?> list, String key) {
    for (final (index, value) in list.indexed) {
      if (value is! T) {
        throwFormatException(value, T, [key, index]);
      }
    }
    return list.cast();
  }

  List<String> _validateListElements<T extends Object?>(
    List<Object?> list,
    String key,
  ) {
    final result = <String>[];
    for (final (index, value) in list.indexed) {
      if (value is! T) {
        result.add(errorString(value, T, [key, index]));
      }
    }
    return result;
  }

  Map<String, T> map$<T extends Object?>(String key, {RegExp? keyPattern}) {
    final map = get<Map<String, Object?>>(key);
    final keyErrors = _validateMapKeys(map, key, keyPattern: keyPattern);
    if (keyErrors.isNotEmpty) {
      throw FormatException(keyErrors.join('\n'));
    }
    return _castMap<T>(map, key);
  }

  List<String> validateMap<T extends Object?>(
    String key, {
    RegExp? keyPattern,
  }) {
    final mapErrors = validate<Map<String, Object?>>(key);
    if (mapErrors.isNotEmpty) {
      return mapErrors;
    }
    final map = get<Map<String, Object?>>(key);
    return [
      ..._validateMapKeys(map, key, keyPattern: keyPattern),
      ..._validateMapElements<T>(map, key),
    ];
  }

  Map<String, T>? optionalMap<T extends Object?>(
    String key, {
    RegExp? keyPattern,
  }) {
    final map = get<Map<String, Object?>?>(key);
    if (map == null) return null;
    final keyErrors = _validateMapKeys(map, key, keyPattern: keyPattern);
    if (keyErrors.isNotEmpty) {
      throw FormatException(keyErrors.join('\n'));
    }
    return _castMap<T>(map, key);
  }

  List<String> validateOptionalMap<T extends Object?>(
    String key, {
    RegExp? keyPattern,
  }) {
    final mapErrors = validate<Map<String, Object?>?>(key);
    if (mapErrors.isNotEmpty) {
      return mapErrors;
    }
    final map = get<Map<String, Object?>?>(key);
    if (map == null) {
      return [];
    }
    return [
      ..._validateMapKeys(map, key, keyPattern: keyPattern),
      ..._validateMapElements<T>(map, key),
    ];
  }

  /// [Map.cast] but with [FormatException]s.
  Map<String, T> _castMap<T extends Object?>(
    Map<String, Object?> map_,
    String parentKey,
  ) {
    for (final MapEntry(:key, :value) in map_.entries) {
      if (value is! T) {
        throwFormatException(value, T, [parentKey, key]);
      }
    }
    return map_.cast();
  }

  List<String> _validateMapKeys(
    Map<String, Object?> map_,
    String parentKey, {
    required RegExp? keyPattern,
  }) {
    if (keyPattern == null) return [];
    final result = <String>[];
    for (final key in map_.keys) {
      if (!keyPattern.hasMatch(key)) {
        result.add(
          keyErrorString(key, pattern: keyPattern, pathExtension: [parentKey]),
        );
      }
    }
    return result;
  }

  List<String> _validateMapElements<T extends Object?>(
    Map<String, Object?> map_,
    String parentKey,
  ) {
    final result = <String>[];
    for (final MapEntry(:key, :value) in map_.entries) {
      if (value is! T) {
        result.add(errorString(value, T, [parentKey, key]));
      }
    }
    return result;
  }

  List<String> validateMapStringElements<T extends Object?>(
    Map<String, String?> map_,
    String parentKey, {
    RegExp? valuePattern,
  }) {
    final result = <String>[];
    for (final MapEntry(:key, :value) in map_.entries) {
      if (value != null &&
          valuePattern != null &&
          !valuePattern.hasMatch(value)) {
        result.add(
          errorString(value, T, [parentKey, key], pattern: valuePattern),
        );
      }
    }
    return result;
  }

  String string(String key, RegExp? pattern) {
    final value = get<String>(key);
    if (pattern != null && !pattern.hasMatch(value)) {
      throwFormatException(value, String, [key], pattern: pattern);
    }
    return value;
  }

  String? optionalString(String key, RegExp? pattern) {
    final value = get<String?>(key);
    if (value == null) return null;
    if (pattern != null && !pattern.hasMatch(value)) {
      throwFormatException(value, String, [key], pattern: pattern);
    }
    return value;
  }

  List<String> validateString(String key, RegExp? pattern) {
    final errors = validate<String>(key);
    if (errors.isNotEmpty) {
      return errors;
    }
    final value = get<String>(key);
    if (pattern != null && !pattern.hasMatch(value)) {
      return [
        errorString(value, String, [key], pattern: pattern),
      ];
    }
    return [];
  }

  List<String> validateOptionalString(String key, RegExp? pattern) {
    final errors = validate<String?>(key);
    if (errors.isNotEmpty) {
      return errors;
    }
    final value = get<String?>(key);
    if (value == null) return [];
    if (pattern != null && !pattern.hasMatch(value)) {
      return [
        errorString(value, String, [key], pattern: pattern),
      ];
    }
    return [];
  }

  List<String>? optionalStringList(String key) => optionalList<String>(key);

  List<String> validateOptionalStringList(String key) =>
      validateOptionalList<String>(key);

  List<String> stringList(String key) => list<String>(key);

  List<String> validateStringList(String key) => validateList<String>(key);

  Uri path$(String key) => _fileSystemPathToUri(get<String>(key));

  List<String> validatePath(String key) => validate<String>(key);

  Uri? optionalPath(String key) {
    final value = get<String?>(key);
    if (value == null) return null;
    return _fileSystemPathToUri(value);
  }

  List<String> validateOptionalPath(String key) => validate<String?>(key);

  List<Uri>? optionalPathList(String key) {
    final strings = optionalStringList(key);
    if (strings == null) {
      return null;
    }
    return [for (final string in strings) _fileSystemPathToUri(string)];
  }

  List<String> validateOptionalPathList(String key) =>
      validateOptionalStringList(key);

  static Uri _fileSystemPathToUri(String path) {
    if (path.endsWith(Platform.pathSeparator)) {
      return Uri.directory(path);
    }
    return Uri.file(path);
  }

  String _jsonPathToString(List<Object> pathEnding) =>
      [...path, ...pathEnding].join('.');

  Never throwFormatException(
    Object? value,
    Type expectedType,
    List<Object> pathExtension, {
    RegExp? pattern,
  }) {
    throw FormatException(
      errorString(value, expectedType, pathExtension, pattern: pattern),
    );
  }

  String errorString(
    Object? value,
    Type expectedType,
    List<Object> pathExtension, {
    RegExp? pattern,
  }) {
    final pathString = _jsonPathToString(pathExtension);
    if (value == null) {
      return "No value was provided for '$pathString'."
          ' Expected a $expectedType.';
    }
    final satisfying = pattern == null ? '' : ' satisfying ${pattern.pattern}';
    return "Unexpected value '$value' (${value.runtimeType}) for '$pathString'."
        ' Expected a $expectedType$satisfying.';
  }

  String keyErrorString(
    String key, {
    required RegExp pattern,
    List<Object> pathExtension = const [],
  }) {
    final pathString = _jsonPathToString(pathExtension);
    return "Unexpected key '$key' in '$pathString'."
        ' Expected a key satisfying ${pattern.pattern}.';
  }

  /// Traverses a JSON path, returns `null` if the path cannot be traversed.
  Object? tryTraverse(List<String> path) {
    Object? json = this.json;
    for (final key in path) {
      if (json is! Map<String, Object?>) {
        return null;
      }
      json = json[key];
    }
    return json;
  }
}

extension on Map<String, Object?> {
  void setOrRemove(String key, Object? value) {
    if (value == null) {
      remove(key);
    } else {
      this[key] = value;
    }
  }
}

extension on List<Uri> {
  List<String> toJson() => [for (final uri in this) uri.toFilePath()];
}

extension<K extends Comparable<K>, V extends Object?> on Map<K, V> {
  void sortOnKey() {
    final result = <K, V>{};
    final keysSorted = keys.toList()..sort();
    for (final key in keysSorted) {
      result[key] = this[key] as V;
    }
    clear();
    addAll(result);
  }
}

void _checkArgumentMapKeys(Map<String, Object?>? map, {RegExp? keyPattern}) {
  if (map == null) return;
  if (keyPattern == null) return;
  for (final key in map.keys) {
    if (!keyPattern.hasMatch(key)) {
      throw ArgumentError.value(
        map,
        "Unexpected key '$key'."
        ' Expected a key satisfying ${keyPattern.pattern}.',
      );
    }
  }
}

void _checkArgumentMapStringElements(
  Map<String, String?>? map, {
  RegExp? valuePattern,
}) {
  if (map == null) return;
  if (valuePattern == null) return;
  for (final entry in map.entries) {
    final value = entry.value;
    if (value != null && !valuePattern.hasMatch(value)) {
      throw ArgumentError.value(
        map,
        "Unexpected value '$value' under key '${entry.key}'."
        ' Expected a value satisfying ${valuePattern.pattern}.',
      );
    }
  }
}
