Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F12359760
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/composer.json b/composer.json
index d7263af..57d349e 100644
--- a/composer.json
+++ b/composer.json
@@ -45,7 +45,8 @@
"keruald/database": "0.6.0",
"keruald/github": "0.2.1",
"keruald/omnitools": "0.16.0",
- "keruald/report": "0.1.0"
+ "keruald/report": "0.1.0",
+ "keruald/yaml": "0.1.0"
},
"autoload": {
"psr-4": {
@@ -60,7 +61,9 @@
"Keruald\\OmniTools\\": "omnitools/src/",
"Keruald\\OmniTools\\Tests\\": "omnitools/tests/",
"Keruald\\Reporting\\": "report/src/",
- "Keruald\\Reporting\\Tests\\": "report/tests/"
+ "Keruald\\Reporting\\Tests\\": "report/tests/",
+ "Keruald\\Yaml\\": "yaml/src/",
+ "Keruald\\Yaml\\Tests\\": "yaml/tests/"
}
},
"scripts": {
diff --git a/metadata.yml b/metadata.yml
index 96602b1..e8eff33 100644
--- a/metadata.yml
+++ b/metadata.yml
@@ -28,6 +28,7 @@ packages:
- github
- omnitools
- report
+ - yaml
packages_namespaces:
cache: Keruald\Cache
@@ -36,3 +37,4 @@ packages_namespaces:
github: Keruald\GitHub
omnitools: Keruald\OmniTools
report: Keruald\Reporting
+ yaml: Keruald\Yaml
diff --git a/phpcs.xml b/phpcs.xml
index d89230c..6b8f384 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -55,4 +55,7 @@
<file>report/src</file>
<file>report/tests</file>
+ <file>yaml/src</file>
+ <file>yaml/tests</file>
+
</ruleset>
diff --git a/phpunit.xml b/phpunit.xml
index e545b4e..5fc519b 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -51,6 +51,9 @@
<testsuite name="Unit tests for keruald/report">
<directory suffix="Test.php">./report/tests</directory>
</testsuite>
+ <testsuite name="Unit tests for keruald/yaml">
+ <directory suffix="Test.php">./yaml/tests</directory>
+ </testsuite>
</testsuites>
<source>
<include>
@@ -60,6 +63,7 @@
<directory suffix=".php">github/src/</directory>
<directory suffix=".php">omnitools/src/</directory>
<directory suffix=".php">report/src/</directory>
+ <directory suffix=".php">yaml/src/</directory>
</include>
</source>
</phpunit>
diff --git a/yaml/composer.json b/yaml/composer.json
new file mode 100644
index 0000000..61bb0f2
--- /dev/null
+++ b/yaml/composer.json
@@ -0,0 +1,41 @@
+{
+ "name": "keruald/yaml",
+ "description": "YAML parser",
+ "license": "BSD-2-Clause",
+ "repositories": [
+ {
+ "type": "vcs",
+ "url": "https://github.com/keruald/yaml"
+ }
+ ],
+ "authors": [
+ {
+ "name": "Sébastien Santoro",
+ "email": "dereckson@espace-win.org"
+ }
+ ],
+ "keywords": [
+ "keruald",
+ "YAML"
+ ],
+ "support": {
+ "irc": "irc://irc.libera.chat/nasqueron",
+ "issues": "https://devcentral.nasqueron.org"
+ },
+ "require": {
+ "keruald/omnitools": "^0.16.0",
+ "php": ">=8.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "12.*"
+ },
+ "autoload": {
+ "psr-4": {
+ "Keruald\\Yaml\\": "src/",
+ "Keruald\\Yaml\\Tests\\": "tests/"
+ }
+ },
+ "scripts": {
+ "test": "phpunit tests"
+ }
+}
diff --git a/yaml/src/Parser.php b/yaml/src/Parser.php
new file mode 100644
index 0000000..c3ccb65
--- /dev/null
+++ b/yaml/src/Parser.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Keruald\Yaml;
+
+use Symfony\Component\Yaml\Tag\TaggedValue;
+use Symfony\Component\Yaml\Yaml;
+
+use Keruald\Yaml\Tags\Tag;
+
+use InvalidArgumentException;
+
+class Parser {
+
+ /**
+ * @var array<string, Tag>
+ */
+ private array $tags = [];
+
+ ///
+ /// Configure
+ ///
+
+ public function withTagClass (string $type) : self {
+ $tag = new $type();
+
+ return $this->withTag($tag);
+ }
+
+ public function withTag (Tag $tag) : self {
+ $tag->register($this->tags);
+
+ return $this;
+ }
+
+ ///
+ /// Parse
+ ///
+
+ /**
+ * @throws InvalidArgumentException if a tag is not defined at parser level
+ */
+ public function parse (string $expression) : mixed {
+ $flags = Yaml::PARSE_CUSTOM_TAGS;
+ $parsed = Yaml::parse($expression, $flags);
+
+ return $this->resolve($parsed);
+ }
+
+ /**
+ * @throws InvalidArgumentException if the file is not found
+ * @throws InvalidArgumentException if a tag is not defined at parser level
+ */
+ public function parseFile (string $filename) : mixed {
+ if (!file_exists($filename)) {
+ throw new InvalidArgumentException("File not found: $filename");
+ }
+
+ $flags = Yaml::PARSE_CUSTOM_TAGS;
+ $parsed = Yaml::parseFile($filename, $flags);
+
+ return $this->resolve($parsed);
+ }
+
+ private function resolve (mixed $data) {
+ if ($data instanceof TaggedValue) {
+ $tag = $data->getTag();
+
+ if (!array_key_exists($tag, $this->tags)) {
+ throw new InvalidArgumentException("Tag not found: $tag");
+ }
+
+ $tagHandler = $this->tags[$tag];
+
+ return $tagHandler->handle($data->getValue());
+ }
+
+ if (is_array($data)) {
+ foreach ($data as $key => $value) {
+ $data[$key] = $this->resolve($value);
+ }
+ }
+
+ return $data;
+ }
+
+}
diff --git a/yaml/src/Tags/EnvTag.php b/yaml/src/Tags/EnvTag.php
new file mode 100644
index 0000000..1955067
--- /dev/null
+++ b/yaml/src/Tags/EnvTag.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace Keruald\Yaml\Tags;
+
+use Keruald\OmniTools\OS\Environment;
+
+/**
+ * Represents an environment variable
+ */
+class EnvTag extends Tag {
+
+ public function getPrimaryTag () : string {
+ return "tag:keruald.nasqueron.org,2025:env";
+ }
+
+ public function getPrivateTag () : string {
+ return "env";
+ }
+
+ /**
+ * @throws \InvalidArgumentException when the variable does not exist.
+ */
+ public function handle (mixed $data) : string {
+ $key = (string)$data;
+
+ return Environment::get($key);
+ }
+
+}
diff --git a/yaml/src/Tags/Tag.php b/yaml/src/Tags/Tag.php
new file mode 100644
index 0000000..99e7493
--- /dev/null
+++ b/yaml/src/Tags/Tag.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Keruald\Yaml\Tags;
+
+abstract class Tag {
+
+ public abstract function getPrimaryTag () : string;
+
+ public abstract function getPrivateTag () : string;
+
+ public abstract function handle (mixed $data) : mixed;
+
+ public function register (&$tags) : void {
+ $tags[$this->getPrimaryTag()] = $this;
+ $tags[$this->getPrivateTag()] = $this;
+ }
+
+}
diff --git a/yaml/tests/ParserTest.php b/yaml/tests/ParserTest.php
new file mode 100644
index 0000000..06f2002
--- /dev/null
+++ b/yaml/tests/ParserTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Keruald\Yaml\Tests;
+
+use Keruald\Yaml\Parser;
+
+use PHPUnit\Framework\TestCase;
+
+use InvalidArgumentException;
+
+class ParserTest extends TestCase {
+
+ private Parser $parser;
+
+ protected function setUp () : void {
+ $this->parser = new Parser;
+ }
+
+ public function testParse () {
+ $this->assertEquals(666, $this->parser->parse("666"));
+ $this->assertEquals("", $this->parser->parse(""));
+ }
+
+ public function testParseUnknownTag () {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage("Tag not found: foo");
+
+ $this->parser->parse("!foo 4");
+ }
+
+ public function testParseFile () {
+ $expected = [
+ "example" => [
+ "foo" => "bar",
+ "skills" => [
+ "quux",
+ "baz",
+ ],
+ ],
+ ];
+
+ $actual = $this->parser->parseFile(__DIR__ . "/data/example.yaml");
+
+ $this->assertEquals($expected, $actual);
+ }
+
+}
diff --git a/yaml/tests/Tags/EnvTagTest.php b/yaml/tests/Tags/EnvTagTest.php
new file mode 100644
index 0000000..52d51d9
--- /dev/null
+++ b/yaml/tests/Tags/EnvTagTest.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace Keruald\Yaml\Tests\Tags;
+
+use Keruald\Yaml\Parser;
+use Keruald\Yaml\Tags\EnvTag;
+use PHPUnit\Framework\TestCase;
+
+class EnvTagTest extends TestCase {
+
+ private EnvTag $tag;
+
+ protected function setUp () : void {
+ $this->tag = new EnvTag();
+
+ $_ENV["ORBEON_DB_HOST"] = "localhost";
+ $_ENV["ORBEON_DB_PORT"] = "5432";
+
+ $_SERVER["ORBEON_DB_NAME"] = "orbeon_db";
+ }
+
+ public function testHandle () {
+ $this->assertEquals("localhost", $this->tag->handle("ORBEON_DB_HOST"));
+ }
+
+ public function testHandleWithServerVariable () {
+ $this->assertEquals("orbeon_db", $this->tag->handle("ORBEON_DB_NAME"));
+ }
+
+ public function testHandleWithMissingVariable () {
+ $this->assertEquals("5432", $this->tag->handle("ORBEON_DB_PORT"));
+ }
+
+ ///
+ /// Integration
+ ///
+
+ public function testFullParse () {
+ $yamlContent = <<<YAML
+database:
+ host: !env ORBEON_DB_HOST
+ port: !env ORBEON_DB_PORT
+ name: !env ORBEON_DB_NAME
+ pool_size: 10
+YAML;
+
+ $expected = [
+ "database" => [
+ "host" => "localhost",
+ "port" => "5432",
+ "name" => "orbeon_db",
+ "pool_size" => 10,
+ ],
+ ];
+
+ $parser = new Parser();
+ $parser->withTagClass(EnvTag::class);
+ $actual = $parser->parse($yamlContent);
+
+ $this->assertEquals($expected, $actual);
+ }
+
+}
diff --git a/yaml/tests/Tags/TagTest.php b/yaml/tests/Tags/TagTest.php
new file mode 100644
index 0000000..7e614e4
--- /dev/null
+++ b/yaml/tests/Tags/TagTest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Keruald\Yaml\Tests\Tags;
+
+use Keruald\Yaml\Tags\Tag;
+use PHPUnit\Framework\TestCase;
+
+class TagTest extends TestCase {
+
+ public static function provideTag () : Tag {
+ return new class () extends Tag {
+ public function getPrimaryTag () : string {
+ return "tag:example.com,2000:test";
+ }
+
+ public function getPrivateTag () : string {
+ return "test";
+ }
+
+ public function handle (mixed $data) : string {
+ return "";
+ }
+ };
+ }
+
+ public function testRegister () {
+ $handlers = [];
+
+ $tag = self::provideTag();
+ $tag->register($handlers);
+
+ $this->assertArrayHasKey("tag:example.com,2000:test", $handlers);
+ $this->assertArrayHasKey("test", $handlers);
+ }
+
+}
diff --git a/yaml/tests/data/example.yaml b/yaml/tests/data/example.yaml
new file mode 100644
index 0000000..f8d8bbb
--- /dev/null
+++ b/yaml/tests/data/example.yaml
@@ -0,0 +1,5 @@
+example:
+ foo: bar
+ skills:
+ - quux
+ - baz
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Oct 31, 02:18 (21 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3116760
Default Alt Text
(10 KB)
Attached To
Mode
rKERUALD Keruald libraries development repository
Attached
Detach File
Event Timeline
Log In to Comment