Skip to content

Commit 0626e64

Browse files
committed
feat: improve validation
1 parent 0884019 commit 0626e64

File tree

6 files changed

+119
-2
lines changed

6 files changed

+119
-2
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
77

88
## [Unreleased]
99

10+
## [v3.4.0] - 2025-10-14
11+
12+
### Added
13+
- Improved `LlmsTxt::validation` by providing more information about the validation errors. Closes issue [8](https://github.com/raphaelstolt/llms-txt-php/issues/8).
14+
1015
## [v3.3.0] - 2025-09-20
1116

1217
### Added
@@ -123,7 +128,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
123128

124129
- Initial release.
125130

126-
[Unreleased]: https://github.com/raphaelstolt/llms-txt-php/compare/v3.3.0...HEAD
131+
[Unreleased]: https://github.com/raphaelstolt/llms-txt-php/compare/v3.4.0...HEAD
132+
[v3.4.0]: https://github.com/raphaelstolt/llms-txt-php/compare/v3.3.0...v3.4.0
127133
[v3.3.0]: https://github.com/raphaelstolt/llms-txt-php/compare/v3.2.0...v3.3.0
128134
[v3.2.0]: https://github.com/raphaelstolt/llms-txt-php/compare/v3.1.0...v3.2.0
129135
[v3.1.0]: https://github.com/raphaelstolt/llms-txt-php/compare/v3.0.0...v3.1.0

src/LlmsTxt.php

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
use \Exception;
88
use Stolt\LlmsTxt\Section\Link;
9+
use Stolt\LlmsTxt\Validation\ValidationError;
10+
use Stolt\LlmsTxt\Validation\ValidationResult;
911

1012
final class LlmsTxt
1113
{
@@ -112,15 +114,55 @@ public function toString(): string
112114
}
113115

114116
/**
117+
* Validates a given llms.txt file content.
118+
*
119+
* If `$detailed` is false (default), it returns a simple boolean for backward compatibility.
120+
* If `$detailed` is true, returns a `ValidationResult` object with rich diagnostics.
121+
*
122+
* @param bool $detailed Whether to return a ValidationResult instead of a boolean.
123+
*
115124
* @throws Exception
125+
* @return bool|ValidationResult
116126
*/
117-
public function validate(): bool
127+
public function validate(bool $detailed = false): bool|ValidationResult
118128
{
119129
if ($this->hasBeenParsed) {
130+
131+
120132
if ($this->title !== '' && $this->description !== '' && $this->details !== '' && \count($this->sections) > 0 && \count($this->sections[0]->getLinks()) > 0) {
133+
if ($detailed) {
134+
return new ValidationResult();
135+
}
121136
return true;
122137
}
123138

139+
if ($detailed) {
140+
$result = new ValidationResult();
141+
142+
if (!isset($this->title) || empty($this->title)) {
143+
$result->addError(new ValidationError('Missing title'));
144+
}
145+
146+
if (!isset($this->description) || empty($this->description)) {
147+
$result->addError(new ValidationError('Missing description'));
148+
}
149+
150+
if (!isset($this->details) || empty($this->details)) {
151+
$result->addError(new ValidationError('Missing details'));
152+
}
153+
154+
if (\count($this->sections) === 0) {
155+
$result->addError(new ValidationError('Missing at least one section'));
156+
$result->addError(new ValidationError('Missing at least one section link'));
157+
}
158+
159+
if (\count($this->sections) > 0 && \count($this->sections[0]->getLinks()) === 0) {
160+
$result->addError(new ValidationError('Missing at least one section link'));
161+
}
162+
163+
return $result;
164+
}
165+
124166
return false;
125167
}
126168

src/Validation/ValidationError.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Stolt\LlmsTxt\Validation;
6+
7+
final class ValidationError
8+
{
9+
public function __construct(
10+
private readonly string $message
11+
) {
12+
}
13+
14+
public function message(): string
15+
{
16+
return $this->message;
17+
}
18+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Stolt\LlmsTxt\Validation;
6+
7+
final class ValidationResult
8+
{
9+
/** @var ValidationError[] */
10+
private array $errors = [];
11+
12+
public function addError(ValidationError $error): void
13+
{
14+
$this->errors[] = $error;
15+
}
16+
17+
public function isValid(): bool
18+
{
19+
return empty($this->errors);
20+
}
21+
22+
/**
23+
* @return ValidationError[]
24+
*/
25+
public function errors(): array
26+
{
27+
return $this->errors;
28+
}
29+
}

tests/LlmsTxtTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,27 @@ public function itValidatesLlmsTxtAsExpected(): void
135135
$this->assertTrue($llmsTxt->validate());
136136
}
137137

138+
#[Test]
139+
public function itValidatesLlmsTxtWithAValidationResultAsExpected(): void
140+
{
141+
$llmsTxt = new LlmsTxt();
142+
$llmsTxt = $llmsTxt->parse(\realpath(__DIR__ . '/fixtures/uv.llms.md'));
143+
144+
$validationResult = $llmsTxt->validate(true);
145+
$this->assertTrue($validationResult->isValid());
146+
}
147+
148+
#[Test]
149+
public function itValidatesLlmsTxtWithAValidationResultAsExpectedWithMissingElements(): void
150+
{
151+
$llmsTxt = new LlmsTxt();
152+
$llmsTxt = $llmsTxt->parse(\realpath(__DIR__ . '/fixtures/invalid.md'));
153+
154+
$validationResult = $llmsTxt->validate(true);
155+
$this->assertFalse($validationResult->isValid());
156+
$this->assertCount(4, $validationResult->errors());
157+
}
158+
138159
#[Test]
139160
public function itThrowsExpectedExceptionWhenNotParsedBeforeValidating(): void
140161
{

tests/fixtures/invalid.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Title

0 commit comments

Comments
 (0)