Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
90.91% |
10 / 11 |
CRAP | |
93.98% |
78 / 83 |
EntitySchema\MediaWiki\Content\EntitySchemaSlotDiffRenderer | |
0.00% |
0 / 1 |
|
90.91% |
10 / 11 |
26.15 | |
93.98% |
78 / 83 |
__construct | |
0.00% |
0 / 1 |
5.16 | |
58.33% |
7 / 12 |
|||
getDiff | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
renderSchemaDiffRows | |
100.00% |
1 / 1 |
5 | |
100.00% |
17 / 17 |
|||
renderDiffOp | |
100.00% |
1 / 1 |
7 | |
100.00% |
20 / 20 |
|||
renderTextDiff | |
100.00% |
1 / 1 |
3 | |
100.00% |
8 / 8 |
|||
diffRow | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
diffContext | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
diffBlankLine | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
diffMarker | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
diffAddedLine | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
diffRemovedLine | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
<?php | |
namespace EntitySchema\MediaWiki\Content; | |
use Content; | |
use ContentHandler; | |
use Diff\DiffOp\AtomicDiffOp; | |
use Diff\DiffOp\Diff\Diff; | |
use Diff\DiffOp\DiffOp; | |
use Diff\DiffOp\DiffOpAdd; | |
use Diff\DiffOp\DiffOpChange; | |
use Diff\DiffOp\DiffOpRemove; | |
use Html; | |
use IContextSource; | |
use MessageLocalizer; | |
use RequestContext; | |
use SlotDiffRenderer; | |
use TextSlotDiffRenderer; | |
use UnexpectedValueException; | |
use EntitySchema\Services\Diff\SchemaDiffer; | |
use EntitySchema\Services\SchemaConverter\SchemaConverter; | |
/** | |
* @license GPL-2.0-or-later | |
*/ | |
class EntitySchemaSlotDiffRenderer extends SlotDiffRenderer { | |
/** @var SchemaConverter */ | |
private $schemaConverter; | |
/** @var SchemaDiffer */ | |
private $schemaDiffer; | |
/** @var TextSlotDiffRenderer */ | |
private $textSlotDiffRenderer; | |
/** @var MessageLocalizer */ | |
private $msgLocalizer; | |
public function __construct( | |
IContextSource $context = null, | |
TextSlotDiffRenderer $textSlotDiffRenderer = null | |
) { | |
if ( $context === null ) { | |
$context = RequestContext::getMain(); | |
} | |
if ( $textSlotDiffRenderer === null ) { | |
$textSlotDiffRenderer = ContentHandler::getForModelID( CONTENT_MODEL_TEXT ) | |
->getSlotDiffRenderer( $context ); | |
if ( !is_a( $textSlotDiffRenderer, TextSlotDiffRenderer::class ) ) { | |
throw new UnexpectedValueException( 'Expected a TextSlotDiffRenderer' ); | |
} | |
} | |
$this->schemaDiffer = new SchemaDiffer(); | |
$this->schemaConverter = new SchemaConverter(); | |
$this->textSlotDiffRenderer = $textSlotDiffRenderer; | |
$this->msgLocalizer = $context; | |
} | |
/** | |
* @phan-suppress PhanParamSignatureMismatch | |
* | |
* @param EntitySchemaContent|null $oldContent | |
* @param EntitySchemaContent|null $newContent | |
* | |
* @return string | |
*/ | |
public function getDiff( Content $oldContent = null, Content $newContent = null ) { | |
$this->normalizeContents( $oldContent, $newContent, EntitySchemaContent::class ); | |
$diff = $this->schemaDiffer->diffSchemas( | |
$this->schemaConverter->getFullArraySchemaData( $oldContent->getText() ), | |
$this->schemaConverter->getFullArraySchemaData( $newContent->getText() ) | |
); | |
return $this->renderSchemaDiffRows( $diff ); | |
} | |
public function renderSchemaDiffRows( Diff $diff ) { | |
// split $diff into labels/descriptions/aliases (renderDiffOp()) | |
// and schema (renderTextDiff()) | |
$nameBadgeDiffOps = []; | |
if ( isset( $diff['labels'] ) ) { | |
$nameBadgeDiffOps[ | |
$this->msgLocalizer->msg( 'entityschema-diff-label' )->text() | |
] = $diff['labels']; | |
} | |
if ( isset( $diff['descriptions'] ) ) { | |
$nameBadgeDiffOps[ | |
$this->msgLocalizer->msg( 'entityschema-diff-description' )->text() | |
] = $diff['descriptions']; | |
} | |
if ( isset( $diff['aliases'] ) ) { | |
$nameBadgeDiffOps[ | |
$this->msgLocalizer->msg( 'entityschema-diff-aliases' )->text() | |
] = $diff['aliases']; | |
} | |
$nameBadgeDiff = $this->renderDiffOp( [], new Diff( $nameBadgeDiffOps, true ) ); | |
if ( isset( $diff['schemaText'] ) ) { | |
$schemaDiff = $this->renderTextDiff( | |
$this->msgLocalizer->msg( 'entityschema-diff-schema' )->text(), | |
$diff['schemaText'] | |
); | |
} else { | |
$schemaDiff = ''; | |
} | |
return $nameBadgeDiff . $schemaDiff; | |
} | |
private function renderDiffOp( array $keys, DiffOp $diffOp ) { | |
if ( $diffOp instanceof Diff ) { | |
$output = ''; | |
foreach ( $diffOp->getOperations() as $key => $op ) { | |
$moreKeys = $keys; | |
$moreKeys[] = $key; | |
$output .= $this->renderDiffOp( $moreKeys, $op ); | |
} | |
return $output; | |
} | |
if ( $diffOp instanceof DiffOpRemove || $diffOp instanceof DiffOpChange ) { | |
$leftContext = $this->diffContext( implode( ' / ', $keys ) ); | |
$leftTds = $this->diffRemovedLine( $diffOp->getOldValue() ); | |
} else { | |
$leftContext = $this->diffContext( '' ); | |
$leftTds = $this->diffBlankLine(); | |
} | |
if ( $diffOp instanceof DiffOpAdd || $diffOp instanceof DiffOpChange ) { | |
$rightContext = $this->diffContext( implode( ' / ', $keys ) ); | |
$rightTds = $this->diffAddedLine( $diffOp->getNewValue() ); | |
} else { | |
$rightContext = $this->diffContext( '' ); | |
$rightTds = $this->diffBlankLine(); | |
} | |
$context = $this->diffRow( $leftContext . $rightContext ); | |
$changes = $this->diffRow( $leftTds . $rightTds ); | |
return $context . $changes; | |
} | |
/** | |
* @suppress PhanUndeclaredMethod | |
*/ | |
private function renderTextDiff( $key, AtomicDiffOp $diffOp ) { | |
if ( $diffOp instanceof DiffOpAdd || $diffOp instanceof DiffOpRemove ) { | |
return $this->renderDiffOp( [ $key ], $diffOp ); | |
} | |
/** @var DiffOpChange $diffOp */ | |
// Line 1 → schema / Line 1 | |
return preg_replace( | |
'/<td[^>]* class="diff-lineno"[^>]*>/', | |
'$0' . htmlspecialchars( $key ) . ' / ', | |
$this->textSlotDiffRenderer->getTextDiff( | |
trim( $diffOp->getOldValue() ), | |
trim( $diffOp->getNewValue() ) | |
) | |
); | |
} | |
private function diffRow( $content ) { | |
return Html::rawElement( | |
'tr', | |
[], | |
$content | |
); | |
} | |
private function diffContext( $context ) { | |
return Html::element( | |
'td', | |
[ 'colspan' => '2', 'class' => 'diff-lineno' ], | |
$context | |
); | |
} | |
private function diffBlankLine() { | |
return Html::element( 'td', [ 'colspan' => '2' ] ); | |
} | |
private function diffMarker( $marker ) { | |
return Html::element( | |
'td', | |
[ 'class' => 'diff-marker' ], | |
$marker | |
); | |
} | |
private function diffAddedLine( $line ) { | |
return $this->diffMarker( '+' ) . Html::element( | |
'td', | |
[ 'class' => 'diff-addedline' ], | |
$line | |
); | |
} | |
private function diffRemovedLine( $line ) { | |
return $this->diffMarker( '−' ) . Html::element( | |
'td', | |
[ 'class' => 'diff-deletedline' ], | |
$line | |
); | |
} | |
} |