1: <?php
2:
3: declare(strict_types=1);
4:
5: /**
6: * This file is part of the Nexus framework.
7: *
8: * (c) John Paul E. Balandan, CPA <paulbalandan@gmail.com>
9: *
10: * For the full copyright and license information, please view
11: * the LICENSE file that was distributed with this source code.
12: */
13:
14: namespace Nexus\PHPStan\Rules\Functions;
15:
16: use PhpParser\Node;
17: use PHPStan\Analyser\Scope;
18: use PHPStan\Rules\Rule;
19: use PHPStan\Rules\RuleErrorBuilder;
20: use PHPStan\ShouldNotHappenException;
21:
22: /**
23: * @implements Rule<Node\Stmt\Function_>
24: */
25: final class FunctionNamingRule implements Rule
26: {
27: public function getNodeType(): string
28: {
29: return Node\Stmt\Function_::class;
30: }
31:
32: public function processNode(Node $node, Scope $scope): array
33: {
34: if (null === $node->namespacedName) {
35: throw new ShouldNotHappenException(); // @codeCoverageIgnore
36: }
37:
38: $functionName = $node->namespacedName->toString();
39:
40: if (! str_starts_with($functionName, 'Nexus\\')) {
41: return [
42: RuleErrorBuilder::message(\sprintf(
43: 'Function %s() should be namespaced using the "Nexus\\" namespace.',
44: $functionName,
45: ))
46: ->identifier('nexus.functionNamespace')
47: ->build(),
48: ];
49: }
50:
51: $basename = basename(str_replace('\\', '/', $functionName));
52:
53: if (preg_match('/^[a-z][a-z0-9_]+$/', $basename) !== 1) {
54: return [
55: RuleErrorBuilder::message(\sprintf(
56: 'Function %s() should be in lower snake case format.',
57: $functionName,
58: ))
59: ->identifier('nexus.functionCasing')
60: ->build(),
61: ];
62: }
63:
64: $errors = [];
65:
66: foreach (array_values($node->params) as $index => $param) {
67: if (! $param->var instanceof Node\Expr\Variable) {
68: continue; // @codeCoverageIgnore
69: }
70:
71: if (! \is_string($param->var->name)) {
72: continue; // @codeCoverageIgnore
73: }
74:
75: if (preg_match('/^[a-z][a-zA-Z0-9]*$/', $param->var->name) !== 1) {
76: $errors[] = RuleErrorBuilder::message(\sprintf(
77: 'Parameter #%d $%s of function %s() should be in camelCase format.',
78: $index + 1,
79: $param->var->name,
80: $functionName,
81: ))
82: ->identifier('nexus.functionParamCasing')
83: ->line($param->getStartLine())
84: ->build()
85: ;
86: }
87: }
88:
89: return $errors;
90: }
91: }
92: