diff --git a/packages/dynamite/dynamite/README.md b/packages/dynamite/dynamite/README.md index 020c3afb7df..2d481c23e23 100644 --- a/packages/dynamite/dynamite/README.md +++ b/packages/dynamite/dynamite/README.md @@ -53,6 +53,13 @@ targets: - 'factory .*\.fromJson\(Map json\) => jsonSerializers\.deserializeWith\(serializer, json\)!;' - 'Map toJson\(\) => jsonSerializers\.serializeWith\(serializer, this\)! as Map;' - 'static BuiltSet<.*> get values => _\$.*Values;' + overrides: + # Tighten linting rules for specific specs + # Mark the generated library as experimental + lib/my_spec.openapi.json: + analyzer_ignores: + - camel_case_types + experimental: true ``` diff --git a/packages/dynamite/dynamite/lib/src/models/dynamite_config/config.dart b/packages/dynamite/dynamite/lib/src/models/dynamite_config/config.dart index 6c6439087e4..3a47acfe4ca 100644 --- a/packages/dynamite/dynamite/lib/src/models/dynamite_config/config.dart +++ b/packages/dynamite/dynamite/lib/src/models/dynamite_config/config.dart @@ -33,6 +33,66 @@ abstract class DynamiteConfig implements Built? get overrides; + + /// Whether the generated library should be marked with the `@experimental` annotation. + bool get experimental; + + @BuiltValueHook(initializeBuilder: true) + static void _defaults(final DynamiteConfigBuilder b) { + b.experimental ??= false; + } + + /// Gets the config for the given [uri]. + /// + /// Returns this if no override is set. + DynamiteConfig configFor(final String uri) { + if (overrides == null) { + return this; + } + + DynamiteConfig? override; + for (final entry in overrides!.entries) { + if (entry.key == uri) { + override = entry.value; + break; + } + } + + if (override == null) { + return this; + } + + return merge(override); + } + + /// Merges `this` config with the given [override]. + /// + /// Throws a [ArgumentError] if the override has overrides itself. + DynamiteConfig merge(final DynamiteConfig other) { + if (other.overrides != null) { + throw ArgumentError('Configs can only be merged with a config that does not have further overrides'); + } + + return rebuild((final b) { + final analyzerIgnores = other.analyzerIgnores; + if (analyzerIgnores != null) { + b.analyzerIgnores.replace(analyzerIgnores); + } + + final coverageIgnores = other.coverageIgnores; + if (coverageIgnores != null) { + b.coverageIgnores.replace(coverageIgnores); + } + + b.experimental = other.experimental; + }); + } } @SerializersFor([ diff --git a/packages/dynamite/dynamite/lib/src/models/dynamite_config/config.g.dart b/packages/dynamite/dynamite/lib/src/models/dynamite_config/config.g.dart index 0903b8d2fc2..e988d30776d 100644 --- a/packages/dynamite/dynamite/lib/src/models/dynamite_config/config.g.dart +++ b/packages/dynamite/dynamite/lib/src/models/dynamite_config/config.g.dart @@ -9,7 +9,9 @@ part of 'config.dart'; Serializers _$_serializers = (Serializers().toBuilder() ..add(DynamiteConfig.serializer) ..addBuilderFactory(const FullType(BuiltSet, [FullType(String)]), () => SetBuilder()) - ..addBuilderFactory(const FullType(BuiltSet, [FullType(String)]), () => SetBuilder())) + ..addBuilderFactory(const FullType(BuiltSet, [FullType(String)]), () => SetBuilder()) + ..addBuilderFactory(const FullType(BuiltMap, [FullType(String), FullType(DynamiteConfig)]), + () => MapBuilder())) .build(); Serializer _$dynamiteConfigSerializer = _$DynamiteConfigSerializer(); @@ -22,7 +24,10 @@ class _$DynamiteConfigSerializer implements StructuredSerializer @override Iterable serialize(Serializers serializers, DynamiteConfig object, {FullType specifiedType = FullType.unspecified}) { - final result = []; + final result = [ + 'experimental', + serializers.serialize(object.experimental, specifiedType: const FullType(bool)), + ]; Object? value; value = object.analyzerIgnores; if (value != null) { @@ -42,6 +47,13 @@ class _$DynamiteConfigSerializer implements StructuredSerializer ..add('pageWidth') ..add(serializers.serialize(value, specifiedType: const FullType(int))); } + value = object.overrides; + if (value != null) { + result + ..add('overrides') + ..add(serializers.serialize(value, + specifiedType: const FullType(BuiltMap, [FullType(String), FullType(DynamiteConfig)]))); + } return result; } @@ -67,6 +79,13 @@ class _$DynamiteConfigSerializer implements StructuredSerializer case 'pageWidth': result.pageWidth = serializers.deserialize(value, specifiedType: const FullType(int)) as int?; break; + case 'overrides': + result.overrides.replace(serializers.deserialize(value, + specifiedType: const FullType(BuiltMap, [FullType(String), FullType(DynamiteConfig)]))!); + break; + case 'experimental': + result.experimental = serializers.deserialize(value, specifiedType: const FullType(bool))! as bool; + break; } } @@ -81,11 +100,19 @@ class _$DynamiteConfig extends DynamiteConfig { final BuiltSet? coverageIgnores; @override final int? pageWidth; + @override + final BuiltMap? overrides; + @override + final bool experimental; factory _$DynamiteConfig([void Function(DynamiteConfigBuilder)? updates]) => (DynamiteConfigBuilder()..update(updates))._build(); - _$DynamiteConfig._({this.analyzerIgnores, this.coverageIgnores, this.pageWidth}) : super._(); + _$DynamiteConfig._( + {this.analyzerIgnores, this.coverageIgnores, this.pageWidth, this.overrides, required this.experimental}) + : super._() { + BuiltValueNullFieldError.checkNotNull(experimental, r'DynamiteConfig', 'experimental'); + } @override DynamiteConfig rebuild(void Function(DynamiteConfigBuilder) updates) => (toBuilder()..update(updates)).build(); @@ -99,7 +126,9 @@ class _$DynamiteConfig extends DynamiteConfig { return other is DynamiteConfig && analyzerIgnores == other.analyzerIgnores && coverageIgnores == other.coverageIgnores && - pageWidth == other.pageWidth; + pageWidth == other.pageWidth && + overrides == other.overrides && + experimental == other.experimental; } @override @@ -108,6 +137,8 @@ class _$DynamiteConfig extends DynamiteConfig { _$hash = $jc(_$hash, analyzerIgnores.hashCode); _$hash = $jc(_$hash, coverageIgnores.hashCode); _$hash = $jc(_$hash, pageWidth.hashCode); + _$hash = $jc(_$hash, overrides.hashCode); + _$hash = $jc(_$hash, experimental.hashCode); _$hash = $jf(_$hash); return _$hash; } @@ -117,7 +148,9 @@ class _$DynamiteConfig extends DynamiteConfig { return (newBuiltValueToStringHelper(r'DynamiteConfig') ..add('analyzerIgnores', analyzerIgnores) ..add('coverageIgnores', coverageIgnores) - ..add('pageWidth', pageWidth)) + ..add('pageWidth', pageWidth) + ..add('overrides', overrides) + ..add('experimental', experimental)) .toString(); } } @@ -137,7 +170,17 @@ class DynamiteConfigBuilder implements Builder _$this._pageWidth; set pageWidth(int? pageWidth) => _$this._pageWidth = pageWidth; - DynamiteConfigBuilder(); + MapBuilder? _overrides; + MapBuilder get overrides => _$this._overrides ??= MapBuilder(); + set overrides(MapBuilder? overrides) => _$this._overrides = overrides; + + bool? _experimental; + bool? get experimental => _$this._experimental; + set experimental(bool? experimental) => _$this._experimental = experimental; + + DynamiteConfigBuilder() { + DynamiteConfig._defaults(this); + } DynamiteConfigBuilder get _$this { final $v = _$v; @@ -145,6 +188,8 @@ class DynamiteConfigBuilder implements Builder openapi.serializers.deserializeWith( openapi.OpenAPI.serializer, @@ -76,7 +76,8 @@ class OpenAPIBuilder implements Builder { throw Exception('Only OpenAPI between $minSupportedVersion and $maxSupportedVersion are supported.'); } - final state = State(buildConfig); + final config = buildConfig.configFor(inputId.path); + final state = State(config); final output = Library((final b) { final analyzerIgnores = state.buildConfig.analyzerIgnores; @@ -114,6 +115,12 @@ class OpenAPIBuilder implements Builder { Directive.part(p.basename(outputId.changeExtension('.g.dart').path)), ); } + + if (state.buildConfig.experimental) { + b.annotations.add( + refer('experimental'), + ); + } }); var outputString = output.accept(emitter).toString(); diff --git a/packages/nextcloud/build.yaml b/packages/nextcloud/build.yaml index 3b4aa1efd69..0c0851e2fe8 100644 --- a/packages/nextcloud/build.yaml +++ b/packages/nextcloud/build.yaml @@ -18,3 +18,10 @@ targets: - 'factory .*\.fromJson\(Map json\) => jsonSerializers\.deserializeWith\(serializer, json\)!;' - 'Map toJson\(\) => jsonSerializers\.serializeWith\(serializer, this\)! as Map;' - 'static BuiltSet<.*> get values => _\$.*Values;' + overrides: + lib/src/api/news.openapi.json: + experimental: true + lib/src/api/notes.openapi.json: + experimental: true + lib/src/api/uppush.openapi.json: + experimental: true diff --git a/packages/nextcloud/lib/src/api/news.openapi.dart b/packages/nextcloud/lib/src/api/news.openapi.dart index f9f5cdad44f..d39869fdff2 100644 --- a/packages/nextcloud/lib/src/api/news.openapi.dart +++ b/packages/nextcloud/lib/src/api/news.openapi.dart @@ -2,6 +2,7 @@ // ignore_for_file: no_leading_underscores_for_local_identifiers // ignore_for_file: public_member_api_docs, unreachable_switch_case +@experimental library news_openapi; import 'package:built_collection/built_collection.dart'; diff --git a/packages/nextcloud/lib/src/api/notes.openapi.dart b/packages/nextcloud/lib/src/api/notes.openapi.dart index 8f59b28093b..dd4de3ca4db 100644 --- a/packages/nextcloud/lib/src/api/notes.openapi.dart +++ b/packages/nextcloud/lib/src/api/notes.openapi.dart @@ -2,6 +2,7 @@ // ignore_for_file: no_leading_underscores_for_local_identifiers // ignore_for_file: public_member_api_docs, unreachable_switch_case +@experimental library notes_openapi; import 'dart:convert'; diff --git a/packages/nextcloud/lib/src/api/uppush.openapi.dart b/packages/nextcloud/lib/src/api/uppush.openapi.dart index adff598d0d1..373fd46be28 100644 --- a/packages/nextcloud/lib/src/api/uppush.openapi.dart +++ b/packages/nextcloud/lib/src/api/uppush.openapi.dart @@ -2,6 +2,7 @@ // ignore_for_file: no_leading_underscores_for_local_identifiers // ignore_for_file: public_member_api_docs, unreachable_switch_case +@experimental library uppush_openapi; import 'package:built_collection/built_collection.dart';