Skip to content

Commit fd03251

Browse files
committed
create registry
1 parent ab01706 commit fd03251

8 files changed

Lines changed: 10764 additions & 442 deletions

File tree

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use App\Models\Registry;
6+
use Illuminate\Console\Command;
7+
use Illuminate\Support\Facades\Artisan;
8+
use Illuminate\Support\Facades\File;
9+
use Illuminate\Support\Str;
10+
11+
class RegistryBuildCommand extends Command
12+
{
13+
/**
14+
* The name and signature of the console command.
15+
*
16+
* @var string
17+
*/
18+
protected $signature = 'registry:build';
19+
20+
/**
21+
* The console command description.
22+
*
23+
* @var string
24+
*/
25+
protected $description = 'Scan resources/js/registry directory and auto-generate the RegistrySeeder';
26+
27+
/**
28+
* Execute the console command.
29+
*/
30+
public function handle(): int
31+
{
32+
$this->info('Scanning resources/js/registry/new-york...');
33+
34+
$registryDir = resource_path('js/registry/new-york');
35+
if (! File::isDirectory($registryDir)) {
36+
$this->error("Registry directory not found at: {$registryDir}");
37+
38+
return Command::FAILURE;
39+
}
40+
41+
$files = File::allFiles($registryDir);
42+
$registryItems = [];
43+
44+
foreach ($files as $file) {
45+
$relativePath = 'resources/js/registry/new-york/'.str_replace('\\', '/', $file->getRelativePathname());
46+
$pathParts = explode('/', str_replace('\\', '/', $file->getRelativePath()));
47+
$filename = $file->getFilenameWithoutExtension();
48+
49+
if (empty($pathParts[0])) {
50+
continue;
51+
}
52+
53+
$itemType = 'registry:hook';
54+
$category = $pathParts[0];
55+
56+
if ($pathParts[0] === 'hooks') {
57+
$itemType = 'registry:hook';
58+
$category = 'hooks';
59+
} elseif ($pathParts[0] === 'lib') {
60+
$itemType = 'registry:lib';
61+
$category = 'lib';
62+
} elseif ($pathParts[0] === 'components') {
63+
if (isset($pathParts[1]) && $pathParts[1] === 'ui') {
64+
$itemType = 'registry:ui';
65+
$category = $pathParts[2] ?? 'components';
66+
} else {
67+
$itemType = 'registry:block';
68+
$category = 'blocks';
69+
}
70+
}
71+
72+
$name = ($itemType === 'registry:block') ? ($pathParts[1] ?? $filename) : $filename;
73+
74+
if (isset($registryItems[$name])) {
75+
$registryItems[$name]['files'][] = [
76+
'path' => $relativePath,
77+
'type' => $itemType,
78+
];
79+
if (in_array($itemType, ['registry:ui', 'registry:block'], true)) {
80+
$registryItems[$name]['type'] = $itemType;
81+
$registryItems[$name]['categories'] = [$category];
82+
}
83+
} else {
84+
$registryItems[$name] = [
85+
'name' => $name,
86+
'title' => Str::headline($name),
87+
'type' => $itemType,
88+
'categories' => [$category],
89+
'files' => [
90+
[
91+
'path' => $relativePath,
92+
'type' => $itemType,
93+
],
94+
],
95+
];
96+
}
97+
}
98+
99+
$this->info('Resolving file contents and dependencies...');
100+
101+
foreach ($registryItems as $name => &$item) {
102+
$dependencies = [];
103+
$registryDependencies = [];
104+
105+
foreach ($item['files'] as &$fileInfo) {
106+
$filePath = base_path($fileInfo['path']);
107+
if (! File::exists($filePath)) {
108+
continue;
109+
}
110+
$content = File::get($filePath);
111+
$fileInfo['content'] = $content;
112+
113+
// Parse import statements
114+
preg_match_all('/import\s+(?:[^"\']*?\s+from\s+)?["\'"]([^"\']+)["\'"]/', $content, $matches);
115+
116+
if (! empty($matches[1])) {
117+
foreach ($matches[1] as $importPath) {
118+
if (str_starts_with($importPath, '@/registry/new-york/')) {
119+
// Local registry import
120+
$depName = basename($importPath);
121+
$depName = preg_replace('/\.(tsx|ts|js|jsx)$/', '', $depName);
122+
123+
// Skip if it's an internal file of the same block
124+
$isInternal = false;
125+
foreach ($item['files'] as $f) {
126+
$fName = basename($f['path']);
127+
$fName = preg_replace('/\.(tsx|ts|js|jsx)$/', '', $fName);
128+
if ($fName === $depName) {
129+
$isInternal = true;
130+
break;
131+
}
132+
}
133+
134+
if (! $isInternal) {
135+
$registryDependencies[] = $depName;
136+
}
137+
} elseif (str_starts_with($importPath, '@/components/ui/')) {
138+
$depName = basename($importPath);
139+
$depName = preg_replace('/\.(tsx|ts|js|jsx)$/', '', $depName);
140+
$registryDependencies[] = $depName;
141+
} elseif (str_starts_with($importPath, '@/lib/utils')) {
142+
$registryDependencies[] = 'utils';
143+
} elseif (! str_starts_with($importPath, '.') && ! str_starts_with($importPath, '@/')) {
144+
// NPM Dependency
145+
$parts = explode('/', $importPath);
146+
$packageName = $parts[0];
147+
if (str_starts_with($packageName, '@') && isset($parts[1])) {
148+
$packageName .= '/'.$parts[1];
149+
}
150+
151+
if (! in_array($packageName, ['react', 'react-dom'])) {
152+
$dependencies[] = $packageName;
153+
}
154+
}
155+
}
156+
}
157+
}
158+
159+
$item['dependencies'] = array_values(array_unique($dependencies));
160+
$item['registryDependencies'] = array_values(array_unique($registryDependencies));
161+
$item['author'] = 'designbycode';
162+
$item['meta'] = [
163+
'category' => $item['categories'][0] ?? 'components',
164+
'version' => '1.0.0',
165+
];
166+
}
167+
unset($item);
168+
169+
// Resolve local registryDependencies to full URLs
170+
$scannedNames = array_keys($registryItems);
171+
foreach ($registryItems as $name => &$item) {
172+
$resolvedRegDeps = [];
173+
foreach ($item['registryDependencies'] as $dep) {
174+
if (in_array($dep, $scannedNames, true)) {
175+
$resolvedRegDeps[] = url("r/{$dep}.json");
176+
} else {
177+
$resolvedRegDeps[] = $dep;
178+
}
179+
}
180+
$item['registryDependencies'] = $resolvedRegDeps;
181+
}
182+
unset($item);
183+
184+
$databaseRecords = [];
185+
foreach ($registryItems as $name => $item) {
186+
try {
187+
$parsed = Registry::fromRegistry($item);
188+
$attributes = $parsed->toArray();
189+
unset($attributes['id'], $attributes['created_at'], $attributes['updated_at'], $attributes['deleted_at'], $attributes['user_id']);
190+
$databaseRecords[] = $attributes;
191+
} catch (\Exception $e) {
192+
$this->error("Failed to parse registry item [{$name}]: ".$e->getMessage());
193+
}
194+
}
195+
196+
$this->info('Generating RegistrySeeder.php...');
197+
198+
$itemsPhpCode = $this->exportArray($databaseRecords, 12);
199+
200+
$seederTemplate = <<<PHP
201+
<?php
202+
203+
namespace Database\Seeders;
204+
205+
use App\Models\Registry;
206+
use App\Models\User;
207+
use Illuminate\Database\Seeder;
208+
209+
class RegistrySeeder extends Seeder
210+
{
211+
/**
212+
* Run the database seeds.
213+
*/
214+
public function run(): void
215+
{
216+
\$userId = User::first()?->id ?? 1;
217+
218+
\$items = [
219+
{$itemsPhpCode}
220+
];
221+
222+
\$total = 0;
223+
224+
foreach (\$items as \$item) {
225+
Registry::updateOrCreate(
226+
['name' => \$item['name']],
227+
array_merge(\$item, ['user_id' => \$userId])
228+
);
229+
\$total++;
230+
}
231+
232+
\$this->command->info("Seeded {\$total} registry items.");
233+
}
234+
}
235+
PHP;
236+
237+
$seederPath = database_path('seeders/RegistrySeeder.php');
238+
File::put($seederPath, $seederTemplate);
239+
240+
$this->info("RegistrySeeder.php generated successfully at {$seederPath}.");
241+
242+
$this->info('Running RegistrySeeder to seed/update database...');
243+
Artisan::call('db:seed', [
244+
'--class' => 'RegistrySeeder',
245+
'--force' => true,
246+
]);
247+
248+
$this->info(Artisan::output());
249+
$this->info('Registry build completed successfully!');
250+
251+
return Command::SUCCESS;
252+
}
253+
254+
/**
255+
* Export array to PHP array string with short syntax.
256+
*/
257+
private function exportArray(array $array, int $indent = 12): string
258+
{
259+
$indentStr = str_repeat(' ', $indent);
260+
$lines = [];
261+
$isAssociative = array_keys($array) !== range(0, count($array) - 1);
262+
263+
foreach ($array as $key => $value) {
264+
$renderedKey = $isAssociative ? var_export($key, true).' => ' : '';
265+
if (is_array($value)) {
266+
$renderedValue = "[\n".$this->exportArray($value, $indent + 4)."\n".str_repeat(' ', $indent).']';
267+
} elseif (is_null($value)) {
268+
$renderedValue = 'null';
269+
} else {
270+
$renderedValue = var_export($value, true);
271+
}
272+
$lines[] = $indentStr.$renderedKey.$renderedValue.',';
273+
}
274+
275+
return implode("\n", $lines);
276+
}
277+
}

0 commit comments

Comments
 (0)