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

Address open GitHub issues #21

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
- uses: hhvm/actions/hack-lint-test@master
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use \Facebook\HackRouter\Codegen;

final class UpdateCodegen {
public function main(): void {
Codegen::forTree(
$codegen = await Codegen::forTree(
__DIR__.'/../src/',
shape(
'controllerBase' => WebController::class,
Expand All @@ -32,7 +32,8 @@ final class UpdateCodegen {
'class' => 'Router',
),
),
)->build;
);
$codegen->build();
}
}
```
Expand Down
6 changes: 0 additions & 6 deletions hhast-lint.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,6 @@
{
"patterns": [ "tests/examples/codegen/*" ],
"disableAllAutoFixes": true
},
{
"patterns": [ "tests/examples/codegen/lookup-path.php" ],
"disabledLinters": [
"Facebook\\HHAST\\Linters\\StrictModeOnlyLinter"
]
}
]
}
15 changes: 12 additions & 3 deletions src/Codegen.hack
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,23 @@ final class Codegen {
?'discardChanges' => bool,
);

/**
* @deprecated, use forTreeAsync() instead.
*/
public static function forTree(
string $source_root,
self::TCodegenConfig $config,
): Codegen {
// leaving for now as it's a public API
/* HHAST_IGNORE_ERROR[DontUseAsioJoin] fix before final release */
return
new self(\HH\Asio\join(TreeParser::fromPathAsync($source_root)), $config);
/* HHAST_IGNORE_ERROR[DontUseAsioJoin] Kept for backward compatibility. */
return \HH\Asio\join(static::forTreeAsync($source_root, $config));
}

public static async function forTreeAsync(
string $source_root,
self::TCodegenConfig $config,
): Awaitable<Codegen> {
return new self(await TreeParser::fromPathAsync($source_root), $config);
}

<<__Memoize>>
Expand Down
35 changes: 33 additions & 2 deletions src/RouterCLILookupCodegenBuilder.hack
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,34 @@ final class RouterCLILookupCodegenBuilder {
private CodegenGeneratedFrom $generatedFrom;
private HackCodegenFactory $cg;

const string CLI_LOOKUP_UTILITY_DOC_TEXT = <<<'TEXT'
A quick way to validate that a path or url routes to the controller you expect.

Usage: path/to/this/utility <%path or url%>.
The output will look something like this:

```
$ tests/examples/codegen/lookup-path.php /a-string/123/derp
HEAD: Facebook\HackRouter\CodeGen\Tests\GetRequestExampleController
GET: Facebook\HackRouter\CodeGen\Tests\GetRequestExampleController
```

You may also copy paste the whole url:
```
$ tests/examples/codegen/lookup-path.php http://localhost:8080/a-string/123/derp?query=abcd#fragment
HEAD: Facebook\HackRouter\CodeGen\Tests\GetRequestExampleController
GET: Facebook\HackRouter\CodeGen\Tests\GetRequestExampleController
```

If the given path does not match any controllers, you'll get the following result:
```
$ tests/examples/codegen/lookup-path.php /a/b/c
No controller found for '/a/b/c'.
```

You can edit the manual sections to change the router and formatter used.
TEXT;

public function __construct(
private IHackCodegenConfig $codegenConfig,
) {
Expand Down Expand Up @@ -75,12 +103,13 @@ final class RouterCLILookupCodegenBuilder {
->addClass($this->getCodegenClass($router_classname, $utility_classname))
->addFunction(
$this->cg->codegenFunction('hack_router_cli_lookup_generated_main')
->setDocBlock(static::CLI_LOOKUP_UTILITY_DOC_TEXT)
->addEmptyUserAttribute('__EntryPoint')
->setReturnType('void')
->setBodyf(
"%s\n".
'$argv = '.
'\\Facebook\\TypeAssert\\matches<KeyedContainer<int, string>>('.
'\\Facebook\\TypeAssert\\matches<vec<string>>('.
"\\HH\\global_get('argv'));\n".
"(new %s())->main(\$argv);\n",
$this->getInitCode(),
Expand Down Expand Up @@ -216,7 +245,7 @@ final class RouterCLILookupCodegenBuilder {

private function getMainMethod(): CodegenMethod {
return $this->cg->codegenMethod('main')
->addParameter('KeyedContainer<int, string> $argv')
->addParameter('vec<string> $argv')
->setReturnType('void')
->setBody(
$this->cg->codegenHackBuilder()
Expand All @@ -229,6 +258,8 @@ final class RouterCLILookupCodegenBuilder {
->addLine('\\fprintf(\\STDERR, "Usage: %s PATH\n", $argv[0]);')
->addLine('exit(1);')
->endIfBlock()
->addInlineComment('The parser is very lenient, `?: $path` is almost never needed.')
->addLine('$path = \parse_url($path, \PHP_URL_PATH) ?: $path;')
->addAssignment(
'$controllers',
'$this->getControllersForPath($path)',
Expand Down
4 changes: 2 additions & 2 deletions tests/CodegenTestCase.hack
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ namespace Facebook\HackRouter;
use function Facebook\FBExpect\expect;

final class CodegenTestCase extends \Facebook\HackTest\HackTest {
public function testCanCreateForTree(): void {
public async function testCanCreateForTreeAsync(): Awaitable<void> {
// Just test it parses and we can create an instance
$codegen = Codegen::forTree(__DIR__.'/examples/', shape());
$codegen = await Codegen::forTreeAsync(__DIR__.'/examples/', shape());
expect($codegen)->toBeInstanceOf(Codegen::class);
}
}
42 changes: 37 additions & 5 deletions tests/examples/codegen/lookup-path.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,50 @@
* To re-generate this file run vendor/hhvm/hacktest/bin/hacktest
*
*
* @partially-generated SignedSource<<cbaefee6b122521b73b4013461591651>>
* @partially-generated SignedSource<<61e1a0bcff805162c34d005bb526d587>>
*/
namespace Facebook\HackRouter\CodeGen\Tests\Generated;

/**
* A quick way to validate that a path or url routes to the controller you
* expect.
*
* Usage: path/to/this/utility <%path or url%>.
* The output will look something like this:
*
* ```
* $ tests/examples/codegen/lookup-path.php /a-string/123/derp
* HEAD: Facebook\HackRouter\CodeGen\Tests\GetRequestExampleController
* GET: Facebook\HackRouter\CodeGen\Tests\GetRequestExampleController
* ```
*
* You may also copy paste the whole url:
* ```
* $ tests/examples/codegen/lookup-path.php
* http://localhost:8080/a-string/123/derp?query=abcd#fragment
* HEAD: Facebook\HackRouter\CodeGen\Tests\GetRequestExampleController
* GET: Facebook\HackRouter\CodeGen\Tests\GetRequestExampleController
* ```
*
* If the given path does not match any controllers, you'll get the following
* result:
* ```
* $ tests/examples/codegen/lookup-path.php /a/b/c
* No controller found for '/a/b/c'.
* ```
*
* You can edit the manual sections to change the router and formatter used.
*/
<<__EntryPoint>>
function hack_router_cli_lookup_generated_main(): void {
/* BEGIN MANUAL SECTION init */
$autoloader = null;
$autoloader_candidates = ImmSet {
$autoloader_candidates = vec[
__DIR__.'/vendor/autoload.hack',
__DIR__.'/../vendor/autoload.hack',
__DIR__.'/../../vendor/autoload.hack',
__DIR__.'/../../../vendor/autoload.hack',
};
];
foreach ($autoloader_candidates as $candidate) {
if (\file_exists($candidate)) {
$autoloader = $candidate;
Expand All @@ -35,7 +65,7 @@ function hack_router_cli_lookup_generated_main(): void {
\Facebook\AutoloadMap\initialize();
/* END MANUAL SECTION */

$argv = \Facebook\TypeAssert\matches<KeyedContainer<int, string>>(\HH\global_get('argv'));
$argv = \Facebook\TypeAssert\matches<vec<string>>(\HH\global_get('argv'));
(new MySiteRouterCLILookup())->main($argv);
}

Expand Down Expand Up @@ -75,12 +105,14 @@ private function getControllersForPath(
}
}

public function main(KeyedContainer<int, string> $argv): void {
public function main(vec<string> $argv): void {
$path = $argv[1] ?? null;
if ($path === null) {
\fprintf(\STDERR, "Usage: %s PATH\n", $argv[0]);
exit(1);
}
// The parser is very lenient, `?: $path` is almost never needed.
$path = \parse_url($path, \PHP_URL_PATH) ?: $path;
$controllers = $this->getControllersForPath($path);
if ($controllers->isEmpty()) {
\printf("No controller found for '%s'.\n", $path);
Expand Down