Jeff Verkoeyen 6b935abea5 Handle API declaration changes in api_diff.
Summary:
Example output:

- [declaration changed] [`-[MDCCollectionViewStylingDelegate collectionView:didRemoveInlayFromItemAtIndexPaths:]`](6c8ca27405/components/Collections/src/MDCCollectionViewStylingDelegate.h (L112)).
```
- (void)collectionView:(nonnull UICollectionView *)collectionView didRemoveInlayFromItemAtIndexPaths:(nonnull NSArray *)indexPaths
- (void)collectionView:(nonnull UICollectionView *)collectionView didRemoveInlayFromItemAtIndexPaths:(nonnull NSArray<NSIndexPath *> *)indexPaths
```

Closes https://github.com/google/material-components-ios/issues/536.

Reviewers: O1 Material components iOS, cjcox

Reviewed By: O1 Material components iOS, cjcox

Tags: #material_components_ios

Differential Revision: http://codereview.cc/D891
2016-05-23 13:17:18 -04:00

176 lines
5.7 KiB
PHP
Executable File

#!/usr/bin/php
<?php
$xml = file_get_contents('php://stdin');
define(BASE_URL, 'https://github.com/google/material-components-ios');
$structure = simplexml_load_string($xml);
// http://stackoverflow.com/a/10473026
function startsWith($haystack, $needle) {
return $needle === "" || strrpos($haystack, $needle, -strlen($haystack)) !== false;
}
$typeToSymbol = array(
'removal' => '[deleted]',
'addition' => '[new]',
'modification' => '[modified]'
);
$typeToPastTenseVerb = array(
'removal' => 'removed',
'addition' => 'added',
'modification' => 'modified'
);
$typeToCommit = array(
'removal' => $argv[1],
'addition' => $argv[2],
'modification' => $argv[1]
);
$output = array();
function getModificationWithType($modifications, $type) {
foreach ($modifications as $modification) {
if ($modification->type == $type) {
return $modification;
}
}
return false;
}
function getRemovedAndAddedFromArrays($previous, $current) {
$removed = array_filter(array_diff($previous, $current));
$added = array_filter(array_diff($current, $previous));
return array($removed, $added);
}
if (!empty($structure)) {
foreach ($structure->difference as $delta) {
if (startsWith($delta->path, '..') || startsWith(strtolower($delta->path), 'private')) {
// Ignore source not in this component and source that is private
continue;
}
$type = $typeToSymbol[strval($delta->type)];
$verb = $typeToPastTenseVerb[strval($delta->type)];
$commit = $typeToCommit[strval($delta->type)];
$url = BASE_URL."/blob/$commit/".$argv[3].'/'.$delta->path.'#L'.$delta->lineNumber;
$link = "[`".$delta->name."`]($url)";
$lines = array();
if ($delta->type == 'modification') {
$modifications = $delta->modifications->modification;
$types = array();
foreach ($modifications as $modification) {
$types []= $modification->type;
}
$oldurl = BASE_URL."/blob/".$argv[1]."/".$argv[3].'/'.$delta->path.'#L'.$delta->lineNumber;
$newurl = BASE_URL."/blob/".$argv[2]."/".$argv[3].'/'.$delta->path.'#L'.$delta->lineNumber;
$didOutputLines = false;
// Special-case interpretations of modifications.
if (count(array_diff($types, array('availability', 'deprecationMessage'))) == 0) {
$availability = getModificationWithType($modifications, 'availability');
$message = getModificationWithType($modifications, 'deprecationMessage');
if ($availability->currentValue == 'Deprecated') {
// API is newly-deprecated.
$lines []= "- [deprecated] [`".$delta->name."`]($newurl).";
$lines []= "*$message->currentValue*";
$didOutputLines = true;
}
} else if (count(array_diff($types, array('protocols'))) == 0) {
$protocols = getModificationWithType($modifications, 'protocols');
list($removed, $added) = getRemovedAndAddedFromArrays(
explode(", ", $protocols->previousValue),
explode(", ", $protocols->currentValue));
$lines []= "- [protocols changed] [`".$delta->name."`]($newurl).";
if (!empty($removed)) {
$lines []= "Removed *".implode(", ", $removed)."*.";
}
if (!empty($added)) {
$lines []= "Added *".implode(", ", $added)."*.";
}
$didOutputLines = true;
} else if (count(array_diff($types, array('declaration'))) == 0) {
$declaration = getModificationWithType($modifications, 'declaration');
if (preg_match("/@property \((.+?)\) (.+?) (.+)/", $declaration->previousValue, $previous)
&& preg_match("/@property \((.+?)\) (.+?) (.+)/", $declaration->currentValue, $current)) {
if ($previous[2] == $current[2]) { // Same type.
$previousAttributes = explode(", ", $previous[1]);
$currentAttributes = explode(", ", $current[1]);
list($removed, $added) = getRemovedAndAddedFromArrays($previousAttributes, $currentAttributes);
$lines []= "- [property attribute change] [`".$delta->name."`]($newurl).";
if (!empty($removed)) {
$lines []= "Removed *".implode(", ", $removed)."*.";
}
if (!empty($added)) {
$lines []= "Added *".implode(", ", $added)."*.";
}
$didOutputLines = true;
}
} else {
$lines []= "- [declaration changed] [`".$delta->name."`]($newurl).";
$lines []= "```";
$lines []= $declaration->previousValue;
$lines []= $declaration->currentValue;
$lines []= "```";
$didOutputLines = true;
}
} else if (count(array_diff($types, array('header'))) == 0) {
// The API has been moved to a new header.
$header = getModificationWithType($modifications, 'header');
$lines []= "- [moved] [`".$delta->name."`]($newurl).";
$lines []= "From *".$header->previousValue."* to *".$header->currentValue."*.";
$didOutputLines = true;
}
if (!$didOutputLines) {
$lines []= "- $type $link";
$lines []= "";
$lines []= "| From | To | Kind |";
$lines []= "|:---- |:-- |:---- |";
foreach ($modifications as $modification) {
$lines []= "| `". $modification->previousValue ."` | `". $modification->currentValue ."` | `".$modification->type ."` |";
}
$lines []= "";
}
} else {
$lines = array("- $type $link");
}
$output []= $lines;
}
}
if (empty($output)) {
echo "No public API changes detected.\n";
exit(0);
}
$firstlines = array();
foreach ($output as $lines) {
$firstlines []= $lines[0];
}
array_multisort($output, $firstlines);
foreach ($output as $lines) {
echo implode("\n", $lines)."\n";
}
?>