Skip to content

Commit 9fe400f

Browse files
authored
Merge pull request #1348 from hydephp/refactor-internal-scripts
Add internal file formatter script
2 parents 9502955 + 9ce2ebc commit 9fe400f

File tree

1 file changed

+280
-0
lines changed

1 file changed

+280
-0
lines changed

monorepo/scripts/FileFormatter.php

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* @internal
7+
*/
8+
require_once __DIR__.'/../../vendor/autoload.php';
9+
10+
$timeStart = microtime(true);
11+
12+
$filesChanged = 0;
13+
$linesCounted = 0;
14+
$dryRun = true;
15+
16+
enum Settings: string
17+
{
18+
case UseUnixFileEndings = 'useUnixFileEndings';
19+
case ReplaceTabsWithSpaces = 'replaceTabsWithSpaces';
20+
case TrimTrailingSpaces = 'trimTrailingSpaces';
21+
case TrimMultipleEmptyLines = 'trimMultipleEmptyLines';
22+
case ForceEmptyLinesAtEndOfFile = 'forceEmptyLinesAtEndOfFile';
23+
}
24+
25+
$settings = [
26+
Settings::UseUnixFileEndings,
27+
Settings::ReplaceTabsWithSpaces,
28+
Settings::TrimTrailingSpaces,
29+
// Settings::TrimMultipleEmptyLines,
30+
Settings::ForceEmptyLinesAtEndOfFile,
31+
];
32+
33+
class CodeFormatter
34+
{
35+
protected string $input;
36+
protected string $output;
37+
protected string $filename;
38+
protected array $settings;
39+
40+
public function __construct(string $input, string $filename, array $settings)
41+
{
42+
$this->input = $input;
43+
$this->filename = $filename;
44+
$this->settings = $settings;
45+
46+
$this->run();
47+
}
48+
49+
protected function run(): void
50+
{
51+
$text = $this->input;
52+
$filename = $this->filename;
53+
54+
$text = $this->useUnixFileEndings($text);
55+
$text = $this->replaceTabsWithSpaces($text);
56+
57+
if (empty(trim($text))) {
58+
// Warn
59+
global $warnings;
60+
$warnings[] = "File $filename is empty";
61+
62+
return;
63+
}
64+
65+
$lines = explode("\n", $text);
66+
$new_lines = [];
67+
68+
$last_line = '';
69+
70+
foreach ($lines as $index => $line) {
71+
global $linesCounted;
72+
$linesCounted++;
73+
74+
/** Normalization */
75+
76+
// Remove multiple empty lines
77+
if (in_array(Settings::TrimMultipleEmptyLines, $this->settings)) {
78+
if (trim($line) == '' && trim($last_line) == '') {
79+
continue;
80+
}
81+
}
82+
83+
$line = $this->trimTrailingSpaces($line);
84+
85+
$new_lines[] = $line;
86+
$last_line = $line;
87+
}
88+
89+
$new_content = implode("\n", $new_lines);
90+
if (in_array(Settings::ForceEmptyLinesAtEndOfFile, $this->settings)) {
91+
$new_content = trim($new_content);
92+
$shouldEndWithNewLine = ! str_ends_with($filename, '.blade.php');
93+
if ($shouldEndWithNewLine) {
94+
$new_content .= "\n";
95+
}
96+
}
97+
$this->output = $new_content;
98+
}
99+
100+
public function getOutput(): string
101+
{
102+
return $this->output;
103+
}
104+
105+
protected function useUnixFileEndings(string $text): string
106+
{
107+
if (! in_array(Settings::UseUnixFileEndings, $this->settings)) {
108+
return $text;
109+
}
110+
111+
return str_replace("\r\n", "\n", $text);
112+
}
113+
114+
protected function replaceTabsWithSpaces(string $text): string
115+
{
116+
if (! in_array(Settings::ReplaceTabsWithSpaces, $this->settings)) {
117+
return $text;
118+
}
119+
120+
return str_replace("\t", ' ', $text);
121+
}
122+
123+
protected function trimTrailingSpaces(string $line): string
124+
{
125+
if (! in_array(Settings::TrimTrailingSpaces, $this->settings)) {
126+
return $line;
127+
}
128+
129+
$line = rtrim($line);
130+
131+
return $line;
132+
}
133+
}
134+
135+
function format_file($filename): void
136+
{
137+
// echo 'Handling '.$filename."\n";
138+
$stream = file_get_contents($filename);
139+
140+
global $settings;
141+
$formatter = new CodeFormatter($stream, $filename, $settings);
142+
$new_content = $formatter->getOutput();
143+
144+
global $dryRun;
145+
if (! $dryRun) {
146+
file_put_contents($filename, $new_content);
147+
}
148+
149+
if ($new_content !== $stream) {
150+
echo 'Saving '.$filename."\n";
151+
if ($dryRun) {
152+
echo "\33[37m";
153+
echo linediff($stream, $new_content);
154+
echo "\33[0m";
155+
}
156+
global $filesChanged;
157+
$filesChanged++;
158+
}
159+
}
160+
161+
function linediff(string $a, string $b): string
162+
{
163+
$a = explode("\n", $a);
164+
$b = explode("\n", $b);
165+
166+
$diffed = array_diff($a, $b);
167+
$wasLastLineEmpty = false;
168+
$diff = '';
169+
foreach ($diffed as $line) {
170+
if (trim($line) == '') {
171+
if ($wasLastLineEmpty) {
172+
continue;
173+
}
174+
$wasLastLineEmpty = true;
175+
} else {
176+
$wasLastLineEmpty = false;
177+
}
178+
$diff .= "\u{0394}".$line."\n";
179+
}
180+
if (trim($diff) === "\u{0394}") {
181+
return 'Added newline at end of file'."\n";
182+
}
183+
184+
return $diff;
185+
}
186+
187+
function find_files(): array
188+
{
189+
$files = [];
190+
191+
$directories = [
192+
__DIR__.'/../../packages',
193+
__DIR__.'/../../tests',
194+
__DIR__.'/../../.github',
195+
];
196+
197+
foreach ($directories as $directory) {
198+
$files = array_merge($files, find_files_in_directory($directory));
199+
}
200+
201+
return $files;
202+
}
203+
204+
function find_files_in_directory(string $directory): array
205+
{
206+
$files = [];
207+
$excludedDirectories = [
208+
'node_modules',
209+
'vendor',
210+
];
211+
212+
$extensions = [
213+
'php',
214+
'blade.php',
215+
'js',
216+
'css',
217+
'yml',
218+
'json',
219+
'md',
220+
];
221+
222+
$directory = realpath($directory);
223+
if ($directory === false) {
224+
return $files;
225+
}
226+
227+
$iterator = new RecursiveIteratorIterator(
228+
new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS),
229+
RecursiveIteratorIterator::SELF_FIRST,
230+
RecursiveIteratorIterator::CATCH_GET_CHILD // Ignore "Permission denied"
231+
);
232+
233+
foreach ($iterator as $file) {
234+
if ($file->isDir()) {
235+
continue;
236+
}
237+
238+
// Skip excluded directories
239+
$path = $file->getPath();
240+
foreach ($excludedDirectories as $excludedDirectory) {
241+
if (str_contains($path, $excludedDirectory)) {
242+
continue 2;
243+
}
244+
}
245+
246+
if (in_array($file->getExtension(), $extensions)) {
247+
$files[] = $file->getPathname();
248+
}
249+
}
250+
251+
return $files;
252+
}
253+
254+
$codeFiles = find_files();
255+
256+
foreach ($codeFiles as $file) {
257+
format_file($file);
258+
}
259+
260+
$time = round((microtime(true) - $timeStart) * 1000, 2);
261+
$linesTransformed = number_format($linesCounted);
262+
$fileCount = count($codeFiles);
263+
264+
echo "\n\n\033[32mAll done!\033[0m Formatted, normalized, and validated $linesTransformed lines of code in $fileCount files in {$time}ms\n";
265+
266+
if ($filesChanged > 0) {
267+
echo "\n\033[32m$filesChanged files were changed.\033[0m ";
268+
} else {
269+
echo "\n\033[32mNo files were changed.\033[0m ";
270+
}
271+
272+
// If --git flag is passed, make a git commit
273+
if (isset($argv[1]) && $argv[1] === '--git') {
274+
if ($filesChanged > 0) {
275+
echo "\n\033[33mCommitting changes to git...\033[0m\n";
276+
passthru('git commit -am "Format Code"');
277+
} else {
278+
echo "\n\033[33mNo changes to commit\033[0m\n";
279+
}
280+
}

0 commit comments

Comments
 (0)