diff --git a/.gitattributes b/.gitattributes index 903f0e8d..cdcffa2d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,5 @@ tests/ export-ignore examples/ export-ignore .hhconfig export-ignore +.hhvmconfig.hdf export-ignore *.hack linguist-language=Hack diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 374346fc..9a597938 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -13,7 +13,7 @@ jobs: matrix: os: [ ubuntu ] hhvm: - - '4.102' + - '4.128' - latest - nightly runs-on: ${{matrix.os}}-latest diff --git a/.hhvmconfig.hdf b/.hhvmconfig.hdf new file mode 100644 index 00000000..e8800caa --- /dev/null +++ b/.hhvmconfig.hdf @@ -0,0 +1,3 @@ +Autoload { + Query = {"expression": ["allof", ["type", "f"], ["suffix", ["anyof", "hack", "php"]], ["not",["anyof",["dirname",".var"],["dirname",".git"]]]]} +} \ No newline at end of file diff --git a/composer.json b/composer.json index 3ec758aa..0f577a62 100644 --- a/composer.json +++ b/composer.json @@ -3,9 +3,7 @@ "description": "Hack Codegen is a library for programmatically generating Hack code", "keywords": ["code generation", "Hack"], "require": { - "hhvm": "^4.102", - "hhvm/hhvm-autoload": "^2.0|^3.0", - "hhvm/hsl": "^4.0" + "hhvm": "^4.128" }, "bin": [ "bin/hh-codegen-verify-signatures", "bin/hh-codegen-verify-signatures.hack" ], "authors": [ @@ -37,6 +35,12 @@ "hhvm/type-assert": "^3.1|^4.0", "facebook/fbexpect": "^2.6.1", "hhvm/hhast": "^4.80", + "hhvm/hhvm-autoload": "^2.0|^3.0", "facebook/difflib": "^1.0" + }, + "config": { + "allow-plugins": { + "hhvm/hhvm-autoload": true + } } } diff --git a/examples/dorm/CodegenDorm.php b/examples/dorm/CodegenDorm.php index f5aa9dbb..09ca706e 100644 --- a/examples/dorm/CodegenDorm.php +++ b/examples/dorm/CodegenDorm.php @@ -184,7 +184,7 @@ private function getGetters(): Vector { } private function getDatabaseRowShape(): CodegenShape { - $db_fields = varray[]; + $db_fields = vec[]; foreach ($this->schema->getFields() as $field) { $type = $field->getType(); if ($type === \DateTime::class) { diff --git a/hh_autoload.json b/hh_autoload.json index 5783f1c8..af181928 100644 --- a/hh_autoload.json +++ b/hh_autoload.json @@ -6,5 +6,6 @@ "examples/", "tests/" ], - "devFailureHandler": "Facebook\\AutoloadMap\\HHClientFallbackHandler" + "devFailureHandler": "Facebook\\AutoloadMap\\HHClientFallbackHandler", + "useFactsIfAvailable": true } diff --git a/src/BaseCodeBuilder.hack b/src/BaseCodeBuilder.hack index f9c2bc63..5dbe6509 100644 --- a/src/BaseCodeBuilder.hack +++ b/src/BaseCodeBuilder.hack @@ -18,7 +18,7 @@ use namespace Facebook\HackCodegen\_Private\Vec as VecP; * should be used to generate code. For example, Hack code is generated using * the `HackBuilder` class. */ - <<__ConsistentConstruct>> +<<__ConsistentConstruct>> abstract class BaseCodeBuilder { const string DELIMITER = "\0"; @@ -94,15 +94,15 @@ abstract class BaseCodeBuilder { return $this; } - /** - * Add the specified code with a %-placeholder format string, but no further + /** + * Add the specified code with a %-placeholder format string, but no further * processing. - * - * For example, if there is a newline, any following characters will not be - * indented. This is useful for heredocs. - * - * @see addVerbatim - */ + * + * For example, if there is a newline, any following characters will not be + * indented. This is useful for heredocs. + * + * @see addVerbatim + */ final public function addVerbatimf( Str\SprintfFormatString $code, mixed ...$args @@ -124,7 +124,7 @@ abstract class BaseCodeBuilder { * * This is unsafe. Use `addf` instead if you have a literal format string. */ - final protected function addvf(string $code, varray $args): this { + final protected function addvf(string $code, vec $args): this { if ($code === null) { return $this; } @@ -190,7 +190,7 @@ abstract class BaseCodeBuilder { * insert a newline. */ final protected function addLineImplvf( ?string $code, - varray $args, + vec $args, ): this { return $this->addvf((string)$code, $args)->newLine(); } diff --git a/src/CodegenFile.hack b/src/CodegenFile.hack index 9391fc18..40c4cbf2 100644 --- a/src/CodegenFile.hack +++ b/src/CodegenFile.hack @@ -45,7 +45,7 @@ final class CodegenFile { private vec $beforeTypes = vec[]; private vec $afterTypes = vec[]; private vec $consts = vec[]; - private vec $enums = vec []; + private vec $enums = vec[]; private bool $doClobber = false; protected ?CodegenGeneratedFrom $generatedFrom; private bool $isSignedFile = true; @@ -411,7 +411,7 @@ final class CodegenFile { if ($header !== null) { invariant( $this->fileType !== CodegenFileType::HACK_STRICT, - 'Pseudomains (and pseudomain headers) are not supported in strict files' + 'Pseudomains (and pseudomain headers) are not supported in strict files', ); $builder->ensureNewLine()->add($header)->ensureNewLine(); } @@ -450,7 +450,7 @@ final class CodegenFile { if ($footer !== null) { invariant( $this->fileType !== CodegenFileType::HACK_STRICT, - 'Pseudomains (and pseudomain footers) are not supported in strict files' + 'Pseudomains (and pseudomain footers) are not supported in strict files', ); $builder->ensureEmptyLine()->add($footer)->ensureNewLine(); } @@ -460,7 +460,7 @@ final class CodegenFile { private function loadExistingFiles(): ?string { $file_names = $this->otherFileNames; $file_names[] = $this->fileName; - $all_content = varray[]; + $all_content = vec[]; foreach ($file_names as $file_name) { if (\file_exists($file_name)) { $content = Filesystem::readFile($file_name); diff --git a/src/HackfmtFormatter.hack b/src/HackfmtFormatter.hack index 8afdc86d..20071832 100644 --- a/src/HackfmtFormatter.hack +++ b/src/HackfmtFormatter.hack @@ -13,21 +13,13 @@ use namespace HH\Lib\{Str, Vec}; final class HackfmtFormatter implements ICodegenFormatter { - public function __construct( - private IHackCodegenConfig $config - ) {} + public function __construct(private IHackCodegenConfig $config) {} - public function format( - string $code, - string $_file_name, - ): string { - $output = varray[]; + public function format(string $code, string $_file_name): string { + $output = vec[]; $exit_code = null; - $tempnam = \tempnam( - \sys_get_temp_dir(), - 'hack-codegen-hackfmt', - ); + $tempnam = \tempnam(\sys_get_temp_dir(), 'hack-codegen-hackfmt'); $options = $this->getFormattedOptions(); @@ -42,10 +34,7 @@ final class HackfmtFormatter implements ICodegenFormatter { \unlink($tempnam); } - invariant( - $exit_code === 0, - 'Failed to invoke hackfmt', - ); + invariant($exit_code === 0, 'Failed to invoke hackfmt'); return Str\join($output, "\n")."\n"; } @@ -53,9 +42,9 @@ final class HackfmtFormatter implements ICodegenFormatter { private function getFormattedOptions(): string { $options = vec[ '--indent-width', - (string) $this->config->getSpacesPerIndentation(), + (string)$this->config->getSpacesPerIndentation(), '--line-width', - (string) $this->config->getMaxLineLength(), + (string)$this->config->getMaxLineLength(), ]; if ($this->config->shouldUseTabs()) { @@ -69,9 +58,6 @@ final class HackfmtFormatter implements ICodegenFormatter { $options[] = '--format-generated-code'; } - return Vec\map( - $options, - \escapeshellarg<>, - ) |> Str\join($$, ' '); + return Vec\map($options, \escapeshellarg<>) |> Str\join($$, ' '); } } diff --git a/src/PartiallyGeneratedCode.hack b/src/PartiallyGeneratedCode.hack index 5c2f1a49..06833224 100644 --- a/src/PartiallyGeneratedCode.hack +++ b/src/PartiallyGeneratedCode.hack @@ -55,7 +55,7 @@ final class PartiallyGeneratedCode { string $existing_code, ?KeyedContainer> $rekeys = null, ): string { - $merged = varray[]; + $merged = vec[]; $existing = $this->extractManualCode($existing_code); $generated = $this->iterateCodeSections($this->code); foreach ($generated as $section) { @@ -110,7 +110,7 @@ final class PartiallyGeneratedCode { * Extract the generated code and returns it as a string. */ public function extractGeneratedCode(): string { - $generated = varray[]; + $generated = vec[]; foreach ($this->iterateCodeSections($this->code) as $section) { list($id, $chunk) = $section; if ($id === null) { @@ -146,18 +146,20 @@ final class PartiallyGeneratedCode { $seen_ids = keyset[]; $current_id = null; - $chunk = varray[]; + $chunk = vec[]; $lines = \explode("\n", $code); foreach ($lines as $line) { if (\strpos($line, self::$manualEnd) !== false) { yield tuple($current_id, Str\join($chunk, "\n")); - $chunk = varray[$line]; + $chunk = vec[$line]; $current_id = null; } else if (\preg_match($begin, $line) === 1) { if ($current_id !== null) { throw new PartiallyGeneratedCodeException( - 'The manual section '.$current_id.' was open before '. + 'The manual section '. + $current_id. + ' was open before '. 'the previous one was closed', ); } @@ -168,7 +170,7 @@ final class PartiallyGeneratedCode { $chunk[] = $line; yield tuple(null, Str\join($chunk, "\n")); - $chunk = varray[]; + $chunk = vec[]; $current_id = \trim(\preg_replace($begin, '\\1', $line)); if (C\contains($seen_ids, $current_id)) { diff --git a/src/key-value-render/HackBuilderValues.hack b/src/key-value-render/HackBuilderValues.hack index 5ce7c033..80c30154 100644 --- a/src/key-value-render/HackBuilderValues.hack +++ b/src/key-value-render/HackBuilderValues.hack @@ -49,7 +49,7 @@ abstract final class HackBuilderValues { /** Render a `vec`-like PHP array literal */ public static function valueArray( IHackBuilderValueRenderer $vr, - ): IHackBuilderValueRenderer> { + ): IHackBuilderValueRenderer> { return new _Private\HackBuilderNativeValueCollectionRenderer( ContainerType::PHP_ARRAY, $vr, @@ -60,7 +60,7 @@ abstract final class HackBuilderValues { public static function keyValueArray( IHackBuilderKeyRenderer $kr, IHackBuilderValueRenderer $vr, - ): IHackBuilderValueRenderer> { + ): IHackBuilderValueRenderer> { return new _Private\HackBuilderNativeKeyValueCollectionRenderer( ContainerType::PHP_ARRAY, $kr, diff --git a/tests/HackBuilderTest.hack b/tests/HackBuilderTest.hack index b83f6e87..24270434 100644 --- a/tests/HackBuilderTest.hack +++ b/tests/HackBuilderTest.hack @@ -63,19 +63,23 @@ final class HackBuilderTest extends CodegenBaseTest { expect_with_context(static::class, $body->getCode())->toBeUnchanged(); $body = $this->getHackBuilder()->addDocBlock($comment, /* max len */ 50); - expect_with_context(static::class, $body->getCode())->toBeUnchanged('docblock2'); + expect_with_context(static::class, $body->getCode())->toBeUnchanged( + 'docblock2', + ); } public function testAsValue(): void { - $dict = $this->getHackBuilder()->addValue( - dict[ - 'foo' => 'bar', - ], - HackBuilderValues::dict( - HackBuilderKeys::export(), - HackBuilderValues::literal(), - ), - )->getCode(); + $dict = $this->getHackBuilder() + ->addValue( + dict[ + 'foo' => 'bar', + ], + HackBuilderValues::dict( + HackBuilderKeys::export(), + HackBuilderValues::literal(), + ), + ) + ->getCode(); expect_with_context(static::class, $dict)->toBeUnchanged(); } @@ -106,7 +110,7 @@ final class HackBuilderTest extends CodegenBaseTest { $shape = $this ->getHackBuilder() ->addValue( - shape('herp' => 'derp', 'foo' => Vector { 'foo', 'bar', 'baz' }), + shape('herp' => 'derp', 'foo' => Vector {'foo', 'bar', 'baz'}), HackBuilderValues::shapeWithPerKeyRendering( shape( 'herp' => HackBuilderValues::export(), @@ -119,7 +123,8 @@ final class HackBuilderTest extends CodegenBaseTest { } public function testWrappedStringSingle(): void { - expect_with_context(static::class, + expect_with_context( + static::class, $this ->getHackBuilder() ->add('return ') @@ -130,12 +135,15 @@ final class HackBuilderTest extends CodegenBaseTest { } public function testWrappedStringDouble(): void { - expect_with_context(static::class, + expect_with_context( + static::class, $this ->getHackBuilder() ->add('return ') - ->addWrappedString('This is a bit longer so we will hit our max '. - 'length cap and then go ahead and finish the line.') + ->addWrappedString( + 'This is a bit longer so we will hit our max '. + 'length cap and then go ahead and finish the line.', + ) ->add(';') ->getCode(), )->toBeUnchanged(); @@ -146,7 +154,8 @@ final class HackBuilderTest extends CodegenBaseTest { two line breaks. Also note that we include a newline and also '. 'do a concat operation to really mix it up. We need to respect newlines with this code and also senseless indentation.'; - expect_with_context(static::class, + expect_with_context( + static::class, $this ->getHackBuilder() ->add('return ') @@ -174,7 +183,8 @@ two line breaks. Also note that we include a newline and also '. } public function testWrappedStringDoNotIndent(): void { - expect_with_context(static::class, + expect_with_context( + static::class, $this ->getHackBuilder() ->add('$this->callMethod(') @@ -197,7 +207,7 @@ two line breaks. Also note that we include a newline and also '. $set = $this ->getHackBuilder() ->addValue( - Set { 'apple', 'oreos', 'banana' }, + Set {'apple', 'oreos', 'banana'}, HackBuilderValues::set(HackBuilderValues::export()), ); @@ -209,7 +219,10 @@ two line breaks. Also note that we include a newline and also '. $body = $this ->getHackBuilder() ->addWithSuggestedLineBreaks( - 'final class'.$del.'ClassNameJustLongEnoughToAvoidEightyColumns'.$del. + 'final class'. + $del. + 'ClassNameJustLongEnoughToAvoidEightyColumns'. + $del. 'extends SomeBaseClass', ); expect_with_context(static::class, $body->getCode())->toBeUnchanged(); @@ -220,8 +233,11 @@ two line breaks. Also note that we include a newline and also '. $body = $this ->getHackBuilder() ->addWithSuggestedLineBreaks( - 'final abstract class'.$del.'ImpossibleClassLongEnoughToCrossEightyColumns'. -$del.'extends SomeBaseClass', + 'final abstract class'. + $del. + 'ImpossibleClassLongEnoughToCrossEightyColumns'. + $del. + 'extends SomeBaseClass', ); expect_with_context(static::class, $body->getCode())->toBeUnchanged(); } @@ -239,11 +255,16 @@ $del.'extends SomeBaseClass', $body = $this ->getHackBuilder() ->addMultilineCall( - "\$foobarbaz_alphabetagama =".$del."\$this->callSomeThingReallyLongName". + "\$foobarbaz_alphabetagama =". + $del. + "\$this->callSomeThingReallyLongName". 'ReallyReallyLongName', Vector { '$someSmallParameter', - "\$foobarbaz_alphabetagama +".$del."\$foobarbaz_alphabetagamaa +".$del. + "\$foobarbaz_alphabetagama +". + $del. + "\$foobarbaz_alphabetagamaa +". + $del. "\$foobarbaz_alphabetagamatheta_foobarbaz", }, ); @@ -274,7 +295,7 @@ $del.'extends SomeBaseClass', ->startIfBlock('$do_that') ->add('return ') ->addValue( - varray[1, 2, 3], + vec[1, 2, 3], HackBuilderValues::valueArray(HackBuilderValues::export()), ) ->closeStatement() @@ -286,9 +307,9 @@ $del.'extends SomeBaseClass', public function testSwitchBodyWithReturnsInCaseAndDefault(): void { // Gosh, I have no idea what names of football shots are! $players = Vector { - darray['name' => 'Ronaldo', 'favorite_shot' => 'freeKick'], - darray['name' => 'Messi', 'favorite_shot' => 'slideKick'], - darray['name' => 'Maradona', 'favorite_shot' => 'handOfGod'], + dict['name' => 'Ronaldo', 'favorite_shot' => 'freeKick'], + dict['name' => 'Messi', 'favorite_shot' => 'slideKick'], + dict['name' => 'Maradona', 'favorite_shot' => 'handOfGod'], }; $body = $this @@ -313,9 +334,9 @@ $del.'extends SomeBaseClass', public function testSwitchBodyWithBreaksInCaseAndDefault(): void { // Gosh, I have no idea what names of football shots are! $players = Vector { - darray['name' => 'Ronaldo', 'favorite_shot' => 'freeKick'], - darray['name' => 'Messi', 'favorite_shot' => 'slideKick'], - darray['name' => 'Maradona', 'favorite_shot' => 'handOfGod'], + dict['name' => 'Ronaldo', 'favorite_shot' => 'freeKick'], + dict['name' => 'Messi', 'favorite_shot' => 'slideKick'], + dict['name' => 'Maradona', 'favorite_shot' => 'handOfGod'], }; $body = $this @@ -340,9 +361,9 @@ $del.'extends SomeBaseClass', public function testSwitchBodyWithMultipleCasesWithoutBreaks(): void { // Gosh, I have no idea what names of football shots are! $players = Vector { - darray['name' => 'Ronaldo', 'favorite_shot' => 'freeKick'], - darray['name' => 'Messi', 'favorite_shot' => 'slideKick'], - darray['name' => 'Maradona', 'favorite_shot' => 'handOfGod'], + dict['name' => 'Ronaldo', 'favorite_shot' => 'freeKick'], + dict['name' => 'Messi', 'favorite_shot' => 'slideKick'], + dict['name' => 'Maradona', 'favorite_shot' => 'handOfGod'], }; $body = $this @@ -369,7 +390,7 @@ $del.'extends SomeBaseClass', ->getHackBuilder() ->add('$foo = ') ->addValue( - Vector { 1, 2, 3 }, + Vector {1, 2, 3}, HackBuilderValues::vector(HackBuilderValues::export()), ) ->getCode(); @@ -383,7 +404,7 @@ $del.'extends SomeBaseClass', ->getHackBuilder() ->addAssignment( '$foo', - Vector { Vector { '$foo', '$bar' }, Vector { '$herp', '$derp' } }, + Vector {Vector {'$foo', '$bar'}, Vector {'$herp', '$derp'}}, HackBuilderValues::vector( HackBuilderValues::vector(HackBuilderValues::export()), ), @@ -396,7 +417,7 @@ $del.'extends SomeBaseClass', ->getHackBuilder() ->addAssignment( '$foo', - Vector { Vector { '$foo', '$bar' }, Vector { '$herp', '$derp' } }, + Vector {Vector {'$foo', '$bar'}, Vector {'$herp', '$derp'}}, HackBuilderValues::vector( HackBuilderValues::vector(HackBuilderValues::literal()), ), @@ -409,7 +430,7 @@ $del.'extends SomeBaseClass', ->getHackBuilder() ->addAssignment( '$foo', - Vector { Map { 'foo' => 'bar' }, Map { 'herp' => 'derp' } }, + Vector {Map {'foo' => 'bar'}, Map {'herp' => 'derp'}}, HackBuilderValues::vector( HackBuilderValues::map( HackBuilderKeys::export(), @@ -425,9 +446,9 @@ $del.'extends SomeBaseClass', ->getHackBuilder() ->addAssignment( '$foo', - ImmVector { ImmVector { 'abc', 'def' }, ImmVector { 'ghi', 'jkl' } }, + ImmVector {ImmVector {'abc', 'def'}, ImmVector {'ghi', 'jkl'}}, HackBuilderValues::immVector( - HackBuilderValues::immVector(HackBuilderValues::export()) + HackBuilderValues::immVector(HackBuilderValues::export()), ), ); expect_with_context(static::class, $body->getCode())->toBeUnchanged(); @@ -439,8 +460,8 @@ $del.'extends SomeBaseClass', ->addAssignment( '$foo', ImmMap { - 'foo' => ImmMap { 'a' => 12, 'b' => 34 }, - 'bar' => ImmMap { 'c' => 45 }, + 'foo' => ImmMap {'a' => 12, 'b' => 34}, + 'bar' => ImmMap {'c' => 45}, }, HackBuilderValues::immMap( HackBuilderKeys::export(), @@ -458,7 +479,7 @@ $del.'extends SomeBaseClass', ->getHackBuilder() ->addAssignment( '$foo', - ImmSet { 'abc', 'def' }, + ImmSet {'abc', 'def'}, HackBuilderValues::immSet(HackBuilderValues::export()), ); expect_with_context(static::class, $body->getCode())->toBeUnchanged(); @@ -470,9 +491,7 @@ $del.'extends SomeBaseClass', ->addAssignment( '$foo', vec['foo', 'bar'], - HackBuilderValues::vec( - HackBuilderValues::export() - ) + HackBuilderValues::vec(HackBuilderValues::export()), ); expect_with_context(static::class, $body->getCode())->toBeUnchanged(); } @@ -483,9 +502,7 @@ $del.'extends SomeBaseClass', ->addAssignment( '$foo', keyset['foo', 'bar'], - HackBuilderValues::keyset( - HackBuilderValues::export() - ) + HackBuilderValues::keyset(HackBuilderValues::export()), ); expect_with_context(static::class, $body->getCode())->toBeUnchanged(); } @@ -499,7 +516,7 @@ $del.'extends SomeBaseClass', HackBuilderValues::dict( HackBuilderKeys::export(), HackBuilderValues::export(), - ) + ), ); expect_with_context(static::class, $body->getCode())->toBeUnchanged(); } @@ -508,7 +525,7 @@ $del.'extends SomeBaseClass', $body = $this ->getHackBuilder() ->addValue( - Map { self::class => \stdClass::class }, + Map {self::class => \stdClass::class}, HackBuilderValues::map( HackBuilderKeys::classname(), HackBuilderValues::classname(), @@ -521,7 +538,7 @@ $del.'extends SomeBaseClass', $body = $this ->getHackBuilder() ->addValue( - Map { 'foo' => 'bar' }, + Map {'foo' => 'bar'}, HackBuilderValues::map( HackBuilderKeys::lambda(($_config, $v) ==> "'key:".$v."'"), HackBuilderValues::lambda(($_config, $v) ==> "'value:".$v."'"), @@ -533,7 +550,7 @@ $del.'extends SomeBaseClass', final class TestAnotherCodegenConfig implements IHackCodegenConfig { public function getFileHeader(): ?Vector { - return Vector { 'Codegen Tests' }; + return Vector {'Codegen Tests'}; } public function getSpacesPerIndentation(): int {