From 731406ccae3f5ba7d9c23a34f8a441e49a3993bd Mon Sep 17 00:00:00 2001
From: imprologic
Date: Sun, 14 Sep 2025 18:30:39 -0400
Subject: [PATCH 1/5] WIP commit
---
.github/workflows/dart.yaml | 26 +
README.md | 0
analysis_options.yaml | 4 +
example/main.dart | 9 +
lib/json_feed.dart | 34 +
lib/src/models.dart | 78 ++
lib/src/models.freezed.dart | 1477 +++++++++++++++++++++++++++++++++++
lib/src/models.g.dart | 126 +++
openai.md | 327 ++++++++
pubspec.yaml | 16 +
test/json_feed_test.dart | 22 +
11 files changed, 2119 insertions(+)
create mode 100644 .github/workflows/dart.yaml
create mode 100644 README.md
create mode 100644 analysis_options.yaml
create mode 100644 example/main.dart
create mode 100644 lib/json_feed.dart
create mode 100644 lib/src/models.dart
create mode 100644 lib/src/models.freezed.dart
create mode 100644 lib/src/models.g.dart
create mode 100644 openai.md
create mode 100644 pubspec.yaml
create mode 100644 test/json_feed_test.dart
diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml
new file mode 100644
index 0000000..69b9b65
--- /dev/null
+++ b/.github/workflows/dart.yaml
@@ -0,0 +1,26 @@
+name: Dart CI
+
+on:
+ push:
+ branches: [ main, master ]
+ pull_request:
+ branches: [ main, master ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ - uses: dart-lang/setup-dart@v1
+ with:
+ sdk: 'stable'
+
+ - name: Get dependencies
+ run: dart pub get
+
+ - name: Run codegen (build_runner)
+ run: dart run build_runner build --delete-conflicting-outputs
+
+ - name: Run tests
+ run: dart test -r expanded
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 0000000..238d889
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1,4 @@
+
+analyzer:
+ errors:
+ invalid_annotation_target: ignore
\ No newline at end of file
diff --git a/example/main.dart b/example/main.dart
new file mode 100644
index 0000000..d6ef700
--- /dev/null
+++ b/example/main.dart
@@ -0,0 +1,9 @@
+import 'package:json_feed/json_feed.dart';
+import 'dart:io';
+
+void main() {
+ final sample = File('example/sample_feed.json').readAsStringSync();
+ final feed = parseJsonFeed(sample);
+ print('Feed title: ${feed.title}');
+ print('Item count: ${feed.items.length}');
+}
diff --git a/lib/json_feed.dart b/lib/json_feed.dart
new file mode 100644
index 0000000..aa0fba3
--- /dev/null
+++ b/lib/json_feed.dart
@@ -0,0 +1,34 @@
+library json_feed;
+
+export 'src/models.dart';
+
+import 'dart:convert';
+
+import 'src/models.dart';
+
+class JsonFeedParseException implements Exception {
+ final String message;
+ JsonFeedParseException(this.message);
+ @override
+ String toString() => 'JsonFeedParseException: $message';
+}
+
+JsonFeed parseJsonFeed(String jsonString) {
+ final decoded = json.decode(jsonString);
+ if (decoded is! Map)
+ throw JsonFeedParseException('Top-level JSON must be an object.');
+
+ // validate minimal requirements per spec
+ final version = decoded['version'];
+ if (version is! String || version.isEmpty)
+ throw JsonFeedParseException('Missing required "version" string.');
+ final items = decoded['items'];
+ if (items is! List)
+ throw JsonFeedParseException('Missing required "items" array.');
+ // authors fallback and extension extraction can be added here
+
+ // Use generated fromJson
+ final feed = JsonFeed.fromJson(decoded);
+
+ return feed;
+}
diff --git a/lib/src/models.dart b/lib/src/models.dart
new file mode 100644
index 0000000..5d0eef0
--- /dev/null
+++ b/lib/src/models.dart
@@ -0,0 +1,78 @@
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+part 'models.freezed.dart';
+part 'models.g.dart';
+
+@freezed
+abstract class Author with _$Author {
+ const factory Author({String? name, String? url, String? avatar}) = _Author;
+
+ factory Author.fromJson(Map json) => _$AuthorFromJson(json);
+}
+
+@freezed
+abstract class Attachment with _$Attachment {
+ const factory Attachment({
+ required String url,
+ @JsonKey(name: 'mime_type') required String mimeType,
+ String? title,
+ @JsonKey(name: 'size_in_bytes') int? sizeInBytes,
+ @JsonKey(name: 'duration_in_seconds') double? durationInSeconds,
+ }) = _Attachment;
+
+ factory Attachment.fromJson(Map json) =>
+ _$AttachmentFromJson(json);
+}
+
+@freezed
+abstract class Hub with _$Hub {
+ const factory Hub({required String type, required String url}) = _Hub;
+
+ factory Hub.fromJson(Map json) => _$HubFromJson(json);
+}
+
+@freezed
+abstract class Item with _$Item {
+ const factory Item({
+ required String id,
+ String? url,
+ @JsonKey(name: 'external_url') String? externalUrl,
+ String? title,
+ @JsonKey(name: 'content_html') String? contentHtml,
+ @JsonKey(name: 'content_text') String? contentText,
+ String? summary,
+ String? image,
+ @JsonKey(name: 'banner_image') String? bannerImage,
+ @JsonKey(name: 'date_published') String? datePublished,
+ @JsonKey(name: 'date_modified') String? dateModified,
+ List? authors,
+ List? tags,
+ String? language,
+ List? attachments,
+ }) = _Item;
+
+ factory Item.fromJson(Map json) => _$ItemFromJson(json);
+}
+
+@freezed
+abstract class JsonFeed with _$JsonFeed {
+ const factory JsonFeed({
+ required String version,
+ required String title,
+ @JsonKey(name: 'home_page_url') String? homePageUrl,
+ @JsonKey(name: 'feed_url') String? feedUrl,
+ String? description,
+ @JsonKey(name: 'user_comment') String? userComment,
+ @JsonKey(name: 'next_url') String? nextUrl,
+ String? icon,
+ String? favicon,
+ List? authors,
+ String? language,
+ bool? expired,
+ List? hubs,
+ @Default([]) List- items,
+ }) = _JsonFeed;
+
+ factory JsonFeed.fromJson(Map json) =>
+ _$JsonFeedFromJson(json);
+}
diff --git a/lib/src/models.freezed.dart b/lib/src/models.freezed.dart
new file mode 100644
index 0000000..8902ffe
--- /dev/null
+++ b/lib/src/models.freezed.dart
@@ -0,0 +1,1477 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// coverage:ignore-file
+// ignore_for_file: type=lint
+// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
+
+part of 'models.dart';
+
+// **************************************************************************
+// FreezedGenerator
+// **************************************************************************
+
+// dart format off
+T _$identity(T value) => value;
+
+/// @nodoc
+mixin _$Author {
+
+ String? get name; String? get url; String? get avatar;
+/// Create a copy of Author
+/// with the given fields replaced by the non-null parameter values.
+@JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+$AuthorCopyWith get copyWith => _$AuthorCopyWithImpl(this as Author, _$identity);
+
+ /// Serializes this Author to a JSON map.
+ Map toJson();
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is Author&&(identical(other.name, name) || other.name == name)&&(identical(other.url, url) || other.url == url)&&(identical(other.avatar, avatar) || other.avatar == avatar));
+}
+
+@JsonKey(includeFromJson: false, includeToJson: false)
+@override
+int get hashCode => Object.hash(runtimeType,name,url,avatar);
+
+@override
+String toString() {
+ return 'Author(name: $name, url: $url, avatar: $avatar)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class $AuthorCopyWith<$Res> {
+ factory $AuthorCopyWith(Author value, $Res Function(Author) _then) = _$AuthorCopyWithImpl;
+@useResult
+$Res call({
+ String? name, String? url, String? avatar
+});
+
+
+
+
+}
+/// @nodoc
+class _$AuthorCopyWithImpl<$Res>
+ implements $AuthorCopyWith<$Res> {
+ _$AuthorCopyWithImpl(this._self, this._then);
+
+ final Author _self;
+ final $Res Function(Author) _then;
+
+/// Create a copy of Author
+/// with the given fields replaced by the non-null parameter values.
+@pragma('vm:prefer-inline') @override $Res call({Object? name = freezed,Object? url = freezed,Object? avatar = freezed,}) {
+ return _then(_self.copyWith(
+name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
+as String?,url: freezed == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
+as String?,avatar: freezed == avatar ? _self.avatar : avatar // ignore: cast_nullable_to_non_nullable
+as String?,
+ ));
+}
+
+}
+
+
+/// Adds pattern-matching-related methods to [Author].
+extension AuthorPatterns on Author {
+/// A variant of `map` that fallback to returning `orElse`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeMap(TResult Function( _Author value)? $default,{required TResult orElse(),}){
+final _that = this;
+switch (_that) {
+case _Author() when $default != null:
+return $default(_that);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// Callbacks receives the raw object, upcasted.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case final Subclass2 value:
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult map(TResult Function( _Author value) $default,){
+final _that = this;
+switch (_that) {
+case _Author():
+return $default(_that);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `map` that fallback to returning `null`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? mapOrNull(TResult? Function( _Author value)? $default,){
+final _that = this;
+switch (_that) {
+case _Author() when $default != null:
+return $default(_that);case _:
+ return null;
+
+}
+}
+/// A variant of `when` that fallback to an `orElse` callback.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeWhen(TResult Function( String? name, String? url, String? avatar)? $default,{required TResult orElse(),}) {final _that = this;
+switch (_that) {
+case _Author() when $default != null:
+return $default(_that.name,_that.url,_that.avatar);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// As opposed to `map`, this offers destructuring.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case Subclass2(:final field2):
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult when(TResult Function( String? name, String? url, String? avatar) $default,) {final _that = this;
+switch (_that) {
+case _Author():
+return $default(_that.name,_that.url,_that.avatar);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `when` that fallback to returning `null`
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? whenOrNull(TResult? Function( String? name, String? url, String? avatar)? $default,) {final _that = this;
+switch (_that) {
+case _Author() when $default != null:
+return $default(_that.name,_that.url,_that.avatar);case _:
+ return null;
+
+}
+}
+
+}
+
+/// @nodoc
+@JsonSerializable()
+
+class _Author implements Author {
+ const _Author({this.name, this.url, this.avatar});
+ factory _Author.fromJson(Map json) => _$AuthorFromJson(json);
+
+@override final String? name;
+@override final String? url;
+@override final String? avatar;
+
+/// Create a copy of Author
+/// with the given fields replaced by the non-null parameter values.
+@override @JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+_$AuthorCopyWith<_Author> get copyWith => __$AuthorCopyWithImpl<_Author>(this, _$identity);
+
+@override
+Map toJson() {
+ return _$AuthorToJson(this, );
+}
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is _Author&&(identical(other.name, name) || other.name == name)&&(identical(other.url, url) || other.url == url)&&(identical(other.avatar, avatar) || other.avatar == avatar));
+}
+
+@JsonKey(includeFromJson: false, includeToJson: false)
+@override
+int get hashCode => Object.hash(runtimeType,name,url,avatar);
+
+@override
+String toString() {
+ return 'Author(name: $name, url: $url, avatar: $avatar)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class _$AuthorCopyWith<$Res> implements $AuthorCopyWith<$Res> {
+ factory _$AuthorCopyWith(_Author value, $Res Function(_Author) _then) = __$AuthorCopyWithImpl;
+@override @useResult
+$Res call({
+ String? name, String? url, String? avatar
+});
+
+
+
+
+}
+/// @nodoc
+class __$AuthorCopyWithImpl<$Res>
+ implements _$AuthorCopyWith<$Res> {
+ __$AuthorCopyWithImpl(this._self, this._then);
+
+ final _Author _self;
+ final $Res Function(_Author) _then;
+
+/// Create a copy of Author
+/// with the given fields replaced by the non-null parameter values.
+@override @pragma('vm:prefer-inline') $Res call({Object? name = freezed,Object? url = freezed,Object? avatar = freezed,}) {
+ return _then(_Author(
+name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
+as String?,url: freezed == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
+as String?,avatar: freezed == avatar ? _self.avatar : avatar // ignore: cast_nullable_to_non_nullable
+as String?,
+ ));
+}
+
+
+}
+
+
+/// @nodoc
+mixin _$Attachment {
+
+ String get url;@JsonKey(name: 'mime_type') String get mimeType; String? get title;@JsonKey(name: 'size_in_bytes') int? get sizeInBytes;@JsonKey(name: 'duration_in_seconds') double? get durationInSeconds;
+/// Create a copy of Attachment
+/// with the given fields replaced by the non-null parameter values.
+@JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+$AttachmentCopyWith get copyWith => _$AttachmentCopyWithImpl(this as Attachment, _$identity);
+
+ /// Serializes this Attachment to a JSON map.
+ Map toJson();
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is Attachment&&(identical(other.url, url) || other.url == url)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.title, title) || other.title == title)&&(identical(other.sizeInBytes, sizeInBytes) || other.sizeInBytes == sizeInBytes)&&(identical(other.durationInSeconds, durationInSeconds) || other.durationInSeconds == durationInSeconds));
+}
+
+@JsonKey(includeFromJson: false, includeToJson: false)
+@override
+int get hashCode => Object.hash(runtimeType,url,mimeType,title,sizeInBytes,durationInSeconds);
+
+@override
+String toString() {
+ return 'Attachment(url: $url, mimeType: $mimeType, title: $title, sizeInBytes: $sizeInBytes, durationInSeconds: $durationInSeconds)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class $AttachmentCopyWith<$Res> {
+ factory $AttachmentCopyWith(Attachment value, $Res Function(Attachment) _then) = _$AttachmentCopyWithImpl;
+@useResult
+$Res call({
+ String url,@JsonKey(name: 'mime_type') String mimeType, String? title,@JsonKey(name: 'size_in_bytes') int? sizeInBytes,@JsonKey(name: 'duration_in_seconds') double? durationInSeconds
+});
+
+
+
+
+}
+/// @nodoc
+class _$AttachmentCopyWithImpl<$Res>
+ implements $AttachmentCopyWith<$Res> {
+ _$AttachmentCopyWithImpl(this._self, this._then);
+
+ final Attachment _self;
+ final $Res Function(Attachment) _then;
+
+/// Create a copy of Attachment
+/// with the given fields replaced by the non-null parameter values.
+@pragma('vm:prefer-inline') @override $Res call({Object? url = null,Object? mimeType = null,Object? title = freezed,Object? sizeInBytes = freezed,Object? durationInSeconds = freezed,}) {
+ return _then(_self.copyWith(
+url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
+as String,mimeType: null == mimeType ? _self.mimeType : mimeType // ignore: cast_nullable_to_non_nullable
+as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
+as String?,sizeInBytes: freezed == sizeInBytes ? _self.sizeInBytes : sizeInBytes // ignore: cast_nullable_to_non_nullable
+as int?,durationInSeconds: freezed == durationInSeconds ? _self.durationInSeconds : durationInSeconds // ignore: cast_nullable_to_non_nullable
+as double?,
+ ));
+}
+
+}
+
+
+/// Adds pattern-matching-related methods to [Attachment].
+extension AttachmentPatterns on Attachment {
+/// A variant of `map` that fallback to returning `orElse`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeMap(TResult Function( _Attachment value)? $default,{required TResult orElse(),}){
+final _that = this;
+switch (_that) {
+case _Attachment() when $default != null:
+return $default(_that);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// Callbacks receives the raw object, upcasted.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case final Subclass2 value:
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult map(TResult Function( _Attachment value) $default,){
+final _that = this;
+switch (_that) {
+case _Attachment():
+return $default(_that);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `map` that fallback to returning `null`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? mapOrNull(TResult? Function( _Attachment value)? $default,){
+final _that = this;
+switch (_that) {
+case _Attachment() when $default != null:
+return $default(_that);case _:
+ return null;
+
+}
+}
+/// A variant of `when` that fallback to an `orElse` callback.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeWhen(TResult Function( String url, @JsonKey(name: 'mime_type') String mimeType, String? title, @JsonKey(name: 'size_in_bytes') int? sizeInBytes, @JsonKey(name: 'duration_in_seconds') double? durationInSeconds)? $default,{required TResult orElse(),}) {final _that = this;
+switch (_that) {
+case _Attachment() when $default != null:
+return $default(_that.url,_that.mimeType,_that.title,_that.sizeInBytes,_that.durationInSeconds);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// As opposed to `map`, this offers destructuring.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case Subclass2(:final field2):
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult when(TResult Function( String url, @JsonKey(name: 'mime_type') String mimeType, String? title, @JsonKey(name: 'size_in_bytes') int? sizeInBytes, @JsonKey(name: 'duration_in_seconds') double? durationInSeconds) $default,) {final _that = this;
+switch (_that) {
+case _Attachment():
+return $default(_that.url,_that.mimeType,_that.title,_that.sizeInBytes,_that.durationInSeconds);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `when` that fallback to returning `null`
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? whenOrNull(TResult? Function( String url, @JsonKey(name: 'mime_type') String mimeType, String? title, @JsonKey(name: 'size_in_bytes') int? sizeInBytes, @JsonKey(name: 'duration_in_seconds') double? durationInSeconds)? $default,) {final _that = this;
+switch (_that) {
+case _Attachment() when $default != null:
+return $default(_that.url,_that.mimeType,_that.title,_that.sizeInBytes,_that.durationInSeconds);case _:
+ return null;
+
+}
+}
+
+}
+
+/// @nodoc
+@JsonSerializable()
+
+class _Attachment implements Attachment {
+ const _Attachment({required this.url, @JsonKey(name: 'mime_type') required this.mimeType, this.title, @JsonKey(name: 'size_in_bytes') this.sizeInBytes, @JsonKey(name: 'duration_in_seconds') this.durationInSeconds});
+ factory _Attachment.fromJson(Map json) => _$AttachmentFromJson(json);
+
+@override final String url;
+@override@JsonKey(name: 'mime_type') final String mimeType;
+@override final String? title;
+@override@JsonKey(name: 'size_in_bytes') final int? sizeInBytes;
+@override@JsonKey(name: 'duration_in_seconds') final double? durationInSeconds;
+
+/// Create a copy of Attachment
+/// with the given fields replaced by the non-null parameter values.
+@override @JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+_$AttachmentCopyWith<_Attachment> get copyWith => __$AttachmentCopyWithImpl<_Attachment>(this, _$identity);
+
+@override
+Map toJson() {
+ return _$AttachmentToJson(this, );
+}
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is _Attachment&&(identical(other.url, url) || other.url == url)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.title, title) || other.title == title)&&(identical(other.sizeInBytes, sizeInBytes) || other.sizeInBytes == sizeInBytes)&&(identical(other.durationInSeconds, durationInSeconds) || other.durationInSeconds == durationInSeconds));
+}
+
+@JsonKey(includeFromJson: false, includeToJson: false)
+@override
+int get hashCode => Object.hash(runtimeType,url,mimeType,title,sizeInBytes,durationInSeconds);
+
+@override
+String toString() {
+ return 'Attachment(url: $url, mimeType: $mimeType, title: $title, sizeInBytes: $sizeInBytes, durationInSeconds: $durationInSeconds)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class _$AttachmentCopyWith<$Res> implements $AttachmentCopyWith<$Res> {
+ factory _$AttachmentCopyWith(_Attachment value, $Res Function(_Attachment) _then) = __$AttachmentCopyWithImpl;
+@override @useResult
+$Res call({
+ String url,@JsonKey(name: 'mime_type') String mimeType, String? title,@JsonKey(name: 'size_in_bytes') int? sizeInBytes,@JsonKey(name: 'duration_in_seconds') double? durationInSeconds
+});
+
+
+
+
+}
+/// @nodoc
+class __$AttachmentCopyWithImpl<$Res>
+ implements _$AttachmentCopyWith<$Res> {
+ __$AttachmentCopyWithImpl(this._self, this._then);
+
+ final _Attachment _self;
+ final $Res Function(_Attachment) _then;
+
+/// Create a copy of Attachment
+/// with the given fields replaced by the non-null parameter values.
+@override @pragma('vm:prefer-inline') $Res call({Object? url = null,Object? mimeType = null,Object? title = freezed,Object? sizeInBytes = freezed,Object? durationInSeconds = freezed,}) {
+ return _then(_Attachment(
+url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
+as String,mimeType: null == mimeType ? _self.mimeType : mimeType // ignore: cast_nullable_to_non_nullable
+as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
+as String?,sizeInBytes: freezed == sizeInBytes ? _self.sizeInBytes : sizeInBytes // ignore: cast_nullable_to_non_nullable
+as int?,durationInSeconds: freezed == durationInSeconds ? _self.durationInSeconds : durationInSeconds // ignore: cast_nullable_to_non_nullable
+as double?,
+ ));
+}
+
+
+}
+
+
+/// @nodoc
+mixin _$Hub {
+
+ String get type; String get url;
+/// Create a copy of Hub
+/// with the given fields replaced by the non-null parameter values.
+@JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+$HubCopyWith get copyWith => _$HubCopyWithImpl(this as Hub, _$identity);
+
+ /// Serializes this Hub to a JSON map.
+ Map toJson();
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is Hub&&(identical(other.type, type) || other.type == type)&&(identical(other.url, url) || other.url == url));
+}
+
+@JsonKey(includeFromJson: false, includeToJson: false)
+@override
+int get hashCode => Object.hash(runtimeType,type,url);
+
+@override
+String toString() {
+ return 'Hub(type: $type, url: $url)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class $HubCopyWith<$Res> {
+ factory $HubCopyWith(Hub value, $Res Function(Hub) _then) = _$HubCopyWithImpl;
+@useResult
+$Res call({
+ String type, String url
+});
+
+
+
+
+}
+/// @nodoc
+class _$HubCopyWithImpl<$Res>
+ implements $HubCopyWith<$Res> {
+ _$HubCopyWithImpl(this._self, this._then);
+
+ final Hub _self;
+ final $Res Function(Hub) _then;
+
+/// Create a copy of Hub
+/// with the given fields replaced by the non-null parameter values.
+@pragma('vm:prefer-inline') @override $Res call({Object? type = null,Object? url = null,}) {
+ return _then(_self.copyWith(
+type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
+as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
+as String,
+ ));
+}
+
+}
+
+
+/// Adds pattern-matching-related methods to [Hub].
+extension HubPatterns on Hub {
+/// A variant of `map` that fallback to returning `orElse`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeMap(TResult Function( _Hub value)? $default,{required TResult orElse(),}){
+final _that = this;
+switch (_that) {
+case _Hub() when $default != null:
+return $default(_that);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// Callbacks receives the raw object, upcasted.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case final Subclass2 value:
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult map(TResult Function( _Hub value) $default,){
+final _that = this;
+switch (_that) {
+case _Hub():
+return $default(_that);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `map` that fallback to returning `null`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? mapOrNull(TResult? Function( _Hub value)? $default,){
+final _that = this;
+switch (_that) {
+case _Hub() when $default != null:
+return $default(_that);case _:
+ return null;
+
+}
+}
+/// A variant of `when` that fallback to an `orElse` callback.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeWhen(TResult Function( String type, String url)? $default,{required TResult orElse(),}) {final _that = this;
+switch (_that) {
+case _Hub() when $default != null:
+return $default(_that.type,_that.url);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// As opposed to `map`, this offers destructuring.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case Subclass2(:final field2):
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult when(TResult Function( String type, String url) $default,) {final _that = this;
+switch (_that) {
+case _Hub():
+return $default(_that.type,_that.url);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `when` that fallback to returning `null`
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? whenOrNull(TResult? Function( String type, String url)? $default,) {final _that = this;
+switch (_that) {
+case _Hub() when $default != null:
+return $default(_that.type,_that.url);case _:
+ return null;
+
+}
+}
+
+}
+
+/// @nodoc
+@JsonSerializable()
+
+class _Hub implements Hub {
+ const _Hub({required this.type, required this.url});
+ factory _Hub.fromJson(Map json) => _$HubFromJson(json);
+
+@override final String type;
+@override final String url;
+
+/// Create a copy of Hub
+/// with the given fields replaced by the non-null parameter values.
+@override @JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+_$HubCopyWith<_Hub> get copyWith => __$HubCopyWithImpl<_Hub>(this, _$identity);
+
+@override
+Map toJson() {
+ return _$HubToJson(this, );
+}
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is _Hub&&(identical(other.type, type) || other.type == type)&&(identical(other.url, url) || other.url == url));
+}
+
+@JsonKey(includeFromJson: false, includeToJson: false)
+@override
+int get hashCode => Object.hash(runtimeType,type,url);
+
+@override
+String toString() {
+ return 'Hub(type: $type, url: $url)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class _$HubCopyWith<$Res> implements $HubCopyWith<$Res> {
+ factory _$HubCopyWith(_Hub value, $Res Function(_Hub) _then) = __$HubCopyWithImpl;
+@override @useResult
+$Res call({
+ String type, String url
+});
+
+
+
+
+}
+/// @nodoc
+class __$HubCopyWithImpl<$Res>
+ implements _$HubCopyWith<$Res> {
+ __$HubCopyWithImpl(this._self, this._then);
+
+ final _Hub _self;
+ final $Res Function(_Hub) _then;
+
+/// Create a copy of Hub
+/// with the given fields replaced by the non-null parameter values.
+@override @pragma('vm:prefer-inline') $Res call({Object? type = null,Object? url = null,}) {
+ return _then(_Hub(
+type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
+as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
+as String,
+ ));
+}
+
+
+}
+
+
+/// @nodoc
+mixin _$Item {
+
+ String get id; String? get url;@JsonKey(name: 'external_url') String? get externalUrl; String? get title;@JsonKey(name: 'content_html') String? get contentHtml;@JsonKey(name: 'content_text') String? get contentText; String? get summary; String? get image;@JsonKey(name: 'banner_image') String? get bannerImage;@JsonKey(name: 'date_published') String? get datePublished;@JsonKey(name: 'date_modified') String? get dateModified; List? get authors; List? get tags; String? get language; List? get attachments;
+/// Create a copy of Item
+/// with the given fields replaced by the non-null parameter values.
+@JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+$ItemCopyWith
- get copyWith => _$ItemCopyWithImpl
- (this as Item, _$identity);
+
+ /// Serializes this Item to a JSON map.
+ Map toJson();
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is Item&&(identical(other.id, id) || other.id == id)&&(identical(other.url, url) || other.url == url)&&(identical(other.externalUrl, externalUrl) || other.externalUrl == externalUrl)&&(identical(other.title, title) || other.title == title)&&(identical(other.contentHtml, contentHtml) || other.contentHtml == contentHtml)&&(identical(other.contentText, contentText) || other.contentText == contentText)&&(identical(other.summary, summary) || other.summary == summary)&&(identical(other.image, image) || other.image == image)&&(identical(other.bannerImage, bannerImage) || other.bannerImage == bannerImage)&&(identical(other.datePublished, datePublished) || other.datePublished == datePublished)&&(identical(other.dateModified, dateModified) || other.dateModified == dateModified)&&const DeepCollectionEquality().equals(other.authors, authors)&&const DeepCollectionEquality().equals(other.tags, tags)&&(identical(other.language, language) || other.language == language)&&const DeepCollectionEquality().equals(other.attachments, attachments));
+}
+
+@JsonKey(includeFromJson: false, includeToJson: false)
+@override
+int get hashCode => Object.hash(runtimeType,id,url,externalUrl,title,contentHtml,contentText,summary,image,bannerImage,datePublished,dateModified,const DeepCollectionEquality().hash(authors),const DeepCollectionEquality().hash(tags),language,const DeepCollectionEquality().hash(attachments));
+
+@override
+String toString() {
+ return 'Item(id: $id, url: $url, externalUrl: $externalUrl, title: $title, contentHtml: $contentHtml, contentText: $contentText, summary: $summary, image: $image, bannerImage: $bannerImage, datePublished: $datePublished, dateModified: $dateModified, authors: $authors, tags: $tags, language: $language, attachments: $attachments)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class $ItemCopyWith<$Res> {
+ factory $ItemCopyWith(Item value, $Res Function(Item) _then) = _$ItemCopyWithImpl;
+@useResult
+$Res call({
+ String id, String? url,@JsonKey(name: 'external_url') String? externalUrl, String? title,@JsonKey(name: 'content_html') String? contentHtml,@JsonKey(name: 'content_text') String? contentText, String? summary, String? image,@JsonKey(name: 'banner_image') String? bannerImage,@JsonKey(name: 'date_published') String? datePublished,@JsonKey(name: 'date_modified') String? dateModified, List? authors, List? tags, String? language, List? attachments
+});
+
+
+
+
+}
+/// @nodoc
+class _$ItemCopyWithImpl<$Res>
+ implements $ItemCopyWith<$Res> {
+ _$ItemCopyWithImpl(this._self, this._then);
+
+ final Item _self;
+ final $Res Function(Item) _then;
+
+/// Create a copy of Item
+/// with the given fields replaced by the non-null parameter values.
+@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? url = freezed,Object? externalUrl = freezed,Object? title = freezed,Object? contentHtml = freezed,Object? contentText = freezed,Object? summary = freezed,Object? image = freezed,Object? bannerImage = freezed,Object? datePublished = freezed,Object? dateModified = freezed,Object? authors = freezed,Object? tags = freezed,Object? language = freezed,Object? attachments = freezed,}) {
+ return _then(_self.copyWith(
+id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
+as String,url: freezed == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
+as String?,externalUrl: freezed == externalUrl ? _self.externalUrl : externalUrl // ignore: cast_nullable_to_non_nullable
+as String?,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
+as String?,contentHtml: freezed == contentHtml ? _self.contentHtml : contentHtml // ignore: cast_nullable_to_non_nullable
+as String?,contentText: freezed == contentText ? _self.contentText : contentText // ignore: cast_nullable_to_non_nullable
+as String?,summary: freezed == summary ? _self.summary : summary // ignore: cast_nullable_to_non_nullable
+as String?,image: freezed == image ? _self.image : image // ignore: cast_nullable_to_non_nullable
+as String?,bannerImage: freezed == bannerImage ? _self.bannerImage : bannerImage // ignore: cast_nullable_to_non_nullable
+as String?,datePublished: freezed == datePublished ? _self.datePublished : datePublished // ignore: cast_nullable_to_non_nullable
+as String?,dateModified: freezed == dateModified ? _self.dateModified : dateModified // ignore: cast_nullable_to_non_nullable
+as String?,authors: freezed == authors ? _self.authors : authors // ignore: cast_nullable_to_non_nullable
+as List?,tags: freezed == tags ? _self.tags : tags // ignore: cast_nullable_to_non_nullable
+as List?,language: freezed == language ? _self.language : language // ignore: cast_nullable_to_non_nullable
+as String?,attachments: freezed == attachments ? _self.attachments : attachments // ignore: cast_nullable_to_non_nullable
+as List?,
+ ));
+}
+
+}
+
+
+/// Adds pattern-matching-related methods to [Item].
+extension ItemPatterns on Item {
+/// A variant of `map` that fallback to returning `orElse`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeMap(TResult Function( _Item value)? $default,{required TResult orElse(),}){
+final _that = this;
+switch (_that) {
+case _Item() when $default != null:
+return $default(_that);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// Callbacks receives the raw object, upcasted.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case final Subclass2 value:
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult map(TResult Function( _Item value) $default,){
+final _that = this;
+switch (_that) {
+case _Item():
+return $default(_that);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `map` that fallback to returning `null`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? mapOrNull(TResult? Function( _Item value)? $default,){
+final _that = this;
+switch (_that) {
+case _Item() when $default != null:
+return $default(_that);case _:
+ return null;
+
+}
+}
+/// A variant of `when` that fallback to an `orElse` callback.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String? url, @JsonKey(name: 'external_url') String? externalUrl, String? title, @JsonKey(name: 'content_html') String? contentHtml, @JsonKey(name: 'content_text') String? contentText, String? summary, String? image, @JsonKey(name: 'banner_image') String? bannerImage, @JsonKey(name: 'date_published') String? datePublished, @JsonKey(name: 'date_modified') String? dateModified, List? authors, List? tags, String? language, List? attachments)? $default,{required TResult orElse(),}) {final _that = this;
+switch (_that) {
+case _Item() when $default != null:
+return $default(_that.id,_that.url,_that.externalUrl,_that.title,_that.contentHtml,_that.contentText,_that.summary,_that.image,_that.bannerImage,_that.datePublished,_that.dateModified,_that.authors,_that.tags,_that.language,_that.attachments);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// As opposed to `map`, this offers destructuring.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case Subclass2(:final field2):
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult when(TResult Function( String id, String? url, @JsonKey(name: 'external_url') String? externalUrl, String? title, @JsonKey(name: 'content_html') String? contentHtml, @JsonKey(name: 'content_text') String? contentText, String? summary, String? image, @JsonKey(name: 'banner_image') String? bannerImage, @JsonKey(name: 'date_published') String? datePublished, @JsonKey(name: 'date_modified') String? dateModified, List? authors, List? tags, String? language, List? attachments) $default,) {final _that = this;
+switch (_that) {
+case _Item():
+return $default(_that.id,_that.url,_that.externalUrl,_that.title,_that.contentHtml,_that.contentText,_that.summary,_that.image,_that.bannerImage,_that.datePublished,_that.dateModified,_that.authors,_that.tags,_that.language,_that.attachments);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `when` that fallback to returning `null`
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String? url, @JsonKey(name: 'external_url') String? externalUrl, String? title, @JsonKey(name: 'content_html') String? contentHtml, @JsonKey(name: 'content_text') String? contentText, String? summary, String? image, @JsonKey(name: 'banner_image') String? bannerImage, @JsonKey(name: 'date_published') String? datePublished, @JsonKey(name: 'date_modified') String? dateModified, List? authors, List? tags, String? language, List? attachments)? $default,) {final _that = this;
+switch (_that) {
+case _Item() when $default != null:
+return $default(_that.id,_that.url,_that.externalUrl,_that.title,_that.contentHtml,_that.contentText,_that.summary,_that.image,_that.bannerImage,_that.datePublished,_that.dateModified,_that.authors,_that.tags,_that.language,_that.attachments);case _:
+ return null;
+
+}
+}
+
+}
+
+/// @nodoc
+@JsonSerializable()
+
+class _Item implements Item {
+ const _Item({required this.id, this.url, @JsonKey(name: 'external_url') this.externalUrl, this.title, @JsonKey(name: 'content_html') this.contentHtml, @JsonKey(name: 'content_text') this.contentText, this.summary, this.image, @JsonKey(name: 'banner_image') this.bannerImage, @JsonKey(name: 'date_published') this.datePublished, @JsonKey(name: 'date_modified') this.dateModified, final List? authors, final List? tags, this.language, final List? attachments}): _authors = authors,_tags = tags,_attachments = attachments;
+ factory _Item.fromJson(Map json) => _$ItemFromJson(json);
+
+@override final String id;
+@override final String? url;
+@override@JsonKey(name: 'external_url') final String? externalUrl;
+@override final String? title;
+@override@JsonKey(name: 'content_html') final String? contentHtml;
+@override@JsonKey(name: 'content_text') final String? contentText;
+@override final String? summary;
+@override final String? image;
+@override@JsonKey(name: 'banner_image') final String? bannerImage;
+@override@JsonKey(name: 'date_published') final String? datePublished;
+@override@JsonKey(name: 'date_modified') final String? dateModified;
+ final List? _authors;
+@override List? get authors {
+ final value = _authors;
+ if (value == null) return null;
+ if (_authors is EqualUnmodifiableListView) return _authors;
+ // ignore: implicit_dynamic_type
+ return EqualUnmodifiableListView(value);
+}
+
+ final List? _tags;
+@override List? get tags {
+ final value = _tags;
+ if (value == null) return null;
+ if (_tags is EqualUnmodifiableListView) return _tags;
+ // ignore: implicit_dynamic_type
+ return EqualUnmodifiableListView(value);
+}
+
+@override final String? language;
+ final List? _attachments;
+@override List? get attachments {
+ final value = _attachments;
+ if (value == null) return null;
+ if (_attachments is EqualUnmodifiableListView) return _attachments;
+ // ignore: implicit_dynamic_type
+ return EqualUnmodifiableListView(value);
+}
+
+
+/// Create a copy of Item
+/// with the given fields replaced by the non-null parameter values.
+@override @JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+_$ItemCopyWith<_Item> get copyWith => __$ItemCopyWithImpl<_Item>(this, _$identity);
+
+@override
+Map toJson() {
+ return _$ItemToJson(this, );
+}
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is _Item&&(identical(other.id, id) || other.id == id)&&(identical(other.url, url) || other.url == url)&&(identical(other.externalUrl, externalUrl) || other.externalUrl == externalUrl)&&(identical(other.title, title) || other.title == title)&&(identical(other.contentHtml, contentHtml) || other.contentHtml == contentHtml)&&(identical(other.contentText, contentText) || other.contentText == contentText)&&(identical(other.summary, summary) || other.summary == summary)&&(identical(other.image, image) || other.image == image)&&(identical(other.bannerImage, bannerImage) || other.bannerImage == bannerImage)&&(identical(other.datePublished, datePublished) || other.datePublished == datePublished)&&(identical(other.dateModified, dateModified) || other.dateModified == dateModified)&&const DeepCollectionEquality().equals(other._authors, _authors)&&const DeepCollectionEquality().equals(other._tags, _tags)&&(identical(other.language, language) || other.language == language)&&const DeepCollectionEquality().equals(other._attachments, _attachments));
+}
+
+@JsonKey(includeFromJson: false, includeToJson: false)
+@override
+int get hashCode => Object.hash(runtimeType,id,url,externalUrl,title,contentHtml,contentText,summary,image,bannerImage,datePublished,dateModified,const DeepCollectionEquality().hash(_authors),const DeepCollectionEquality().hash(_tags),language,const DeepCollectionEquality().hash(_attachments));
+
+@override
+String toString() {
+ return 'Item(id: $id, url: $url, externalUrl: $externalUrl, title: $title, contentHtml: $contentHtml, contentText: $contentText, summary: $summary, image: $image, bannerImage: $bannerImage, datePublished: $datePublished, dateModified: $dateModified, authors: $authors, tags: $tags, language: $language, attachments: $attachments)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class _$ItemCopyWith<$Res> implements $ItemCopyWith<$Res> {
+ factory _$ItemCopyWith(_Item value, $Res Function(_Item) _then) = __$ItemCopyWithImpl;
+@override @useResult
+$Res call({
+ String id, String? url,@JsonKey(name: 'external_url') String? externalUrl, String? title,@JsonKey(name: 'content_html') String? contentHtml,@JsonKey(name: 'content_text') String? contentText, String? summary, String? image,@JsonKey(name: 'banner_image') String? bannerImage,@JsonKey(name: 'date_published') String? datePublished,@JsonKey(name: 'date_modified') String? dateModified, List? authors, List? tags, String? language, List? attachments
+});
+
+
+
+
+}
+/// @nodoc
+class __$ItemCopyWithImpl<$Res>
+ implements _$ItemCopyWith<$Res> {
+ __$ItemCopyWithImpl(this._self, this._then);
+
+ final _Item _self;
+ final $Res Function(_Item) _then;
+
+/// Create a copy of Item
+/// with the given fields replaced by the non-null parameter values.
+@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? url = freezed,Object? externalUrl = freezed,Object? title = freezed,Object? contentHtml = freezed,Object? contentText = freezed,Object? summary = freezed,Object? image = freezed,Object? bannerImage = freezed,Object? datePublished = freezed,Object? dateModified = freezed,Object? authors = freezed,Object? tags = freezed,Object? language = freezed,Object? attachments = freezed,}) {
+ return _then(_Item(
+id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
+as String,url: freezed == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
+as String?,externalUrl: freezed == externalUrl ? _self.externalUrl : externalUrl // ignore: cast_nullable_to_non_nullable
+as String?,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
+as String?,contentHtml: freezed == contentHtml ? _self.contentHtml : contentHtml // ignore: cast_nullable_to_non_nullable
+as String?,contentText: freezed == contentText ? _self.contentText : contentText // ignore: cast_nullable_to_non_nullable
+as String?,summary: freezed == summary ? _self.summary : summary // ignore: cast_nullable_to_non_nullable
+as String?,image: freezed == image ? _self.image : image // ignore: cast_nullable_to_non_nullable
+as String?,bannerImage: freezed == bannerImage ? _self.bannerImage : bannerImage // ignore: cast_nullable_to_non_nullable
+as String?,datePublished: freezed == datePublished ? _self.datePublished : datePublished // ignore: cast_nullable_to_non_nullable
+as String?,dateModified: freezed == dateModified ? _self.dateModified : dateModified // ignore: cast_nullable_to_non_nullable
+as String?,authors: freezed == authors ? _self._authors : authors // ignore: cast_nullable_to_non_nullable
+as List?,tags: freezed == tags ? _self._tags : tags // ignore: cast_nullable_to_non_nullable
+as List?,language: freezed == language ? _self.language : language // ignore: cast_nullable_to_non_nullable
+as String?,attachments: freezed == attachments ? _self._attachments : attachments // ignore: cast_nullable_to_non_nullable
+as List?,
+ ));
+}
+
+
+}
+
+
+/// @nodoc
+mixin _$JsonFeed {
+
+ String get version; String get title;@JsonKey(name: 'home_page_url') String? get homePageUrl;@JsonKey(name: 'feed_url') String? get feedUrl; String? get description;@JsonKey(name: 'user_comment') String? get userComment;@JsonKey(name: 'next_url') String? get nextUrl; String? get icon; String? get favicon; List? get authors; String? get language; bool? get expired; List? get hubs; List
- get items;
+/// Create a copy of JsonFeed
+/// with the given fields replaced by the non-null parameter values.
+@JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+$JsonFeedCopyWith get copyWith => _$JsonFeedCopyWithImpl(this as JsonFeed, _$identity);
+
+ /// Serializes this JsonFeed to a JSON map.
+ Map toJson();
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is JsonFeed&&(identical(other.version, version) || other.version == version)&&(identical(other.title, title) || other.title == title)&&(identical(other.homePageUrl, homePageUrl) || other.homePageUrl == homePageUrl)&&(identical(other.feedUrl, feedUrl) || other.feedUrl == feedUrl)&&(identical(other.description, description) || other.description == description)&&(identical(other.userComment, userComment) || other.userComment == userComment)&&(identical(other.nextUrl, nextUrl) || other.nextUrl == nextUrl)&&(identical(other.icon, icon) || other.icon == icon)&&(identical(other.favicon, favicon) || other.favicon == favicon)&&const DeepCollectionEquality().equals(other.authors, authors)&&(identical(other.language, language) || other.language == language)&&(identical(other.expired, expired) || other.expired == expired)&&const DeepCollectionEquality().equals(other.hubs, hubs)&&const DeepCollectionEquality().equals(other.items, items));
+}
+
+@JsonKey(includeFromJson: false, includeToJson: false)
+@override
+int get hashCode => Object.hash(runtimeType,version,title,homePageUrl,feedUrl,description,userComment,nextUrl,icon,favicon,const DeepCollectionEquality().hash(authors),language,expired,const DeepCollectionEquality().hash(hubs),const DeepCollectionEquality().hash(items));
+
+@override
+String toString() {
+ return 'JsonFeed(version: $version, title: $title, homePageUrl: $homePageUrl, feedUrl: $feedUrl, description: $description, userComment: $userComment, nextUrl: $nextUrl, icon: $icon, favicon: $favicon, authors: $authors, language: $language, expired: $expired, hubs: $hubs, items: $items)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class $JsonFeedCopyWith<$Res> {
+ factory $JsonFeedCopyWith(JsonFeed value, $Res Function(JsonFeed) _then) = _$JsonFeedCopyWithImpl;
+@useResult
+$Res call({
+ String version, String title,@JsonKey(name: 'home_page_url') String? homePageUrl,@JsonKey(name: 'feed_url') String? feedUrl, String? description,@JsonKey(name: 'user_comment') String? userComment,@JsonKey(name: 'next_url') String? nextUrl, String? icon, String? favicon, List? authors, String? language, bool? expired, List? hubs, List
- items
+});
+
+
+
+
+}
+/// @nodoc
+class _$JsonFeedCopyWithImpl<$Res>
+ implements $JsonFeedCopyWith<$Res> {
+ _$JsonFeedCopyWithImpl(this._self, this._then);
+
+ final JsonFeed _self;
+ final $Res Function(JsonFeed) _then;
+
+/// Create a copy of JsonFeed
+/// with the given fields replaced by the non-null parameter values.
+@pragma('vm:prefer-inline') @override $Res call({Object? version = null,Object? title = null,Object? homePageUrl = freezed,Object? feedUrl = freezed,Object? description = freezed,Object? userComment = freezed,Object? nextUrl = freezed,Object? icon = freezed,Object? favicon = freezed,Object? authors = freezed,Object? language = freezed,Object? expired = freezed,Object? hubs = freezed,Object? items = null,}) {
+ return _then(_self.copyWith(
+version: null == version ? _self.version : version // ignore: cast_nullable_to_non_nullable
+as String,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
+as String,homePageUrl: freezed == homePageUrl ? _self.homePageUrl : homePageUrl // ignore: cast_nullable_to_non_nullable
+as String?,feedUrl: freezed == feedUrl ? _self.feedUrl : feedUrl // ignore: cast_nullable_to_non_nullable
+as String?,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
+as String?,userComment: freezed == userComment ? _self.userComment : userComment // ignore: cast_nullable_to_non_nullable
+as String?,nextUrl: freezed == nextUrl ? _self.nextUrl : nextUrl // ignore: cast_nullable_to_non_nullable
+as String?,icon: freezed == icon ? _self.icon : icon // ignore: cast_nullable_to_non_nullable
+as String?,favicon: freezed == favicon ? _self.favicon : favicon // ignore: cast_nullable_to_non_nullable
+as String?,authors: freezed == authors ? _self.authors : authors // ignore: cast_nullable_to_non_nullable
+as List?,language: freezed == language ? _self.language : language // ignore: cast_nullable_to_non_nullable
+as String?,expired: freezed == expired ? _self.expired : expired // ignore: cast_nullable_to_non_nullable
+as bool?,hubs: freezed == hubs ? _self.hubs : hubs // ignore: cast_nullable_to_non_nullable
+as List?,items: null == items ? _self.items : items // ignore: cast_nullable_to_non_nullable
+as List
- ,
+ ));
+}
+
+}
+
+
+/// Adds pattern-matching-related methods to [JsonFeed].
+extension JsonFeedPatterns on JsonFeed {
+/// A variant of `map` that fallback to returning `orElse`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeMap(TResult Function( _JsonFeed value)? $default,{required TResult orElse(),}){
+final _that = this;
+switch (_that) {
+case _JsonFeed() when $default != null:
+return $default(_that);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// Callbacks receives the raw object, upcasted.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case final Subclass2 value:
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult map(TResult Function( _JsonFeed value) $default,){
+final _that = this;
+switch (_that) {
+case _JsonFeed():
+return $default(_that);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `map` that fallback to returning `null`.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case final Subclass value:
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? mapOrNull(TResult? Function( _JsonFeed value)? $default,){
+final _that = this;
+switch (_that) {
+case _JsonFeed() when $default != null:
+return $default(_that);case _:
+ return null;
+
+}
+}
+/// A variant of `when` that fallback to an `orElse` callback.
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return orElse();
+/// }
+/// ```
+
+@optionalTypeArgs TResult maybeWhen(TResult Function( String version, String title, @JsonKey(name: 'home_page_url') String? homePageUrl, @JsonKey(name: 'feed_url') String? feedUrl, String? description, @JsonKey(name: 'user_comment') String? userComment, @JsonKey(name: 'next_url') String? nextUrl, String? icon, String? favicon, List? authors, String? language, bool? expired, List? hubs, List
- items)? $default,{required TResult orElse(),}) {final _that = this;
+switch (_that) {
+case _JsonFeed() when $default != null:
+return $default(_that.version,_that.title,_that.homePageUrl,_that.feedUrl,_that.description,_that.userComment,_that.nextUrl,_that.icon,_that.favicon,_that.authors,_that.language,_that.expired,_that.hubs,_that.items);case _:
+ return orElse();
+
+}
+}
+/// A `switch`-like method, using callbacks.
+///
+/// As opposed to `map`, this offers destructuring.
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case Subclass2(:final field2):
+/// return ...;
+/// }
+/// ```
+
+@optionalTypeArgs TResult when(TResult Function( String version, String title, @JsonKey(name: 'home_page_url') String? homePageUrl, @JsonKey(name: 'feed_url') String? feedUrl, String? description, @JsonKey(name: 'user_comment') String? userComment, @JsonKey(name: 'next_url') String? nextUrl, String? icon, String? favicon, List? authors, String? language, bool? expired, List? hubs, List
- items) $default,) {final _that = this;
+switch (_that) {
+case _JsonFeed():
+return $default(_that.version,_that.title,_that.homePageUrl,_that.feedUrl,_that.description,_that.userComment,_that.nextUrl,_that.icon,_that.favicon,_that.authors,_that.language,_that.expired,_that.hubs,_that.items);case _:
+ throw StateError('Unexpected subclass');
+
+}
+}
+/// A variant of `when` that fallback to returning `null`
+///
+/// It is equivalent to doing:
+/// ```dart
+/// switch (sealedClass) {
+/// case Subclass(:final field):
+/// return ...;
+/// case _:
+/// return null;
+/// }
+/// ```
+
+@optionalTypeArgs TResult? whenOrNull(TResult? Function( String version, String title, @JsonKey(name: 'home_page_url') String? homePageUrl, @JsonKey(name: 'feed_url') String? feedUrl, String? description, @JsonKey(name: 'user_comment') String? userComment, @JsonKey(name: 'next_url') String? nextUrl, String? icon, String? favicon, List? authors, String? language, bool? expired, List? hubs, List
- items)? $default,) {final _that = this;
+switch (_that) {
+case _JsonFeed() when $default != null:
+return $default(_that.version,_that.title,_that.homePageUrl,_that.feedUrl,_that.description,_that.userComment,_that.nextUrl,_that.icon,_that.favicon,_that.authors,_that.language,_that.expired,_that.hubs,_that.items);case _:
+ return null;
+
+}
+}
+
+}
+
+/// @nodoc
+@JsonSerializable()
+
+class _JsonFeed implements JsonFeed {
+ const _JsonFeed({required this.version, required this.title, @JsonKey(name: 'home_page_url') this.homePageUrl, @JsonKey(name: 'feed_url') this.feedUrl, this.description, @JsonKey(name: 'user_comment') this.userComment, @JsonKey(name: 'next_url') this.nextUrl, this.icon, this.favicon, final List? authors, this.language, this.expired, final List? hubs, final List
- items = const []}): _authors = authors,_hubs = hubs,_items = items;
+ factory _JsonFeed.fromJson(Map json) => _$JsonFeedFromJson(json);
+
+@override final String version;
+@override final String title;
+@override@JsonKey(name: 'home_page_url') final String? homePageUrl;
+@override@JsonKey(name: 'feed_url') final String? feedUrl;
+@override final String? description;
+@override@JsonKey(name: 'user_comment') final String? userComment;
+@override@JsonKey(name: 'next_url') final String? nextUrl;
+@override final String? icon;
+@override final String? favicon;
+ final List? _authors;
+@override List? get authors {
+ final value = _authors;
+ if (value == null) return null;
+ if (_authors is EqualUnmodifiableListView) return _authors;
+ // ignore: implicit_dynamic_type
+ return EqualUnmodifiableListView(value);
+}
+
+@override final String? language;
+@override final bool? expired;
+ final List? _hubs;
+@override List? get hubs {
+ final value = _hubs;
+ if (value == null) return null;
+ if (_hubs is EqualUnmodifiableListView) return _hubs;
+ // ignore: implicit_dynamic_type
+ return EqualUnmodifiableListView(value);
+}
+
+ final List
- _items;
+@override@JsonKey() List
- get items {
+ if (_items is EqualUnmodifiableListView) return _items;
+ // ignore: implicit_dynamic_type
+ return EqualUnmodifiableListView(_items);
+}
+
+
+/// Create a copy of JsonFeed
+/// with the given fields replaced by the non-null parameter values.
+@override @JsonKey(includeFromJson: false, includeToJson: false)
+@pragma('vm:prefer-inline')
+_$JsonFeedCopyWith<_JsonFeed> get copyWith => __$JsonFeedCopyWithImpl<_JsonFeed>(this, _$identity);
+
+@override
+Map toJson() {
+ return _$JsonFeedToJson(this, );
+}
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is _JsonFeed&&(identical(other.version, version) || other.version == version)&&(identical(other.title, title) || other.title == title)&&(identical(other.homePageUrl, homePageUrl) || other.homePageUrl == homePageUrl)&&(identical(other.feedUrl, feedUrl) || other.feedUrl == feedUrl)&&(identical(other.description, description) || other.description == description)&&(identical(other.userComment, userComment) || other.userComment == userComment)&&(identical(other.nextUrl, nextUrl) || other.nextUrl == nextUrl)&&(identical(other.icon, icon) || other.icon == icon)&&(identical(other.favicon, favicon) || other.favicon == favicon)&&const DeepCollectionEquality().equals(other._authors, _authors)&&(identical(other.language, language) || other.language == language)&&(identical(other.expired, expired) || other.expired == expired)&&const DeepCollectionEquality().equals(other._hubs, _hubs)&&const DeepCollectionEquality().equals(other._items, _items));
+}
+
+@JsonKey(includeFromJson: false, includeToJson: false)
+@override
+int get hashCode => Object.hash(runtimeType,version,title,homePageUrl,feedUrl,description,userComment,nextUrl,icon,favicon,const DeepCollectionEquality().hash(_authors),language,expired,const DeepCollectionEquality().hash(_hubs),const DeepCollectionEquality().hash(_items));
+
+@override
+String toString() {
+ return 'JsonFeed(version: $version, title: $title, homePageUrl: $homePageUrl, feedUrl: $feedUrl, description: $description, userComment: $userComment, nextUrl: $nextUrl, icon: $icon, favicon: $favicon, authors: $authors, language: $language, expired: $expired, hubs: $hubs, items: $items)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class _$JsonFeedCopyWith<$Res> implements $JsonFeedCopyWith<$Res> {
+ factory _$JsonFeedCopyWith(_JsonFeed value, $Res Function(_JsonFeed) _then) = __$JsonFeedCopyWithImpl;
+@override @useResult
+$Res call({
+ String version, String title,@JsonKey(name: 'home_page_url') String? homePageUrl,@JsonKey(name: 'feed_url') String? feedUrl, String? description,@JsonKey(name: 'user_comment') String? userComment,@JsonKey(name: 'next_url') String? nextUrl, String? icon, String? favicon, List? authors, String? language, bool? expired, List? hubs, List
- items
+});
+
+
+
+
+}
+/// @nodoc
+class __$JsonFeedCopyWithImpl<$Res>
+ implements _$JsonFeedCopyWith<$Res> {
+ __$JsonFeedCopyWithImpl(this._self, this._then);
+
+ final _JsonFeed _self;
+ final $Res Function(_JsonFeed) _then;
+
+/// Create a copy of JsonFeed
+/// with the given fields replaced by the non-null parameter values.
+@override @pragma('vm:prefer-inline') $Res call({Object? version = null,Object? title = null,Object? homePageUrl = freezed,Object? feedUrl = freezed,Object? description = freezed,Object? userComment = freezed,Object? nextUrl = freezed,Object? icon = freezed,Object? favicon = freezed,Object? authors = freezed,Object? language = freezed,Object? expired = freezed,Object? hubs = freezed,Object? items = null,}) {
+ return _then(_JsonFeed(
+version: null == version ? _self.version : version // ignore: cast_nullable_to_non_nullable
+as String,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
+as String,homePageUrl: freezed == homePageUrl ? _self.homePageUrl : homePageUrl // ignore: cast_nullable_to_non_nullable
+as String?,feedUrl: freezed == feedUrl ? _self.feedUrl : feedUrl // ignore: cast_nullable_to_non_nullable
+as String?,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
+as String?,userComment: freezed == userComment ? _self.userComment : userComment // ignore: cast_nullable_to_non_nullable
+as String?,nextUrl: freezed == nextUrl ? _self.nextUrl : nextUrl // ignore: cast_nullable_to_non_nullable
+as String?,icon: freezed == icon ? _self.icon : icon // ignore: cast_nullable_to_non_nullable
+as String?,favicon: freezed == favicon ? _self.favicon : favicon // ignore: cast_nullable_to_non_nullable
+as String?,authors: freezed == authors ? _self._authors : authors // ignore: cast_nullable_to_non_nullable
+as List?,language: freezed == language ? _self.language : language // ignore: cast_nullable_to_non_nullable
+as String?,expired: freezed == expired ? _self.expired : expired // ignore: cast_nullable_to_non_nullable
+as bool?,hubs: freezed == hubs ? _self._hubs : hubs // ignore: cast_nullable_to_non_nullable
+as List?,items: null == items ? _self._items : items // ignore: cast_nullable_to_non_nullable
+as List
- ,
+ ));
+}
+
+
+}
+
+// dart format on
diff --git a/lib/src/models.g.dart b/lib/src/models.g.dart
new file mode 100644
index 0000000..ddb30e3
--- /dev/null
+++ b/lib/src/models.g.dart
@@ -0,0 +1,126 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'models.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+_Author _$AuthorFromJson(Map json) => _Author(
+ name: json['name'] as String?,
+ url: json['url'] as String?,
+ avatar: json['avatar'] as String?,
+);
+
+Map _$AuthorToJson(_Author instance) => {
+ 'name': instance.name,
+ 'url': instance.url,
+ 'avatar': instance.avatar,
+};
+
+_Attachment _$AttachmentFromJson(Map json) => _Attachment(
+ url: json['url'] as String,
+ mimeType: json['mime_type'] as String,
+ title: json['title'] as String?,
+ sizeInBytes: (json['size_in_bytes'] as num?)?.toInt(),
+ durationInSeconds: (json['duration_in_seconds'] as num?)?.toDouble(),
+);
+
+Map _$AttachmentToJson(_Attachment instance) =>
+ {
+ 'url': instance.url,
+ 'mime_type': instance.mimeType,
+ 'title': instance.title,
+ 'size_in_bytes': instance.sizeInBytes,
+ 'duration_in_seconds': instance.durationInSeconds,
+ };
+
+_Hub _$HubFromJson(Map json) =>
+ _Hub(type: json['type'] as String, url: json['url'] as String);
+
+Map _$HubToJson(_Hub instance) => {
+ 'type': instance.type,
+ 'url': instance.url,
+};
+
+_Item _$ItemFromJson(Map json) => _Item(
+ id: json['id'] as String,
+ url: json['url'] as String?,
+ externalUrl: json['external_url'] as String?,
+ title: json['title'] as String?,
+ contentHtml: json['content_html'] as String?,
+ contentText: json['content_text'] as String?,
+ summary: json['summary'] as String?,
+ image: json['image'] as String?,
+ bannerImage: json['banner_image'] as String?,
+ datePublished: json['date_published'] as String?,
+ dateModified: json['date_modified'] as String?,
+ authors: (json['authors'] as List?)
+ ?.map((e) => Author.fromJson(e as Map))
+ .toList(),
+ tags: (json['tags'] as List?)?.map((e) => e as String).toList(),
+ language: json['language'] as String?,
+ attachments: (json['attachments'] as List?)
+ ?.map((e) => Attachment.fromJson(e as Map))
+ .toList(),
+);
+
+Map _$ItemToJson(_Item instance) => {
+ 'id': instance.id,
+ 'url': instance.url,
+ 'external_url': instance.externalUrl,
+ 'title': instance.title,
+ 'content_html': instance.contentHtml,
+ 'content_text': instance.contentText,
+ 'summary': instance.summary,
+ 'image': instance.image,
+ 'banner_image': instance.bannerImage,
+ 'date_published': instance.datePublished,
+ 'date_modified': instance.dateModified,
+ 'authors': instance.authors,
+ 'tags': instance.tags,
+ 'language': instance.language,
+ 'attachments': instance.attachments,
+};
+
+_JsonFeed _$JsonFeedFromJson(Map json) => _JsonFeed(
+ version: json['version'] as String,
+ title: json['title'] as String,
+ homePageUrl: json['home_page_url'] as String?,
+ feedUrl: json['feed_url'] as String?,
+ description: json['description'] as String?,
+ userComment: json['user_comment'] as String?,
+ nextUrl: json['next_url'] as String?,
+ icon: json['icon'] as String?,
+ favicon: json['favicon'] as String?,
+ authors: (json['authors'] as List?)
+ ?.map((e) => Author.fromJson(e as Map))
+ .toList(),
+ language: json['language'] as String?,
+ expired: json['expired'] as bool?,
+ hubs: (json['hubs'] as List?)
+ ?.map((e) => Hub.fromJson(e as Map))
+ .toList(),
+ items:
+ (json['items'] as List?)
+ ?.map((e) => Item.fromJson(e as Map))
+ .toList() ??
+ const [],
+);
+
+Map _$JsonFeedToJson(_JsonFeed instance) => {
+ 'version': instance.version,
+ 'title': instance.title,
+ 'home_page_url': instance.homePageUrl,
+ 'feed_url': instance.feedUrl,
+ 'description': instance.description,
+ 'user_comment': instance.userComment,
+ 'next_url': instance.nextUrl,
+ 'icon': instance.icon,
+ 'favicon': instance.favicon,
+ 'authors': instance.authors,
+ 'language': instance.language,
+ 'expired': instance.expired,
+ 'hubs': instance.hubs,
+ 'items': instance.items,
+};
diff --git a/openai.md b/openai.md
new file mode 100644
index 0000000..be7c00a
--- /dev/null
+++ b/openai.md
@@ -0,0 +1,327 @@
+# json\_feed\_package
+
+A small Dart package that implements JSON Feed v1.1 models + parsing using `freezed` and `json_serializable`, ready for codegen, tests and CI.
+
+---
+
+## File tree
+
+```
+json_feed/
+├── LICENSE
+├── README.md
+├── analysis_options.yaml
+├── pubspec.yaml
+├── lib/
+│ ├── json_feed.dart
+│ └── src/
+│ └── models.dart
+├── example/
+│ └── main.dart
+├── test/
+│ └── json_feed_test.dart
+└── .github/
+ └── workflows/
+ └── dart.yml
+```
+
+---
+
+## LICENSE
+
+> MIT License
+
+(Include MIT license text in your repository.)
+
+---
+
+## README.md
+
+A short README with usage and commands to run.
+
+---
+
+## pubspec.yaml
+
+```yaml
+name: json_feed
+description: A Dart implementation of JSON Feed v1.1 with freezed/json_serializable codegen.
+version: 0.1.0
+homepage: https://example.org/json_feed
+environment:
+ sdk: '>=2.18.0 <4.0.0'
+
+dependencies:
+ freezed_annotation: ^2.2.0
+ json_annotation: ^4.8.0
+
+dev_dependencies:
+ build_runner: ^2.4.6
+ freezed: ^2.2.0
+ json_serializable: ^6.6.1
+ test: ^1.24.0
+
+# optional: classifier and authors
+
+```
+
+---
+
+## analysis\_options.yaml
+
+```yaml
+include: package:pedantic/analysis_options.yaml
+
+# You can customize rules here if you prefer.
+```
+
+---
+
+## lib/src/models.dart
+
+This file contains the `freezed` annotated models used by the package. It declares the `JsonFeed`, `Item`, `Author`, `Attachment`, and `Hub` classes.
+
+```dart
+// lib/src/models.dart
+
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+part 'models.freezed.dart';
+part 'models.g.dart';
+
+@freezed
+class JsonFeed with _$_JsonFeed {
+ @JsonSerializable(explicitToJson: true)
+ const factory JsonFeed({
+ required String version,
+ required String title,
+ @JsonKey(name: 'home_page_url') String? homePageUrl,
+ @JsonKey(name: 'feed_url') String? feedUrl,
+ String? description,
+ @JsonKey(name: 'user_comment') String? userComment,
+ @JsonKey(name: 'next_url') String? nextUrl,
+ String? icon,
+ String? favicon,
+ @JsonKey(defaultValue: []) List authors,
+ String? language,
+ bool? expired,
+ @JsonKey(defaultValue: []) List hubs,
+ @JsonKey(defaultValue:
- []) List
- items,
+ // capture extension keys starting with '_' in a map
+ @JsonKey(name: '_extensions') @JsonKey(ignore: true) Map? extensions,
+ }) = _JsonFeed;
+
+ factory JsonFeed.fromJson(Map json) => _$JsonFeedFromJson(json);
+}
+
+@freezed
+class Author with _$_Author {
+ @JsonSerializable()
+ const factory Author({
+ String? name,
+ String? url,
+ String? avatar,
+ @JsonKey(ignore: true) Map? extras,
+ }) = _Author;
+
+ factory Author.fromJson(Map json) => _$AuthorFromJson(json);
+}
+
+@freezed
+class Hub with _$_Hub {
+ @JsonSerializable()
+ const factory Hub({
+ required String type,
+ required String url,
+ }) = _Hub;
+
+ factory Hub.fromJson(Map json) => _$HubFromJson(json);
+}
+
+@freezed
+class Attachment with _$_Attachment {
+ @JsonSerializable()
+ const factory Attachment({
+ required String url,
+ @JsonKey(name: 'mime_type') required String mimeType,
+ String? title,
+ @JsonKey(name: 'size_in_bytes') int? sizeInBytes,
+ @JsonKey(name: 'duration_in_seconds') double? durationInSeconds,
+ @JsonKey(ignore: true) Map? extras,
+ }) = _Attachment;
+
+ factory Attachment.fromJson(Map json) => _$AttachmentFromJson(json);
+}
+
+@freezed
+class Item with _$_Item {
+ @JsonSerializable(explicitToJson: true)
+ const factory Item({
+ required String id,
+ String? url,
+ @JsonKey(name: 'external_url') String? externalUrl,
+ String? title,
+ @JsonKey(name: 'content_html') String? contentHtml,
+ @JsonKey(name: 'content_text') String? contentText,
+ String? summary,
+ String? image,
+ @JsonKey(name: 'banner_image') String? bannerImage,
+ @JsonKey(name: 'date_published') String? datePublished,
+ @JsonKey(name: 'date_modified') String? dateModified,
+ @JsonKey(defaultValue: []) List authors,
+ @JsonKey(defaultValue: []) List tags,
+ String? language,
+ @JsonKey(defaultValue: []) List attachments,
+ @JsonKey(ignore: true) Map? extensions,
+ }) = _Item;
+
+ factory Item.fromJson(Map json) => _$ItemFromJson(json);
+}
+```
+
+Notes:
+
+* `extensions` / `extras` fields are marked `ignore` so that the generated `fromJson`/`toJson` don't expect them. We'll populate them manually in a top-level parsing helper if you want to preserve `_`-prefixed keys.
+* Dates are kept as strings for simple parsing; you can add custom converters if you prefer `DateTime` fields.
+
+---
+
+## lib/json\_feed.dart
+
+Top-level helpers to parse/validate the feed and to preserve `_`-prefixed extension keys.
+
+```dart
+// lib/json_feed.dart
+
+library json_feed;
+
+export 'src/models.dart';
+
+import 'dart:convert';
+
+import 'src/models.dart';
+
+class JsonFeedParseException implements Exception {
+ final String message;
+ JsonFeedParseException(this.message);
+ @override
+ String toString() => 'JsonFeedParseException: $message';
+}
+
+JsonFeed parseJsonFeed(String jsonString) {
+ final decoded = json.decode(jsonString);
+ if (decoded is! Map) throw JsonFeedParseException('Top-level JSON must be an object.');
+
+ // validate minimal requirements per spec
+ final version = decoded['version'];
+ if (version is! String || version.isEmpty) throw JsonFeedParseException('Missing required "version" string.');
+ final items = decoded['items'];
+ if (items is! List) throw JsonFeedParseException('Missing required "items" array.');
+ // authors fallback and extension extraction can be added here
+
+ // Use generated fromJson
+ final feed = JsonFeed.fromJson(decoded);
+
+ // TODO: populate ignored extensions/extras if needed by scanning keys starting with '_'
+
+ return feed;
+}
+```
+
+---
+
+## example/main.dart
+
+```dart
+import 'package:json_feed/json_feed.dart';
+import 'dart:io';
+
+void main() {
+ final sample = File('example/sample_feed.json').readAsStringSync();
+ final feed = parseJsonFeed(sample);
+ print('Feed title: ${feed.title}');
+ print('Item count: ${feed.items.length}');
+}
+```
+
+---
+
+## test/json\_feed\_test.dart
+
+A small unit test that runs the generator and validates parsing of a minimal JSON Feed.
+
+```dart
+import 'package:test/test.dart';
+import 'package:json_feed/json_feed.dart';
+
+void main() {
+ test('parse minimal feed', () {
+ final json = '''{
+ "version": "https://jsonfeed.org/version/1.1",
+ "title": "Example Feed",
+ "items": [
+ {
+ "id": "1",
+ "content_text": "Hello world"
+ }
+ ]
+ }''';
+
+ final feed = parseJsonFeed(json);
+ expect(feed.version, isNotEmpty);
+ expect(feed.items, isNotEmpty);
+ expect(feed.items.first.id, '1');
+ });
+}
+```
+
+---
+
+## .github/workflows/dart.yml
+
+```yaml
+name: Dart CI
+
+on:
+ push:
+ branches: [ main, master ]
+ pull_request:
+ branches: [ main, master ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ - uses: dart-lang/setup-dart@v1
+ with:
+ sdk: 'stable'
+
+ - name: Get dependencies
+ run: dart pub get
+
+ - name: Run codegen (build_runner)
+ run: dart run build_runner build --delete-conflicting-outputs
+
+ - name: Run tests
+ run: dart test -r expanded
+```
+
+---
+
+## How to use locally
+
+1. `dart pub get`
+2. `dart run build_runner build --delete-conflicting-outputs` (generates `*.g.dart` and `*.freezed.dart`)
+3. `dart test`
+
+---
+
+If you'd like I can:
+
+* include custom `JsonKey` `fromJson`/`toJson` converters for `DateTime` fields,
+* implement preservation of `_`-prefixed extension keys into `extensions` maps, and
+* produce `examples/sample_feed.json` with a fuller sample feed used by tests.
+
+Tell me which of those you'd like next and I will add them.
diff --git a/pubspec.yaml b/pubspec.yaml
new file mode 100644
index 0000000..36660c4
--- /dev/null
+++ b/pubspec.yaml
@@ -0,0 +1,16 @@
+name: json_feed
+description: A Dart implementation of JSON Feed v1.1 with freezed/json_serializable codegen.
+version: 0.1.0
+homepage: https://example.org/json_feed
+environment:
+ sdk: '>=3.8.0<4.0.0'
+
+dependencies:
+ freezed_annotation: ^3.1.0
+ json_annotation: ^4.9.0
+
+dev_dependencies:
+ test: ^1.24.0
+ build_runner: ^2.8.0
+ freezed: ^3.2.3
+ json_serializable: ^6.11.1
diff --git a/test/json_feed_test.dart b/test/json_feed_test.dart
new file mode 100644
index 0000000..e8d365b
--- /dev/null
+++ b/test/json_feed_test.dart
@@ -0,0 +1,22 @@
+import 'package:test/test.dart';
+import 'package:json_feed/json_feed.dart';
+
+void main() {
+ test('parse minimal feed', () {
+ final json = '''{
+ "version": "https://jsonfeed.org/version/1.1",
+ "title": "Example Feed",
+ "items": [
+ {
+ "id": "1",
+ "content_text": "Hello world"
+ }
+ ]
+ }''';
+
+ final feed = parseJsonFeed(json);
+ expect(feed.version, isNotEmpty);
+ expect(feed.items, isNotEmpty);
+ expect(feed.items.first.id, '1');
+ });
+}
From e28af1d0f952d0ec1f5248c67a93d11dff51140e Mon Sep 17 00:00:00 2001
From: imprologic
Date: Sun, 14 Sep 2025 18:51:20 -0400
Subject: [PATCH 2/5] added a more complex test
---
.DS_Store | Bin 0 -> 6148 bytes
test/json_feed_test.dart | 107 +++++++++++++++++++++++++++++++++++++++
2 files changed, 107 insertions(+)
create mode 100644 .DS_Store
diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..e3a74312ca754ea3256121dc077f0dd3794315b8
GIT binary patch
literal 6148
zcmeHK%}T>S5Z-O0CKMqD1-%8lR&8sw2QMMk7cim+m70)JgE3p0)Er77cYPsW#OHBl
zcOw?-Rm9G~?l-@?*$=Wmj4|#_qc&qUW6Xqx$Wd7$=w2GC>10HXV}wOE4igcA{ib7o
z9q`)?cECm~X8G6e564NI<*n8`uhosU^$pWB8|Iz=APPSZ@@eJ;lN+=yg-F6m55lW>
zSPbl~Gm+*&oDL_lAdZHRa(f-8ktjSdO`}ZK`YK>rmNl?jjj=)#tS9yfQ05L!e5CbdA
zfIbq;#>z543nvDMfu9(_{lS5T=xQt#%B=%Bygp;xKtur@-x7$9Mpt905F#L4l>(|#
zuAdlOm4n~Wd9KD%p(dLh7{6B|ZX6Yk;
zv4kvQfEf5^3~;0G_dQsYK3l&n56@Z$+C4NB%qvj=0e#^T00!Hello world
",
+ "content_text": "Hello world",
+ "summary": "Summary of item 1",
+ "image": "https://example.com/image1.png",
+ "banner_image": "https://example.com/banner1.png",
+ "date_published": "2023-01-01T12:00:00Z",
+ "date_modified": "2023-01-02T12:00:00Z",
+ "authors": [
+ {
+ "name": "Jane Doe",
+ "url": "https://example.com/jane",
+ "avatar": "https://example.com/jane.jpg"
+ }
+ ],
+ "tags": ["tag1", "tag2"],
+ "language": "en",
+ "attachments": [
+ {
+ "url": "https://example.com/audio.mp3",
+ "mime_type": "audio/mpeg",
+ "title": "Audio",
+ "size_in_bytes": 123456,
+ "duration_in_seconds": 120.5
+ }
+ ]
+ }
+ ]
+ }''';
+
+ final feed = parseJsonFeed(json);
+ expect(feed.version, equals("https://jsonfeed.org/version/1.1"));
+ expect(feed.title, equals("Complete Feed"));
+ expect(feed.homePageUrl, equals("https://example.com/"));
+ expect(feed.feedUrl, equals("https://example.com/feed.json"));
+ expect(feed.description, equals("A complete example feed"));
+ expect(feed.userComment, equals("This is a user comment."));
+ expect(feed.nextUrl, equals("https://example.com/feed.json?page=2"));
+ expect(feed.icon, equals("https://example.com/icon.png"));
+ expect(feed.favicon, equals("https://example.com/favicon.ico"));
+ expect(feed.authors, isNotNull);
+ expect(feed.authors!.first.name, equals("Jane Doe"));
+ expect(feed.language, equals("en"));
+ expect(feed.expired, isFalse);
+ expect(feed.hubs, isNotNull);
+ expect(feed.hubs!.first.type, equals("WebSub"));
+ expect(feed.hubs!.first.url, equals("https://hub.example.com/"));
+ expect(feed.items, isNotEmpty);
+
+ final item = feed.items.first;
+ expect(item.id, equals("1"));
+ expect(item.url, equals("https://example.com/1"));
+ expect(item.externalUrl, equals("https://external.com/1"));
+ expect(item.title, equals("Item 1"));
+ expect(item.contentHtml, equals("Hello world
"));
+ expect(item.contentText, equals("Hello world"));
+ expect(item.summary, equals("Summary of item 1"));
+ expect(item.image, equals("https://example.com/image1.png"));
+ expect(item.bannerImage, equals("https://example.com/banner1.png"));
+ expect(item.datePublished, equals("2023-01-01T12:00:00Z"));
+ expect(item.dateModified, equals("2023-01-02T12:00:00Z"));
+ expect(item.authors, isNotNull);
+ expect(item.authors!.first.name, equals("Jane Doe"));
+ expect(item.tags, containsAll(["tag1", "tag2"]));
+ expect(item.language, equals("en"));
+ expect(item.attachments, isNotNull);
+ expect(
+ item.attachments!.first.url,
+ equals("https://example.com/audio.mp3"),
+ );
+ expect(item.attachments!.first.mimeType, equals("audio/mpeg"));
+ expect(item.attachments!.first.title, equals("Audio"));
+ expect(item.attachments!.first.sizeInBytes, equals(123456));
+ expect(item.attachments!.first.durationInSeconds, equals(120.5));
+ });
}
From 15a7cf7b2d5a019ea05d4b9add80f107a98be261 Mon Sep 17 00:00:00 2001
From: imprologic
Date: Sun, 14 Sep 2025 18:52:39 -0400
Subject: [PATCH 3/5] removed .DS_Store
---
.DS_Store | Bin 6148 -> 0 bytes
.gitignore | 3 +++
2 files changed, 3 insertions(+)
delete mode 100644 .DS_Store
diff --git a/.DS_Store b/.DS_Store
deleted file mode 100644
index e3a74312ca754ea3256121dc077f0dd3794315b8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 6148
zcmeHK%}T>S5Z-O0CKMqD1-%8lR&8sw2QMMk7cim+m70)JgE3p0)Er77cYPsW#OHBl
zcOw?-Rm9G~?l-@?*$=Wmj4|#_qc&qUW6Xqx$Wd7$=w2GC>10HXV}wOE4igcA{ib7o
z9q`)?cECm~X8G6e564NI<*n8`uhosU^$pWB8|Iz=APPSZ@@eJ;lN+=yg-F6m55lW>
zSPbl~Gm+*&oDL_lAdZHRa(f-8ktjSdO`}ZK`YK>rmNl?jjj=)#tS9yfQ05L!e5CbdA
zfIbq;#>z543nvDMfu9(_{lS5T=xQt#%B=%Bygp;xKtur@-x7$9Mpt905F#L4l>(|#
zuAdlOm4n~Wd9KD%p(dLh7{6B|ZX6Yk;
zv4kvQfEf5^3~;0G_dQsYK3l&n56@Z$+C4NB%qvj=0e#^T00!
Date: Mon, 15 Sep 2025 08:58:23 -0400
Subject: [PATCH 4/5] README.md text
---
README.md | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
diff --git a/README.md b/README.md
index e69de29..60742ff 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,65 @@
+
+# JsonFeed Parser for Dart
+
+A Dart library for parsing [JSON Feed](https://jsonfeed.org/version/1) format feeds. This package provides strongly-typed models and utilities for working with JSON Feed data, including validation and error handling.
+
+## Features
+
+- Fully-typed models for JSON Feed, Item, Author, Attachment, and Hub (using [freezed](https://pub.dev/packages/freezed) and [json_serializable](https://pub.dev/packages/json_serializable))
+- Simple API for parsing JSON Feed strings
+- Custom exception handling for invalid feeds
+- Null safety and modern Dart support
+
+## Getting Started
+
+Add this package to your `pubspec.yaml`:
+
+```yaml
+dependencies:
+ jsonfeed:
+ git:
+ url: https://github.com/imprologic/json_feed.git
+```
+
+Import and use in your Dart code:
+
+```dart
+import 'package:jsonfeed/json_feed.dart';
+
+void main() {
+ final jsonString = '{ ... }'; // your JSON Feed string
+ try {
+ final feed = parseJsonFeed(jsonString);
+ print(feed.title);
+ } catch (e) {
+ print('Failed to parse feed: $e');
+ }
+}
+```
+
+## Code Generation
+
+This package uses code generation for immutable models. Run the following command to generate the necessary files:
+
+```bash
+dart run build_runner watch -d
+```
+
+## Running Tests
+
+To run the unit tests:
+
+```bash
+dart test
+```
+
+## Project Structure
+
+- `lib/json_feed.dart`: Main library entry point and parser
+- `lib/src/models.dart`: Data models for JSON Feed and related types
+- `test/json_feed_test.dart`: Unit tests
+
+## License
+
+See [LICENSE](LICENSE).
+
From 431e839499aae079bf23768f5f0d69298107a4a9 Mon Sep 17 00:00:00 2001
From: imprologic
Date: Mon, 15 Sep 2025 13:20:09 -0400
Subject: [PATCH 5/5] README.md correction
---
README.md | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 60742ff..eacd5ae 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,6 @@
-
# JsonFeed Parser for Dart
-A Dart library for parsing [JSON Feed](https://jsonfeed.org/version/1) format feeds. This package provides strongly-typed models and utilities for working with JSON Feed data, including validation and error handling.
+A Dart library for parsing [JSON Feed](https://www.jsonfeed.org/version/1.1/) format feeds. This package provides strongly-typed models and utilities for working with JSON Feed data, including validation and error handling.
## Features