PHP code example of mougrim / yaml-cst

1. Go to this page and download the library: Download mougrim/yaml-cst library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

mougrim / yaml-cst example snippets


use Mougrim\YamlCst\DomainModel\YamlPatch;
use Mougrim\YamlCst\Factory\YamlLineMapFactory;
use Mougrim\YamlCst\Factory\YamlSyntaxExceptionFactory;
use Mougrim\YamlCst\Factory\YamlTreeSitterCoreFactory;
use Mougrim\YamlCst\Helper\YamlTextStyleHelper;
use Mougrim\YamlCst\YamlCstParser;
use Mougrim\YamlCst\YamlDocumentPatchApplier;
use Mougrim\YamlCst\YamlIndexBuilder;
use Mougrim\YamlCst\YamlPatchConflictChecker;

$lineMapFactory = new YamlLineMapFactory();
$core = (new YamlTreeSitterCoreFactory())->create(); // create once per process
$parser = new YamlCstParser(
    $lineMapFactory,
    new YamlIndexBuilder(new YamlTextStyleHelper()),
    new YamlSyntaxExceptionFactory($lineMapFactory),
);
$applier = new YamlDocumentPatchApplier($parser, new YamlPatchConflictChecker());

$yaml = "database:\n  host: localhost\n  port: 5432\n";
$document = $parser->parse($yaml, $core);

// Read a value
echo $document->index->get(['database', 'host'])->valueText($yaml); // localhost

// Patch a value and get a new document
$span = $document->index->get(['database', 'host'])->valueSpan();
$updated = $applier->apply($document, $core, [new YamlPatch($span, 'production.db')]);
echo $updated->source; // database:\n  host: production.db\n  port: 5432\n

use Mougrim\YamlCst\Factory\YamlLineMapFactory;
use Mougrim\YamlCst\Factory\YamlSyntaxExceptionFactory;
use Mougrim\YamlCst\Factory\YamlTreeSitterCoreFactory;
use Mougrim\YamlCst\Helper\YamlTextStyleHelper;
use Mougrim\YamlCst\YamlCstParser;
use Mougrim\YamlCst\YamlDocumentPatchApplier;
use Mougrim\YamlCst\YamlIndexBuilder;
use Mougrim\YamlCst\YamlPatchConflictChecker;

// Create the native core once — reuse it for every parse() call.
$core = (new YamlTreeSitterCoreFactory())->create();

$lineMapFactory = new YamlLineMapFactory();
$parser = new YamlCstParser(
    $lineMapFactory,
    new YamlIndexBuilder(
        textStyleHelper: new YamlTextStyleHelper(),
    ),
    new YamlSyntaxExceptionFactory($lineMapFactory),
);

$conflictChecker = new YamlPatchConflictChecker();
$applier = new YamlDocumentPatchApplier($parser, $conflictChecker);

$yaml = <<<YAML
database:
  host: localhost
  port: 5432
  credentials:
    user: app
    password: secret
YAML;

$document = $parser->parse($yaml, $core);

// Primary API — segment-based, unambiguous
$hostPair = $document->index->get(['database', 'host']);

echo $hostPair->keyText;  // "host"

// Extract the value text using its byte span
$valueSpan = $hostPair->valueSpan();
echo substr($yaml, $valueSpan->startByte, $valueSpan->length());
// "localhost"

// Check whether a path exists before accessing it
if ($document->index->has(['database', 'port'])) {
    $portPair = $document->index->get(['database', 'port']);
}

// Non-throwing lookup — returns null when not found
$portPair = $document->index->find(['database', 'port']);
if ($portPair !== null) {
    // ...
}

// Get the raw value text directly (convenience method)
$hostText = $document->index->get(['database', 'host'])->valueText($yaml);
// "localhost"

// List direct children of a parent segment path
$dbChildren = $document->index->childrenOf(['database']);
foreach ($dbChildren as $pair) {
    echo $pair->keyText . "\n";
    // host, port, credentials
}

// Lookup a key whose name contains a literal dot — unambiguous with segments
$dotKeyPair = $document->index->find(['my.key']); // key literally named "my.key"

// All indexed segment paths in document order: [['database'], ['database','host'], ...]
$paths = $document->index->allPaths();

// Convenience: dot-joined path strings (fine when key names don't contain dots)
$dotPaths = $document->index->allDotPaths(); // ['database', 'database.host', ...]
$hostPair = $document->index->getByPath('database.host');

use Mougrim\YamlCst\DomainModel\YamlPatch;

$valueSpan = $document->index->get(['database', 'host'])->valueSpan();

// Collect patches and pass them to apply() — returns a new, re-parsed document
// $applier is created in the setup section above
$updated = $applier->apply($document, $core, [
    new YamlPatch($valueSpan, 'production.db.example.com'),
]);

echo $updated->source;
// database:
//   host: production.db.example.com
//   port: 5432
//   ...

use Mougrim\YamlCst\Enum\YamlNodeType;
use Mougrim\YamlCst\YamlCstSearcher;

$yaml = <<<YAML
servers:
  - host: web1
    port: 80
  - host: web2
    port: 80
YAML;

$document = $parser->parse($yaml, $core);
$searcher = new YamlCstSearcher();

// Find the first BLOCK_MAPPING_PAIR anywhere in the tree
$firstPair = $searcher->firstDescendantOfType(
    $document->tree->root(),
    YamlNodeType::BLOCK_MAPPING_PAIR,
);

// Iterate the direct BLOCK_MAPPING_PAIR children of a block-mapping node
$blockMapping = $searcher->firstDescendantOfType(
    $document->tree->root(),
    YamlNodeType::BLOCK_MAPPING,
);

if ($blockMapping !== null) {
    foreach ($searcher->directMappingPairs($blockMapping) as $pair) {
        $keyNode = $pair->childByField(\Mougrim\YamlCst\Enum\YamlNodeField::KEY);
        echo $keyNode->text($yaml) . "\n"; // "servers"
    }
}

// Iterate items in a block sequence using the convenience helper
$blockSequence = $searcher->firstDescendantOfType(
    $document->tree->root(),
    YamlNodeType::BLOCK_SEQUENCE,
);

if ($blockSequence !== null) {
    foreach ($searcher->directSequenceItems($blockSequence) as $item) {
        // $item is a block_sequence_item node
        echo $item->type()?->value . "\n";
    }
}

// Skip comment nodes during traversal
foreach ($node->namedChildren() as $child) {
    if ($child->isExtra()) {
        continue; // skip comments and other extras
    }
    // process $child
}

// Find ALL block-mapping pairs in the tree (not just the first)
$allPairs = $searcher->allDescendantsOfType(
    $document->tree->root(),
    YamlNodeType::BLOCK_MAPPING_PAIR,
);

// Navigate to a sibling node
$node = $searcher->firstDescendantOfType($document->tree->root(), YamlNodeType::BLOCK_MAPPING_PAIR);

if ($node !== null) {
    $next = $node->nextNamedSibling();
    if (!$next->isNull()) {
        echo $next->type()?->value . "\n";
    }

    $prev = $node->previousNamedSibling();
    if (!$prev->isNull()) {
        echo $prev->type()?->value . "\n";
    }
}

// Using valueText() — the shortest form
$host = $document->index->get(['database', 'host'])->valueText($yaml);

// Equivalent using spans
$span = $document->index->get(['database', 'host'])->valueSpan();
$host = $span !== null ? substr($yaml, $span->startByte, $span->length()) : null;

$helper = new YamlTextStyleHelper();
$rawValue = $document->index->get(['database', 'host'])->valueText($yaml); // '"localhost"'

// Minimal unescaping (only \" and '' are handled)
$value = $helper->normalizeScalar($rawValue); // 'localhost'

// Full YAML 1.2 unescaping (\n, \t, \\, \uXXXX, etc.)
$fullyUnescaped = $helper->fullyNormalizeScalar($rawValue); // 'localhost'

$rawPair = $document->index->get(['database', 'host'])->pairText($yaml);
// "host: localhost"

use Mougrim\YamlCst\Helper\YamlMappingPatchHelper;

$patchHelper = new YamlMappingPatchHelper(
    textStyleHelper: new YamlTextStyleHelper(),
);
$updated = $applier->apply($document, $core, [
    $patchHelper->replacementPatch(
        $document->index->get(['database', 'host']),
        'production.db.example.com',
    ),
]);

use Mougrim\YamlCst\DomainModel\YamlPatch;

$valueSpan = $document->index->get(['database', 'host'])->valueSpan();

$updated = $applier->apply($document, $core, [
    new YamlPatch($valueSpan, 'production.db.example.com'),
]);

use Mougrim\YamlCst\Helper\YamlMappingPatchHelper;

$patchHelper = new YamlMappingPatchHelper(
    textStyleHelper: new YamlTextStyleHelper(),
);
$patch = $patchHelper->deletionPatch(
    $document->source,
    $document->index->get(['database', 'password']),
);

$updated = $applier->apply($document, $core, [$patch]);

use Mougrim\YamlCst\Helper\YamlMappingPatchHelper;

$patchHelper = new YamlMappingPatchHelper(
    textStyleHelper: new YamlTextStyleHelper(),
);
$patch = $patchHelper->insertionPatch(
    $document->source,
    $document->index->get(['database', 'port']),
    'timeout: 30',
);

$updated = $applier->apply($document, $core, [$patch]);

use Mougrim\YamlCst\Exception\PathNotFoundException;
use Mougrim\YamlCst\Exception\PatchConflictException;
use Mougrim\YamlCst\Exception\YamlSyntaxException;

try {
    $document = $parser->parse($invalidYaml, $core);
} catch (YamlSyntaxException $e) {
    // "YAML syntax error at line 3 (byte 42): ..."
    echo $e->getMessage();
}

try {
    $document->index->get(['nonexistent', 'path']);
} catch (PathNotFoundException $e) {
    echo $e->getMessage();  // "Path not found: nonexistent.path"
}

$span = $document->index->get(['database', 'host'])->keySpan();
$location = $document->lineMap->locate($span->startByte);

echo "Line {$location->line}, column {$location->col}";

use Mougrim\YamlCst\Helper\YamlTextStyleHelper;

$helper = new YamlTextStyleHelper();

// Detect the end-of-line sequence used in the source ("\r\n" or "\n")
$eol = $helper->detectEndOfLine($yaml);

// Find the byte offset where the line containing $byteOffset starts
$lineStart = $helper->lineStart($yaml, $byteOffset);

// Extract the leading whitespace (indent) before a given byte offset
$indent = $helper->indentOfLineTo($yaml, $lineStart, $byteOffset);

// Find the byte offset after the next newline (useful for line-level patching)
$nextLine = $helper->nextLineBreakEnd($yaml, $byteOffset);

// Fully unescape a double-quoted YAML scalar (all YAML 1.2 escape sequences)
$resolved = $helper->fullyNormalizeScalar('"hello\\nworld"'); // "hello\nworld"

$core = (new YamlTreeSitterCoreFactory())->create(
    coreLibPath: '/opt/lib/libtree-sitter.so',
    yamlLibPath: '/opt/lib/libtree-sitter-yaml.so',
);

use Mougrim\YamlCst\Exception\YamlCstExceptionInterface;

try {
    $document = $parser->parse($yaml, $core);
    $pair = $document->index->get(['database', 'host']);
} catch (YamlCstExceptionInterface $e) {
    // handles all yaml-cst exceptions
}
ini
ffi.enable = true