Test Failed
Push — master ( 08713d...9fa0b4 )
by Kirill
03:13
created

Factory::build()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 2
dl 0
loc 14
ccs 0
cts 10
cp 0
crap 6
rs 9.7998
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
        'InterfaceDefinition'  => Definition\InterfaceBuilder::class,
37
        'ObjectDefinition'     => Definition\ObjectBuilder::class,
38
        'ScalarDefinition'     => Definition\ScalarBuilder::class,
39
        'SchemaDefinition'     => Definition\SchemaBuilder::class,
40
        'UnionDefinition'      => Definition\UnionBuilder::class,
41
42
        'FieldDefinition'      => Dependent\FieldBuilder::class,
43
        'ArgumentDefinition'   => Dependent\ArgumentBuilder::class,
44
        'EnumValue'            => Dependent\EnumValueBuilder::class,
45
        'InputFieldDefinition' => Dependent\InputFieldBuilder::class,
46
47
        'Directive' => Invocation\DirectiveBuilder::class,
48
    ];
49
50
    /**
51
     * @var Pipeline
52
     */
53
    private $pipeline;
54
55
    /**
56
     * @var Document
57
     */
58
    private $document;
59
60
    /**
61
     * @var RuleInterface
62
     */
63
    private $ast;
64
65
    /**
66
     * Processor constructor.
67
     * @param Document $document
68
     * @param RuleInterface $ast
69
     */
70
    public function __construct(Document $document, RuleInterface $ast)
71
    {
72
        $this->ast      = $ast;
73
        $this->document = $document;
74
        $this->pipeline = new Pipeline();
75
    }
76
77
    /**
78
     * @return Document
79
     * @throws \Railt\Io\Exception\ExternalFileException
80
     */
81
    public function process(): Document
82
    {
83
        $dictionary = $this->document->getDictionary();
84
85
        foreach ($this->ast as $child) {
86
            $definition = $this->build($child, $this->document);
87
88
            if ($definition instanceof TypeDefinition) {
89
                if ($dictionary->has($definition->getName())) {
90
                    $error = \sprintf('Can not redeclare already registered type %s', $definition);
91
                    throw (new TypeConflictException($error))->in($definition);
92
                }
93
94
                $this->document->withDefinition($definition);
95
            }
96
97
            if ($definition instanceof DirectiveInvocation) {
98
                $this->document->withDirective($definition);
99
            }
100
        }
101
102
        foreach ($this->pipeline as $next) {
103
            $next();
104
        }
105
106
        return $this->document;
107
    }
108
109
    /**
110
     * @param RuleInterface $rule
111
     * @param DefinitionInterface $parent
112
     * @return DefinitionInterface
113
     * @throws \Railt\Io\Exception\ExternalFileException
114
     */
115
    public function build(RuleInterface $rule, DefinitionInterface $parent): DefinitionInterface
116
    {
117
        $mapping = self::NODE_MAPPINGS[$rule->getName()] ?? null;
118
119
        if ($mapping === null) {
120
            throw (new CompilerException(\sprintf('No mappings found for %s AST',
121
                $rule->getName())))->throwsIn($this->document->getFile(), $rule->getOffset());
122
        }
123
124
        /** @var BuilderInterface $instance */
125
        $instance = new $mapping($this->pipeline, $this);
126
127
        return $instance->build($rule, $parent);
128
    }
129
}
130