Page MenuHomeWickedGov Phorge

MockSiteConfig.php
No OneTemporary

Size
12 KB
Referenced Files
None
Subscribers
None

MockSiteConfig.php

<?php
declare( strict_types = 1 );
namespace Wikimedia\Parsoid\Mocks;
use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\ErrorLogHandler;
use Monolog\Logger;
use Wikimedia\Bcp47Code\Bcp47Code;
use Wikimedia\Bcp47Code\Bcp47CodeValue;
use Wikimedia\Parsoid\Config\SiteConfig;
use Wikimedia\Parsoid\Config\StubMetadataCollector;
use Wikimedia\Parsoid\Core\ContentMetadataCollector;
use Wikimedia\Parsoid\Core\LinkTarget;
use Wikimedia\Parsoid\DOM\Document;
use Wikimedia\Parsoid\Utils\Title;
use Wikimedia\Parsoid\Utils\Utils;
class MockSiteConfig extends SiteConfig {
/** @var ?int Unix timestamp */
private $fakeTimestamp = 946782245; // 2000-01-02T03:04:05Z
/** @var int */
private $timezoneOffset = 0; // UTC
/** @var bool */
private $interwikiMagic = true;
/** @var array */
private $linterOverrides = [];
private const NAMESPACE_MAP = [
'media' => -2,
'special' => -1,
'' => 0,
'talk' => 1,
'user' => 2,
'user_talk' => 3,
// Last one will be used by namespaceName
'project' => 4, 'wp' => 4, 'wikipedia' => 4,
'project_talk' => 5, 'wt' => 5, 'wikipedia_talk' => 5,
'file' => 6,
'file_talk' => 7,
'template' => 10,
'template_talk' => 11,
'help' => 12,
'category' => 14,
'category_talk' => 15,
];
/** @var array<int,bool> */
protected $namespacesWithSubpages = [];
/** @var array */
protected $interwikiMap = [];
/** @var int */
private $maxDepth = 40;
/** @var string|null */
private $linkPrefixRegex = null;
/** @var string|bool */
private $externalLinkTarget;
public function __construct( array $opts ) {
parent::__construct();
if ( isset( $opts['linting'] ) ) {
$this->linterEnabled = $opts['linting'];
}
if ( isset( $opts['maxDepth'] ) ) {
$this->maxDepth = $opts['maxDepth'];
}
if ( isset( $opts['linterOverrides'] ) ) {
$this->linterOverrides = $opts['linterOverrides'];
}
$this->linkPrefixRegex = $opts['linkPrefixRegex'] ?? null;
$this->linkTrailRegex = $opts['linkTrailRegex'] ?? '/^([a-z]+)/sD'; // enwiki default
$this->externalLinkTarget = $opts['externallinktarget'] ?? false;
// Use Monolog's PHP console handler
$logger = new Logger( "Parsoid CLI" );
$handler = new ErrorLogHandler();
$handler->setFormatter( new LineFormatter( '%message%' ) );
$logger->pushHandler( $handler );
$this->setLogger( $logger );
}
public function getLinterSiteConfig(): array {
return $this->linterOverrides + parent::getLinterSiteConfig();
}
public function allowedExternalImagePrefixes(): array {
return [];
}
public function baseURI(): string {
return '//my.wiki.example/wikix/';
}
/**
* @inheritDoc
*/
public function exportMetadataToHeadBcp47(
Document $document,
ContentMetadataCollector $metadata,
string $defaultTitle,
Bcp47Code $lang
): void {
'@phan-var StubMetadataCollector $metadata'; // @var StubMetadataCollector $metadata
$moduleLoadURI = $this->server() . $this->scriptpath() . '/load.php';
// Look for a displaytitle.
$displayTitle = $metadata->getPageProperty( 'displaytitle' ) ??
// Use the default title, properly escaped
Utils::escapeHtml( $defaultTitle );
$this->exportMetadataHelper(
$document,
$moduleLoadURI,
$metadata->getModules(),
$metadata->getModuleStyles(),
$metadata->getJsConfigVars(),
$displayTitle,
$lang
);
}
public function redirectRegexp(): string {
return '/(?i:#REDIRECT)/';
}
public function categoryRegexp(): string {
return '/Category/';
}
public function bswRegexp(): string {
return '/' .
'NOGLOBAL|DISAMBIG|NOCOLLABORATIONHUBTOC|nocollaborationhubtoc|NOTOC|notoc|' .
'NOGALLERY|nogallery|FORCETOC|forcetoc|TOC|toc|NOEDITSECTION|noeditsection|' .
'NOTITLECONVERT|notitleconvert|NOTC|notc|NOCONTENTCONVERT|nocontentconvert|' .
'NOCC|nocc|NEWSECTIONLINK|NONEWSECTIONLINK|HIDDENCAT|INDEX|NOINDEX|STATICREDIRECT' .
'/';
}
/** @inheritDoc */
public function canonicalNamespaceId( string $name ): ?int {
return self::NAMESPACE_MAP[$name] ?? null;
}
/** @inheritDoc */
public function namespaceId( string $name ): ?int {
$name = Utils::normalizeNamespaceName( $name );
return self::NAMESPACE_MAP[$name] ?? null;
}
/** @inheritDoc */
public function namespaceName( int $ns ): ?string {
static $map = null;
if ( $map === null ) {
$map = array_flip( self::NAMESPACE_MAP );
}
if ( !isset( $map[$ns] ) ) {
return null;
}
return ucwords( strtr( $map[$ns], '_', ' ' ) );
}
/** @inheritDoc */
public function namespaceHasSubpages( int $ns ): bool {
return !empty( $this->namespacesWithSubpages[$ns] );
}
/** @inheritDoc */
public function namespaceCase( int $ns ): string {
return 'first-letter';
}
/** @inheritDoc */
public function specialPageLocalName( string $alias ): ?string {
return null;
}
public function setInterwikiMagic( bool $val ): void {
$this->interwikiMagic = $val;
}
public function interwikiMagic(): bool {
return $this->interwikiMagic;
}
public function interwikiMap(): array {
return $this->interwikiMap;
}
public function iwp(): string {
return 'mywiki';
}
public function legalTitleChars(): string {
return ' %!"$&\'()*,\-.\/0-9:;=?@A-Z\\\\^_`a-z~\x80-\xFF+';
}
public function linkPrefixRegex(): ?string {
return $this->linkPrefixRegex;
}
protected function linkTrail(): string {
// @phan-suppress-previous-line PhanPluginNeverReturnMethod
throw new \BadMethodCallException(
'Should not be used. linkTrailRegex() is overridden here.' );
}
public function linkTrailRegex(): ?string {
return $this->linkTrailRegex;
}
public function langBcp47(): Bcp47Code {
return new Bcp47CodeValue( 'en' );
}
public function mainPageLinkTarget(): LinkTarget {
return Title::newFromText( 'Main Page', $this );
}
/** @inheritDoc */
public function getMWConfigValue( string $key ) {
switch ( $key ) {
case 'CiteResponsiveReferences':
return true;
case 'CiteResponsiveReferencesThreshold':
return 10;
default:
return null;
}
}
public function rtl(): bool {
return false;
}
/** @inheritDoc */
public function langConverterEnabledBcp47( Bcp47Code $lang ): bool {
return $lang->toBcp47Code() === 'sr';
}
public function script(): string {
return '/wx/index.php';
}
public function scriptpath(): string {
return '/wx';
}
public function server(): string {
return '//my.wiki.example';
}
public function timezoneOffset(): int {
return $this->timezoneOffset;
}
/** @inheritDoc */
public function variantsFor( Bcp47Code $lang ): ?array {
switch ( $lang->toBcp47Code() ) {
case 'sr':
return [
'base' => new Bcp47CodeValue( 'sr' ),
'fallbacks' => [
new Bcp47CodeValue( 'sr-Cyrl' )
]
];
case 'sr-Cyrl':
return [
'base' => new Bcp47CodeValue( 'sr' ),
'fallbacks' => [
new Bcp47CodeValue( 'sr' )
]
];
case 'sr-Latn':
return [
'base' => new Bcp47CodeValue( 'sr' ),
'fallbacks' => [
new Bcp47CodeValue( 'sr' )
]
];
default:
return null;
}
}
public function widthOption(): int {
return 220;
}
/** @inheritDoc */
protected function getVariableIDs(): array {
return []; // None for now
}
/** @inheritDoc */
protected function haveComputedFunctionSynonyms(): bool {
return false;
}
/** @inheritDoc */
protected function updateFunctionSynonym( string $func, string $magicword, bool $caseSensitive ): void {
/* Nothing for now. Look at src/Config/Api/SiteConfig when mocking is needed. */
}
/** @inheritDoc */
protected function getMagicWords(): array {
return [
'toc' => [ 0, '__TOC__' ],
'img_thumbnail' => [ 1, 'thumb' ],
'img_framed' => [ 1, 'frame', 'framed' ],
'img_frameless' => [ 1, 'frameless' ],
'img_manualthumb' => [ 1, 'thumbnail=$1', 'thumb=$1' ],
'img_none' => [ 1, 'none' ],
'img_left' => [ 1, 'left' ],
'img_right' => [ 1, 'right' ],
// T345026: 'sub' should follow 'img_sub' to match dewikivoyage
'img_sub' => [ 1, 'sub' ],
'sub' => [ 0, 'sub' ],
'notoc' => [ 0, '__NOTOC__' ],
'timedmedia_loop' => [ 0, 'loop' ],
'timedmedia_muted' => [ 0, 'muted' ],
];
}
/** @inheritDoc */
public function getMagicWordMatcher( string $id ): string {
if ( $id === 'toc' ) {
return '/^TOC$/';
} else {
return '/(?!)/';
}
}
/** @inheritDoc */
public function getParameterizedAliasMatcher( array $words ): callable {
$paramMWs = [
'img_lossy' => "/^(?:(?i:lossy\=(.*?)))$/uS",
'timedmedia_thumbtime' => "/^(?:(?i:thumbtime\=(.*?)))$/uS",
'timedmedia_starttime' => "/^(?:(?i:start\=(.*?)))$/uS",
'timedmedia_endtime' => "/^(?:(?i:end\=(.*?)))$/uS",
'timedmedia_disablecontrols' => "/^(?:(?i:disablecontrols\=(.*?)))$/uS",
'img_manualthumb' => "/^(?:(?:thumbnail\=(.*?)|thumb\=(.*?)))$/uS",
'img_width' => "/^(?:(?:(.*?)px))$/uS",
'img_lang' => "/^(?:(?:lang\=(.*?)))$/uS",
'img_page' => "/^(?:(?:page\=(.*?)|page (.*?)))$/uS",
'img_upright' => "/^(?:(?:upright\=(.*?)|upright (.*?)))$/uS",
'img_link' => "/^(?:(?:link\=(.*?)))$/uS",
'img_alt' => "/^(?:(?:alt\=(.*?)))$/uS",
'img_class' => "/^(?:(?:class\=(.*?)))$/uS"
];
$regexes = array_intersect_key( $paramMWs, array_flip( $words ) );
return static function ( $text ) use ( $regexes ) {
/**
* $name is the canonical magic word name
* $re has patterns for matching aliases
*/
foreach ( $regexes as $name => $re ) {
if ( preg_match( $re, $text, $m ) ) {
unset( $m[0] );
// Ex. regexp here is, /^(?:(?:|vinculo\=(.*?)|enlace\=(.*?)|link\=(.*?)))$/uS
// Check all the capture groups for a value, if not, it's safe to return an
// empty string since we did get a match.
foreach ( $m as $v ) {
if ( $v !== '' ) {
return [ 'k' => $name, 'v' => $v ];
}
}
return [ 'k' => $name, 'v' => '' ];
}
}
return null;
};
}
/** @inheritDoc */
protected function getNonNativeExtensionTags(): array {
return [
'indicator' => true,
'timeline' => true,
'hiero' => true,
'charinsert' => true,
'inputbox' => true,
'source' => true,
'syntaxhighlight' => true,
'section' => true,
'score' => true,
'templatedata' => true,
'math' => true,
'ce' => true,
'chem' => true,
'graph' => true,
'maplink' => true,
'categorytree' => true,
'templatestyles' => true
];
}
/** @inheritDoc */
public function getMaxTemplateDepth(): int {
return $this->maxDepth;
}
/** @inheritDoc */
protected function getSpecialPageAliases( string $specialPage ): array {
if ( $specialPage === 'Booksources' ) {
return [ 'Booksources', 'BookSources' ]; // Mock value
} else {
throw new \BadMethodCallException( 'Not implemented' );
}
}
/** @inheritDoc */
protected function getSpecialNSAliases(): array {
return [ "Special", "special" ]; // Mock value
}
/** @inheritDoc */
protected function getProtocols(): array {
return [ "http:", "https:", "irc:", "ircs:", "news:", "ftp:", "mailto:", "gopher:", "//" ];
}
public function fakeTimestamp(): ?int {
return $this->fakeTimestamp;
}
/**
* Set the fake timestamp for testing
* @param ?int $ts Unix timestamp
*/
public function setFakeTimestamp( ?int $ts ): void {
$this->fakeTimestamp = $ts;
}
/**
* Set the timezone offset for testing
* @param int $offset Offset from UTC
*/
public function setTimezoneOffset( int $offset ): void {
$this->timezoneOffset = $offset;
}
public function scrubBidiChars(): bool {
return true;
}
/** @inheritDoc */
public function getNoFollowConfig(): array {
return [
'nofollow' => true,
'nsexceptions' => [ 1 ],
'domainexceptions' => [ 'www.example.com' ]
];
}
/** @inheritDoc */
public function getExternalLinkTarget() {
return $this->externalLinkTarget;
}
/** @var ?MockMetrics */
private $metrics;
/** @inheritDoc */
public function metrics(): ?StatsdDataFactoryInterface {
if ( $this->metrics === null ) {
$this->metrics = new MockMetrics();
}
return $this->metrics;
}
/**
* Increment a counter metric
* @param string $name
* @param array $labels
* @param float $amount
* @return void
*/
public function incrementCounter( string $name, array $labels, float $amount = 1 ): void {
// We don't use the labels for now, using MockMetrics instead
$this->metrics->increment( $name );
}
/**
* Record a timing metric
* @param string $name
* @param float $value
* @param array $labels
* @return void
*/
public function observeTiming( string $name, float $value, array $labels ): void {
// We don't use the labels for now, using MockMetrics instead
$this->metrics->timing( $name, $value );
}
}

File Metadata

Mime Type
text/x-php
Expires
Aug 19 2026, 20:46 (7 w, 4 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ba/f4/4da601dee6c200a4539a0c9e28bc
Default Alt Text
MockSiteConfig.php (12 KB)

Event Timeline