The Great Parser JS to PHP port of 2020!*

* Not to be confused with the Parsing Team's
"Great Parser JS to PHP port of 2019"

Gasp as OR hacks are changed to null coalescing operators.
Applaud as variable declarations are dropped.
Cheer as parameters and return values are type-hinted.
Shudder as DomNodeLists have no indexOf method.

Moving discussion parsing to the server should allow
us to implement much cleaner APIs for commenting.

Bug: T252252
Co-authored-by: Ed Sanders <esanders@wikimedia.org>
Change-Id: Ic1438d516e223db462cb227f6668e856672f538c
This commit is contained in:
Roan Kattouw 2019-12-09 18:38:17 -08:00 committed by Ed Sanders
parent 111dbeba9a
commit 7b7a2cd69c
4 changed files with 1231 additions and 1 deletions

View file

@ -1,6 +1,8 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<ruleset> <ruleset>
<rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki" /> <rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki">
<exclude name="MediaWiki.ControlStructures.AssignmentInControlStructures.AssignmentInControlStructures" />
</rule>
<file>.</file> <file>.</file>
<arg name="extensions" value="php,php5,inc" /> <arg name="extensions" value="php,php5,inc" />
<arg name="encoding" value="UTF-8" /> <arg name="encoding" value="UTF-8" />

View file

@ -225,6 +225,7 @@
] ]
}, },
"AutoloadClasses": { "AutoloadClasses": {
"DiscussionToolsCommentParser": "includes/DiscussionToolsCommentParser.php",
"DiscussionToolsData": "includes/DiscussionToolsData.php", "DiscussionToolsData": "includes/DiscussionToolsData.php",
"DiscussionToolsHooks": "includes/DiscussionToolsHooks.php" "DiscussionToolsHooks": "includes/DiscussionToolsHooks.php"
}, },

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,124 @@
<?php
use Wikimedia\TestingAccessWrapper;
/**
* @coversDefaultClass DiscussionToolsCommentParser
*/
class DiscussionToolsCommentParserTest extends MediaWikiTestCase {
private static function getJson( $relativePath ) {
$json = json_decode(
// TODO: Move cases out of /qunit
file_get_contents( __DIR__ . '/../qunit/' . $relativePath ),
true
);
return $json;
}
/**
* @dataProvider provideTimestampRegexps
* @covers ::getTimestampRegexp
*/
public function testGetTimestampRegexp( $format, $expected, $message ) {
$parser = TestingAccessWrapper::newFromObject(
DiscussionToolsCommentParser::newFromGlobalState()
);
// HACK: Fix differences between JS & PHP regexes
// TODO: We may just have to have two version in the test data
$expected = preg_replace( '/\\\\u([0-9A-F]+)/', '\\\\x{$1}', $expected );
$expected = str_replace( ':', '\:', $expected );
$expected = '/' . $expected . '/u';
$result = $parser->getTimestampRegexp( $format, '\\d', [ 'UTC' => 'UTC' ] );
self::assertSame( $expected, $result, $message );
}
public function provideTimestampRegexps() {
return self::getJson( './cases/timestamp-regex.json' );
}
/**
* @dataProvider provideTimestampParser
* @covers ::getTimestampParser
*/
public function testGetTimestampParser( $format, $data, $expected, $message ) {
$parser = TestingAccessWrapper::newFromObject(
DiscussionToolsCommentParser::newFromGlobalState()
);
$expected = new DateTimeImmutable( $expected );
$tsParser = $parser->getTimestampParser( $format, null, 'UTC', [ 'UTC' => 'UTC' ] );
self::assertEquals( $expected, $tsParser( $data ), $message );
}
public function provideTimestampParser() {
return self::getJson( './cases/timestamp-parser.json' );
}
/**
* @dataProvider provideTimestampParserDST
* @covers ::getTimestampParser
*/
public function testGetTimestampParserDST(
$sample, $expected, $expectedUtc, $format, $timezone, $timezoneAbbrs, $message
) {
$parser = TestingAccessWrapper::newFromObject(
DiscussionToolsCommentParser::newFromGlobalState()
);
$regexp = $parser->getTimestampRegexp( $format, '\\d', $timezoneAbbrs );
$tsParser = $parser->getTimestampParser( $format, null, $timezone, $timezoneAbbrs );
$expected = new DateTimeImmutable( $expected );
$expectedUtc = new DateTimeImmutable( $expectedUtc );
preg_match( $regexp, $sample, $match, PREG_OFFSET_CAPTURE );
$date = $tsParser( $match );
self::assertEquals( $expected, $date, $message );
self::assertEquals( $expectedUtc, $date, $message );
}
public function provideTimestampParserDST() {
return self::getJson( './cases/timestamp-parser-dst.json' );
}
/**
* @dataProvider provideAuthors
* @covers ::getAuthors
*/
public function testGetAuthors( $thread, $expected ) {
$parser = DiscussionToolsCommentParser::newFromGlobalState();
self::assertEquals( $expected, $parser->getAuthors( $thread ) );
}
public function provideAuthors() {
return [
[
'thread' => (object)[
'replies' => [
(object)[
'author' => 'Eve',
'replies' => []
],
(object)[
'author' => 'Bob',
'replies' => [
(object)[
'author' => 'Alice',
'replies' => []
]
]
]
]
],
'expected' => [ 'Alice', 'Bob', 'Eve' ]
]
];
}
}