Page MenuHomeDevCentral

No OneTemporary

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

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)

Event Timeline