3131use FormatPHP \Exception \UnableToWriteFileException ;
3232use FormatPHP \Extractor \Parser \Descriptor \PhpParser ;
3333use FormatPHP \Extractor \Parser \DescriptorParserInterface ;
34+ use FormatPHP \Extractor \Parser \ParserErrorCollection ;
3435use FormatPHP \Format \Writer \FormatPHPWriter ;
3536use FormatPHP \Format \Writer \SimpleWriter ;
3637use FormatPHP \Format \Writer \SmartlingWriter ;
@@ -67,11 +68,7 @@ class MessageExtractor
6768 private Globber $ globber ;
6869 private LoggerInterface $ logger ;
6970 private MessageExtractorOptions $ options ;
70-
71- /**
72- * @var DescriptorParserInterface[]
73- */
74- private array $ parsers ;
71+ private ParserErrorCollection $ errors ;
7572
7673 /**
7774 * @throws LogicException
@@ -86,7 +83,7 @@ public function __construct(
8683 $ this ->logger = $ logger ;
8784 $ this ->globber = $ globber ;
8885 $ this ->file = $ file ;
89- $ this ->parsers = $ this -> loadParsers ();
86+ $ this ->errors = new ParserErrorCollection ();
9087 }
9188
9289 /**
@@ -135,14 +132,19 @@ public function process(array $files): void
135132 $ this ->writeOutput ($ this ->prepareOutput ($ formatter , $ descriptors ));
136133 }
137134
135+ public function getErrors (): ParserErrorCollection
136+ {
137+ return $ this ->errors ;
138+ }
139+
138140 /**
139141 * @throws UnableToProcessFileException
140142 */
141143 private function parse (DescriptorCollection $ descriptors , string $ filePath ): DescriptorCollection
142144 {
143- foreach ($ this ->parsers as $ parser ) {
145+ foreach ($ this ->getDescriptorParsers () as $ parser ) {
144146 /** @var DescriptorCollection $descriptors */
145- $ descriptors = $ descriptors ->merge ($ parser-> parse ($ filePath ));
147+ $ descriptors = $ descriptors ->merge ($ parser ($ filePath, $ this -> options , $ this -> errors ));
146148 }
147149
148150 return $ descriptors ;
@@ -153,25 +155,50 @@ private function parse(DescriptorCollection $descriptors, string $filePath): Des
153155 *
154156 * @throws LogicException
155157 */
156- private function loadParsers (): array
158+ private function getDescriptorParsers (): array
157159 {
158160 $ parsers = [];
159- $ parsers [] = $ this ->getPhpParser ();
161+
162+ foreach ($ this ->options ->parsers as $ parser ) {
163+ $ parsers [] = $ this ->loadDescriptorParser ($ parser );
164+ }
160165
161166 return $ parsers ;
162167 }
163168
164169 /**
165170 * @throws LogicException
166171 */
167- private function getPhpParser ( ): PhpParser
172+ private function loadDescriptorParser ( string $ parserNameOrScript ): DescriptorParserInterface
168173 {
169- return new PhpParser (
170- $ this ->file ,
171- $ this ->options ->additionalFunctionNames ,
172- $ this ->options ->pragma ,
173- $ this ->options ->preserveWhitespace ,
174- );
174+ switch (strtolower ($ parserNameOrScript )) {
175+ case 'php ' :
176+ return new PhpParser ($ this ->file );
177+ }
178+
179+ if (class_exists ($ parserNameOrScript ) && is_a ($ parserNameOrScript , DescriptorParserInterface::class, true )) {
180+ $ parser = new $ parserNameOrScript ();
181+ } else {
182+ /** @var Closure(string,MessageExtractorOptions,ParserErrorCollection):DescriptorCollection | null $parser */
183+ $ parser = $ this ->file ->loadClosureFromScript ($ parserNameOrScript );
184+ }
185+
186+ if ($ parser instanceof DescriptorParserInterface) {
187+ return $ parser ;
188+ }
189+
190+ if (is_callable ($ parser )) {
191+ return $ this ->createInvokableDescriptorParser ($ parser );
192+ }
193+
194+ throw new InvalidArgumentException (sprintf (
195+ 'The parser provided is not a known descriptor parser, an instance of '
196+ . '%s, or a callable of the shape `callable(string,%s,%s):%s`. ' ,
197+ DescriptorParserInterface::class,
198+ MessageExtractorOptions::class,
199+ ParserErrorCollection::class,
200+ DescriptorCollection::class,
201+ ));
175202 }
176203
177204 /**
@@ -256,4 +283,25 @@ private function writeOutput(string $output): void
256283
257284 $ this ->file ->writeContents ($ stream , $ output );
258285 }
286+
287+ private function createInvokableDescriptorParser (callable $ parser ): DescriptorParserInterface
288+ {
289+ return new class ($ parser ) implements DescriptorParserInterface {
290+ private Closure $ parser ;
291+
292+ public function __construct (callable $ parser )
293+ {
294+ $ this ->parser = Closure::fromCallable ($ parser );
295+ }
296+
297+ public function __invoke (
298+ string $ filePath ,
299+ MessageExtractorOptions $ options ,
300+ ParserErrorCollection $ errors
301+ ): DescriptorCollection {
302+ /** @var DescriptorCollection */
303+ return ($ this ->parser )($ filePath , $ options , $ errors );
304+ }
305+ };
306+ }
259307}
0 commit comments