From 9415eebccba65fdc93e67c4838fb9b0c982593ae Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 12:59:29 +0200 Subject: [PATCH 01/37] Remove HH_FIXME for ENT_HTML5 --- src/_Private/decode_html_entity.php | 2 +- src/render/HTMLRenderer.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/_Private/decode_html_entity.php b/src/_Private/decode_html_entity.php index cb7cf98..c0e9a00 100644 --- a/src/_Private/decode_html_entity.php +++ b/src/_Private/decode_html_entity.php @@ -40,7 +40,7 @@ function decode_html_entity(string $string): ?(string, string, string) { $out = \html_entity_decode( $match, - /* HH_FIXME[4106] */ /* HH_FIXME[2049] */ \ENT_HTML5, + \ENT_HTML5, 'UTF-8', ); if ($out === $match) { diff --git a/src/render/HTMLRenderer.php b/src/render/HTMLRenderer.php index 61ca072..9f56e50 100644 --- a/src/render/HTMLRenderer.php +++ b/src/render/HTMLRenderer.php @@ -42,7 +42,7 @@ protected static function escapeURIAttribute(string $text): string { // to match cmark's behavior so that we can run the spec test suite. $text = \html_entity_decode( $text, - /* HH_FIXME[4106] */ /* HH_FIXME[2049] */ \ENT_HTML5, + \ENT_HTML5, 'UTF-8', ); From 572bf9df32db57033810a2f1f73bc82a354b6f43 Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 12:59:37 +0200 Subject: [PATCH 02/37] Require xhp-lib --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ad3d3a5..6dafb00 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ }, "require": { "hhvm": "^4.128", - "hhvm/type-assert": "^3.1|^4.0" + "hhvm/type-assert": "^3.1|^4.0", + "facebook/xhp-lib": "^4.1" }, "require-dev": { "hhvm/hacktest": "^2.0", From e625dd912eb04ee655ac584171c68dee836213f4 Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 13:01:31 +0200 Subject: [PATCH 03/37] Format the affect files --- src/render/HTMLRenderer.php | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/render/HTMLRenderer.php b/src/render/HTMLRenderer.php index 9f56e50..9620277 100644 --- a/src/render/HTMLRenderer.php +++ b/src/render/HTMLRenderer.php @@ -12,7 +12,6 @@ use namespace HH\Lib\{C, Str, Vec}; -// TODO: fix namespace support in XHP, use that :'( class HTMLRenderer extends Renderer { const keyset> EXTENSIONS = keyset[ TagFilterExtension::class, @@ -40,11 +39,7 @@ protected static function escapeAttribute(string $text): string { protected static function escapeURIAttribute(string $text): string { // While the spec states that no particular method is required, we attempt // to match cmark's behavior so that we can run the spec test suite. - $text = \html_entity_decode( - $text, - \ENT_HTML5, - 'UTF-8', - ); + $text = \html_entity_decode($text, \ENT_HTML5, 'UTF-8'); $out = ''; $len = Str\length($text); @@ -287,9 +282,8 @@ protected function renderThematicBreak(): string { protected function renderAutoLink(Inlines\AutoLink $node): string { $href = self::escapeURIAttribute($node->getDestination()); $text = self::escapeContent($node->getText()); - $noFollowUgcTag = $this->getContext()->areLinksNoFollowUGC() - ? ' rel="nofollow ugc"' - : ''; + $noFollowUgcTag = + $this->getContext()->areLinksNoFollowUGC() ? ' rel="nofollow ugc"' : ''; return ''.$text.''; } @@ -344,10 +338,10 @@ protected function renderLink(Inlines\Link $node): string { $text = $node->getText() |> Vec\map($$, $child ==> $this->render($child)) |> Str\join($$, ''); - $noFollowUgcTag = $this->getContext()->areLinksNoFollowUGC() - ? ' rel="nofollow ugc"' - : ''; - return ''.$text.''; + $noFollowUgcTag = + $this->getContext()->areLinksNoFollowUGC() ? ' rel="nofollow ugc"' : ''; + return + ''.$text.''; } <<__Override>> From 94aac71e92703e094a7b6a8b1a71f6772e74a487 Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 13:04:10 +0200 Subject: [PATCH 04/37] Shift hhast into top gear --- hhast-lint.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hhast-lint.json b/hhast-lint.json index 6a389c6..20b0467 100644 --- a/hhast-lint.json +++ b/hhast-lint.json @@ -1,3 +1,7 @@ { - "roots": [ "src/", "tests/" ] -} + "roots": [ + "src/", + "tests/" + ], + "builtinLinters": "all" +} \ No newline at end of file From 8d8282bfc02c8b3cff190267a6b38c200c60fcbd Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 13:05:10 +0200 Subject: [PATCH 05/37] Lint PreferSingleQuotedStringLiteral --- src/ParserContext.php | 2 +- src/_Private/consume_link_title.php | 4 +- src/_Private/get_html_entity_table.php | 2 +- src/inlines/BackslashEscape.php | 2 +- src/inlines/Context.php | 4 +- src/inlines/Emphasis.php | 2 +- src/inlines/_Private/parse_with_blacklist.php | 2 +- src/render/HTMLRenderer.php | 6 +-- src/render/MarkdownRenderer.php | 10 ++-- src/render/RenderContext.php | 6 +-- src/render/Renderer.php | 2 +- src/unparsed-blocks/Context.php | 6 +-- src/unparsed-blocks/FencedCodeBlock.php | 2 +- src/unparsed-blocks/HTMLBlock.php | 4 +- .../LinkReferenceDefinition.php | 6 +-- src/unparsed-blocks/TableExtension.php | 2 +- tests/NoFollowUgcAndImageTest.php | 10 ++-- tests/SpecTest.php | 6 +-- tests/XSSTest.php | 46 +++++++++---------- 19 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/ParserContext.php b/src/ParserContext.php index 1b603fb..01d2575 100644 --- a/src/ParserContext.php +++ b/src/ParserContext.php @@ -21,7 +21,7 @@ enum SourceType: int { final class ParserContext { - const keyset DEFAULT_URI_SCHEME_ALLOW_LIST = keyset["http", "https", "irc", "mailto"]; + const keyset DEFAULT_URI_SCHEME_ALLOW_LIST = keyset['http', 'https', 'irc', 'mailto']; private BlockContext $blockContext; private InlineContext $inlineContext; diff --git a/src/_Private/consume_link_title.php b/src/_Private/consume_link_title.php index 7600ad7..8b9ecd3 100644 --- a/src/_Private/consume_link_title.php +++ b/src/_Private/consume_link_title.php @@ -43,7 +43,7 @@ function consume_quoted_link_title(string $input): ?(string, int) { break; } - if ($chr === "\\") { + if ($chr === '\\') { if ($idx + 1 < $len) { $next = $input[$idx + 1]; if (C\contains_key(ASCII_PUNCTUATION, $next)) { @@ -99,7 +99,7 @@ function consume_parenthesized_link_title(string $input): ?(string, int) { continue; } - if ($chr === "\\") { + if ($chr === '\\') { if ($idx + 1 < $len) { $next = $input[$idx + 1]; if (C\contains_key(ASCII_PUNCTUATION, $next)) { diff --git a/src/_Private/get_html_entity_table.php b/src/_Private/get_html_entity_table.php index f2bfad9..14547c5 100644 --- a/src/_Private/get_html_entity_table.php +++ b/src/_Private/get_html_entity_table.php @@ -17,7 +17,7 @@ function get_html_entity_table(): dict { $file = __DIR__.'/../../third-party/entities.json'; invariant( \file_exists($file), - "Expected %s to exist", + 'Expected %s to exist', $file, ); $data = \json_decode( diff --git a/src/inlines/BackslashEscape.php b/src/inlines/BackslashEscape.php index 592b262..c59d241 100644 --- a/src/inlines/BackslashEscape.php +++ b/src/inlines/BackslashEscape.php @@ -21,7 +21,7 @@ public static function consume( string $string, int $offset, ): ?(Inline, int) { - if ($string[$offset] !== "\\") { + if ($string[$offset] !== '\\') { return null; } diff --git a/src/inlines/Context.php b/src/inlines/Context.php index 9ce9461..5bfcafc 100644 --- a/src/inlines/Context.php +++ b/src/inlines/Context.php @@ -99,7 +99,7 @@ public function disableNamedExtension(string $name): this { $this->disabledInlineTypes, Keyset\filter( self::ALL_INLINE_TYPES, - $class ==> Str\ends_with(Str\lowercase($class), "\\".$name.'extension'), + $class ==> Str\ends_with(Str\lowercase($class), '\\'.$name.'extension'), ), ); return $this; @@ -110,7 +110,7 @@ public function enableNamedExtension(string $name): this { $this->disabledInlineTypes, $class ==> !Str\ends_with( Str\lowercase($class), - "\\".Str\lowercase($name).'extension', + '\\'.Str\lowercase($name).'extension', ), ); return $this; diff --git a/src/inlines/Emphasis.php b/src/inlines/Emphasis.php index 805cb80..506bd5f 100644 --- a/src/inlines/Emphasis.php +++ b/src/inlines/Emphasis.php @@ -482,7 +482,7 @@ private static function isStartOfRun( } $previous = $markdown[$offset - 1]; - if ($previous !== "\\" && $previous !== $first) { + if ($previous !== '\\' && $previous !== $first) { return true; } diff --git a/src/inlines/_Private/parse_with_blacklist.php b/src/inlines/_Private/parse_with_blacklist.php index ba16f18..a951c93 100644 --- a/src/inlines/_Private/parse_with_blacklist.php +++ b/src/inlines/_Private/parse_with_blacklist.php @@ -41,7 +41,7 @@ function parse_with_denylist ( list($inline, $new_offset) = $result; invariant( $new_offset > $offset, - "Failed to consume any data with %s", + 'Failed to consume any data with %s', \get_class($inline), ); $offset = $new_offset; diff --git a/src/render/HTMLRenderer.php b/src/render/HTMLRenderer.php index 9620277..6fadad4 100644 --- a/src/render/HTMLRenderer.php +++ b/src/render/HTMLRenderer.php @@ -250,7 +250,7 @@ protected function renderTableDataRow( int $row_idx, Blocks\TableExtension::TRow $row, ): string { - $html = ""; + $html = ''; for ($i = 0; $i < C\count($row); ++$i) { $cell = $row[$i]; @@ -270,7 +270,7 @@ protected function renderTableDataCell( if ($alignment !== null) { $alignment = ' align="'.$alignment.'"'; } - return "'.$this->renderNodes($cell).""; + return ''.$this->renderNodes($cell).''; } <<__Override>> @@ -341,7 +341,7 @@ protected function renderLink(Inlines\Link $node): string { $noFollowUgcTag = $this->getContext()->areLinksNoFollowUGC() ? ' rel="nofollow ugc"' : ''; return - ''.$text.''; + ''.$text.''; } <<__Override>> diff --git a/src/render/MarkdownRenderer.php b/src/render/MarkdownRenderer.php index c0fd999..c6ba5c3 100644 --- a/src/render/MarkdownRenderer.php +++ b/src/render/MarkdownRenderer.php @@ -223,10 +223,10 @@ protected function renderParagraph(Blocks\Paragraph $node): string { $line ==> { $parsed = UnparsedBlocks\parse($ctx, $line)->getChildren(); if (!C\firstx($parsed) is UnparsedBlocks\Paragraph) { - return " ".$line; + return ' '.$line; } if (\preg_match('/^ {0,3}[=-]+ *$/', $line)) { - return "\\".$line; + return '\\'.$line; } return $line; }, @@ -286,7 +286,7 @@ protected function renderTableDataCell( Blocks\TableExtension::TCell $cell, ): string { return $this->renderNodes($cell) - |> Str\replace($$, "|", "\\|"); + |> Str\replace($$, '|', '\\|'); } <<__Override>> @@ -307,7 +307,7 @@ protected function renderInlineWithPlainTextContent( Inlines\InlineWithPlainTextContent $node, ): string { if ($node is Inlines\BackslashEscape) { - return "\\".$node->getContent(); + return '\\'.$node->getContent(); } if ($node is Inlines\EntityReference) { // This matters if the entity reference is for whitespace: if we print @@ -369,7 +369,7 @@ protected function renderHardLineBreak(): string { protected function renderImage(Inlines\Image $node): string { $t = $node->getTitle(); return Str\format( - "![%s](<%s>%s)", + '![%s](<%s>%s)', $this->renderNodes($node->getDescription()), $node->getSource(), $t === null ? '' : (' "'.$t.'"'), diff --git a/src/render/RenderContext.php b/src/render/RenderContext.php index f67ee73..0842b02 100644 --- a/src/render/RenderContext.php +++ b/src/render/RenderContext.php @@ -60,7 +60,7 @@ public function areLinksNoFollowUGC(): bool { public function disableNamedExtension(string $extension): this { $this->enabledExtensions = Vec\filter( $this->enabledExtensions, - $obj ==> !Str\ends_with_ci(\get_class($obj), "\\".$extension.'Extension'), + $obj ==> !Str\ends_with_ci(\get_class($obj), '\\'.$extension.'Extension'), ); return $this; } @@ -68,7 +68,7 @@ public function disableNamedExtension(string $extension): this { public function disableImageFiltering(): this { foreach ($this->extensions as $extension) { if ($extension is TagFilterExtension) { - $extension->removeFromTagBlacklist(keyset["removeFromTagBlacklist(keyset[' Vec\filter( $$, $obj ==> - Str\ends_with_ci(\get_class($obj), "\\".$extension.'Extension'), + Str\ends_with_ci(\get_class($obj), '\\'.$extension.'Extension'), ) |> Vec\concat($$, $this->enabledExtensions) |> Vec\unique_by($$, $x ==> \get_class($x)); diff --git a/src/render/Renderer.php b/src/render/Renderer.php index a06720c..03814b2 100644 --- a/src/render/Renderer.php +++ b/src/render/Renderer.php @@ -173,7 +173,7 @@ protected function renderResolvedNode( } invariant_violation( - "Unhandled node type: %s", + 'Unhandled node type: %s', \get_class($node), ); } diff --git a/src/unparsed-blocks/Context.php b/src/unparsed-blocks/Context.php index 78d209e..4d353f9 100644 --- a/src/unparsed-blocks/Context.php +++ b/src/unparsed-blocks/Context.php @@ -56,7 +56,7 @@ public function disableNamedExtension(string $name): this { self::ALL_BLOCK_TYPES, $class ==> Str\ends_with( Str\lowercase($class), - "\\".Str\lowercase($name).'extension', + '\\'.Str\lowercase($name).'extension', ), ), ); @@ -66,7 +66,7 @@ public function disableNamedExtension(string $name): this { public function enableNamedExtension(string $name): this { $this->disabledBlockTypes = Keyset\filter( $this->disabledBlockTypes, - $class ==> !Str\ends_with(Str\lowercase($class), "\\".$name.'extension'), + $class ==> !Str\ends_with(Str\lowercase($class), '\\'.$name.'extension'), ); return $this; } @@ -156,7 +156,7 @@ public function pushContext(string $context, mixed $value): this { public function popContext(string $context): this { $stack = $this->stacks[$context] ?? vec[]; $count = C\count($stack) - 1; - invariant($count >= 0, "Trying to pop more than was pushed"); + invariant($count >= 0, 'Trying to pop more than was pushed'); $stack = Vec\take($stack, $count); $this->stacks[$context] = $stack; return $this; diff --git a/src/unparsed-blocks/FencedCodeBlock.php b/src/unparsed-blocks/FencedCodeBlock.php index 3ec3ce6..940029b 100644 --- a/src/unparsed-blocks/FencedCodeBlock.php +++ b/src/unparsed-blocks/FencedCodeBlock.php @@ -58,7 +58,7 @@ protected static function createFromLines( for ($i = 0; $i < $len; ++$i) { $char = $info[$i]; if ( - $char === "\\" + $char === '\\' && $i + 1 < $len ) { $next = $info[$i + 1]; diff --git a/src/unparsed-blocks/HTMLBlock.php b/src/unparsed-blocks/HTMLBlock.php index 2d1baea..f0cb5dc 100644 --- a/src/unparsed-blocks/HTMLBlock.php +++ b/src/unparsed-blocks/HTMLBlock.php @@ -27,9 +27,9 @@ class HTMLBlock extends FencedBlock { self::SINGLE_QUOTED_ATTRIBUTE_VALUE.'|'. self::DOUBLE_QUOTED_ATTRIBUTE_VALUE. ')'; - const string ATTRIBUTE_VALUE_SPECIFICATION = "\\s*=\\s*".self::ATTRIBUTE_VALUE; + const string ATTRIBUTE_VALUE_SPECIFICATION = '\\s*=\\s*'.self::ATTRIBUTE_VALUE; const string ATTRIBUTE = - "\\s+".self::ATTRIBUTE_NAME.'('.self::ATTRIBUTE_VALUE_SPECIFICATION.')?'; + '\\s+'.self::ATTRIBUTE_NAME.'('.self::ATTRIBUTE_VALUE_SPECIFICATION.')?'; const dict PARAGRAPH_INTERRUPTING_PATTERNS = dict[ // GFM spec states that closing tag doesn't need to match opening tag diff --git a/src/unparsed-blocks/LinkReferenceDefinition.php b/src/unparsed-blocks/LinkReferenceDefinition.php index 3e8216a..456057d 100644 --- a/src/unparsed-blocks/LinkReferenceDefinition.php +++ b/src/unparsed-blocks/LinkReferenceDefinition.php @@ -45,7 +45,7 @@ public function getKey(): string { public static function normalizeKey(string $in): string { return $in |> Str\trim($$) - |> \mb_convert_case($$, \MB_CASE_LOWER, "UTF-8") + |> \mb_convert_case($$, \MB_CASE_LOWER, 'UTF-8') |> \preg_replace('/\s+/', ' ', $$); } @@ -183,9 +183,9 @@ private static function consumeLabel(Lines $lines): ?(string, Lines) { if ($char === ']') { break; } - if ($char === "\\") { + if ($char === '\\') { if ($i + 1 < $len) { - $label .= "\\".$line[$i + 1]; + $label .= '\\'.$line[$i + 1]; ++$i; continue; } diff --git a/src/unparsed-blocks/TableExtension.php b/src/unparsed-blocks/TableExtension.php index 882630f..b5269e5 100644 --- a/src/unparsed-blocks/TableExtension.php +++ b/src/unparsed-blocks/TableExtension.php @@ -178,7 +178,7 @@ private static function consumeRow( $definitely_row, Vec\map( $parts, - $part ==> Str\trim($part) |> Str\replace($$, "\\|", '|'), + $part ==> Str\trim($part) |> Str\replace($$, '\\|', '|'), ), $rest, ); diff --git a/tests/NoFollowUgcAndImageTest.php b/tests/NoFollowUgcAndImageTest.php index 4b27e94..a92bef1 100644 --- a/tests/NoFollowUgcAndImageTest.php +++ b/tests/NoFollowUgcAndImageTest.php @@ -15,7 +15,7 @@ use namespace HH\Lib\{Str}; final class NoFollowUgcAndImageTest extends TestCase { - const keyset DEFAULT_URI_SCHEME_ALLOW_LIST = keyset["http", "https", "irc", "mailto"]; + const keyset DEFAULT_URI_SCHEME_ALLOW_LIST = keyset['http', 'https', 'irc', 'mailto']; protected function assertXSSExampleMatches( string $name, @@ -65,21 +65,21 @@ public function getNoFollowUgcAndImageExamples(): vec<(string, string)> { return vec[ // LINKS tuple( - "[facebook](https://www.facebook.com)", + '[facebook](https://www.facebook.com)', "

facebook

\n", ), // AUTOLINKS tuple( - "", + '', "

https://www.facebook.com

\n", ), // LINK REFERENCE DEFINITIONS tuple( - "[foo]: + '[foo]: https://www.facebook.com -[foo]", +[foo]', "

foo

\n", ), // IMAGES diff --git a/tests/SpecTest.php b/tests/SpecTest.php index 371cf10..759d272 100644 --- a/tests/SpecTest.php +++ b/tests/SpecTest.php @@ -32,7 +32,7 @@ public function getSpecExamples(): vec<(string, string, string, ?string)> { } $start += Str\length(self::EXAMPLE_START); $newline = Str\search($text, "\n", $start); - invariant($newline !== null, "No newline after start marker"); + invariant($newline !== null, 'No newline after start marker'); $extension = Str\trim(Str\slice($text, $start, $newline - $start)); $start = $newline; $end = Str\search($text, self::EXAMPLE_END, $start); @@ -52,7 +52,7 @@ public function getSpecExamples(): vec<(string, string, string, ?string)> { $count = C\count($parts); invariant( $count === 1 || $count === 2, - "examples should have input and output, example %d has %d parts", + 'examples should have input and output, example %d has %d parts', C\count($examples) + 1, $count, ); @@ -65,7 +65,7 @@ public function getSpecExamples(): vec<(string, string, string, ?string)> { } expect(C\count($examples))->toBeSame( self::EXAMPLE_COUNT, - "Did not get the expected number of examples", + 'Did not get the expected number of examples', ); return $examples; } diff --git a/tests/XSSTest.php b/tests/XSSTest.php index b9cacd0..76fa5c2 100644 --- a/tests/XSSTest.php +++ b/tests/XSSTest.php @@ -23,7 +23,7 @@ protected function assertXSSExampleMatches( ): void { $parser_ctx = (new ParserContext()) ->enableHTML_UNSAFE() - ->setAllowedURISchemes(keyset["foo"]) + ->setAllowedURISchemes(keyset['foo']) ->disableExtensions(); $render_ctx = (new RenderContext()) ->disableExtensions(); @@ -61,91 +61,91 @@ public function getXSSExamples(): vec<(string, string)> { return vec[ // LINKS tuple( - "[a](javascript:prompt(document.cookie))", + '[a](javascript:prompt(document.cookie))', "

[a](javascript:prompt(document.cookie))

\n", ), tuple( - "[notmalicious](javascript:window.onerror=alert;throw%20document.cookie)", + '[notmalicious](javascript:window.onerror=alert;throw%20document.cookie)', "

[notmalicious](javascript:window.onerror=alert;throw%20document.cookie)

\n", ), tuple( - "[a](j a v a s c r i p t:prompt(document.cookie))", + '[a](j a v a s c r i p t:prompt(document.cookie))', "

[a](j a v a s c r i p t:prompt(document.cookie))

\n", ), tuple( - "[test](javascript://%0d%0aprompt(1))", + '[test](javascript://%0d%0aprompt(1))', "

[test](javascript://%0d%0aprompt(1))

\n", ), tuple( - "[test](javascript://%0d%0aprompt(1);com)", + '[test](javascript://%0d%0aprompt(1);com)', "

[test](javascript://%0d%0aprompt(1);com)

\n", ), tuple( - "[notmalicious](javascript:window.onerror=alert;throw%20document.cookie)", + '[notmalicious](javascript:window.onerror=alert;throw%20document.cookie)', "

[notmalicious](javascript:window.onerror=alert;throw%20document.cookie)

\n", ), tuple( - "[notmalicious](javascript://%0d%0awindow.onerror=alert;throw%20document.cookie)", + '[notmalicious](javascript://%0d%0awindow.onerror=alert;throw%20document.cookie)', "

[notmalicious](javascript://%0d%0awindow.onerror=alert;throw%20document.cookie)

\n", ), tuple( - "[a](data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K)", + '[a](data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K)', "

[a](data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K)

\n", ), tuple( - "[clickme](vbscript:alert(document.domain))", + '[clickme](vbscript:alert(document.domain))', "

[clickme](vbscript:alert(document.domain))

\n", ), tuple( - "[a](javascript:this;alert(1))", + '[a](javascript:this;alert(1))', "

[a](javascript:this;alert(1))

\n", ), tuple( - "[a](javascript://www.google.com%0Aprompt(1))", + '[a](javascript://www.google.com%0Aprompt(1))', "

[a](javascript://www.google.com%0Aprompt(1))

\n", ), tuple( - "[a](javascript://%0d%0aconfirm(1);com)", + '[a](javascript://%0d%0aconfirm(1);com)', "

[a](javascript://%0d%0aconfirm(1);com)

\n", ), tuple( - "[a](javascript:window.onerror=confirm;throw%201)", + '[a](javascript:window.onerror=confirm;throw%201)', "

[a](javascript:window.onerror=confirm;throw%201)

\n", ), tuple( - "[a](javascript://www.google.com%0Aalert(1))", + '[a](javascript://www.google.com%0Aalert(1))', "

[a](javascript://www.google.com%0Aalert(1))

\n", ), tuple( "[a]('javascript:alert(\"1\")')", "

[a]('javascript:alert("1")')

\n", ), - tuple("[a](JaVaScRiPt:alert(1))", "

[a](JaVaScRiPt:alert(1))

\n"), + tuple('[a](JaVaScRiPt:alert(1))', "

[a](JaVaScRiPt:alert(1))

\n"), // AUTOLINKS tuple( - "<\h1\>confirm(2)", + '<\h1\>confirm(2)', "

</http://<?php><\h1><script:script>confirm(2)

\n", ), tuple( - "", + '', "

<javascript:prompt(document.cookie)>

\n", ), - tuple("", "

<me@example.com>

\n"), + tuple('', "

<me@example.com>

\n"), // LINK REFERENCE DEFINITIONS tuple( - "[foo]: + '[foo]: javascript:prompt(document.cookie) -[foo]", +[foo]', "

[foo]:\njavascript:prompt(document.cookie)

\n

[foo]

\n", ), // An accepted URI works, but a bad URI that's a longer version of the target URI shouldn't work tuple( - "", + '', "

foo:blah

\n", ), tuple( - "", + '', "

<foobar:blah>

\n", ) ]; From 8134e9d4b59d940b75e32bc645dd8c6f1484bf18 Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 13:05:42 +0200 Subject: [PATCH 06/37] Lint NoFinalMethodInFinalClass --- src/blocks/BlockSequence.php | 4 ++-- src/blocks/InlineSequenceBlock.php | 4 ++-- src/unparsed-blocks/BlockSequence.php | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/blocks/BlockSequence.php b/src/blocks/BlockSequence.php index d3bc4d1..75689c7 100644 --- a/src/blocks/BlockSequence.php +++ b/src/blocks/BlockSequence.php @@ -17,13 +17,13 @@ final class BlockSequence extends LeafBlock { private vec $children; - final public function __construct( + public function __construct( vec $children, ) { $this->children = Vec\filter_nulls($children); } - final public static function flatten(?Block ...$children): this { + public static function flatten(?Block ...$children): this { return new self(vec($children)); } diff --git a/src/blocks/InlineSequenceBlock.php b/src/blocks/InlineSequenceBlock.php index b98e61b..d856b1a 100644 --- a/src/blocks/InlineSequenceBlock.php +++ b/src/blocks/InlineSequenceBlock.php @@ -18,13 +18,13 @@ final class InlineSequenceBlock extends LeafBlock { private vec $children; - final public function __construct( + public function __construct( vec $children, ) { $this->children = Vec\filter_nulls($children); } - final public static function flatten(?Inlines\Inline ...$children): this { + public static function flatten(?Inlines\Inline ...$children): this { return new self(vec($children)); } diff --git a/src/unparsed-blocks/BlockSequence.php b/src/unparsed-blocks/BlockSequence.php index dba5c31..473dd4d 100644 --- a/src/unparsed-blocks/BlockSequence.php +++ b/src/unparsed-blocks/BlockSequence.php @@ -19,17 +19,17 @@ final class BlockSequence extends Block implements BlockProducer { private vec $children; - final public function __construct( + public function __construct( vec $children, ) { $this->children = Vec\filter_nulls($children); } - final public function getChildren(): vec { + public function getChildren(): vec { return $this->children; } - final public static function flatten(?Block ...$children): this { + public static function flatten(?Block ...$children): this { return new self(vec($children)); } From dccc27672fc25390df42b8fb1be7f121b98cefe3 Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 13:06:08 +0200 Subject: [PATCH 07/37] Lint DontHaveTwoEmptyLinesInARow --- src/blocks/BlankLine.php | 1 - src/blocks/ContainerBlock.php | 1 - src/blocks/Document.php | 1 - src/blocks/ThematicBreak.php | 1 - src/inlines/SoftLineBreak.php | 1 - src/unparsed-blocks/BlockQuote.php | 1 - src/unparsed-blocks/ContainerBlock.php | 1 - src/unparsed-blocks/FencedBlock.php | 1 - 8 files changed, 8 deletions(-) diff --git a/src/blocks/BlankLine.php b/src/blocks/BlankLine.php index 74162d4..ac5a284 100644 --- a/src/blocks/BlankLine.php +++ b/src/blocks/BlankLine.php @@ -10,6 +10,5 @@ namespace Facebook\Markdown\Blocks; - class BlankLine extends LeafBlock { } diff --git a/src/blocks/ContainerBlock.php b/src/blocks/ContainerBlock.php index 6a2bbd1..cbad0ee 100644 --- a/src/blocks/ContainerBlock.php +++ b/src/blocks/ContainerBlock.php @@ -10,7 +10,6 @@ namespace Facebook\Markdown\Blocks; - abstract class ContainerBlock extends Block { public function __construct( protected vec $children, diff --git a/src/blocks/Document.php b/src/blocks/Document.php index 5f309a0..45881ca 100644 --- a/src/blocks/Document.php +++ b/src/blocks/Document.php @@ -10,6 +10,5 @@ namespace Facebook\Markdown\Blocks; - class Document extends ContainerBlock { } diff --git a/src/blocks/ThematicBreak.php b/src/blocks/ThematicBreak.php index 7b410e6..fa1d27c 100644 --- a/src/blocks/ThematicBreak.php +++ b/src/blocks/ThematicBreak.php @@ -10,6 +10,5 @@ namespace Facebook\Markdown\Blocks; - class ThematicBreak extends LeafBlock { } diff --git a/src/inlines/SoftLineBreak.php b/src/inlines/SoftLineBreak.php index b628488..6014d44 100644 --- a/src/inlines/SoftLineBreak.php +++ b/src/inlines/SoftLineBreak.php @@ -10,7 +10,6 @@ namespace Facebook\Markdown\Inlines; - class SoftLineBreak extends Inline { public function __construct() { } diff --git a/src/unparsed-blocks/BlockQuote.php b/src/unparsed-blocks/BlockQuote.php index 8be04ff..0c1c4cf 100644 --- a/src/unparsed-blocks/BlockQuote.php +++ b/src/unparsed-blocks/BlockQuote.php @@ -46,7 +46,6 @@ public static function consume( $parsed = null; } - if (C\is_empty($contents)) { return null; } diff --git a/src/unparsed-blocks/ContainerBlock.php b/src/unparsed-blocks/ContainerBlock.php index 59ac7e5..53ba4db 100644 --- a/src/unparsed-blocks/ContainerBlock.php +++ b/src/unparsed-blocks/ContainerBlock.php @@ -12,7 +12,6 @@ use namespace HH\Lib\Vec; - abstract class ContainerBlock extends Block { public function __construct( diff --git a/src/unparsed-blocks/FencedBlock.php b/src/unparsed-blocks/FencedBlock.php index 2c86dc3..a6fb1aa 100644 --- a/src/unparsed-blocks/FencedBlock.php +++ b/src/unparsed-blocks/FencedBlock.php @@ -10,7 +10,6 @@ namespace Facebook\Markdown\UnparsedBlocks; - abstract class FencedBlock extends LeafBlock implements BlockProducer { protected abstract static function createFromLines( vec $lines, From 799edc0e41bbb38ca2796a2e33b33c277fcc38c4 Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 13:16:42 +0200 Subject: [PATCH 08/37] Disable FinalOrAbstractClassLinter This library contain many non-final classes, all of which may have been extended elsewhere. Accept that this library doesn't meet this strict standard and move on. --- hhast-lint.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hhast-lint.json b/hhast-lint.json index 20b0467..16ff964 100644 --- a/hhast-lint.json +++ b/hhast-lint.json @@ -3,5 +3,8 @@ "src/", "tests/" ], - "builtinLinters": "all" + "builtinLinters": "all", + "disabledLinters": [ + "Facebook\\HHAST\\FinalOrAbstractClassLinter" + ] } \ No newline at end of file From 32a5de57618a1e97da108918fab70590776313b5 Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 13:24:38 +0200 Subject: [PATCH 09/37] Disable UseStatementWithAsLinter This library contains classes with duplicate names. Example: ``` use type Facebook\Markdown\Block\ThematicBreak as ASTNode; class ThematicBreak {} ``` The alias to ASTNode allows the UnparsedBlocks\ThematicBreak to refer to the other. A use statement without an alias would create a name collision with the declaration. One could choose to always refer to the other node using a qualified name: Blocks\ThematicBreak --- hhast-lint.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hhast-lint.json b/hhast-lint.json index 16ff964..e5363e5 100644 --- a/hhast-lint.json +++ b/hhast-lint.json @@ -5,6 +5,7 @@ ], "builtinLinters": "all", "disabledLinters": [ - "Facebook\\HHAST\\FinalOrAbstractClassLinter" + "Facebook\\HHAST\\FinalOrAbstractClassLinter", + "Facebook\\HHAST\\UseStatementWithAsLinter" ] } \ No newline at end of file From 228532a127016d9e337fa0c4b9241c0cd6f021ac Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 13:29:25 +0200 Subject: [PATCH 10/37] Lint NoEmptyStatementsLinter This linter found `$offset;`, but I can't imagine what this was supposed to do. It's an int, so what the intent to increment / decrement it? Thank you @ryangreenberg for adding this linter to hhast. --- src/inlines/Link.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/inlines/Link.php b/src/inlines/Link.php index 4c0ad95..dc0de11 100644 --- a/src/inlines/Link.php +++ b/src/inlines/Link.php @@ -87,6 +87,7 @@ public static function consumeLinkish( if ($chr === ']') { --$depth; if ($depth === 0) { + // HHAST_FIXME[NoEmptyStatements] What was this supposed to do? $offset; break; } From 9ff4e8cf3ed70dea9bf50683201242412a20c5a5 Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 13:30:10 +0200 Subject: [PATCH 11/37] Lint clean with "all" --- src/render/RenderContext.php | 2 +- src/unparsed-blocks/_Private/is_paragraph_continuation_text.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/RenderContext.php b/src/render/RenderContext.php index 0842b02..ef3b4d6 100644 --- a/src/render/RenderContext.php +++ b/src/render/RenderContext.php @@ -82,7 +82,7 @@ public function enableNamedExtension(string $extension): this { Str\ends_with_ci(\get_class($obj), '\\'.$extension.'Extension'), ) |> Vec\concat($$, $this->enabledExtensions) - |> Vec\unique_by($$, $x ==> \get_class($x)); + |> Vec\unique_by($$, \get_class<>); return $this; } diff --git a/src/unparsed-blocks/_Private/is_paragraph_continuation_text.php b/src/unparsed-blocks/_Private/is_paragraph_continuation_text.php index 03b907b..1ada580 100644 --- a/src/unparsed-blocks/_Private/is_paragraph_continuation_text.php +++ b/src/unparsed-blocks/_Private/is_paragraph_continuation_text.php @@ -8,7 +8,7 @@ * */ -namespace Facebook\Markdown\UnparsedBlocks\_Private;; +namespace Facebook\Markdown\UnparsedBlocks\_Private; use type Facebook\Markdown\UnparsedBlocks\{BlockProducer, Context, Lines}; use namespace HH\Lib\C; From 0bf465f5e8d497c2705bf6f6fe4655261fe99163 Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 13:31:53 +0200 Subject: [PATCH 12/37] Remove needless null check with help from HHClientLinter --- src/unparsed-blocks/TableExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unparsed-blocks/TableExtension.php b/src/unparsed-blocks/TableExtension.php index b5269e5..971f9e6 100644 --- a/src/unparsed-blocks/TableExtension.php +++ b/src/unparsed-blocks/TableExtension.php @@ -142,7 +142,7 @@ private static function consumeRow( $parts = vec[]; $start = 0; $len = Str\length($first); - while ($start !== null && $start < $len) { + while ($start < $len) { $end = Str\search($first, '|', $start); if ($end === null) { $parts[] = Str\slice($first, $start); From cbc51f9db2129ee8637fc8c3ee3b647167844285 Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 15:00:33 +0200 Subject: [PATCH 13/37] Introduce a couple hacks to aid in the migration https://codebeforethehorse.tumblr.com/post/87306947716/converting-a-project-to-xhp --- src/_Private/DO_NOT_ESCAPE.php | 29 ++++++++++++++++++ src/_Private/DO_NOT_ESCAPE_ATTRIBUTE.php | 33 ++++++++++++++++++++ src/_Private/FORCE_RENDER.php | 38 ++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 src/_Private/DO_NOT_ESCAPE.php create mode 100644 src/_Private/DO_NOT_ESCAPE_ATTRIBUTE.php create mode 100644 src/_Private/FORCE_RENDER.php diff --git a/src/_Private/DO_NOT_ESCAPE.php b/src/_Private/DO_NOT_ESCAPE.php new file mode 100644 index 0000000..0116d16 --- /dev/null +++ b/src/_Private/DO_NOT_ESCAPE.php @@ -0,0 +1,29 @@ + { + return $this->dangerDangerDanger; + } +} diff --git a/src/_Private/DO_NOT_ESCAPE_ATTRIBUTE.php b/src/_Private/DO_NOT_ESCAPE_ATTRIBUTE.php new file mode 100644 index 0000000..da32225 --- /dev/null +++ b/src/_Private/DO_NOT_ESCAPE_ATTRIBUTE.php @@ -0,0 +1,33 @@ +(string $danger_danger_danger): T { + return \HH\FIXME\UNSAFE_CAST( + new DO_NOT_ESCAPE_ATTRIBUTE($danger_danger_danger), + 'XHP has this feature, where it allows you to set unsafe attributes. '. + 'This api is deprecated and the typechecker does not know about it. '. + 'By casting to a unbound T, the callers get `nothing`, which hides this, '. + 'from the typechecker. Use sparingly!', + ); +} + +final class DO_NOT_ESCAPE_ATTRIBUTE + extends XHP\UnsafeAttributeValue_DEPRECATED { + public function __construct(private string $dangerDangerDanger) {} + + public function toHTMLString(): string { + return $this->dangerDangerDanger; + } +} diff --git a/src/_Private/FORCE_RENDER.php b/src/_Private/FORCE_RENDER.php new file mode 100644 index 0000000..b144a3c --- /dev/null +++ b/src/_Private/FORCE_RENDER.php @@ -0,0 +1,38 @@ +toHTMLStringAsync()); + } + + if ($child is XHP\Core\node) { + // HHAST_FIXME[DontUseAsioJoin] We'll cross that bridge when we get to it. + return Asio\join($child->toStringAsync()); + } + + if (\is_scalar($child)) { + // Mostly for me during this migration. + \error_log((new \Exception('Asked to render scalar at:'))->toString()); + return (string)$child; + } + + invariant_violation( + 'How to render: %s?', + \is_object($child) ? \get_class($child) : \gettype($child), + ); +} From b02c8d9a3825432548356e4dd885b8ccc381be72 Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 15:03:06 +0200 Subject: [PATCH 14/37] Prepare for boolean attributes in tests XHP renders `disabled={true}` as `disabled`, but the spec expects `disabled=""`. It would be a shame if this small incompatibility would block xhp adoption. Let's make the spec tests allow these stringless boolean attributes. --- tests/TestCase.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/TestCase.php b/tests/TestCase.php index 6f3b224..11ccd8c 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -15,6 +15,10 @@ abstract class TestCase extends \Facebook\HackTest\HackTest { const string TAB_REPLACEMENT = "\u{2192}"; + const dict BOOLEAN_ATTRIBUTE_REPLACEMENTS = dict[ + ' checked ' => ' checked="" ', + ' disabled ' => ' disabled="" ', + ]; final protected function assertExampleMatches( string $name, @@ -33,7 +37,8 @@ final protected function assertExampleMatches( } $ast = parse($parser_ctx, $in); - $actual_html = (new HTMLRenderer($render_ctx))->render($ast); + $actual_html = (new HTMLRenderer($render_ctx))->render($ast) + |> self::addEmptyStringsForBooleanAttributes($$); // Improve output readability $actual_html = Str\replace($actual_html, "\t", self::TAB_REPLACEMENT); @@ -46,4 +51,10 @@ final protected function assertExampleMatches( $in, ); } + + private static function addEmptyStringsForBooleanAttributes( + string $html, + )[]: string { + return Str\replace_every($html, static::BOOLEAN_ATTRIBUTE_REPLACEMENTS); + } } From c8fdbdd4908a9f03ac792e7da4a4abf66a6769c4 Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 15:13:22 +0200 Subject: [PATCH 15/37] Introduce an escape hatch for XHP rendering The HTMLXHPRenderer still needs to be written. --- src/render/HTMLRenderer.php | 10 ++++++++++ src/render/RenderableAsHTML.php | 3 +++ src/render/RenderableAsXHP.php | 20 ++++++++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 src/render/RenderableAsXHP.php diff --git a/src/render/HTMLRenderer.php b/src/render/HTMLRenderer.php index 6fadad4..9c83e9a 100644 --- a/src/render/HTMLRenderer.php +++ b/src/render/HTMLRenderer.php @@ -66,9 +66,19 @@ protected function renderNodes(vec $nodes): string { <<__Override>> protected function renderResolvedNode(ASTNode $node): string { + if ($node is RenderableAsXHP) { + $xhp_renderer = new HTMLXHPRenderer($this->getContext()); + return $node->renderAsXHP($this->getContext(), $xhp_renderer) + |> _Private\FORCE_RENDER($$); + } + + // This interface is implemented by users of this library. + // It must remain unchanged for backwards compatibility. + // Ideally users would switch over to RenderableAsXHP. if ($node is RenderableAsHTML) { return $node->renderAsHTML($this->getContext(), $this); } + return parent::renderResolvedNode($node); } diff --git a/src/render/RenderableAsHTML.php b/src/render/RenderableAsHTML.php index 887f862..c0e7389 100644 --- a/src/render/RenderableAsHTML.php +++ b/src/render/RenderableAsHTML.php @@ -10,6 +10,9 @@ namespace Facebook\Markdown; +/** + * @see RenderableAsXHP and use it if you can. + */ interface RenderableAsHTML { public function renderAsHTML( RenderContext $context, diff --git a/src/render/RenderableAsXHP.php b/src/render/RenderableAsXHP.php new file mode 100644 index 0000000..93204fd --- /dev/null +++ b/src/render/RenderableAsXHP.php @@ -0,0 +1,20 @@ + Date: Sat, 27 May 2023 15:25:18 +0200 Subject: [PATCH 16/37] Create covariant interface IRenderer All methods have been extracted from Renderer. We need this interface to write tests again HTML(XHP)?Renderer. This itnerface allows us to reference them as `IRenderer`. --- src/render/IRenderer.php | 54 ++++++++++++++++++++++++++++++++++++++++ src/render/Renderer.php | 2 +- tests/TestCase.php | 9 +++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/render/IRenderer.php diff --git a/src/render/IRenderer.php b/src/render/IRenderer.php new file mode 100644 index 0000000..debfb8e --- /dev/null +++ b/src/render/IRenderer.php @@ -0,0 +1,54 @@ + { + protected function getContext(): RenderContext; + + public function render(ASTNode $node): T; + + protected function renderNodes(vec $nodes): T; + + ///// blocks ///// + + protected function renderBlankLine(): T; + protected function renderBlockQuote(Blocks\BlockQuote $node): T; + protected function renderCodeBlock(Blocks\CodeBlock $node): T; + protected function renderDocument(Blocks\Document $node): T; + protected function renderHeading(Blocks\Heading $node): T; + protected function renderHTMLBlock(Blocks\HTMLBlock $node): T; + protected function renderLinkReferenceDefinition( + Blocks\LinkReferenceDefinition $node, + ): T; + protected function renderListOfItems(Blocks\ListOfItems $node): T; + protected function renderParagraph(Blocks\Paragraph $node): T; + protected function renderTableExtension(Blocks\TableExtension $node): T; + protected function renderThematicBreak(): T; + + ///// inlines //// + + protected function renderAutoLink(Inlines\AutoLink $node): T; + protected function renderCodeSpan(Inlines\CodeSpan $node): T; + protected function renderEmphasis(Inlines\Emphasis $node): T; + protected function renderHardLineBreak(): T; + protected function renderImage(Inlines\Image $node): T; + protected function renderInlineWithPlainTextContent( + Inlines\InlineWithPlainTextContent $node, + ): T; + protected function renderLink(Inlines\Link $node): T; + protected function renderRawHTML(Inlines\RawHTML $node): T; + protected function renderSoftLineBreak(): T; + protected function renderStrikethroughExtension( + Inlines\StrikethroughExtension $node, + ): T; + + protected function renderResolvedNode(ASTNode $node): T; +} diff --git a/src/render/Renderer.php b/src/render/Renderer.php index 03814b2..c620233 100644 --- a/src/render/Renderer.php +++ b/src/render/Renderer.php @@ -12,7 +12,7 @@ use namespace HH\Lib\C; -abstract class Renderer { +abstract class Renderer implements IRenderer { public function __construct( private RenderContext $context, ) { diff --git a/tests/TestCase.php b/tests/TestCase.php index 11ccd8c..b6f6570 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -12,6 +12,7 @@ use namespace HH\Lib\Str; use function Facebook\FBExpect\expect; +use type XHPChild; abstract class TestCase extends \Facebook\HackTest\HackTest { const string TAB_REPLACEMENT = "\u{2192}"; @@ -20,6 +21,14 @@ abstract class TestCase extends \Facebook\HackTest\HackTest { ' disabled ' => ' disabled="" ', ]; + protected function providerHTMLRendererConstructors()[]: vec<(function( + RenderContext, + ): IRenderer)> { + return vec[ + ($ctx)[defaults] ==> new HTMLRenderer($ctx), + ]; + } + final protected function assertExampleMatches( string $name, string $in, From 82ba6ddedcc925490c7bde3e333dc666dc107274 Mon Sep 17 00:00:00 2001 From: Lexidor Digital <31805625+lexidor@users.noreply.github.com> Date: Sat, 27 May 2023 15:42:58 +0200 Subject: [PATCH 17/37] Prepare the tests for a new renderer --- tests/EdgeCaseTest.php | 26 ++++++++----- tests/NoFollowUgcAndImageTest.php | 38 +++++++++++------- tests/SpecTest.php | 37 +++++++++++------- tests/TestCase.php | 65 +++++++++++++++++++++++-------- tests/XSSTest.php | 45 ++++++++++----------- 5 files changed, 134 insertions(+), 77 deletions(-) diff --git a/tests/EdgeCaseTest.php b/tests/EdgeCaseTest.php index 4823e50..fc95d86 100644 --- a/tests/EdgeCaseTest.php +++ b/tests/EdgeCaseTest.php @@ -12,6 +12,7 @@ use type Facebook\HackTest\DataProvider; use function Facebook\FBExpect\expect; +use type XHPChild; final class EdgeCaseTest extends TestCase { public function getManualExamples(): vec<(string, string)> { @@ -58,8 +59,11 @@ public function getManualExamples(): vec<(string, string)> { } <> - public function testManualExample(string $in, string $expected_html): void { - $this->assertExampleMatches( + public async function testManualExample( + string $in, + string $expected_html, + ): Awaitable { + await $this->assertExampleMatchesAsync( 'unnamed', $in, $expected_html, @@ -67,18 +71,22 @@ public function testManualExample(string $in, string $expected_html): void { ); } - public function testTagFilter(): void { + <> + public async function testTagFilter( + (function(RenderContext): IRenderer) $constructor, + ): Awaitable { $ast = parse( (new ParserContext())->setSourceType(SourceType::TRUSTED), '