diff --git a/src/CodegenFile.php b/src/CodegenFile.php index 6f6ae246..46816287 100644 --- a/src/CodegenFile.php +++ b/src/CodegenFile.php @@ -39,6 +39,8 @@ final class CodegenFile { private ?Map> $rekey = null; private bool $createOnly = false; private ?ICodegenFormatter $formatter; + private ?string $fileNamespace; + private Map $useNamespaces = Map {}; public function __construct( private IHackCodegenConfig $config, @@ -270,6 +272,15 @@ public function setDoClobber(bool $do_force): this { private function getContent(): string { $builder = hack_builder(); + $builder->addLineIf( + $this->fileNamespace !== null, + 'namespace %s;', + $this->fileNamespace, + ); + foreach ($this->useNamespaces as $ns => $as) { + $builder->addLine($as === null ? "use $ns;" : "use $ns as $as;"); + } + foreach ($this->beforeTypes as $type) { $builder->ensureNewLine()->newLine(); $builder->add($type->render()); @@ -330,6 +341,33 @@ public function setGeneratedFrom( return $this; } + public function setNamespace(string $file_namespace): this { + invariant($this->fileNamespace === null, 'namespace has already been set'); + $this->fileNamespace = $file_namespace; + return $this; + } + + public function useNamespace(string $ns, ?string $as = null): this { + invariant( + !$this->useNamespaces->contains($ns), + $ns.' is already being used', + ); + $this->useNamespaces[$ns] = $as; + return $this; + } + + public function useClass(string $ns, ?string $as = null): this { + return $this->useNamespace($ns, $as); + } + + public function useFunction(string $ns, ?string $as = null): this { + return $this->useNamespace('function '.$ns, $as); + } + + public function useConst(string $ns, ?string $as = null): this { + return $this->useNamespace('const '.$ns, $as); + } + /** * If called, save() will only write the file if it doesn't exist */ diff --git a/test/CodegenFileTestCase.codegen b/test/CodegenFileTestCase.codegen index 700d5143..58dea2c4 100644 --- a/test/CodegenFileTestCase.codegen +++ b/test/CodegenFileTestCase.codegen @@ -30,6 +30,23 @@ function fun(): int { return 0; } +!@#$%codegentest:testNamespace +> + */ +namespace MyNamespace; +use Another\Space; +use My\Space\Bar as bar; +use function My\Space\my_function as f; +use const My\Space\MAX_RETRIES; + +class Foo { +} + !@#$%codegentest:testNoSignature setNamespace('MyNamespace') + ->useNamespace('Another\Space') + ->useClass('My\Space\Bar', 'bar') + ->useFunction('My\Space\my_function', 'f') + ->useConst('My\Space\MAX_RETRIES') + ->addClass( + codegen_class('Foo') + ) + ->render(); + + self::assertUnchanged($code); + } + }