Skip to content

Conversation

BrianHenryIE
Copy link
Owner

@BrianHenryIE BrianHenryIE commented Mar 26, 2025

  • Preprocesses each file before making replacements to expand relative namespaces to fqdn namespaces
  • Fixes issues with multiple namespaces in one file

Fix: #154

Copy link

github-actions bot commented Mar 26, 2025

strauss.phar.zip @ 5270a18

@BrianHenryIE
Copy link
Owner Author

Please test @simon-skooster

@simon-skooster
Copy link

OK, so that change seems to have addressed the problem with implements. I think a similar strategy is now needed for instances of use, and for type declarations, and qualified references.

In \Latte\Loaders\FileLoader, the following errors remain...

namespace StraussLatte\Latte\Loaders;

use StraussLatte\Latte;

/**
 * Template loader.
 */
class FileLoader implements Latte\Loader
{
	use StraussLatte\Latte\Strict; // <-- Undefined type 'StraussLatte\Latte\Loaders\StraussLatte\Latte\Strict'.

and...

	public function getContent($fileName): string
	{
		$file = $this->baseDir . $fileName;
		if ($this->baseDir && !StraussLatte\Latte\Helpers::startsWith($this->normalizePath($file), $this->baseDir)) {
		//                     ^--Undefined type 'StraussLatte\Latte\Loaders\StraussLatte\Latte\Helpers'.

In \Latte\Macros\BlockMacros, there is an example of an error with a type declaration...

namespace StraussLatte\Latte\Macros;

use StraussLatte\Latte;
use StraussLatte\Latte\CompileException;
use StraussLatte\Latte\Helpers;
use StraussLatte\Latte\MacroNode;
use StraussLatte\Latte\PhpHelpers;
use StraussLatte\Latte\PhpWriter;
use StraussLatte\Latte\Runtime\Block;
use StraussLatte\Latte\Runtime\SnippetDriver;
use StraussLatte\Latte\Runtime\Template;

/**
 * Block macros.
 */
class BlockMacros extends MacroSet
{
	// ...
	public static function install(StraussLatte\Latte\Compiler $compiler): void
	//                             ^-- Undefined type 'StraussLatte\Latte\Macros\StraussLatte\Latte\Compiler'.

I fear I've opened a can of worms for you.

@BrianHenryIE
Copy link
Owner Author

Try this again, please. Now, it's using php-parser to expand relative namespaces to become fully qualified namespaces before it performs replacements.

@BrianHenryIE BrianHenryIE changed the title Fix: replaces relative namespaces in implements statements Fix: relative namespaces Mar 27, 2025
@simon-skooster
Copy link

That appears to have worked. All namespace-related errors in Latte\Loaders\FileLoader are gone (as are those in StringLoader.

The type declaration error I mentioned in \Latte\Macros\BlockMacros is still an issue. In that same file, there is also a reference to Latte\Compiler::CONTEXT_HTML_ATTRIBUTE, which becomes StraussLatte\Latte\Compiler::CONTEXT_HTML_ATTRIBUTE, and then expands to StraussLatte\Latte\Macros\StraussLatte\Latte\Compiler.

The replacements resulting in those errors weren't strictly needed due to a use StraussLatte\Latte statement at the top of the file. Perhaps all replacements should be absolute.

@simon-skooster
Copy link

I have found a couple more issues in Latte's src/compatibility.php. I suspect these are unrelated to this issue, and so might be best handled separately.

In that file, there are two namespace blocks, but only the second is prefixed by Strauss. So...

namespace Latte {
    // ...
}

namespace Latte\Runtime {
    // ...
}

...becomes...

namespace Latte {
    // ...
}

namespace StraussLatte\Latte\Runtime {
    // ...
}

Also (in that same file)...

	if (false) {
		/** @deprecated use Latte\Runtime\HtmlStringable */
		interface IHtmlString extends HtmlStringable
		{
		}
	} elseif (!interface_exists(IHtmlString::class)) {
		class_alias(HtmlStringable::class, IHtmlString::class);
	}

...becomes...

	if (false) {
		/** @deprecated use StraussLatte\Latte\Runtime\HtmlStringable */
		interface StraussLatte_IHtmlString extends HtmlStringable
		{
		}
	} elseif (!interface_exists(StraussLatte_IHtmlString::class)) {
		class_alias(HtmlStringable::class, StraussLatte_IHtmlString::class);
	}

The StraussLatte_ prefixes are not needed and break code that references \Latte\Runtime\IHtmlString.

@BrianHenryIE
Copy link
Owner Author

OK, there could still be more php-parser types that I need to check for relative namespaces but I think I've covered the ones you mentioned.

The two-namespaces-in-one-file issue is fixed too.

Give it a whirl and let me know if it's working now.

@simon-skooster
Copy link

The latest build no longer results in errors in any of the Loaders. It also correctly handles the contents of src/compatibility.php. In other words, all issues mentioned above appear to be fixed.

Looking further through the Latte code, I've found the following (likely more PHP-Parser node types to visit/track)...

namespace StraussLatte\Latte\Macros;

use StraussLatte\Latte;
use StraussLatte\Latte\CompileException;
use StraussLatte\Latte\MacroNode;
/**
 * Base Macro implementation. Allows add multiple macros.
 */
class MacroSet implements \StraussLatte\Latte\Macro
{
	/** @var StraussLatte\Latte\Compiler */ <-- Undefined type 
	private $compiler;
	// ...
	public function getCompiler(): StraussLatte\Latte\Compiler // <-- Undefined type 'StraussLatte\Latte\Macros\StraussLatte\Latte\Compiler'
	{
		return $this->compiler;
	}

In Latte\Runtime\Filters, an isset statement results in an error...

	if ($new === 'style' || $new === 'script' || isset(StraussLatte\Latte\Helpers::$emptyElements[strtolower($orig)]) !== isset(StraussLatte\Latte\Helpers::$emptyElements[$new])) {
	                                                // ^-- Undefined type
		throw new \StraussLatte\Latte\RuntimeException("Forbidden tag <{$orig}> change to <{$new}>.");
	}

Finally, in Latte\Tools\Linter, there are a couple of errors. For some reason, a type declaration is missing a leading backslash, despite other having one. Also, a catch type declaration is also missing a leading backslash...

namespace StraussLatte\Latte\Tools;

use StraussLatte\Latte;
use Nette;
final class Linter
{
	use \StraussLatte\Latte\Strict;
	// ....
	public function __construct(?StraussLatte\Latte\Engine $engine = null, bool $debug = false)
	                          // ^-- Undefined type
	{
	// ....
	public function lintLatte(string $file): bool
	{
		try {
			$code = $this->engine->compile($s);
		} catch (StraussLatte\Latte\CompileException $e) { // <-- Undefined type

I wonder if many of these prefixings could be avoided by fixing/adding use statements. Would that leave only fully-qualified namespace references in need of prefixing?

Thank you for responding so quickly to these issues.

@BrianHenryIE
Copy link
Owner Author

BrianHenryIE commented Mar 29, 2025

ok, all known issues should be fixed. There's probably more cases still! Just report them as you encounter them.

I did notice in src/Tools/Linter.php#L93

if (substr($s, 0, 3) === "\xEF\xBB\xBF") {

those special characters were returned different by PHP-Parser. I'm not sure if that's a problem or another valid representation of the characters.

Edit:

This issue/PR has covered a few interesting edge cases. I had an idea for better testing – to take the top packages on Packagist, run Strauss against them, then run their unit tests. If the tests fail after but not before, it should uncover many shortcomings of Strauss, and eventually prove its reliability. There are two open issues (#112, #153) right now that basically can't be done with the current regex approach, so until Strauss's Prefixer is properly rewritten to use php-parser, I won't implement this. But I thought I'd share, as this PR has help familiarise me with php-parser, thank you.

@simon-skooster
Copy link

I was just about to comment that I could no longer find any Strauss-related errors in the Latte code when I checked Latte\Bridges\Tracy\BlueScreenPanel, where I found this...

namespace StraussLatte\Latte\Bridges\Tracy;

use StraussLatte\Latte;
use Tracy;
use Tracy\BlueScreen;
use Tracy\Helpers;

/**
 * BlueScreen panels for Tracy 2.x
 */
class BlueScreenPanel
{
	// ...
	public static function renderError(?\Throwable $e): ?array
	{
		if ($e instanceof StraussLatte\Latte\CompileException && $e->sourceName) {
		//                ^-- Undefined type 'StraussLatte\Latte\Bridges\Tracy\StraussLatte\Latte\CompileException'

All of the other issues I've reported above appear to have been fixed.

Regarding testing, in addition to running the unit tests of certain popular/large packages, I'd suggest considering using a linter to produce before and after results, which could then be compared (to some extent). That might be quicker/cheaper than running unit test.

Thanks for all your work on Strauss. I hope to be able to contribute more than just bug reports in the future.

@simon-skooster
Copy link

Good news! I can no longer find any Strauss-related errors in the processed Latte source code. This PR looks good to me.

@BrianHenryIE BrianHenryIE merged commit c720d03 into master Apr 11, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Strauss, Latte, and relative namespaces
2 participants