Grimoire provides project-specific linter rules and analyzer extensions for Mago.
composer require --dev phpinnacle/grimoireExtend the bundled Mago configuration from your project's mago.toml:
extends = "vendor/phpinnacle/grimoire/mago.toml"Relative configuration paths are resolved from the worker's working directory, which defaults to the directory containing mago.toml.
Create grimoire.json:
{
"rules": {
"class-member-order": [
{
"order": [
"trait-use:*",
"enum-case:*",
"public:constant:*",
"protected:constant:*",
"private:constant:*",
"public:static:property:*",
"protected:static:property:*",
"private:static:property:*",
"public:property:*",
"protected:property:*",
"private:property:*",
"method:__construct",
"public:static:method:*",
"public:method:*",
"protected:static:method:*",
"protected:method:*",
"private:static:method:*",
"private:method:*"
]
}
],
"class-method-order": [
{
"extends": "Illuminate\\Database\\Migrations\\Migration",
"order": [
"up",
"down",
"getConnection",
"public:static:*",
"public:*",
"protected:*",
"private:*"
]
}
],
"compact-empty-method-body": {
"method-pattern": "__construct"
}
}
}Orders trait uses, enum cases, constants, properties, and methods using the first matching configuration in the class-member-order array. The optional extends glob matches the resolved direct parent class; omit it to match every class-like declaration.
Selectors use the form [modifier:...:]type:name-pattern. Supported types are trait-use, enum-case, constant, property, and method. For example, public:static:property:cache* matches public static properties whose names begin with cache, while method:__construct matches constructors. A grouped property, constant, or trait-use declaration matches when any declared name matches. Members unmatched by any selector remain last in their original order. Comments and attributes move with their member.
Orders class methods using the first matching configuration in the class-method-order array. The optional extends glob matches the resolved direct parent class; omit it to match any class.
Selectors are evaluated from top to bottom. A bare selector is a method-name glob; prefixes require matching modifiers, so public:static:* matches every public static method. Methods unmatched by any selector remain last in their original order.
Requires empty method bodies to use compact braces ({}). Bodies containing comments are not considered empty.
By default, the rule applies to every method. Restrict it with the method-pattern glob in grimoire.json.
Apply the safe fixes with:
mago lint --fix --only phpinnacle/class-member-order,phpinnacle/class-method-order,phpinnacle/compact-empty-method-bodyDisallows return type declarations on anonymous functions and arrow functions, including static variants. Named functions and methods are unaffected. The rule is enabled by default and requires no configuration.
$callback = function (string $value) {
return trim($value);
};
$mapper = static fn (string $value) => trim($value);The automatic fix removes the return type declaration and preserves comments. It is classified as unsafe because removing a return type can change runtime behavior. Apply it with:
mago lint --fix --unsafe --format-after-fix --only phpinnacle/no-closure-return-typecomposer test