Skip to content

Commit 076f289

Browse files
authored
Add support for replacing class synopses based on stubs (#7340)
1 parent 1ffbb73 commit 076f289

File tree

1 file changed

+139
-28
lines changed

1 file changed

+139
-28
lines changed

build/gen_stub.php

Lines changed: 139 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,7 +1494,7 @@ public function getClassSynopsisElement(DOMDocument $doc, array $classMap): ?DOM
14941494
$parentClassName = self::getClassSynopsisFilename($parent);
14951495
$includeElement = $this->createIncludeElement(
14961496
$doc,
1497-
"xmlns(db=http://docbook.org/ns/docbook) xpointer(id('class.$parentClassName')/db:partintro/db:section/db:classsynopsis/db:fieldsynopsis[preceding-sibling::db:classsynopsisinfo[1][@role='comment' and text()='&Properties;']]))"
1497+
"xmlns(db=http://docbook.org/ns/docbook) xpointer(id('class.$parentClassName')/db:partintro/db:section/db:classsynopsis/db:fieldsynopsis[preceding-sibling::db:classsynopsisinfo[1][@role='comment' and text()='Properties']]))"
14981498
);
14991499
$classSynopsis->appendChild($includeElement);
15001500
}
@@ -1512,7 +1512,7 @@ public function getClassSynopsisElement(DOMDocument $doc, array $classMap): ?DOM
15121512
$classSynopsis->appendChild(new DOMText("\n "));
15131513
$includeElement = $this->createIncludeElement(
15141514
$doc,
1515-
"xmlns(db=http://docbook.org/ns/docbook) xpointer(id('class.$className')/db:refentry/db:refsect1[@role='description']/descendant::db:constructorsynopsis[not(@role='procedural')]"
1515+
"xmlns(db=http://docbook.org/ns/docbook) xpointer(id('class.$className')/db:refentry/db:refsect1[@role='description']/descendant::db:constructorsynopsis[not(@role='procedural')])"
15161516
);
15171517
$classSynopsis->appendChild($includeElement);
15181518
}
@@ -1530,7 +1530,7 @@ public function getClassSynopsisElement(DOMDocument $doc, array $classMap): ?DOM
15301530
$classSynopsis->appendChild(new DOMText("\n "));
15311531
$includeElement = $this->createIncludeElement(
15321532
$doc,
1533-
"xmlns(db=http://docbook.org/ns/docbook) xpointer(id('class.$className')/db:refentry/db:refsect1[@role='description']/descendant::db:destructorsynopsis[not(@role='procedural')]"
1533+
"xmlns(db=http://docbook.org/ns/docbook) xpointer(id('class.$className')/db:refentry/db:refsect1[@role='description']/descendant::db:destructorsynopsis[not(@role='procedural')])"
15341534
);
15351535
$classSynopsis->appendChild($includeElement);
15361536
}
@@ -2440,7 +2440,113 @@ function generateClassSynopses(array $classMap): array {
24402440
*/
24412441
function replaceClassSynopses(string $targetDirectory, array $classMap): array
24422442
{
2443-
throw new Exception("Not yet implemented!");
2443+
$classSynopses = [];
2444+
2445+
$it = new RecursiveIteratorIterator(
2446+
new RecursiveDirectoryIterator($targetDirectory),
2447+
RecursiveIteratorIterator::LEAVES_ONLY
2448+
);
2449+
2450+
foreach ($it as $file) {
2451+
$pathName = $file->getPathName();
2452+
if (!preg_match('/\.xml$/i', $pathName)) {
2453+
continue;
2454+
}
2455+
2456+
$xml = file_get_contents($pathName);
2457+
if ($xml === false) {
2458+
continue;
2459+
}
2460+
2461+
if (stripos($xml, "<classsynopsis") === false) {
2462+
continue;
2463+
}
2464+
2465+
$replacedXml = getReplacedSynopsisXml($xml);
2466+
2467+
$doc = new DOMDocument();
2468+
$doc->formatOutput = false;
2469+
$doc->preserveWhiteSpace = true;
2470+
$doc->validateOnParse = true;
2471+
$success = $doc->loadXML($replacedXml);
2472+
if (!$success) {
2473+
echo "Failed opening $pathName\n";
2474+
continue;
2475+
}
2476+
2477+
$classSynopsisElements = [];
2478+
foreach ($doc->getElementsByTagName("classsynopsis") as $element) {
2479+
$classSynopsisElements[] = $element;
2480+
}
2481+
2482+
foreach ($classSynopsisElements as $classSynopsis) {
2483+
if (!$classSynopsis instanceof DOMElement) {
2484+
continue;
2485+
}
2486+
2487+
$firstChild = $classSynopsis->firstElementChild;
2488+
if ($firstChild === null) {
2489+
continue;
2490+
}
2491+
$firstChild = $firstChild->firstElementChild;
2492+
if ($firstChild === null) {
2493+
continue;
2494+
}
2495+
$className = $firstChild->textContent;
2496+
if (!isset($classMap[$className])) {
2497+
continue;
2498+
}
2499+
$classInfo = $classMap[$className];
2500+
2501+
$newClassSynopsis = $classInfo->getClassSynopsisElement($doc, $classMap);
2502+
if ($newClassSynopsis === null) {
2503+
continue;
2504+
}
2505+
2506+
// Check if there is any change - short circuit if there is not any.
2507+
2508+
if (replaceAndCompareXmls($doc, $classSynopsis, $newClassSynopsis)) {
2509+
continue;
2510+
}
2511+
2512+
// Return the updated XML
2513+
2514+
$replacedXml = $doc->saveXML();
2515+
2516+
$replacedXml = preg_replace(
2517+
[
2518+
"/REPLACED-ENTITY-([A-Za-z0-9._{}%-]+?;)/",
2519+
"/<phpdoc:classref\s+xmlns:phpdoc=\"([a-z0-9.:\/]+)\"\s+xmlns=\"([a-z0-9.:\/]+)\"\s+xmlns:xi=\"([a-z0-9.:\/]+)\"\s+xml:id=\"([a-z0-9._-]+)\"\s*>/i",
2520+
"/<phpdoc:classref\s+xmlns:phpdoc=\"([a-z0-9.:\/]+)\"\s+xmlns=\"([a-z0-9.:\/]+)\"\s+xmlns:xlink=\"([a-z0-9.:\/]+)\"\s+xmlns:xi=\"([a-z0-9.:\/]+)\"\s+xml:id=\"([a-z0-9._-]+)\"\s*>/i",
2521+
],
2522+
[
2523+
"&$1",
2524+
"<phpdoc:classref xml:id=\"$4\" xmlns:phpdoc=\"$1\" xmlns=\"$2\" xmlns:xi=\"$4\">",
2525+
"<phpdoc:classref xml:id=\"$5\" xmlns:phpdoc=\"$1\" xmlns=\"$2\" xmlns:xlink=\"$3\" xmlns:xi=\"$4\">",
2526+
],
2527+
$replacedXml
2528+
);
2529+
2530+
$classSynopses[$pathName] = $replacedXml;
2531+
}
2532+
}
2533+
2534+
return $classSynopses;
2535+
}
2536+
2537+
function getReplacedSynopsisXml(string $xml): string
2538+
{
2539+
return preg_replace(
2540+
[
2541+
"/&([A-Za-z0-9._{}%-]+?;)/",
2542+
"/<(\/)*xi:([A-Za-z]+?)/"
2543+
],
2544+
[
2545+
"REPLACED-ENTITY-$1",
2546+
"<$1XI$2",
2547+
],
2548+
$xml
2549+
);
24442550
}
24452551

24462552
/**
@@ -2489,7 +2595,7 @@ function replaceMethodSynopses(string $targetDirectory, array $funcMap, array $a
24892595
continue;
24902596
}
24912597

2492-
$replacedXml = preg_replace("/&([A-Za-z0-9._{}%-]+?;)/", "REPLACED-ENTITY-$1", $xml);
2598+
$replacedXml = getReplacedSynopsisXml($xml);
24932599

24942600
$doc = new DOMDocument();
24952601
$doc->formatOutput = false;
@@ -2501,10 +2607,6 @@ function replaceMethodSynopses(string $targetDirectory, array $funcMap, array $a
25012607
continue;
25022608
}
25032609

2504-
$docComparator = new DOMDocument();
2505-
$docComparator->preserveWhiteSpace = false;
2506-
$docComparator->formatOutput = true;
2507-
25082610
$methodSynopsisElements = [];
25092611
foreach ($doc->getElementsByTagName("constructorsynopsis") as $element) {
25102612
$methodSynopsisElements[] = $element;
@@ -2568,19 +2670,7 @@ function replaceMethodSynopses(string $targetDirectory, array $funcMap, array $a
25682670

25692671
// Check if there is any change - short circuit if there is not any.
25702672

2571-
$xml1 = $doc->saveXML($methodSynopsis);
2572-
$xml1 = preg_replace("/&([A-Za-z0-9._{}%-]+?;)/", "REPLACED-ENTITY-$1", $xml1);
2573-
$docComparator->loadXML($xml1);
2574-
$xml1 = $docComparator->saveXML();
2575-
2576-
$methodSynopsis->parentNode->replaceChild($newMethodSynopsis, $methodSynopsis);
2577-
2578-
$xml2 = $doc->saveXML($newMethodSynopsis);
2579-
$xml2 = preg_replace("/&([A-Za-z0-9._{}%-]+?;)/", "REPLACED-ENTITY-$1", $xml2);
2580-
$docComparator->loadXML($xml2);
2581-
$xml2 = $docComparator->saveXML();
2582-
2583-
if ($xml1 === $xml2) {
2673+
if (replaceAndCompareXmls($doc, $methodSynopsis, $newMethodSynopsis)) {
25842674
continue;
25852675
}
25862676

@@ -2631,6 +2721,28 @@ function replaceMethodSynopses(string $targetDirectory, array $funcMap, array $a
26312721
return $methodSynopses;
26322722
}
26332723

2724+
function replaceAndCompareXmls(DOMDocument $doc, DOMElement $originalSynopsis, DOMElement $newSynopsis): bool
2725+
{
2726+
$docComparator = new DOMDocument();
2727+
$docComparator->preserveWhiteSpace = false;
2728+
$docComparator->formatOutput = true;
2729+
2730+
$xml1 = $doc->saveXML($originalSynopsis);
2731+
$xml1 = getReplacedSynopsisXml($xml1);
2732+
$docComparator->loadXML($xml1);
2733+
$xml1 = $docComparator->saveXML();
2734+
2735+
$originalSynopsis->parentNode->replaceChild($newSynopsis, $originalSynopsis);
2736+
2737+
$xml2 = $doc->saveXML($newSynopsis);
2738+
$xml2 = getReplacedSynopsisXml($xml2);
2739+
2740+
$docComparator->loadXML($xml2);
2741+
$xml2 = $docComparator->saveXML();
2742+
2743+
return $xml1 === $xml2;
2744+
}
2745+
26342746
function installPhpParser(string $version, string $phpParserDir) {
26352747
$lockFile = __DIR__ . "/PHP-Parser-install-lock";
26362748
$lockFd = fopen($lockFile, 'w+');
@@ -2715,13 +2827,12 @@ function initPhpParser() {
27152827
$context->forceRegeneration = isset($options["f"]) || isset($options["force-regeneration"]);
27162828
$context->forceParse = $context->forceRegeneration || $printParameterStats || $verify || $generateClassSynopses || $replaceClassSynopses || $generateMethodSynopses || $replaceMethodSynopses;
27172829

2718-
$targetClassSynopses = $argv[$optind + 1] ?? null;
2719-
if ($replaceClassSynopses && $targetClassSynopses === null) {
2830+
$targetSynopses = $argv[$argc - 1] ?? null;
2831+
if ($replaceClassSynopses && $targetSynopses === null) {
27202832
die("A target class synopsis directory must be provided for.\n");
27212833
}
27222834

2723-
$targetMethodSynopses = $argv[$optind + 1 + ($targetClassSynopses !== null)] ?? null;
2724-
if ($replaceMethodSynopses && $targetMethodSynopses === null) {
2835+
if ($replaceMethodSynopses && $targetSynopses === null) {
27252836
die("A target method synopsis directory must be provided.\n");
27262837
}
27272838

@@ -2884,7 +2995,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc
28842995
}
28852996

28862997
if ($replaceClassSynopses) {
2887-
$classSynopses = replaceClassSynopses($targetClassSynopses, $classMap);
2998+
$classSynopses = replaceClassSynopses($targetSynopses, $classMap);
28882999

28893000
foreach ($classSynopses as $filename => $content) {
28903001
if (file_put_contents($filename, $content)) {
@@ -2912,7 +3023,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc
29123023
}
29133024

29143025
if ($replaceMethodSynopses) {
2915-
$methodSynopses = replaceMethodSynopses($targetMethodSynopses, $funcMap, $aliasMap);
3026+
$methodSynopses = replaceMethodSynopses($targetSynopses, $funcMap, $aliasMap);
29163027

29173028
foreach ($methodSynopses as $filename => $content) {
29183029
if (file_put_contents($filename, $content)) {

0 commit comments

Comments
 (0)