Skip to content

Commit 912ef23

Browse files
committed
added UseParser spec and fixed FQN finding in comments
1 parent bbbf363 commit 912ef23

7 files changed

Lines changed: 189 additions & 27 deletions

File tree

specs/parser/CommentParser.spec.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
describe('CommentParser', function(){
1010
beforeEach(function(){
1111
$this->useParser = new UseParser;
12+
$this->uses = new Uses(
13+
$this->useParser->parseFQCN('Entity\Node')
14+
);
1215
$this->useParser->setUses(
13-
new Uses(
14-
$this->useParser->parseFQCN('Entity\Node')
15-
)
16+
$this->uses
1617
);
18+
$this->uses->add($this->useParser->parseFQCN(Comment::class));
1719
$this->parser = new CommentParser($this->useParser);
1820
$this->simpleDoc = <<<'DOCBLOCK'
1921
/**

specs/parser/UseParser.spec.php

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
3+
use Parser\UseParser;
4+
use Entity\Node\Uses;
5+
use Entity\FQCN;
6+
7+
describe('UseParser', function(){
8+
beforeEach(function(){
9+
$this->useParser = new UseParser;
10+
$this->uses = new Uses(
11+
$this->useParser->parseFQCN('Parser')
12+
);
13+
$this->useParser->setUses($this->uses);
14+
});
15+
describe('parseFQCN()', function(){
16+
it('returns instance of FQCN', function(){
17+
expect($this->useParser->parseFQCN('App'))
18+
->to->be->an->instanceof(FQCN::class);
19+
});
20+
it('splits complex name by \\', function(){
21+
$fqcn = $this->useParser->parseFQCN(Uses::class);
22+
expect($fqcn->getParts())->to->equal([
23+
'Entity',
24+
'Node',
25+
'Uses'
26+
]);
27+
});
28+
it('creates from single name', function(){
29+
$fqcn = $this->useParser->parseFQCN('App');
30+
expect($fqcn->getParts())->to->equal([
31+
'App'
32+
]);
33+
});
34+
it('works with absolute names', function(){
35+
$fqcn = $this->useParser->parseFQCN('\App');
36+
expect($fqcn->getParts())->to->equal([
37+
'App'
38+
]);
39+
});
40+
it('creates valid FQCN', function(){
41+
$fqcn = $this->useParser->parseFQCN(Uses::class);
42+
expect($fqcn->toString())->to->equal(Uses::class);
43+
});
44+
it('works with array-type', function(){
45+
$fqcn = $this->useParser->parseFQCN(Uses::class.'[]');
46+
expect($fqcn->getParts())->to->equal([
47+
'Entity',
48+
'Node',
49+
'Uses'
50+
]);
51+
expect($fqcn->isArray())->to->equal(true);
52+
});
53+
it('works with empty string', function(){
54+
$fqcn = $this->useParser->parseFQCN('');
55+
expect($fqcn)->to->be->an->instanceof(FQCN::class);
56+
});
57+
describe('Scalar types', function(){
58+
$scalars = ['string', 'int', 'float', 'array'];
59+
foreach($scalars AS $scalar){
60+
it('creates valid parts from ' . $scalar, function() use ($scalar){
61+
$fqcn = $this->useParser->parseFQCN($scalar);
62+
expect($fqcn->getParts())->to->equal([
63+
$scalar
64+
]);
65+
});
66+
it('creates non-array fqcn from ' . $scalar, function() use ($scalar){
67+
$fqcn = $this->useParser->parseFQCN($scalar);
68+
expect($fqcn->isArray())->to->equal(false);
69+
});
70+
it('creates scalar fqcn from ' . $scalar, function() use ($scalar){
71+
$fqcn = $this->useParser->parseFQCN($scalar);
72+
expect($fqcn->isScalar())->to->equal(true);
73+
});
74+
}
75+
});
76+
});
77+
describe('parseType()', function(){
78+
beforeEach(function(){
79+
$this->uses->add(
80+
$this->useParser->parseFQCN(Uses::class)
81+
);
82+
$this->uses->add(
83+
$this->useParser->parseFQCN(FQCN::class)
84+
);
85+
});
86+
it('returns FQCN from uses if exists', function(){
87+
$fqcn = $this->useParser->parseType('FQCN');
88+
expect($fqcn->toString())->to->equal(FQCN::class);
89+
});
90+
it('works with scalars', function(){
91+
$fqcn = $this->useParser->parseType('string');
92+
expect($fqcn->isScalar())->to->equal(true);
93+
});
94+
it('works with absolute names', function(){
95+
$fqcn = $this->useParser->parseType('\Entity\Project');
96+
expect($fqcn->getParts())->to->equal([
97+
'Entity',
98+
'Project'
99+
]);
100+
101+
});
102+
});
103+
});

src/Entity/FQCN.php

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace Entity;
44

55
class FQCN {
6-
private $parts;
6+
77
public function __get($key){
88
if($key === "className"){
99
return $this->getClassName();
@@ -12,13 +12,30 @@ public function __get($key){
1212
return $this->getNamespace();
1313
}
1414
}
15-
public function __construct($className, $namespace = ""){
15+
public function __construct($className, $namespace = "", $isArray=false){
1616
if($namespace){
17-
$this->parts = explode("\\", $namespace);
17+
if(!is_array($namespace)){
18+
$this->parts = explode("\\", $namespace);
19+
}
20+
else{
21+
$this->parts = $namespace;
22+
}
1823
}
1924
else {
2025
$this->parts = [];
2126
}
27+
$this->_isArray = $isArray;
28+
$this->_isScalar = false;
29+
if(count($this->parts) === 0){
30+
switch($className){
31+
case "int":
32+
case "string":
33+
case "float":
34+
case "array":
35+
$this->_isScalar = true;
36+
break;
37+
}
38+
}
2239
$this->parts[] = $className;
2340
}
2441
public function join(FQCN $join){
@@ -51,4 +68,14 @@ public function toString(){
5168
public function __toString(){
5269
return $this->toString();
5370
}
71+
public function isArray(){
72+
return $this->_isArray;
73+
}
74+
public function isScalar(){
75+
return $this->_isScalar;
76+
}
77+
78+
private $parts;
79+
private $_isArray;
80+
private $_isScalar;
5481
}

src/Entity/Node/MethodData.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public function getReturn(){
4242
if($this->return instanceof FQCN){
4343
return $this->return->toString();
4444
}
45-
return "none";
45+
return "void";
4646
}
4747
public function isPublic() {
4848
return (bool) ($this->type & ClassData::MODIFIER_PUBLIC);

src/Entity/Node/Uses.php

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,8 @@ public function add(FQCN $fqcn, $alias = null){
3737
$this->map[$alias] = $fqcn;
3838
}
3939

40-
public function toArray(){
41-
$map = [
42-
"uses" => [],
43-
"alias" => [],
44-
"file" => $this->fqcn->toString()
45-
];
46-
foreach($this->map AS $alias=>$fqcn){
47-
$map["uses"][$alias] = $fqcn->getNamespace();
48-
}
49-
return $map;
40+
public function all(){
41+
return $this->map;
5042
}
43+
5144
}

src/Parser/CommentParser.php

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use phpDocumentor\Reflection\DocBlock;
66
use phpDocumentor\Reflection\DocBlock\Tag;
7+
use phpDocumentor\Reflection\DocBlock\Context;
78
use Entity\Node\Comment;
89
use Entity\Node\MethodParam;
910
use Entity\Node\Variable;
@@ -34,13 +35,13 @@ public function parse($doc){
3435
}
3536

3637
/**
37-
* This is a method description
38+
* Parses doc comment and populates comment entity
3839
*
3940
* @param string $text
40-
* @return DocBlock
4141
*/
4242
protected function parseDoc(Comment $comment, $text){
43-
$block = new DocBlock($text);
43+
$context = $this->getContext();
44+
$block = new DocBlock($text, $context);
4445
foreach($block->getTags() AS $tag){
4546
switch($tag->getName()){
4647
case "param":
@@ -72,9 +73,18 @@ protected function createVar(Tag $tag){
7273
$param = new Variable($name);
7374
return $param;
7475
}
76+
/**
77+
* Creates FQN by type string
78+
*
79+
* @param string $type
80+
* @return \Entity\FQCN
81+
*/
7582
protected function getFQCN($type){
7683
return $this->useParser->parseType($type);
7784
}
85+
/**
86+
* @return string
87+
*/
7888
protected function trimComment($comment){
7989
$lines = explode("\n", $comment);
8090
foreach($lines AS $key => $line){
@@ -86,6 +96,17 @@ protected function trimComment($comment){
8696
}
8797
return implode("\n", $lines);
8898
}
99+
/**
100+
* @return Context
101+
*/
102+
protected function getContext(){
103+
$uses = $this->useParser->getUses();
104+
$namespace = $uses->getFQCN()->toString();
105+
$aliases = array_map(function($fqcn){
106+
return $fqcn->toString();
107+
}, $uses->all());
108+
return new Context($namespace, $aliases);
109+
}
89110

90111
private $useParser;
91112
}

src/Parser/UseParser.php

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,19 @@ public function parse(Use_ $node){
1717
}
1818
}
1919
public function parseType($type){
20+
$pureFQCN = $this->parseFQCN($type);
21+
if($pureFQCN->isScalar()){
22+
return $pureFQCN;
23+
}
24+
if(strpos($type, '\\') === 0){
25+
return $pureFQCN;
26+
}
2027
$fqcn = $this->uses->find($type);
2128
if(!empty($fqcn)){
2229
return $fqcn;
2330
}
2431
return $this->uses->getFQCN()->join(
25-
$this->parseFQCN($type)
32+
$pureFQCN
2633
);
2734
}
2835
public function getFQCN(Name $node = null){
@@ -39,14 +46,23 @@ public function getFQCN(Name $node = null){
3946
return $fqcn;
4047
}
4148
public function parseFQCN($fqcn){
42-
$regex = '/(.*)(?=\\\\(\w+)$)|(.*)/';
43-
$ret = preg_match($regex, $fqcn, $matches);
44-
if(!$ret) {
45-
throw new \Exception("Error while parsing FQCN");
49+
$fqcn = trim($fqcn, '\\');
50+
if(empty($fqcn)){
51+
return new FQCN('');
52+
}
53+
$parts = explode('\\', $fqcn);
54+
$name = array_pop($parts);
55+
$regex = '/(\w+)(\\[\\])?/';
56+
preg_match($regex, $name, $matches);
57+
if(count($matches) === 0){
58+
throw new \Exception("Could not parse FQCN for empty class name: " . $fqcn);
4659
}
60+
$name = $matches[1];
61+
$isArray = count($matches) === 3 && $matches[2] = '[]';
4762
return new FQCN(
48-
count($matches) == 3 ? $matches[2] : $matches[3],
49-
count($matches) == 3 ? $matches[1] : ""
63+
$name,
64+
$parts,
65+
$isArray
5066
);
5167
}
5268
public function getUses(){

0 commit comments

Comments
 (0)