github carthage-software/mago 1.21.1
Mago 1.21.1

latest release: 1.22.0
16 hours ago

Mago 1.21.1

Mago 1.21.1 is a bug-fix release that cleans up five regressions introduced by the features shipped in 1.21.0. The string-style fixer no longer emits invalid PHP for chains that aren't rooted in a variable, the prefer-explode-over-preg-split fixer emits clean double-quoted escapes for separators containing control characters instead of splatting raw newlines or tabs into the source, the analyzer now expands generics like value-of<Enum> before comparing class-constant values and property defaults, the type parser accepts new as a class-constant name after :: despite the new new<T> type construct, and OSC 8 editor-URL hyperlinks on Windows drop the \\?\ verbatim prefix so terminal-to-editor links work again.

🐛 Bug Fixes

Linter

  • string-style fixer only interpolates chains rooted in a variable: Fixed the concat-to-interpolation auto-fix for the string-style rule to correctly reject chains that aren't rooted in a $variable. Previously, "Hello " . SomeEnum::World->value was rewritten to "Hello {SomeEnum::World->value}" which is invalid PHP, since interpolation braces only accept chains rooted in a variable. The check now recurses through property, null-safe property, array, method, and null-safe method accesses, returning true only when the chain's root is a variable (#1658)
  • prefer-explode-over-preg-split fixer emits proper escapes for control characters: When the extracted separator contains control bytes (\n, \t, \r, \x01, etc.), the fixer now emits a double-quoted PHP string with escape sequences instead of dropping raw control bytes into a single-quoted string. So preg_split("/\n\n/", $s) now becomes explode("\n\n", $s) instead of explode('<LF><LF>', $s) which split the call onto multiple lines. Non-ASCII bytes still use single quotes since their UTF-8 encoding round-trips verbatim (#1655)

Analyzer

  • Expand declared type before comparing constant values and property defaults: The invalid-constant-value and invalid-property-default-value checks introduced in 1.21.0 did not expand derived types like value-of<Enum> before comparing against the initializer's type, producing false positives on patterns such as /** @var array<value-of<Color>, int> */ const WEIGHTS = [Color::Red->value => 1, ...]. The declared type is now expanded (self/static, generics, templates, conditionals, class constants) before the subtype check runs. The parameter-default path was already correctly expanding (#1657)

Type Syntax

  • Allow new as a member-name identifier after ::: The new<T> type construct introduced in 1.21.0 made new a reserved keyword in the type grammar, which in turn broke class-constant and enum-case references like Action::NEW or Foo::new. The parser now treats new as an identifier in every post-:: context (plain, qualified, and fully-qualified class references; plus the array{Foo::NEW: int} shape-key pattern) when it isn't followed by <. Top-level new<T> still parses as the NewType construct unchanged (#1654)

Reporting

  • Strip Win32 verbatim prefix from OSC 8 editor-URL hyperlinks: On Windows, file paths surfaced to the terminal through OSC 8 editor hyperlinks (--editor-url) carried the \\?\ verbatim prefix that std::fs::canonicalize adds, which editors and file:// handlers don't accept. The prefix is now stripped before the path is templated into the URL — \\?\C:\… becomes C:\…, and \\?\UNC\server\share\… becomes \\server\share\…. Applies to both the rich and emacs formatters (#1659)

🙏 Thank You

Issue Reporters

Thank you to everyone who reported issues that shaped this release:

Full Changelog: 1.21.0...1.21.1

Don't miss a new mago release

NewReleases is sending notifications on new releases.