blob: 0feadbd2241af3444af252696fc1567298467e2a [file] [log] [blame] [edit]
// 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}.',
);
}
}
}