Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F12359780
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
8 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..61bb0f2
--- /dev/null
+++ b/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/src/Parser.php b/src/Parser.php
new file mode 100644
index 0000000..c3ccb65
--- /dev/null
+++ b/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/src/Tags/EnvTag.php b/src/Tags/EnvTag.php
new file mode 100644
index 0000000..1955067
--- /dev/null
+++ b/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/src/Tags/Tag.php b/src/Tags/Tag.php
new file mode 100644
index 0000000..99e7493
--- /dev/null
+++ b/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/tests/ParserTest.php b/tests/ParserTest.php
new file mode 100644
index 0000000..06f2002
--- /dev/null
+++ b/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/tests/Tags/EnvTagTest.php b/tests/Tags/EnvTagTest.php
new file mode 100644
index 0000000..52d51d9
--- /dev/null
+++ b/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/tests/Tags/TagTest.php b/tests/Tags/TagTest.php
new file mode 100644
index 0000000..7e614e4
--- /dev/null
+++ b/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/tests/data/example.yaml b/tests/data/example.yaml
new file mode 100644
index 0000000..f8d8bbb
--- /dev/null
+++ b/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:20 (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3116770
Default Alt Text
(8 KB)
Attached To
Mode
rKYAML Keruald YAML
Attached
Detach File
Event Timeline
Log In to Comment