1: <?php
2:
3: namespace LaravelUi5\Core\Commands;
4:
5: use Illuminate\Filesystem\Filesystem;
6: use Illuminate\Support\Facades\File;
7: use Illuminate\Support\Str;
8: use Symfony\Component\Yaml\Yaml;
9: use Throwable;
10:
11: class GenerateUi5LibraryCommand extends BaseGenerator
12: {
13: protected $signature = 'ui5:lib
14: {name : The CamelCase name of the library}
15: {--php-ns-prefix=Pragmatiqu : The PHP namespace prefix}
16: {--js-ns-prefix=io.pragmatiqu : The JS namespace prefix}
17: {--create : Create a new module from scratch}
18: {--refresh : Refresh metadata and assets from source project}';
19:
20: protected $description = 'Generate a Ui5Library implementation from a UI5 library build';
21:
22: protected Filesystem $files;
23:
24: public function __construct(Filesystem $files)
25: {
26: parent::__construct();
27: $this->files = $files;
28: }
29:
30: public function handle(): int
31: {
32: $name = $this->argument('name');
33: $this->assertCamelCase('Ui5Library', $name);
34:
35: $kebab = Str::kebab($name);
36: $phpPrefix = rtrim($this->option('php-ns-prefix'), '\\');
37: $phpNamespace = "{$phpPrefix}\\{$name}";
38: $jsPrefix = rtrim($this->option('js-ns-prefix'), '.');
39:
40: // Support both LaravelUi5 and Easy UI5 conventions
41: $conventionPaths = [
42: base_path("../ui5-{$kebab}-lib/"),
43: base_path("../{$jsPrefix}.{$kebab}/"),
44: ];
45:
46: $sourcePath = collect($conventionPaths)->first(fn($path) => File::exists($path));
47: if (is_null($sourcePath)) {
48: $this->components->error("Source folder for UI5 lib not found. Tried:");
49: foreach ($conventionPaths as $conventionPath) {
50: $this->components->info("- {$conventionPath}");
51: }
52: return self::FAILURE;
53: }
54:
55: $targetPath = base_path("ui5/{$name}/src/");
56: $classPath = base_path("ui5/{$name}/src/{$name}Library.php");
57: $modulePath = base_path("ui5/{$name}/src/{$name}Module.php");
58:
59: $create = $this->option('create');
60: $refresh = $this->option('refresh');
61: $moduleExists = File::exists($classPath);
62:
63: // Decision tree
64: if ($create && $moduleExists) {
65: $this->components->error("Module already exists. Use --refresh to update.");
66: return 1;
67: }
68:
69: if ($refresh && !$moduleExists) {
70: $this->components->error("Module does not exist. Use --create to scaffold.");
71: return 1;
72: }
73:
74: if (!$create && !$refresh) {
75: if ($moduleExists) {
76: $this->components->info("Module already exists. Use --refresh to update.");
77: } else {
78: $this->components->info("Module does not exist. Use --create to scaffold.");
79: }
80: return 0;
81: }
82:
83: $yaml = Yaml::parseFile($sourcePath . 'ui5.yaml');
84: $ui5Namespace = $yaml['metadata']['name'] ?? null;
85: if (!$ui5Namespace || !is_string($ui5Namespace)) {
86: $this->components->error("Invalid or missing namespace in ui5.yaml");
87: return 1;
88: }
89:
90: $distPath = $sourcePath . 'dist/resources/' . Str::of($ui5Namespace)->replace('.', '/');
91: $libraryPath = "{$distPath}/.library";
92: if (!File::exists($libraryPath)) {
93: $this->components->error("Failed to load .library file at: {$libraryPath}");
94: $this->newLine();
95: $this->components->info("Run `npm run build` to create library assets.");
96: return 1;
97: }
98:
99: $libraryXml = simplexml_load_file($libraryPath);
100: $title = (string)$libraryXml->title ?? 'Untitled';
101: $description = (string)$libraryXml->documentation ?? 'No description';
102: $vendor = (string)$libraryXml->vendor ?? 'Vendor not supplied';
103:
104: $package = json_decode(file_get_contents($sourcePath . 'package.json'), true);
105: $version = $package['version'] ?? '1.0.0';
106:
107: File::ensureDirectoryExists($targetPath);
108:
109: // Generate class
110: $this->files->put($classPath, $this->compileStub('Ui5Library.stub', [
111: 'namespace' => $phpNamespace,
112: 'class' => "{$name}Library",
113: 'ui5Namespace' => $ui5Namespace,
114: 'version' => $version,
115: 'title' => $title,
116: 'description' => $description,
117: 'vendor' => $vendor,
118: ]));
119:
120: $this->files->put($modulePath, $this->compileStub('Ui5ModuleLib.stub', [
121: 'phpNamespace' => $phpNamespace,
122: 'class' => "{$name}Library",
123: 'moduleClass' => "{$name}Module",
124: ]));
125:
126: // Copy artefacts
127: $i18nFiles = collect(File::files($sourcePath))
128: ->filter(fn($f) => Str::endsWith($f->getFilename(), '.properties'))
129: ->map(fn($f) => $f->getFilename())
130: ->all();
131:
132: $staticFiles = collect([
133: 'library-preload.js',
134: 'library-preload.js.map',
135: 'library-dbg.js',
136: 'library-dbg.js.map',
137: ]);
138:
139: $assets = $staticFiles->merge($i18nFiles)->unique()->values()->all();
140:
141: $this->copyDistAssets($distPath, $targetPath, $assets);
142:
143: $operation = $moduleExists ? 'Updated' : 'Created';
144: $this->components->success("{$operation} Ui5Library module `{$name}`");
145:
146: return self::SUCCESS;
147: }
148: }
149: