Skip to content

Commit 554351e

Browse files
committed
feature #109 Allow to build RST content strings (javiereguiluz)
This PR was squashed before being merged into the main branch. Discussion ---------- Allow to build RST content strings The common use case is to build all the RST contents stored in some dir. However, sometimes you need to build just the contents of a single file or a string. For example we need this for symfony.com, where many blog posts are written as RST contents. This PR adds a new `buildString(string $contents): BuildResult` content to complement the current `build(BuildConfig $config): BuildResult` method. I had to add some config options and methods ... please tell me what you think about their naming. Thanks! Commits ------- fd965cc Allow to build RST content strings
2 parents 7e2e19f + fd965cc commit 554351e

File tree

4 files changed

+143
-3
lines changed

4 files changed

+143
-3
lines changed

src/BuildConfig.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ class BuildConfig
3030
private $subdirectoryToBuild;
3131
private $excludedPaths;
3232
private $fileFinder;
33+
// needed to know if we're building an entire directory of RST contents or just a single RST string
34+
private $contentIsString;
35+
// these are the *.fjson files generated by Sphinx and maintained for compatibility reasons
36+
private $generateJsonFiles;
3337

3438
public function __construct()
3539
{
@@ -38,6 +42,8 @@ public function __construct()
3842
$this->symfonyVersion = '4.4';
3943
$this->excludedPaths = [];
4044
$this->imagesPublicPrefix = '';
45+
$this->contentIsString = false;
46+
$this->generateJsonFiles = true;
4147
}
4248

4349
public function createFileFinder(): Finder
@@ -128,6 +134,16 @@ public function getImagesPublicPrefix(): string
128134
return $this->imagesPublicPrefix;
129135
}
130136

137+
public function generateJsonFiles(): bool
138+
{
139+
return $this->generateJsonFiles;
140+
}
141+
142+
public function isContentAString(): bool
143+
{
144+
return $this->contentIsString;
145+
}
146+
131147
public function setSymfonyVersion(string $version): self
132148
{
133149
$this->symfonyVersion = $version;
@@ -219,4 +235,23 @@ public function setExcludedPaths(array $excludedPaths)
219235

220236
$this->excludedPaths = $excludedPaths;
221237
}
238+
239+
/*
240+
* Call this method when you're building a string of RST contents (e.g. the
241+
* contents of a single file) instead of the common case of building an
242+
* entire directory of RST files.
243+
*/
244+
public function setContentIsString(): self
245+
{
246+
$this->contentIsString = true;
247+
248+
return $this;
249+
}
250+
251+
public function disableJsonFileGeneration(): self
252+
{
253+
$this->generateJsonFiles = false;
254+
255+
return $this;
256+
}
222257
}

src/BuildResult.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ class BuildResult
1717
{
1818
private $builder;
1919
private $errors;
20+
// only defined when using build() method
2021
private $jsonResults = [];
22+
// only defined when using buildString() method
23+
private $stringResult = null;
2124

2225
public function __construct(Builder $builder)
2326
{
@@ -45,6 +48,11 @@ public function getErrors(): array
4548
return $this->errors;
4649
}
4750

51+
public function getErrorTrace(): string
52+
{
53+
return implode("\n", $this->errors);
54+
}
55+
4856
public function getMetadata(): Metas
4957
{
5058
return $this->builder->getMetas();
@@ -72,4 +80,18 @@ public function setJsonResults(array $jsonResults): void
7280
{
7381
$this->jsonResults = $jsonResults;
7482
}
83+
84+
/**
85+
* Returns the HTML result of building some string contents
86+
* using the buildString() builder method
87+
*/
88+
public function getStringResult(): ?string
89+
{
90+
return $this->stringResult;
91+
}
92+
93+
public function setStringResult(string $result): void
94+
{
95+
$this->stringResult = $result;
96+
}
7597
}

src/DocBuilder.php

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

55
use Doctrine\RST\Builder;
66
use Symfony\Component\Console\Output\NullOutput;
7+
use Symfony\Component\DomCrawler\Crawler;
78
use Symfony\Component\Filesystem\Filesystem;
89
use SymfonyDocsBuilder\CI\MissingFilesChecker;
910
use SymfonyDocsBuilder\Generator\HtmlForPdfGenerator;
@@ -38,15 +39,49 @@ public function build(BuildConfig $config): BuildResult
3839
$filesystem->dumpFile($config->getOutputDir().'/build_errors.txt', implode("\n", $buildResult->getErrors()));
3940
}
4041

41-
$metas = $buildResult->getMetadata();
42-
if ($config->getSubdirectoryToBuild()) {
42+
if ($config->isContentAString()) {
43+
$htmlFilePath = $config->getOutputDir().'/index.html';
44+
if (is_file($htmlFilePath)) {
45+
// generated HTML contents are a full HTML page, so we need to
46+
// extract the contents of the <body> tag
47+
$crawler = new Crawler(file_get_contents($htmlFilePath));
48+
$buildResult->setStringResult(trim($crawler->filter('body')->html()));
49+
}
50+
} elseif ($config->getSubdirectoryToBuild()) {
51+
$metas = $buildResult->getMetadata();
4352
$htmlForPdfGenerator = new HtmlForPdfGenerator($metas, $config);
4453
$htmlForPdfGenerator->generateHtmlForPdf();
45-
} else {
54+
} elseif ($config->generateJsonFiles()) {
55+
$metas = $buildResult->getMetadata();
4656
$jsonGenerator = new JsonGenerator($metas, $config);
4757
$buildResult->setJsonResults($jsonGenerator->generateJson($builder->getIndexName()));
4858
}
4959

5060
return $buildResult;
5161
}
62+
63+
public function buildString(string $contents): BuildResult
64+
{
65+
$filesystem = new Filesystem();
66+
$tmpDir = sys_get_temp_dir().'/doc_builder_build_string_'.random_int(1, 100000000);
67+
if ($filesystem->exists($tmpDir)) {
68+
$filesystem->remove($tmpDir);
69+
}
70+
$filesystem->mkdir($tmpDir);
71+
72+
$filesystem->dumpFile($tmpDir.'/index.rst', $contents);
73+
74+
$buildConfig = (new BuildConfig())
75+
->setContentIsString()
76+
->setContentDir($tmpDir)
77+
->setOutputDir($tmpDir.'/output')
78+
->disableBuildCache()
79+
->disableJsonFileGeneration()
80+
;
81+
82+
$buildResult = $this->build($buildConfig);
83+
$filesystem->remove($tmpDir);
84+
85+
return $buildResult;
86+
}
5287
}

tests/IntegrationTest.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,54 @@ public function parserUnitBlockProvider()
261261
];
262262
}
263263

264+
public function testParseString()
265+
{
266+
$rstString = <<<RST
267+
Lorem ipsum dolor sit amet
268+
==========================
269+
270+
Consectetur adipisicing elit, sed do eiusmod
271+
tempor **incididunt ut** labore et dolore magna aliqua.
272+
273+
* Ut enim ad minim veniam
274+
* Quis nostrud exercitation
275+
* Ullamco laboris nisi ut
276+
277+
`Aliquip ex ea commodo <https://symfony.com>`_ consequat.
278+
Duis aute irure dolor in reprehenderit in voluptate `velit esse`_.
279+
280+
Cillum dolore eu fugiat nulla pariatur
281+
--------------------------------------
282+
283+
Excepteur sint occaecat cupidatat non proident, sunt in
284+
culpa qui *officia deserunt* mollit anim id est laborum.
285+
286+
.. _`velit esse`: https://github.com
287+
RST;
288+
289+
$htmlString = <<<HTML
290+
<div class="section">
291+
<h1 id="lorem-ipsum-dolor-sit-amet"><a class="headerlink" href="#lorem-ipsum-dolor-sit-amet" title="Permalink to this headline">Lorem ipsum dolor sit amet</a></h1>
292+
<p>Consectetur adipisicing elit, sed do eiusmod
293+
tempor <strong>incididunt ut</strong> labore et dolore magna aliqua.</p>
294+
<ul>
295+
<li>Ut enim ad minim veniam</li>
296+
<li>Quis nostrud exercitation</li>
297+
<li>Ullamco laboris nisi ut</li>
298+
</ul>
299+
<p><a href="https://symfony.com" class="reference external">Aliquip ex ea commodo</a> consequat.
300+
Duis aute irure dolor in reprehenderit in voluptate <a href="https://github.com" class="reference external" rel="external noopener noreferrer" target="_blank">velit esse</a>.</p>
301+
<div class="section">
302+
<h2 id="cillum-dolore-eu-fugiat-nulla-pariatur"><a class="headerlink" href="#cillum-dolore-eu-fugiat-nulla-pariatur" title="Permalink to this headline">Cillum dolore eu fugiat nulla pariatur</a></h2>
303+
<p>Excepteur sint occaecat cupidatat non proident, sunt in
304+
culpa qui <em>officia deserunt</em> mollit anim id est laborum.</p>
305+
</div>
306+
</div>
307+
HTML;
308+
309+
$this->assertSame($htmlString, (new DocBuilder())->buildString($rstString)->getStringResult());
310+
}
311+
264312
private function createIndenter(): Indenter
265313
{
266314
$indenter = new Indenter();

0 commit comments

Comments
 (0)