5
5
use Exception ;
6
6
use Illuminate \Console \GeneratorCommand ;
7
7
use Illuminate \Contracts \Filesystem \FileNotFoundException ;
8
+ use Illuminate \Support \Str ;
9
+ use InvalidArgumentException ;
8
10
use Kirschbaum \Paragon \Concerns \Builders \EnumBuilder ;
9
11
use Kirschbaum \Paragon \Concerns \Builders \EnumJsBuilder ;
10
12
use Kirschbaum \Paragon \Concerns \Builders \EnumTsBuilder ;
13
+ use Kirschbaum \Paragon \Concerns \DiscoverEnums ;
11
14
use Kirschbaum \Paragon \Generators \AbstractEnumGenerator ;
15
+ use Kirschbaum \Paragon \Generators \EnumGenerator ;
16
+ use ReflectionEnum ;
17
+ use ReflectionException ;
12
18
use Symfony \Component \Console \Attribute \AsCommand ;
13
19
use Symfony \Component \Console \Input \InputArgument ;
20
+ use Symfony \Component \Console \Input \InputInterface ;
14
21
use Symfony \Component \Console \Input \InputOption ;
22
+ use Symfony \Component \Console \Output \OutputInterface ;
23
+ use Throwable ;
24
+ use UnitEnum ;
15
25
26
+ use function Laravel \Prompts \search ;
16
27
use function Laravel \Prompts \text ;
17
28
18
29
#[AsCommand(name: 'paragon:enum:add-method ' , description: 'Create a new global typescript method to be applied to every generated enum ' )]
@@ -28,9 +39,9 @@ public function handle(): ?bool
28
39
{
29
40
parent ::handle ();
30
41
31
- app (AbstractEnumGenerator::class, [ ' builder ' => $ this ->builder ()]) ();
42
+ $ this ->runGenerator ();
32
43
33
- $ this ->components -> info ( " Abstract enum class has been rebuilt to include new [ { $ this -> name ()} ] method. " );
44
+ $ this ->writeInfo ( );
34
45
35
46
return true ;
36
47
}
@@ -70,6 +81,38 @@ protected function promptForMissingArgumentsUsing(): array
70
81
];
71
82
}
72
83
84
+ /**
85
+ * Interact further with the user if they were prompted for missing arguments.
86
+ *
87
+ * @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter
88
+ */
89
+ protected function afterPromptingForMissingArguments (InputInterface $ input , OutputInterface $ output ): void
90
+ {
91
+ if (
92
+ is_string ($ this ->option ('enum ' ))
93
+ || $ this ->option ('global ' )
94
+ ) {
95
+ return ;
96
+ }
97
+
98
+ /**
99
+ * @var string $enumPath
100
+ */
101
+ $ enumPath = config ('paragon.enums.paths.php ' );
102
+
103
+ $ enums = DiscoverEnums::within (app_path ($ enumPath ))
104
+ ->mapWithKeys (fn (ReflectionEnum $ reflector ) => [$ reflector ->getName () => $ reflector ->getName ()]);
105
+
106
+ $ enum = search (
107
+ label: 'Which enum should this method be created for? ' ,
108
+ options: fn (string $ value ) => strlen ($ value ) > 0
109
+ ? $ enums ->filter (fn (string $ enum ): bool => Str::contains ($ enum , $ value , ignoreCase: true ))->all ()
110
+ : []
111
+ );
112
+
113
+ $ input ->setOption ('enum ' , $ enum );
114
+ }
115
+
73
116
/**
74
117
* Build the file with the given name.
75
118
*
@@ -88,15 +131,30 @@ protected function buildClass($name): string
88
131
/**
89
132
* Get the destination class path.
90
133
*
91
- * @throws Exception
134
+ * @throws Throwable
92
135
*/
93
136
protected function getPath ($ name ): string
94
137
{
95
- /** @var string */
96
- $ methods = config ('paragon.enums.paths.methods ' );
138
+ /**
139
+ * @var string $path
140
+ */
141
+ $ path = config ('paragon.enums.paths.methods ' );
97
142
$ extension = $ this ->option ('javascript ' ) ? 'js ' : 'ts ' ;
98
143
99
- return resource_path ($ methods ) . "/ {$ this ->name ()}. {$ extension }" ;
144
+ if (! $ this ->option ('global ' )) {
145
+ $ enum = str ($ this ->enumOption ())->replace ('/ ' , '\\' );
146
+
147
+ throw_unless (
148
+ enum_exists ($ enum ->toString ()),
149
+ ReflectionException::class,
150
+ "Class \"{$ enum }\" does not exist "
151
+ );
152
+
153
+ $ path = $ enum ->replace ('\\' , '/ ' )
154
+ ->prepend (Str::finish ($ path , '/ ' ));
155
+ }
156
+
157
+ return resource_path ($ path ) . "/ {$ this ->name ()}. {$ extension }" ;
100
158
}
101
159
102
160
/**
@@ -120,7 +178,48 @@ protected function builder(): EnumBuilder
120
178
return $ this ->option ('javascript ' )
121
179
? app (EnumJsBuilder::class)
122
180
: app (EnumTsBuilder::class);
181
+ }
182
+
183
+ /**
184
+ * @throws ReflectionException
185
+ * @throws Throwable
186
+ */
187
+ protected function runGenerator (): void
188
+ {
189
+ $ this ->option ('global ' )
190
+ ? app (AbstractEnumGenerator::class, ['builder ' => $ this ->builder ()])()
191
+ : app (EnumGenerator::class, [
192
+ 'enum ' => new ReflectionEnum ($ this ->enumOption ()),
193
+ 'builder ' => $ this ->builder (),
194
+ 'forceRegenerate ' => true ,
195
+ ])();
196
+ }
197
+
198
+ protected function writeInfo (): void
199
+ {
200
+ $ name = $ this ->option ('global ' )
201
+ ? 'Abstract '
202
+ : Str::afterLast ($ this ->enumOption (), '\\' );
123
203
204
+ $ this ->components ->info ("[ {$ name }] enum class has been rebuilt to include new [ {$ this ->name ()}()] method. " );
205
+ }
206
+
207
+ /**
208
+ * @return class-string<UnitEnum>
209
+ *
210
+ * @throws Throwable
211
+ */
212
+ protected function enumOption (): string
213
+ {
214
+ $ enum = $ this ->option ('enum ' );
215
+
216
+ throw_unless (
217
+ is_string ($ enum ) && is_a ($ enum , UnitEnum::class, true ),
218
+ InvalidArgumentException::class,
219
+ 'The enum option must be a valid class-string of a UnitEnum '
220
+ );
221
+
222
+ return $ enum ;
124
223
}
125
224
126
225
/**
@@ -131,6 +230,18 @@ protected function builder(): EnumBuilder
131
230
protected function getOptions (): array
132
231
{
133
232
return [
233
+ new InputOption (
234
+ name: 'enum ' ,
235
+ shortcut: 'e ' ,
236
+ mode: InputOption::VALUE_REQUIRED ,
237
+ description: 'Fully qualified namespace of enum to use ' ,
238
+ ),
239
+ new InputOption (
240
+ name: 'global ' ,
241
+ shortcut: 'g ' ,
242
+ mode: InputOption::VALUE_NONE ,
243
+ description: 'Create global enum method ' ,
244
+ ),
134
245
new InputOption (
135
246
name: 'javascript ' ,
136
247
shortcut: 'j ' ,
0 commit comments