packages/sql-parser/src/Resource/ResourceWriter.php
1<?php
2
3declare(strict_types=1);
4
5namespace SqlParser\Resource;
6
7use RuntimeException;
8use SqlParser\Table\ParseTable;
9use SqlParser\Table\TableFile;
10
11/**
12 * Writes the generated resources of one release where the registry expects them.
13 *
14 * @visibility root
15 */
16final class ResourceWriter
17{
18 /**
19 * @param TableFile $tables Stores parse tables
20 */
21 public function __construct(private readonly TableFile $tables = new TableFile())
22 {
23 }
24
25 /**
26 * Writes the parse table of a release.
27 *
28 * @param SqlVersion $version The release
29 * @param ParseTable $table Its table
30 *
31 * @throws RuntimeException When the file cannot be written
32 */
33 public function writeTable(SqlVersion $version, ParseTable $table): void
34 {
35 $this->ensureDirectory($version->tablePath);
36 $this->tables->save($table, $version->tablePath);
37 }
38
39 /**
40 * Writes the keyword table of a release as a PHP file returning an array.
41 *
42 * @param SqlVersion $version The release
43 * @param array<string, array<string, string>> $keywords Terminal name by spelling, by group
44 * @param string $origin Where the keywords were read from
45 *
46 * @throws RuntimeException When the file cannot be written
47 */
48 public function writeKeywords(SqlVersion $version, array $keywords, string $origin): void
49 {
50 $this->ensureDirectory($version->keywordPath);
51 $body = "<?php\n\ndeclare(strict_types=1);\n\n/**\n * Keyword tokens of {$version->name}, generated from {$origin}.\n *\n * @return array<string, array<string, string>>\n */\nreturn " . $this->export($keywords, 0) . ";\n";
52 if (file_put_contents($version->keywordPath, $body) === false) {
53 throw new RuntimeException("Cannot write keyword table to {$version->keywordPath}");
54 }
55 }
56
57 /**
58 * Renders a nested array of strings as PHP source, one entry per line.
59 *
60 * @param array<string, array<string, string>|string> $values Values to render
61 * @param int $indent Nesting depth
62 *
63 * @return string PHP source of the array
64 */
65 public function export(array $values, int $indent): string
66 {
67 $pad = str_repeat(' ', $indent + 1);
68 $lines = ['['];
69 foreach ($values as $key => $value) {
70 $rendered = is_array($value) ? $this->export($value, $indent + 1) : var_export($value, true);
71 $lines[] = $pad . var_export($key, true) . ' => ' . $rendered . ',';
72 }
73 $lines[] = str_repeat(' ', $indent) . ']';
74
75 return implode("\n", $lines);
76 }
77
78 /**
79 * Makes sure the directory of a path exists.
80 *
81 * @param string $path File about to be written
82 *
83 * @throws RuntimeException When the directory cannot be made
84 */
85 public function ensureDirectory(string $path): void
86 {
87 $directory = dirname($path);
88 if (!is_dir($directory) && !mkdir($directory, 0777, true) && !is_dir($directory)) {
89 throw new RuntimeException("Cannot create {$directory}");
90 }
91 }
92}
93