3 declare(strict_types
=1);
6 * This file is part of the TYPO3 CMS project.
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
15 * The TYPO3 project - inspiring people to share!
18 require __DIR__
. '/../../vendor/autoload.php';
20 if (PHP_SAPI
!== 'cli') {
21 die('Script must be called from command line.' . chr(10));
24 use Symfony\Component\Finder\Finder
;
27 * Check ReST files for integrity. If errors are found, they will be
28 * output on stdout and the program will exit with exit code 1.
30 * Optional arguments: -d <directory>
32 * By default, the standard path is used. You can override this for
35 class validateRstFiles
50 protected $baseDir = 'typo3/sysext/core/Documentation/Changelog';
52 public function __construct(string $dir = '')
55 $this->baseDir
= $dir;
59 public function validate()
61 printf('Searching for rst snippets in ' . $this->baseDir
. chr(10));
64 $finder = $this->findFiles();
65 foreach ($finder as $file) {
66 $filename = (string)$file;
67 $this->clearMessages();
68 $fileContent = $file->getContents();
69 $this->validateContent($fileContent);
70 $a = explode(chr(10), trim($fileContent));
71 $lastLine = array_pop($a);
72 $this->validateLastLine($lastLine);
73 $this->validateLastLineByFilename($filename, $lastLine);
76 $shortPath = substr($filename, strlen($this->baseDir
));
77 $shortPath = ltrim($shortPath, '/\\');
80 '%-10s | %-12s | %-17s | %s ' . chr(10),
81 $this->messages
['include']['title'],
82 $this->messages
['reference']['title'],
83 $this->messages
['index']['title'],
86 if ($this->messages
['include']['message']) {
87 printf($this->messages
['include']['message'] . chr(10));
89 if ($this->messages
['reference']['message']) {
90 printf($this->messages
['reference']['message'] . chr(10));
92 if ($this->messages
['index']['message']) {
93 printf($this->messages
['index']['message'] . chr(10));
99 fwrite(STDERR
, 'Found ' . $count . ' rst files with errors, check full log for details.' . chr(10));
105 public function findFiles(): Finder
107 $finder = new Finder();
112 ->notName('Index.rst')
113 ->notName('Howto.rst');
118 protected function clearMessages()
135 $this->isError
= false;
138 protected function validateContent(string $fileContent)
143 'regex' => '#^\\.\\. include:: \\.\\./\\.\\./Includes.txt#m',
144 'title' => 'no include',
145 'message' => 'insert \'.. include:: ../../Includes.txt\' in first line of the file',
148 'type' => 'reference',
149 'regex' => '#^See :issue:`[0-9]{4,6}`#m',
150 'title' => 'no reference',
151 'message' => 'insert \'See :issue:`<issuenumber>`\' after headline',
155 foreach ($checkFor as $values) {
156 if (preg_match($values['regex'], $fileContent) !== 1) {
157 $this->messages
[$values['type']]['title'] = $values['title'];
158 $this->messages
[$values['type']]['message'] = $values['message'];
159 $this->isError
= true;
164 protected function validateLastLine(string $line)
169 'regex' => '#^\.\. index:: (?:(?:TypoScript|TSConfig|TCA|FlexForm|LocalConfiguration|Fluid|FAL|Database|JavaScript|PHP-API|Frontend|Backend|CLI|RTE|YAML|ext:[a-zA-Z_0-9]+)(?:,\\s|$))+#',
170 'title' => 'no or wrong index',
171 'message' => 'insert \'.. index:: <at least one valid keyword>\' at the last line of the file. See Build/Scripts/validateRstFiles.php for allowed keywords',
175 foreach ($checkFor as $values) {
176 if (preg_match($values['regex'], $line) !== 1) {
177 $this->messages
[$values['type']]['title'] = $values['title'];
178 $this->messages
[$values['type']]['message'] = $values['message'];
179 $this->isError
= true;
184 protected function validateLastLineByFilename(string $path, string $lastLine)
189 'regexIgnoreFilename' => '#'
190 . 'Changelog[\\\\/]' // Ignore all Changelog files
191 . '(?:' // which are either
192 . '.+[\\\\/](?:Feature|Important)' // from any version but of type "Feature" or "Important"
194 . '[78]' // from 7.x and 8.x (as there was no extension scanner back then)
197 'regex' => '#^\.\. index:: .*[, ](?:Fully|Partially|Not)Scanned([, ]|$).*#',
198 'title' => 'missing FullyScanned / PartiallyScanned / NotScanned tag',
199 'message' => 'insert \'.. index:: <at least one valid keyword and either FullyScanned, PartiallyScanned or NotScanned>\' at the last line of the file. See Build/Scripts/validateRstFiles.php for allowed keywords',
203 foreach ($checkFor as $values) {
204 if (preg_match($values['regexIgnoreFilename'], $path) === 1) {
207 if (preg_match($values['regex'], $lastLine) !== 1) {
208 $this->messages
[$values['type']]['title'] = $values['title'];
209 $this->messages
[$values['type']]['message'] = $values['message'];
210 $this->isError
= true;
217 $args = getopt('d:');
218 if (isset($args['d'])) {
221 $validator = new validateRstFiles($dir);
222 $validator->validate();