Skip to content
This repository has been archived by the owner on Jul 1, 2023. It is now read-only.

Use xhp for html rendering #27

Open
wants to merge 37 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9415eeb
Remove HH_FIXME for ENT_HTML5
lexidor May 27, 2023
572bf9d
Require xhp-lib
lexidor May 27, 2023
e625dd9
Format the affect files
lexidor May 27, 2023
94aac71
Shift hhast into top gear
lexidor May 27, 2023
8d8282b
Lint PreferSingleQuotedStringLiteral
lexidor May 27, 2023
8134e9d
Lint NoFinalMethodInFinalClass
lexidor May 27, 2023
dccc276
Lint DontHaveTwoEmptyLinesInARow
lexidor May 27, 2023
799edc0
Disable FinalOrAbstractClassLinter
lexidor May 27, 2023
32a5de5
Disable UseStatementWithAsLinter
lexidor May 27, 2023
228532a
Lint NoEmptyStatementsLinter
lexidor May 27, 2023
9ff4e8c
Lint clean with "all"
lexidor May 27, 2023
0bf465f
Remove needless null check with help from HHClientLinter
lexidor May 27, 2023
cbc51f9
Introduce a couple hacks to aid in the migration
lexidor May 27, 2023
b02c8d9
Prepare for boolean attributes in tests
lexidor May 27, 2023
c8fdbdd
Introduce an escape hatch for XHP rendering
lexidor May 27, 2023
b5e961a
Create covariant interface IRenderer<T>
lexidor May 27, 2023
82ba6dd
Prepare the tests for a new renderer
lexidor May 27, 2023
728a277
Fix doubly normalized html in tests
lexidor May 27, 2023
c5f3fd4
FAILING_TEST_ON_PURPOSE_TO_ENSURE_THIS_IS_COVERED
lexidor May 27, 2023
30979eb
Change the type of HTMLXhpRenderer to Render<node>
lexidor May 27, 2023
19916da
Move simple cases to native XHP
lexidor May 27, 2023
1e5646d
Emit images with xhp
lexidor May 27, 2023
8a5c5b4
Move more simple cases to native XHP
lexidor May 27, 2023
666c388
Render lists with XHP
lexidor May 27, 2023
b60ab93
Remove the last FORCE_RENDER() call in HTMLXHPRenderer
lexidor May 27, 2023
c6a0f40
Make DO_NOT_ESCAPE_ATTRIBUTE slightly less dangerous
lexidor May 27, 2023
63148c2
Remove FORCE_RENDER
lexidor May 27, 2023
9482d13
Increase the scare factor of DO_NOT_ESCAPE()
lexidor May 27, 2023
6b25e2c
Factor out escape_uri_attribute
lexidor May 27, 2023
fb18394
Wrap the HTMLXHPRenderer in a Renderer<string>
lexidor May 27, 2023
69b6b88
Put HTMLRenderer::URI_SAFE back for BC
lexidor May 27, 2023
86ec5dc
Lint almost clean (including HHClientLinter)
lexidor May 27, 2023
999f859
Optimization found by HHClientLinter
lexidor May 27, 2023
c096490
Remove needless xhp_join() calls
lexidor May 27, 2023
c53319a
Update README to mention RenderableAsXHP
lexidor May 27, 2023
4a55838
Remove hhvm(-autoload) requirement
lexidor May 27, 2023
08e5859
Fix CI
lexidor May 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ jobs:
# Run tests on all OS's and HHVM versions, even if one fails
fail-fast: false
matrix:
os: [ ubuntu ]
os: [ ubuntu-20.04 ]
hhvm:
- '4.128'
- latest
- nightly
runs-on: ${{matrix.os}}-latest
- '4.153'
- '4.168'
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Create branch for version alias
Expand Down
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@ Originally, the Ruby GFM pipeline was the best fit; over time, we started to wan

FBMarkdown exists to address all of these goals.

## Requirements

- HHVM 3.24 or above.
- [hhvm-autoload](https://github.com/hhvm/hhvm-autoload)

## Installing FBMarkdown

hhvm composer.phar require facebook/fbmarkdown
Expand Down Expand Up @@ -90,7 +85,8 @@ Extend `Facebook\Markdown\Inlines\Inline` or a subclass, and pass your classname

There are then several approaches to rendering:
- instantiate your subclass, and add support for it to a custom renderer
- instantiate your subclass, and make it implement the `Facebook\Markdown\RenderableAsHTML` interface
- instantiate your subclass, and make it implement the `Facebook\Markdown\RenderableAsXHP` interface
- Failing that, try the `Facebook\Markdown\RenderableAsHTML` interface.
- if it could be replaced with several existing inlines, return a
`Facebook\Markdown\Inlines\InlineSequence`, then you won't need to extend the renderer.

Expand All @@ -101,7 +97,8 @@ to `$render_ctx->getBlockContext()->prependBlockTypes(...)`.

There are then several approaches to rendering:
- create a subclass of `Block`, and add support for it to a custom renderer
- create a subclass of `Block`, and make it implement the `Facebook\Markdown\RenderableAsHTML` interface
- create a subclass of `Block`, and make it implement the `Facebook\Markdown\RenderableAsXHP` interface
- Failing that, try the `Facebook\Markdown\RenderableAsHTML` interface.
- if it could be replaced with several existing blocks, return a
`Facebook\Markdown\Blocks\BlockSequence`
- if it could be replaced with a paragraph of inlines, return a `Facebook\Markdown\Blocks\InlineSequenceBlock`
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
12 changes: 10 additions & 2 deletions hhast-lint.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
{
"roots": [ "src/", "tests/" ]
}
"roots": [
"src/",
"tests/"
],
"builtinLinters": "all",
"disabledLinters": [
"Facebook\\HHAST\\FinalOrAbstractClassLinter",
"Facebook\\HHAST\\UseStatementWithAsLinter"
]
}
2 changes: 1 addition & 1 deletion src/ParserContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ enum SourceType: int {

final class ParserContext {

const keyset<string> DEFAULT_URI_SCHEME_ALLOW_LIST = keyset["http", "https", "irc", "mailto"];
const keyset<string> DEFAULT_URI_SCHEME_ALLOW_LIST = keyset['http', 'https', 'irc', 'mailto'];
private BlockContext $blockContext;
private InlineContext $inlineContext;

Expand Down
29 changes: 29 additions & 0 deletions src/_Private/ChildValidationDisablerDisposable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?hh // strict
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\Markdown\_Private;

use namespace Facebook\XHP\ChildValidation;
use type IDisposable;

final class ChildValidationDisablerDisposable implements IDisposable {
private bool $shouldRestore;

public function __construct() {
$this->shouldRestore = ChildValidation\is_enabled();
ChildValidation\disable();
}

public function __dispose(): void {
if ($this->shouldRestore) {
ChildValidation\enable();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?hh // strict
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\Markdown\_Private;

use namespace Facebook\XHP;
use type Facebook\XHP\Core\frag;

/**
* @see https://codebeforethehorse.tumblr.com/post/87306947716/converting-a-project-to-xhp
*/
// HHAST_IGNORE_ERROR[CamelCasedMethodsUnderscoredFunctions] intentionally SHOUT_CASE
function EMBED_THIS_STRING_AS_IS_WITHOUT_ESCAPING_OR_FILTERING(
string $danger_danger_danger,
): frag {
return <frag>{new POTENTIAL_XSS_HOLE($danger_danger_danger)}</frag>;
}

final class POTENTIAL_XSS_HOLE implements XHP\UnsafeRenderable {
public function __construct(private string $dangerDangerDanger) {}

public async function toHTMLStringAsync(): Awaitable<string> {
return $this->dangerDangerDanger;
}
}
22 changes: 22 additions & 0 deletions src/_Private/EscapedAttribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?hh // strict
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\Markdown\_Private;

use namespace Facebook\XHP;

final class EscapedAttribute extends XHP\UnsafeAttributeValue_DEPRECATED {
public function __construct(private string $dangerDangerDanger) {}

<<__Override>>
public function toHTMLString(): string {
return $this->dangerDangerDanger;
}
}
22 changes: 22 additions & 0 deletions src/_Private/URI_SAFE.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?hh // strict
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\Markdown\_Private;

// This is the list from the reference implementation
//hackfmt-ignore
const keyset<string> URI_SAFE = keyset[
'-', '_', '.', '+', '!', '*', "'", '(', ')', ';', ':', '%', '#', '@', '?',
'=', ';', ':', '/', ',', '+', '&', '$',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
];
4 changes: 2 additions & 2 deletions src/_Private/consume_link_title.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down Expand Up @@ -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)) {
Expand Down
2 changes: 1 addition & 1 deletion src/_Private/decode_html_entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
18 changes: 18 additions & 0 deletions src/_Private/disable_child_validation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?hh // strict
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\Markdown\_Private;

use type IDisposable;

<<__ReturnDisposable>>
function disable_child_validation(): IDisposable {
return new ChildValidationDisablerDisposable();
}
33 changes: 33 additions & 0 deletions src/_Private/escape_uri_attribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?hh // strict
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\Markdown\_Private;

use namespace HH\Lib\{C, Str};

function escape_uri_attribute(string $uri): EscapedAttribute {
// 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.
$uri = \html_entity_decode($uri, \ENT_HTML5, 'UTF-8');

$out = '';
$len = Str\length($uri);
for ($i = 0; $i < $len; ++$i) {
$char = $uri[$i];
if (C\contains_key(URI_SAFE, $char)) {
$out .= $char;
continue;
}
$out .= \urlencode($char);
}
$uri = $out;

return new EscapedAttribute(plain_text_to_html_attribute($uri));
}
2 changes: 1 addition & 1 deletion src/_Private/get_html_entity_table.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function get_html_entity_table(): dict<string, string> {
$file = __DIR__.'/../../third-party/entities.json';
invariant(
\file_exists($file),
"Expected %s to exist",
'Expected %s to exist',
$file,
);
$data = \json_decode(
Expand Down
30 changes: 30 additions & 0 deletions src/_Private/td_with_align.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?hh // strict
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\Markdown\_Private;

use namespace Facebook\XHP\ChildValidation as XHPChild;
use namespace Facebook\XHP\HTML\Category;
use type Facebook\XHP\HTML\element;

final xhp class td_with_align extends element implements Category\Sectioning {
use XHPChild\Validation;
attribute :Facebook:XHP:HTML:td,
string align;

<<__Override>>
protected static function getChildrenDeclaration(): XHPChild\Constraint {
return XHPChild\any_number_of(
XHPChild\any_of(XHPChild\pcdata(), XHPChild\of_type<Category\Flow>()),
);
}

protected string $tagName = 'td';
}
30 changes: 30 additions & 0 deletions src/_Private/th_with_align.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?hh // strict
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\Markdown\_Private;

use namespace Facebook\XHP\ChildValidation as XHPChild;
use namespace Facebook\XHP\HTML\Category;
use type Facebook\XHP\HTML\element;

final xhp class th_with_align extends element implements Category\Sectioning {
use XHPChild\Validation;
attribute :Facebook:XHP:HTML:th,
string align;

<<__Override>>
protected static function getChildrenDeclaration(): XHPChild\Constraint {
return XHPChild\any_number_of(
XHPChild\any_of(XHPChild\pcdata(), XHPChild\of_type<Category\Flow>()),
);
}

protected string $tagName = 'th';
}
24 changes: 24 additions & 0 deletions src/_Private/trim_node.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?hh // strict
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

namespace Facebook\Markdown\_Private;

use namespace HH\Lib\{Str, Vec};
use type Facebook\XHP\AlwaysValidChild;
use type Facebook\XHP\Core\primitive;

final xhp class trim_node extends primitive implements AlwaysValidChild {
<<__Override>>
public async function stringifyAsync(): Awaitable<string> {
return await Vec\map_async($this->getChildren(), static::renderChildAsync<>)
|> Str\join($$, '')
|> Str\trim($$);
}
}
Loading