diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml
deleted file mode 100644
index bed9ebf5..00000000
--- a/.github/workflows/analysis.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-name: Psalm analysis
-
-on:
- push:
- branches:
- - master
- pull_request:
- branches:
- - master
-
-jobs:
- psalm:
- name: Psalm
- runs-on: ubuntu-latest
- steps:
- - name: Checkout code
- uses: actions/checkout@v2
-
- - name: Psalm
- uses: docker://vimeo/psalm-github-actions
\ No newline at end of file
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index bef8a5f7..c27349a5 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -1,4 +1,4 @@
-name: Lint and test
+name: Lint, analyse and test
on:
push:
@@ -13,12 +13,12 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- php: ['7.3', '7.4', '8.0']
+ php: ['7.3', '7.4', '8.0', '8.1']
name: PHP ${{ matrix.php }} tests
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@v3
- name: Install PHP
- uses: shivammathur/setup-php@1.3.7
+ uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
- name: Debugging
@@ -30,13 +30,31 @@ jobs:
run: composer install --prefer-dist --no-suggest --no-progress
- name: Run tests
run: vendor/bin/phpunit --printer mheap\\GithubActionsReporter\\Printer
+ analysis:
+ runs-on: ubuntu-latest
+ name: Analysis of code
+ steps:
+ - uses: actions/checkout@v3
+ - name: Install PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: '8.1'
+ - name: Debugging
+ run: |
+ php --version
+ php -m
+ composer --version
+ - name: Install dependencies
+ run: composer install --prefer-dist --no-suggest --no-progress
+ - name: Run validate
+ run: composer run analysis
lint:
runs-on: ubuntu-latest
- name: Lint project files
+ name: Lint all project files
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@v3
- name: Install PHP
- uses: shivammathur/setup-php@1.3.7
+ uses: shivammathur/setup-php@v2
with:
php-version: '7.4'
- name: Debugging
diff --git a/composer.json b/composer.json
index c97d2253..2b25de38 100644
--- a/composer.json
+++ b/composer.json
@@ -22,17 +22,30 @@
"CoenJacobs\\Mozart\\": "src/"
}
},
+ "config": {
+ "allow-plugins": {
+ "phpstan/extension-installer": true
+ }
+ },
"require-dev": {
"phpunit/phpunit": "^8.5",
"squizlabs/php_codesniffer": "^3.5",
"mheap/phpunit-github-actions-printer": "^1.4",
- "vimeo/psalm": "^4.4"
+ "phpstan/phpstan": "^1.8",
+ "phpstan/phpstan-deprecation-rules": "^1.0",
+ "phpstan/extension-installer": "^1.2"
},
"scripts": {
"lint": [
"composer validate",
"phpcs"
],
+ "analysis": [
+ "@analysis:phpstan"
+ ],
+ "analysis:phpstan": [
+ "./vendor/bin/phpstan --memory-limit=2G"
+ ],
"test": [
"phpunit"
]
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
new file mode 100644
index 00000000..eb0b0284
--- /dev/null
+++ b/phpstan-baseline.neon
@@ -0,0 +1,211 @@
+parameters:
+ ignoreErrors:
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\Autoloader\\:\\:getSearchNamespace\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: src/Composer/Autoload/Autoloader.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\Autoloader\\:\\:processConfig\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: src/Composer/Autoload/Autoloader.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\Autoloader\\:\\:processConfig\\(\\) has parameter \\$autoloadConfig with no type specified\\.$#"
+ count: 1
+ path: src/Composer/Autoload/Autoloader.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\Classmap\\:\\:processConfig\\(\\) has parameter \\$autoloadConfig with no type specified\\.$#"
+ count: 1
+ path: src/Composer/Autoload/Classmap.php
+
+ -
+ message: "#^Property CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\Classmap\\:\\:\\$files type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: src/Composer/Autoload/Classmap.php
+
+ -
+ message: "#^Property CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\Classmap\\:\\:\\$paths type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: src/Composer/Autoload/Classmap.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\NamespaceAutoloader\\:\\:processConfig\\(\\) has parameter \\$autoloadConfig with no type specified\\.$#"
+ count: 1
+ path: src/Composer/Autoload/NamespaceAutoloader.php
+
+ -
+ message: "#^PHPDoc tag @var has invalid value \\(\\)\\: Unexpected token \"\\*/\", expected type at offset 9$#"
+ count: 1
+ path: src/Composer/Package.php
+
+ -
+ message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#"
+ count: 1
+ path: src/Composer/Package.php
+
+ -
+ message: "#^Property CoenJacobs\\\\Mozart\\\\Composer\\\\Package\\:\\:\\$config has no type specified\\.$#"
+ count: 1
+ path: src/Composer/Package.php
+
+ -
+ message: "#^Property CoenJacobs\\\\Mozart\\\\Composer\\\\Package\\:\\:\\$dependencies type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: src/Composer/Package.php
+
+ -
+ message: "#^Access to an undefined property object\\:\\:\\$dep_namespace\\.$#"
+ count: 2
+ path: src/Console/Commands/Compose.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:getAllDependenciesOfPackage\\(\\) has parameter \\$dependencies with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: src/Console/Commands/Compose.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:getAllDependenciesOfPackage\\(\\) return type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: src/Console/Commands/Compose.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:movePackage\\(\\) has parameter \\$package with no type specified\\.$#"
+ count: 1
+ path: src/Console/Commands/Compose.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:movePackages\\(\\) has parameter \\$packages with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: src/Console/Commands/Compose.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:replacePackage\\(\\) has parameter \\$package with no type specified\\.$#"
+ count: 1
+ path: src/Console/Commands/Compose.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:replacePackages\\(\\) has parameter \\$packages with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: src/Console/Commands/Compose.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:replaceParentInTree\\(\\) has parameter \\$packages with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: src/Console/Commands/Compose.php
+
+ -
+ message: "#^PHPDoc tag @var has invalid value \\(\\)\\: Unexpected token \"\\*/\", expected type at offset 9$#"
+ count: 1
+ path: src/Console/Commands/Compose.php
+
+ -
+ message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#"
+ count: 2
+ path: src/Console/Commands/Compose.php
+
+ -
+ message: "#^Property CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:\\$config has no type specified\\.$#"
+ count: 1
+ path: src/Console/Commands/Compose.php
+
+ -
+ message: "#^Property CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:\\$workingDir \\(string\\) does not accept string\\|false\\.$#"
+ count: 1
+ path: src/Console/Commands/Compose.php
+
+ -
+ message: "#^Access to an undefined property CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\Autoloader\\:\\:\\$namespace\\.$#"
+ count: 1
+ path: src/Mover.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Mover\\:\\:__construct\\(\\) has parameter \\$config with no type specified\\.$#"
+ count: 1
+ path: src/Mover.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Mover\\:\\:__construct\\(\\) has parameter \\$workingDir with no type specified\\.$#"
+ count: 1
+ path: src/Mover.php
+
+ -
+ message: "#^Property CoenJacobs\\\\Mozart\\\\Mover\\:\\:\\$movedPackages type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: src/Mover.php
+
+ -
+ message: "#^Anonymous function has an unused use \\$contents\\.$#"
+ count: 1
+ path: src/Replace/ClassmapReplacer.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Replace\\\\ClassmapReplacer\\:\\:replace\\(\\) should return string but returns string\\|null\\.$#"
+ count: 1
+ path: src/Replace/ClassmapReplacer.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Replace\\\\ClassmapReplacer\\:\\:saveReplacedClass\\(\\) has parameter \\$classname with no type specified\\.$#"
+ count: 1
+ path: src/Replace/ClassmapReplacer.php
+
+ -
+ message: "#^Strict comparison using \\=\\=\\= between false and non\\-falsy\\-string will always evaluate to false\\.$#"
+ count: 1
+ path: src/Replace/ClassmapReplacer.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Replace\\\\NamespaceReplacer\\:\\:replace\\(\\) should return string but returns string\\|null\\.$#"
+ count: 1
+ path: src/Replace/NamespaceReplacer.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Replace\\\\Replacer\\:\\:replace\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: src/Replace/Replacer.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Replace\\\\Replacer\\:\\:replace\\(\\) has parameter \\$contents with no type specified\\.$#"
+ count: 1
+ path: src/Replace/Replacer.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Replace\\\\Replacer\\:\\:setAutoloader\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: src/Replace/Replacer.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Replacer\\:\\:__construct\\(\\) has parameter \\$config with no type specified\\.$#"
+ count: 1
+ path: src/Replacer.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Replacer\\:\\:__construct\\(\\) has parameter \\$workingDir with no type specified\\.$#"
+ count: 1
+ path: src/Replacer.php
+
+ -
+ message: "#^Method CoenJacobs\\\\Mozart\\\\Replacer\\:\\:replaceInFile\\(\\) has parameter \\$targetFile with no type specified\\.$#"
+ count: 1
+ path: src/Replacer.php
+
+ -
+ message: "#^Parameter \\#2 \\$contents of method League\\\\Flysystem\\\\Filesystem\\:\\:put\\(\\) expects string, string\\|null given\\.$#"
+ count: 1
+ path: src/Replacer.php
+
+ -
+ message: "#^Parameter \\#3 \\$subject of function preg_replace_callback expects array\\|string, string\\|null given\\.$#"
+ count: 1
+ path: src/Replacer.php
+
+ -
+ message: "#^Property CoenJacobs\\\\Mozart\\\\Replacer\\:\\:\\$replacedClasses type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: src/Replacer.php
+
+ -
+ message: "#^Strict comparison using \\=\\=\\= between false and non\\-falsy\\-string will always evaluate to false\\.$#"
+ count: 2
+ path: src/Replacer.php
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
new file mode 100644
index 00000000..dcc32dd4
--- /dev/null
+++ b/phpstan.neon.dist
@@ -0,0 +1,8 @@
+includes:
+ - phpstan-baseline.neon
+
+parameters:
+ level: 8
+ reportUnmatchedIgnoredErrors: false
+ paths:
+ - ./src
diff --git a/psalm.xml b/psalm.xml
deleted file mode 100644
index 30258a70..00000000
--- a/psalm.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php
index c0971f78..a832cf11 100644
--- a/src/Console/Commands/Compose.php
+++ b/src/Console/Commands/Compose.php
@@ -160,8 +160,6 @@ public function replacePackage($package): void
* @param ((int|string)|mixed)[] $slugs
*
* @return Package[]
- *
- * @psalm-return array
*/
private function findPackages(array $slugs): array
{
diff --git a/tests/replacers/ClassmapReplacerIntegrationTest.php b/tests/replacers/ClassmapReplacerIntegrationTest.php
deleted file mode 100644
index 4ff6a566..00000000
--- a/tests/replacers/ClassmapReplacerIntegrationTest.php
+++ /dev/null
@@ -1,137 +0,0 @@
-testsWorkingDir = __DIR__ . '/temptestdir';
- if (!file_exists($this->testsWorkingDir)) {
- mkdir($this->testsWorkingDir);
- }
-
- $mozart_config = new class() {
- public $dep_namespace = "Mozart";
- public $classmap_prefix = "Mozart_";
- public $dep_directory = "/dep_directory/";
- public $classmap_directory = "/classmap_directory/";
-
- };
-
- $composer = new class() {
- public $repositories = array();
- public $require = array();
- public $minimum_stability = "dev";
- public $extra;
- };
-
- $composer->extra = new class() {
- public $mozart;
- };
-
- $composer->extra->mozart = $mozart_config;
-
- $this->composer = $composer;
- }
-
- /**
- * Issue #93 shows a classname being updated inside a class whose namespace has also been updated
- * by Mozart.
- *
- * This is caused by the same files being loaded by both a PSR-4 autolaoder and classmap autoloader.
- * @see https://github.com/katzgrau/KLogger/blob/de2d3ab6777a393a9879e0496ebb8e0644066e3f/composer.json#L24-L29
- */
- public function test_it_does_not_make_classname_replacement_inside_namespaced_file()
- {
-
- $composer = $this->composer;
-
- $composer->repositories[] = new class() {
- public $url = "https://github.com/BrianHenryIE/bh-wp-logger";
- public $type = "git";
- };
-
- $composer->require["brianhenryie/wp-logger"] = "dev-master#dd2bb0665e01e11b282178e76a2334198d3860c5";
-
- $composer_json_string = json_encode($composer);
- $composer_json_string = str_replace('minimum_stability', 'minimum-stability', $composer_json_string);
-
- file_put_contents($this->testsWorkingDir . '/composer.json', $composer_json_string);
-
- chdir($this->testsWorkingDir);
-
- exec('composer update');
-
- $inputInterfaceMock = $this->createMock(InputInterface::class);
- $outputInterfaceMock = $this->createMock(OutputInterface::class);
-
- $mozartCompose = new Compose();
-
- $mozartCompose->run($inputInterfaceMock, $outputInterfaceMock);
-
- $php_string = file_get_contents($this->testsWorkingDir .'/dep_directory/BrianHenryIE/WP_Logger/class-logger.php');
-
- // Confirm problem is gone.
- $this->assertStringNotContainsString('class Mozart_Logger extends', $php_string);
-
- // Confirm solution is correct.
- $this->assertStringContainsString('class Logger extends', $php_string);
- }
-
-
- /**
- * Delete $this->testsWorkingDir after each test.
- *
- * @see https://stackoverflow.com/questions/3349753/delete-directory-with-files-in-it
- */
- public function tearDown(): void
- {
- parent::tearDown();
-
- $dir = $this->testsWorkingDir;
-
- $it = new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS);
- $files = new RecursiveIteratorIterator(
- $it,
- RecursiveIteratorIterator::CHILD_FIRST
- );
- foreach ($files as $file) {
- if ($file->isDir()) {
- rmdir($file->getRealPath());
- } else {
- unlink($file->getRealPath());
- }
- }
- rmdir($dir);
- }
-}
diff --git a/tests/replacers/NamespaceReplacerIntegrationTest.php b/tests/replacers/NamespaceReplacerIntegrationTest.php
deleted file mode 100644
index 80bc04a3..00000000
--- a/tests/replacers/NamespaceReplacerIntegrationTest.php
+++ /dev/null
@@ -1,131 +0,0 @@
-testsWorkingDir = __DIR__ . '/temptestdir';
- if (!file_exists($this->testsWorkingDir)) {
- mkdir($this->testsWorkingDir);
- }
-
- $mozart_config = new class() {
- public $dep_namespace = "Mozart";
- public $classmap_prefix = "Mozart_";
- public $dep_directory = "/dep_directory/";
- public $classmap_directory = "/classmap_directory/";
-
- };
-
- $composer = new class() {
- public $require = array();
- public $extra;
- };
-
- $composer->extra = new class() {
- public $mozart;
- };
-
- $composer->extra->mozart = $mozart_config;
-
- $this->composer = $composer;
- }
-
- /**
- * After PR #84, running Mozart on Mpdf began prefixing the class name inside the namespaced file.
- *
- * The problem coming from the filename matching the namespace name?
- *
- * dev-master#5d8041fdefc94ff57edcbe83ab468a9988c4fc11
- *
- * @see https://github.com/coenjacobs/mozart/pull/84/files
- *
- * Should be: "class Mpdf implements" because its namespace has already been prefixed.
- */
- public function test_it_does_not_make_classname_replacement_inside_namespaced_file()
- {
-
- $composer = $this->composer;
-
- $composer->require["mpdf/mpdf"] = "8.0.10";
-
- file_put_contents($this->testsWorkingDir . '/composer.json', json_encode($composer));
-
- chdir($this->testsWorkingDir);
-
- exec('composer update');
-
- $inputInterfaceMock = $this->createMock(InputInterface::class);
- $outputInterfaceMock = $this->createMock(OutputInterface::class);
-
- $mozartCompose = new Compose();
-
- $mozartCompose->run($inputInterfaceMock, $outputInterfaceMock);
-
- $mpdf_php = file_get_contents($this->testsWorkingDir .'/dep_directory/Mpdf/Mpdf.php');
-
- // Confirm problem is gone.
- $this->assertStringNotContainsString('class Mozart\Mpdf implements', $mpdf_php);
-
- // Confirm solution is correct.
- $this->assertStringContainsString('class Mpdf implements', $mpdf_php);
- }
-
-
- /**
- * Delete $this->testsWorkingDir after each test.
- *
- * @see https://stackoverflow.com/questions/3349753/delete-directory-with-files-in-it
- */
- public function tearDown(): void
- {
- parent::tearDown();
-
- $dir = $this->testsWorkingDir;
-
- $it = new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS);
- $files = new RecursiveIteratorIterator(
- $it,
- RecursiveIteratorIterator::CHILD_FIRST
- );
- foreach ($files as $file) {
- if ($file->isDir()) {
- rmdir($file->getRealPath());
- } else {
- unlink($file->getRealPath());
- }
- }
- rmdir($dir);
- }
-}