From 8bf40aad60593b91a71091f974d820ee202dad0a Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Fri, 18 Aug 2023 10:09:06 +0400
Subject: [PATCH 01/33] New package.
---
composer.json | 12 +++--
packages/documentator/CHANGELOG.md | 3 ++
packages/documentator/LICENSE | 21 ++++++++
packages/documentator/README.md | 7 +++
packages/documentator/composer.json | 48 +++++++++++++++++++
packages/documentator/metadata.json | 3 ++
packages/documentator/phpunit.xml | 29 +++++++++++
packages/documentator/src/Package.php | 7 +++
.../documentator/src/PackageException.php | 12 +++++
packages/documentator/src/Provider.php | 9 ++++
phpunit.xml | 5 ++
11 files changed, 152 insertions(+), 4 deletions(-)
create mode 100644 packages/documentator/CHANGELOG.md
create mode 100644 packages/documentator/LICENSE
create mode 100644 packages/documentator/README.md
create mode 100644 packages/documentator/composer.json
create mode 100644 packages/documentator/metadata.json
create mode 100644 packages/documentator/phpunit.xml
create mode 100644 packages/documentator/src/Package.php
create mode 100644 packages/documentator/src/PackageException.php
create mode 100644 packages/documentator/src/Provider.php
diff --git a/composer.json b/composer.json
index 638206fa4..6089e3244 100644
--- a/composer.json
+++ b/composer.json
@@ -100,7 +100,8 @@
"LastDragon_ru\\LaraASP\\Spa\\": "packages/spa/src/",
"LastDragon_ru\\LaraASP\\GraphQL\\": "packages/graphql/src/",
"LastDragon_ru\\LaraASP\\GraphQLPrinter\\": "packages/graphql-printer/src/",
- "LastDragon_ru\\LaraASP\\Serializer\\": "packages/serializer/src/"
+ "LastDragon_ru\\LaraASP\\Serializer\\": "packages/serializer/src/",
+ "LastDragon_ru\\LaraASP\\Documentator\\": "packages/documentator/src/"
},
"exclude-from-classmap": [
"packages/core/src/**Test.php",
@@ -112,7 +113,8 @@
"packages/spa/src/**Test.php",
"packages/graphql/src/**Test.php",
"packages/graphql-printer/src/**Test.php",
- "packages/serializer/src/**Test.php"
+ "packages/serializer/src/**Test.php",
+ "packages/documentator/src/**Test.php"
]
},
"autoload-dev": {
@@ -128,7 +130,8 @@
"LastDragon_ru\\LaraASP\\Spa\\Provider",
"LastDragon_ru\\LaraASP\\GraphQL\\Provider",
"LastDragon_ru\\LaraASP\\Queue\\Provider",
- "LastDragon_ru\\LaraASP\\Serializer\\Provider"
+ "LastDragon_ru\\LaraASP\\Serializer\\Provider",
+ "LastDragon_ru\\LaraASP\\Documentator\\Provider"
]
}
},
@@ -178,6 +181,7 @@
"lastdragon-ru/lara-asp-spa": "self.version",
"lastdragon-ru/lara-asp-graphql": "self.version",
"lastdragon-ru/lara-asp-graphql-printer": "self.version",
- "lastdragon-ru/lara-asp-serializer": "self.version"
+ "lastdragon-ru/lara-asp-serializer": "self.version",
+ "lastdragon-ru/lara-asp-documentator": "self.version"
}
}
diff --git a/packages/documentator/CHANGELOG.md b/packages/documentator/CHANGELOG.md
new file mode 100644
index 000000000..8a5f44710
--- /dev/null
+++ b/packages/documentator/CHANGELOG.md
@@ -0,0 +1,3 @@
+# Changelog
+
+Please see [Releases](https://github.com/LastDragon-ru/lara-asp/releases).
diff --git a/packages/documentator/LICENSE b/packages/documentator/LICENSE
new file mode 100644
index 000000000..e970b27ef
--- /dev/null
+++ b/packages/documentator/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Aleksei Lebedev
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/documentator/README.md b/packages/documentator/README.md
new file mode 100644
index 000000000..29dd8798c
--- /dev/null
+++ b/packages/documentator/README.md
@@ -0,0 +1,7 @@
+# The Documentator
+
+> This package is the part of Awesome Set of Packages for Laravel.
+>
+> [Read more](https://github.com/LastDragon-ru/lara-asp).
+
+This package provides various utilities for documentation generation.
diff --git a/packages/documentator/composer.json b/packages/documentator/composer.json
new file mode 100644
index 000000000..7aa5444af
--- /dev/null
+++ b/packages/documentator/composer.json
@@ -0,0 +1,48 @@
+{
+ "name": "lastdragon-ru/lara-asp-documentator",
+ "homepage": "https://github.com/LastDragon-ru/lara-asp",
+ "description": "The Awesome Set of Packages for Laravel - The Documentator.",
+ "readme": "README.md",
+ "license": "MIT",
+ "type": "library",
+ "keywords": [
+ "documetation",
+ "utils",
+ "laravel-package",
+ "laravel",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/LastDragon-ru/lara-asp/issues",
+ "source": "https://github.com/LastDragon-ru/lara-asp",
+ "forum": "https://github.com/LastDragon-ru/lara-asp/discussions"
+ },
+ "require": {
+ "php": "^8.1|^8.2",
+ "laravel/framework": "^9.21.0|^10.0.0"
+ },
+ "require-dev": {
+ "lastdragon-ru/lara-asp-testing": "self.version",
+ "orchestra/testbench": "^7.0.0|^8.0.0",
+ "phpunit/phpunit": "^9.5.0|^10.1.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "LastDragon_ru\\LaraASP\\Documentator\\": "src/"
+ },
+ "exclude-from-classmap": [
+ "src/**Test.php"
+ ]
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "LastDragon_ru\\LaraASP\\Documentator\\Provider"
+ ]
+ }
+ },
+ "config": {
+ "sort-packages": true,
+ "optimize-autoloader": true
+ }
+}
diff --git a/packages/documentator/metadata.json b/packages/documentator/metadata.json
new file mode 100644
index 000000000..1be1b18fe
--- /dev/null
+++ b/packages/documentator/metadata.json
@@ -0,0 +1,3 @@
+{
+ "version": "0.0.0"
+}
diff --git a/packages/documentator/phpunit.xml b/packages/documentator/phpunit.xml
new file mode 100644
index 000000000..34fd5cfb9
--- /dev/null
+++ b/packages/documentator/phpunit.xml
@@ -0,0 +1,29 @@
+
+
+
+
+ ./src
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/documentator/src/Package.php b/packages/documentator/src/Package.php
new file mode 100644
index 000000000..a3e040924
--- /dev/null
+++ b/packages/documentator/src/Package.php
@@ -0,0 +1,7 @@
+
./packages/serializer/src
+
+ ./packages/documentator/src
+
From 89d4d696673870ca765a6f6ae68b1d19d2119e60 Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Fri, 18 Aug 2023 10:10:28 +0400
Subject: [PATCH 02/33] PHPUnit: test suit names fix.
---
phpunit.xml | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/phpunit.xml b/phpunit.xml
index b0e41dd5d..55f87ad78 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -6,37 +6,37 @@
executionOrder="random"
colors="true">
-
+
./packages/core/src
-
+
./packages/migrator/src
-
+
./packages/queue/src
-
+
./packages/testing/src
-
+
./packages/eloquent/src
-
+
./packages/formatter/src
-
+
./packages/spa/src
-
+
./packages/graphql/src
-
+
./packages/graphql-printer/src
-
+
./packages/serializer/src
-
+
./packages/documentator/src
From 1aabea095e5cc3ab27329030c5d8b502a859ca2c Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Fri, 18 Aug 2023 10:46:40 +0400
Subject: [PATCH 03/33] Minimal setup to run `artisan`.
---
.gitignore | 2 +
artisan | 38 ++++++++++++
config/app.php | 162 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 202 insertions(+)
create mode 100755 artisan
create mode 100644 config/app.php
diff --git a/.gitignore b/.gitignore
index 68e5d56fa..457e35ad5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,3 +28,5 @@ Thumbs.db
# Project
composer.lock
Vagrant.yml
+bootstrap
+storage
diff --git a/artisan b/artisan
new file mode 100755
index 000000000..8ba7a81ed
--- /dev/null
+++ b/artisan
@@ -0,0 +1,38 @@
+#!/usr/bin/env php
+singleton(
+ ConsoleKernelContract::class,
+ ConsoleKernel::class,
+);
+$app->singleton(
+ ExceptionHandlerContract::class,
+ ExceptionHandler::class
+);
+
+// Run
+$input = new ArgvInput();
+$kernel = $app->make(ConsoleKernelContract::class);
+$status = $kernel->handle($input, new ConsoleOutput());
+
+// Shutdown
+$kernel->terminate($input, $status);
+
+exit($status);
diff --git a/config/app.php b/config/app.php
new file mode 100644
index 000000000..10dc6eb49
--- /dev/null
+++ b/config/app.php
@@ -0,0 +1,162 @@
+ env('APP_NAME', 'LaraAsp'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Application Environment
+ |--------------------------------------------------------------------------
+ |
+ | This value determines the "environment" your application is currently
+ | running in. This may determine how you prefer to configure various
+ | services the application utilizes. Set this in your ".env" file.
+ |
+ */
+ 'env' => env('APP_ENV', 'production'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Application Debug Mode
+ |--------------------------------------------------------------------------
+ |
+ | When your application is in debug mode, detailed error messages with
+ | stack traces will be shown on every error that occurs within your
+ | application. If disabled, a simple generic error page is shown.
+ |
+ */
+ 'debug' => (bool) env('APP_DEBUG', false),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Application URL
+ |--------------------------------------------------------------------------
+ |
+ | This URL is used by the console to properly generate URLs when using
+ | the Artisan command line tool. You should set this to the root of
+ | your application so that it is used when running Artisan tasks.
+ |
+ */
+ 'url' => env('APP_URL', 'http://localhost'),
+ 'asset_url' => env('ASSET_URL'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Application Timezone
+ |--------------------------------------------------------------------------
+ |
+ | Here you may specify the default timezone for your application, which
+ | will be used by the PHP date and date-time functions. We have gone
+ | ahead and set this to a sensible default for you out of the box.
+ |
+ */
+ 'timezone' => 'UTC',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Application Locale Configuration
+ |--------------------------------------------------------------------------
+ |
+ | The application locale determines the default locale that will be used
+ | by the translation service provider. You are free to set this value
+ | to any of the locales which will be supported by the application.
+ |
+ */
+ 'locale' => 'en',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Application Fallback Locale
+ |--------------------------------------------------------------------------
+ |
+ | The fallback locale determines the locale to use when the current one
+ | is not available. You may change the value to correspond to any of
+ | the language folders that are provided through your application.
+ |
+ */
+ 'fallback_locale' => 'en',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Faker Locale
+ |--------------------------------------------------------------------------
+ |
+ | This locale will be used by the Faker PHP library when generating fake
+ | data for your database seeds. For example, this will be used to get
+ | localized telephone numbers, street address information and more.
+ |
+ */
+ 'faker_locale' => 'en_US',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Encryption Key
+ |--------------------------------------------------------------------------
+ |
+ | This key is used by the Illuminate encrypter service and should be set
+ | to a random, 32 character string, otherwise these encrypted strings
+ | will not be safe. Please do this before deploying an application!
+ |
+ */
+ 'key' => env('APP_KEY'),
+ 'cipher' => 'AES-256-CBC',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Maintenance Mode Driver
+ |--------------------------------------------------------------------------
+ |
+ | These configuration options determine the driver used to determine and
+ | manage Laravel's "maintenance mode" status. The "cache" driver will
+ | allow maintenance mode to be controlled across multiple machines.
+ |
+ | Supported drivers: "file", "cache"
+ |
+ */
+ 'maintenance' => [
+ 'driver' => 'file',
+ // 'store' => 'redis',
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Autoloaded Service Providers
+ |--------------------------------------------------------------------------
+ |
+ | The service providers listed here will be automatically loaded on the
+ | request to your application. Feel free to add your own services to
+ | this array to grant expanded functionality to your applications.
+ |
+ */
+ 'providers' => ServiceProvider::defaultProviders()->merge([
+ DocumentatorProvider::class,
+ ])->toArray(),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Class Aliases
+ |--------------------------------------------------------------------------
+ |
+ | This array of class aliases will be registered when this application
+ | is started. However, feel free to register as many as you wish as
+ | the aliases are "lazy" loaded so they don't hinder performance.
+ |
+ */
+ 'aliases' => Facade::defaultAliases()->merge([
+ // 'Example' => App\Facades\Example::class,
+ ])->toArray(),
+];
From 0df24b5dbb9d5063aeb78e4e4492cd608c7257bb Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Fri, 18 Aug 2023 13:08:29 +0400
Subject: [PATCH 04/33] ci: version will be dumped into root `metadata.json`
too.
---
.release-it/config.js | 2 +-
metadata.json | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
create mode 100644 metadata.json
diff --git a/.release-it/config.js b/.release-it/config.js
index 8e0f2ec32..c4f155f61 100644
--- a/.release-it/config.js
+++ b/.release-it/config.js
@@ -146,7 +146,7 @@ module.exports = {
plugins: {
'@release-it/bumper': {
out: {
- file: 'packages/*/metadata.json',
+ file: ['metadata.json', 'packages/*/metadata.json'],
},
},
'@release-it/conventional-changelog': {
diff --git a/metadata.json b/metadata.json
new file mode 100644
index 000000000..4e2c1114d
--- /dev/null
+++ b/metadata.json
@@ -0,0 +1,3 @@
+{
+ "version": "0.15.0"
+}
From a86500c37878775c267b65fa68c2675860e7f6f3 Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Fri, 18 Aug 2023 18:26:36 +0400
Subject: [PATCH 05/33] `Version` helper.
---
packages/documentator/composer.json | 2 +
.../src/Testing/Package/TestCase.php | 20 ++++++
packages/documentator/src/Utils/Version.php | 63 +++++++++++++++++++
.../documentator/src/Utils/VersionTest.php | 40 ++++++++++++
4 files changed, 125 insertions(+)
create mode 100644 packages/documentator/src/Testing/Package/TestCase.php
create mode 100644 packages/documentator/src/Utils/Version.php
create mode 100644 packages/documentator/src/Utils/VersionTest.php
diff --git a/packages/documentator/composer.json b/packages/documentator/composer.json
index 7aa5444af..c9216ea98 100644
--- a/packages/documentator/composer.json
+++ b/packages/documentator/composer.json
@@ -19,6 +19,8 @@
},
"require": {
"php": "^8.1|^8.2",
+ "ext-mbstring": "*",
+ "composer/semver": "^3.2",
"laravel/framework": "^9.21.0|^10.0.0"
},
"require-dev": {
diff --git a/packages/documentator/src/Testing/Package/TestCase.php b/packages/documentator/src/Testing/Package/TestCase.php
new file mode 100644
index 000000000..413565e85
--- /dev/null
+++ b/packages/documentator/src/Testing/Package/TestCase.php
@@ -0,0 +1,20 @@
+0|[1-9]\d*)
+ \.
+ (?P0|[1-9]\d*)
+ \.
+ (?P0|[1-9]\d*)
+ (?:-(?P(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)
+ (?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*
+ ))?
+ (?:\+(?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
+ /x
+ SEMVER;
+
+ public static function isVersion(string $string): bool {
+ return static::isSemver($string)
+ || (str_starts_with($string, 'v') && static::isSemver(static::normalize($string)));
+ }
+
+ public static function isSemver(string $string): bool {
+ return (bool) preg_match(static::SEMVER, $string);
+ }
+
+ public static function compare(string $a, string $b): int {
+ $r = 0;
+
+ if ($a !== $b) {
+ $a = static::normalize($a);
+ $b = static::normalize($b);
+ $r = $a !== $b
+ ? (Comparator::greaterThan($a, $b) ? 1 : -1)
+ : 0;
+ }
+
+ return $r;
+ }
+
+ public static function normalize(string $version): string {
+ if (str_starts_with($version, 'v')) {
+ $version = mb_substr($version, 1);
+ } elseif (str_starts_with($version, 'dev-')) {
+ $version = '9999999-dev';
+ } else {
+ // empty
+ }
+
+ return $version;
+ }
+}
diff --git a/packages/documentator/src/Utils/VersionTest.php b/packages/documentator/src/Utils/VersionTest.php
new file mode 100644
index 000000000..652daf5c0
--- /dev/null
+++ b/packages/documentator/src/Utils/VersionTest.php
@@ -0,0 +1,40 @@
+
Date: Sat, 19 Aug 2023 09:07:16 +0400
Subject: [PATCH 06/33] `Process` & `Git` helpers.
---
composer.json | 1 +
packages/documentator/composer.json | 3 +-
packages/documentator/src/Utils/Git.php | 37 +++++++++++++++++++++
packages/documentator/src/Utils/Process.php | 29 ++++++++++++++++
4 files changed, 69 insertions(+), 1 deletion(-)
create mode 100644 packages/documentator/src/Utils/Git.php
create mode 100644 packages/documentator/src/Utils/Process.php
diff --git a/composer.json b/composer.json
index 6089e3244..4a0e268b8 100644
--- a/composer.json
+++ b/composer.json
@@ -55,6 +55,7 @@
"symfony/finder": "^6.3.0",
"symfony/http-foundation": "^6.3.0",
"symfony/mime": "^6.3.0",
+ "symfony/process": "^6.3.0",
"symfony/property-access": "^6.3.0",
"symfony/property-info": "^6.3.0",
"symfony/psr-http-message-bridge": "^2.0.0",
diff --git a/packages/documentator/composer.json b/packages/documentator/composer.json
index c9216ea98..7e6a724ae 100644
--- a/packages/documentator/composer.json
+++ b/packages/documentator/composer.json
@@ -21,7 +21,8 @@
"php": "^8.1|^8.2",
"ext-mbstring": "*",
"composer/semver": "^3.2",
- "laravel/framework": "^9.21.0|^10.0.0"
+ "laravel/framework": "^9.21.0|^10.0.0",
+ "symfony/process": "^6.3.0"
},
"require-dev": {
"lastdragon-ru/lara-asp-testing": "self.version",
diff --git a/packages/documentator/src/Utils/Git.php b/packages/documentator/src/Utils/Git.php
new file mode 100644
index 000000000..efa47592a
--- /dev/null
+++ b/packages/documentator/src/Utils/Git.php
@@ -0,0 +1,37 @@
+
+ */
+ public function getTags(callable $filter = null, string $root = null): array {
+ $tags = $this->process->run(['git', 'tag', '--list'], $root);
+ $tags = explode("\n", $tags);
+ $tags = $filter ? array_filter($tags, $filter) : $tags;
+ $tags = array_values($tags);
+
+ return $tags;
+ }
+
+ public function getFile(string $path, string $revision = 'HEAD', string $root = null): string {
+ return $this->process->run(['git', 'show', "{$revision}:{$path}"], $root);
+ }
+
+ public function getBranch(string $root = null): string {
+ return $this->process->run(['git', 'rev-parse', '--abbrev-ref=HEAD'], $root);
+ }
+}
diff --git a/packages/documentator/src/Utils/Process.php b/packages/documentator/src/Utils/Process.php
new file mode 100644
index 000000000..c41df8e0d
--- /dev/null
+++ b/packages/documentator/src/Utils/Process.php
@@ -0,0 +1,29 @@
+ $command
+ */
+ public function run(array $command, string $cwd = null): string {
+ $process = new SymfonyProcess($command, $cwd);
+
+ $process->run();
+
+ if (!$process->isSuccessful()) {
+ throw new ProcessFailedException($process);
+ }
+
+ return trim($process->getOutput());
+ }
+}
From d4b427cd2fb4e90858c3667e91ae0cc277a39959 Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Sat, 19 Aug 2023 09:16:00 +0400
Subject: [PATCH 07/33] Classes to cache metadata.
---
packages/documentator/composer.json | 3 +-
.../documentator/src/Metadata/Metadata.php | 20 +++++
.../documentator/src/Metadata/Storage.php | 80 +++++++++++++++++++
3 files changed, 102 insertions(+), 1 deletion(-)
create mode 100644 packages/documentator/src/Metadata/Metadata.php
create mode 100644 packages/documentator/src/Metadata/Storage.php
diff --git a/packages/documentator/composer.json b/packages/documentator/composer.json
index 7e6a724ae..707dbdd00 100644
--- a/packages/documentator/composer.json
+++ b/packages/documentator/composer.json
@@ -22,7 +22,8 @@
"ext-mbstring": "*",
"composer/semver": "^3.2",
"laravel/framework": "^9.21.0|^10.0.0",
- "symfony/process": "^6.3.0"
+ "symfony/process": "^6.3.0",
+ "lastdragon-ru/lara-asp-serializer": "self.version"
},
"require-dev": {
"lastdragon-ru/lara-asp-testing": "self.version",
diff --git a/packages/documentator/src/Metadata/Metadata.php b/packages/documentator/src/Metadata/Metadata.php
new file mode 100644
index 000000000..94749a09e
--- /dev/null
+++ b/packages/documentator/src/Metadata/Metadata.php
@@ -0,0 +1,20 @@
+>> $requirements
+ */
+ public function __construct(
+ public string $version = '0.0.0',
+ public array $requirements = [],
+ ) {
+ // empty
+ }
+}
diff --git a/packages/documentator/src/Metadata/Storage.php b/packages/documentator/src/Metadata/Storage.php
new file mode 100644
index 000000000..f3d738389
--- /dev/null
+++ b/packages/documentator/src/Metadata/Storage.php
@@ -0,0 +1,80 @@
+path}/metadata.json";
+ }
+
+ public function load(): Metadata {
+ $metadata = is_file($this->getPath()) ? file_get_contents($this->getPath()) : false;
+ $metadata = $metadata !== false
+ ? $this->serializer->deserialize(Metadata::class, $metadata, self::Format)
+ : new Metadata();
+
+ return $metadata;
+ }
+
+ public function save(Metadata $metadata): bool {
+ $metadata = $this->normalize($metadata);
+ $context = (new JsonEncoderContextBuilder())->withEncodeOptions(self::Options)->toArray();
+ $content = $this->serializer->serialize($metadata, self::Format, $context);
+ $result = file_put_contents($this->getPath(), $content) !== false;
+
+ return $result;
+ }
+
+ protected function normalize(Metadata $metadata): Metadata {
+ $comparator = static fn($a, $b) => -Version::compare($a, $b);
+
+ uksort($metadata->requirements, $comparator);
+
+ foreach ($metadata->requirements as &$requirement) {
+ uksort($requirement, strcmp(...));
+
+ foreach ($requirement as &$versions) {
+ usort($versions, $comparator);
+ }
+ }
+
+ return $metadata;
+ }
+}
From ed0d61d89f3fb5cf86eaaf19cefd463e7fd28061 Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Sat, 19 Aug 2023 11:48:24 +0400
Subject: [PATCH 08/33] Artisan app setup fix.
---
.gitignore | 1 -
config/view.php | 32 ++++++++++++++++++++++++++++++
storage/framework/views/.gitignore | 2 ++
storage/logs/.gitignore | 2 ++
4 files changed, 36 insertions(+), 1 deletion(-)
create mode 100644 config/view.php
create mode 100644 storage/framework/views/.gitignore
create mode 100644 storage/logs/.gitignore
diff --git a/.gitignore b/.gitignore
index 457e35ad5..b70ecd80f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,4 +29,3 @@ Thumbs.db
composer.lock
Vagrant.yml
bootstrap
-storage
diff --git a/config/view.php b/config/view.php
new file mode 100644
index 000000000..1143b9220
--- /dev/null
+++ b/config/view.php
@@ -0,0 +1,32 @@
+ [
+ resource_path('views'),
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Compiled View Path
+ |--------------------------------------------------------------------------
+ |
+ | This option determines where all the compiled Blade templates will be
+ | stored for your application. Typically, this is within the storage
+ | directory. However, as usual, you are free to change this value.
+ |
+ */
+ 'compiled' => env(
+ 'VIEW_COMPILED_PATH',
+ realpath(storage_path('framework/views')),
+ ),
+];
diff --git a/storage/framework/views/.gitignore b/storage/framework/views/.gitignore
new file mode 100644
index 000000000..d6b7ef32c
--- /dev/null
+++ b/storage/framework/views/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/storage/logs/.gitignore b/storage/logs/.gitignore
new file mode 100644
index 000000000..d6b7ef32c
--- /dev/null
+++ b/storage/logs/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
From 2842250b5f6b10c43cb8f30fd98931438dd36049 Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Sat, 19 Aug 2023 14:46:24 +0400
Subject: [PATCH 09/33] feat(documentator): Command
`lara-asp-documentator:requirements` to generate a table with the required
versions of PHP/Laravel in Markdown format.
---
config/app.php | 2 +
metadata.json | 414 +++++++++++++++++-
packages/documentator/composer.json | 1 +
.../views/requirements/markdown.blade.php | 15 +
.../src/Commands/Requirements.php | 208 +++++++++
.../src/Commands/RequirementsTest.json | 413 +++++++++++++++++
.../src/Commands/RequirementsTest.php | 102 +++++
.../documentator/src/Metadata/Storage.php | 1 +
packages/documentator/src/Provider.php | 15 +-
.../src/Testing/Package/TestCase.php | 2 +
packages/documentator/src/Utils/Version.php | 2 +-
phpcs.xml | 1 +
12 files changed, 1172 insertions(+), 4 deletions(-)
create mode 100644 packages/documentator/resources/views/requirements/markdown.blade.php
create mode 100644 packages/documentator/src/Commands/Requirements.php
create mode 100644 packages/documentator/src/Commands/RequirementsTest.json
create mode 100644 packages/documentator/src/Commands/RequirementsTest.php
diff --git a/config/app.php b/config/app.php
index 10dc6eb49..3db8236ad 100644
--- a/config/app.php
+++ b/config/app.php
@@ -3,6 +3,7 @@
use Illuminate\Support\Facades\Facade;
use Illuminate\Support\ServiceProvider;
use LastDragon_ru\LaraASP\Documentator\Provider as DocumentatorProvider;
+use LastDragon_ru\LaraASP\Serializer\Provider as SerializerProvider;
return [
/*
@@ -143,6 +144,7 @@
|
*/
'providers' => ServiceProvider::defaultProviders()->merge([
+ SerializerProvider::class,
DocumentatorProvider::class,
])->toArray(),
diff --git a/metadata.json b/metadata.json
index 4e2c1114d..8908753f7 100644
--- a/metadata.json
+++ b/metadata.json
@@ -1,3 +1,413 @@
{
- "version": "0.15.0"
-}
+ "version": "0.15.0",
+ "requirements": {
+ "HEAD": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1"
+ ]
+ },
+ "5.0.0-beta.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1"
+ ]
+ },
+ "4.5.2": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.5.1": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.5.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.4.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.3.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.2.1": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.2.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.1.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.0.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "3.0.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "2.1.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "2.0.3": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "2.0.2": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "2.0.1": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "2.0.0": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "1.1.2": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "1.1.1": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "1.1.0": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "1.0.4": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "1.0.3": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "1.0.2": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "1.0.1": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "1.0.0": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "0.15.0": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "0.14.1": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "0.14.0": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "0.13.0": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "0.12.0": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "0.11.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.10.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.9.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.8.1": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.8.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.7.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.6.1": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.6.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.5.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.4.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.3.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=7.4.0"
+ ]
+ },
+ "0.2.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=7.4.0"
+ ]
+ },
+ "0.1.0": {
+ "laravel/framework": [
+ "^8.0"
+ ],
+ "php": [
+ ">=7.4.0"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/documentator/composer.json b/packages/documentator/composer.json
index 707dbdd00..9659555cc 100644
--- a/packages/documentator/composer.json
+++ b/packages/documentator/composer.json
@@ -23,6 +23,7 @@
"composer/semver": "^3.2",
"laravel/framework": "^9.21.0|^10.0.0",
"symfony/process": "^6.3.0",
+ "lastdragon-ru/lara-asp-core": "self.version",
"lastdragon-ru/lara-asp-serializer": "self.version"
},
"require-dev": {
diff --git a/packages/documentator/resources/views/requirements/markdown.blade.php b/packages/documentator/resources/views/requirements/markdown.blade.php
new file mode 100644
index 000000000..861e6e892
--- /dev/null
+++ b/packages/documentator/resources/views/requirements/markdown.blade.php
@@ -0,0 +1,15 @@
+ $packages Package name (key) and title (value)
+ * @var array>> $requirements
+ */
+
+?>
+| Requirement | Constraint | Supported by |
+|--------------|---------------------|------------------|
+@foreach ($packages as $key => $title)
+@foreach ($requirements[$key] as $constraint => $versions)
+| @if ($loop->first) {{$title}} @endif | `{!!$constraint!!}` | @foreach($versions as $version) @if(is_string($version))`{{$version}}` @else `{{$version[0]}} ⋯ {{$version[1]}}` @endif @if (!$loop->last), @endif
+@endforeach |
+@endforeach
+@endforeach
diff --git a/packages/documentator/src/Commands/Requirements.php b/packages/documentator/src/Commands/Requirements.php
new file mode 100644
index 000000000..aedd8b4bf
--- /dev/null
+++ b/packages/documentator/src/Commands/Requirements.php
@@ -0,0 +1,208 @@
+argument('cwd') ?? getcwd());
+ $tags = $git->getTags(Version::isVersion(...), $cwd);
+ $tags[] = 'HEAD';
+
+ // Collect requirements
+ $storage = new Storage($serializer, $cwd);
+ $metadata = $storage->load();
+ $packages = [
+ 'php' => 'PHP',
+ 'laravel/framework' => 'Laravel',
+ ];
+
+ foreach ($tags as $tag) {
+ // Cached?
+ if ($tag !== 'HEAD' && array_keys($metadata->requirements[$tag] ?? []) === array_keys($packages)) {
+ continue;
+ }
+
+ // Load
+ $package = $this->getPackageInfo($git, $tag, $cwd);
+
+ if (!$package) {
+ continue;
+ }
+
+ // Update
+ $metadata->requirements[$tag] = [];
+
+ foreach ($packages as $key => $title) {
+ $metadata->requirements[$tag][$key] = explode('|', Cast::toString($package['require'][$key] ?? ''));
+ }
+ }
+
+ // Cleanup
+ $metadata->requirements = array_intersect_key(
+ $metadata->requirements,
+ array_fill_keys($tags, null),
+ );
+
+ // Save
+ $storage->save($metadata);
+
+ // Prepare
+ $requirements = $this->getRequirements($packages, $metadata);
+
+ // Render
+ $package = Package::Name;
+ $output = view("{$package}::requirements.markdown", [
+ 'packages' => $packages,
+ 'requirements' => $requirements,
+ ])->render();
+
+ $this->output->writeln($output);
+ }
+
+ /**
+ * @return array|null
+ */
+ protected function getPackageInfo(Git $git, string $tag, string $cwd): ?array {
+ try {
+ $package = $git->getFile('composer.json', $tag, $cwd);
+ $package = json_decode($package, true, flags: JSON_THROW_ON_ERROR);
+
+ assert(is_array($package));
+ } catch (Exception) {
+ $package = null;
+ }
+
+ return $package;
+ }
+
+ /**
+ * @param array $packages
+ *
+ * @return array>>
+ */
+ protected function getRequirements(array $packages, Metadata $metadata): array {
+ // Extract
+ $requirements = [];
+
+ foreach ($metadata->requirements as $versionName => $versionPackages) {
+ foreach ($versionPackages as $packageName => $packageVersions) {
+ foreach ($packageVersions as $packageVersion) {
+ $requirements[$packageName][$packageVersion] ??= [];
+ $requirements[$packageName][$packageVersion][] = $versionName;
+ }
+ }
+ }
+
+ // Sort
+ $priorities = array_combine(array_keys($packages), range(0, count($packages) - 1));
+
+ uksort($requirements, static function (string $a, string $b) use ($priorities): int {
+ return $priorities[$a] <=> $priorities[$b];
+ });
+
+ // Merge
+ $versions = array_keys($metadata->requirements);
+
+ foreach ($requirements as &$packageVersions) {
+ foreach ($packageVersions as &$versionNames) {
+ $versionNames = $this->getMergedVersions($versions, $versionNames);
+ }
+ }
+
+ // Return
+ return $requirements;
+ }
+
+ /**
+ * @param list $versions
+ * @param list $merge
+ *
+ * @return list
+ */
+ protected function getMergedVersions(array $versions, array $merge): array {
+ // Group
+ $ranges = [];
+ $current = [];
+
+ foreach ($merge as $key => $version) {
+ $index = array_search($version, $versions, true);
+ $nextMerge = $merge[$key + 1] ?? null;
+ $nextVersion = $index !== false ? ($versions[$index + 1] ?? null) : null;
+
+ $current[] = $version;
+
+ if ($nextMerge !== $nextVersion) {
+ $ranges[] = $current;
+ $current = [];
+ }
+ }
+
+ if ($current) {
+ $ranges[] = $current;
+ }
+
+ // Merge
+ $merged = [];
+
+ foreach ($ranges as $range) {
+ if (count($range) > 2) {
+ $merged[] = [reset($range), end($range)];
+ } elseif (count($range) === 2) {
+ $merged[] = reset($range);
+ $merged[] = end($range);
+ } else {
+ $merged[] = reset($range);
+ }
+ }
+
+ return $merged;
+ }
+}
diff --git a/packages/documentator/src/Commands/RequirementsTest.json b/packages/documentator/src/Commands/RequirementsTest.json
new file mode 100644
index 000000000..2a786e3b0
--- /dev/null
+++ b/packages/documentator/src/Commands/RequirementsTest.json
@@ -0,0 +1,413 @@
+{
+ "version": "0.15.0",
+ "requirements": {
+ "HEAD": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1"
+ ]
+ },
+ "5.0.0-beta.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1"
+ ]
+ },
+ "4.5.2": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.5.1": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.5.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.4.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.3.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.2.1": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.2.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.1.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "4.0.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "3.0.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "2.1.0": {
+ "laravel/framework": [
+ "^10.0.0",
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "2.0.3": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "2.0.2": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "2.0.1": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "2.0.0": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.2",
+ "^8.1",
+ "^8.0"
+ ]
+ },
+ "1.1.2": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "1.1.1": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "1.1.0": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "1.0.4": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "1.0.3": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "1.0.2": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "1.0.1": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "1.0.0": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "0.15.0": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "0.14.1": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "0.14.0": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "0.13.0": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "0.12.0": {
+ "laravel/framework": [
+ "^9.0.0",
+ "^8.22.1"
+ ],
+ "php": [
+ "^8.0.0"
+ ]
+ },
+ "0.11.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.10.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.9.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.8.1": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.8.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.7.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.6.1": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.6.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.5.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.4.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=8.0.0"
+ ]
+ },
+ "0.3.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=7.4.0"
+ ]
+ },
+ "0.2.0": {
+ "laravel/framework": [
+ "^8.22.1"
+ ],
+ "php": [
+ ">=7.4.0"
+ ]
+ },
+ "0.1.0": {
+ "laravel/framework": [
+ "^8.0"
+ ],
+ "php": [
+ ">=7.4.0"
+ ]
+ }
+ }
+}
diff --git a/packages/documentator/src/Commands/RequirementsTest.php b/packages/documentator/src/Commands/RequirementsTest.php
new file mode 100644
index 000000000..d65abfd45
--- /dev/null
+++ b/packages/documentator/src/Commands/RequirementsTest.php
@@ -0,0 +1,102 @@
+getMergedVersions($versions, $versions),
+ );
+ self::assertEquals(
+ [
+ '0.1.0',
+ ],
+ $command->getMergedVersions($versions, ['0.1.0']),
+ );
+ self::assertEquals(
+ [
+ '0.1.0',
+ '0.3.0-beta.1',
+ '1.1.0',
+ ],
+ $command->getMergedVersions($versions, ['0.1.0', '0.3.0-beta.1', '1.1.0']),
+ );
+ self::assertEquals(
+ [
+ ['0.1.0', '0.3.0-beta.0'],
+ '1.0.0',
+ '1.2.1-rc.0',
+ '1.2.1',
+ ],
+ $command->getMergedVersions($versions, ['0.1.0', '0.2.0', '0.3.0-beta.0', '1.0.0', '1.2.1-rc.0', '1.2.1']),
+ );
+ }
+
+ public function testGetRequirements(): void {
+ $metadata = self::getTestData()->content('.json');
+ $metadata = $this->app->make(Serializer::class)->deserialize(Metadata::class, $metadata);
+ $packages = [
+ 'laravel/framework' => 'Laravel',
+ 'php' => 'PHP',
+ ];
+ $command = new class() extends Requirements {
+ /**
+ * @inheritDoc
+ */
+ public function getRequirements(array $packages, Metadata $metadata): array {
+ return parent::getRequirements($packages, $metadata);
+ }
+ };
+
+ self::assertEquals(
+ [
+ 'laravel/framework' => [
+ '^10.0.0' => [['HEAD', '2.1.0']],
+ '^9.0.0' => [['HEAD', '0.12.0']],
+ '^8.22.1' => [['3.0.0', '0.2.0']],
+ '^8.0' => ['0.1.0'],
+ ],
+ 'php' => [
+ '^8.2' => [['HEAD', '2.0.0']],
+ '^8.1' => [['HEAD', '2.0.0']],
+ '^8.0' => [['4.5.2', '2.0.0']],
+ '^8.0.0' => [['1.1.2', '0.12.0']],
+ '>=8.0.0' => [['0.11.0', '0.4.0']],
+ '>=7.4.0' => [['0.3.0', '0.1.0']],
+ ],
+ ],
+ $command->getRequirements($packages, $metadata),
+ );
+ }
+}
diff --git a/packages/documentator/src/Metadata/Storage.php b/packages/documentator/src/Metadata/Storage.php
index f3d738389..655116c8f 100644
--- a/packages/documentator/src/Metadata/Storage.php
+++ b/packages/documentator/src/Metadata/Storage.php
@@ -9,6 +9,7 @@
use function file_get_contents;
use function file_put_contents;
use function is_file;
+use function strcmp;
use function uksort;
use function usort;
diff --git a/packages/documentator/src/Provider.php b/packages/documentator/src/Provider.php
index e4490b647..b748d29e8 100644
--- a/packages/documentator/src/Provider.php
+++ b/packages/documentator/src/Provider.php
@@ -3,7 +3,20 @@
namespace LastDragon_ru\LaraASP\Documentator;
use Illuminate\Support\ServiceProvider;
+use LastDragon_ru\LaraASP\Core\Concerns\ProviderWithViews;
+use LastDragon_ru\LaraASP\Documentator\Commands\Requirements;
class Provider extends ServiceProvider {
- // empty
+ use ProviderWithViews;
+
+ public function boot(): void {
+ $this->bootViews();
+ $this->commands(
+ Requirements::class,
+ );
+ }
+
+ protected function getName(): string {
+ return Package::Name;
+ }
}
diff --git a/packages/documentator/src/Testing/Package/TestCase.php b/packages/documentator/src/Testing/Package/TestCase.php
index 413565e85..c1e2d233b 100644
--- a/packages/documentator/src/Testing/Package/TestCase.php
+++ b/packages/documentator/src/Testing/Package/TestCase.php
@@ -3,6 +3,7 @@
namespace LastDragon_ru\LaraASP\Documentator\Testing\Package;
use LastDragon_ru\LaraASP\Documentator\Provider;
+use LastDragon_ru\LaraASP\Serializer\Provider as SerializerProvider;
use LastDragon_ru\LaraASP\Testing\Package\TestCase as PackageTestCase;
/**
@@ -15,6 +16,7 @@ class TestCase extends PackageTestCase {
protected function getPackageProviders(mixed $app): array {
return [
Provider::class,
+ SerializerProvider::class,
];
}
}
diff --git a/packages/documentator/src/Utils/Version.php b/packages/documentator/src/Utils/Version.php
index 4bbc36b92..74685c34d 100644
--- a/packages/documentator/src/Utils/Version.php
+++ b/packages/documentator/src/Utils/Version.php
@@ -52,7 +52,7 @@ public static function compare(string $a, string $b): int {
public static function normalize(string $version): string {
if (str_starts_with($version, 'v')) {
$version = mb_substr($version, 1);
- } elseif (str_starts_with($version, 'dev-')) {
+ } elseif ($version === 'HEAD' || str_starts_with($version, 'dev-')) {
$version = '9999999-dev';
} else {
// empty
diff --git a/phpcs.xml b/phpcs.xml
index 938c2321b..470c87b1b 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -5,6 +5,7 @@
Lara Asp coding standard, based on PSR12
./packages
+ *.blade.php
From 4e67b4adbf15f8b17dcaf9493a28e7d0d85d3c86 Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Mon, 21 Aug 2023 13:36:51 +0400
Subject: [PATCH 10/33] `Preprocessor`.
---
packages/documentator/composer.json | 1 +
.../Exceptions/PreprocessFailed.php | 9 ++
.../src/Preprocessor/Instruction.php | 9 ++
.../Instructions/IncludeCommand.php | 36 +++++
.../Instructions/IncludeCommandTest.php | 32 +++++
.../Instructions/IncludeExample.php | 97 +++++++++++++
.../Instructions/IncludeExampleTest.php | 108 +++++++++++++++
.../IncludeExampleTest~example.md | 3 +
.../IncludeExampleTest~runnable.md | 3 +
.../IncludeExampleTest~runnable.run | 1 +
.../Preprocessor/Instructions/IncludeFile.php | 36 +++++
.../Instructions/IncludeFileTest.md | 3 +
.../Instructions/IncludeFileTest.php | 33 +++++
.../src/Preprocessor/Preprocessor.php | 130 ++++++++++++++++++
.../src/Preprocessor/PreprocessorTest.php | 62 +++++++++
15 files changed, 563 insertions(+)
create mode 100644 packages/documentator/src/Preprocessor/Exceptions/PreprocessFailed.php
create mode 100644 packages/documentator/src/Preprocessor/Instruction.php
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeCommand.php
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeCommandTest.php
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest.php
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest~example.md
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest~runnable.md
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest~runnable.run
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeFile.php
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeFileTest.md
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeFileTest.php
create mode 100644 packages/documentator/src/Preprocessor/Preprocessor.php
create mode 100644 packages/documentator/src/Preprocessor/PreprocessorTest.php
diff --git a/packages/documentator/composer.json b/packages/documentator/composer.json
index 9659555cc..b26a2ff62 100644
--- a/packages/documentator/composer.json
+++ b/packages/documentator/composer.json
@@ -22,6 +22,7 @@
"ext-mbstring": "*",
"composer/semver": "^3.2",
"laravel/framework": "^9.21.0|^10.0.0",
+ "symfony/filesystem": "^6.3.0",
"symfony/process": "^6.3.0",
"lastdragon-ru/lara-asp-core": "self.version",
"lastdragon-ru/lara-asp-serializer": "self.version"
diff --git a/packages/documentator/src/Preprocessor/Exceptions/PreprocessFailed.php b/packages/documentator/src/Preprocessor/Exceptions/PreprocessFailed.php
new file mode 100644
index 000000000..3859397c7
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Exceptions/PreprocessFailed.php
@@ -0,0 +1,9 @@
+process->run([$target], $path);
+ } catch (Exception $exception) {
+ throw new PreprocessFailed(
+ sprintf(
+ 'Failed to execute command `%s`.',
+ $target,
+ ),
+ $exception,
+ );
+ }
+ }
+}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeCommandTest.php b/packages/documentator/src/Preprocessor/Instructions/IncludeCommandTest.php
new file mode 100644
index 000000000..e84ef473d
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeCommandTest.php
@@ -0,0 +1,32 @@
+shouldReceive('run')
+ ->with([$command], $path)
+ ->once()
+ ->andReturn($expected);
+
+ $instance = $this->app->make(IncludeCommand::class, [
+ 'process' => $process,
+ ]);
+
+ self::assertEquals($expected, $instance->process($path, $command));
+ }
+}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php b/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
new file mode 100644
index 000000000..4a8f5fe97
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
@@ -0,0 +1,97 @@
+getLanguage($path, $target);
+ $content = trim(parent::process($path, $target));
+ $content = <<getCommand($path, $target);
+
+ if ($command) {
+ try {
+ $output = $this->process->run($command, $path);
+ } catch (Exception $exception) {
+ throw new PreprocessFailed(
+ sprintf(
+ 'Failed to execute command `%s`.',
+ implode(' ', $command),
+ ),
+ $exception,
+ );
+ }
+
+ if (preg_match_all('/\R/u', $output) > static::Limit) {
+ $output = <<Output
+
+ ```plain
+ $output
+ ```
+
+
+ CODE;
+ } else {
+ $output = <<
+ */
+ protected function getCommand(string $path, string $target): ?array {
+ $info = pathinfo($target);
+ $file = isset($info['dirname'])
+ ? "{$info['dirname']}/{$info['filename']}.run"
+ : "{$info['filename']}.run";
+ $path = (new Filesystem())->isAbsolutePath($file) ? $file : "{$path}/{$file}";
+ $command = is_file($path) ? [$file] : null;
+
+ return $command;
+ }
+}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest.php b/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest.php
new file mode 100644
index 000000000..55b405c42
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest.php
@@ -0,0 +1,108 @@
+path('~example.md'));
+ $file = basename(self::getTestData()->path('~example.md'));
+ $expected = trim(self::getTestData()->content('~example.md'));
+ $process = Mockery::mock(Process::class);
+ $process
+ ->shouldReceive('run')
+ ->never();
+
+ $instance = $this->app->make(IncludeExample::class, [
+ 'process' => $process,
+ ]);
+
+ self::assertEquals(
+ <<process($path, $file),
+ );
+ }
+
+ public function testProcess(): void {
+ $path = dirname(self::getTestData()->path('~runnable.md'));
+ $file = self::getTestData()->path('~runnable.md');
+ $expected = trim(self::getTestData()->content('~runnable.md'));
+ $output = 'command output';
+ $process = Mockery::mock(Process::class);
+ $process
+ ->shouldReceive('run')
+ ->with([self::getTestData()->path('~runnable.run')], $path)
+ ->once()
+ ->andReturn($output);
+
+ $instance = $this->app->make(IncludeExample::class, [
+ 'process' => $process,
+ ]);
+
+ self::assertEquals(
+ <<process($path, $file),
+ );
+ }
+
+ public function testProcessLongOutput(): void {
+ $path = dirname(self::getTestData()->path('~runnable.md'));
+ $file = self::getTestData()->path('~runnable.md');
+ $expected = trim(self::getTestData()->content('~runnable.md'));
+ $output = implode("\n", range(0, IncludeExample::Limit + 1));
+ $process = Mockery::mock(Process::class);
+ $process
+ ->shouldReceive('run')
+ ->with([self::getTestData()->path('~runnable.run')], $path)
+ ->once()
+ ->andReturn($output);
+
+ $instance = $this->app->make(IncludeExample::class, [
+ 'process' => $process,
+ ]);
+
+ self::assertEquals(
+ <<Output
+
+ ```plain
+ {$output}
+ ```
+
+
+ EXPECTED,
+ $instance->process($path, $file),
+ );
+ }
+}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest~example.md b/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest~example.md
new file mode 100644
index 000000000..a6886c0f7
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest~example.md
@@ -0,0 +1,3 @@
+# File
+
+content of the file
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest~runnable.md b/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest~runnable.md
new file mode 100644
index 000000000..a6886c0f7
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest~runnable.md
@@ -0,0 +1,3 @@
+# File
+
+content of the file
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest~runnable.run b/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest~runnable.run
new file mode 100644
index 000000000..8eca9947a
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest~runnable.run
@@ -0,0 +1 @@
+/command
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeFile.php b/packages/documentator/src/Preprocessor/Instructions/IncludeFile.php
new file mode 100644
index 000000000..d80acd811
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeFile.php
@@ -0,0 +1,36 @@
+isAbsolutePath($target) ? $target : "{$path}/{$target}";
+ $content = file_get_contents($file);
+
+ if ($content === false) {
+ throw new PreprocessFailed(
+ sprintf(
+ 'Failed to include `%s`.',
+ $target,
+ ),
+ );
+ }
+
+ return $content;
+ }
+}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeFileTest.md b/packages/documentator/src/Preprocessor/Instructions/IncludeFileTest.md
new file mode 100644
index 000000000..a6886c0f7
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeFileTest.md
@@ -0,0 +1,3 @@
+# File
+
+content of the file
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeFileTest.php b/packages/documentator/src/Preprocessor/Instructions/IncludeFileTest.php
new file mode 100644
index 000000000..0d7840f56
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeFileTest.php
@@ -0,0 +1,33 @@
+path('.md'));
+ $file = basename(self::getTestData()->path('.md'));
+ $expected = self::getTestData()->content('.md');
+ $instance = $this->app->make(IncludeFile::class);
+
+ self::assertEquals($expected, $instance->process($path, $file));
+ }
+
+ public function testProcessAbsolute(): void {
+ $path = 'invalid/directory';
+ $file = self::getTestData()->path('.md');
+ $expected = self::getTestData()->content('.md');
+ $instance = $this->app->make(IncludeFile::class);
+
+ self::assertEquals($expected, $instance->process($path, $file));
+ }
+}
diff --git a/packages/documentator/src/Preprocessor/Preprocessor.php b/packages/documentator/src/Preprocessor/Preprocessor.php
new file mode 100644
index 000000000..1f6d638e3
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Preprocessor.php
@@ -0,0 +1,130 @@
+ "")
+ *
+ * Supported instructions:
+ *
+ * | `` | `` | Description |
+ * |-------------------|--------------------------------|----------------------------------------------------------|
+ * | `include:file` | path to the file | Include content of the file as is. |
+ * | `include:command` | the command to execute | Execute the command and include output. |
+ * | `include:example` | path to the example file | Include file in the code block + its output if possible. |
+ *
+ * Limitations:
+ * - `` will be processed everywhere in the file (eg within the code
+ * block) and may give unpredictable results.
+ * - `` cannot be inside text.
+ * - Nested `` doesn't supported.
+ */
+class Preprocessor {
+ protected const Warning = 'Generated automatically. Do not edit.';
+ protected const Regexp = <<<'REGEXP'
+ /^
+ (?P\[[^]]*?\]\((?P(?P.+?)\s+\"(?P[^"]+?)\")\))
+ (?P\
+
+ {$content}
+
+
+ RESULT;
+ } else {
+ $content = $matches['preprocess'];
+ }
+
+ return $content;
+ },
+ subject : $string,
+ flags : PREG_UNMATCHED_AS_NULL,
+ );
+
+ if ($result === null) {
+ throw new PreprocessFailed('Unexpected error.');
+ }
+
+ return $result;
+ }
+
+ protected function getHash(string $identifier): string {
+ return sha1($identifier);
+ }
+}
diff --git a/packages/documentator/src/Preprocessor/PreprocessorTest.php b/packages/documentator/src/Preprocessor/PreprocessorTest.php
new file mode 100644
index 000000000..b97bddb41
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/PreprocessorTest.php
@@ -0,0 +1,62 @@
+
+
+ outdated
+
+
+ MARKDOWN;
+ $instruction = Mockery::mock(Instruction::class);
+ $instruction
+ ->shouldReceive('getName')
+ ->once()
+ ->andReturn('test');
+ $instruction
+ ->shouldReceive('process')
+ ->with('path', './path/to/file')
+ ->once()
+ ->andReturn('content');
+
+ $preprocessor = (new Preprocessor())
+ ->addInstruction($instruction);
+
+ self::assertEquals(
+ <<<'MARKDOWN'
+ Bla bla bla [Link](./path/to/file "test") should be ignored.
+
+ [Link](./path/to/file "unknown")
+
+ [Link](./path/to/file "test")
+
+ content
+
+
+
+ [Link](./path/to/file "test")
+
+ content
+
+
+ MARKDOWN,
+ $preprocessor->process('path', $content),
+ );
+ }
+}
From 0fa1e6ef60055c18c38e6e65ed7fb4d07be8e3f5 Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Mon, 21 Aug 2023 14:37:04 +0400
Subject: [PATCH 11/33] feat(documentator): Command
`lara-asp-documentator:preprocess` to preprocess Markdown files.
---
packages/documentator/composer.json | 1 +
.../documentator/src/Commands/Preprocess.php | 55 +++++++++++++++++++
packages/documentator/src/Provider.php | 2 +
3 files changed, 58 insertions(+)
create mode 100644 packages/documentator/src/Commands/Preprocess.php
diff --git a/packages/documentator/composer.json b/packages/documentator/composer.json
index b26a2ff62..1435530da 100644
--- a/packages/documentator/composer.json
+++ b/packages/documentator/composer.json
@@ -23,6 +23,7 @@
"composer/semver": "^3.2",
"laravel/framework": "^9.21.0|^10.0.0",
"symfony/filesystem": "^6.3.0",
+ "symfony/finder": "^6.3.0",
"symfony/process": "^6.3.0",
"lastdragon-ru/lara-asp-core": "self.version",
"lastdragon-ru/lara-asp-serializer": "self.version"
diff --git a/packages/documentator/src/Commands/Preprocess.php b/packages/documentator/src/Commands/Preprocess.php
new file mode 100644
index 000000000..519628d25
--- /dev/null
+++ b/packages/documentator/src/Commands/Preprocess.php
@@ -0,0 +1,55 @@
+argument('path') ?? $cwd);
+ $finder = Finder::create()
+ ->ignoreVCSIgnored(true)
+ ->in($path)
+ ->exclude('vendor')
+ ->exclude('node_modules')
+ ->files()
+ ->name('*.md');
+
+ foreach ($finder as $file) {
+ $this->components->task($file->getPathname(), static function () use ($preprocessor, $file): bool {
+ $path = $file->getPath();
+ $content = $file->getContents();
+ $result = $preprocessor->process($path, $content);
+
+ return $content === $result
+ || file_put_contents($file->getPathname(), $result) !== false;
+ });
+ }
+ }
+}
diff --git a/packages/documentator/src/Provider.php b/packages/documentator/src/Provider.php
index b748d29e8..f921d0898 100644
--- a/packages/documentator/src/Provider.php
+++ b/packages/documentator/src/Provider.php
@@ -4,6 +4,7 @@
use Illuminate\Support\ServiceProvider;
use LastDragon_ru\LaraASP\Core\Concerns\ProviderWithViews;
+use LastDragon_ru\LaraASP\Documentator\Commands\Preprocess;
use LastDragon_ru\LaraASP\Documentator\Commands\Requirements;
class Provider extends ServiceProvider {
@@ -13,6 +14,7 @@ public function boot(): void {
$this->bootViews();
$this->commands(
Requirements::class,
+ Preprocess::class,
);
}
From 980f393a6150de0b37b7f68871ede54a9f79146c Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Mon, 21 Aug 2023 15:10:54 +0400
Subject: [PATCH 12/33] Preprocessor fixes.
---
.../src/Preprocessor/Instructions/IncludeCommand.php | 6 +++++-
.../src/Preprocessor/Instructions/IncludeCommandTest.php | 2 +-
packages/documentator/src/Preprocessor/Preprocessor.php | 4 +++-
3 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeCommand.php b/packages/documentator/src/Preprocessor/Instructions/IncludeCommand.php
index a382c6721..72da5ed48 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeCommand.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeCommand.php
@@ -7,6 +7,7 @@
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instruction;
use LastDragon_ru\LaraASP\Documentator\Utils\Process;
+use function explode;
use function sprintf;
class IncludeCommand implements Instruction {
@@ -22,7 +23,10 @@ public static function getName(): string {
public function process(string $path, string $target): string {
try {
- return $this->process->run([$target], $path);
+ return $this->process->run(
+ explode(' ', $target, 2), // todo(documentator): Probably we need to parse args?
+ $path,
+ );
} catch (Exception $exception) {
throw new PreprocessFailed(
sprintf(
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeCommandTest.php b/packages/documentator/src/Preprocessor/Instructions/IncludeCommandTest.php
index e84ef473d..0d2d5f3db 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeCommandTest.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeCommandTest.php
@@ -19,7 +19,7 @@ public function testProcess(): void {
$process = Mockery::mock(Process::class);
$process
->shouldReceive('run')
- ->with([$command], $path)
+ ->with(['command', 'to execute'], $path)
->once()
->andReturn($expected);
diff --git a/packages/documentator/src/Preprocessor/Preprocessor.php b/packages/documentator/src/Preprocessor/Preprocessor.php
index 1f6d638e3..f51b87ee1 100644
--- a/packages/documentator/src/Preprocessor/Preprocessor.php
+++ b/packages/documentator/src/Preprocessor/Preprocessor.php
@@ -11,6 +11,7 @@
use function preg_replace_callback;
use function sha1;
use function trim;
+use function urldecode;
use const PREG_UNMATCHED_AS_NULL;
@@ -93,7 +94,8 @@ public function process(string $path, string $string): string {
if ($content === null) {
$instruction = $this->getInstruction($matches['instruction']);
- $content = trim($instruction?->process($path, $matches['target']) ?? '');
+ $target = urldecode($matches['target']);
+ $content = trim($instruction?->process($path, $target) ?? '');
$this->cache[$hash] = $content;
}
From 9068359215dcc263c4cc2c5d4b80b96ff4e8c902 Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Tue, 22 Aug 2023 08:19:16 +0400
Subject: [PATCH 13/33] `Preprocessor` will use Link reference definitions
---
.../src/Preprocessor/Preprocessor.php | 27 ++++++++++++-------
.../src/Preprocessor/PreprocessorTest.php | 27 +++++++++++--------
2 files changed, 34 insertions(+), 20 deletions(-)
diff --git a/packages/documentator/src/Preprocessor/Preprocessor.php b/packages/documentator/src/Preprocessor/Preprocessor.php
index f51b87ee1..72e0bd81f 100644
--- a/packages/documentator/src/Preprocessor/Preprocessor.php
+++ b/packages/documentator/src/Preprocessor/Preprocessor.php
@@ -18,7 +18,8 @@
/**
* Replaces special instructions in Markdown.
*
- * [Link]( "")
+ * []:
+ * [=name]:
*
* Supported instructions:
*
@@ -38,10 +39,16 @@ class Preprocessor {
protected const Warning = 'Generated automatically. Do not edit.';
protected const Regexp = <<<'REGEXP'
/^
- (?P\[[^]]*?\]\((?P(?P.+?)\s+\"(?P[^"]+?)\")\))
- (?P\
+ {$matches['expression']}
+ [//]: # (start: {$hash})
+ [//]: # (warning: {$warning})
{$content}
-
+ [//]: # (end: {$hash})
RESULT;
} else {
- $content = $matches['preprocess'];
+ $content = $matches['expression'];
}
return $content;
diff --git a/packages/documentator/src/Preprocessor/PreprocessorTest.php b/packages/documentator/src/Preprocessor/PreprocessorTest.php
index b97bddb41..45a551779 100644
--- a/packages/documentator/src/Preprocessor/PreprocessorTest.php
+++ b/packages/documentator/src/Preprocessor/PreprocessorTest.php
@@ -12,17 +12,18 @@
class PreprocessorTest extends TestCase {
public function testProcess(): void {
$content = <<<'MARKDOWN'
- Bla bla bla [Link](./path/to/file "test") should be ignored.
+ Bla bla bla [test]: ./path/to/file should be ignored.
- [Link](./path/to/file "unknown")
+ [unknown]: ./path/to/file
- [Link](./path/to/file "test")
+ [test]: ./path/to/file
- [Link](./path/to/file "test")
+ [test]: ./path/to/file
+ [//]: # (start: hash)
outdated
-
+ [//]: # (end: hash)
MARKDOWN;
$instruction = Mockery::mock(Instruction::class);
$instruction
@@ -40,21 +41,25 @@ public function testProcess(): void {
self::assertEquals(
<<<'MARKDOWN'
- Bla bla bla [Link](./path/to/file "test") should be ignored.
+ Bla bla bla [test]: ./path/to/file should be ignored.
- [Link](./path/to/file "unknown")
+ [unknown]: ./path/to/file
- [Link](./path/to/file "test")
+ [test]: ./path/to/file
+ [//]: # (start: 8c3f20586897a62ee759aae56b703dd6cd11a8ad)
+ [//]: # (warning: Generated automatically. Do not edit.)
content
-
+ [//]: # (end: 8c3f20586897a62ee759aae56b703dd6cd11a8ad)
- [Link](./path/to/file "test")
+ [test]: ./path/to/file
+ [//]: # (start: 8c3f20586897a62ee759aae56b703dd6cd11a8ad)
+ [//]: # (warning: Generated automatically. Do not edit.)
content
-
+ [//]: # (end: 8c3f20586897a62ee759aae56b703dd6cd11a8ad)
MARKDOWN,
$preprocessor->process('path', $content),
);
From 67f81a9ee153a4fda43cff923b6d80af38af232f Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Tue, 22 Aug 2023 09:00:58 +0400
Subject: [PATCH 14/33] 'Path` helper.
---
.../Instructions/IncludeExample.php | 4 +--
.../Preprocessor/Instructions/IncludeFile.php | 4 +--
packages/documentator/src/Utils/Path.php | 26 +++++++++++++++++++
packages/documentator/src/Utils/PathTest.php | 20 ++++++++++++++
4 files changed, 50 insertions(+), 4 deletions(-)
create mode 100644 packages/documentator/src/Utils/Path.php
create mode 100644 packages/documentator/src/Utils/PathTest.php
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php b/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
index 4a8f5fe97..ac8025088 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
@@ -4,8 +4,8 @@
use Exception;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PreprocessFailed;
+use LastDragon_ru\LaraASP\Documentator\Utils\Path;
use LastDragon_ru\LaraASP\Documentator\Utils\Process;
-use Symfony\Component\Filesystem\Filesystem;
use function implode;
use function is_file;
@@ -89,7 +89,7 @@ protected function getCommand(string $path, string $target): ?array {
$file = isset($info['dirname'])
? "{$info['dirname']}/{$info['filename']}.run"
: "{$info['filename']}.run";
- $path = (new Filesystem())->isAbsolutePath($file) ? $file : "{$path}/{$file}";
+ $path = Path::getPath($path, $file);
$command = is_file($path) ? [$file] : null;
return $command;
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeFile.php b/packages/documentator/src/Preprocessor/Instructions/IncludeFile.php
index d80acd811..2a5129df2 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeFile.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeFile.php
@@ -4,7 +4,7 @@
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PreprocessFailed;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instruction;
-use Symfony\Component\Filesystem\Filesystem;
+use LastDragon_ru\LaraASP\Documentator\Utils\Path;
use function file_get_contents;
use function sprintf;
@@ -19,7 +19,7 @@ public static function getName(): string {
}
public function process(string $path, string $target): string {
- $file = (new Filesystem())->isAbsolutePath($target) ? $target : "{$path}/{$target}";
+ $file = Path::getPath($path, $target);
$content = file_get_contents($file);
if ($content === false) {
diff --git a/packages/documentator/src/Utils/Path.php b/packages/documentator/src/Utils/Path.php
new file mode 100644
index 000000000..9c322ec8e
--- /dev/null
+++ b/packages/documentator/src/Utils/Path.php
@@ -0,0 +1,26 @@
+
Date: Tue, 22 Aug 2023 09:37:54 +0400
Subject: [PATCH 15/33] `Preprocessor` will cache instructions only for current
file.
---
.../src/Preprocessor/Preprocessor.php | 23 ++++++++-----------
.../src/Preprocessor/PreprocessorTest.php | 5 ++++
packages/documentator/src/Utils/Path.php | 13 +++++++++--
3 files changed, 26 insertions(+), 15 deletions(-)
diff --git a/packages/documentator/src/Preprocessor/Preprocessor.php b/packages/documentator/src/Preprocessor/Preprocessor.php
index 72e0bd81f..3a1223465 100644
--- a/packages/documentator/src/Preprocessor/Preprocessor.php
+++ b/packages/documentator/src/Preprocessor/Preprocessor.php
@@ -7,6 +7,7 @@
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeCommand;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeExample;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeFile;
+use LastDragon_ru\LaraASP\Documentator\Utils\Path;
use function preg_replace_callback;
use function sha1;
@@ -55,11 +56,6 @@ class Preprocessor {
*/
private array $instructions = [];
- /**
- * @var array
- */
- private array $cache = [];
-
public function __construct() {
$this->addInstruction(IncludeFile::class);
$this->addInstruction(IncludeCommand::class);
@@ -92,18 +88,19 @@ protected function getInstruction(string $name): ?Instruction {
}
public function process(string $path, string $string): string {
+ $path = Path::normalize($path);
+ $cache = [];
$result = preg_replace_callback(
pattern : static::Regexp,
- callback: function (array $matches) use ($path): string {
- $identifier = $matches['instruction'].'='.$matches['target'];
- $hash = $this->getHash($identifier);
- $content = $this->cache[$hash] ?? null;
+ callback: function (array $matches) use (&$cache, $path): string {
+ $hash = $this->getHash("{$matches['instruction']}={$matches['target']}");
+ $content = $cache[$hash] ?? null;
if ($content === null) {
- $instruction = $this->getInstruction($matches['instruction']);
- $target = urldecode($matches['target']);
- $content = trim($instruction?->process($path, $target) ?? '');
- $this->cache[$hash] = $content;
+ $instruction = $this->getInstruction($matches['instruction']);
+ $target = urldecode($matches['target']);
+ $content = trim($instruction?->process($path, $target) ?? '');
+ $cache[$hash] = $content;
}
// Return
diff --git a/packages/documentator/src/Preprocessor/PreprocessorTest.php b/packages/documentator/src/Preprocessor/PreprocessorTest.php
index 45a551779..90d08e446 100644
--- a/packages/documentator/src/Preprocessor/PreprocessorTest.php
+++ b/packages/documentator/src/Preprocessor/PreprocessorTest.php
@@ -21,8 +21,13 @@ public function testProcess(): void {
[test]: ./path/to/file
[//]: # (start: hash)
+ [test]: ./path/to/file
+ [//]: # (start: nested-hash)
+
outdated
+ [//]: # (end: nested-hash)
+
[//]: # (end: hash)
MARKDOWN;
$instruction = Mockery::mock(Instruction::class);
diff --git a/packages/documentator/src/Utils/Path.php b/packages/documentator/src/Utils/Path.php
index 9c322ec8e..227229365 100644
--- a/packages/documentator/src/Utils/Path.php
+++ b/packages/documentator/src/Utils/Path.php
@@ -9,13 +9,22 @@
class Path {
public static function getPath(string $root, string $path): string {
- $root = is_file($root) ? dirname($root) : $root;
- $path = static::isAbsolute($path) ? $path : "{$root}/{$path}";
+ $path = static::isRelative($path)
+ ? SymfonyPath::join(static::getDirname($root), $path)
+ : $path;
$path = static::normalize($path);
return $path;
}
+ public static function getDirname(string $path): string {
+ return is_file($path) ? dirname($path) : $path;
+ }
+
+ public static function isRelative(string $path): bool {
+ return SymfonyPath::isRelative($path);
+ }
+
public static function isAbsolute(string $path): bool {
return SymfonyPath::isAbsolute($path);
}
From f92cbc1bb602d432740e9b1fae0bdd4417f6eea8 Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Tue, 22 Aug 2023 11:16:12 +0400
Subject: [PATCH 16/33] `Markdown` helper.
---
composer.json | 1 +
packages/documentator/composer.json | 1 +
packages/documentator/src/Utils/Markdown.php | 74 ++++++++++++
.../documentator/src/Utils/MarkdownTest.php | 112 ++++++++++++++++++
4 files changed, 188 insertions(+)
create mode 100644 packages/documentator/src/Utils/Markdown.php
create mode 100644 packages/documentator/src/Utils/MarkdownTest.php
diff --git a/composer.json b/composer.json
index 4a0e268b8..1f7078858 100644
--- a/composer.json
+++ b/composer.json
@@ -46,6 +46,7 @@
"guzzlehttp/psr7": "^1.9.1|^2.4.5",
"http-interop/http-factory-guzzle": "^1.0.0",
"laravel/framework": "^9.21.0|^10.0.0",
+ "league/commonmark": "^2.4",
"nuwave/lighthouse": "^6.5.0",
"opis/json-schema": "^2.3.0",
"phpdocumentor/type-resolver": "^1.7",
diff --git a/packages/documentator/composer.json b/packages/documentator/composer.json
index 1435530da..7988f59e9 100644
--- a/packages/documentator/composer.json
+++ b/packages/documentator/composer.json
@@ -22,6 +22,7 @@
"ext-mbstring": "*",
"composer/semver": "^3.2",
"laravel/framework": "^9.21.0|^10.0.0",
+ "league/commonmark": "^2.4",
"symfony/filesystem": "^6.3.0",
"symfony/finder": "^6.3.0",
"symfony/process": "^6.3.0",
diff --git a/packages/documentator/src/Utils/Markdown.php b/packages/documentator/src/Utils/Markdown.php
new file mode 100644
index 000000000..f0386bf41
--- /dev/null
+++ b/packages/documentator/src/Utils/Markdown.php
@@ -0,0 +1,74 @@
+next();
+ $summary = $node instanceof Paragraph
+ ? static::getText($string, $node)
+ : null;
+
+ return $summary;
+ }
+
+ protected static function getDocumentNode(string $string): Document {
+ $converter = new GithubFlavoredMarkdownConverter();
+ $environment = $converter->getEnvironment();
+ $parser = new MarkdownParser($environment);
+
+ return $parser->parse($string);
+ }
+
+ protected static function getTitleNode(string $string): ?Heading {
+ $node = static::getDocumentNode($string)->firstChild();
+ $header = $node instanceof Heading && $node->getLevel() === 1
+ ? $node
+ : null;
+
+ return $header;
+ }
+
+ protected static function getText(string $string, ?AbstractBlock $node): ?string {
+ // todo(documentator): There is no way to convert AST back to Markdown yet
+ // https://github.com/thephpleague/commonmark/issues/419
+ if (!$node || $node->getStartLine() === null || $node->getEndLine() === null) {
+ return null;
+ }
+
+ $start = $node->getStartLine() - 1;
+ $end = $node->getEndLine() - 1;
+ $lines = (array) preg_split('/\R/u', $string);
+ $lines = array_slice($lines, $start, $end - $start + 1);
+ $text = trim(implode("\n", $lines));
+
+ return $text;
+ }
+}
diff --git a/packages/documentator/src/Utils/MarkdownTest.php b/packages/documentator/src/Utils/MarkdownTest.php
new file mode 100644
index 000000000..7912aec32
--- /dev/null
+++ b/packages/documentator/src/Utils/MarkdownTest.php
@@ -0,0 +1,112 @@
+ Not a paragraph
+
+ fsdfsdfsdf
+ MARKDOWN,
+ ),
+ );
+ self::assertEquals(
+ 'fsdfsdfsdf',
+ Markdown::getSummary(
+ <<<'MARKDOWN'
+ #
+
+ fsdfsdfsdf
+ MARKDOWN,
+ ),
+ );
+ self::assertEquals(
+ <<<'TEXT'
+ fsdfsdfsdf
+ fsdfsdfsdf
+ TEXT,
+ Markdown::getSummary(
+ <<<'MARKDOWN'
+
+ # Header
+
+ fsdfsdfsdf
+ fsdfsdfsdf
+ MARKDOWN,
+ ),
+ );
+ }
+}
From 53b1fdadcf0b10a29dd8d5a5bd6ab02655d402ef Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Tue, 22 Aug 2023 13:53:23 +0400
Subject: [PATCH 17/33] New instruction: `include:package-list`.
---
.../views/package-list/markdown.blade.php | 18 +++
.../Instructions/IncludePackageList.php | 129 ++++++++++++++++++
.../Instructions/IncludePackageListTest.md | 11 ++
.../Instructions/IncludePackageListTest.php | 30 ++++
.../not a package/README.md | 3 +
.../package custom readme/CUSTOM.md | 5 +
.../package custom readme/README.md | 3 +
.../package custom readme/composer.json | 5 +
.../package no title/README.md | 3 +
.../package no title/composer.json | 5 +
.../IncludePackageListTest/package/README.md | 3 +
.../package/composer.json | 5 +
.../src/Preprocessor/Preprocessor.php | 2 +
13 files changed, 222 insertions(+)
create mode 100644 packages/documentator/resources/views/package-list/markdown.blade.php
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.md
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.php
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/not a package/README.md
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/CUSTOM.md
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/README.md
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/composer.json
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package no title/README.md
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package no title/composer.json
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package/README.md
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package/composer.json
diff --git a/packages/documentator/resources/views/package-list/markdown.blade.php b/packages/documentator/resources/views/package-list/markdown.blade.php
new file mode 100644
index 000000000..d1c52da5d
--- /dev/null
+++ b/packages/documentator/resources/views/package-list/markdown.blade.php
@@ -0,0 +1,18 @@
+ $packages
+ */
+
+?>
+@foreach ($packages as $package)
+## {{ $package['title'] }}
+@if($package['summary'])
+
+{{ $package['summary'] }}
+@endif
+
+[Read more](<{{ $package['readme'] }}>).
+@if (!$loop->last)
+
+@endif
+@endforeach
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php b/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php
new file mode 100644
index 000000000..a9fc904da
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php
@@ -0,0 +1,129 @@
+ $packages */
+ $packages = [];
+ $directories = Finder::create()
+ ->ignoreVCSIgnored(true)
+ ->in(Path::getPath($path, $target))
+ ->depth(0)
+ ->exclude('vendor')
+ ->exclude('node_modules')
+ ->directories();
+
+ foreach ($directories as $directory) {
+ // Package?
+ $root = $directory->getPathname();
+ $package = $this->getPackageInfo($root);
+
+ if (!$package) {
+ continue;
+ }
+
+ // Readme
+ $readme = $this->getPackageReadme($root, $package);
+ $content = $readme
+ ? file_get_contents("{$root}/{$readme}")
+ : false;
+
+ if ($content === false) {
+ continue;
+ }
+
+ // Extract
+ $title = Markdown::getTitle($content);
+
+ if ($title) {
+ $path = Path::normalize("{$target}/{$directory->getFilename()}");
+
+ $packages[] = [
+ 'path' => $path,
+ 'title' => $title,
+ 'summary' => Markdown::getSummary($content),
+ 'readme' => Path::normalize("{$path}/{$readme}"),
+ ];
+ }
+ }
+
+ // Packages?
+ if (!$packages) {
+ return '';
+ }
+
+ // Render
+ $package = Package::Name;
+ $list = view("{$package}::package-list.markdown", [
+ 'packages' => $packages,
+ ])->render();
+
+ // Return
+ return $list;
+ }
+
+ /**
+ * @return array|null
+ */
+ protected function getPackageInfo(string $path): ?array {
+ try {
+ $file = "{$path}/composer.json";
+ $package = is_file($file) ? file_get_contents($file) : false;
+ $package = $package !== false
+ ? json_decode($package, true, flags: JSON_THROW_ON_ERROR)
+ : null;
+
+ assert(is_array($package));
+ } catch (Exception) {
+ $package = null;
+ }
+
+ return $package;
+ }
+
+ /**
+ * @param array $package
+ */
+ protected function getPackageReadme(string $path, array $package): ?string {
+ $readme = null;
+ $variants = [
+ $package['readme'] ?? null,
+ 'README.md',
+ ];
+
+ foreach ($variants as $variant) {
+ if ($variant && is_string($variant) && is_file(Path::getPath($path, $variant))) {
+ $readme = $variant;
+ break;
+ }
+ }
+
+ return $readme;
+ }
+}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.md b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.md
new file mode 100644
index 000000000..b7b49deaf
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.md
@@ -0,0 +1,11 @@
+
+
+## The Package
+
+Summary text.
+
+[Read more]().
+
+## The Package with custom readme
+
+[Read more]().
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.php b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.php
new file mode 100644
index 000000000..f5d7a0a6f
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.php
@@ -0,0 +1,30 @@
+path('/');
+ $instance = $this->app->make(IncludePackageList::class);
+ $actual = $instance->process(dirname($path), basename($path));
+
+ self::assertEquals(
+ self::getTestData()->content('.md'),
+ <<
+
+ {$actual}
+ MARKDOWN,
+ );
+ }
+}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/not a package/README.md b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/not a package/README.md
new file mode 100644
index 000000000..3f6f7e12f
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/not a package/README.md
@@ -0,0 +1,3 @@
+# No `composer.json`
+
+`composer.json` is required.
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/CUSTOM.md b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/CUSTOM.md
new file mode 100644
index 000000000..231405d90
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/CUSTOM.md
@@ -0,0 +1,5 @@
+# The Package with custom readme
+
+## Section
+
+Text.
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/README.md b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/README.md
new file mode 100644
index 000000000..147bdcf3c
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/README.md
@@ -0,0 +1,3 @@
+# Should not be used
+
+Should not be used.
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/composer.json b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/composer.json
new file mode 100644
index 000000000..4b26f97e1
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/composer.json
@@ -0,0 +1,5 @@
+{
+ "name": "lastdragon-ru/lara-asp-documentator",
+ "homepage": "https://github.com/LastDragon-ru/lara-asp",
+ "readme": "CUSTOM.md"
+}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package no title/README.md b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package no title/README.md
new file mode 100644
index 000000000..e600bbdef
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package no title/README.md
@@ -0,0 +1,3 @@
+
+
+Package readme.
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package no title/composer.json b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package no title/composer.json
new file mode 100644
index 000000000..0a9113a4a
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package no title/composer.json
@@ -0,0 +1,5 @@
+{
+ "name": "lastdragon-ru/lara-asp-documentator",
+ "homepage": "https://github.com/LastDragon-ru/lara-asp",
+ "readme": "README.md"
+}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package/README.md b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package/README.md
new file mode 100644
index 000000000..26d9a5bb0
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package/README.md
@@ -0,0 +1,3 @@
+# The Package
+
+Summary text.
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package/composer.json b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package/composer.json
new file mode 100644
index 000000000..0a9113a4a
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package/composer.json
@@ -0,0 +1,5 @@
+{
+ "name": "lastdragon-ru/lara-asp-documentator",
+ "homepage": "https://github.com/LastDragon-ru/lara-asp",
+ "readme": "README.md"
+}
diff --git a/packages/documentator/src/Preprocessor/Preprocessor.php b/packages/documentator/src/Preprocessor/Preprocessor.php
index 3a1223465..ff08dfa11 100644
--- a/packages/documentator/src/Preprocessor/Preprocessor.php
+++ b/packages/documentator/src/Preprocessor/Preprocessor.php
@@ -7,6 +7,7 @@
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeCommand;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeExample;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeFile;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludePackageList;
use LastDragon_ru\LaraASP\Documentator\Utils\Path;
use function preg_replace_callback;
@@ -60,6 +61,7 @@ public function __construct() {
$this->addInstruction(IncludeFile::class);
$this->addInstruction(IncludeCommand::class);
$this->addInstruction(IncludeExample::class);
+ $this->addInstruction(IncludePackageList::class);
}
/**
From 047501c19b07f11f8a7df477daed8ab9f6c43b4c Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Tue, 22 Aug 2023 14:37:03 +0400
Subject: [PATCH 18/33] `Preprocessor` minor improvements.
---
.../src/Preprocessor/Preprocessor.php | 35 +++++++++++++------
.../src/Preprocessor/PreprocessorTest.php | 28 ++++++++++++---
2 files changed, 48 insertions(+), 15 deletions(-)
diff --git a/packages/documentator/src/Preprocessor/Preprocessor.php b/packages/documentator/src/Preprocessor/Preprocessor.php
index ff08dfa11..4762ca98f 100644
--- a/packages/documentator/src/Preprocessor/Preprocessor.php
+++ b/packages/documentator/src/Preprocessor/Preprocessor.php
@@ -11,9 +11,9 @@
use LastDragon_ru\LaraASP\Documentator\Utils\Path;
use function preg_replace_callback;
+use function rawurldecode;
use function sha1;
use function trim;
-use function urldecode;
use const PREG_UNMATCHED_AS_NULL;
@@ -36,6 +36,8 @@
* block) and may give unpredictable results.
* - `` cannot be inside text.
* - Nested `` doesn't supported.
+ *
+ * @todo Use https://github.com/thephpleague/commonmark?
*/
class Preprocessor {
protected const Warning = 'Generated automatically. Do not edit.';
@@ -95,27 +97,40 @@ public function process(string $path, string $string): string {
$result = preg_replace_callback(
pattern : static::Regexp,
callback: function (array $matches) use (&$cache, $path): string {
- $hash = $this->getHash("{$matches['instruction']}={$matches['target']}");
- $content = $cache[$hash] ?? null;
+ $hash = $this->getHash("{$matches['instruction']}={$matches['target']}");
+ $content = $cache[$hash] ?? null;
+ $instruction = $this->getInstruction($matches['instruction']);
if ($content === null) {
- $instruction = $this->getInstruction($matches['instruction']);
- $target = urldecode($matches['target']);
+ $target = rawurldecode($matches['target']);
$content = trim($instruction?->process($path, $target) ?? '');
$cache[$hash] = $content;
}
// Return
+ $warning = static::Warning;
+ $prefix = <<shouldReceive('getName')
->once()
->andReturn('test');
- $instruction
+ $testInstruction
->shouldReceive('process')
->with('path', './path/to/file')
->once()
->andReturn('content');
+ $emptyInstruction = new class() implements Instruction {
+ public static function getName(): string {
+ return 'empty';
+ }
+
+ public function process(string $path, string $target): string {
+ return '';
+ }
+ };
$preprocessor = (new Preprocessor())
- ->addInstruction($instruction);
+ ->addInstruction($testInstruction)
+ ->addInstruction($emptyInstruction);
self::assertEquals(
<<<'MARKDOWN'
@@ -50,6 +62,12 @@ public function testProcess(): void {
[unknown]: ./path/to/file
+ [empty]: ./path/to/file
+ [//]: # (start: a3fab3c67a30d7c1ba21b17c4c0e9e609e78373c)
+ [//]: # (warning: Generated automatically. Do not edit.)
+ [//]: # (empty)
+ [//]: # (end: a3fab3c67a30d7c1ba21b17c4c0e9e609e78373c)
+
[test]: ./path/to/file
[//]: # (start: 8c3f20586897a62ee759aae56b703dd6cd11a8ad)
[//]: # (warning: Generated automatically. Do not edit.)
From 2198e55606736fae177f875590a3e8056849f441 Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Tue, 22 Aug 2023 14:47:40 +0400
Subject: [PATCH 19/33] `IncludeExample` minor fixes.
---
.../src/Preprocessor/Instructions/IncludeExample.php | 1 +
.../src/Preprocessor/Instructions/IncludeExampleTest.php | 1 +
2 files changed, 2 insertions(+)
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php b/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
index ac8025088..78c74e9c7 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
@@ -65,6 +65,7 @@ public function process(string $path, string $target): string {
} else {
$output = <<
Date: Tue, 22 Aug 2023 16:51:47 +0400
Subject: [PATCH 20/33] `IncludePackageList` will sort packages by title.
---
.../resources/views/package-list/markdown.blade.php | 4 ++--
.../Preprocessor/Instructions/IncludePackageList.php | 12 ++++++++----
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/packages/documentator/resources/views/package-list/markdown.blade.php b/packages/documentator/resources/views/package-list/markdown.blade.php
index d1c52da5d..777a99450 100644
--- a/packages/documentator/resources/views/package-list/markdown.blade.php
+++ b/packages/documentator/resources/views/package-list/markdown.blade.php
@@ -1,6 +1,6 @@
$packages
+ * @var list $packages
*/
?>
@@ -11,7 +11,7 @@
{{ $package['summary'] }}
@endif
-[Read more](<{{ $package['readme'] }}>).
+[Read more](<{{ $package['path'] }}>).
@if (!$loop->last)
@endif
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php b/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php
index a9fc904da..6ccbf1a62 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php
@@ -15,6 +15,8 @@
use function is_file;
use function is_string;
use function json_decode;
+use function strcmp;
+use function usort;
use function view;
use const JSON_THROW_ON_ERROR;
@@ -62,13 +64,10 @@ public function process(string $path, string $target): string {
$title = Markdown::getTitle($content);
if ($title) {
- $path = Path::normalize("{$target}/{$directory->getFilename()}");
-
$packages[] = [
- 'path' => $path,
+ 'path' => Path::normalize("{$target}/{$directory->getFilename()}/{$readme}"),
'title' => $title,
'summary' => Markdown::getSummary($content),
- 'readme' => Path::normalize("{$path}/{$readme}"),
];
}
}
@@ -78,6 +77,11 @@ public function process(string $path, string $target): string {
return '';
}
+ // Sort
+ usort($packages, static function (array $a, $b): int {
+ return strcmp($a['title'], $b['title']);
+ });
+
// Render
$package = Package::Name;
$list = view("{$package}::package-list.markdown", [
From 6a9c2281d9f0fff4150cd73e89f5e93e1098e518 Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Tue, 22 Aug 2023 20:42:54 +0400
Subject: [PATCH 21/33] New instruction: `include:document-list`.
---
.../views/document-list/markdown.blade.php | 18 +++++
.../Instructions/IncludeDocumentList.php | 73 +++++++++++++++++++
.../Instructions/IncludeDocumentListTest.md | 13 ++++
.../Instructions/IncludeDocumentListTest.php | 30 ++++++++
.../IncludeDocumentListTest/Document A.md | 5 ++
.../IncludeDocumentListTest/Document B.md | 5 ++
.../IncludeDocumentListTest/WithoutTitle.md | 3 +
.../src/Preprocessor/Preprocessor.php | 2 +
8 files changed, 149 insertions(+)
create mode 100644 packages/documentator/resources/views/document-list/markdown.blade.php
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeDocumentList.php
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.md
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.php
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document A.md
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document B.md
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/WithoutTitle.md
diff --git a/packages/documentator/resources/views/document-list/markdown.blade.php b/packages/documentator/resources/views/document-list/markdown.blade.php
new file mode 100644
index 000000000..7cfddaf71
--- /dev/null
+++ b/packages/documentator/resources/views/document-list/markdown.blade.php
@@ -0,0 +1,18 @@
+ $documents
+ */
+
+?>
+@foreach ($documents as $document)
+## {{ $document['title'] }}
+@if($document['summary'])
+
+{{ $document['summary'] }}
+@endif
+
+[Read more](<{{ $document['path'] }}>).
+@if (!$loop->last)
+
+@endif
+@endforeach
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentList.php b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentList.php
new file mode 100644
index 000000000..e99df3758
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentList.php
@@ -0,0 +1,73 @@
+ $documents */
+ $documents = [];
+ $files = Finder::create()
+ ->in(Path::getPath($path, $target))
+ ->depth(0)
+ ->name('*.md')
+ ->files();
+
+ foreach ($files as $file) {
+ // Package?
+ $content = file_get_contents($file->getPathname());
+
+ if (!$content) {
+ continue;
+ }
+
+ // Extract
+ $title = Markdown::getTitle($content);
+
+ if ($title) {
+ $documents[] = [
+ 'path' => Path::normalize("{$target}/{$file->getFilename()}"),
+ 'title' => $title,
+ 'summary' => Markdown::getSummary($content),
+ ];
+ }
+ }
+
+ // Empty?
+ if (!$documents) {
+ return '';
+ }
+
+ // Sort
+ usort($documents, static function (array $a, $b): int {
+ return strcmp($a['title'], $b['title']);
+ });
+
+ // Render
+ $package = Package::Name;
+ $list = view("{$package}::document-list.markdown", [
+ 'documents' => $documents,
+ ])->render();
+
+ // Return
+ return $list;
+ }
+}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.md b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.md
new file mode 100644
index 000000000..b1052cd31
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.md
@@ -0,0 +1,13 @@
+
+
+## Document
+
+Summary text.
+
+[Read more]().
+
+## Document A
+
+Summary text.
+
+[Read more]().
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.php b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.php
new file mode 100644
index 000000000..d298a4225
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.php
@@ -0,0 +1,30 @@
+path('/');
+ $instance = $this->app->make(IncludeDocumentList::class);
+ $actual = $instance->process(dirname($path), basename($path));
+
+ self::assertEquals(
+ self::getTestData()->content('.md'),
+ <<
+
+ {$actual}
+ MARKDOWN,
+ );
+ }
+}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document A.md b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document A.md
new file mode 100644
index 000000000..c4f2592b3
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document A.md
@@ -0,0 +1,5 @@
+# Document A
+
+Summary text.
+
+Another text.
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document B.md b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document B.md
new file mode 100644
index 000000000..a2b9c7123
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document B.md
@@ -0,0 +1,5 @@
+# Document
+
+Summary text.
+
+Another text.
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/WithoutTitle.md b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/WithoutTitle.md
new file mode 100644
index 000000000..0b64c6705
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/WithoutTitle.md
@@ -0,0 +1,3 @@
+
+
+Document text.
diff --git a/packages/documentator/src/Preprocessor/Preprocessor.php b/packages/documentator/src/Preprocessor/Preprocessor.php
index 4762ca98f..5058d2330 100644
--- a/packages/documentator/src/Preprocessor/Preprocessor.php
+++ b/packages/documentator/src/Preprocessor/Preprocessor.php
@@ -5,6 +5,7 @@
use Illuminate\Container\Container;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PreprocessFailed;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeCommand;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeDocumentList;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeExample;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeFile;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludePackageList;
@@ -64,6 +65,7 @@ public function __construct() {
$this->addInstruction(IncludeCommand::class);
$this->addInstruction(IncludeExample::class);
$this->addInstruction(IncludePackageList::class);
+ $this->addInstruction(IncludeDocumentList::class);
}
/**
From 4fa1a510c3e3b1eb2a1ce187d686cfb9fbdfa1ef Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Wed, 23 Aug 2023 09:36:50 +0400
Subject: [PATCH 22/33] Improvements and fixes.
---
.../documentator/src/Commands/Preprocess.php | 4 +--
.../documentator/src/Metadata/Storage.php | 3 +-
.../Exceptions/InstructionFailed.php | 24 ++++++++++++++
.../Exceptions/TargetCommandFailed.php | 22 +++++++++++++
.../Exceptions/TargetIsNotDirectory.php | 22 +++++++++++++
.../Exceptions/TargetIsNotFile.php | 22 +++++++++++++
.../Instructions/IncludeCommand.php | 14 +++-----
.../Instructions/IncludeCommandTest.php | 6 ++--
.../Instructions/IncludeDocumentList.php | 23 +++++++++++--
.../Instructions/IncludeDocumentListTest.php | 24 +++++++++++---
.../IncludeDocumentListTest/Document B.md | 2 +-
.../IncludeDocumentListTest/Document.md | 3 ++
...cludeDocumentListTest~AnotherDirectory.md} | 10 ++++--
.../IncludeDocumentListTest~SameDirectory.md | 13 ++++++++
.../Instructions/IncludeExample.php | 21 ++++--------
.../Instructions/IncludeExampleTest.php | 12 +++----
.../Preprocessor/Instructions/IncludeFile.php | 13 +++-----
.../Instructions/IncludeFileTest.php | 8 ++---
.../Instructions/IncludePackageList.php | 32 ++++++++++++-------
.../Instructions/IncludePackageListTest.php | 5 ++-
packages/documentator/src/Utils/Path.php | 4 +++
21 files changed, 212 insertions(+), 75 deletions(-)
create mode 100644 packages/documentator/src/Preprocessor/Exceptions/InstructionFailed.php
create mode 100644 packages/documentator/src/Preprocessor/Exceptions/TargetCommandFailed.php
create mode 100644 packages/documentator/src/Preprocessor/Exceptions/TargetIsNotDirectory.php
create mode 100644 packages/documentator/src/Preprocessor/Exceptions/TargetIsNotFile.php
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document.md
rename packages/documentator/src/Preprocessor/Instructions/{IncludeDocumentListTest.md => IncludeDocumentListTest~AnotherDirectory.md} (69%)
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest~SameDirectory.md
diff --git a/packages/documentator/src/Commands/Preprocess.php b/packages/documentator/src/Commands/Preprocess.php
index 519628d25..e23513ef6 100644
--- a/packages/documentator/src/Commands/Preprocess.php
+++ b/packages/documentator/src/Commands/Preprocess.php
@@ -43,12 +43,12 @@ public function __invoke(Preprocessor $preprocessor): void {
foreach ($finder as $file) {
$this->components->task($file->getPathname(), static function () use ($preprocessor, $file): bool {
- $path = $file->getPath();
+ $path = $file->getPathname();
$content = $file->getContents();
$result = $preprocessor->process($path, $content);
return $content === $result
- || file_put_contents($file->getPathname(), $result) !== false;
+ || file_put_contents($path, $result) !== false;
});
}
}
diff --git a/packages/documentator/src/Metadata/Storage.php b/packages/documentator/src/Metadata/Storage.php
index 655116c8f..96110ff27 100644
--- a/packages/documentator/src/Metadata/Storage.php
+++ b/packages/documentator/src/Metadata/Storage.php
@@ -2,6 +2,7 @@
namespace LastDragon_ru\LaraASP\Documentator\Metadata;
+use LastDragon_ru\LaraASP\Documentator\Utils\Path;
use LastDragon_ru\LaraASP\Documentator\Utils\Version;
use LastDragon_ru\LaraASP\Serializer\Contracts\Serializer;
use Symfony\Component\Serializer\Context\Encoder\JsonEncoderContextBuilder;
@@ -42,7 +43,7 @@ public function __construct(
}
protected function getPath(): string {
- return "{$this->path}/metadata.json";
+ return Path::join($this->path, 'metadata.json');
}
public function load(): Metadata {
diff --git a/packages/documentator/src/Preprocessor/Exceptions/InstructionFailed.php b/packages/documentator/src/Preprocessor/Exceptions/InstructionFailed.php
new file mode 100644
index 000000000..08d12da20
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Exceptions/InstructionFailed.php
@@ -0,0 +1,24 @@
+path;
+ }
+
+ public function getTarget(): string {
+ return $this->target;
+ }
+}
diff --git a/packages/documentator/src/Preprocessor/Exceptions/TargetCommandFailed.php b/packages/documentator/src/Preprocessor/Exceptions/TargetCommandFailed.php
new file mode 100644
index 000000000..2107a3de8
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Exceptions/TargetCommandFailed.php
@@ -0,0 +1,22 @@
+process->run(
explode(' ', $target, 2), // todo(documentator): Probably we need to parse args?
- $path,
+ dirname($path),
);
} catch (Exception $exception) {
- throw new PreprocessFailed(
- sprintf(
- 'Failed to execute command `%s`.',
- $target,
- ),
- $exception,
- );
+ throw new TargetCommandFailed($path, $target, $exception);
}
}
}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeCommandTest.php b/packages/documentator/src/Preprocessor/Instructions/IncludeCommandTest.php
index 0d2d5f3db..482384436 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeCommandTest.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeCommandTest.php
@@ -7,19 +7,21 @@
use Mockery;
use PHPUnit\Framework\Attributes\CoversClass;
+use function dirname;
+
/**
* @internal
*/
#[CoversClass(IncludeFile::class)]
class IncludeCommandTest extends TestCase {
public function testProcess(): void {
- $path = 'current/working/directory';
+ $path = 'current/working/directory/file.md';
$expected = 'result';
$command = 'command to execute';
$process = Mockery::mock(Process::class);
$process
->shouldReceive('run')
- ->with(['command', 'to execute'], $path)
+ ->with(['command', 'to execute'], dirname($path))
->once()
->andReturn($expected);
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentList.php b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentList.php
index e99df3758..3b2d62a2d 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentList.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentList.php
@@ -3,12 +3,16 @@
namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;
use LastDragon_ru\LaraASP\Documentator\Package;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\TargetIsNotDirectory;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instruction;
use LastDragon_ru\LaraASP\Documentator\Utils\Markdown;
use LastDragon_ru\LaraASP\Documentator\Utils\Path;
use Symfony\Component\Finder\Finder;
+use function basename;
+use function dirname;
use function file_get_contents;
+use function is_dir;
use function strcmp;
use function usort;
use function view;
@@ -23,16 +27,29 @@ public static function getName(): string {
}
public function process(string $path, string $target): string {
+ // Directory?
+ $root = Path::getPath(dirname($path), $target);
+
+ if (!is_dir($root)) {
+ throw new TargetIsNotDirectory($path, $target);
+ }
+
/** @var list $documents */
$documents = [];
+ $target = Path::normalize($target);
$files = Finder::create()
- ->in(Path::getPath($path, $target))
+ ->in($root)
->depth(0)
->name('*.md')
->files();
foreach ($files as $file) {
- // Package?
+ // Same?
+ if ($target === '' && $file->getFilename() === basename($path)) {
+ continue;
+ }
+
+ // Content?
$content = file_get_contents($file->getPathname());
if (!$content) {
@@ -44,7 +61,7 @@ public function process(string $path, string $target): string {
if ($title) {
$documents[] = [
- 'path' => Path::normalize("{$target}/{$file->getFilename()}"),
+ 'path' => Path::join($target, $file->getFilename()),
'title' => $title,
'summary' => Markdown::getSummary($content),
];
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.php b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.php
index d298a4225..4d926a220 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.php
@@ -6,20 +6,19 @@
use PHPUnit\Framework\Attributes\CoversClass;
use function basename;
-use function dirname;
/**
* @internal
*/
#[CoversClass(IncludeDocumentList::class)]
class IncludeDocumentListTest extends TestCase {
- public function testProcess(): void {
- $path = self::getTestData()->path('/');
+ public function testProcessSameDirectory(): void {
+ $path = self::getTestData()->file('Document.md');
$instance = $this->app->make(IncludeDocumentList::class);
- $actual = $instance->process(dirname($path), basename($path));
+ $actual = $instance->process($path->getPathname(), './');
self::assertEquals(
- self::getTestData()->content('.md'),
+ self::getTestData()->content('~SameDirectory.md'),
<<
@@ -27,4 +26,19 @@ public function testProcess(): void {
MARKDOWN,
);
}
+
+ public function testProcessAnotherDirectory(): void {
+ $path = self::getTestData()->file('~AnotherDirectory.md');
+ $instance = $this->app->make(IncludeDocumentList::class);
+ $actual = $instance->process($path->getPathname(), basename(self::getTestData()->path('/')));
+
+ self::assertEquals(
+ self::getTestData()->content('~AnotherDirectory.md'),
+ <<
+
+ {$actual}
+ MARKDOWN,
+ );
+ }
}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document B.md b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document B.md
index a2b9c7123..67675789d 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document B.md
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document B.md
@@ -1,4 +1,4 @@
-# Document
+# Document B
Summary text.
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document.md b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document.md
new file mode 100644
index 000000000..9a246aef7
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/Document.md
@@ -0,0 +1,3 @@
+# Document
+
+Document summary.
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.md b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest~AnotherDirectory.md
similarity index 69%
rename from packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.md
rename to packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest~AnotherDirectory.md
index b1052cd31..57418b25f 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.md
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest~AnotherDirectory.md
@@ -2,12 +2,18 @@
## Document
-Summary text.
+Document summary.
-[Read more]().
+[Read more]().
## Document A
Summary text.
[Read more]().
+
+## Document B
+
+Summary text.
+
+[Read more]().
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest~SameDirectory.md b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest~SameDirectory.md
new file mode 100644
index 000000000..eeceb2f41
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest~SameDirectory.md
@@ -0,0 +1,13 @@
+
+
+## Document A
+
+Summary text.
+
+[Read more]().
+
+## Document B
+
+Summary text.
+
+[Read more]().
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php b/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
index 78c74e9c7..130463951 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
@@ -3,15 +3,14 @@
namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;
use Exception;
-use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PreprocessFailed;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\TargetCommandFailed;
use LastDragon_ru\LaraASP\Documentator\Utils\Path;
use LastDragon_ru\LaraASP\Documentator\Utils\Process;
-use function implode;
+use function dirname;
use function is_file;
use function pathinfo;
use function preg_match_all;
-use function sprintf;
use function trim;
use const PATHINFO_EXTENSION;
@@ -41,15 +40,9 @@ public function process(string $path, string $target): string {
if ($command) {
try {
- $output = $this->process->run($command, $path);
+ $output = $this->process->run($command, dirname($path));
} catch (Exception $exception) {
- throw new PreprocessFailed(
- sprintf(
- 'Failed to execute command `%s`.',
- implode(' ', $command),
- ),
- $exception,
- );
+ throw new TargetCommandFailed($path, $target, $exception);
}
if (preg_match_all('/\R/u', $output) > static::Limit) {
@@ -88,10 +81,10 @@ protected function getLanguage(string $path, string $target): string {
protected function getCommand(string $path, string $target): ?array {
$info = pathinfo($target);
$file = isset($info['dirname'])
- ? "{$info['dirname']}/{$info['filename']}.run"
+ ? Path::join($info['dirname'], "{$info['filename']}.run")
: "{$info['filename']}.run";
- $path = Path::getPath($path, $file);
- $command = is_file($path) ? [$file] : null;
+ $command = Path::getPath(dirname($path), $file);
+ $command = is_file($command) ? [$command] : null;
return $command;
}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest.php b/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest.php
index d5864dd67..083790dec 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeExampleTest.php
@@ -19,7 +19,7 @@
#[CoversClass(IncludeFile::class)]
class IncludeExampleTest extends TestCase {
public function testProcessNoRun(): void {
- $path = dirname(self::getTestData()->path('~example.md'));
+ $path = self::getTestData()->path('~example.md');
$file = basename(self::getTestData()->path('~example.md'));
$expected = trim(self::getTestData()->content('~example.md'));
$process = Mockery::mock(Process::class);
@@ -42,14 +42,14 @@ public function testProcessNoRun(): void {
}
public function testProcess(): void {
- $path = dirname(self::getTestData()->path('~runnable.md'));
- $file = self::getTestData()->path('~runnable.md');
+ $path = self::getTestData()->path('~runnable.md');
+ $file = basename(self::getTestData()->path('~runnable.md'));
$expected = trim(self::getTestData()->content('~runnable.md'));
$output = 'command output';
$process = Mockery::mock(Process::class);
$process
->shouldReceive('run')
- ->with([self::getTestData()->path('~runnable.run')], $path)
+ ->with([self::getTestData()->path('~runnable.run')], dirname($path))
->once()
->andReturn($output);
@@ -74,14 +74,14 @@ public function testProcess(): void {
}
public function testProcessLongOutput(): void {
- $path = dirname(self::getTestData()->path('~runnable.md'));
+ $path = self::getTestData()->path('~runnable.md');
$file = self::getTestData()->path('~runnable.md');
$expected = trim(self::getTestData()->content('~runnable.md'));
$output = implode("\n", range(0, IncludeExample::Limit + 1));
$process = Mockery::mock(Process::class);
$process
->shouldReceive('run')
- ->with([self::getTestData()->path('~runnable.run')], $path)
+ ->with([self::getTestData()->path('~runnable.run')], dirname($path))
->once()
->andReturn($output);
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeFile.php b/packages/documentator/src/Preprocessor/Instructions/IncludeFile.php
index 2a5129df2..30cbd02ca 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeFile.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeFile.php
@@ -2,12 +2,12 @@
namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;
-use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PreprocessFailed;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\TargetIsNotFile;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instruction;
use LastDragon_ru\LaraASP\Documentator\Utils\Path;
+use function dirname;
use function file_get_contents;
-use function sprintf;
class IncludeFile implements Instruction {
public function __construct() {
@@ -19,16 +19,11 @@ public static function getName(): string {
}
public function process(string $path, string $target): string {
- $file = Path::getPath($path, $target);
+ $file = Path::getPath(dirname($path), $target);
$content = file_get_contents($file);
if ($content === false) {
- throw new PreprocessFailed(
- sprintf(
- 'Failed to include `%s`.',
- $target,
- ),
- );
+ throw new TargetIsNotFile($path, $target);
}
return $content;
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeFileTest.php b/packages/documentator/src/Preprocessor/Instructions/IncludeFileTest.php
index 0d7840f56..719d1b03f 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeFileTest.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeFileTest.php
@@ -5,21 +5,17 @@
use LastDragon_ru\LaraASP\Documentator\Testing\Package\TestCase;
use PHPUnit\Framework\Attributes\CoversClass;
-use function basename;
-use function dirname;
-
/**
* @internal
*/
#[CoversClass(IncludeFile::class)]
class IncludeFileTest extends TestCase {
public function testProcessRelative(): void {
- $path = dirname(self::getTestData()->path('.md'));
- $file = basename(self::getTestData()->path('.md'));
+ $file = self::getTestData()->file('.md');
$expected = self::getTestData()->content('.md');
$instance = $this->app->make(IncludeFile::class);
- self::assertEquals($expected, $instance->process($path, $file));
+ self::assertEquals($expected, $instance->process($file->getPathname(), $file->getFilename()));
}
public function testProcessAbsolute(): void {
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php b/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php
index 6ccbf1a62..d9b8c7c29 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php
@@ -4,14 +4,17 @@
use Exception;
use LastDragon_ru\LaraASP\Documentator\Package;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\TargetIsNotDirectory;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instruction;
use LastDragon_ru\LaraASP\Documentator\Utils\Markdown;
use LastDragon_ru\LaraASP\Documentator\Utils\Path;
use Symfony\Component\Finder\Finder;
use function assert;
+use function dirname;
use function file_get_contents;
use function is_array;
+use function is_dir;
use function is_file;
use function is_string;
use function json_decode;
@@ -31,11 +34,18 @@ public static function getName(): string {
}
public function process(string $path, string $target): string {
+ // Directory?
+ $root = Path::getPath(dirname($path), $target);
+
+ if (!is_dir($root)) {
+ throw new TargetIsNotDirectory($path, $target);
+ }
+
/** @var list $packages */
$packages = [];
$directories = Finder::create()
->ignoreVCSIgnored(true)
- ->in(Path::getPath($path, $target))
+ ->in($root)
->depth(0)
->exclude('vendor')
->exclude('node_modules')
@@ -43,20 +53,20 @@ public function process(string $path, string $target): string {
foreach ($directories as $directory) {
// Package?
- $root = $directory->getPathname();
- $package = $this->getPackageInfo($root);
+ $packagePath = $directory->getPathname();
+ $packageInfo = $this->getPackageInfo($packagePath);
- if (!$package) {
+ if (!$packageInfo) {
continue;
}
// Readme
- $readme = $this->getPackageReadme($root, $package);
+ $readme = $this->getPackageReadme($packagePath, $packageInfo);
$content = $readme
- ? file_get_contents("{$root}/{$readme}")
+ ? file_get_contents(Path::join($packagePath, $readme))
: false;
- if ($content === false) {
+ if (!$readme || $content === false) {
continue;
}
@@ -65,7 +75,7 @@ public function process(string $path, string $target): string {
if ($title) {
$packages[] = [
- 'path' => Path::normalize("{$target}/{$directory->getFilename()}/{$readme}"),
+ 'path' => Path::join($target, $directory->getFilename(), $readme),
'title' => $title,
'summary' => Markdown::getSummary($content),
];
@@ -83,8 +93,8 @@ public function process(string $path, string $target): string {
});
// Render
- $package = Package::Name;
- $list = view("{$package}::package-list.markdown", [
+ $packageInfo = Package::Name;
+ $list = view("{$packageInfo}::package-list.markdown", [
'packages' => $packages,
])->render();
@@ -97,7 +107,7 @@ public function process(string $path, string $target): string {
*/
protected function getPackageInfo(string $path): ?array {
try {
- $file = "{$path}/composer.json";
+ $file = Path::join($path, 'composer.json');
$package = is_file($file) ? file_get_contents($file) : false;
$package = $package !== false
? json_decode($package, true, flags: JSON_THROW_ON_ERROR)
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.php b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.php
index f5d7a0a6f..37e9912ca 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.php
@@ -6,7 +6,6 @@
use PHPUnit\Framework\Attributes\CoversClass;
use function basename;
-use function dirname;
/**
* @internal
@@ -14,9 +13,9 @@
#[CoversClass(IncludePackageList::class)]
class IncludePackageListTest extends TestCase {
public function testProcess(): void {
- $path = self::getTestData()->path('/');
+ $path = self::getTestData()->file('.md');
$instance = $this->app->make(IncludePackageList::class);
- $actual = $instance->process(dirname($path), basename($path));
+ $actual = $instance->process($path->getPathname(), basename(self::getTestData()->path('/')));
self::assertEquals(
self::getTestData()->content('.md'),
diff --git a/packages/documentator/src/Utils/Path.php b/packages/documentator/src/Utils/Path.php
index 227229365..ae5d06507 100644
--- a/packages/documentator/src/Utils/Path.php
+++ b/packages/documentator/src/Utils/Path.php
@@ -32,4 +32,8 @@ public static function isAbsolute(string $path): bool {
public static function normalize(string $path): string {
return SymfonyPath::canonicalize($path);
}
+
+ public static function join(string ...$paths): string {
+ return SymfonyPath::join(...$paths);
+ }
}
From ddf643df4b5b4c53d5609624ff9d186c2defb6d1 Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Thu, 24 Aug 2023 09:13:02 +0400
Subject: [PATCH 23/33] `IncludeCommand` => `IncludeExec`.
---
.../{TargetCommandFailed.php => TargetExecFailed.php} | 2 +-
.../src/Preprocessor/Instructions/IncludeExample.php | 4 ++--
.../Instructions/{IncludeCommand.php => IncludeExec.php} | 8 ++++----
.../{IncludeCommandTest.php => IncludeExecTest.php} | 4 ++--
packages/documentator/src/Preprocessor/Preprocessor.php | 6 +++---
5 files changed, 12 insertions(+), 12 deletions(-)
rename packages/documentator/src/Preprocessor/Exceptions/{TargetCommandFailed.php => TargetExecFailed.php} (90%)
rename packages/documentator/src/Preprocessor/Instructions/{IncludeCommand.php => IncludeExec.php} (83%)
rename packages/documentator/src/Preprocessor/Instructions/{IncludeCommandTest.php => IncludeExecTest.php} (89%)
diff --git a/packages/documentator/src/Preprocessor/Exceptions/TargetCommandFailed.php b/packages/documentator/src/Preprocessor/Exceptions/TargetExecFailed.php
similarity index 90%
rename from packages/documentator/src/Preprocessor/Exceptions/TargetCommandFailed.php
rename to packages/documentator/src/Preprocessor/Exceptions/TargetExecFailed.php
index 2107a3de8..84d25ae93 100644
--- a/packages/documentator/src/Preprocessor/Exceptions/TargetCommandFailed.php
+++ b/packages/documentator/src/Preprocessor/Exceptions/TargetExecFailed.php
@@ -6,7 +6,7 @@
use function sprintf;
-class TargetCommandFailed extends InstructionFailed {
+class TargetExecFailed extends InstructionFailed {
public function __construct(string $path, string $target, Throwable $previous = null) {
parent::__construct(
$path,
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php b/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
index 130463951..10afb71ab 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
@@ -3,7 +3,7 @@
namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;
use Exception;
-use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\TargetCommandFailed;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\TargetExecFailed;
use LastDragon_ru\LaraASP\Documentator\Utils\Path;
use LastDragon_ru\LaraASP\Documentator\Utils\Process;
@@ -42,7 +42,7 @@ public function process(string $path, string $target): string {
try {
$output = $this->process->run($command, dirname($path));
} catch (Exception $exception) {
- throw new TargetCommandFailed($path, $target, $exception);
+ throw new TargetExecFailed($path, $target, $exception);
}
if (preg_match_all('/\R/u', $output) > static::Limit) {
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeCommand.php b/packages/documentator/src/Preprocessor/Instructions/IncludeExec.php
similarity index 83%
rename from packages/documentator/src/Preprocessor/Instructions/IncludeCommand.php
rename to packages/documentator/src/Preprocessor/Instructions/IncludeExec.php
index a83816cca..f681e8708 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeCommand.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeExec.php
@@ -3,14 +3,14 @@
namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;
use Exception;
-use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\TargetCommandFailed;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\TargetExecFailed;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instruction;
use LastDragon_ru\LaraASP\Documentator\Utils\Process;
use function dirname;
use function explode;
-class IncludeCommand implements Instruction {
+class IncludeExec implements Instruction {
public function __construct(
protected readonly Process $process,
) {
@@ -18,7 +18,7 @@ public function __construct(
}
public static function getName(): string {
- return 'include:command';
+ return 'include:exec';
}
public function process(string $path, string $target): string {
@@ -28,7 +28,7 @@ public function process(string $path, string $target): string {
dirname($path),
);
} catch (Exception $exception) {
- throw new TargetCommandFailed($path, $target, $exception);
+ throw new TargetExecFailed($path, $target, $exception);
}
}
}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeCommandTest.php b/packages/documentator/src/Preprocessor/Instructions/IncludeExecTest.php
similarity index 89%
rename from packages/documentator/src/Preprocessor/Instructions/IncludeCommandTest.php
rename to packages/documentator/src/Preprocessor/Instructions/IncludeExecTest.php
index 482384436..13dbc34c8 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeCommandTest.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeExecTest.php
@@ -13,7 +13,7 @@
* @internal
*/
#[CoversClass(IncludeFile::class)]
-class IncludeCommandTest extends TestCase {
+class IncludeExecTest extends TestCase {
public function testProcess(): void {
$path = 'current/working/directory/file.md';
$expected = 'result';
@@ -25,7 +25,7 @@ public function testProcess(): void {
->once()
->andReturn($expected);
- $instance = $this->app->make(IncludeCommand::class, [
+ $instance = $this->app->make(IncludeExec::class, [
'process' => $process,
]);
diff --git a/packages/documentator/src/Preprocessor/Preprocessor.php b/packages/documentator/src/Preprocessor/Preprocessor.php
index 5058d2330..9daabbc0f 100644
--- a/packages/documentator/src/Preprocessor/Preprocessor.php
+++ b/packages/documentator/src/Preprocessor/Preprocessor.php
@@ -4,9 +4,9 @@
use Illuminate\Container\Container;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PreprocessFailed;
-use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeCommand;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeDocumentList;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeExample;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeExec;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeFile;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludePackageList;
use LastDragon_ru\LaraASP\Documentator\Utils\Path;
@@ -29,7 +29,7 @@
* | `` | `` | Description |
* |-------------------|--------------------------------|----------------------------------------------------------|
* | `include:file` | path to the file | Include content of the file as is. |
- * | `include:command` | the command to execute | Execute the command and include output. |
+ * | `include:exec` | the command to execute | Execute the command and include output. |
* | `include:example` | path to the example file | Include file in the code block + its output if possible. |
*
* Limitations:
@@ -62,7 +62,7 @@ class Preprocessor {
public function __construct() {
$this->addInstruction(IncludeFile::class);
- $this->addInstruction(IncludeCommand::class);
+ $this->addInstruction(IncludeExec::class);
$this->addInstruction(IncludeExample::class);
$this->addInstruction(IncludePackageList::class);
$this->addInstruction(IncludeDocumentList::class);
From 9b780a4d343dec8661c7092bdcb5a8fa9163c3e0 Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Thu, 24 Aug 2023 10:03:47 +0400
Subject: [PATCH 24/33] `IncludeDocumentList`/`IncludePackageList` will report
error instead ignoring.
---
.../Exceptions/DocumentTitleIsMissing.php | 31 +++++++++
.../PackageComposerJsonIsMissing.php | 31 +++++++++
.../Exceptions/PackageReadmeIsMissing.php | 31 +++++++++
.../Instructions/IncludeDocumentList.php | 3 +
.../Instructions/IncludeDocumentListTest.php | 17 +++++
.../invalid/Document.md | 3 +
.../{ => invalid}/WithoutTitle.md | 0
.../Instructions/IncludePackageList.php | 22 +++---
.../Instructions/IncludePackageListTest.md | 4 +-
.../Instructions/IncludePackageListTest.php | 56 ++++++++++++++-
.../package}/README.md | 0
.../package}/composer.json | 0
.../package}/README.md | 0
.../{ => no title}/package/composer.json | 0
.../package custom readme/CUSTOM.md | 0
.../package custom readme/README.md | 0
.../package custom readme/composer.json | 0
.../{ => packages}/package/README.md | 0
.../packages/package/composer.json | 5 ++
.../src/Preprocessor/Preprocessor.php | 69 +++++++++++--------
20 files changed, 230 insertions(+), 42 deletions(-)
create mode 100644 packages/documentator/src/Preprocessor/Exceptions/DocumentTitleIsMissing.php
create mode 100644 packages/documentator/src/Preprocessor/Exceptions/PackageComposerJsonIsMissing.php
create mode 100644 packages/documentator/src/Preprocessor/Exceptions/PackageReadmeIsMissing.php
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/invalid/Document.md
rename packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/{ => invalid}/WithoutTitle.md (100%)
rename packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/{not a package => invalid/package}/README.md (100%)
rename packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/{package no title => no readme/package}/composer.json (100%)
rename packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/{package no title => no title/package}/README.md (100%)
rename packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/{ => no title}/package/composer.json (100%)
rename packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/{ => packages}/package custom readme/CUSTOM.md (100%)
rename packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/{ => packages}/package custom readme/README.md (100%)
rename packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/{ => packages}/package custom readme/composer.json (100%)
rename packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/{ => packages}/package/README.md (100%)
create mode 100644 packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/packages/package/composer.json
diff --git a/packages/documentator/src/Preprocessor/Exceptions/DocumentTitleIsMissing.php b/packages/documentator/src/Preprocessor/Exceptions/DocumentTitleIsMissing.php
new file mode 100644
index 000000000..2ac043cde
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Exceptions/DocumentTitleIsMissing.php
@@ -0,0 +1,31 @@
+document,
+ $path,
+ ),
+ $previous,
+ );
+ }
+
+ public function getDocument(): string {
+ return $this->document;
+ }
+}
diff --git a/packages/documentator/src/Preprocessor/Exceptions/PackageComposerJsonIsMissing.php b/packages/documentator/src/Preprocessor/Exceptions/PackageComposerJsonIsMissing.php
new file mode 100644
index 000000000..1f839d3fb
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Exceptions/PackageComposerJsonIsMissing.php
@@ -0,0 +1,31 @@
+package,
+ $path,
+ ),
+ $previous,
+ );
+ }
+
+ public function getPackage(): string {
+ return $this->package;
+ }
+}
diff --git a/packages/documentator/src/Preprocessor/Exceptions/PackageReadmeIsMissing.php b/packages/documentator/src/Preprocessor/Exceptions/PackageReadmeIsMissing.php
new file mode 100644
index 000000000..9ef99f9d6
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Exceptions/PackageReadmeIsMissing.php
@@ -0,0 +1,31 @@
+package,
+ $path,
+ ),
+ $previous,
+ );
+ }
+
+ public function getPackage(): string {
+ return $this->package;
+ }
+}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentList.php b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentList.php
index 3b2d62a2d..2d7da43b5 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentList.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentList.php
@@ -3,6 +3,7 @@
namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;
use LastDragon_ru\LaraASP\Documentator\Package;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\DocumentTitleIsMissing;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\TargetIsNotDirectory;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instruction;
use LastDragon_ru\LaraASP\Documentator\Utils\Markdown;
@@ -65,6 +66,8 @@ public function process(string $path, string $target): string {
'title' => $title,
'summary' => Markdown::getSummary($content),
];
+ } else {
+ throw new DocumentTitleIsMissing($path, $target, Path::join($target, $file->getFilename()));
}
}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.php b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.php
index 4d926a220..34661e2bc 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest.php
@@ -2,6 +2,7 @@
namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\DocumentTitleIsMissing;
use LastDragon_ru\LaraASP\Documentator\Testing\Package\TestCase;
use PHPUnit\Framework\Attributes\CoversClass;
@@ -41,4 +42,20 @@ public function testProcessAnotherDirectory(): void {
MARKDOWN,
);
}
+
+ public function testProcessWithoutTitle(): void {
+ $path = self::getTestData()->file('invalid/Document.md');
+ $target = './';
+ $instance = $this->app->make(IncludeDocumentList::class);
+
+ self::expectExceptionObject(
+ new DocumentTitleIsMissing(
+ $path->getPathname(),
+ $target,
+ 'WithoutTitle.md',
+ ),
+ );
+
+ $instance->process($path->getPathname(), $target);
+ }
}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/invalid/Document.md b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/invalid/Document.md
new file mode 100644
index 000000000..9a246aef7
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/invalid/Document.md
@@ -0,0 +1,3 @@
+# Document
+
+Document summary.
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/WithoutTitle.md b/packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/invalid/WithoutTitle.md
similarity index 100%
rename from packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/WithoutTitle.md
rename to packages/documentator/src/Preprocessor/Instructions/IncludeDocumentListTest/invalid/WithoutTitle.md
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php b/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php
index d9b8c7c29..a1eda3f20 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php
@@ -4,6 +4,9 @@
use Exception;
use LastDragon_ru\LaraASP\Documentator\Package;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\DocumentTitleIsMissing;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PackageComposerJsonIsMissing;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PackageReadmeIsMissing;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\TargetIsNotDirectory;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instruction;
use LastDragon_ru\LaraASP\Documentator\Utils\Markdown;
@@ -51,13 +54,13 @@ public function process(string $path, string $target): string {
->exclude('node_modules')
->directories();
- foreach ($directories as $directory) {
+ foreach ($directories as $package) {
// Package?
- $packagePath = $directory->getPathname();
+ $packagePath = $package->getPathname();
$packageInfo = $this->getPackageInfo($packagePath);
if (!$packageInfo) {
- continue;
+ throw new PackageComposerJsonIsMissing($path, $target, Path::join($target, $package->getFilename()));
}
// Readme
@@ -67,18 +70,21 @@ public function process(string $path, string $target): string {
: false;
if (!$readme || $content === false) {
- continue;
+ throw new PackageReadmeIsMissing($path, $target, Path::join($target, $package->getFilename()));
}
// Extract
- $title = Markdown::getTitle($content);
+ $packageTitle = Markdown::getTitle($content);
+ $readmePath = Path::join($target, $package->getFilename(), $readme);
- if ($title) {
+ if ($packageTitle) {
$packages[] = [
- 'path' => Path::join($target, $directory->getFilename(), $readme),
- 'title' => $title,
+ 'path' => $readmePath,
+ 'title' => $packageTitle,
'summary' => Markdown::getSummary($content),
];
+ } else {
+ throw new DocumentTitleIsMissing($path, $target, $readmePath);
}
}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.md b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.md
index b7b49deaf..ede1f959b 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.md
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.md
@@ -4,8 +4,8 @@
Summary text.
-[Read more]().
+[Read more]().
## The Package with custom readme
-[Read more]().
+[Read more]().
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.php b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.php
index 37e9912ca..50a97c4a2 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest.php
@@ -2,6 +2,9 @@
namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\DocumentTitleIsMissing;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PackageComposerJsonIsMissing;
+use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PackageReadmeIsMissing;
use LastDragon_ru\LaraASP\Documentator\Testing\Package\TestCase;
use PHPUnit\Framework\Attributes\CoversClass;
@@ -13,9 +16,10 @@
#[CoversClass(IncludePackageList::class)]
class IncludePackageListTest extends TestCase {
public function testProcess(): void {
- $path = self::getTestData()->file('.md');
+ $path = self::getTestData()->file('Document.md')->getPathname();
+ $target = basename(self::getTestData()->path('/packages'));
$instance = $this->app->make(IncludePackageList::class);
- $actual = $instance->process($path->getPathname(), basename(self::getTestData()->path('/')));
+ $actual = $instance->process($path, $target);
self::assertEquals(
self::getTestData()->content('.md'),
@@ -26,4 +30,52 @@ public function testProcess(): void {
MARKDOWN,
);
}
+
+ public function testProcessNotAPackage(): void {
+ $path = self::getTestData()->file('Document.md')->getPathname();
+ $target = basename(self::getTestData()->path('/invalid'));
+ $instance = $this->app->make(IncludePackageList::class);
+
+ self::expectExceptionObject(
+ new PackageComposerJsonIsMissing(
+ $path,
+ $target,
+ 'invalid/package',
+ ),
+ );
+
+ $instance->process($path, $target);
+ }
+
+ public function testProcessNoReadme(): void {
+ $path = self::getTestData()->file('Document.md')->getPathname();
+ $target = basename(self::getTestData()->path('/no readme'));
+ $instance = $this->app->make(IncludePackageList::class);
+
+ self::expectExceptionObject(
+ new PackageReadmeIsMissing(
+ $path,
+ $target,
+ 'no readme/package',
+ ),
+ );
+
+ $instance->process($path, $target);
+ }
+
+ public function testProcessNoTitle(): void {
+ $path = self::getTestData()->file('Document.md')->getPathname();
+ $target = basename(self::getTestData()->path('/no title'));
+ $instance = $this->app->make(IncludePackageList::class);
+
+ self::expectExceptionObject(
+ new DocumentTitleIsMissing(
+ $path,
+ $target,
+ 'no title/package/README.md',
+ ),
+ );
+
+ $instance->process($path, $target);
+ }
}
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/not a package/README.md b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/invalid/package/README.md
similarity index 100%
rename from packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/not a package/README.md
rename to packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/invalid/package/README.md
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package no title/composer.json b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/no readme/package/composer.json
similarity index 100%
rename from packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package no title/composer.json
rename to packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/no readme/package/composer.json
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package no title/README.md b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/no title/package/README.md
similarity index 100%
rename from packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package no title/README.md
rename to packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/no title/package/README.md
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package/composer.json b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/no title/package/composer.json
similarity index 100%
rename from packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package/composer.json
rename to packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/no title/package/composer.json
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/CUSTOM.md b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/packages/package custom readme/CUSTOM.md
similarity index 100%
rename from packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/CUSTOM.md
rename to packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/packages/package custom readme/CUSTOM.md
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/README.md b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/packages/package custom readme/README.md
similarity index 100%
rename from packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/README.md
rename to packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/packages/package custom readme/README.md
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/composer.json b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/packages/package custom readme/composer.json
similarity index 100%
rename from packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package custom readme/composer.json
rename to packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/packages/package custom readme/composer.json
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package/README.md b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/packages/package/README.md
similarity index 100%
rename from packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/package/README.md
rename to packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/packages/package/README.md
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/packages/package/composer.json b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/packages/package/composer.json
new file mode 100644
index 000000000..0a9113a4a
--- /dev/null
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageListTest/packages/package/composer.json
@@ -0,0 +1,5 @@
+{
+ "name": "lastdragon-ru/lara-asp-documentator",
+ "homepage": "https://github.com/LastDragon-ru/lara-asp",
+ "readme": "README.md"
+}
diff --git a/packages/documentator/src/Preprocessor/Preprocessor.php b/packages/documentator/src/Preprocessor/Preprocessor.php
index 9daabbc0f..6efc872e2 100644
--- a/packages/documentator/src/Preprocessor/Preprocessor.php
+++ b/packages/documentator/src/Preprocessor/Preprocessor.php
@@ -2,6 +2,7 @@
namespace LastDragon_ru\LaraASP\Documentator\Preprocessor;
+use Exception;
use Illuminate\Container\Container;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PreprocessFailed;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeDocumentList;
@@ -96,53 +97,61 @@ protected function getInstruction(string $name): ?Instruction {
public function process(string $path, string $string): string {
$path = Path::normalize($path);
$cache = [];
- $result = preg_replace_callback(
- pattern : static::Regexp,
- callback: function (array $matches) use (&$cache, $path): string {
- $hash = $this->getHash("{$matches['instruction']}={$matches['target']}");
- $content = $cache[$hash] ?? null;
- $instruction = $this->getInstruction($matches['instruction']);
-
- if ($content === null) {
- $target = rawurldecode($matches['target']);
- $content = trim($instruction?->process($path, $target) ?? '');
- $cache[$hash] = $content;
- }
-
- // Return
- $warning = static::Warning;
- $prefix = <<getHash("{$matches['instruction']}={$matches['target']}");
+ $content = $cache[$hash] ?? null;
+ $instruction = $this->getInstruction($matches['instruction']);
+
+ if ($content === null) {
+ $target = rawurldecode($matches['target']);
+ $content = trim($instruction?->process($path, $target) ?? '');
+ $cache[$hash] = $content;
+ }
+
+ // Return
+ $warning = static::Warning;
+ $prefix = <<
Date: Thu, 24 Aug 2023 10:40:46 +0400
Subject: [PATCH 25/33] Command description moved to `AsCommand` Attribute.
---
packages/documentator/src/Commands/Preprocess.php | 11 ++++-------
packages/documentator/src/Commands/Requirements.php | 11 ++++-------
2 files changed, 8 insertions(+), 14 deletions(-)
diff --git a/packages/documentator/src/Commands/Preprocess.php b/packages/documentator/src/Commands/Preprocess.php
index e23513ef6..c8bc8b3e7 100644
--- a/packages/documentator/src/Commands/Preprocess.php
+++ b/packages/documentator/src/Commands/Preprocess.php
@@ -12,16 +12,13 @@
use function file_put_contents;
use function getcwd;
-#[AsCommand(name: Preprocess::Name)]
+#[AsCommand(
+ name : Preprocess::Name,
+ description: 'Preprocess Markdown files.',
+)]
class Preprocess extends Command {
public const Name = Package::Name.':preprocess';
- /**
- * @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint
- * @var string|null
- */
- public $description = 'Preprocess Markdown files.';
-
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint
* @var string
diff --git a/packages/documentator/src/Commands/Requirements.php b/packages/documentator/src/Commands/Requirements.php
index aedd8b4bf..fefcf4c2e 100644
--- a/packages/documentator/src/Commands/Requirements.php
+++ b/packages/documentator/src/Commands/Requirements.php
@@ -32,16 +32,13 @@
use const JSON_THROW_ON_ERROR;
-#[AsCommand(name: Requirements::Name)]
+#[AsCommand(
+ name : Requirements::Name,
+ description: 'Generates a table with the required versions of PHP/Laravel in Markdown format.',
+)]
class Requirements extends Command {
public const Name = Package::Name.':requirements';
- /**
- * @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint
- * @var string|null
- */
- public $description = 'Generates a table with the required versions of PHP/Laravel in Markdown format.';
-
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint
* @var string
From bcaabf6bce239d8a71f60df19339f2bdbdc4505a Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Thu, 24 Aug 2023 11:31:26 +0400
Subject: [PATCH 26/33] `Preprocess` command will return help with all
available Instructions.
---
.../documentator/src/Commands/Preprocess.php | 69 +++++++++++++++++++
.../src/Preprocessor/Instruction.php | 4 ++
.../Instructions/IncludeDocumentList.php | 12 ++++
.../Instructions/IncludeExample.php | 12 ++++
.../Preprocessor/Instructions/IncludeExec.php | 8 +++
.../Preprocessor/Instructions/IncludeFile.php | 8 +++
.../Instructions/IncludePackageList.php | 11 +++
.../src/Preprocessor/Preprocessor.php | 20 +++---
.../src/Preprocessor/PreprocessorTest.php | 8 +++
9 files changed, 144 insertions(+), 8 deletions(-)
diff --git a/packages/documentator/src/Commands/Preprocess.php b/packages/documentator/src/Commands/Preprocess.php
index c8bc8b3e7..11ef23e59 100644
--- a/packages/documentator/src/Commands/Preprocess.php
+++ b/packages/documentator/src/Commands/Preprocess.php
@@ -3,6 +3,7 @@
namespace LastDragon_ru\LaraASP\Documentator\Commands;
use Illuminate\Console\Command;
+use Illuminate\Container\Container;
use LastDragon_ru\LaraASP\Core\Utils\Cast;
use LastDragon_ru\LaraASP\Documentator\Package;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Preprocessor;
@@ -11,7 +12,13 @@
use function file_put_contents;
use function getcwd;
+use function implode;
+use function ksort;
+use function strtr;
+/**
+ * @see Preprocessor
+ */
#[AsCommand(
name : Preprocess::Name,
description: 'Preprocess Markdown files.',
@@ -19,6 +26,30 @@
class Preprocess extends Command {
public const Name = Package::Name.':preprocess';
+ /**
+ * @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint
+ * @var string
+ */
+ public $help = <<<'HELP'
+ Replaces special instructions in Markdown.
+
+ ```plain
+ []:
+ [=name]:
+ ```
+
+ ### Supported instructions:
+
+ %instructions%
+
+ ### Limitations:
+
+ * `` will be processed everywhere in the file (eg within
+ the code block) and may give unpredictable results.
+ * `` cannot be inside text.
+ * Nested `` doesn't support.
+ HELP;
+
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint
* @var string
@@ -49,4 +80,42 @@ public function __invoke(Preprocessor $preprocessor): void {
});
}
}
+
+ public function getProcessedHelp(): string {
+ return strtr(parent::getProcessedHelp(), [
+ '%instructions%' => $this->getInstructionsHelp(),
+ ]);
+ }
+
+ protected function getInstructionsHelp(): string {
+ $preprocessor = Container::getInstance()->make(Preprocessor::class);
+ $instructions = $preprocessor->getInstructions();
+ $help = [];
+
+ foreach ($instructions as $instruction) {
+ $name = $instruction::getName();
+ $desc = $instruction::getDescription();
+ $target = $instruction::getTargetDescription();
+
+ if ($target !== null) {
+ $help[$name] = <<` - {$target}
+
+ {$desc}
+ HELP;
+ } else {
+ $help[$name] = <<` directory. Each file
+ must have `# Header` as the first construction. The first paragraph
+ after the Header will be used as a summary.
+ DESC;
+ }
+
+ public static function getTargetDescription(): ?string {
+ return 'Directory path.';
+ }
+
public function process(string $path, string $target): string {
// Directory?
$root = Path::getPath(dirname($path), $target);
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php b/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
index 10afb71ab..216ae3293 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeExample.php
@@ -28,6 +28,18 @@ public static function getName(): string {
return 'include:example';
}
+ public static function getDescription(): string {
+ return <<<'DESC'
+ Includes contents of the `` file as an example wrapped into
+ ` ```code block``` `. It also searches for `.run` file, execute
+ it if found, and include its result right after the code block.
+ DESC;
+ }
+
+ public static function getTargetDescription(): ?string {
+ return 'Example file path.';
+ }
+
public function process(string $path, string $target): string {
$language = $this->getLanguage($path, $target);
$content = trim(parent::process($path, $target));
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeExec.php b/packages/documentator/src/Preprocessor/Instructions/IncludeExec.php
index f681e8708..0ff90ff60 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeExec.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeExec.php
@@ -21,6 +21,14 @@ public static function getName(): string {
return 'include:exec';
}
+ public static function getDescription(): string {
+ return 'Executes the `` and returns result.';
+ }
+
+ public static function getTargetDescription(): ?string {
+ return 'Path to the executable.';
+ }
+
public function process(string $path, string $target): string {
try {
return $this->process->run(
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludeFile.php b/packages/documentator/src/Preprocessor/Instructions/IncludeFile.php
index 30cbd02ca..e6e7ed65c 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludeFile.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludeFile.php
@@ -18,6 +18,14 @@ public static function getName(): string {
return 'include:file';
}
+ public static function getDescription(): string {
+ return 'Includes the `` file.';
+ }
+
+ public static function getTargetDescription(): ?string {
+ return 'File path.';
+ }
+
public function process(string $path, string $target): string {
$file = Path::getPath(dirname($path), $target);
$content = file_get_contents($file);
diff --git a/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php b/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php
index a1eda3f20..ef0e0f20e 100644
--- a/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php
+++ b/packages/documentator/src/Preprocessor/Instructions/IncludePackageList.php
@@ -36,6 +36,17 @@ public static function getName(): string {
return 'include:package-list';
}
+ public static function getDescription(): string {
+ return <<<'DESC'
+ Generates package list from `` directory. The readme file will be
+ used to determine package name and summary.
+ DESC;
+ }
+
+ public static function getTargetDescription(): ?string {
+ return 'Directory path.';
+ }
+
public function process(string $path, string $target): string {
// Directory?
$root = Path::getPath(dirname($path), $target);
diff --git a/packages/documentator/src/Preprocessor/Preprocessor.php b/packages/documentator/src/Preprocessor/Preprocessor.php
index 6efc872e2..3eec64d0f 100644
--- a/packages/documentator/src/Preprocessor/Preprocessor.php
+++ b/packages/documentator/src/Preprocessor/Preprocessor.php
@@ -4,6 +4,7 @@
use Exception;
use Illuminate\Container\Container;
+use LastDragon_ru\LaraASP\Documentator\Commands\Preprocess;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PreprocessFailed;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeDocumentList;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeExample;
@@ -12,6 +13,7 @@
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludePackageList;
use LastDragon_ru\LaraASP\Documentator\Utils\Path;
+use function array_column;
use function preg_replace_callback;
use function rawurldecode;
use function sha1;
@@ -25,14 +27,6 @@
* []:
* [=name]:
*
- * Supported instructions:
- *
- * | `` | `` | Description |
- * |-------------------|--------------------------------|----------------------------------------------------------|
- * | `include:file` | path to the file | Include content of the file as is. |
- * | `include:exec` | the command to execute | Execute the command and include output. |
- * | `include:example` | path to the example file | Include file in the code block + its output if possible. |
- *
* Limitations:
* - `` will be processed everywhere in the file (eg within the code
* block) and may give unpredictable results.
@@ -40,6 +34,9 @@
* - Nested `` doesn't supported.
*
* @todo Use https://github.com/thephpleague/commonmark?
+ * @todo Sync with {@see Preprocess} command
+ *
+ * @see Preprocess
*/
class Preprocessor {
protected const Warning = 'Generated automatically. Do not edit.';
@@ -69,6 +66,13 @@ public function __construct() {
$this->addInstruction(IncludeDocumentList::class);
}
+ /**
+ * @return list>
+ */
+ public function getInstructions(): array {
+ return array_column($this->instructions, 0);
+ }
+
/**
* @param Instruction|class-string $instruction
*/
diff --git a/packages/documentator/src/Preprocessor/PreprocessorTest.php b/packages/documentator/src/Preprocessor/PreprocessorTest.php
index 0a46077cf..f1a1e0ded 100644
--- a/packages/documentator/src/Preprocessor/PreprocessorTest.php
+++ b/packages/documentator/src/Preprocessor/PreprocessorTest.php
@@ -47,6 +47,14 @@ public static function getName(): string {
return 'empty';
}
+ public static function getDescription(): string {
+ return '';
+ }
+
+ public static function getTargetDescription(): ?string {
+ return '';
+ }
+
public function process(string $path, string $target): string {
return '';
}
From 7c69e0857b1dae1d9689e4f30b4c2917a2c9b28a Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Thu, 24 Aug 2023 13:23:10 +0400
Subject: [PATCH 27/33] `Markdown` will allow comments before Header and
Summary.
---
packages/documentator/src/Utils/Markdown.php | 54 ++++++++++++++++---
.../documentator/src/Utils/MarkdownTest.php | 30 +++++++++++
2 files changed, 77 insertions(+), 7 deletions(-)
diff --git a/packages/documentator/src/Utils/Markdown.php b/packages/documentator/src/Utils/Markdown.php
index f0386bf41..9063a2ca6 100644
--- a/packages/documentator/src/Utils/Markdown.php
+++ b/packages/documentator/src/Utils/Markdown.php
@@ -3,16 +3,20 @@
namespace LastDragon_ru\LaraASP\Documentator\Utils;
use League\CommonMark\Extension\CommonMark\Node\Block\Heading;
+use League\CommonMark\Extension\CommonMark\Node\Block\HtmlBlock;
use League\CommonMark\GithubFlavoredMarkdownConverter;
use League\CommonMark\Node\Block\AbstractBlock;
use League\CommonMark\Node\Block\Document;
use League\CommonMark\Node\Block\Paragraph;
+use League\CommonMark\Node\Node;
use League\CommonMark\Parser\MarkdownParser;
use function array_slice;
use function implode;
use function ltrim;
use function preg_split;
+use function str_ends_with;
+use function str_starts_with;
use function trim;
class Markdown {
@@ -31,9 +35,10 @@ public static function getTitle(string $string): ?string {
* Returns the first paragraph right after `# Header` if present.
*/
public static function getSummary(string $string): ?string {
- $node = static::getTitleNode($string)?->next();
- $summary = $node instanceof Paragraph
- ? static::getText($string, $node)
+ $title = static::getTitleNode($string);
+ $summary = static::getFirstNode($title?->next(), Paragraph::class);
+ $summary = $summary
+ ? static::getText($string, $summary)
: null;
return $summary;
@@ -48,10 +53,8 @@ protected static function getDocumentNode(string $string): Document {
}
protected static function getTitleNode(string $string): ?Heading {
- $node = static::getDocumentNode($string)->firstChild();
- $header = $node instanceof Heading && $node->getLevel() === 1
- ? $node
- : null;
+ $document = static::getDocumentNode($string);
+ $header = static::getFirstNode($document, Heading::class, static fn ($n) => $n->getLevel() === 1);
return $header;
}
@@ -71,4 +74,41 @@ protected static function getText(string $string, ?AbstractBlock $node): ?string
return $text;
}
+
+ /**
+ * @template T of Node
+ *
+ * @param class-string $class
+ * @param callable(T): bool $filter
+ *
+ * @return ?T
+ */
+ protected static function getFirstNode(?Node $node, string $class, callable $filter = null): ?Node {
+ // Null?
+ if ($node === null) {
+ return null;
+ }
+
+ // Wanted?
+ if ($node instanceof $class && ($filter === null || $filter($node))) {
+ return $node;
+ }
+
+ // Comment?
+ if (
+ $node instanceof HtmlBlock
+ && str_starts_with($node->getLiteral(), '')
+ ) {
+ return static::getFirstNode($node->next(), $class, $filter);
+ }
+
+ // Document?
+ if ($node instanceof Document) {
+ return static::getFirstNode($node->firstChild(), $class, $filter);
+ }
+
+ // Not found
+ return null;
+ }
}
diff --git a/packages/documentator/src/Utils/MarkdownTest.php b/packages/documentator/src/Utils/MarkdownTest.php
index 7912aec32..0973db750 100644
--- a/packages/documentator/src/Utils/MarkdownTest.php
+++ b/packages/documentator/src/Utils/MarkdownTest.php
@@ -44,6 +44,18 @@ public function testGetTitle(): void {
# Header
+ fsdfsdfsdf
+ MARKDOWN,
+ ),
+ );
+ self::assertEquals(
+ 'Header',
+ Markdown::getTitle(
+ <<<'MARKDOWN'
+
+
+ # Header
+
fsdfsdfsdf
MARKDOWN,
),
@@ -103,6 +115,24 @@ public function testGetSummary(): void {
# Header
+ fsdfsdfsdf
+ fsdfsdfsdf
+ MARKDOWN,
+ ),
+ );
+ self::assertEquals(
+ <<<'TEXT'
+ fsdfsdfsdf
+ fsdfsdfsdf
+ TEXT,
+ Markdown::getSummary(
+ <<<'MARKDOWN'
+
+
+ # Header
+
+
+
fsdfsdfsdf
fsdfsdfsdf
MARKDOWN,
From 87c7dec3718d955321d3a317025e971f4efe6d34 Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Thu, 24 Aug 2023 13:54:47 +0400
Subject: [PATCH 28/33] `Preprocess` command will use
`Symfony\Component\Filesystem\Filesystem` instead of `file_put_contents`.
---
.../documentator/src/Commands/Preprocess.php | 24 +++++++++++--------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/packages/documentator/src/Commands/Preprocess.php b/packages/documentator/src/Commands/Preprocess.php
index 11ef23e59..29bf08ebc 100644
--- a/packages/documentator/src/Commands/Preprocess.php
+++ b/packages/documentator/src/Commands/Preprocess.php
@@ -8,9 +8,9 @@
use LastDragon_ru\LaraASP\Documentator\Package;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Preprocessor;
use Symfony\Component\Console\Attribute\AsCommand;
+use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
-use function file_put_contents;
use function getcwd;
use function implode;
use function ksort;
@@ -58,7 +58,7 @@ class Preprocess extends Command {
{path? : directory to process}
SIGNATURE;
- public function __invoke(Preprocessor $preprocessor): void {
+ public function __invoke(Filesystem $filesystem, Preprocessor $preprocessor): void {
$cwd = getcwd();
$path = Cast::toString($this->argument('path') ?? $cwd);
$finder = Finder::create()
@@ -70,14 +70,18 @@ public function __invoke(Preprocessor $preprocessor): void {
->name('*.md');
foreach ($finder as $file) {
- $this->components->task($file->getPathname(), static function () use ($preprocessor, $file): bool {
- $path = $file->getPathname();
- $content = $file->getContents();
- $result = $preprocessor->process($path, $content);
-
- return $content === $result
- || file_put_contents($path, $result) !== false;
- });
+ $this->components->task(
+ $file->getPathname(),
+ static function () use ($filesystem, $preprocessor, $file): void {
+ $path = $file->getPathname();
+ $content = $file->getContents();
+ $result = $preprocessor->process($path, $content);
+
+ if ($content !== $result) {
+ $filesystem->dumpFile($path, $content);
+ }
+ },
+ );
}
}
From 6de62b4b49ca737aa4da7a68eb99471fe3ac50bc Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Fri, 25 Aug 2023 10:52:06 +0400
Subject: [PATCH 29/33] feat(documentator): Command
`lara-asp-documentator:commands` to save commands help into Markdown files.
---
packages/core/src/Utils/Cast.php | 13 ++
.../views/commands/markdown.blade.php | 47 ++++++
.../documentator/src/Commands/Commands.php | 92 ++++++++++++
.../src/Commands/CommandsTest.php | 142 ++++++++++++++++++
.../src/Commands/CommandsTest~a.md | 27 ++++
.../src/Commands/CommandsTest~b.md | 10 ++
packages/documentator/src/Provider.php | 2 +
.../src/Utils/ArtisanSerializer.php | 85 +++++++++++
.../src/Utils/ArtisanSerializerTest.php | 45 ++++++
9 files changed, 463 insertions(+)
create mode 100644 packages/documentator/resources/views/commands/markdown.blade.php
create mode 100644 packages/documentator/src/Commands/Commands.php
create mode 100644 packages/documentator/src/Commands/CommandsTest.php
create mode 100644 packages/documentator/src/Commands/CommandsTest~a.md
create mode 100644 packages/documentator/src/Commands/CommandsTest~b.md
create mode 100644 packages/documentator/src/Utils/ArtisanSerializer.php
create mode 100644 packages/documentator/src/Utils/ArtisanSerializerTest.php
diff --git a/packages/core/src/Utils/Cast.php b/packages/core/src/Utils/Cast.php
index 9a333dd4d..3d70f4787 100644
--- a/packages/core/src/Utils/Cast.php
+++ b/packages/core/src/Utils/Cast.php
@@ -63,4 +63,17 @@ public static function toIterable(mixed $value): iterable {
return $value;
}
+
+ /**
+ * @template T of object
+ *
+ * @param class-string $class
+ *
+ * @return T
+ */
+ public static function to(string $class, mixed $value): object {
+ assert($value instanceof $class);
+
+ return $value;
+ }
}
diff --git a/packages/documentator/resources/views/commands/markdown.blade.php b/packages/documentator/resources/views/commands/markdown.blade.php
new file mode 100644
index 000000000..c724ac14d
--- /dev/null
+++ b/packages/documentator/resources/views/commands/markdown.blade.php
@@ -0,0 +1,47 @@
+
+
+
+# `{{ $command->getName() }}`
+@if($command->getDescription())
+
+{!! $command->getDescription() !!}
+@endif
+
+## Usages
+
+@foreach(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage)
+* `{!! $usage !!}`
+@endforeach
+@if($command->getDescription() !== ($help = $command->getProcessedHelp()))
+
+## Description
+
+{!! $help !!}
+@endif
+@if($command->getDefinition()->getArguments())
+
+## Arguments
+@foreach($command->getDefinition()->getArguments() as $argument)
+
+### `{!! $serializer->getArgumentSignature($argument) !!}`
+
+{!! $argument->getDescription() ?: '_No description provided._' !!}
+@endforeach
+@endif
+@if($command->getDefinition()->getOptions())
+
+## Options
+@foreach($command->getDefinition()->getOptions() as $option)
+
+### `{!! $serializer->getOptionSignature($option) !!}`@if($option->isNegatable()), `--no-{{ $option->getName() }}`@endif
+
+
+{!! $option->getDescription() ?: '_No description provided._' !!}
+@endforeach
+@endif
diff --git a/packages/documentator/src/Commands/Commands.php b/packages/documentator/src/Commands/Commands.php
new file mode 100644
index 000000000..da7f9b972
--- /dev/null
+++ b/packages/documentator/src/Commands/Commands.php
@@ -0,0 +1,92 @@
+getApplication());
+ $namespace = $application->findNamespace(Cast::toString($this->argument('namespace')));
+ $target = Cast::toString($this->argument('target'));
+ $default = Cast::toBool($this->option('defaults'));
+ $commands = $application->all($namespace);
+
+ // Cleanup
+ $this->components->task(
+ 'Prepare',
+ static function () use ($filesystem, $target): void {
+ if (is_dir($target)) {
+ $filesystem->remove(
+ Finder::create()->in($target),
+ );
+ } else {
+ $filesystem->mkdir($target);
+ }
+ },
+ );
+
+ // Process
+ foreach ($commands as $command) {
+ if ($command->isHidden()) {
+ continue;
+ }
+
+ $this->components->task(
+ "Command: {$command->getName()}",
+ static function () use ($filesystem, $serializer, $namespace, $target, $default, $command): void {
+ // Default options?
+ if ($default) {
+ $command->mergeApplicationDefinition();
+ } else {
+ $command->setDefinition(
+ $command->getNativeDefinition(),
+ );
+ }
+
+ // Render
+ $name = Str::after((string) $command->getName(), "{$namespace}:");
+ $path = Path::getPath($target, "{$name}.md");
+ $package = Package::Name;
+ $content = view("{$package}::commands.markdown", [
+ 'serializer' => $serializer,
+ 'command' => $command,
+ ])->render();
+
+ $filesystem->dumpFile($path, $content);
+ },
+ );
+ }
+ }
+}
diff --git a/packages/documentator/src/Commands/CommandsTest.php b/packages/documentator/src/Commands/CommandsTest.php
new file mode 100644
index 000000000..cddf7ae63
--- /dev/null
+++ b/packages/documentator/src/Commands/CommandsTest.php
@@ -0,0 +1,142 @@
+
+ // =========================================================================
+ /**
+ * @inheritDoc
+ */
+ protected function getPackageProviders(mixed $app): array {
+ return array_merge(parent::getPackageProviders($app), [
+ CommandsTest_Provider::class,
+ ]);
+ }
+ //
+
+ //
+ // =========================================================================
+ public function testInvoke(): void {
+ $directory = self::getTempDirectory();
+
+ self::assertNotFalse(
+ file_put_contents(Path::join($directory, 'file.txt'), static::class),
+ );
+
+ $this->artisan("lara-asp-documentator:commands test-namespace {$directory}");
+
+ $files = iterator_to_array(Finder::create()->in($directory)->files());
+ $files = array_reduce($files, static function (array $combined, SplFileInfo $file): array {
+ return array_merge($combined, [
+ $file->getFilename() => $file->getContents(),
+ ]);
+ }, []);
+
+ self::assertEquals(
+ [
+ 'command-a.md' => self::getTestData()->content('~a.md'),
+ 'command-b.md' => self::getTestData()->content('~b.md'),
+ ],
+ $files,
+ );
+ }
+ //
+}
+
+// @phpcs:disable PSR1.Classes.ClassDeclaration.MultipleClasses
+// @phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
+
+/**
+ * @internal
+ * @noinspection PhpMultipleClassesDeclarationsInOneFile
+ */
+class CommandsTest_Provider extends ServiceProvider {
+ public function boot(): void {
+ $this->commands(
+ CommandsTest_CommandA::class,
+ CommandsTest_CommandB::class,
+ CommandsTest_CommandC::class,
+ );
+ }
+}
+
+/**
+ * @internal
+ * @noinspection PhpMultipleClassesDeclarationsInOneFile
+ */
+class CommandsTest_CommandA extends Command {
+ /**
+ * @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint
+ * @var string
+ */
+ protected $signature = <<<'SIGNATURE'
+ test-namespace:command-a
+ {arg-a : Argument a}
+ {arg-b? : Optional argument b}
+ {--a|option-a : Option A}
+ {--option-b= : Option B}
+ SIGNATURE;
+
+ public function __invoke(): void {
+ throw new Exception('Should not be called.');
+ }
+}
+
+/**
+ * @internal
+ * @noinspection PhpMultipleClassesDeclarationsInOneFile
+ */
+#[AsCommand(
+ name : 'test-namespace:command-b',
+ description: 'Command B description.',
+)]
+class CommandsTest_CommandB extends Command {
+ /**
+ * @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint
+ * @var array
+ */
+ protected $aliases = ['command-b-alias'];
+
+ public function __invoke(): void {
+ throw new Exception('Should not be called.');
+ }
+}
+
+/**
+ * @internal
+ * @noinspection PhpMultipleClassesDeclarationsInOneFile
+ */
+#[AsCommand(
+ name: 'test-namespace:command-c',
+)]
+class CommandsTest_CommandC extends Command {
+ /**
+ * @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint
+ * @var boolean
+ */
+ protected $hidden = true;
+
+ public function __invoke(): void {
+ throw new Exception('Should not be called.');
+ }
+}
diff --git a/packages/documentator/src/Commands/CommandsTest~a.md b/packages/documentator/src/Commands/CommandsTest~a.md
new file mode 100644
index 000000000..1fbd28e31
--- /dev/null
+++ b/packages/documentator/src/Commands/CommandsTest~a.md
@@ -0,0 +1,27 @@
+
+
+# `test-namespace:command-a`
+
+## Usages
+
+* `test-namespace:command-a [-a|--option-a] [--option-b [OPTION-B]] [--] []`
+
+## Arguments
+
+### `arg-a`
+
+Argument a
+
+### `arg-b?`
+
+Optional argument b
+
+## Options
+
+### `--a|option-a`
+
+Option A
+
+### `--option-b=`
+
+Option B
diff --git a/packages/documentator/src/Commands/CommandsTest~b.md b/packages/documentator/src/Commands/CommandsTest~b.md
new file mode 100644
index 000000000..eaccc4b83
--- /dev/null
+++ b/packages/documentator/src/Commands/CommandsTest~b.md
@@ -0,0 +1,10 @@
+
+
+# `test-namespace:command-b`
+
+Command B description.
+
+## Usages
+
+* `test-namespace:command-b`
+* `command-b-alias`
diff --git a/packages/documentator/src/Provider.php b/packages/documentator/src/Provider.php
index f921d0898..3c1c79b2f 100644
--- a/packages/documentator/src/Provider.php
+++ b/packages/documentator/src/Provider.php
@@ -4,6 +4,7 @@
use Illuminate\Support\ServiceProvider;
use LastDragon_ru\LaraASP\Core\Concerns\ProviderWithViews;
+use LastDragon_ru\LaraASP\Documentator\Commands\Commands;
use LastDragon_ru\LaraASP\Documentator\Commands\Preprocess;
use LastDragon_ru\LaraASP\Documentator\Commands\Requirements;
@@ -15,6 +16,7 @@ public function boot(): void {
$this->commands(
Requirements::class,
Preprocess::class,
+ Commands::class,
);
}
diff --git a/packages/documentator/src/Utils/ArtisanSerializer.php b/packages/documentator/src/Utils/ArtisanSerializer.php
new file mode 100644
index 000000000..48ef8df20
--- /dev/null
+++ b/packages/documentator/src/Utils/ArtisanSerializer.php
@@ -0,0 +1,85 @@
+getDefault() !== null;
+ $signature = $argument->getName();
+
+ if ($default) {
+ $signature .= '=';
+ }
+
+ if (!$argument->isRequired() && !$default) {
+ $signature .= '?';
+ }
+
+ if ($argument->isArray()) {
+ $signature .= '*';
+ }
+
+ if ($default) {
+ $signature .= $this->getValue($argument->getDefault());
+ }
+
+ return $signature;
+ }
+
+ public function getOptionSignature(InputOption $option): string {
+ $default = $option->getDefault() !== null && $option->acceptValue();
+ $signature = '--';
+
+ if ($option->getShortcut()) {
+ $signature .= $option->getShortcut().'|';
+ }
+
+ $signature .= $option->getName();
+
+ if ($default || $option->isValueOptional()) {
+ $signature .= '=';
+ }
+
+ if ($option->isNegatable()) {
+ // Not yet supported by Laravel :(
+ }
+
+ if ($option->isArray()) {
+ $signature .= '*';
+ }
+
+ if ($default) {
+ $signature .= $this->getValue($option->getDefault());
+ }
+
+ return $signature;
+ }
+
+ protected function getValue(mixed $value): string {
+ // Signature is a string so all should be fine.
+ return match (true) {
+ is_array($value) => implode(',', array_map($this->getValue(...), $value)),
+ is_bool($value) => ($value ? 'true' : 'false'),
+ is_scalar($value) => (string) $value,
+ default => '',
+ };
+ }
+}
diff --git a/packages/documentator/src/Utils/ArtisanSerializerTest.php b/packages/documentator/src/Utils/ArtisanSerializerTest.php
new file mode 100644
index 000000000..5c4aa87c4
--- /dev/null
+++ b/packages/documentator/src/Utils/ArtisanSerializerTest.php
@@ -0,0 +1,45 @@
+getArgumentSignature($argument));
+ }
+
+ #[TestWith(['--user'])]
+ #[TestWith(['--u|user'])]
+ #[TestWith(['--user=*'])]
+ #[TestWith(['--u|user=*'])]
+ #[TestWith(['--u|user=default'])]
+ #[TestWith(['--u|user=*default'])]
+ public function testGetOptionSignature(string $signature): void {
+ $parsed = Parser::parse("command {{$signature}}")[2] ?? [];
+ $option = reset($parsed);
+
+ self::assertInstanceOf(InputOption::class, $option);
+ self::assertEquals($signature, (new ArtisanSerializer())->getOptionSignature($option));
+ }
+}
From 6a0fc83280f4ec70e1bb344afb5088ae709e1676 Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Fri, 25 Aug 2023 11:08:34 +0400
Subject: [PATCH 30/33] `Preprocess` command fixes & Minor improvements.
---
.../documentator/src/Commands/Preprocess.php | 33 ++++++++++---------
1 file changed, 17 insertions(+), 16 deletions(-)
diff --git a/packages/documentator/src/Commands/Preprocess.php b/packages/documentator/src/Commands/Preprocess.php
index 29bf08ebc..a14d35c13 100644
--- a/packages/documentator/src/Commands/Preprocess.php
+++ b/packages/documentator/src/Commands/Preprocess.php
@@ -26,6 +26,14 @@
class Preprocess extends Command {
public const Name = Package::Name.':preprocess';
+ /**
+ * @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint
+ * @var string
+ */
+ public $signature = self::Name.<<<'SIGNATURE'
+ {path? : Directory to process.}
+ SIGNATURE;
+
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint
* @var string
@@ -38,11 +46,11 @@ class Preprocess extends Command {
[=name]:
```
- ### Supported instructions:
+ ### Supported instructions
%instructions%
- ### Limitations:
+ ### Limitations
* `` will be processed everywhere in the file (eg within
the code block) and may give unpredictable results.
@@ -50,14 +58,6 @@ class Preprocess extends Command {
* Nested `` doesn't support.
HELP;
- /**
- * @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint
- * @var string
- */
- public $signature = self::Name.<<<'SIGNATURE'
- {path? : directory to process}
- SIGNATURE;
-
public function __invoke(Filesystem $filesystem, Preprocessor $preprocessor): void {
$cwd = getcwd();
$path = Cast::toString($this->argument('path') ?? $cwd);
@@ -78,7 +78,7 @@ static function () use ($filesystem, $preprocessor, $file): void {
$result = $preprocessor->process($path, $content);
if ($content !== $result) {
- $filesystem->dumpFile($path, $content);
+ $filesystem->dumpFile($path, $result);
}
},
);
@@ -86,13 +86,14 @@ static function () use ($filesystem, $preprocessor, $file): void {
}
public function getProcessedHelp(): string {
+ $preprocessor = Container::getInstance()->make(Preprocessor::class);
+
return strtr(parent::getProcessedHelp(), [
- '%instructions%' => $this->getInstructionsHelp(),
+ '%instructions%' => $this->getInstructionsHelp($preprocessor),
]);
}
- protected function getInstructionsHelp(): string {
- $preprocessor = Container::getInstance()->make(Preprocessor::class);
+ protected function getInstructionsHelp(Preprocessor $preprocessor): string {
$instructions = $preprocessor->getInstructions();
$help = [];
@@ -103,7 +104,7 @@ protected function getInstructionsHelp(): string {
if ($target !== null) {
$help[$name] = <<`
* `` - {$target}
@@ -111,7 +112,7 @@ protected function getInstructionsHelp(): string {
HELP;
} else {
$help[$name] = <<
Date: Fri, 25 Aug 2023 11:10:09 +0400
Subject: [PATCH 31/33] Documentation.
---
.markdownlint.yaml | 7 +-
packages/documentator/README.md | 26 +++++++
.../documentator/docs/commands/commands.md | 25 +++++++
.../documentator/docs/commands/preprocess.md | 68 +++++++++++++++++++
.../docs/commands/requirements.md | 15 ++++
5 files changed, 140 insertions(+), 1 deletion(-)
create mode 100644 packages/documentator/docs/commands/commands.md
create mode 100644 packages/documentator/docs/commands/preprocess.md
create mode 100644 packages/documentator/docs/commands/requirements.md
diff --git a/.markdownlint.yaml b/.markdownlint.yaml
index 4c3793ad5..c2a980a58 100644
--- a/.markdownlint.yaml
+++ b/.markdownlint.yaml
@@ -251,5 +251,10 @@ MD052: true
MD053:
# Ignored definitions
ignored_definitions: [
- "//"
+ "//",
+ "include:document-list",
+ "include:example",
+ "include:exec",
+ "include:file",
+ "include:package-list",
]
diff --git a/packages/documentator/README.md b/packages/documentator/README.md
index 29dd8798c..cfcd022ff 100644
--- a/packages/documentator/README.md
+++ b/packages/documentator/README.md
@@ -5,3 +5,29 @@
> [Read more](https://github.com/LastDragon-ru/lara-asp).
This package provides various utilities for documentation generation.
+
+# Commands
+
+[include:document-list]: ./docs/commands
+[//]: # (start: eb736c56d36bfbf743249954931dda71ebb3dec0)
+[//]: # (warning: Generated automatically. Do not edit.)
+
+## `lara-asp-documentator:commands`
+
+Saves help for each command in the `namespace` into a separate file in the `target` directory.
+
+[Read more]().
+
+## `lara-asp-documentator:preprocess`
+
+Preprocess Markdown files.
+
+[Read more]().
+
+## `lara-asp-documentator:requirements`
+
+Generates a table with the required versions of PHP/Laravel in Markdown format.
+
+[Read more]().
+
+[//]: # (end: eb736c56d36bfbf743249954931dda71ebb3dec0)
diff --git a/packages/documentator/docs/commands/commands.md b/packages/documentator/docs/commands/commands.md
new file mode 100644
index 000000000..2320de0cf
--- /dev/null
+++ b/packages/documentator/docs/commands/commands.md
@@ -0,0 +1,25 @@
+
+
+# `lara-asp-documentator:commands`
+
+Saves help for each command in the `namespace` into a separate file in the `target` directory.
+
+## Usages
+
+* `lara-asp-documentator:commands [--defaults] [--] `
+
+## Arguments
+
+### `namespace`
+
+The namespace of the commands.
+
+### `target`
+
+Directory to save generated files. It will be created if not exist. All files/directories inside it will be removed otherwise.
+
+## Options
+
+### `--defaults`
+
+Include application default arguments/options like `--help`, etc.
diff --git a/packages/documentator/docs/commands/preprocess.md b/packages/documentator/docs/commands/preprocess.md
new file mode 100644
index 000000000..064cdabeb
--- /dev/null
+++ b/packages/documentator/docs/commands/preprocess.md
@@ -0,0 +1,68 @@
+
+
+# `lara-asp-documentator:preprocess`
+
+Preprocess Markdown files.
+
+## Usages
+
+* `lara-asp-documentator:preprocess []`
+
+## Description
+
+Replaces special instructions in Markdown.
+
+```plain
+[]:
+[=name]:
+```
+
+### Supported instructions
+
+#### `[include:document-list]: `
+
+* `` - Directory path.
+
+Returns the list of `*.md` files in the `` directory. Each file
+must have `# Header` as the first construction. The first paragraph
+after the Header will be used as a summary.
+
+#### `[include:example]: `
+
+* `` - Example file path.
+
+Includes contents of the `` file as an example wrapped into
+` ```code block``` `. It also searches for `.run` file, execute
+it if found, and include its result right after the code block.
+
+#### `[include:exec]: `
+
+* `` - Path to the executable.
+
+Executes the `` and returns result.
+
+#### `[include:file]: `
+
+* `` - File path.
+
+Includes the `` file.
+
+#### `[include:package-list]: `
+
+* `` - Directory path.
+
+Generates package list from `` directory. The readme file will be
+used to determine package name and summary.
+
+### Limitations
+
+* `` will be processed everywhere in the file (eg within
+ the code block) and may give unpredictable results.
+* `` cannot be inside text.
+* Nested `` doesn't support.
+
+## Arguments
+
+### `path?`
+
+Directory to process.
diff --git a/packages/documentator/docs/commands/requirements.md b/packages/documentator/docs/commands/requirements.md
new file mode 100644
index 000000000..cc2cbc126
--- /dev/null
+++ b/packages/documentator/docs/commands/requirements.md
@@ -0,0 +1,15 @@
+
+
+# `lara-asp-documentator:requirements`
+
+Generates a table with the required versions of PHP/Laravel in Markdown format.
+
+## Usages
+
+* `lara-asp-documentator:requirements []`
+
+## Arguments
+
+### `cwd?`
+
+working directory (should be a git repository)
From 206e218ec0de7782d28c2e4fc54b3999c63b6a9d Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Fri, 25 Aug 2023 11:20:57 +0400
Subject: [PATCH 32/33] Preprocessor will handle `[instruction]: `.
---
.../documentator/src/Preprocessor/Preprocessor.php | 12 +++++++++---
.../src/Preprocessor/PreprocessorTest.php | 4 ++--
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/packages/documentator/src/Preprocessor/Preprocessor.php b/packages/documentator/src/Preprocessor/Preprocessor.php
index 3eec64d0f..020ca5fe1 100644
--- a/packages/documentator/src/Preprocessor/Preprocessor.php
+++ b/packages/documentator/src/Preprocessor/Preprocessor.php
@@ -14,9 +14,12 @@
use LastDragon_ru\LaraASP\Documentator\Utils\Path;
use function array_column;
+use function mb_substr;
use function preg_replace_callback;
use function rawurldecode;
use function sha1;
+use function str_ends_with;
+use function str_starts_with;
use function trim;
use const PREG_UNMATCHED_AS_NULL;
@@ -43,7 +46,7 @@ class Preprocessor {
protected const Regexp = <<<'REGEXP'
/^
(?P
- \[(?P[^\]=]+)(?:=[^]]+)?\]:\s(?P[^ ]+?)
+ \[(?P[^\]=]+)(?:=[^]]+)?\]:\s(?P(?:[^ ]+?)|(?:<[^>]+?>))
)
(?P\R
\[\/\/\]:\s\#\s\(start:\s(?P[^)]+)\)
@@ -107,12 +110,15 @@ public function process(string $path, string $string): string {
$result = preg_replace_callback(
pattern : static::Regexp,
callback: function (array $matches) use (&$cache, $path): string {
- $hash = $this->getHash("{$matches['instruction']}={$matches['target']}");
+ $target = $matches['target'];
+ $target = str_starts_with($target, '<') && str_ends_with($target, '>')
+ ? mb_substr($target, 1, -1)
+ : rawurldecode($target);
+ $hash = $this->getHash("{$matches['instruction']}={$target}");
$content = $cache[$hash] ?? null;
$instruction = $this->getInstruction($matches['instruction']);
if ($content === null) {
- $target = rawurldecode($matches['target']);
$content = trim($instruction?->process($path, $target) ?? '');
$cache[$hash] = $content;
}
diff --git a/packages/documentator/src/Preprocessor/PreprocessorTest.php b/packages/documentator/src/Preprocessor/PreprocessorTest.php
index f1a1e0ded..e0d0f8b75 100644
--- a/packages/documentator/src/Preprocessor/PreprocessorTest.php
+++ b/packages/documentator/src/Preprocessor/PreprocessorTest.php
@@ -20,7 +20,7 @@ public function testProcess(): void {
[test]: ./path/to/file
- [test]: ./path/to/file
+ [test]: <./path/to/file>
[//]: # (start: hash)
[test]: ./path/to/file
@@ -84,7 +84,7 @@ public function process(string $path, string $target): string {
[//]: # (end: 8c3f20586897a62ee759aae56b703dd6cd11a8ad)
- [test]: ./path/to/file
+ [test]: <./path/to/file>
[//]: # (start: 8c3f20586897a62ee759aae56b703dd6cd11a8ad)
[//]: # (warning: Generated automatically. Do not edit.)
From 6df7bdfbfb67608dd4efc3d4c84849d84453846c Mon Sep 17 00:00:00 2001
From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com>
Date: Fri, 25 Aug 2023 11:50:55 +0400
Subject: [PATCH 33/33] Tests fixes.
---
.../src/Commands/CommandsTest.php | 24 +++++++--
.../src/Utils/ArtisanSerializerTest.php | 51 ++++++++++++++-----
packages/documentator/src/Utils/Path.php | 8 +--
packages/documentator/src/Utils/PathTest.php | 6 ++-
4 files changed, 68 insertions(+), 21 deletions(-)
diff --git a/packages/documentator/src/Commands/CommandsTest.php b/packages/documentator/src/Commands/CommandsTest.php
index cddf7ae63..ed8204289 100644
--- a/packages/documentator/src/Commands/CommandsTest.php
+++ b/packages/documentator/src/Commands/CommandsTest.php
@@ -37,13 +37,17 @@ protected function getPackageProviders(mixed $app): array {
//
// =========================================================================
public function testInvoke(): void {
- $directory = self::getTempDirectory();
+ $directory = Path::normalize(self::getTempDirectory());
self::assertNotFalse(
file_put_contents(Path::join($directory, 'file.txt'), static::class),
);
- $this->artisan("lara-asp-documentator:commands test-namespace {$directory}");
+ $result = $this
+ ->withoutMockingConsoleOutput()
+ ->artisan("lara-asp-documentator:commands test-namespace {$directory}");
+
+ self::assertEquals(Command::SUCCESS, $result);
$files = iterator_to_array(Finder::create()->in($directory)->files());
$files = array_reduce($files, static function (array $combined, SplFileInfo $file): array {
@@ -107,16 +111,28 @@ public function __invoke(): void {
* @noinspection PhpMultipleClassesDeclarationsInOneFile
*/
#[AsCommand(
- name : 'test-namespace:command-b',
- description: 'Command B description.',
+ name: 'test-namespace:command-b',
)]
class CommandsTest_CommandB extends Command {
+ /**
+ * @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint
+ * @var string|null
+ */
+ protected $description = 'Command B description.';
+
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint
* @var array
*/
protected $aliases = ['command-b-alias'];
+ public function __construct() {
+ parent::__construct();
+
+ // @phpstan-ignore-next-line Required for Laravel v9
+ $this->setAliases((array) $this->aliases);
+ }
+
public function __invoke(): void {
throw new Exception('Should not be called.');
}
diff --git a/packages/documentator/src/Utils/ArtisanSerializerTest.php b/packages/documentator/src/Utils/ArtisanSerializerTest.php
index 5c4aa87c4..c0ac0e6ea 100644
--- a/packages/documentator/src/Utils/ArtisanSerializerTest.php
+++ b/packages/documentator/src/Utils/ArtisanSerializerTest.php
@@ -5,7 +5,6 @@
use Illuminate\Console\Parser;
use LastDragon_ru\LaraASP\Documentator\Testing\Package\TestCase;
use PHPUnit\Framework\Attributes\CoversClass;
-use PHPUnit\Framework\Attributes\TestWith;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
@@ -16,11 +15,11 @@
*/
#[CoversClass(ArtisanSerializer::class)]
class ArtisanSerializerTest extends TestCase {
- #[TestWith(['user'])]
- #[TestWith(['user?'])]
- #[TestWith(['user*?'])]
- #[TestWith(['user=default'])]
- #[TestWith(['user=*default'])]
+ //
+ // =========================================================================
+ /**
+ * @dataProvider dataProviderGetArgumentSignature
+ */
public function testGetArgumentSignature(string $signature): void {
$parsed = Parser::parse("command {{$signature}}")[1] ?? [];
$argument = reset($parsed);
@@ -29,12 +28,9 @@ public function testGetArgumentSignature(string $signature): void {
self::assertEquals($signature, (new ArtisanSerializer())->getArgumentSignature($argument));
}
- #[TestWith(['--user'])]
- #[TestWith(['--u|user'])]
- #[TestWith(['--user=*'])]
- #[TestWith(['--u|user=*'])]
- #[TestWith(['--u|user=default'])]
- #[TestWith(['--u|user=*default'])]
+ /**
+ * @dataProvider dataProviderGetOptionSignature
+ */
public function testGetOptionSignature(string $signature): void {
$parsed = Parser::parse("command {{$signature}}")[2] ?? [];
$option = reset($parsed);
@@ -42,4 +38,35 @@ public function testGetOptionSignature(string $signature): void {
self::assertInstanceOf(InputOption::class, $option);
self::assertEquals($signature, (new ArtisanSerializer())->getOptionSignature($option));
}
+ //
+
+ //
+ // =========================================================================
+ /**
+ * @return array
+ */
+ public static function dataProviderGetArgumentSignature(): array {
+ return [
+ ['user'],
+ ['user?'],
+ ['user*?'],
+ ['user=default'],
+ ['user=*default'],
+ ];
+ }
+
+ /**
+ * @return array
+ */
+ public static function dataProviderGetOptionSignature(): array {
+ return [
+ ['--user'],
+ ['--u|user'],
+ ['--user=*'],
+ ['--u|user=*'],
+ ['--u|user=default'],
+ ['--u|user=*default'],
+ ];
+ }
+ //
}
diff --git a/packages/documentator/src/Utils/Path.php b/packages/documentator/src/Utils/Path.php
index ae5d06507..461b2dfb4 100644
--- a/packages/documentator/src/Utils/Path.php
+++ b/packages/documentator/src/Utils/Path.php
@@ -10,7 +10,7 @@
class Path {
public static function getPath(string $root, string $path): string {
$path = static::isRelative($path)
- ? SymfonyPath::join(static::getDirname($root), $path)
+ ? static::join(static::getDirname($root), $path)
: $path;
$path = static::normalize($path);
@@ -18,15 +18,15 @@ public static function getPath(string $root, string $path): string {
}
public static function getDirname(string $path): string {
- return is_file($path) ? dirname($path) : $path;
+ return static::normalize(is_file($path) ? dirname($path) : $path);
}
public static function isRelative(string $path): bool {
- return SymfonyPath::isRelative($path);
+ return SymfonyPath::isRelative(static::normalize($path));
}
public static function isAbsolute(string $path): bool {
- return SymfonyPath::isAbsolute($path);
+ return SymfonyPath::isAbsolute(static::normalize($path));
}
public static function normalize(string $path): string {
diff --git a/packages/documentator/src/Utils/PathTest.php b/packages/documentator/src/Utils/PathTest.php
index 39d38feef..2e394b3f7 100644
--- a/packages/documentator/src/Utils/PathTest.php
+++ b/packages/documentator/src/Utils/PathTest.php
@@ -6,6 +6,7 @@
use PHPUnit\Framework\Attributes\CoversClass;
use function dirname;
+use function str_replace;
/**
* @internal
@@ -15,6 +16,9 @@ class PathTest extends TestCase {
public function testGetPath(): void {
self::assertEquals('/absolute/path/to/file', Path::getPath('any/path', '/absolute/path/./to/file'));
self::assertEquals('/absolute/path/to/file', Path::getPath('/absolute/path', 'to/./file'));
- self::assertEquals(dirname(__FILE__).'/to/file', Path::getPath(__FILE__, 'to/./file'));
+ self::assertEquals(
+ str_replace('\\', '/', dirname(__FILE__).'/to/file'),
+ Path::getPath(__FILE__, 'to/./file'),
+ );
}
}