- https://example.com/products/aperiam-voluptatem-atque-quia-et
+ https://example.com/products/sunt-aut-eum-hic-enim-veritatis-libero
2025-09-04T04:08:12+00:00
0.9
- https://example.com/products/eligendi-aperiam-est-fugiat-nobis-consequatur-harum-nihil
+ https://example.com/products/rerum-est-ipsum-est-et-alias-commodi-neque-quod
2025-09-04T04:08:12+00:00
0.9
diff --git a/docs/snippets/receipt-yandex-feed.xml b/docs/snippets/receipt-yandex-feed.xml
index 1bf1309..a7ab487 100644
--- a/docs/snippets/receipt-yandex-feed.xml
+++ b/docs/snippets/receipt-yandex-feed.xml
@@ -17,36 +17,36 @@
- https://example.com/products/velit-rerum-et-omnis-provident-rerum-inventore-est
- GD-N~_Z(N
- et et eligendi aliquam
- Itaque esse qui tempora non. Illum et quia cum ea quo est. Sit animi et voluptate voluptatem voluptates animi. At illum asperiores vero animi.
+ https://example.com/products/fugiat-aut-sequi-minima-quia-facere
+ GD-O)N->X
+ adipisci quis asperiores rem
+ Cumque necessitatibus quia minima aspernatur et dolor quae. Dignissimos maxime aut rerum velit perspiciatis. Beatae sit a quisquam atque.
true
- 957
+ 456
RUR
- porro
- https://via.placeholder.com/640x480.png/00bbcc?text=possimus
- https://via.placeholder.com/640x480.png/00ffdd?text=qui
- https://via.placeholder.com/640x480.png/005511?text=ullam
- GD-N~_Z(N
- 6
- male
+ eos
+ https://via.placeholder.com/640x480.png/00ff77?text=facere
+ https://via.placeholder.com/640x480.png/006622?text=illo
+ https://via.placeholder.com/640x480.png/00cc77?text=magni
+ GD-O)N->X
+ 2
+ female
- https://example.com/products/deserunt-odio-earum-neque-ipsum-alias-magni
- GD-'B'"SS
- est veritatis officiis quae
- Et velit libero dolorem sed est. Repellendus commodi tempore reiciendis quo. Cupiditate reprehenderit dolor molestiae nulla voluptas. Dolorem alias a architecto est quas dolore quas iste.
+ https://example.com/products/earum-voluptatem-magnam-error-molestiae-odit-consectetur
+ GD-+5T19
+ alias veritatis dignissimos omnis
+ Sint qui voluptatem quos et. Sint natus beatae ipsum maiores ipsa quas.
true
- 844
+ 553
RUR
- doloribus
- https://via.placeholder.com/640x480.png/0099ee?text=quo
- https://via.placeholder.com/640x480.png/0044ee?text=expedita
- https://via.placeholder.com/640x480.png/007777?text=fugiat
- GD-'B'"SS
- 5
- female
+ consequatur
+ https://via.placeholder.com/640x480.png/00bb99?text=voluptas
+ https://via.placeholder.com/640x480.png/00bb22?text=recusandae
+ https://via.placeholder.com/640x480.png/0088ee?text=fugit
+ GD-+5T19
+ 9
+ male
diff --git a/docs/topics/advanced-usage.topic b/docs/topics/advanced-usage.topic
index bb79d6f..e05a780 100644
--- a/docs/topics/advanced-usage.topic
+++ b/docs/topics/advanced-usage.topic
@@ -62,6 +62,7 @@
+
To add information to the beginning of the root element (if present) or without it,
diff --git a/docs/topics/create-feeds.topic b/docs/topics/create-feeds.topic
index 04d955b..9f8add8 100644
--- a/docs/topics/create-feeds.topic
+++ b/docs/topics/create-feeds.topic
@@ -101,10 +101,6 @@
-
-
-
-
You can generate feeds in different formats.
A feed class can be correctly exported only to the format for which it is intended.
@@ -117,7 +113,6 @@
-
diff --git a/docs/topics/supported-formats.topic b/docs/topics/supported-formats.topic
index a1c7400..d004e72 100644
--- a/docs/topics/supported-formats.topic
+++ b/docs/topics/supported-formats.topic
@@ -12,14 +12,20 @@
-
-
- xml
- json
-
+
+
+ Generates feeds in XML format.
+
+
+ Generates feeds in JSON format.
+
+
+ Generates feeds in JSON Lines format.
+
+
+
+
+ By default, the xml format is used.
+
-
- By default, the xml format is used.
-
-
diff --git a/src/Converters/ConvertToJsonLines.php b/src/Converters/ConvertToJsonLines.php
new file mode 100644
index 0000000..6e028bd
--- /dev/null
+++ b/src/Converters/ConvertToJsonLines.php
@@ -0,0 +1,77 @@
+options &= ~JSON_PRETTY_PRINT;
+ }
+
+ public function header(Feed $feed): string
+ {
+ return '';
+ }
+
+ public function footer(Feed $feed): string
+ {
+ return '';
+ }
+
+ public function root(Feed $feed): string
+ {
+ return '';
+ }
+
+ public function item(FeedItem $item, bool $isLast): string
+ {
+ $data = $this->performItem($item->toArray());
+
+ return $this->toJson($data);
+ }
+
+ public function info(array $info, bool $afterRoot): string
+ {
+ $data = $this->performItem($info);
+
+ return $this->toJson($data);
+ }
+
+ protected function performItem(array $data): array
+ {
+ foreach ($data as &$value) {
+ if (is_array($value)) {
+ $value = $this->performItem($value);
+
+ continue;
+ }
+
+ $value = $this->transformValue($value);
+ }
+
+ return $data;
+ }
+
+ protected function toJson(array $data): string
+ {
+ return json_encode($data, $this->options);
+ }
+}
diff --git a/src/Enums/FeedFormatEnum.php b/src/Enums/FeedFormatEnum.php
index 89fc743..6055d38 100644
--- a/src/Enums/FeedFormatEnum.php
+++ b/src/Enums/FeedFormatEnum.php
@@ -6,6 +6,7 @@
enum FeedFormatEnum: string
{
- case Xml = 'xml';
- case Json = 'json';
+ case Xml = 'xml';
+ case Json = 'json';
+ case JsonLines = 'jsonl';
}
diff --git a/src/Feeds/Feed.php b/src/Feeds/Feed.php
index 1c1c769..db47435 100644
--- a/src/Feeds/Feed.php
+++ b/src/Feeds/Feed.php
@@ -44,8 +44,8 @@ public function chunkSize(): int
public function header(): string
{
return match ($this->format()) {
- FeedFormatEnum::Xml => '',
- FeedFormatEnum::Json => '',
+ FeedFormatEnum::Xml => '',
+ default => ''
};
}
diff --git a/src/Services/GeneratorService.php b/src/Services/GeneratorService.php
index 55c9c5b..0326ff3 100644
--- a/src/Services/GeneratorService.php
+++ b/src/Services/GeneratorService.php
@@ -6,6 +6,7 @@
use DragonCode\LaravelFeed\Converters\Converter;
use DragonCode\LaravelFeed\Converters\ConvertToJson;
+use DragonCode\LaravelFeed\Converters\ConvertToJsonLines;
use DragonCode\LaravelFeed\Converters\ConvertToXml;
use DragonCode\LaravelFeed\Enums\FeedFormatEnum;
use DragonCode\LaravelFeed\Feeds\Feed;
@@ -24,6 +25,7 @@ public function __construct(
protected FilesystemService $filesystem,
protected ConvertToXml $xmlConverter,
protected ConvertToJson $jsonConverter,
+ protected ConvertToJsonLines $jsonLinesConverter,
protected FeedQuery $query,
) {}
@@ -147,8 +149,9 @@ protected function setLastActivity(Feed $feed): void
protected function converter(Feed $feed): Converter
{
return match ($feed->format()) {
- FeedFormatEnum::Xml => $this->xmlConverter,
- FeedFormatEnum::Json => $this->jsonConverter,
+ FeedFormatEnum::Xml => $this->xmlConverter,
+ FeedFormatEnum::Json => $this->jsonConverter,
+ FeedFormatEnum::JsonLines => $this->jsonLinesConverter,
};
}
diff --git a/tests/.pest/snapshots/Feature/Feeds/EmptyTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/EmptyTest/export_with_data_set____false__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/EmptyTest/export_with_data_set____false__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Defaults/EmptyTest/export_with_data_set____false__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/EmptyTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/EmptyTest/export_with_data_set____true__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/EmptyTest/export_with_data_set____true__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Defaults/EmptyTest/export_with_data_set____true__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/FullTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/FullTest/export_with_data_set____false__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/FullTest/export_with_data_set____false__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Defaults/FullTest/export_with_data_set____false__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/FullTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/FullTest/export_with_data_set____true__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/FullTest/export_with_data_set____true__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Defaults/FullTest/export_with_data_set____true__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/ModelTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/ModelTest/export_with_data_set____false__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/ModelTest/export_with_data_set____false__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Defaults/ModelTest/export_with_data_set____false__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/ModelTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/ModelTest/export_with_data_set____true__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/ModelTest/export_with_data_set____true__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Defaults/ModelTest/export_with_data_set____true__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/PartialTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/PartialTest/export_with_data_set____false__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/PartialTest/export_with_data_set____false__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Defaults/PartialTest/export_with_data_set____false__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/PartialTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/PartialTest/export_with_data_set____true__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/PartialTest/export_with_data_set____true__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Defaults/PartialTest/export_with_data_set____true__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/DefaultTest/export_with_data_set____false__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/JsonTest/export_with_data_set____false__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/DefaultTest/export_with_data_set____false__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/DefaultTest/export_with_data_set____true__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/JsonTest/export_with_data_set____true__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/DefaultTest/export_with_data_set____true__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonInfoTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/InfoTest/export_with_data_set____false__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/JsonInfoTest/export_with_data_set____false__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/InfoTest/export_with_data_set____false__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonInfoTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/InfoTest/export_with_data_set____true__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/JsonInfoTest/export_with_data_set____true__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/InfoTest/export_with_data_set____true__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonRootInfoTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootInfoTest/export_with_data_set____false__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/JsonRootInfoTest/export_with_data_set____false__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootInfoTest/export_with_data_set____false__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonRootInfoTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootInfoTest/export_with_data_set____true__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/JsonRootInfoTest/export_with_data_set____true__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootInfoTest/export_with_data_set____true__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonRootTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootTest/export_with_data_set____false__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/JsonRootTest/export_with_data_set____false__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootTest/export_with_data_set____false__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonRootTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootTest/export_with_data_set____true__.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/JsonRootTest/export_with_data_set____true__.snap
rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootTest/export_with_data_set____true__.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/DefaultTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/DefaultTest/export_with_data_set____false__.snap
new file mode 100644
index 0000000..5f50397
--- /dev/null
+++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/DefaultTest/export_with_data_set____false__.snap
@@ -0,0 +1,3 @@
+{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
\ No newline at end of file
diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/DefaultTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/DefaultTest/export_with_data_set____true__.snap
new file mode 100644
index 0000000..5f50397
--- /dev/null
+++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/DefaultTest/export_with_data_set____true__.snap
@@ -0,0 +1,3 @@
+{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
\ No newline at end of file
diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/InfoTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/InfoTest/export_with_data_set____false__.snap
new file mode 100644
index 0000000..dc646bf
--- /dev/null
+++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/InfoTest/export_with_data_set____false__.snap
@@ -0,0 +1,4 @@
+{"name":"Laravel","company":"Laravel","platform":"Laravel","url":"https://example.com","email":"test@example.com","currencies":{"@currency":[{"@attributes":{"id":"RUR","rate":"1"}}]},"categories":{"@category":[{"@attributes":{"id":41},"@value":"Домашние майки"},{"@attributes":{"id":539},"@value":"Велосипедки"},{"@attributes":{"id":44},"@value":"Ремни"}]}}
+{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
\ No newline at end of file
diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/InfoTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/InfoTest/export_with_data_set____true__.snap
new file mode 100644
index 0000000..dc646bf
--- /dev/null
+++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/InfoTest/export_with_data_set____true__.snap
@@ -0,0 +1,4 @@
+{"name":"Laravel","company":"Laravel","platform":"Laravel","url":"https://example.com","email":"test@example.com","currencies":{"@currency":[{"@attributes":{"id":"RUR","rate":"1"}}]},"categories":{"@category":[{"@attributes":{"id":41},"@value":"Домашние майки"},{"@attributes":{"id":539},"@value":"Велосипедки"},{"@attributes":{"id":44},"@value":"Ремни"}]}}
+{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
\ No newline at end of file
diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootInfoTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootInfoTest/export_with_data_set____false__.snap
new file mode 100644
index 0000000..dc646bf
--- /dev/null
+++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootInfoTest/export_with_data_set____false__.snap
@@ -0,0 +1,4 @@
+{"name":"Laravel","company":"Laravel","platform":"Laravel","url":"https://example.com","email":"test@example.com","currencies":{"@currency":[{"@attributes":{"id":"RUR","rate":"1"}}]},"categories":{"@category":[{"@attributes":{"id":41},"@value":"Домашние майки"},{"@attributes":{"id":539},"@value":"Велосипедки"},{"@attributes":{"id":44},"@value":"Ремни"}]}}
+{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
\ No newline at end of file
diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootInfoTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootInfoTest/export_with_data_set____true__.snap
new file mode 100644
index 0000000..dc646bf
--- /dev/null
+++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootInfoTest/export_with_data_set____true__.snap
@@ -0,0 +1,4 @@
+{"name":"Laravel","company":"Laravel","platform":"Laravel","url":"https://example.com","email":"test@example.com","currencies":{"@currency":[{"@attributes":{"id":"RUR","rate":"1"}}]},"categories":{"@category":[{"@attributes":{"id":41},"@value":"Домашние майки"},{"@attributes":{"id":539},"@value":"Велосипедки"},{"@attributes":{"id":44},"@value":"Ремни"}]}}
+{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
\ No newline at end of file
diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootTest/export_with_data_set____false__.snap
new file mode 100644
index 0000000..5f50397
--- /dev/null
+++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootTest/export_with_data_set____false__.snap
@@ -0,0 +1,3 @@
+{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
\ No newline at end of file
diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootTest/export_with_data_set____true__.snap
new file mode 100644
index 0000000..5f50397
--- /dev/null
+++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootTest/export_with_data_set____true__.snap
@@ -0,0 +1,3 @@
+{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
+{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"}
\ No newline at end of file
diff --git a/tests/.pest/snapshots/Feature/Feeds/SitemapTest/export.snap b/tests/.pest/snapshots/Feature/Feeds/Receipts/SitemapTest/export.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/SitemapTest/export.snap
rename to tests/.pest/snapshots/Feature/Feeds/Receipts/SitemapTest/export.snap
diff --git a/tests/.pest/snapshots/Feature/Feeds/YandexTest/export.snap b/tests/.pest/snapshots/Feature/Feeds/Receipts/YandexTest/export.snap
similarity index 100%
rename from tests/.pest/snapshots/Feature/Feeds/YandexTest/export.snap
rename to tests/.pest/snapshots/Feature/Feeds/Receipts/YandexTest/export.snap
diff --git a/tests/Expectations.php b/tests/Expectations.php
index 2f3a677..d54dd5b 100644
--- a/tests/Expectations.php
+++ b/tests/Expectations.php
@@ -55,3 +55,11 @@
return $next();
});
+
+expect()->extend('toBeJsonLines', function () {
+ foreach (explode("\n", $this->value) as $line) {
+ expect($line)->toBeJson();
+ }
+
+ return $this;
+});
diff --git a/tests/Feature/Feeds/EmptyTest.php b/tests/Feature/Feeds/Defaults/EmptyTest.php
similarity index 100%
rename from tests/Feature/Feeds/EmptyTest.php
rename to tests/Feature/Feeds/Defaults/EmptyTest.php
diff --git a/tests/Feature/Feeds/FullTest.php b/tests/Feature/Feeds/Defaults/FullTest.php
similarity index 100%
rename from tests/Feature/Feeds/FullTest.php
rename to tests/Feature/Feeds/Defaults/FullTest.php
diff --git a/tests/Feature/Feeds/ModelTest.php b/tests/Feature/Feeds/Defaults/ModelTest.php
similarity index 100%
rename from tests/Feature/Feeds/ModelTest.php
rename to tests/Feature/Feeds/Defaults/ModelTest.php
diff --git a/tests/Feature/Feeds/PartialTest.php b/tests/Feature/Feeds/Defaults/PartialTest.php
similarity index 100%
rename from tests/Feature/Feeds/PartialTest.php
rename to tests/Feature/Feeds/Defaults/PartialTest.php
diff --git a/tests/Feature/Feeds/JsonTest.php b/tests/Feature/Feeds/Formats/Json/DefaultTest.php
similarity index 68%
rename from tests/Feature/Feeds/JsonTest.php
rename to tests/Feature/Feeds/Formats/Json/DefaultTest.php
index f12326a..24e1c1e 100644
--- a/tests/Feature/Feeds/JsonTest.php
+++ b/tests/Feature/Feeds/Formats/Json/DefaultTest.php
@@ -2,6 +2,7 @@
declare(strict_types=1);
+use DragonCode\LaravelFeed\Enums\FeedFormatEnum;
use Workbench\App\Data\NewsFakeData;
use Workbench\App\Feeds\JsonFeed;
@@ -10,5 +11,5 @@
createNews(...NewsFakeData::toArray());
- expectFeedSnapshot(JsonFeed::class, true);
+ expectFeedSnapshot(JsonFeed::class, FeedFormatEnum::Json);
})->with('boolean');
diff --git a/tests/Feature/Feeds/JsonInfoTest.php b/tests/Feature/Feeds/Formats/Json/InfoTest.php
similarity index 67%
rename from tests/Feature/Feeds/JsonInfoTest.php
rename to tests/Feature/Feeds/Formats/Json/InfoTest.php
index 326af29..4f2e572 100644
--- a/tests/Feature/Feeds/JsonInfoTest.php
+++ b/tests/Feature/Feeds/Formats/Json/InfoTest.php
@@ -2,6 +2,7 @@
declare(strict_types=1);
+use DragonCode\LaravelFeed\Enums\FeedFormatEnum;
use Workbench\App\Data\NewsFakeData;
use Workbench\App\Feeds\JsonInfoFeed;
@@ -10,5 +11,5 @@
createNews(...NewsFakeData::toArray());
- expectFeedSnapshot(JsonInfoFeed::class, true);
+ expectFeedSnapshot(JsonInfoFeed::class, FeedFormatEnum::Json);
})->with('boolean');
diff --git a/tests/Feature/Feeds/JsonRootInfoTest.php b/tests/Feature/Feeds/Formats/Json/RootInfoTest.php
similarity index 67%
rename from tests/Feature/Feeds/JsonRootInfoTest.php
rename to tests/Feature/Feeds/Formats/Json/RootInfoTest.php
index beae030..aefe67a 100644
--- a/tests/Feature/Feeds/JsonRootInfoTest.php
+++ b/tests/Feature/Feeds/Formats/Json/RootInfoTest.php
@@ -2,6 +2,7 @@
declare(strict_types=1);
+use DragonCode\LaravelFeed\Enums\FeedFormatEnum;
use Workbench\App\Data\NewsFakeData;
use Workbench\App\Feeds\JsonRootInfoFeed;
@@ -10,5 +11,5 @@
createNews(...NewsFakeData::toArray());
- expectFeedSnapshot(JsonRootInfoFeed::class, true);
+ expectFeedSnapshot(JsonRootInfoFeed::class, FeedFormatEnum::Json);
})->with('boolean');
diff --git a/tests/Feature/Feeds/JsonRootTest.php b/tests/Feature/Feeds/Formats/Json/RootTest.php
similarity index 67%
rename from tests/Feature/Feeds/JsonRootTest.php
rename to tests/Feature/Feeds/Formats/Json/RootTest.php
index bef3130..476b912 100644
--- a/tests/Feature/Feeds/JsonRootTest.php
+++ b/tests/Feature/Feeds/Formats/Json/RootTest.php
@@ -2,6 +2,7 @@
declare(strict_types=1);
+use DragonCode\LaravelFeed\Enums\FeedFormatEnum;
use Workbench\App\Data\NewsFakeData;
use Workbench\App\Feeds\JsonRootFeed;
@@ -10,5 +11,5 @@
createNews(...NewsFakeData::toArray());
- expectFeedSnapshot(JsonRootFeed::class, true);
+ expectFeedSnapshot(JsonRootFeed::class, FeedFormatEnum::Json);
})->with('boolean');
diff --git a/tests/Feature/Feeds/Formats/JsonLines/DefaultTest.php b/tests/Feature/Feeds/Formats/JsonLines/DefaultTest.php
new file mode 100644
index 0000000..608535f
--- /dev/null
+++ b/tests/Feature/Feeds/Formats/JsonLines/DefaultTest.php
@@ -0,0 +1,15 @@
+with('boolean');
diff --git a/tests/Feature/Feeds/Formats/JsonLines/InfoTest.php b/tests/Feature/Feeds/Formats/JsonLines/InfoTest.php
new file mode 100644
index 0000000..db76746
--- /dev/null
+++ b/tests/Feature/Feeds/Formats/JsonLines/InfoTest.php
@@ -0,0 +1,15 @@
+with('boolean');
diff --git a/tests/Feature/Feeds/Formats/JsonLines/RootInfoTest.php b/tests/Feature/Feeds/Formats/JsonLines/RootInfoTest.php
new file mode 100644
index 0000000..0263e7e
--- /dev/null
+++ b/tests/Feature/Feeds/Formats/JsonLines/RootInfoTest.php
@@ -0,0 +1,15 @@
+with('boolean');
diff --git a/tests/Feature/Feeds/Formats/JsonLines/RootTest.php b/tests/Feature/Feeds/Formats/JsonLines/RootTest.php
new file mode 100644
index 0000000..e5d083a
--- /dev/null
+++ b/tests/Feature/Feeds/Formats/JsonLines/RootTest.php
@@ -0,0 +1,15 @@
+with('boolean');
diff --git a/tests/Feature/Feeds/SitemapTest.php b/tests/Feature/Feeds/Receipts/SitemapTest.php
similarity index 100%
rename from tests/Feature/Feeds/SitemapTest.php
rename to tests/Feature/Feeds/Receipts/SitemapTest.php
diff --git a/tests/Feature/Feeds/YandexTest.php b/tests/Feature/Feeds/Receipts/YandexTest.php
similarity index 100%
rename from tests/Feature/Feeds/YandexTest.php
rename to tests/Feature/Feeds/Receipts/YandexTest.php
diff --git a/tests/Helpers/expects.php b/tests/Helpers/expects.php
index 438e207..0d805b0 100644
--- a/tests/Helpers/expects.php
+++ b/tests/Helpers/expects.php
@@ -3,10 +3,11 @@
declare(strict_types=1);
use DragonCode\LaravelFeed\Commands\FeedGenerateCommand;
+use DragonCode\LaravelFeed\Enums\FeedFormatEnum;
use function Pest\Laravel\artisan;
-function expectFeedSnapshot(string $class, bool $isJson = false): void
+function expectFeedSnapshot(string $class, FeedFormatEnum $format = FeedFormatEnum::Xml): void
{
$feed = findFeed($class);
@@ -20,9 +21,11 @@ function expectFeedSnapshot(string $class, bool $isJson = false): void
$content = file_get_contents($instance->path());
- if ($isJson) {
- expect($content)->toBeJson();
- }
+ match ($format) {
+ FeedFormatEnum::Json => expect($content)->toBeJson(),
+ FeedFormatEnum::JsonLines => expect($content)->toBeJsonLines(),
+ default => null
+ };
expect($content)->toMatchSnapshot();
}
diff --git a/workbench/app/Feeds/JsonLinesFeed.php b/workbench/app/Feeds/JsonLinesFeed.php
new file mode 100644
index 0000000..43c0fce
--- /dev/null
+++ b/workbench/app/Feeds/JsonLinesFeed.php
@@ -0,0 +1,28 @@
+