Skip to content

Commit 1326d19

Browse files
committed
Implement getRequiredFunctionCalls check and use it in filter plugin validation.
This address scenario where file is supposed to contain certain function call, such as `class_alias` in Filter plugin type backward compatibility support per https://moodledev.io/docs/4.5/devupdate#filter-plugins The patch makes possible for deleveloper to specify: * getRequiredFunctionCalls to make sure file contains function call as name suggests. * FileTokens::notFoundHint to give some context for requirement to improve developer experience. This works with FileTokens in any other validation methods.
1 parent 8b2d4c3 commit 1326d19

File tree

13 files changed

+208
-0
lines changed

13 files changed

+208
-0
lines changed

.php-cs-fixer.cache

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

.phpunit.result.cache

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

docs/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,14 @@ This project adheres to [Semantic Versioning](https://semver.org/).
99
The format of this change log follows the advice given at [Keep a CHANGELOG](https://keepachangelog.com).
1010

1111
## [Unreleased]
12+
### Added
13+
- Improvements to plugin validation implementation:
14+
`getRequiredFunctionCalls` in plugin type specific `Requirements` class can be used to validate that file contains function call.
15+
`FileTokens::notFoundHint` can be used to give some context for validation error to improve developer experience.
16+
1217
### Fixed
1318
- Fixed stylelinting error in non-theme plugins containing scss.
19+
- Updated filter plugin validation requirements to comply with Moodle 4.5
1420

1521
### Removed
1622
- Stylelint less component task (`grunt stylelint:less`) has been deprecated in

src/Parser/StatementFilter.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414

1515
use PhpParser\Node\Expr\Array_;
1616
use PhpParser\Node\Expr\Assign;
17+
use PhpParser\Node\Expr\FuncCall;
1718
use PhpParser\Node\Expr\PropertyFetch;
1819
use PhpParser\Node\Expr\Variable;
1920
use PhpParser\Node\Identifier;
21+
use PhpParser\Node\Name;
2022
use PhpParser\Node\Scalar\String_;
2123
use PhpParser\Node\Stmt;
2224
use PhpParser\Node\Stmt\Class_;
@@ -116,6 +118,26 @@ public function filterAssignments(array $statements): array
116118
return $assigns;
117119
}
118120

121+
/**
122+
* Extract all the function call expressions from the statements.
123+
*
124+
* @param Stmt[] $statements
125+
*
126+
* @return FuncCall[]
127+
*/
128+
public function filterFunctionCalls(array $statements): array
129+
{
130+
$calls = [];
131+
foreach ($statements as $statement) {
132+
// Only expressions that are function calls.
133+
if ($statement instanceof Expression && $statement->expr instanceof FuncCall) {
134+
$calls[] = $statement->expr;
135+
}
136+
}
137+
138+
return $calls;
139+
}
140+
119141
/**
120142
* Find first variable assignment with a given name.
121143
*

src/PluginValidate/Finder/FileTokens.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ class FileTokens
2929
*/
3030
public string $file;
3131

32+
/**
33+
* Not found error hint.
34+
*
35+
* @var string
36+
*/
37+
public string $hint = '';
38+
3239
/**
3340
* @param string $file
3441
*/
@@ -59,6 +66,16 @@ public function hasTokens(): bool
5966
return !empty($this->tokens);
6067
}
6168

69+
/**
70+
* Do we have any hint?
71+
*
72+
* @return bool
73+
*/
74+
public function hasHint(): bool
75+
{
76+
return !empty($this->hint);
77+
}
78+
6279
/**
6380
* @param Token $token
6481
*
@@ -166,4 +183,18 @@ public function resetTokens(): void
166183
$token->reset();
167184
}
168185
}
186+
187+
/**
188+
* Not found error additional information guiding user how to fix it (optional).
189+
*
190+
* @param string $hint
191+
*
192+
* @return self
193+
*/
194+
public function notFoundHint(string $hint): self
195+
{
196+
$this->hint = $hint;
197+
198+
return $this;
199+
}
169200
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Moodle Plugin CI package.
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*
9+
* Copyright (c) 2024 Moodle Pty Ltd <[email protected]>
10+
* License http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
11+
*/
12+
13+
namespace MoodlePluginCI\PluginValidate\Finder;
14+
15+
use PhpParser\Node\Name;
16+
17+
/**
18+
* Finds function call.
19+
*/
20+
class FunctionCallFinder extends AbstractParserFinder
21+
{
22+
public function getType(): string
23+
{
24+
return 'function call';
25+
}
26+
27+
public function findTokens($file, FileTokens $fileTokens): void
28+
{
29+
$statements = $this->parser->parseFile($file);
30+
31+
foreach ($this->filter->filterFunctionCalls($statements) as $funccall) {
32+
if ($funccall->name instanceof Name) {
33+
$fileTokens->compare((string) $funccall->name);
34+
}
35+
}
36+
}
37+
}

src/PluginValidate/PluginValidate.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use MoodlePluginCI\PluginValidate\Finder\ClassFinder;
1818
use MoodlePluginCI\PluginValidate\Finder\FileTokens;
1919
use MoodlePluginCI\PluginValidate\Finder\FinderInterface;
20+
use MoodlePluginCI\PluginValidate\Finder\FunctionCallFinder;
2021
use MoodlePluginCI\PluginValidate\Finder\FunctionFinder;
2122
use MoodlePluginCI\PluginValidate\Finder\LangFinder;
2223
use MoodlePluginCI\PluginValidate\Finder\TableFinder;
@@ -98,6 +99,9 @@ public function addMessagesFromTokens(string $type, FileTokens $fileTokens): voi
9899
$this->addSuccess(sprintf('In %s, found %s %s', $fileTokens->file, $type, implode(' OR ', $token->tokens)));
99100
} else {
100101
$this->addError(sprintf('In %s, failed to find %s %s', $fileTokens->file, $type, implode(' OR ', $token->tokens)));
102+
if ($fileTokens->hasHint()) {
103+
$this->addError(sprintf('Hint: %s', $fileTokens->hint));
104+
}
101105
}
102106
}
103107
}
@@ -115,6 +119,7 @@ public function verifyRequirements(): void
115119
$this->findRequiredTokens(new TableFinder(), [$this->requirements->getRequiredTables()]);
116120
$this->findRequiredTokens(new TablePrefixFinder(), [$this->requirements->getRequiredTablePrefix()]);
117121
$this->findRequiredTokens(new BehatTagFinder(), $this->requirements->getRequiredBehatTags());
122+
$this->findRequiredTokens(new FunctionCallFinder(), $this->requirements->getRequiredFunctionCalls());
118123
}
119124

120125
/**

src/PluginValidate/Requirements/AbstractRequirements.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ protected function fileExists(string $file): bool
7676
return file_exists($this->plugin->directory . '/' . $file);
7777
}
7878

79+
/**
80+
* Required function calls.
81+
*
82+
* @return FileTokens[]
83+
*/
84+
abstract public function getRequiredFunctionCalls(): array;
85+
7986
/**
8087
* An array of required files, paths are relative to the plugin directory.
8188
*

src/PluginValidate/Requirements/FilterRequirements.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,15 @@ public function getRequiredStrings(): FileTokens
5050
{
5151
return FileTokens::create($this->getLangFile())->mustHave('filtername');
5252
}
53+
54+
public function getRequiredFunctionCalls(): array
55+
{
56+
if ($this->moodleVersion <= 404 && !$this->fileExists('classes/text_filter.php')) {
57+
return [];
58+
}
59+
60+
return [
61+
FileTokens::create('filter.php')->mustHave('class_alias')->notFoundHint('https://moodledev.io/docs/4.5/devupdate#filter-plugins'),
62+
];
63+
}
5364
}

src/PluginValidate/Requirements/GenericRequirements.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ public function getRequiredClasses(): array
4646
return [];
4747
}
4848

49+
public function getRequiredFunctionCalls(): array
50+
{
51+
return [];
52+
}
53+
4954
public function getRequiredStrings(): FileTokens
5055
{
5156
return FileTokens::create($this->getLangFile())->mustHave('pluginname');

0 commit comments

Comments
 (0)