Completed
Push — master ( 8afd90...4bf010 )
by Kirill
03:48
created

Factory::process()   B

Complexity

Conditions 6
Paths 11

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6.105

Importance

Changes 0
Metric Value
cc 6
nc 11
nop 0
dl 0
loc 27
ccs 12
cts 14
cp 0.8571
crap 6.105
rs 8.8657
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of Railt package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
declare(strict_types=1);
9
10
namespace Railt\SDL\Compiler;
11
12
use Railt\Parser\Ast\RuleInterface;
13
use Railt\Reflection\Contracts\Definition as DefinitionInterface;
14
use Railt\Reflection\Contracts\Definition\TypeDefinition;
15
use Railt\Reflection\Contracts\Invocation\DirectiveInvocation;
16
use Railt\Reflection\Document;
17
use Railt\SDL\Compiler\Builder\BuilderInterface;
18
use Railt\SDL\Compiler\Builder\Definition;
19
use Railt\SDL\Compiler\Builder\Dependent;
20
use Railt\SDL\Compiler\Builder\Invocation;
21
use Railt\SDL\Exception\CompilerException;
22
use Railt\SDL\Exception\TypeConflictException;
23
24
/**
25
 * Class Factory
26
 */
27
class Factory
28
{
29
    /**
30
     * @var BuilderInterface[]
31
     */
32
    private const NODE_MAPPINGS = [
33
        'DirectiveDefinition'  => Definition\DirectiveBuilder::class,
34
        'EnumDefinition'       => Definition\EnumBuilder::class,
35
        'InputDefinition'      => Definition\InputBuilder::class,
36
        'InputUnionDefinition' => Definition\InputUnionBuilder::class,
37
        'InterfaceDefinition'  => Definition\InterfaceBuilder::class,
38
        'ObjectDefinition'     => Definition\ObjectBuilder::class,
39
        'ScalarDefinition'     => Definition\ScalarBuilder::class,
40
        'SchemaDefinition'     => Definition\SchemaBuilder::class,
41
        'UnionDefinition'      => Definition\UnionBuilder::class,
42
43
        'FieldDefinition'      => Dependent\FieldBuilder::class,
44
        'ArgumentDefinition'   => Dependent\ArgumentBuilder::class,
45
        'EnumValue'            => Dependent\EnumValueBuilder::class,
46
        'InputFieldDefinition' => Dependent\InputFieldBuilder::class,
47
48
        'Directive' => Invocation\DirectiveBuilder::class,
49
    ];
50
51
    /**
52
     * @var Pipeline
53
     */
54
    private $pipeline;
55
56
    /**
57
     * @var Document
58
     */
59
    private $document;
60
61
    /**
62
     * @var RuleInterface
63
     */
64
    private $ast;
65
66
    /**
67
     * Processor constructor.
68
     * @param Document $document
69
     * @param RuleInterface $ast
70
     */
71 1
    public function __construct(Document $document, RuleInterface $ast)
72
    {
73 1
        $this->ast      = $ast;
74 1
        $this->document = $document;
75 1
        $this->pipeline = new Pipeline();
76 1
    }
77
78
    /**
79
     * @return Document
80
     * @throws \Railt\Io\Exception\ExternalFileException
81
     */
82 1
    public function process(): Document
83
    {
84 1
        $dictionary = $this->document->getDictionary();
85
86 1
        foreach ($this->ast as $child) {
87 1
            $definition = $this->build($child, $this->document);
88
89 1
            if ($definition instanceof TypeDefinition) {
90 1
                if ($dictionary->has($definition->getName())) {
91
                    $error = \sprintf('Can not redeclare already registered type %s', $definition);
92
                    throw (new TypeConflictException($error))->in($definition);
93
                }
94
95 1
                $this->document->withDefinition($definition);
96
            }
97
98 1
            if ($definition instanceof DirectiveInvocation) {
99 1
                $this->document->withDirective($definition);
100
            }
101
        }
102
103 1
        foreach ($this->pipeline as $next) {
104 1
            $next();
105
        }
106
107 1
        return $this->document;
108
    }
109
110
    /**
111
     * @param RuleInterface $rule
112
     * @param DefinitionInterface $parent
113
     * @return DefinitionInterface
114
     * @throws \Railt\Io\Exception\ExternalFileException
115
     */
116 1
    public function build(RuleInterface $rule, DefinitionInterface $parent): DefinitionInterface
117
    {
118 1
        $mapping = self::NODE_MAPPINGS[$rule->getName()] ?? null;
119
120 1
        if ($mapping === null) {
121
            throw (new CompilerException(\sprintf('No mappings found for %s AST',
122
                $rule->getName())))->throwsIn($this->document->getFile(), $rule->getOffset());
123
        }
124
125
        /** @var BuilderInterface $instance */
126 1
        $instance = new $mapping($this->pipeline, $this);
127
128 1
        return $instance->build($rule, $parent);
129
    }
130
}
131