Skip to content

Commit 207a2ad

Browse files
committed
Add basic support for protected detection, including inheritance
1 parent 9ad46b6 commit 207a2ad

File tree

4 files changed

+117
-10
lines changed

4 files changed

+117
-10
lines changed

bin/annotate

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ require_once __DIR__ . '/../vendor/autoload.php';
104104
$io->newLine();
105105
$io->writeln('Writing annotations...');
106106
$progressBar = $io->createProgressBar(count($fileList));
107+
$xmlFileParser->prepareProtectionStatus();
107108
foreach($fileList as $filePath) {
108109
if (str_ends_with($filePath, 'xml')) {
109110
$xmlFileParser->writeAnnotationsToFile($filePath, $outputDir, $inputDir, $linkPrefix, $mixAnnotationsIntoSource);

src/Frame.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,20 @@
44

55
namespace App;
66

7-
use RuntimeException;
87
use SimpleXMLElement;
98

109
class Frame
1110
{
1211
private readonly ?self $originalParent;
1312
/** @var array<string, KeyValueDTO> */
1413
private array $keyValues;
14+
private ProtectedEnum $protected = ProtectedEnum::UNPROTECTED;
1515

1616
public function __construct(
1717
private readonly string $name,
1818
private readonly string $type,
1919
private readonly SimpleXMLElement $xmlElement,
20+
private readonly bool $explicitlyProtected = false,
2021
private ?self $parent = null,
2122
private array $children = [],
2223
) {
@@ -71,6 +72,21 @@ public function getClassName(): ?string
7172
return $this->sanitizeClassName($prefix === '' ? $name : ($prefix . '_' . $name));
7273
}
7374

75+
public function isExplicitlyProtected(): bool
76+
{
77+
return $this->explicitlyProtected || $this->getProtected() === ProtectedEnum::PROTECTED;
78+
}
79+
80+
public function setProtected(ProtectedEnum $protected): void
81+
{
82+
$this->protected = $protected;
83+
}
84+
85+
public function getProtected(): ProtectedEnum
86+
{
87+
return $this->protected;
88+
}
89+
7490
public function getParent(): ?self
7591
{
7692
return $this->parent;

src/ProtectedEnum.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App;
6+
7+
enum ProtectedEnum
8+
{
9+
case IMPLICIT;
10+
case PROTECTED;
11+
case UNPROTECTED;
12+
}

src/XmlFileParser.php

Lines changed: 87 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -103,19 +103,20 @@ private function parseNode(SimpleXMLElement $node, Registry $fileRegistry, strin
103103
}
104104
$isIntrinsic = (string) ($node->attributes()['intrinsic'] ?? '') === 'true';
105105
$isTemplate = (string) ($node->attributes()['virtual'] ?? '') === 'true';
106+
$isProtected = (string) ($node->attributes()['protected'] ?? '') === 'true';
106107

107108
$type = $node->getName();
108109
if (isset(self::TYPE_ALIASSES[$type])) {
109110
$type = self::TYPE_ALIASSES[$type];
110111
}
111112
if ($isIntrinsic) {
112-
$frame = new Intrinsic($name, $type, $node, $parent);
113+
$frame = new Intrinsic($name, $type, $node, $isProtected, $parent);
113114
$this->intrinsicRegistry->register($frame->getClassName(), $frame);
114115
} elseif ($isTemplate) {
115-
$frame = new Template($name, $type, $node, $parent);
116+
$frame = new Template($name, $type, $node, $isProtected, $parent);
116117
$this->templateRegistry->register($frame->getClassName(), $frame);
117118
} else {
118-
$frame = new Frame($name, $type, $node, $parent);
119+
$frame = new Frame($name, $type, $node, $isProtected, $parent);
119120
$this->frameRegistry->register($frame->getClassName(), $frame);
120121
}
121122
if (!empty($name)) {
@@ -163,6 +164,51 @@ private function parseNode(SimpleXMLElement $node, Registry $fileRegistry, strin
163164
}
164165
}
165166

167+
public function prepareProtectionStatus(): void
168+
{
169+
foreach ($this->templateRegistry->all() as $template) {
170+
$this->checkProtectionState($template);
171+
}
172+
foreach ($this->frameRegistry->all() as $frame) {
173+
$this->checkProtectionState($frame);
174+
}
175+
}
176+
177+
private function checkProtectionState(Frame $frame): void
178+
{
179+
if ($frame->isExplicitlyProtected()) {
180+
$frame->setProtected(ProtectedEnum::PROTECTED);
181+
} else {
182+
foreach ($this->iterateInherits($frame) as $template) {
183+
if ($template->isExplicitlyProtected()) {
184+
$frame->setProtected(ProtectedEnum::PROTECTED);
185+
186+
break;
187+
}
188+
if ($template->getProtected() === ProtectedEnum::IMPLICIT) {
189+
$frame->setProtected(ProtectedEnum::IMPLICIT);
190+
}
191+
}
192+
if ($frame->getProtected() === ProtectedEnum::UNPROTECTED) {
193+
foreach ($frame->getChildren() as $child) {
194+
$this->checkProtectionState($child);
195+
if ($child->getProtected() !== ProtectedEnum::UNPROTECTED) {
196+
$frame->setProtected(ProtectedEnum::IMPLICIT);
197+
}
198+
}
199+
}
200+
}
201+
if ($frame->getProtected() !== ProtectedEnum::UNPROTECTED) {
202+
$parent = $frame->getParent();
203+
while ($parent) {
204+
if ($parent->getProtected() === ProtectedEnum::UNPROTECTED) {
205+
$parent->setProtected(ProtectedEnum::IMPLICIT);
206+
}
207+
$parent = $parent->getParent();
208+
}
209+
}
210+
}
211+
166212
public function writeAnnotationsToFile(string $filename, string $outDir, string $prefixToStrip, ?string $linkPrefix, bool $includeScripts): void
167213
{
168214
$fileRegistry = $this->perFileRegistry[$filename] ?? null;
@@ -295,6 +341,13 @@ private function writeFrame(Frame $frame, ?string $linkPrefix, ?string $typeOver
295341
if ($linkPrefix) {
296342
$data .= "--- [Source]($linkPrefix#L" . $frame->getLineNumber() . ")\n";
297343
}
344+
if ($frame->getProtected() !== ProtectedEnum::UNPROTECTED) {
345+
$text = match($frame->getProtected()) {
346+
ProtectedEnum::PROTECTED => 'Explicitly protected',
347+
ProtectedEnum::IMPLICIT => 'Implicitly protected',
348+
};
349+
$data .= "--- $text\n";
350+
}
298351
if ($frame->getParent()) {
299352
$data .= '--- child of ' . ($frame->getParent()->getName() ?: $frame->getParent()->getClassName());
300353
if ($frame->getOriginalParent() && $frame->getOriginalParent() !== $frame->getParent()) {
@@ -380,6 +433,7 @@ private function writeClassAndFieldHints(Frame $frame): string
380433
}
381434
$allParentKeys = [];
382435
$allParentArrays = [];
436+
$protected = [];
383437
foreach ($frame->getChildren() as $child) {
384438
$typehint = $this->childHasInterestingData($child) ? $child->getClassName() : null;
385439
if (empty($typehint) && 1 === count($child->getInherits())) {
@@ -388,24 +442,40 @@ private function writeClassAndFieldHints(Frame $frame): string
388442
$typehint = $typehint ?: $child->getType();
389443
$parentKeys = [];
390444
if ($child->getParentKey()) {
445+
$key = $child->getParentKey();
391446
$parentKeys[$child->getParentKey()] = $typehint ?: 'table';
447+
if ($child->getProtected() !== ProtectedEnum::UNPROTECTED) {
448+
$protected[$key] = $child->getProtected();
449+
}
392450
}
393451
foreach ($this->iterateInherits($child) as $inherit) {
394-
if ($inherit->getParentKey()) {
452+
$key = $inherit->getParentKey();
453+
if ($key) {
395454
$inheritTypehint = $typehint ?: $inherit->getClassName();
396-
$parentKeys[$inherit->getParentKey()] = $inheritTypehint;
455+
$parentKeys[$key] = $inheritTypehint;
456+
if ($inherit->getProtected() !== ProtectedEnum::UNPROTECTED) {
457+
$protected[$key] = $inherit->getProtected();
458+
}
397459
}
398460
}
399461
$allParentKeys[] = $parentKeys;
400462

401463
$parentArrays = [];
402464
if ($child->getParentArray()) {
403-
$parentArrays[$child->getParentArray()] = $typehint ?: 'table';
465+
$key = $child->getParentArray();
466+
$parentArrays[$key] = $typehint ?: 'table';
467+
if ($child->getProtected() !== ProtectedEnum::UNPROTECTED) {
468+
$protected[$key] = $child->getProtected();
469+
}
404470
}
405471
foreach ($this->iterateInherits($child) as $inherit) {
406-
if ($inherit->getParentArray()) {
472+
$key = $inherit->getParentArray();
473+
if ($key) {
407474
$inheritTypehint = $typehint ?: $inherit->getClassName();
408-
$parentArrays[$inherit->getParentArray()] ??= $inheritTypehint;
475+
$parentArrays[$key] ??= $inheritTypehint;
476+
if ($inherit->getProtected() !== ProtectedEnum::UNPROTECTED) {
477+
$protected[$key] = $inherit->getProtected();
478+
}
409479
}
410480
}
411481
$allParentArrays[] = $parentArrays;
@@ -418,7 +488,15 @@ private function writeClassAndFieldHints(Frame $frame): string
418488
}
419489
}
420490
foreach ($mergedParentKeys as $key => $types) {
421-
$data .= '--- @field ' . $key . ' ' . implode(' | ', array_unique($types)) . "\n";
491+
$data .= sprintf(
492+
"--- @field %s %s%s\n",
493+
$key,
494+
implode(' | ', array_unique($types)),
495+
isset($protected[$key]) ? (' # ' . match($protected[$key]) {
496+
ProtectedEnum::PROTECTED => 'Explicitly protected',
497+
ProtectedEnum::IMPLICIT => 'Implicitly protected',
498+
}) : '',
499+
);
422500
}
423501

424502
$mergedParentArrays = [];

0 commit comments

Comments
 (0)