Have Parsoid\Config\PageConfigFactory take a rev instead of wikitext
* This let us pass mocked revisions in the parser test runner while running in Parsoid mode. * This leads to improvement in wt2html tests results where a revision id is queried. I've verified this in the Cite extension repo as also the main parserTests.text file but I cannot enable Parsoid integrated testing on the main parser tests file without doing a sweep over all parser tests and adding appropriate test sections * Currently, PageConfigFactory doesn't have unit tests. Will look into adding them separately in a followup. * Moved the setupParsoidTransform function to a more suitable place in the ParserTestRunner.php file. Bug: T270310 Change-Id: I94d68c8528bb2f7b367c68d80d14ebc1ab904a7f
This commit is contained in:
parent
29578f449e
commit
5f5b4cbbb4
4 changed files with 91 additions and 80 deletions
|
|
@ -34,7 +34,6 @@ use MediaWiki\Revision\RevisionRecord;
|
||||||
use ParserCache;
|
use ParserCache;
|
||||||
use ParserOptions;
|
use ParserOptions;
|
||||||
use ParserOutput;
|
use ParserOutput;
|
||||||
use TitleValue;
|
|
||||||
use User;
|
use User;
|
||||||
use Wikimedia\Message\MessageValue;
|
use Wikimedia\Message\MessageValue;
|
||||||
use Wikimedia\ParamValidator\ParamValidator;
|
use Wikimedia\ParamValidator\ParamValidator;
|
||||||
|
|
@ -230,11 +229,7 @@ class ParsoidHTMLHelper {
|
||||||
// TODO: make ParsoidPageConfigFactory take PageReference as well
|
// TODO: make ParsoidPageConfigFactory take PageReference as well
|
||||||
return MediaWikiServices::getInstance()
|
return MediaWikiServices::getInstance()
|
||||||
->get( 'ParsoidPageConfigFactory' )
|
->get( 'ParsoidPageConfigFactory' )
|
||||||
->create(
|
->create( $this->page, null, $this->revision );
|
||||||
TitleValue::newFromPage( $this->page ),
|
|
||||||
null,
|
|
||||||
$this->revision ? $this->revision->getId() : null
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,9 @@ use MediaWiki\Rest\HttpException;
|
||||||
use MediaWiki\Rest\LocalizedHttpException;
|
use MediaWiki\Rest\LocalizedHttpException;
|
||||||
use MediaWiki\Rest\Response;
|
use MediaWiki\Rest\Response;
|
||||||
use MediaWiki\Rest\ResponseException;
|
use MediaWiki\Rest\ResponseException;
|
||||||
|
use MediaWiki\Revision\MutableRevisionRecord;
|
||||||
use MediaWiki\Revision\RevisionAccessException;
|
use MediaWiki\Revision\RevisionAccessException;
|
||||||
|
use MediaWiki\Revision\SlotRecord;
|
||||||
use MobileContext;
|
use MobileContext;
|
||||||
use ParserOutput;
|
use ParserOutput;
|
||||||
use RequestContext;
|
use RequestContext;
|
||||||
|
|
@ -53,6 +55,7 @@ use Wikimedia\Parsoid\Utils\ContentUtils;
|
||||||
use Wikimedia\Parsoid\Utils\DOMCompat;
|
use Wikimedia\Parsoid\Utils\DOMCompat;
|
||||||
use Wikimedia\Parsoid\Utils\DOMUtils;
|
use Wikimedia\Parsoid\Utils\DOMUtils;
|
||||||
use Wikimedia\Parsoid\Utils\Timing;
|
use Wikimedia\Parsoid\Utils\Timing;
|
||||||
|
use WikitextContent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for Parsoid handlers.
|
* Base class for Parsoid handlers.
|
||||||
|
|
@ -364,6 +367,24 @@ abstract class ParsoidHandler extends Handler {
|
||||||
throw new LogicException( 'Title not found!' );
|
throw new LogicException( 'Title not found!' );
|
||||||
}
|
}
|
||||||
$user = RequestContext::getMain()->getUser();
|
$user = RequestContext::getMain()->getUser();
|
||||||
|
|
||||||
|
if ( $wikitextOverride === null ) {
|
||||||
|
$revisionRecord = null;
|
||||||
|
} else {
|
||||||
|
// Create a mutable revision record point to the same revision
|
||||||
|
// and set to the desired wikitext.
|
||||||
|
$revisionRecord = new MutableRevisionRecord( $title );
|
||||||
|
if ( $revision !== null ) {
|
||||||
|
$revisionRecord->setId( $revision );
|
||||||
|
}
|
||||||
|
$revisionRecord->setSlot(
|
||||||
|
SlotRecord::newUnsaved(
|
||||||
|
SlotRecord::MAIN,
|
||||||
|
new WikitextContent( $wikitextOverride )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Note: Parsoid by design isn't supposed to use the user
|
// Note: Parsoid by design isn't supposed to use the user
|
||||||
// context right now, and all user state is expected to be
|
// context right now, and all user state is expected to be
|
||||||
// introduced as a post-parse transform. So although we pass a
|
// introduced as a post-parse transform. So although we pass a
|
||||||
|
|
@ -371,7 +392,7 @@ abstract class ParsoidHandler extends Handler {
|
||||||
// corner cases; see PageConfigFactory::create() for more.
|
// corner cases; see PageConfigFactory::create() for more.
|
||||||
// @phan-suppress-next-line PhanUndeclaredMethod method defined in subtype
|
// @phan-suppress-next-line PhanUndeclaredMethod method defined in subtype
|
||||||
return $this->pageConfigFactory->create(
|
return $this->pageConfigFactory->create(
|
||||||
$title, $user, $revision, $wikitextOverride, $pagelanguageOverride,
|
$title, $user, $revisionRecord ?? $revision, null, $pagelanguageOverride,
|
||||||
$this->parsoidSettings
|
$this->parsoidSettings
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,8 @@
|
||||||
|
|
||||||
namespace MediaWiki\Parser\Parsoid\Config;
|
namespace MediaWiki\Parser\Parsoid\Config;
|
||||||
|
|
||||||
use MediaWiki\Linker\LinkTarget;
|
|
||||||
use MediaWiki\Logger\LoggerFactory;
|
use MediaWiki\Logger\LoggerFactory;
|
||||||
use MediaWiki\Revision\MutableRevisionRecord;
|
use MediaWiki\Page\PageIdentity;
|
||||||
use MediaWiki\Revision\RevisionAccessException;
|
use MediaWiki\Revision\RevisionAccessException;
|
||||||
use MediaWiki\Revision\RevisionRecord;
|
use MediaWiki\Revision\RevisionRecord;
|
||||||
use MediaWiki\Revision\RevisionStore;
|
use MediaWiki\Revision\RevisionStore;
|
||||||
|
|
@ -63,41 +62,52 @@ class PageConfigFactory extends \Wikimedia\Parsoid\Config\PageConfigFactory {
|
||||||
*
|
*
|
||||||
* Note that Parsoid isn't supposed to use the user context by design; all
|
* Note that Parsoid isn't supposed to use the user context by design; all
|
||||||
* user-specific processing is expected to be introduced as a post-parse
|
* user-specific processing is expected to be introduced as a post-parse
|
||||||
* transform. The $user parameter is therefore usually null, especially
|
* transform. The $user parameter is therefore usually null, especially
|
||||||
* in background job parsing, although there are corner cases during
|
* in background job parsing, although there are corner cases during
|
||||||
* extension processing where a non-null $user could affect the output.
|
* extension processing where a non-null $user could affect the output.
|
||||||
*
|
*
|
||||||
* @param LinkTarget $title The page represented by the PageConfig.
|
* @param PageIdentity $pageId The page represented by the PageConfig.
|
||||||
* @param ?UserIdentity $user User who is doing rendering (for parsing options).
|
* @param ?UserIdentity $user User who is doing rendering (for parsing options).
|
||||||
* @param ?int $revisionId The revision of the page.
|
* @param int|RevisionRecord|null $revision Revision id or a revision record
|
||||||
* @param ?string $wikitextOverride Wikitext to use instead of the
|
* @param ?string $unused
|
||||||
* contents of the specific $revision; used when $revision is null
|
|
||||||
* (a new page) or when we are parsing a stashed text.
|
|
||||||
* @param ?string $pagelanguageOverride
|
* @param ?string $pagelanguageOverride
|
||||||
* @param ?array $parsoidSettings Used to enable the debug API if requested
|
* @param ?array $parsoidSettings Used to enable the debug API if requested
|
||||||
* @return \Wikimedia\Parsoid\Config\PageConfig
|
* @return \Wikimedia\Parsoid\Config\PageConfig
|
||||||
*/
|
*/
|
||||||
public function create(
|
public function create(
|
||||||
LinkTarget $title,
|
PageIdentity $pageId,
|
||||||
?UserIdentity $user = null,
|
?UserIdentity $user = null,
|
||||||
?int $revisionId = null,
|
$revision = null,
|
||||||
?string $wikitextOverride = null,
|
?string $unused = null, /* Added to mollify CI with cross-repo uses */
|
||||||
?string $pagelanguageOverride = null,
|
?string $pagelanguageOverride = null,
|
||||||
?array $parsoidSettings = null
|
?array $parsoidSettings = null
|
||||||
): \Wikimedia\Parsoid\Config\PageConfig {
|
): \Wikimedia\Parsoid\Config\PageConfig {
|
||||||
$title = Title::newFromLinkTarget( $title );
|
$title = Title::castFromPageIdentity( $pageId );
|
||||||
|
'@phan-var Title $title';
|
||||||
|
|
||||||
if ( !empty( $parsoidSettings['debugApi'] ) ) {
|
if ( !empty( $parsoidSettings['debugApi'] ) ) {
|
||||||
return ApiPageConfig::fromSettings( $parsoidSettings, [
|
if ( $revision === null ) {
|
||||||
"title" => $title->getPrefixedText(),
|
throw new \InvalidArgumentException(
|
||||||
"pageContent" => $wikitextOverride,
|
"Revision not provided. Cannot lookup revision via debug API." );
|
||||||
"pageLanguage" => $pagelanguageOverride,
|
}
|
||||||
"revid" => $revisionId,
|
|
||||||
"loadData" => true,
|
$content = $revision->getContent( SlotRecord::MAIN );
|
||||||
] );
|
if ( $content instanceof WikitextContent ) {
|
||||||
|
$wtContent = $content->getText();
|
||||||
|
return ApiPageConfig::fromSettings( $parsoidSettings, [
|
||||||
|
"title" => $title->getPrefixedText(),
|
||||||
|
"pageContent" => $wtContent,
|
||||||
|
"pageLanguage" => $pagelanguageOverride,
|
||||||
|
"revid" => $revision->getId(),
|
||||||
|
"loadData" => true,
|
||||||
|
] );
|
||||||
|
} else {
|
||||||
|
throw new \UnexpectedValueException(
|
||||||
|
"Non-wikitext content models not supported by debug API" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $revisionId === null ) {
|
if ( $revision === null ) {
|
||||||
// Fetch the 'latest' revision for the given title.
|
// Fetch the 'latest' revision for the given title.
|
||||||
// Note: This initial fetch of the page context revision is
|
// Note: This initial fetch of the page context revision is
|
||||||
// *not* using Parser::fetchCurrentRevisionRecordOfTitle()
|
// *not* using Parser::fetchCurrentRevisionRecordOfTitle()
|
||||||
|
|
@ -110,31 +120,31 @@ class PageConfigFactory extends \Wikimedia\Parsoid\Config\PageConfigFactory {
|
||||||
) ?: null;
|
) ?: null;
|
||||||
// Note that $revisionRecord could still be null here if no
|
// Note that $revisionRecord could still be null here if no
|
||||||
// page with that $title yet exists.
|
// page with that $title yet exists.
|
||||||
|
} elseif ( !is_int( $revision ) ) {
|
||||||
|
$revisionRecord = $revision;
|
||||||
} else {
|
} else {
|
||||||
// Fetch the correct revision record by the supplied id.
|
// Fetch the correct revision record by the supplied id.
|
||||||
// This accesses the replica DB and may (or may not) fail over to
|
// This accesses the replica DB and may (or may not) fail over to
|
||||||
// the primary DB if the revision isn't found.
|
// the primary DB if the revision isn't found.
|
||||||
$revisionRecord = $this->revisionStore->getRevisionById(
|
$revisionRecord = $this->revisionStore->getRevisionById( $revision );
|
||||||
$revisionId
|
|
||||||
);
|
|
||||||
if ( $revisionRecord === null ) {
|
if ( $revisionRecord === null ) {
|
||||||
// This revision really ought to exist. Check the primary DB.
|
// This revision really ought to exist. Check the primary DB.
|
||||||
// This *could* cause two requests to the primary DB if there
|
// This *could* cause two requests to the primary DB if there
|
||||||
// were pending writes, but this codepath should be very rare.
|
// were pending writes, but this codepath should be very rare.
|
||||||
// [T259855]
|
// [T259855]
|
||||||
$revisionRecord = $this->revisionStore->getRevisionById(
|
$revisionRecord = $this->revisionStore->getRevisionById(
|
||||||
$revisionId, RevisionStore::READ_LATEST
|
$revision, RevisionStore::READ_LATEST
|
||||||
);
|
);
|
||||||
$success = ( $revisionRecord !== null ) ? 'success' : 'failure';
|
$success = ( $revisionRecord !== null ) ? 'success' : 'failure';
|
||||||
LoggerFactory::getInstance( 'Parsoid' )->error(
|
LoggerFactory::getInstance( 'Parsoid' )->error(
|
||||||
"Retried revision fetch after failure: {$success}", [
|
"Retried revision fetch after failure: {$success}", [
|
||||||
'id' => $revisionId,
|
'id' => $revision,
|
||||||
'title' => $title->getPrefixedText(),
|
'title' => $title->getPrefixedText(),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ( $revisionRecord === null ) {
|
if ( $revisionRecord === null ) {
|
||||||
throw new RevisionAccessException( "Can't find revision {$revisionId}" );
|
throw new RevisionAccessException( "Can't find revision {$revision}" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -149,24 +159,6 @@ class PageConfigFactory extends \Wikimedia\Parsoid\Config\PageConfigFactory {
|
||||||
throw new RevisionAccessException( 'Not an available content version.' );
|
throw new RevisionAccessException( 'Not an available content version.' );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $wikitextOverride !== null ) {
|
|
||||||
if ( $revisionRecord ) {
|
|
||||||
// PORT-FIXME this is not really the right thing to do; need
|
|
||||||
// a clone-like constructor for MutableRevisionRecord
|
|
||||||
$revisionRecord = MutableRevisionRecord::newFromParentRevision(
|
|
||||||
$revisionRecord
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$revisionRecord = new MutableRevisionRecord( $title );
|
|
||||||
}
|
|
||||||
$revisionRecord->setSlot(
|
|
||||||
SlotRecord::newUnsaved(
|
|
||||||
SlotRecord::MAIN,
|
|
||||||
new WikitextContent( $wikitextOverride )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$parserOptions =
|
$parserOptions =
|
||||||
$user
|
$user
|
||||||
? ParserOptions::newFromUser( $user )
|
? ParserOptions::newFromUser( $user )
|
||||||
|
|
|
||||||
|
|
@ -1572,35 +1572,6 @@ class ParserTestRunner {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setupParsoidTransform( ParserTest $test ): array {
|
|
||||||
$services = MediaWikiServices::getInstance();
|
|
||||||
$pageConfigFactory = $services->get( 'ParsoidPageConfigFactory' );
|
|
||||||
$pageConfig = null;
|
|
||||||
[ $title, $options, $revId ] = $this->setupParserOptions(
|
|
||||||
$test,
|
|
||||||
static function ( $context, $title, $revId, $wikitext ) use ( $pageConfigFactory, &$pageConfig ) {
|
|
||||||
$pageConfig = $pageConfigFactory->create(
|
|
||||||
$title,
|
|
||||||
$context->getUser(),
|
|
||||||
// @todo T270310: Parsoid doesn't have a mechanism
|
|
||||||
// to override revid with a fake revision, like the
|
|
||||||
// legacy parser does, so {{REVISIONID}} will be
|
|
||||||
// 'wrong' in parser tests. Probably need to
|
|
||||||
// override
|
|
||||||
// ParserOptions::getCurrentRevisionRecordCallback()
|
|
||||||
// (like we do for the 'lastsavedrevision' option
|
|
||||||
// below) in order to fix this.
|
|
||||||
null/*$revId*/,
|
|
||||||
// @todo T270310: Parsoid should really accept a
|
|
||||||
// RevisionRecord here, instead of raw wikitext.
|
|
||||||
$wikitext,
|
|
||||||
$context->getLanguage()->getCode()
|
|
||||||
);
|
|
||||||
return $pageConfig->getParserOptions();
|
|
||||||
} );
|
|
||||||
return [ $pageConfig, $title, $options, $revId ];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Parsoid $parsoid
|
* @param Parsoid $parsoid
|
||||||
* @param PageConfig $pageConfig
|
* @param PageConfig $pageConfig
|
||||||
|
|
@ -1771,6 +1742,38 @@ class ParserTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function setupParsoidTransform( ParserTest $test ): array {
|
||||||
|
$services = MediaWikiServices::getInstance();
|
||||||
|
$pageConfigFactory = $services->get( 'ParsoidPageConfigFactory' );
|
||||||
|
$pageConfig = null;
|
||||||
|
$runner = $this;
|
||||||
|
[ $title, $options, $revId ] = $this->setupParserOptions(
|
||||||
|
$test,
|
||||||
|
static function ( $context, $title, $revId, $wikitext ) use ( $runner, $pageConfigFactory, &$pageConfig ) {
|
||||||
|
$user = $context->getUser();
|
||||||
|
$content = new WikitextContent( $wikitext );
|
||||||
|
$title = Title::newFromRow( (object)[
|
||||||
|
'page_id' => 187,
|
||||||
|
'page_len' => $content->getSize(),
|
||||||
|
'page_latest' => 1337,
|
||||||
|
'page_namespace' => $title->getNamespace(),
|
||||||
|
'page_title' => $title->getDBkey(),
|
||||||
|
'page_is_redirect' => 0
|
||||||
|
] );
|
||||||
|
$revRecord = new MutableRevisionRecord( $title );
|
||||||
|
$revRecord->setContent( SlotRecord::MAIN, $content )
|
||||||
|
->setUser( $user )
|
||||||
|
->setTimestamp( strval( $runner->getFakeTimestamp() ) )
|
||||||
|
->setPageId( $title->getArticleID() )
|
||||||
|
->setId( $title->getLatestRevID() );
|
||||||
|
$pageConfig = $pageConfigFactory->create(
|
||||||
|
$title, $user, $revRecord, $context->getLanguage()->getCode()
|
||||||
|
);
|
||||||
|
return $pageConfig->getParserOptions();
|
||||||
|
} );
|
||||||
|
return [ $pageConfig, $title, $options, $revId ];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to register a Parsoid extension module in such a
|
* Helper function to register a Parsoid extension module in such a
|
||||||
* way that it can be cleaned up after the test is complete.
|
* way that it can be cleaned up after the test is complete.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue