Skip to content

Commit ffe0a18

Browse files
Merge branch 'main' into support-short-code
2 parents c190c4b + 96aaba7 commit ffe0a18

File tree

20 files changed

+346
-20
lines changed

20 files changed

+346
-20
lines changed

packages/guides-cli/src/Command/Run.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
namespace phpDocumentor\Guides\Cli\Command;
1515

1616
use Flyfinder\Finder;
17+
use Flyfinder\Path;
18+
use Flyfinder\Specification\InPath;
19+
use Flyfinder\Specification\NotSpecification;
20+
use Flyfinder\Specification\OrSpecification;
21+
use Flyfinder\Specification\SpecificationInterface;
1722
use League\Flysystem\Adapter\Local;
1823
use League\Flysystem\Filesystem;
1924
use League\Tactician\CommandBus;
@@ -51,7 +56,10 @@
5156
use Symfony\Component\Console\Output\OutputInterface;
5257
use Symfony\Component\EventDispatcher\EventDispatcher;
5358

59+
use function array_map;
5460
use function array_pop;
61+
use function array_reduce;
62+
use function array_shift;
5563
use function assert;
5664
use function count;
5765
use function implode;
@@ -93,6 +101,13 @@ public function __construct(
93101
'If set, only the specified file is parsed, relative to the directory specified in "input"',
94102
);
95103

104+
$this->addOption(
105+
'exclude-path',
106+
null,
107+
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
108+
'Paths to exclude, doc files in these directories will not be parsed',
109+
);
110+
96111
$this->addOption(
97112
'input-format',
98113
null,
@@ -314,12 +329,28 @@ protected function execute(InputInterface $input, OutputInterface $output): int
314329
}
315330

316331
if ($settings->getInputFile() === '') {
332+
$exclude = null;
333+
if ($input->getOption('exclude-path')) {
334+
/** @var string[] $excludedPaths */
335+
$excludedPaths = (array) $input->getOption('exclude-path');
336+
$excludedSpecifications = array_map(static fn (string $path) => new NotSpecification(new InPath(new Path($path))), $excludedPaths);
337+
$excludedSpecification = array_shift($excludedSpecifications);
338+
assert($excludedSpecification !== null);
339+
340+
$exclude = array_reduce(
341+
$excludedSpecifications,
342+
static fn (SpecificationInterface $carry, SpecificationInterface $spec) => new OrSpecification($carry, $spec),
343+
$excludedSpecification,
344+
);
345+
}
346+
317347
$documents = $this->commandBus->handle(
318348
new ParseDirectoryCommand(
319349
$sourceFileSystem,
320350
'',
321351
$settings->getInputFormat(),
322352
$projectNode,
353+
$exclude,
323354
),
324355
);
325356
} else {

packages/guides-restructured-text/src/RestructuredText/Directives/ConfvalDirective.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,12 @@ protected function processSub(
6161
CollectionNode $collectionNode,
6262
Directive $directive,
6363
): Node|null {
64-
$id = $this->anchorReducer->reduceAnchor($directive->getData());
64+
$id = $directive->getData();
65+
if ($directive->hasOption('name')) {
66+
$id = (string) $directive->getOption('name')->getValue();
67+
}
68+
69+
$id = $this->anchorReducer->reduceAnchor($id);
6570
$type = null;
6671
$required = false;
6772
$default = null;
@@ -79,7 +84,7 @@ protected function processSub(
7984
}
8085

8186
foreach ($directive->getOptions() as $option) {
82-
if (in_array($option->getName(), ['type', 'required', 'default', 'noindex'], true)) {
87+
if (in_array($option->getName(), ['type', 'required', 'default', 'noindex', 'name'], true)) {
8388
continue;
8489
}
8590

packages/guides/src/Compiler/NodeTransformers/CollectLinkTargetsTransformer.php

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@
2323
use phpDocumentor\Guides\Nodes\Node;
2424
use phpDocumentor\Guides\Nodes\SectionNode;
2525
use phpDocumentor\Guides\ReferenceResolvers\AnchorNormalizer;
26+
use Psr\Log\LoggerInterface;
2627
use SplStack;
2728
use Webmozart\Assert\Assert;
2829

30+
use function sprintf;
31+
2932
/** @implements NodeTransformer<DocumentNode|AnchorNode|SectionNode> */
3033
final class CollectLinkTargetsTransformer implements NodeTransformer
3134
{
@@ -34,6 +37,7 @@ final class CollectLinkTargetsTransformer implements NodeTransformer
3437

3538
public function __construct(
3639
private readonly AnchorNormalizer $anchorReducer,
40+
private LoggerInterface|null $logger = null,
3741
) {
3842
/*
3943
* TODO: remove stack here, as we should not have sub documents in this way, sub documents are
@@ -47,7 +51,11 @@ public function enterNode(Node $node, CompilerContext $compilerContext): Node
4751
{
4852
if ($node instanceof DocumentNode) {
4953
$this->documentStack->push($node);
50-
} elseif ($node instanceof AnchorNode) {
54+
55+
return $node;
56+
}
57+
58+
if ($node instanceof AnchorNode) {
5159
$currentDocument = $compilerContext->getDocumentNode();
5260
$parentSection = $compilerContext->getShadowTree()->getParent()?->getNode();
5361
$title = null;
@@ -64,12 +72,33 @@ public function enterNode(Node $node, CompilerContext $compilerContext): Node
6472
$title,
6573
),
6674
);
67-
} elseif ($node instanceof LinkTargetNode) {
75+
76+
return $node;
77+
}
78+
79+
if ($node instanceof SectionNode) {
6880
$currentDocument = $this->documentStack->top();
6981
Assert::notNull($currentDocument);
70-
$anchor = $node->getId();
82+
$anchorName = $node->getId();
7183
$compilerContext->getProjectNode()->addLinkTarget(
72-
$anchor,
84+
$anchorName,
85+
new InternalTarget(
86+
$currentDocument->getFilePath(),
87+
$anchorName,
88+
$node->getLinkText(),
89+
$node->getLinkType(),
90+
),
91+
);
92+
93+
return $node;
94+
}
95+
96+
if ($node instanceof LinkTargetNode) {
97+
$currentDocument = $this->documentStack->top();
98+
Assert::notNull($currentDocument);
99+
$anchor = $this->anchorReducer->reduceAnchor($node->getId());
100+
$this->addLinkTargetToProject(
101+
$compilerContext,
73102
new InternalTarget(
74103
$currentDocument->getFilePath(),
75104
$anchor,
@@ -79,11 +108,12 @@ public function enterNode(Node $node, CompilerContext $compilerContext): Node
79108
);
80109
if ($node instanceof MultipleLinkTargetsNode) {
81110
foreach ($node->getAdditionalIds() as $id) {
82-
$compilerContext->getProjectNode()->addLinkTarget(
83-
$id,
111+
$anchor = $this->anchorReducer->reduceAnchor($id);
112+
$this->addLinkTargetToProject(
113+
$compilerContext,
84114
new InternalTarget(
85115
$currentDocument->getFilePath(),
86-
$id,
116+
$anchor,
87117
$node->getLinkText(),
88118
$node->getLinkType(),
89119
),
@@ -114,4 +144,28 @@ public function getPriority(): int
114144
// After MetasPass
115145
return 5000;
116146
}
147+
148+
private function addLinkTargetToProject(CompilerContext $compilerContext, InternalTarget $internalTarget): void
149+
{
150+
if ($compilerContext->getProjectNode()->hasInternalTarget($internalTarget->getAnchor(), $internalTarget->getLinkType())) {
151+
$otherLink = $compilerContext->getProjectNode()->getInternalTarget($internalTarget->getAnchor(), $internalTarget->getLinkType());
152+
$this->logger?->warning(
153+
sprintf(
154+
'Duplicate anchor "%s" for link type "%s" in document "%s". The anchor is already used at "%s"',
155+
$internalTarget->getAnchor(),
156+
$internalTarget->getLinkType(),
157+
$compilerContext->getDocumentNode()->getFilePath(),
158+
$otherLink?->getDocumentPath(),
159+
),
160+
$compilerContext->getLoggerInformation(),
161+
);
162+
163+
return;
164+
}
165+
166+
$compilerContext->getProjectNode()->addLinkTarget(
167+
$internalTarget->getAnchor(),
168+
$internalTarget,
169+
);
170+
}
117171
}

packages/guides/src/FileCollector.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
use Flyfinder\Specification\AndSpecification;
1818
use Flyfinder\Specification\HasExtension;
1919
use Flyfinder\Specification\InPath;
20+
use Flyfinder\Specification\NotSpecification;
21+
use Flyfinder\Specification\SpecificationInterface;
2022
use InvalidArgumentException;
2123
use League\Flysystem\FilesystemInterface;
2224

@@ -36,14 +38,19 @@ final class FileCollector
3638
* This takes into account the presence of cached & fresh MetaEntry
3739
* objects, and avoids adding files to the parse queue that have
3840
* not changed and whose direct dependencies have not changed.
41+
*
42+
* @param SpecificationInterface|null $excludedSpecification specification that is used to exclude specific files/directories
3943
*/
40-
public function collect(FilesystemInterface $filesystem, string $directory, string $extension): Files
44+
public function collect(FilesystemInterface $filesystem, string $directory, string $extension, SpecificationInterface|null $excludedSpecification = null): Files
4145
{
4246
$directory = trim($directory, '/');
47+
$specification = new AndSpecification(new InPath(new Path($directory)), new HasExtension([$extension]));
48+
if ($excludedSpecification) {
49+
$specification = new AndSpecification($specification, new NotSpecification($excludedSpecification));
50+
}
51+
4352
/** @var array<array<string>> $files */
44-
$files = $filesystem->find(
45-
new AndSpecification(new InPath(new Path($directory)), new HasExtension([$extension])),
46-
);
53+
$files = $filesystem->find($specification);
4754

4855
// completely populate the splFileInfos property
4956
$this->fileInfos = [];

packages/guides/src/Handlers/ParseDirectoryCommand.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace phpDocumentor\Guides\Handlers;
1515

16+
use Flyfinder\Specification\SpecificationInterface;
1617
use League\Flysystem\FilesystemInterface;
1718
use phpDocumentor\Guides\Nodes\ProjectNode;
1819

@@ -23,6 +24,7 @@ public function __construct(
2324
private readonly string $directory,
2425
private readonly string $inputFormat,
2526
private readonly ProjectNode $projectNode,
27+
private readonly SpecificationInterface|null $excludedSpecification = null,
2628
) {
2729
}
2830

@@ -45,4 +47,9 @@ public function getProjectNode(): ProjectNode
4547
{
4648
return $this->projectNode;
4749
}
50+
51+
public function getExcludedSpecification(): SpecificationInterface|null
52+
{
53+
return $this->excludedSpecification;
54+
}
4855
}

packages/guides/src/Handlers/ParseDirectoryHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public function handle(ParseDirectoryCommand $command): array
5656
$extension,
5757
);
5858

59-
$files = $this->fileCollector->collect($origin, $currentDirectory, $extension);
59+
$files = $this->fileCollector->collect($origin, $currentDirectory, $extension, $command->getExcludedSpecification());
6060

6161
$postCollectFilesForParsingEvent = $this->eventDispatcher->dispatch(
6262
new PostCollectFilesForParsingEvent($command, $files),

packages/guides/src/Nodes/ProjectNode.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ public function addLinkTarget(string $anchorName, InternalTarget $target): void
152152
$this->internalLinkTargets[$target->getLinkType()][$anchorName] = $target;
153153
}
154154

155+
public function hasInternalTarget(string $anchorName, string $linkType = SectionNode::STD_LABEL): bool
156+
{
157+
return isset($this->internalLinkTargets[$linkType][$anchorName]);
158+
}
159+
155160
public function getInternalTarget(string $anchorName, string $linkType = SectionNode::STD_LABEL): InternalTarget|null
156161
{
157162
return $this->internalLinkTargets[$linkType][$anchorName] ?? null;

tests/Functional/tests/section-nesting/section-nesting.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ <h1>
3737
<h1>
3838
Level 1 Test 4
3939
</h1>
40-
<div class="section" id="level-2-test-3">
40+
<div class="section" id="level-2-test-3b">
4141
<h2>
42-
Level 2 Test 3
42+
Level 2 Test 3b
4343
</h2>
4444
<div class="section" id="level-3-test-1">
4545
<h3>

tests/Functional/tests/section-nesting/section-nesting.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ Level 1 Test 3
2222
Level 1 Test 4
2323
==============
2424

25-
Level 2 Test 3
26-
--------------
25+
Level 2 Test 3b
26+
---------------
2727

2828
Level 3 Test 1
2929
**************

tests/Integration/tests/confval/expected/index.html renamed to tests/Integration/tests/confval/confval-name/expected/another.html

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>Confval directive</title>
5+
6+
</head>
7+
<body>
18
<!-- content start -->
29
<div class="section" id="confval-directive">
310
<h1>Confval directive</h1>
411

512
<dl class="confval">
6-
<dt id="demo">
13+
<dt id="another-demo">
714
<code class="sig-name descname"><span class="pre">demo</span></code></dt>
815
<dd>
916
<div class="line-block">
@@ -21,3 +28,5 @@ <h1>Confval directive</h1>
2128
</div>
2229

2330
<!-- content end -->
31+
</body>
32+
</html>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>Confval directive</title>
5+
6+
</head>
7+
<body>
8+
<!-- content start -->
9+
<div class="section" id="confval-directive">
10+
<h1>Confval directive</h1>
11+
12+
<dl class="confval">
13+
<dt id="demo">
14+
<code class="sig-name descname"><span class="pre">demo</span></code></dt>
15+
<dd>
16+
<div class="line-block">
17+
<div class="line"><strong>Type:</strong> <code>&quot;Hello World&quot;</code></div>
18+
<div class="line"><strong>Required:</strong> true</div>
19+
<div class="line"><strong>Custom Info:</strong> <strong>custom</strong></div>
20+
21+
</div>
22+
<div class="confval-description">
23+
<p>This is the confval <code>demo</code> content!</p><p>Another paragraph.</p>
24+
</div>
25+
</dd>
26+
</dl>
27+
<p>See option <a href="/index.html#demo">demo</a>.</p>
28+
<div class="toc">
29+
<ul class="menu-level">
30+
<li class="toc-item"><a href="/another.html#confval-directive">Confval directive</a></li>
31+
32+
</ul>
33+
</div>
34+
35+
</div>
36+
37+
<!-- content end -->
38+
</body>
39+
</html>

0 commit comments

Comments
 (0)