From b5962f6106d0c6164c09e70c055a0d8eef6d5e24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Dec 2024 01:27:16 +0000 Subject: [PATCH 01/80] Bump league/commonmark from 2.5.3 to 2.6.0 Bumps [league/commonmark](https://github.com/thephpleague/commonmark) from 2.5.3 to 2.6.0. - [Release notes](https://github.com/thephpleague/commonmark/releases) - [Changelog](https://github.com/thephpleague/commonmark/blob/2.6/CHANGELOG.md) - [Commits](https://github.com/thephpleague/commonmark/compare/2.5.3...2.6.0) --- updated-dependencies: - dependency-name: league/commonmark dependency-type: indirect ... Signed-off-by: dependabot[bot] --- composer.lock | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/composer.lock b/composer.lock index a841a15d206..0d0432a0ac6 100644 --- a/composer.lock +++ b/composer.lock @@ -2707,16 +2707,16 @@ }, { "name": "league/commonmark", - "version": "2.5.3", + "version": "2.6.0", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "b650144166dfa7703e62a22e493b853b58d874b0" + "reference": "d150f911e0079e90ae3c106734c93137c184f932" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/b650144166dfa7703e62a22e493b853b58d874b0", - "reference": "b650144166dfa7703e62a22e493b853b58d874b0", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d150f911e0079e90ae3c106734c93137c184f932", + "reference": "d150f911e0079e90ae3c106734c93137c184f932", "shasum": "" }, "require": { @@ -2741,8 +2741,9 @@ "phpstan/phpstan": "^1.8.2", "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", "scrutinizer/ocular": "^1.8.1", - "symfony/finder": "^5.3 | ^6.0 || ^7.0", - "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 || ^7.0", + "symfony/finder": "^5.3 | ^6.0 | ^7.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", "unleashedtech/php-coding-standard": "^3.1.1", "vimeo/psalm": "^4.24.0 || ^5.0.0" }, @@ -2752,7 +2753,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.6-dev" + "dev-main": "2.7-dev" } }, "autoload": { @@ -2809,7 +2810,7 @@ "type": "tidelift" } ], - "time": "2024-08-16T11:46:16+00:00" + "time": "2024-12-07T15:34:16+00:00" }, { "name": "league/config", @@ -4581,16 +4582,16 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", "shasum": "" }, "require": { @@ -4628,7 +4629,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" }, "funding": [ { @@ -4644,7 +4645,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/error-handler", From 81042228a9e95787af53b9042fbd729f3dc9fa97 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2024 21:28:10 +0000 Subject: [PATCH 02/80] Bump sass from 1.82.0 to 1.83.0 in /packages/hydefront Bumps [sass](https://github.com/sass/dart-sass) from 1.82.0 to 1.83.0. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.82.0...1.83.0) --- updated-dependencies: - dependency-name: sass dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- packages/hydefront/package-lock.json | 9 ++++----- packages/hydefront/package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/hydefront/package-lock.json b/packages/hydefront/package-lock.json index 3c1a80b62d4..0ec68bfe590 100644 --- a/packages/hydefront/package-lock.json +++ b/packages/hydefront/package-lock.json @@ -9,7 +9,7 @@ "version": "3.4.1", "license": "MIT", "devDependencies": { - "sass": "1.82.0" + "sass": "1.83.0" } }, "node_modules/@parcel/watcher": { @@ -427,11 +427,10 @@ } }, "node_modules/sass": { - "version": "1.82.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.82.0.tgz", - "integrity": "sha512-j4GMCTa8elGyN9A7x7bEglx0VgSpNUG4W4wNedQ33wSMdnkqQCT8HTwOaVSV4e6yQovcu/3Oc4coJP/l0xhL2Q==", + "version": "1.83.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.83.0.tgz", + "integrity": "sha512-qsSxlayzoOjdvXMVLkzF84DJFc2HZEL/rFyGIKbbilYtAvlCxyuzUeff9LawTn4btVnLKg75Z8MMr1lxU1lfGw==", "dev": true, - "license": "MIT", "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", diff --git a/packages/hydefront/package.json b/packages/hydefront/package.json index 24d47717472..6bf26adf96f 100644 --- a/packages/hydefront/package.json +++ b/packages/hydefront/package.json @@ -23,7 +23,7 @@ }, "homepage": "https://github.com/hydephp/hydefront#readme", "devDependencies": { - "sass": "1.82.0" + "sass": "1.83.0" }, "main": "dist/hyde.css" } From a1817b8252c0aeb16fab1e6af9a64c88ffaae169 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Dec 2024 21:14:37 +0000 Subject: [PATCH 03/80] Bump tailwindcss from 3.4.16 to 3.4.17 Bumps [tailwindcss](https://github.com/tailwindlabs/tailwindcss) from 3.4.16 to 3.4.17. - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/v3.4.17/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/compare/v3.4.16...v3.4.17) --- updated-dependencies: - dependency-name: tailwindcss dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index db9eab07b2e..ce9f164dff1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "laravel-mix": "^6.0.49", "postcss": "^8.4.49", "prettier": "3.4.2", - "tailwindcss": "^3.4.16" + "tailwindcss": "^3.4.17" } }, "node_modules/@alloc/quick-lru": { @@ -8476,9 +8476,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.16", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.16.tgz", - "integrity": "sha512-TI4Cyx7gDiZ6r44ewaJmt0o6BrMCT5aK5e0rmJ/G9Xq3w7CX/5VXl/zIPEJZFUK5VEqwByyhqNPycPlvcK4ZNw==", + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", + "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "dev": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", @@ -15879,9 +15879,9 @@ } }, "tailwindcss": { - "version": "3.4.16", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.16.tgz", - "integrity": "sha512-TI4Cyx7gDiZ6r44ewaJmt0o6BrMCT5aK5e0rmJ/G9Xq3w7CX/5VXl/zIPEJZFUK5VEqwByyhqNPycPlvcK4ZNw==", + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", + "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "dev": true, "requires": { "@alloc/quick-lru": "^5.2.0", diff --git a/package.json b/package.json index 27fac568277..fcaed842ab5 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,6 @@ "laravel-mix": "^6.0.49", "postcss": "^8.4.49", "prettier": "3.4.2", - "tailwindcss": "^3.4.16" + "tailwindcss": "^3.4.17" } } From d6daf0186950822079411f22212073094dcf44e8 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Wed, 11 Dec 2024 21:56:51 +0100 Subject: [PATCH 04/80] Add a rule that ensures we don't use `GLOB_BRACE` This is as it does not work on all systems --- monorepo/HydeStan/HydeStan.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/monorepo/HydeStan/HydeStan.php b/monorepo/HydeStan/HydeStan.php index 279fed01ce4..96d28ff3a9c 100644 --- a/monorepo/HydeStan/HydeStan.php +++ b/monorepo/HydeStan/HydeStan.php @@ -15,6 +15,7 @@ final class HydeStan private const FILE_ANALYSERS = [ NoFixMeAnalyser::class, UnImportedFunctionAnalyser::class, + NoGlobBraceAnalyser::class, ]; private const TEST_FILE_ANALYSERS = [ @@ -370,6 +371,27 @@ public function run(string $file, string $contents): void } } +class NoGlobBraceAnalyser extends FileAnalyser +{ + public function run(string $file, string $contents): void + { + $lines = explode("\n", $contents); + + foreach ($lines as $lineNumber => $line) { + AnalysisStatisticsContainer::analysedExpression(); + + if (str_contains($line, 'GLOB_BRACE')) { + $this->fail(sprintf('Usage of `GLOB_BRACE` found in %s at line %d. This feature is not supported on all systems and should be avoided.', + realpath(BASE_PATH.'/'.$file), + $lineNumber + 1 + )); + + HydeStan::addActionsMessage('error', $file, $lineNumber + 1, 'HydeStan: NoGlobBraceError', '`GLOB_BRACE` is not supported on all systems. Consider refactoring to avoid it.'); + } + } + } +} + class NoTestReferenceAnalyser extends LineAnalyser { public function run(string $file, int $lineNumber, string $line): void From d3ec04c21bdd3d9fb9eb0963f04322e54cf128af Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 12 Dec 2024 21:19:41 +0100 Subject: [PATCH 05/80] Test recursive discovery --- .../tests/Feature/FileCollectionTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/framework/tests/Feature/FileCollectionTest.php b/packages/framework/tests/Feature/FileCollectionTest.php index 2bc4f1d66a4..492705f3bb0 100644 --- a/packages/framework/tests/Feature/FileCollectionTest.php +++ b/packages/framework/tests/Feature/FileCollectionTest.php @@ -106,4 +106,20 @@ public function testDocumentationPagesAreDiscovered() $this->assertArrayHasKey('_docs/foo.md', $collection->toArray()); $this->assertEquals(new SourceFile('_docs/foo.md', DocumentationPage::class), $collection->get('_docs/foo.md')); } + + public function testDiscoverFilesForRecursivelyDiscoversFilesInSubdirectories() + { + $this->file('_pages/foo.md'); + $this->file('_pages/foo/bar.md'); + //$this->file('_pages/foo/bar/baz.md'); + $collection = FileCollection::init(Hyde::getInstance())->boot(); + + $this->assertArrayHasKey('_pages/foo.md', $collection->toArray()); + $this->assertArrayHasKey('_pages/foo/bar.md', $collection->toArray()); + //$this->assertArrayHasKey('_pages/foo/bar/baz.md', $collection->toArray()); + + $this->assertEquals(new SourceFile('_pages/foo.md', MarkdownPage::class), $collection->get('_pages/foo.md')); + $this->assertEquals(new SourceFile('_pages/foo/bar.md', MarkdownPage::class), $collection->get('_pages/foo/bar.md')); + //$this->assertEquals(new SourceFile('_pages/foo/bar/baz.md', MarkdownPage::class), $collection->get('_pages/foo/bar/baz.md')); + } } From dab8680f5be3f717c83437393d65cd5e9ad6968e Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 13 Dec 2024 18:15:11 +0100 Subject: [PATCH 06/80] Draft new method for improved file finding --- packages/framework/src/Facades/Filesystem.php | 5 +++++ packages/framework/src/Foundation/Kernel/Filesystem.php | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/packages/framework/src/Facades/Filesystem.php b/packages/framework/src/Facades/Filesystem.php index fa0434212e1..97094cf9b46 100644 --- a/packages/framework/src/Facades/Filesystem.php +++ b/packages/framework/src/Facades/Filesystem.php @@ -69,6 +69,11 @@ public static function smartGlob(string $pattern, int $flags = 0): Collection return self::kernel()->filesystem()->smartGlob($pattern, $flags); } + public static function findFiles(string $directory, bool $recursive = false, ?bool $matchExtension = null): Collection + { + return self::kernel()->filesystem()->findFiles($directory, $recursive, $matchExtension); + } + /** * Touch one or more files in the project's directory. * diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index a8f36a32df1..56c9cd0d493 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -183,4 +183,10 @@ public function smartGlob(string $pattern, int $flags = 0): Collection return $files->map(fn (string $path): string => $this->pathToRelative($path)); } + + /** @return \Illuminate\Support\Collection */ + public function findFiles(string $directory, bool $recursive = false, ?bool $matchExtension = null): Collection + { + // Todo: Implement this method + } } From f9428400259a9dd1f05e3f46640de82871b0cebb Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 13 Dec 2024 19:19:28 +0100 Subject: [PATCH 07/80] Create testing helper to add several files at once --- packages/testing/src/CreatesTemporaryFiles.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/testing/src/CreatesTemporaryFiles.php b/packages/testing/src/CreatesTemporaryFiles.php index b1a656f4e46..1d05f20f969 100644 --- a/packages/testing/src/CreatesTemporaryFiles.php +++ b/packages/testing/src/CreatesTemporaryFiles.php @@ -35,6 +35,23 @@ protected function file(string $path, ?string $contents = null): void $this->cleanUpWhenDone($path); } + /** + * List of filenames, or map of filenames to contents, of temporary files to create in the project directory. + * + * The test case will automatically remove the files when the test is completed. + */ + protected function files(array $files): void + { + foreach ($files as $path => $contents) { + if (is_int($path)) { + $path = $contents; + $contents = null; + } + + $this->file($path, $contents); + } + } + /** * Create a temporary directory in the project directory. * From 7ee8393aba6b4406fac8f272a88a4fb5ebc8ff19 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 13 Dec 2024 19:41:40 +0100 Subject: [PATCH 08/80] Create FilesystemFindFilesTest.php --- .../tests/Unit/FilesystemFindFilesTest.php | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 packages/framework/tests/Unit/FilesystemFindFilesTest.php diff --git a/packages/framework/tests/Unit/FilesystemFindFilesTest.php b/packages/framework/tests/Unit/FilesystemFindFilesTest.php new file mode 100644 index 00000000000..e44d5b8eeb4 --- /dev/null +++ b/packages/framework/tests/Unit/FilesystemFindFilesTest.php @@ -0,0 +1,113 @@ +files(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md']); + $this->assertSameArray(['apple.md', 'banana.md', 'cherry.md'], 'directory'); + } + + public function testFindFilesWithMixedExtensions() + { + $this->files(['directory/apple.md', 'directory/banana.txt', 'directory/cherry.blade.php']); + $this->assertSameArray(['apple.md', 'banana.txt', 'cherry.blade.php'], 'directory'); + } + + public function testFindFilesWithExtension() + { + $this->files(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md']); + $this->assertSameArray(['apple.md', 'banana.md', 'cherry.md'], 'directory', 'md'); + } + + public function testFindFilesWithMixedExtensionsReturnsOnlySpecifiedExtension() + { + $this->files(['directory/apple.md', 'directory/banana.txt', 'directory/cherry.blade.php']); + $this->assertSameArray(['apple.md'], 'directory', 'md'); + } + + public function testFindFilesWithRecursive() + { + $this->files(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md', 'directory/nested/dates.md']); + $this->assertSameArray(['apple.md', 'banana.md', 'cherry.md', 'nested/dates.md'], 'directory', false, true); + } + + public function testFindFilesWithDeeplyRecursiveFiles() + { + $this->files(['directory/apple.md', 'directory/nested/banana.md', 'directory/nested/deeply/cherry.md']); + $this->assertSameArray(['apple.md', 'nested/banana.md', 'nested/deeply/cherry.md'], 'directory', false, true); + } + + public function testFindFilesWithVeryDeeplyRecursiveFiles() + { + $this->files(['directory/apple.md', 'directory/nested/banana.md', 'directory/nested/deeply/cherry.md', 'directory/nested/very/very/deeply/dates.md', 'directory/nested/very/very/excessively/deeply/elderberries.md']); + $this->assertSameArray(['apple.md', 'nested/banana.md', 'nested/deeply/cherry.md', 'nested/very/very/deeply/dates.md', 'nested/very/very/excessively/deeply/elderberries.md'], 'directory', false, true); + } + + public function testFindFilesIgnoresNestedFilesIfNotRecursive() + { + $this->files(['directory/apple.md', 'directory/nested/banana.md', 'directory/nested/deeply/cherry.md']); + $this->assertSameArray(['apple.md'], 'directory'); + } + + public function testFindFilesReturnsCorrectFilesWhenUsingNestedSubdirectoriesOfDifferentExtensions() + { + $this->files(['directory/apple.md', 'directory/nested/banana.md', 'directory/nested/deeply/cherry.blade.php']); + $this->assertSameArray(['apple.md', 'nested/banana.md'], 'directory', 'md', true); + } + + public function testFindFileMethodTypes() + { + $this->file('directory/apple.md'); + $filesystem = new Filesystem(Hyde::getInstance()); + $files = $filesystem->findFiles('directory'); + + $this->assertInstanceOf(Collection::class, $files); + $this->assertContainsOnly('int', $files->keys()); + $this->assertContainsOnly('string', $files->all()); + $this->assertSame('apple.md', $files->first()); + } + + public function testFindFileMethodTypesWithArguments() + { + $this->file('directory/apple.md'); + $filesystem = new Filesystem(Hyde::getInstance()); + + $this->assertInstanceOf(Collection::class, $filesystem->findFiles('directory', false, false)); + $this->assertInstanceOf(Collection::class, $filesystem->findFiles('directory', 'md', false)); + $this->assertInstanceOf(Collection::class, $filesystem->findFiles('directory', false, true)); + $this->assertInstanceOf(Collection::class, $filesystem->findFiles('directory', 'md', true)); + } + + protected function assertSameArray(array $expected, string $directory, string|false $matchExtension = false, bool $recursive = false): void + { + $files = (new Filesystem(Hyde::getInstance()))->findFiles($directory, $matchExtension, $recursive); + + // Compare sorted arrays because some filesystems may return files in a different order. + $this->assertSame(collect($expected)->sort()->values()->all(), $files->sort()->values()->all()); + } + + protected function tearDown(): void + { + $this->cleanUpFilesystem(); + } +} From 4f73bda1a86c9b9bef3d114a555707f40761415d Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 13 Dec 2024 19:47:49 +0100 Subject: [PATCH 09/80] Move high level tests to feature test --- .../Feature/Foundation/FilesystemTest.php | 44 +++++++++++++++++++ .../tests/Unit/FilesystemFindFilesTest.php | 22 ---------- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/packages/framework/tests/Feature/Foundation/FilesystemTest.php b/packages/framework/tests/Feature/Foundation/FilesystemTest.php index 5527f9ce127..0f40af09f8e 100644 --- a/packages/framework/tests/Feature/Foundation/FilesystemTest.php +++ b/packages/framework/tests/Feature/Foundation/FilesystemTest.php @@ -13,16 +13,22 @@ use Hyde\Pages\HtmlPage; use Hyde\Pages\MarkdownPage; use Hyde\Pages\MarkdownPost; +use Hyde\Testing\CreatesTemporaryFiles; use Hyde\Testing\UnitTestCase; +use Illuminate\Support\Collection; use function Hyde\normalize_slashes; /** * @covers \Hyde\Foundation\HydeKernel * @covers \Hyde\Foundation\Kernel\Filesystem + * + * @see \Hyde\Framework\Testing\Unit\FilesystemFindFilesTest */ class FilesystemTest extends UnitTestCase { + use CreatesTemporaryFiles; + protected string $originalBasePath; protected Filesystem $filesystem; @@ -361,4 +367,42 @@ public function testPathToRelativeHelperDoesNotModifyNonProjectPaths() $this->assertSame(normalize_slashes($testString), Hyde::pathToRelative($testString)); } } + + public function testFindFileMethodFindsFilesInDirectory() + { + $this->files(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md']); + $files = $this->filesystem->findFiles('directory'); + + $this->assertCount(3, $files); + $this->assertContains('apple.md', $files); + $this->assertContains('banana.md', $files); + $this->assertContains('cherry.md', $files); + + $this->cleanUpFilesystem(); + } + + public function testFindFileMethodTypes() + { + $this->file('directory/apple.md'); + $files = $this->filesystem->findFiles('directory'); + + $this->assertInstanceOf(Collection::class, $files); + $this->assertContainsOnly('int', $files->keys()); + $this->assertContainsOnly('string', $files->all()); + $this->assertSame('apple.md', $files->first()); + + $this->cleanUpFilesystem(); + } + + public function testFindFileMethodTypesWithArguments() + { + $this->file('directory/apple.md'); + + $this->assertInstanceOf(Collection::class, $this->filesystem->findFiles('directory', false, false)); + $this->assertInstanceOf(Collection::class, $this->filesystem->findFiles('directory', 'md', false)); + $this->assertInstanceOf(Collection::class, $this->filesystem->findFiles('directory', false, true)); + $this->assertInstanceOf(Collection::class, $this->filesystem->findFiles('directory', 'md', true)); + + $this->cleanUpFilesystem(); + } } diff --git a/packages/framework/tests/Unit/FilesystemFindFilesTest.php b/packages/framework/tests/Unit/FilesystemFindFilesTest.php index e44d5b8eeb4..8ee9582a07a 100644 --- a/packages/framework/tests/Unit/FilesystemFindFilesTest.php +++ b/packages/framework/tests/Unit/FilesystemFindFilesTest.php @@ -75,28 +75,6 @@ public function testFindFilesReturnsCorrectFilesWhenUsingNestedSubdirectoriesOfD $this->assertSameArray(['apple.md', 'nested/banana.md'], 'directory', 'md', true); } - public function testFindFileMethodTypes() - { - $this->file('directory/apple.md'); - $filesystem = new Filesystem(Hyde::getInstance()); - $files = $filesystem->findFiles('directory'); - - $this->assertInstanceOf(Collection::class, $files); - $this->assertContainsOnly('int', $files->keys()); - $this->assertContainsOnly('string', $files->all()); - $this->assertSame('apple.md', $files->first()); - } - - public function testFindFileMethodTypesWithArguments() - { - $this->file('directory/apple.md'); - $filesystem = new Filesystem(Hyde::getInstance()); - - $this->assertInstanceOf(Collection::class, $filesystem->findFiles('directory', false, false)); - $this->assertInstanceOf(Collection::class, $filesystem->findFiles('directory', 'md', false)); - $this->assertInstanceOf(Collection::class, $filesystem->findFiles('directory', false, true)); - $this->assertInstanceOf(Collection::class, $filesystem->findFiles('directory', 'md', true)); - } protected function assertSameArray(array $expected, string $directory, string|false $matchExtension = false, bool $recursive = false): void { From b7389dce39a74757372aa45a1f91616a02675e8c Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 13 Dec 2024 19:49:46 +0100 Subject: [PATCH 10/80] Update signature to put extension first Bools might be more common to put first, but think extension may be more common to use --- packages/framework/src/Facades/Filesystem.php | 2 +- packages/framework/src/Foundation/Kernel/Filesystem.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/framework/src/Facades/Filesystem.php b/packages/framework/src/Facades/Filesystem.php index 97094cf9b46..96e638c94e3 100644 --- a/packages/framework/src/Facades/Filesystem.php +++ b/packages/framework/src/Facades/Filesystem.php @@ -69,7 +69,7 @@ public static function smartGlob(string $pattern, int $flags = 0): Collection return self::kernel()->filesystem()->smartGlob($pattern, $flags); } - public static function findFiles(string $directory, bool $recursive = false, ?bool $matchExtension = null): Collection + public static function findFiles(string $directory, string|false $matchExtension = false, bool $recursive = false): Collection { return self::kernel()->filesystem()->findFiles($directory, $recursive, $matchExtension); } diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index 56c9cd0d493..bc17cf36c6b 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -185,7 +185,7 @@ public function smartGlob(string $pattern, int $flags = 0): Collection } /** @return \Illuminate\Support\Collection */ - public function findFiles(string $directory, bool $recursive = false, ?bool $matchExtension = null): Collection + public function findFiles(string $directory, string|false $matchExtension = false, bool $recursive = false): Collection { // Todo: Implement this method } From ea06af82732f20183b27df69b34870fa195fb713 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 13 Dec 2024 19:50:03 +0100 Subject: [PATCH 11/80] Implement the new file finder method --- .../src/Foundation/Kernel/Filesystem.php | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index bc17cf36c6b..193576a0be8 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -8,6 +8,7 @@ use Hyde\Foundation\HydeKernel; use Hyde\Foundation\PharSupport; use Illuminate\Support\Collection; +use Symfony\Component\Finder\Finder; use function collect; use function Hyde\normalize_slashes; @@ -187,6 +188,32 @@ public function smartGlob(string $pattern, int $flags = 0): Collection /** @return \Illuminate\Support\Collection */ public function findFiles(string $directory, string|false $matchExtension = false, bool $recursive = false): Collection { - // Todo: Implement this method + // Resolve the full directory path based on the project root + $directory = $this->path($directory); + + // Create a Symfony Finder instance + $finder = new Finder(); + + // Configure Finder to look in the directory + $finder->files()->in($directory); + + // Configure Finder for recursive or non-recursive search + if (! $recursive) { + $finder->depth('== 0'); + } + + // Optionally match file extensions + if ($matchExtension !== false) { + $finder->name('*.'.$matchExtension); + } + + // Collect relative paths + $files = collect(); + + foreach ($finder as $file) { + $files->push(str_replace($directory . DIRECTORY_SEPARATOR, '', $file->getRealPath())); + } + + return $files; } } From ca4c0a2e4f58efd6a60b373ca5d9cdb1f428d80f Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 13 Dec 2024 19:51:46 +0100 Subject: [PATCH 12/80] Apply fixes from StyleCI --- packages/framework/src/Foundation/Kernel/Filesystem.php | 2 +- packages/framework/tests/Unit/FilesystemFindFilesTest.php | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index 193576a0be8..cabd75d816f 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -211,7 +211,7 @@ public function findFiles(string $directory, string|false $matchExtension = fals $files = collect(); foreach ($finder as $file) { - $files->push(str_replace($directory . DIRECTORY_SEPARATOR, '', $file->getRealPath())); + $files->push(str_replace($directory.DIRECTORY_SEPARATOR, '', $file->getRealPath())); } return $files; diff --git a/packages/framework/tests/Unit/FilesystemFindFilesTest.php b/packages/framework/tests/Unit/FilesystemFindFilesTest.php index 8ee9582a07a..da126c3e1e5 100644 --- a/packages/framework/tests/Unit/FilesystemFindFilesTest.php +++ b/packages/framework/tests/Unit/FilesystemFindFilesTest.php @@ -8,7 +8,6 @@ use Hyde\Testing\UnitTestCase; use Hyde\Testing\CreatesTemporaryFiles; use Hyde\Foundation\Kernel\Filesystem; -use Illuminate\Support\Collection; /** * @covers \Hyde\Foundation\Kernel\Filesystem::findFiles @@ -75,7 +74,6 @@ public function testFindFilesReturnsCorrectFilesWhenUsingNestedSubdirectoriesOfD $this->assertSameArray(['apple.md', 'nested/banana.md'], 'directory', 'md', true); } - protected function assertSameArray(array $expected, string $directory, string|false $matchExtension = false, bool $recursive = false): void { $files = (new Filesystem(Hyde::getInstance()))->findFiles($directory, $matchExtension, $recursive); From beb6c724de343ac4f18d6d10064675101aafad65 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 13 Dec 2024 20:01:29 +0100 Subject: [PATCH 13/80] Test edge cases --- .../tests/Unit/FilesystemFindFilesTest.php | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/packages/framework/tests/Unit/FilesystemFindFilesTest.php b/packages/framework/tests/Unit/FilesystemFindFilesTest.php index da126c3e1e5..27b4165144c 100644 --- a/packages/framework/tests/Unit/FilesystemFindFilesTest.php +++ b/packages/framework/tests/Unit/FilesystemFindFilesTest.php @@ -8,6 +8,7 @@ use Hyde\Testing\UnitTestCase; use Hyde\Testing\CreatesTemporaryFiles; use Hyde\Foundation\Kernel\Filesystem; +use Symfony\Component\Finder\Exception\DirectoryNotFoundException; /** * @covers \Hyde\Foundation\Kernel\Filesystem::findFiles @@ -74,6 +75,72 @@ public function testFindFilesReturnsCorrectFilesWhenUsingNestedSubdirectoriesOfD $this->assertSameArray(['apple.md', 'nested/banana.md'], 'directory', 'md', true); } + public function testFindFilesWithFilesHavingNoExtensions() + { + $this->files(['directory/file', 'directory/another_file']); + $this->assertSameArray(['file', 'another_file'], 'directory'); + } + + public function testFindFilesWithSpecialCharactersInNames() + { + $this->files(['directory/file-with-dash.md', 'directory/another_file.txt', 'directory/special@char!.blade.php']); + $this->assertSameArray(['file-with-dash.md', 'another_file.txt', 'special@char!.blade.php'], 'directory'); + } + + public function testFindFilesWithSpecialPrefixes() + { + $this->files(['directory/_file.md', 'directory/-another_file.txt', 'directory/~special_file.blade.php']); + $this->assertSameArray(['_file.md', '-another_file.txt', '~special_file.blade.php'], 'directory'); + } + + public function testFindFilesWithHiddenFiles() + { + $this->files(['directory/.hidden_file', 'directory/.another_hidden.md', 'directory/visible_file.md']); + $this->assertSameArray(['visible_file.md'], 'directory'); + } + + public function testFindFilesWithRecursiveAndHiddenFiles() + { + $this->files(['directory/.hidden_file', 'directory/nested/.another_hidden.md', 'directory/nested/visible_file.md']); + $this->assertSameArray(['nested/visible_file.md'], 'directory', false, true); + } + + public function testFindFilesWithEmptyExtensionFilter() + { + $this->files(['directory/file.md', 'directory/another_file.txt']); + $this->assertSameArray([], 'directory', ''); + } + + public function testFindFilesWithCaseInsensitiveExtensions() + { + $this->files(['directory/file.MD', 'directory/another_file.md', 'directory/ignored.TXT']); + $this->assertSameArray(['another_file.md'], 'directory', 'md'); + } + + public function testFindFilesWithCaseInsensitiveFilenames() + { + $this->files(['directory/file.md', 'directory/anotherFile.md', 'directory/ANOTHER_FILE.md']); + $this->assertSameArray(['file.md', 'anotherFile.md', 'ANOTHER_FILE.md'], 'directory'); + } + + public function testFindFilesHandlesLargeNumberOfFiles() + { + $this->files(array_map(fn ($i) => "directory/file$i.md", range(1, 100))); + $this->assertSameArray(array_map(fn ($i) => "file$i.md", range(1, 100)), 'directory'); + } + + public function testFindFilesWithEmptyDirectory() + { + $this->directory('directory'); + $this->assertSameArray([], 'directory'); + } + + public function testFindFilesWithNonExistentDirectory() + { + $this->expectException(DirectoryNotFoundException::class); + $this->assertSameArray([], 'nonexistent-directory'); + } + protected function assertSameArray(array $expected, string $directory, string|false $matchExtension = false, bool $recursive = false): void { $files = (new Filesystem(Hyde::getInstance()))->findFiles($directory, $matchExtension, $recursive); From 077bb2cf1614c78cca973d9299fc911c7094ca12 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Fri, 13 Dec 2024 20:08:06 +0100 Subject: [PATCH 14/80] Fix parameter order and add facade tests --- packages/framework/src/Facades/Filesystem.php | 2 +- .../tests/Unit/FilesystemFindFilesTest.php | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Facades/Filesystem.php b/packages/framework/src/Facades/Filesystem.php index 96e638c94e3..c8d859d9fa1 100644 --- a/packages/framework/src/Facades/Filesystem.php +++ b/packages/framework/src/Facades/Filesystem.php @@ -71,7 +71,7 @@ public static function smartGlob(string $pattern, int $flags = 0): Collection public static function findFiles(string $directory, string|false $matchExtension = false, bool $recursive = false): Collection { - return self::kernel()->filesystem()->findFiles($directory, $recursive, $matchExtension); + return self::kernel()->filesystem()->findFiles($directory, $matchExtension, $recursive); } /** diff --git a/packages/framework/tests/Unit/FilesystemFindFilesTest.php b/packages/framework/tests/Unit/FilesystemFindFilesTest.php index 27b4165144c..96ed93256a2 100644 --- a/packages/framework/tests/Unit/FilesystemFindFilesTest.php +++ b/packages/framework/tests/Unit/FilesystemFindFilesTest.php @@ -12,6 +12,7 @@ /** * @covers \Hyde\Foundation\Kernel\Filesystem::findFiles + * @covers \Hyde\Facades\Filesystem::findFiles * * @see \Hyde\Framework\Testing\Feature\FilesystemFacadeTest */ @@ -141,6 +142,25 @@ public function testFindFilesWithNonExistentDirectory() $this->assertSameArray([], 'nonexistent-directory'); } + public function testFindFilesFromFilesystemFacade() + { + $this->files(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md']); + $files = \Hyde\Facades\Filesystem::findFiles('directory'); + + $this->assertSame(['apple.md', 'banana.md', 'cherry.md'], $files->sort()->values()->all()); + } + + public function testFindFilesFromFilesystemFacadeWithArguments() + { + $this->files(['directory/apple.md', 'directory/banana.txt', 'directory/cherry.blade.php', 'directory/nested/dates.md']); + + $files = \Hyde\Facades\Filesystem::findFiles('directory', 'md'); + $this->assertSame(['apple.md'], $files->all()); + + $files = \Hyde\Facades\Filesystem::findFiles('directory', false, true); + $this->assertSame(['apple.md', 'banana.txt', 'cherry.blade.php', 'nested/dates.md'], $files->sort()->values()->all()); + } + protected function assertSameArray(array $expected, string $directory, string|false $matchExtension = false, bool $recursive = false): void { $files = (new Filesystem(Hyde::getInstance()))->findFiles($directory, $matchExtension, $recursive); From 9da4382e0e33f975bfabe1a60fde642a1dce44c1 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 10:38:44 +0100 Subject: [PATCH 15/80] Match extensions case insensitivly --- packages/framework/src/Foundation/Kernel/Filesystem.php | 4 ++-- packages/framework/tests/Unit/FilesystemFindFilesTest.php | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index cabd75d816f..a207efa3d21 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -202,9 +202,9 @@ public function findFiles(string $directory, string|false $matchExtension = fals $finder->depth('== 0'); } - // Optionally match file extensions + // Optionally match file extensions (case-insensitively) if ($matchExtension !== false) { - $finder->name('*.'.$matchExtension); + $finder->name('/\.' . preg_quote($matchExtension, '/') . '$/i'); } // Collect relative paths diff --git a/packages/framework/tests/Unit/FilesystemFindFilesTest.php b/packages/framework/tests/Unit/FilesystemFindFilesTest.php index 96ed93256a2..35eee65066a 100644 --- a/packages/framework/tests/Unit/FilesystemFindFilesTest.php +++ b/packages/framework/tests/Unit/FilesystemFindFilesTest.php @@ -115,7 +115,7 @@ public function testFindFilesWithEmptyExtensionFilter() public function testFindFilesWithCaseInsensitiveExtensions() { $this->files(['directory/file.MD', 'directory/another_file.md', 'directory/ignored.TXT']); - $this->assertSameArray(['another_file.md'], 'directory', 'md'); + $this->assertSameArray(['file.MD', 'another_file.md'], 'directory', 'md'); } public function testFindFilesWithCaseInsensitiveFilenames() @@ -124,6 +124,12 @@ public function testFindFilesWithCaseInsensitiveFilenames() $this->assertSameArray(['file.md', 'anotherFile.md', 'ANOTHER_FILE.md'], 'directory'); } + public function testFindFilesWithCaseInsensitiveExtensionFilter() + { + $this->files(['directory/file.MD', 'directory/another_file.md', 'directory/ignored.TXT']); + $this->assertSameArray(['file.MD', 'another_file.md'], 'directory', 'MD'); + } + public function testFindFilesHandlesLargeNumberOfFiles() { $this->files(array_map(fn ($i) => "directory/file$i.md", range(1, 100))); From f6bbd94cdbd758e106e5ee3097c435588d1ec3c7 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 10:38:58 +0100 Subject: [PATCH 16/80] Normalize input by removing a leading dot if present --- packages/framework/src/Foundation/Kernel/Filesystem.php | 6 +++++- packages/framework/tests/Unit/FilesystemFindFilesTest.php | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index a207efa3d21..891e5e1b0c3 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -204,7 +204,11 @@ public function findFiles(string $directory, string|false $matchExtension = fals // Optionally match file extensions (case-insensitively) if ($matchExtension !== false) { - $finder->name('/\.' . preg_quote($matchExtension, '/') . '$/i'); + // Normalize input by removing a leading dot if present + $normalizedExtension = ltrim($matchExtension, '.'); + + // Use a case-insensitive regex to match file extensions + $finder->name('/\.' . preg_quote($normalizedExtension, '/') . '$/i'); } // Collect relative paths diff --git a/packages/framework/tests/Unit/FilesystemFindFilesTest.php b/packages/framework/tests/Unit/FilesystemFindFilesTest.php index 35eee65066a..c535b61d037 100644 --- a/packages/framework/tests/Unit/FilesystemFindFilesTest.php +++ b/packages/framework/tests/Unit/FilesystemFindFilesTest.php @@ -130,6 +130,13 @@ public function testFindFilesWithCaseInsensitiveExtensionFilter() $this->assertSameArray(['file.MD', 'another_file.md'], 'directory', 'MD'); } + public function testFindFilesWithLeadingDotInFileExtension() + { + $this->files(['directory/file.md', 'directory/another_file.md', 'directory/ignored.txt']); + $this->assertSameArray(['file.md', 'another_file.md'], 'directory', 'md'); + $this->assertSameArray(['file.md', 'another_file.md'], 'directory', '.md'); + } + public function testFindFilesHandlesLargeNumberOfFiles() { $this->files(array_map(fn ($i) => "directory/file$i.md", range(1, 100))); From 01af8d5b4fe2d2fe5aaa741f6a64605289ed46ea Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 10:40:56 +0100 Subject: [PATCH 17/80] Sort the values to normalize between filesystems --- packages/framework/src/Foundation/Kernel/Filesystem.php | 3 ++- packages/framework/tests/Unit/FilesystemFindFilesTest.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index 891e5e1b0c3..0877de59b3b 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -218,6 +218,7 @@ public function findFiles(string $directory, string|false $matchExtension = fals $files->push(str_replace($directory.DIRECTORY_SEPARATOR, '', $file->getRealPath())); } - return $files; + // Sort files for consistent output + return $files->sort()->values(); } } diff --git a/packages/framework/tests/Unit/FilesystemFindFilesTest.php b/packages/framework/tests/Unit/FilesystemFindFilesTest.php index c535b61d037..9d97eeec877 100644 --- a/packages/framework/tests/Unit/FilesystemFindFilesTest.php +++ b/packages/framework/tests/Unit/FilesystemFindFilesTest.php @@ -179,7 +179,7 @@ protected function assertSameArray(array $expected, string $directory, string|fa $files = (new Filesystem(Hyde::getInstance()))->findFiles($directory, $matchExtension, $recursive); // Compare sorted arrays because some filesystems may return files in a different order. - $this->assertSame(collect($expected)->sort()->values()->all(), $files->sort()->values()->all()); + $this->assertSame(collect($expected)->sort()->values()->all(), $files->all()); } protected function tearDown(): void From be7abcc405d77d578e906fd0bd606f8f4f08f187 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 10:49:56 +0100 Subject: [PATCH 18/80] Cleanup and refactor the code --- .../src/Foundation/Kernel/Filesystem.php | 23 ++++--------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index 0877de59b3b..adbcb22d2d3 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -188,37 +188,22 @@ public function smartGlob(string $pattern, int $flags = 0): Collection /** @return \Illuminate\Support\Collection */ public function findFiles(string $directory, string|false $matchExtension = false, bool $recursive = false): Collection { - // Resolve the full directory path based on the project root - $directory = $this->path($directory); + $finder = Finder::create()->files()->in($this->path($directory)); - // Create a Symfony Finder instance - $finder = new Finder(); - - // Configure Finder to look in the directory - $finder->files()->in($directory); - - // Configure Finder for recursive or non-recursive search - if (! $recursive) { + if ($recursive === false) { $finder->depth('== 0'); } - // Optionally match file extensions (case-insensitively) if ($matchExtension !== false) { - // Normalize input by removing a leading dot if present - $normalizedExtension = ltrim($matchExtension, '.'); - - // Use a case-insensitive regex to match file extensions - $finder->name('/\.' . preg_quote($normalizedExtension, '/') . '$/i'); + $finder->name('/\.'.preg_quote(ltrim($matchExtension, '.'), '/').'$/i'); } - // Collect relative paths $files = collect(); foreach ($finder as $file) { - $files->push(str_replace($directory.DIRECTORY_SEPARATOR, '', $file->getRealPath())); + $files->push(str_replace($this->path($directory).DIRECTORY_SEPARATOR, '', $file->getRealPath())); } - // Sort files for consistent output return $files->sort()->values(); } } From 3485774a07ce84a70754a634f7df5e8f1eb29f4f Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 10:53:37 +0100 Subject: [PATCH 19/80] Collect iterator directly --- packages/framework/src/Foundation/Kernel/Filesystem.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index adbcb22d2d3..9c1fcdfe054 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -198,11 +198,9 @@ public function findFiles(string $directory, string|false $matchExtension = fals $finder->name('/\.'.preg_quote(ltrim($matchExtension, '.'), '/').'$/i'); } - $files = collect(); - - foreach ($finder as $file) { - $files->push(str_replace($this->path($directory).DIRECTORY_SEPARATOR, '', $file->getRealPath())); - } + $files = collect($finder)->map(function (string $file) use ($directory): string { + return str_replace($this->path($directory) . DIRECTORY_SEPARATOR, '', $file); + }); return $files->sort()->values(); } From 2c3786df94159f2cc3d06df87f256cb386390956 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 10:54:41 +0100 Subject: [PATCH 20/80] Clean up the method --- packages/framework/src/Foundation/Kernel/Filesystem.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index 9c1fcdfe054..7b1e1430f70 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -8,6 +8,7 @@ use Hyde\Foundation\HydeKernel; use Hyde\Foundation\PharSupport; use Illuminate\Support\Collection; +use Illuminate\Support\Str; use Symfony\Component\Finder\Finder; use function collect; @@ -199,7 +200,7 @@ public function findFiles(string $directory, string|false $matchExtension = fals } $files = collect($finder)->map(function (string $file) use ($directory): string { - return str_replace($this->path($directory) . DIRECTORY_SEPARATOR, '', $file); + return Str::after(normalize_slashes($file), $this->path($directory).'/'); }); return $files->sort()->values(); From edb397c2a0e0e33cdc3d177db8d33b2c940695ed Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 10:55:02 +0100 Subject: [PATCH 21/80] Inline local variable --- packages/framework/src/Foundation/Kernel/Filesystem.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index 7b1e1430f70..850a2cb2a77 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -199,10 +199,8 @@ public function findFiles(string $directory, string|false $matchExtension = fals $finder->name('/\.'.preg_quote(ltrim($matchExtension, '.'), '/').'$/i'); } - $files = collect($finder)->map(function (string $file) use ($directory): string { + return collect($finder)->map(function (string $file) use ($directory): string { return Str::after(normalize_slashes($file), $this->path($directory).'/'); - }); - - return $files->sort()->values(); + })->sort()->values(); } } From edbadae1a49e567aa746314052fe824de966de7a Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 11:05:11 +0100 Subject: [PATCH 22/80] Document the method --- packages/framework/src/Facades/Filesystem.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/framework/src/Facades/Filesystem.php b/packages/framework/src/Facades/Filesystem.php index c8d859d9fa1..8c690b1a0ae 100644 --- a/packages/framework/src/Facades/Filesystem.php +++ b/packages/framework/src/Facades/Filesystem.php @@ -69,6 +69,16 @@ public static function smartGlob(string $pattern, int $flags = 0): Collection return self::kernel()->filesystem()->smartGlob($pattern, $flags); } + /** + * Find files in the project's directory, with optional filtering by extension and recursion. + * + * The returned collection will be a list of paths relative to the specified directory. + * + * @param string $directory + * @param string|false $matchExtension The file extension to match, or false to match all files. + * @param bool $recursive Whether to search recursively or not. + * @return \Illuminate\Support\Collection + */ public static function findFiles(string $directory, string|false $matchExtension = false, bool $recursive = false): Collection { return self::kernel()->filesystem()->findFiles($directory, $matchExtension, $recursive); From 2825c84a3958a7be538a64d5f3cd424fdc06d77f Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 11:09:58 +0100 Subject: [PATCH 23/80] Return paths relative to the project root --- packages/framework/src/Facades/Filesystem.php | 2 +- packages/framework/src/Foundation/Kernel/Filesystem.php | 2 +- .../framework/tests/Feature/Foundation/FilesystemTest.php | 8 ++++---- packages/framework/tests/Unit/FilesystemFindFilesTest.php | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/framework/src/Facades/Filesystem.php b/packages/framework/src/Facades/Filesystem.php index 8c690b1a0ae..eb99587bdfd 100644 --- a/packages/framework/src/Facades/Filesystem.php +++ b/packages/framework/src/Facades/Filesystem.php @@ -72,7 +72,7 @@ public static function smartGlob(string $pattern, int $flags = 0): Collection /** * Find files in the project's directory, with optional filtering by extension and recursion. * - * The returned collection will be a list of paths relative to the specified directory. + * The returned collection will be a list of paths relative to the project root. * * @param string $directory * @param string|false $matchExtension The file extension to match, or false to match all files. diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index 850a2cb2a77..9c68233ebaf 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -200,7 +200,7 @@ public function findFiles(string $directory, string|false $matchExtension = fals } return collect($finder)->map(function (string $file) use ($directory): string { - return Str::after(normalize_slashes($file), $this->path($directory).'/'); + return $this->pathToRelative($file); })->sort()->values(); } } diff --git a/packages/framework/tests/Feature/Foundation/FilesystemTest.php b/packages/framework/tests/Feature/Foundation/FilesystemTest.php index 0f40af09f8e..9e4c1d9ddab 100644 --- a/packages/framework/tests/Feature/Foundation/FilesystemTest.php +++ b/packages/framework/tests/Feature/Foundation/FilesystemTest.php @@ -374,9 +374,9 @@ public function testFindFileMethodFindsFilesInDirectory() $files = $this->filesystem->findFiles('directory'); $this->assertCount(3, $files); - $this->assertContains('apple.md', $files); - $this->assertContains('banana.md', $files); - $this->assertContains('cherry.md', $files); + $this->assertContains('directory/apple.md', $files); + $this->assertContains('directory/banana.md', $files); + $this->assertContains('directory/cherry.md', $files); $this->cleanUpFilesystem(); } @@ -389,7 +389,7 @@ public function testFindFileMethodTypes() $this->assertInstanceOf(Collection::class, $files); $this->assertContainsOnly('int', $files->keys()); $this->assertContainsOnly('string', $files->all()); - $this->assertSame('apple.md', $files->first()); + $this->assertSame('directory/apple.md', $files->first()); $this->cleanUpFilesystem(); } diff --git a/packages/framework/tests/Unit/FilesystemFindFilesTest.php b/packages/framework/tests/Unit/FilesystemFindFilesTest.php index 9d97eeec877..9255c6a5008 100644 --- a/packages/framework/tests/Unit/FilesystemFindFilesTest.php +++ b/packages/framework/tests/Unit/FilesystemFindFilesTest.php @@ -160,7 +160,7 @@ public function testFindFilesFromFilesystemFacade() $this->files(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md']); $files = \Hyde\Facades\Filesystem::findFiles('directory'); - $this->assertSame(['apple.md', 'banana.md', 'cherry.md'], $files->sort()->values()->all()); + $this->assertSame(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md'], $files->sort()->values()->all()); } public function testFindFilesFromFilesystemFacadeWithArguments() @@ -168,10 +168,10 @@ public function testFindFilesFromFilesystemFacadeWithArguments() $this->files(['directory/apple.md', 'directory/banana.txt', 'directory/cherry.blade.php', 'directory/nested/dates.md']); $files = \Hyde\Facades\Filesystem::findFiles('directory', 'md'); - $this->assertSame(['apple.md'], $files->all()); + $this->assertSame(['directory/apple.md'], $files->all()); $files = \Hyde\Facades\Filesystem::findFiles('directory', false, true); - $this->assertSame(['apple.md', 'banana.txt', 'cherry.blade.php', 'nested/dates.md'], $files->sort()->values()->all()); + $this->assertSame(['directory/apple.md', 'directory/banana.txt', 'directory/cherry.blade.php', 'directory/nested/dates.md'], $files->sort()->values()->all()); } protected function assertSameArray(array $expected, string $directory, string|false $matchExtension = false, bool $recursive = false): void @@ -179,7 +179,7 @@ protected function assertSameArray(array $expected, string $directory, string|fa $files = (new Filesystem(Hyde::getInstance()))->findFiles($directory, $matchExtension, $recursive); // Compare sorted arrays because some filesystems may return files in a different order. - $this->assertSame(collect($expected)->sort()->values()->all(), $files->all()); + $this->assertSame(collect($expected)->map(fn (string $file): string => $directory.'/'.$file)->sort()->values()->all(), $files->all()); } protected function tearDown(): void From 71773ffe50362a6ae218e097e22d8c9475d85ee9 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 11:10:48 +0100 Subject: [PATCH 24/80] Update the file collection class to use better file finder --- packages/framework/src/Foundation/Kernel/FileCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/Foundation/Kernel/FileCollection.php b/packages/framework/src/Foundation/Kernel/FileCollection.php index b52355ddef8..49c67e49aa3 100644 --- a/packages/framework/src/Foundation/Kernel/FileCollection.php +++ b/packages/framework/src/Foundation/Kernel/FileCollection.php @@ -59,7 +59,7 @@ protected function runExtensionHandlers(): void protected function discoverFilesFor(string $pageClass): void { // Scan the source directory, and directories therein, for files that match the model's file extension. - foreach (Filesystem::smartGlob($pageClass::sourcePath('{*,**/*}'), GLOB_BRACE) as $path) { + foreach (Filesystem::findFiles($pageClass::sourceDirectory(), $pageClass::fileExtension(), true) as $path) { if (! str_starts_with(basename((string) $path), '_')) { $this->addFile(SourceFile::make($path, $pageClass)); } From 8cb72826c4c36fb1319606a40cc735f2dad0aa89 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 11:11:58 +0100 Subject: [PATCH 25/80] Files can now be discovered of any recursive depth And they can be compiled and viewed through the realtime compiler just fine --- packages/framework/tests/Feature/FileCollectionTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/framework/tests/Feature/FileCollectionTest.php b/packages/framework/tests/Feature/FileCollectionTest.php index 492705f3bb0..cb0d5ba85d9 100644 --- a/packages/framework/tests/Feature/FileCollectionTest.php +++ b/packages/framework/tests/Feature/FileCollectionTest.php @@ -111,15 +111,15 @@ public function testDiscoverFilesForRecursivelyDiscoversFilesInSubdirectories() { $this->file('_pages/foo.md'); $this->file('_pages/foo/bar.md'); - //$this->file('_pages/foo/bar/baz.md'); + $this->file('_pages/foo/bar/baz.md'); $collection = FileCollection::init(Hyde::getInstance())->boot(); $this->assertArrayHasKey('_pages/foo.md', $collection->toArray()); $this->assertArrayHasKey('_pages/foo/bar.md', $collection->toArray()); - //$this->assertArrayHasKey('_pages/foo/bar/baz.md', $collection->toArray()); + $this->assertArrayHasKey('_pages/foo/bar/baz.md', $collection->toArray()); $this->assertEquals(new SourceFile('_pages/foo.md', MarkdownPage::class), $collection->get('_pages/foo.md')); $this->assertEquals(new SourceFile('_pages/foo/bar.md', MarkdownPage::class), $collection->get('_pages/foo/bar.md')); - //$this->assertEquals(new SourceFile('_pages/foo/bar/baz.md', MarkdownPage::class), $collection->get('_pages/foo/bar/baz.md')); + $this->assertEquals(new SourceFile('_pages/foo/bar/baz.md', MarkdownPage::class), $collection->get('_pages/foo/bar/baz.md')); } } From 4e3a4aedf9e6695940a4f32f9945e3261b312418 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 13:44:50 +0100 Subject: [PATCH 26/80] Support multiple file extensions for file finder --- packages/framework/src/Facades/Filesystem.php | 6 +- .../src/Foundation/Kernel/Filesystem.php | 9 +- .../tests/Unit/FilesystemFindFilesTest.php | 85 ++++++++++++++++++- 3 files changed, 92 insertions(+), 8 deletions(-) diff --git a/packages/framework/src/Facades/Filesystem.php b/packages/framework/src/Facades/Filesystem.php index eb99587bdfd..487f61199a6 100644 --- a/packages/framework/src/Facades/Filesystem.php +++ b/packages/framework/src/Facades/Filesystem.php @@ -75,13 +75,13 @@ public static function smartGlob(string $pattern, int $flags = 0): Collection * The returned collection will be a list of paths relative to the project root. * * @param string $directory - * @param string|false $matchExtension The file extension to match, or false to match all files. + * @param string|array|false $matchExtensions The file extension(s) to match, or false to match all files. * @param bool $recursive Whether to search recursively or not. * @return \Illuminate\Support\Collection */ - public static function findFiles(string $directory, string|false $matchExtension = false, bool $recursive = false): Collection + public static function findFiles(string $directory, string|array|false $matchExtensions = false, bool $recursive = false): Collection { - return self::kernel()->filesystem()->findFiles($directory, $matchExtension, $recursive); + return self::kernel()->filesystem()->findFiles($directory, $matchExtensions, $recursive); } /** diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index 9c68233ebaf..e4bef03a93e 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -7,6 +7,7 @@ use Hyde\Hyde; use Hyde\Foundation\HydeKernel; use Hyde\Foundation\PharSupport; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Str; use Symfony\Component\Finder\Finder; @@ -187,7 +188,7 @@ public function smartGlob(string $pattern, int $flags = 0): Collection } /** @return \Illuminate\Support\Collection */ - public function findFiles(string $directory, string|false $matchExtension = false, bool $recursive = false): Collection + public function findFiles(string $directory, string|array|false $matchExtensions = false, bool $recursive = false): Collection { $finder = Finder::create()->files()->in($this->path($directory)); @@ -195,8 +196,10 @@ public function findFiles(string $directory, string|false $matchExtension = fals $finder->depth('== 0'); } - if ($matchExtension !== false) { - $finder->name('/\.'.preg_quote(ltrim($matchExtension, '.'), '/').'$/i'); + if ($matchExtensions !== false) { + $finder->name('/\.('.implode('|', array_map(function (string $extension): string { + return preg_quote(ltrim($extension, '.'), '/'); + }, Arr::wrap($matchExtensions))).')$/i'); } return collect($finder)->map(function (string $file) use ($directory): string { diff --git a/packages/framework/tests/Unit/FilesystemFindFilesTest.php b/packages/framework/tests/Unit/FilesystemFindFilesTest.php index 9255c6a5008..7b3f86cb92f 100644 --- a/packages/framework/tests/Unit/FilesystemFindFilesTest.php +++ b/packages/framework/tests/Unit/FilesystemFindFilesTest.php @@ -174,9 +174,90 @@ public function testFindFilesFromFilesystemFacadeWithArguments() $this->assertSame(['directory/apple.md', 'directory/banana.txt', 'directory/cherry.blade.php', 'directory/nested/dates.md'], $files->sort()->values()->all()); } - protected function assertSameArray(array $expected, string $directory, string|false $matchExtension = false, bool $recursive = false): void + public function testFindFilesWithMultipleExtensions() { - $files = (new Filesystem(Hyde::getInstance()))->findFiles($directory, $matchExtension, $recursive); + $this->files(['directory/file1.md', 'directory/file2.txt', 'directory/file3.blade.php']); + $this->assertSameArray(['file1.md', 'file2.txt'], 'directory', ['md', 'txt']); + } + + public function testFindFilesWithMultipleExtensionsButOnlyOneMatches() + { + $this->files(['directory/file1.md', 'directory/file2.blade.php', 'directory/file3.blade.php']); + $this->assertSameArray(['file1.md'], 'directory', ['md', 'txt']); + } + + public function testFindFilesWithMultipleExtensionsCaseInsensitive() + { + $this->files(['directory/file1.MD', 'directory/file2.TXT', 'directory/file3.blade.PHP']); + $this->assertSameArray(['file1.MD', 'file2.TXT'], 'directory', ['md', 'txt']); + } + + public function testFindFilesWithEmptyArrayExtensions() + { + $this->files(['directory/file1.md', 'directory/file2.txt']); + $this->assertSameArray([], 'directory', []); + } + + public function testFindFilesWithMixedExtensionsAndRecursion() + { + $this->files(['directory/file1.md', 'directory/nested/file2.txt', 'directory/nested/deep/file3.blade.php']); + $this->assertSameArray(['file1.md', 'nested/file2.txt'], 'directory', ['md', 'txt'], true); + } + + public function testFindFilesWithMixedExtensionsNoRecursion() + { + $this->files(['directory/file1.md', 'directory/nested/file2.txt']); + $this->assertSameArray(['file1.md'], 'directory', ['md', 'txt'], false); + } + + public function testFindFilesWithNoFilesMatchingAnyExtension() + { + $this->files(['directory/file1.md', 'directory/file2.txt']); + $this->assertSameArray([], 'directory', ['php', 'html']); + } + + public function testFindFilesWithRecursiveAndNoFilesMatchingAnyExtension() + { + $this->files(['directory/file1.md', 'directory/nested/file2.txt']); + $this->assertSameArray([], 'directory', ['php', 'html'], true); + } + + public function testFindFilesWithRecursiveAndSomeMatchingExtensions() + { + $this->files(['directory/file1.md', 'directory/nested/file2.txt', 'directory/nested/deep/file3.html']); + $this->assertSameArray(['file1.md', 'nested/file2.txt'], 'directory', ['md', 'txt'], true); + } + + public function testFindFilesWithOnlyDotInExtensions() + { + $this->files(['directory/file.md', 'directory/file.txt']); + $this->assertSameArray(['file.md'], 'directory', '.md'); + $this->assertSameArray(['file.txt'], 'directory', '.txt'); + } + + public function testFindFilesWithNoFilesWhenDirectoryContainsUnmatchedExtensions() + { + $this->files(['directory/file.md', 'directory/file.txt']); + $this->assertSameArray([], 'directory', 'php'); + $this->assertSameArray([], 'directory', ['php']); + } + + public function testFindFilesWithEmptyDirectoryAndMultipleExtensions() + { + $this->directory('directory'); + $this->assertSameArray([], 'directory', ['md', 'txt']); + } + + public function testFindFilesWithInvalidExtensionsThrowsNoError() + { + $this->files(['directory/file.md', 'directory/file.txt']); + $this->assertSameArray([], 'directory', ''); + $this->assertSameArray([], 'directory', ['']); + } + + protected function assertSameArray(array $expected, string $directory, string|array|false $matchExtensions = false, bool $recursive = false): void + { + $files = (new Filesystem(Hyde::getInstance()))->findFiles($directory, $matchExtensions, $recursive); // Compare sorted arrays because some filesystems may return files in a different order. $this->assertSame(collect($expected)->map(fn (string $file): string => $directory.'/'.$file)->sort()->values()->all(), $files->all()); From 9ae2e24c741034815995d34ae630f05f0c898823 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 13:48:05 +0100 Subject: [PATCH 27/80] Update data collection class to use better file finder feature --- packages/framework/src/Support/DataCollections.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/framework/src/Support/DataCollections.php b/packages/framework/src/Support/DataCollections.php index e05596c68e8..433bc17d76d 100644 --- a/packages/framework/src/Support/DataCollections.php +++ b/packages/framework/src/Support/DataCollections.php @@ -12,6 +12,7 @@ use Illuminate\Support\Collection; use Illuminate\Support\Str; +use function Hyde\path_join; use function implode; use function json_decode; use function sprintf; @@ -102,9 +103,7 @@ public static function json(string $name, bool $asArray = false): static protected static function findFiles(string $name, array|string $extensions): Collection { - return Filesystem::smartGlob(sprintf('%s/%s/*.{%s}', - static::$sourceDirectory, $name, implode(',', (array) $extensions) - ), GLOB_BRACE); + return Filesystem::findFiles(path_join(static::$sourceDirectory, $name), $extensions); } protected static function makeIdentifier(string $path): string From 22c09f7b0524857316033c56145e126d0ccfca95 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 13:49:25 +0100 Subject: [PATCH 28/80] Handle side effect in v1 branch --- packages/framework/src/Support/DataCollections.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/framework/src/Support/DataCollections.php b/packages/framework/src/Support/DataCollections.php index 433bc17d76d..aa124dcebf8 100644 --- a/packages/framework/src/Support/DataCollections.php +++ b/packages/framework/src/Support/DataCollections.php @@ -103,6 +103,13 @@ public static function json(string $name, bool $asArray = false): static protected static function findFiles(string $name, array|string $extensions): Collection { + if (! Filesystem::exists(path_join(static::$sourceDirectory, $name))) { + // To maintain compatability in the v1 branch, we return an empty collection if the directory does not exist. + // In v2.0, this will throw an exception by the findFiles method in the Filesystem class. + + return new Collection(); + } + return Filesystem::findFiles(path_join(static::$sourceDirectory, $name), $extensions); } From f68b1066bd8f6a2812c7be673e42c4c5c8473b7f Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 13:54:14 +0100 Subject: [PATCH 29/80] Don't throw if the directory does not exist If this was primarily a code API feature I would want this, but from our code (which is why we added this method) we want to be graceful if directories do not exist. If we throw, then we need to catch or add a precheck in a bunch of other places. --- packages/framework/src/Foundation/Kernel/Filesystem.php | 4 ++++ packages/framework/tests/Unit/FilesystemFindFilesTest.php | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index e4bef03a93e..840329e5dba 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -190,6 +190,10 @@ public function smartGlob(string $pattern, int $flags = 0): Collection /** @return \Illuminate\Support\Collection */ public function findFiles(string $directory, string|array|false $matchExtensions = false, bool $recursive = false): Collection { + if (! \Hyde\Facades\Filesystem::isDirectory($directory)) { + return collect(); + } + $finder = Finder::create()->files()->in($this->path($directory)); if ($recursive === false) { diff --git a/packages/framework/tests/Unit/FilesystemFindFilesTest.php b/packages/framework/tests/Unit/FilesystemFindFilesTest.php index 7b3f86cb92f..7193c078679 100644 --- a/packages/framework/tests/Unit/FilesystemFindFilesTest.php +++ b/packages/framework/tests/Unit/FilesystemFindFilesTest.php @@ -8,7 +8,6 @@ use Hyde\Testing\UnitTestCase; use Hyde\Testing\CreatesTemporaryFiles; use Hyde\Foundation\Kernel\Filesystem; -use Symfony\Component\Finder\Exception\DirectoryNotFoundException; /** * @covers \Hyde\Foundation\Kernel\Filesystem::findFiles @@ -151,7 +150,6 @@ public function testFindFilesWithEmptyDirectory() public function testFindFilesWithNonExistentDirectory() { - $this->expectException(DirectoryNotFoundException::class); $this->assertSameArray([], 'nonexistent-directory'); } From 6bae95b8a73d2b49914b9f1984fff1ae7a00a057 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 13:49:28 +0100 Subject: [PATCH 30/80] Revert "Handle side effect in v1 branch" This reverts commit fcad720597dc5c6bdd7c9049cec14ef9288528d7. --- packages/framework/src/Support/DataCollections.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/framework/src/Support/DataCollections.php b/packages/framework/src/Support/DataCollections.php index aa124dcebf8..433bc17d76d 100644 --- a/packages/framework/src/Support/DataCollections.php +++ b/packages/framework/src/Support/DataCollections.php @@ -103,13 +103,6 @@ public static function json(string $name, bool $asArray = false): static protected static function findFiles(string $name, array|string $extensions): Collection { - if (! Filesystem::exists(path_join(static::$sourceDirectory, $name))) { - // To maintain compatability in the v1 branch, we return an empty collection if the directory does not exist. - // In v2.0, this will throw an exception by the findFiles method in the Filesystem class. - - return new Collection(); - } - return Filesystem::findFiles(path_join(static::$sourceDirectory, $name), $extensions); } From cf12d59566ac73e90ee5b32abc924df1d8d25b01 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Sat, 14 Dec 2024 12:54:29 +0000 Subject: [PATCH 31/80] Apply fixes from StyleCI --- packages/framework/src/Facades/Filesystem.php | 4 ++-- packages/framework/src/Foundation/Kernel/Filesystem.php | 3 +-- packages/framework/src/Support/DataCollections.php | 2 -- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/framework/src/Facades/Filesystem.php b/packages/framework/src/Facades/Filesystem.php index 487f61199a6..2cbcf58bd59 100644 --- a/packages/framework/src/Facades/Filesystem.php +++ b/packages/framework/src/Facades/Filesystem.php @@ -75,8 +75,8 @@ public static function smartGlob(string $pattern, int $flags = 0): Collection * The returned collection will be a list of paths relative to the project root. * * @param string $directory - * @param string|array|false $matchExtensions The file extension(s) to match, or false to match all files. - * @param bool $recursive Whether to search recursively or not. + * @param string|array|false $matchExtensions The file extension(s) to match, or false to match all files. + * @param bool $recursive Whether to search recursively or not. * @return \Illuminate\Support\Collection */ public static function findFiles(string $directory, string|array|false $matchExtensions = false, bool $recursive = false): Collection diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index 840329e5dba..fee5ee435cc 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -9,7 +9,6 @@ use Hyde\Foundation\PharSupport; use Illuminate\Support\Arr; use Illuminate\Support\Collection; -use Illuminate\Support\Str; use Symfony\Component\Finder\Finder; use function collect; @@ -206,7 +205,7 @@ public function findFiles(string $directory, string|array|false $matchExtensions }, Arr::wrap($matchExtensions))).')$/i'); } - return collect($finder)->map(function (string $file) use ($directory): string { + return collect($finder)->map(function (string $file): string { return $this->pathToRelative($file); })->sort()->values(); } diff --git a/packages/framework/src/Support/DataCollections.php b/packages/framework/src/Support/DataCollections.php index 433bc17d76d..91a22906800 100644 --- a/packages/framework/src/Support/DataCollections.php +++ b/packages/framework/src/Support/DataCollections.php @@ -13,9 +13,7 @@ use Illuminate\Support\Str; use function Hyde\path_join; -use function implode; use function json_decode; -use function sprintf; use function Hyde\unslash; use function str_starts_with; From 95592c6121691e851d215a0dc1eb71fe591fd9ec Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 14:36:35 +0100 Subject: [PATCH 32/80] Refactor test to not test implementations --- .../Pages/PageModelGetAllFilesHelperTest.php | 54 +++++++------------ 1 file changed, 20 insertions(+), 34 deletions(-) diff --git a/packages/framework/tests/Unit/Pages/PageModelGetAllFilesHelperTest.php b/packages/framework/tests/Unit/Pages/PageModelGetAllFilesHelperTest.php index 6ca5e43d91f..68257f0e847 100644 --- a/packages/framework/tests/Unit/Pages/PageModelGetAllFilesHelperTest.php +++ b/packages/framework/tests/Unit/Pages/PageModelGetAllFilesHelperTest.php @@ -4,56 +4,43 @@ namespace Hyde\Framework\Testing\Unit\Pages; -use Hyde\Hyde; +use Hyde\Foundation\HydeKernel; use Hyde\Pages\BladePage; +use Hyde\Testing\CreatesTemporaryFiles; use Hyde\Testing\UnitTestCase; use Hyde\Pages\DocumentationPage; use Hyde\Pages\MarkdownPage; use Hyde\Pages\MarkdownPost; -use Mockery\ExpectationInterface; -/** - * @see \Hyde\Pages\Concerns\HydePage::files() - */ class PageModelGetAllFilesHelperTest extends UnitTestCase { - protected static bool $needsConfig = true; - - /** @var \Illuminate\Filesystem\Filesystem&\Mockery\MockInterface */ - protected $filesystem; + use CreatesTemporaryFiles; - protected function setUp(): void - { - self::setupKernel(); - - $this->filesystem = $this->mockFilesystemStrict() - ->shouldReceive('missing')->withAnyArgs()->andReturn(false)->byDefault() - ->shouldReceive('get')->withAnyArgs()->andReturn('foo')->byDefault() - ->shouldReceive('glob')->once()->with(Hyde::path('_pages/{*,**/*}.html'), GLOB_BRACE)->andReturn([])->byDefault() - ->shouldReceive('glob')->once()->with(Hyde::path('_pages/{*,**/*}.blade.php'), GLOB_BRACE)->andReturn([])->byDefault() - ->shouldReceive('glob')->once()->with(Hyde::path('_pages/{*,**/*}.md'), GLOB_BRACE)->andReturn([])->byDefault() - ->shouldReceive('glob')->once()->with(Hyde::path('_posts/{*,**/*}.md'), GLOB_BRACE)->andReturn([])->byDefault() - ->shouldReceive('glob')->once()->with(Hyde::path('_docs/{*,**/*}.md'), GLOB_BRACE)->andReturn([])->byDefault(); - } + protected static bool $needsKernel = true; + protected static bool $needsConfig = true; protected function tearDown(): void { - $this->verifyMockeryExpectations(); + $this->cleanupFilesystem(); } public function testBladePageGetHelperReturnsBladePageArray() { - $this->shouldReceiveGlob('_pages/{*,**/*}.blade.php')->andReturn(['_pages/test-page.blade.php']); + $this->files(['_pages/test-page.blade.php']); + + HydeKernel::getInstance()->boot(); $array = BladePage::files(); - $this->assertCount(1, $array); + $this->assertCount(3, $array); $this->assertIsArray($array); - $this->assertEquals(['test-page'], $array); + $this->assertEquals(['404', 'index', 'test-page'], $array); } public function testMarkdownPageGetHelperReturnsMarkdownPageArray() { - $this->shouldReceiveGlob('_pages/{*,**/*}.md')->andReturn(['_pages/test-page.md']); + $this->files(['_pages/test-page.md']); + + HydeKernel::getInstance()->boot(); $array = MarkdownPage::files(); $this->assertCount(1, $array); @@ -63,7 +50,9 @@ public function testMarkdownPageGetHelperReturnsMarkdownPageArray() public function testMarkdownPostGetHelperReturnsMarkdownPostArray() { - $this->shouldReceiveGlob('_posts/{*,**/*}.md')->andReturn(['_posts/test-post.md']); + $this->files(['_posts/test-post.md']); + + HydeKernel::getInstance()->boot(); $array = MarkdownPost::files(); $this->assertCount(1, $array); @@ -73,16 +62,13 @@ public function testMarkdownPostGetHelperReturnsMarkdownPostArray() public function testDocumentationPageGetHelperReturnsDocumentationPageArray() { - $this->shouldReceiveGlob('_docs/{*,**/*}.md')->andReturn(['_docs/test-page.md']); + $this->files(['_docs/test-page.md']); + + HydeKernel::getInstance()->boot(); $array = DocumentationPage::files(); $this->assertCount(1, $array); $this->assertIsArray($array); $this->assertEquals(['test-page'], $array); } - - protected function shouldReceiveGlob(string $withPath): ExpectationInterface - { - return $this->filesystem->shouldReceive('glob')->once()->with(Hyde::path($withPath), GLOB_BRACE); - } } From 8423ea29bc3bfbb1db23d41a340d96bbfc293f61 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 17:00:12 +0100 Subject: [PATCH 33/80] Refactor media file discovery to use improved file finder --- packages/framework/src/Support/Filesystem/MediaFile.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 45298a50694..aea39afd555 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -4,6 +4,7 @@ namespace Hyde\Support\Filesystem; +use Hyde\Facades\Filesystem; use Hyde\Hyde; use Hyde\Facades\Config; use Hyde\Framework\Exceptions\FileNotFoundException; @@ -106,13 +107,11 @@ protected static function discoverMediaAssetFiles(): array protected static function getMediaAssetFiles(): array { - return glob(Hyde::path(static::getMediaGlobPattern()), GLOB_BRACE) ?: []; + return Filesystem::findFiles(Hyde::getMediaDirectory(), static::getMediaFileExtensions(), true)->all(); } - protected static function getMediaGlobPattern(): string + protected static function getMediaFileExtensions(): array { - return sprintf(Hyde::getMediaDirectory().'/{*,**/*,**/*/*}.{%s}', implode(',', - Config::getArray('hyde.media_extensions', self::EXTENSIONS) - )); + return Config::getArray('hyde.media_extensions', self::EXTENSIONS); } } From 1212d6a9faf7c53aca3245b83e46ffa6c49c417f Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 17:01:10 +0100 Subject: [PATCH 34/80] Fix test not testing the documented behavior See https://github.com/hydephp/develop/issues/39 --- packages/framework/tests/Feature/DiscoveryServiceTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/tests/Feature/DiscoveryServiceTest.php b/packages/framework/tests/Feature/DiscoveryServiceTest.php index e545cd64b7b..abafa46cd9b 100644 --- a/packages/framework/tests/Feature/DiscoveryServiceTest.php +++ b/packages/framework/tests/Feature/DiscoveryServiceTest.php @@ -130,7 +130,7 @@ public function testMediaAssetExtensionsCanBeAddedByCommaSeparatedValues() $this->assertSame([], MediaFile::files()); - self::mockConfig(['hyde.media_extensions' => ['1,2,3']]); + self::mockConfig(['hyde.media_extensions' => '1,2,3']); $this->assertSame(['test.1', 'test.2', 'test.3'], MediaFile::files()); } From c61ba27c507192d396b4b2bc274c12be0748e870 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 17:11:01 +0100 Subject: [PATCH 35/80] Support comma separated extensions input --- .../src/Foundation/Kernel/Filesystem.php | 6 +++++- .../tests/Unit/FilesystemFindFilesTest.php | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index fee5ee435cc..a37546dbe15 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -200,9 +200,13 @@ public function findFiles(string $directory, string|array|false $matchExtensions } if ($matchExtensions !== false) { + if (is_string($matchExtensions)) { + $matchExtensions = array_map('trim', explode(',', $matchExtensions)); + } + $finder->name('/\.('.implode('|', array_map(function (string $extension): string { return preg_quote(ltrim($extension, '.'), '/'); - }, Arr::wrap($matchExtensions))).')$/i'); + }, $matchExtensions)).')$/i'); } return collect($finder)->map(function (string $file): string { diff --git a/packages/framework/tests/Unit/FilesystemFindFilesTest.php b/packages/framework/tests/Unit/FilesystemFindFilesTest.php index 7193c078679..5c992d01cfc 100644 --- a/packages/framework/tests/Unit/FilesystemFindFilesTest.php +++ b/packages/framework/tests/Unit/FilesystemFindFilesTest.php @@ -253,6 +253,24 @@ public function testFindFilesWithInvalidExtensionsThrowsNoError() $this->assertSameArray([], 'directory', ['']); } + public function testFindFilesWithCsvStringExtensions() + { + $this->files(['directory/file1.md', 'directory/file2.txt', 'directory/file3.jpg']); + $this->assertSameArray(['file1.md', 'file2.txt'], 'directory', 'md,txt'); + } + + public function testFindFilesWithCsvStringExtensionsAndSpaces() + { + $this->files(['directory/file1.md', 'directory/file2.txt', 'directory/file3.jpg']); + $this->assertSameArray(['file1.md', 'file2.txt'], 'directory', 'md, txt'); + } + + public function testFindFilesWithCsvStringExtensionsMixedCase() + { + $this->files(['directory/file1.MD', 'directory/file2.TXT', 'directory/file3.jpg']); + $this->assertSameArray(['file1.MD', 'file2.TXT'], 'directory', 'md,TXT'); + } + protected function assertSameArray(array $expected, string $directory, string|array|false $matchExtensions = false, bool $recursive = false): void { $files = (new Filesystem(Hyde::getInstance()))->findFiles($directory, $matchExtensions, $recursive); From a0e93c42d9a67d315083b11136d171ee0d60287f Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 17:11:23 +0100 Subject: [PATCH 36/80] Custom media file extensions now take string config input As documented in the original implementation details --- packages/framework/src/Support/Filesystem/MediaFile.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index aea39afd555..3bf8b17805b 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -110,8 +110,8 @@ protected static function getMediaAssetFiles(): array return Filesystem::findFiles(Hyde::getMediaDirectory(), static::getMediaFileExtensions(), true)->all(); } - protected static function getMediaFileExtensions(): array + protected static function getMediaFileExtensions(): array|string { - return Config::getArray('hyde.media_extensions', self::EXTENSIONS); + return Config::get('hyde.media_extensions', self::EXTENSIONS); } } From 04526e626729d6cba8b694ff2b41f41cfc9c545d Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Sat, 14 Dec 2024 16:17:40 +0000 Subject: [PATCH 37/80] Apply fixes from StyleCI --- packages/framework/src/Foundation/Kernel/Filesystem.php | 1 - packages/framework/src/Support/Filesystem/MediaFile.php | 3 --- 2 files changed, 4 deletions(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index a37546dbe15..5175e48ee46 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -7,7 +7,6 @@ use Hyde\Hyde; use Hyde\Foundation\HydeKernel; use Hyde\Foundation\PharSupport; -use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Symfony\Component\Finder\Finder; diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 3bf8b17805b..1237a95baad 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -15,12 +15,9 @@ use function array_merge; use function array_keys; use function filesize; -use function implode; use function pathinfo; use function collect; use function is_file; -use function sprintf; -use function glob; /** * File abstraction for a project media file. From d6a26e53a1eb2fa9f7525747aec98da30d2fa1c0 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 17:16:59 +0100 Subject: [PATCH 38/80] Add refactoring todo The refactoring is worthwhile because: Makes the code more maintainable and testable Breaks down complex logic into smaller, focused methods Preserves the public API while improving internal organization Reduces the cognitive load when reading the Filesystem class We can make it swappable in testing through the service container --- packages/framework/src/Foundation/Kernel/Filesystem.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index 5175e48ee46..7c6fe24bb84 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -188,6 +188,8 @@ public function smartGlob(string $pattern, int $flags = 0): Collection /** @return \Illuminate\Support\Collection */ public function findFiles(string $directory, string|array|false $matchExtensions = false, bool $recursive = false): Collection { + // TODO: Extract to internal class + if (! \Hyde\Facades\Filesystem::isDirectory($directory)) { return collect(); } From e6ec49b5ab9e740e7f96aacaeb1d7aad65062fa6 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 19:18:55 +0100 Subject: [PATCH 39/80] Move facade tests to main test --- .../Feature/Foundation/FilesystemTest.php | 20 +++++++++++++++++++ .../tests/Unit/FilesystemFindFilesTest.php | 19 ------------------ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/packages/framework/tests/Feature/Foundation/FilesystemTest.php b/packages/framework/tests/Feature/Foundation/FilesystemTest.php index 9e4c1d9ddab..2b5576e20f0 100644 --- a/packages/framework/tests/Feature/Foundation/FilesystemTest.php +++ b/packages/framework/tests/Feature/Foundation/FilesystemTest.php @@ -22,6 +22,7 @@ /** * @covers \Hyde\Foundation\HydeKernel * @covers \Hyde\Foundation\Kernel\Filesystem + * @covers \Hyde\Facades\Filesystem * * @see \Hyde\Framework\Testing\Unit\FilesystemFindFilesTest */ @@ -405,4 +406,23 @@ public function testFindFileMethodTypesWithArguments() $this->cleanUpFilesystem(); } + + public function testFindFilesFromFilesystemFacade() + { + $this->files(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md']); + $files = \Hyde\Facades\Filesystem::findFiles('directory'); + + $this->assertSame(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md'], $files->sort()->values()->all()); + } + + public function testFindFilesFromFilesystemFacadeWithArguments() + { + $this->files(['directory/apple.md', 'directory/banana.txt', 'directory/cherry.blade.php', 'directory/nested/dates.md']); + + $files = \Hyde\Facades\Filesystem::findFiles('directory', 'md'); + $this->assertSame(['directory/apple.md'], $files->all()); + + $files = \Hyde\Facades\Filesystem::findFiles('directory', false, true); + $this->assertSame(['directory/apple.md', 'directory/banana.txt', 'directory/cherry.blade.php', 'directory/nested/dates.md'], $files->sort()->values()->all()); + } } diff --git a/packages/framework/tests/Unit/FilesystemFindFilesTest.php b/packages/framework/tests/Unit/FilesystemFindFilesTest.php index 5c992d01cfc..0e90c9fdc31 100644 --- a/packages/framework/tests/Unit/FilesystemFindFilesTest.php +++ b/packages/framework/tests/Unit/FilesystemFindFilesTest.php @@ -153,25 +153,6 @@ public function testFindFilesWithNonExistentDirectory() $this->assertSameArray([], 'nonexistent-directory'); } - public function testFindFilesFromFilesystemFacade() - { - $this->files(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md']); - $files = \Hyde\Facades\Filesystem::findFiles('directory'); - - $this->assertSame(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md'], $files->sort()->values()->all()); - } - - public function testFindFilesFromFilesystemFacadeWithArguments() - { - $this->files(['directory/apple.md', 'directory/banana.txt', 'directory/cherry.blade.php', 'directory/nested/dates.md']); - - $files = \Hyde\Facades\Filesystem::findFiles('directory', 'md'); - $this->assertSame(['directory/apple.md'], $files->all()); - - $files = \Hyde\Facades\Filesystem::findFiles('directory', false, true); - $this->assertSame(['directory/apple.md', 'directory/banana.txt', 'directory/cherry.blade.php', 'directory/nested/dates.md'], $files->sort()->values()->all()); - } - public function testFindFilesWithMultipleExtensions() { $this->files(['directory/file1.md', 'directory/file2.txt', 'directory/file3.blade.php']); From 2e9c4043248aa3b06d1e5b3ed67c6167552ab746 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 19:19:00 +0100 Subject: [PATCH 40/80] Remove test link --- packages/framework/tests/Feature/Foundation/FilesystemTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/framework/tests/Feature/Foundation/FilesystemTest.php b/packages/framework/tests/Feature/Foundation/FilesystemTest.php index 2b5576e20f0..eff8fcab51f 100644 --- a/packages/framework/tests/Feature/Foundation/FilesystemTest.php +++ b/packages/framework/tests/Feature/Foundation/FilesystemTest.php @@ -23,8 +23,6 @@ * @covers \Hyde\Foundation\HydeKernel * @covers \Hyde\Foundation\Kernel\Filesystem * @covers \Hyde\Facades\Filesystem - * - * @see \Hyde\Framework\Testing\Unit\FilesystemFindFilesTest */ class FilesystemTest extends UnitTestCase { From 5971948188b0e486d9cf302934c4dafc74246bbc Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 19:25:48 +0100 Subject: [PATCH 41/80] Extract internal class for file finder helper --- .../src/Foundation/Kernel/Filesystem.php | 28 +---------- .../Framework/Actions/Internal/FileFinder.php | 47 +++++++++++++++++++ ...emFindFilesTest.php => FileFinderTest.php} | 7 +-- 3 files changed, 51 insertions(+), 31 deletions(-) create mode 100644 packages/framework/src/Framework/Actions/Internal/FileFinder.php rename packages/framework/tests/Unit/{FilesystemFindFilesTest.php => FileFinderTest.php} (98%) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index 7c6fe24bb84..3d0e3a7ab25 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -8,7 +8,7 @@ use Hyde\Foundation\HydeKernel; use Hyde\Foundation\PharSupport; use Illuminate\Support\Collection; -use Symfony\Component\Finder\Finder; +use Hyde\Framework\Actions\Internal\FileFinder; use function collect; use function Hyde\normalize_slashes; @@ -188,30 +188,6 @@ public function smartGlob(string $pattern, int $flags = 0): Collection /** @return \Illuminate\Support\Collection */ public function findFiles(string $directory, string|array|false $matchExtensions = false, bool $recursive = false): Collection { - // TODO: Extract to internal class - - if (! \Hyde\Facades\Filesystem::isDirectory($directory)) { - return collect(); - } - - $finder = Finder::create()->files()->in($this->path($directory)); - - if ($recursive === false) { - $finder->depth('== 0'); - } - - if ($matchExtensions !== false) { - if (is_string($matchExtensions)) { - $matchExtensions = array_map('trim', explode(',', $matchExtensions)); - } - - $finder->name('/\.('.implode('|', array_map(function (string $extension): string { - return preg_quote(ltrim($extension, '.'), '/'); - }, $matchExtensions)).')$/i'); - } - - return collect($finder)->map(function (string $file): string { - return $this->pathToRelative($file); - })->sort()->values(); + return FileFinder::handle($directory, $matchExtensions, $recursive); } } diff --git a/packages/framework/src/Framework/Actions/Internal/FileFinder.php b/packages/framework/src/Framework/Actions/Internal/FileFinder.php new file mode 100644 index 00000000000..e596fac7170 --- /dev/null +++ b/packages/framework/src/Framework/Actions/Internal/FileFinder.php @@ -0,0 +1,47 @@ +|false $matchExtensions + * @return \Illuminate\Support\Collection + */ + public static function handle(string $directory, string|array|false $matchExtensions = false, bool $recursive = false): Collection + { + if (! Filesystem::isDirectory($directory)) { + return collect(); + } + + $finder = Finder::create()->files()->in(Hyde::path($directory)); + + if ($recursive === false) { + $finder->depth('== 0'); + } + + if ($matchExtensions !== false) { + if (is_string($matchExtensions)) { + $matchExtensions = array_map('trim', explode(',', $matchExtensions)); + } + + $finder->name('/\.('.implode('|', array_map(function (string $extension): string { + return preg_quote(ltrim($extension, '.'), '/'); + }, $matchExtensions)).')$/i'); + } + + return collect($finder)->map(function (string $file): string { + return Hyde::pathToRelative($file); + })->sort()->values(); + } +} diff --git a/packages/framework/tests/Unit/FilesystemFindFilesTest.php b/packages/framework/tests/Unit/FileFinderTest.php similarity index 98% rename from packages/framework/tests/Unit/FilesystemFindFilesTest.php rename to packages/framework/tests/Unit/FileFinderTest.php index 0e90c9fdc31..852daddfa5d 100644 --- a/packages/framework/tests/Unit/FilesystemFindFilesTest.php +++ b/packages/framework/tests/Unit/FileFinderTest.php @@ -10,12 +10,9 @@ use Hyde\Foundation\Kernel\Filesystem; /** - * @covers \Hyde\Foundation\Kernel\Filesystem::findFiles - * @covers \Hyde\Facades\Filesystem::findFiles - * - * @see \Hyde\Framework\Testing\Feature\FilesystemFacadeTest + * @covers \Hyde\Framework\Actions\Internal\FileFinder */ -class FilesystemFindFilesTest extends UnitTestCase +class FileFinderTest extends UnitTestCase { use CreatesTemporaryFiles; From 3d0993a30b5400244455d03b5e9c4ae47b299eca Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 19:27:20 +0100 Subject: [PATCH 42/80] Add missing test cleanup --- .../framework/tests/Feature/Foundation/FilesystemTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/framework/tests/Feature/Foundation/FilesystemTest.php b/packages/framework/tests/Feature/Foundation/FilesystemTest.php index eff8fcab51f..ed40fa05795 100644 --- a/packages/framework/tests/Feature/Foundation/FilesystemTest.php +++ b/packages/framework/tests/Feature/Foundation/FilesystemTest.php @@ -411,6 +411,8 @@ public function testFindFilesFromFilesystemFacade() $files = \Hyde\Facades\Filesystem::findFiles('directory'); $this->assertSame(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md'], $files->sort()->values()->all()); + + $this->cleanUpFilesystem(); } public function testFindFilesFromFilesystemFacadeWithArguments() @@ -422,5 +424,7 @@ public function testFindFilesFromFilesystemFacadeWithArguments() $files = \Hyde\Facades\Filesystem::findFiles('directory', false, true); $this->assertSame(['directory/apple.md', 'directory/banana.txt', 'directory/cherry.blade.php', 'directory/nested/dates.md'], $files->sort()->values()->all()); + + $this->cleanUpFilesystem(); } } From 935ab77833a7eac0cab533429a115ef273a3853c Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 19:31:40 +0100 Subject: [PATCH 43/80] Dependency inject the finder so we can mock it in tests --- .../src/Foundation/Kernel/Filesystem.php | 4 +++- .../tests/Feature/Foundation/FilesystemTest.php | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index 3d0e3a7ab25..9e6d6f408b9 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -188,6 +188,8 @@ public function smartGlob(string $pattern, int $flags = 0): Collection /** @return \Illuminate\Support\Collection */ public function findFiles(string $directory, string|array|false $matchExtensions = false, bool $recursive = false): Collection { - return FileFinder::handle($directory, $matchExtensions, $recursive); + $finder = app(FileFinder::class); + + return $finder::handle($directory, $matchExtensions, $recursive); } } diff --git a/packages/framework/tests/Feature/Foundation/FilesystemTest.php b/packages/framework/tests/Feature/Foundation/FilesystemTest.php index ed40fa05795..d4b9a8aa968 100644 --- a/packages/framework/tests/Feature/Foundation/FilesystemTest.php +++ b/packages/framework/tests/Feature/Foundation/FilesystemTest.php @@ -7,6 +7,7 @@ use Hyde\Foundation\HydeKernel; use Hyde\Foundation\Kernel\Filesystem; use Hyde\Foundation\PharSupport; +use Hyde\Framework\Actions\Internal\FileFinder; use Hyde\Hyde; use Hyde\Pages\BladePage; use Hyde\Pages\DocumentationPage; @@ -427,4 +428,18 @@ public function testFindFilesFromFilesystemFacadeWithArguments() $this->cleanUpFilesystem(); } + + public function testCanSwapOutFileFinder() + { + app()->bind(FileFinder::class, function () { + return new class { + public static function handle(): Collection + { + return collect(['mocked']); + } + }; + }); + + $this->assertSame(['mocked'], \Hyde\Facades\Filesystem::findFiles('directory')->toArray()); + } } From b420f7a9cdc997862f975d7e69331c14cc6ccafe Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 11:30:11 +0100 Subject: [PATCH 44/80] Improve test mocks --- .../tests/Unit/DataCollectionUnitTest.php | 45 ++++++++----------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/packages/framework/tests/Unit/DataCollectionUnitTest.php b/packages/framework/tests/Unit/DataCollectionUnitTest.php index 26791d39fa5..bf15e4ffa7a 100644 --- a/packages/framework/tests/Unit/DataCollectionUnitTest.php +++ b/packages/framework/tests/Unit/DataCollectionUnitTest.php @@ -4,7 +4,7 @@ namespace Hyde\Framework\Testing\Unit; -use Hyde\Hyde; +use Hyde\Framework\Actions\Internal\FileFinder; use Hyde\Support\DataCollections; use Hyde\Testing\UnitTestCase; use Illuminate\Filesystem\Filesystem; @@ -45,18 +45,9 @@ public function testCanConvertCollectionToJson() $this->assertSame('[]', (new DataCollections())->toJson()); } - public function testFindMarkdownFilesCallsProperGlobPattern() - { - $this->mockFilesystemFacade(['shouldReceiveGlob' => true]); - - DataCollections::markdown('foo')->keys()->toArray(); - - $this->verifyMockeryExpectations(); - } - public function testFindMarkdownFilesWithNoFiles() { - $this->mockFilesystemFacade(); + $this->mockFileFinder([]); $this->assertSame([], DataCollections::markdown('foo')->keys()->toArray()); @@ -65,7 +56,7 @@ public function testFindMarkdownFilesWithNoFiles() public function testFindMarkdownFilesWithFiles() { - $this->mockFilesystemFacade(['glob' => ['bar.md']]); + $this->mockFileFinder(['bar.md']); $this->assertSame(['bar.md'], DataCollections::markdown('foo')->keys()->toArray()); @@ -77,25 +68,25 @@ public function testStaticMarkdownHelperReturnsNewDataCollectionInstance() $this->assertInstanceOf(DataCollections::class, DataCollections::markdown('foo')); } - protected function mockFilesystemFacade(array $config = []): void + protected function mockFileFinder(array $files): void { - $defaults = [ - 'exists' => true, - 'glob' => [], - 'get' => 'foo', - ]; + $filesystem = Mockery::mock(Filesystem::class); + $filesystem->shouldReceive('exists')->andReturn(true); + $filesystem->shouldReceive('get')->andReturn('foo'); - $config = array_merge($defaults, $config); + app()->instance(Filesystem::class, $filesystem); - $filesystem = Mockery::mock(Filesystem::class, $config); + $finder = Mockery::mock(FileFinder::class); + $finder->shouldReceive('handle')->andReturn(collect($files)); - if (isset($config['shouldReceiveGlob'])) { - $filesystem->shouldReceive('glob') - ->with(Hyde::path('resources/collections/foo/*.{md}'), GLOB_BRACE) - ->once() - ->andReturn($config['glob']); - } + app()->instance(FileFinder::class, $finder); + } - app()->instance(Filesystem::class, $filesystem); + protected function verifyMockeryExpectations(): void + { + parent::verifyMockeryExpectations(); + + app()->forgetInstance(Filesystem::class); + app()->forgetInstance(FileFinder::class); } } From 9090e0f8d3f6fbfcc33c48162ab72589b56a22d7 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 19:32:04 +0100 Subject: [PATCH 45/80] Cleanup the code --- packages/framework/src/Foundation/Kernel/Filesystem.php | 4 +--- .../framework/src/Framework/Actions/Internal/FileFinder.php | 6 +++--- .../framework/tests/Feature/Foundation/FilesystemTest.php | 3 ++- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index 9e6d6f408b9..b480e204f64 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -188,8 +188,6 @@ public function smartGlob(string $pattern, int $flags = 0): Collection /** @return \Illuminate\Support\Collection */ public function findFiles(string $directory, string|array|false $matchExtensions = false, bool $recursive = false): Collection { - $finder = app(FileFinder::class); - - return $finder::handle($directory, $matchExtensions, $recursive); + return app(FileFinder::class)->handle($directory, $matchExtensions, $recursive); } } diff --git a/packages/framework/src/Framework/Actions/Internal/FileFinder.php b/packages/framework/src/Framework/Actions/Internal/FileFinder.php index e596fac7170..014755b1c22 100644 --- a/packages/framework/src/Framework/Actions/Internal/FileFinder.php +++ b/packages/framework/src/Framework/Actions/Internal/FileFinder.php @@ -15,7 +15,7 @@ class FileFinder { /** - * @param string|array|false $matchExtensions + * @param string|array|false $matchExtensions * @return \Illuminate\Support\Collection */ public static function handle(string $directory, string|array|false $matchExtensions = false, bool $recursive = false): Collection @@ -36,8 +36,8 @@ public static function handle(string $directory, string|array|false $matchExtens } $finder->name('/\.('.implode('|', array_map(function (string $extension): string { - return preg_quote(ltrim($extension, '.'), '/'); - }, $matchExtensions)).')$/i'); + return preg_quote(ltrim($extension, '.'), '/'); + }, $matchExtensions)).')$/i'); } return collect($finder)->map(function (string $file): string { diff --git a/packages/framework/tests/Feature/Foundation/FilesystemTest.php b/packages/framework/tests/Feature/Foundation/FilesystemTest.php index d4b9a8aa968..25bf108239f 100644 --- a/packages/framework/tests/Feature/Foundation/FilesystemTest.php +++ b/packages/framework/tests/Feature/Foundation/FilesystemTest.php @@ -432,7 +432,8 @@ public function testFindFilesFromFilesystemFacadeWithArguments() public function testCanSwapOutFileFinder() { app()->bind(FileFinder::class, function () { - return new class { + return new class + { public static function handle(): Collection { return collect(['mocked']); From 1e1b8a366844a9954b5aae7cda4cae579f588a98 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 14 Dec 2024 19:49:26 +0100 Subject: [PATCH 46/80] Clean up and merge tests --- .../Pages/PageModelGetAllFilesHelperTest.php | 74 ----------- .../Pages/PageModelGetFileHelpersTest.php | 115 ++++++++++++++++++ .../Unit/Pages/PageModelGetHelperTest.php | 97 --------------- 3 files changed, 115 insertions(+), 171 deletions(-) delete mode 100644 packages/framework/tests/Unit/Pages/PageModelGetAllFilesHelperTest.php create mode 100644 packages/framework/tests/Unit/Pages/PageModelGetFileHelpersTest.php delete mode 100644 packages/framework/tests/Unit/Pages/PageModelGetHelperTest.php diff --git a/packages/framework/tests/Unit/Pages/PageModelGetAllFilesHelperTest.php b/packages/framework/tests/Unit/Pages/PageModelGetAllFilesHelperTest.php deleted file mode 100644 index 68257f0e847..00000000000 --- a/packages/framework/tests/Unit/Pages/PageModelGetAllFilesHelperTest.php +++ /dev/null @@ -1,74 +0,0 @@ -cleanupFilesystem(); - } - - public function testBladePageGetHelperReturnsBladePageArray() - { - $this->files(['_pages/test-page.blade.php']); - - HydeKernel::getInstance()->boot(); - - $array = BladePage::files(); - $this->assertCount(3, $array); - $this->assertIsArray($array); - $this->assertEquals(['404', 'index', 'test-page'], $array); - } - - public function testMarkdownPageGetHelperReturnsMarkdownPageArray() - { - $this->files(['_pages/test-page.md']); - - HydeKernel::getInstance()->boot(); - - $array = MarkdownPage::files(); - $this->assertCount(1, $array); - $this->assertIsArray($array); - $this->assertEquals(['test-page'], $array); - } - - public function testMarkdownPostGetHelperReturnsMarkdownPostArray() - { - $this->files(['_posts/test-post.md']); - - HydeKernel::getInstance()->boot(); - - $array = MarkdownPost::files(); - $this->assertCount(1, $array); - $this->assertIsArray($array); - $this->assertEquals(['test-post'], $array); - } - - public function testDocumentationPageGetHelperReturnsDocumentationPageArray() - { - $this->files(['_docs/test-page.md']); - - HydeKernel::getInstance()->boot(); - - $array = DocumentationPage::files(); - $this->assertCount(1, $array); - $this->assertIsArray($array); - $this->assertEquals(['test-page'], $array); - } -} diff --git a/packages/framework/tests/Unit/Pages/PageModelGetFileHelpersTest.php b/packages/framework/tests/Unit/Pages/PageModelGetFileHelpersTest.php new file mode 100644 index 00000000000..0586b3110d3 --- /dev/null +++ b/packages/framework/tests/Unit/Pages/PageModelGetFileHelpersTest.php @@ -0,0 +1,115 @@ +withFile('_pages/test-page.blade.php'); + + $array = BladePage::files(); + $this->assertCount(3, $array); + $this->assertIsArray($array); + $this->assertEquals(['404', 'index', 'test-page'], $array); + } + + public function testMarkdownPageFilesHelperReturnsMarkdownPageArray() + { + $this->withFile('_pages/test-page.md'); + + $array = MarkdownPage::files(); + $this->assertCount(1, $array); + $this->assertIsArray($array); + $this->assertEquals(['test-page'], $array); + } + + public function testMarkdownPostFilesHelperReturnsMarkdownPostArray() + { + $this->withFile('_posts/test-post.md'); + + $array = MarkdownPost::files(); + $this->assertCount(1, $array); + $this->assertIsArray($array); + $this->assertEquals(['test-post'], $array); + } + + public function testDocumentationPageFilesHelperReturnsDocumentationPageArray() + { + $this->withFile('_docs/test-page.md'); + + $array = DocumentationPage::files(); + $this->assertCount(1, $array); + $this->assertIsArray($array); + $this->assertEquals(['test-page'], $array); + } + + public function testBladePageAllHelperReturnsBladePageCollection() + { + $this->withFile('_pages/test-page.blade.php'); + + $collection = BladePage::all(); + + $this->assertCount(3, $collection); + $this->assertInstanceOf(Collection::class, $collection); + $this->assertContainsOnlyInstancesOf(BladePage::class, $collection); + } + + public function testMarkdownPageAllHelperReturnsMarkdownPageCollection() + { + $this->withFile('_pages/test-page.md'); + + $collection = MarkdownPage::all(); + $this->assertCount(1, $collection); + $this->assertInstanceOf(Collection::class, $collection); + $this->assertContainsOnlyInstancesOf(MarkdownPage::class, $collection); + } + + public function testMarkdownPostAllHelperReturnsMarkdownPostCollection() + { + $this->withFile('_posts/test-post.md'); + + $collection = MarkdownPost::all(); + $this->assertCount(1, $collection); + $this->assertInstanceOf(Collection::class, $collection); + $this->assertContainsOnlyInstancesOf(MarkdownPost::class, $collection); + } + + public function testDocumentationPageAllHelperReturnsDocumentationPageCollection() + { + $this->withFile('_docs/test-page.md'); + + $collection = DocumentationPage::all(); + $this->assertCount(1, $collection); + $this->assertInstanceOf(Collection::class, $collection); + $this->assertContainsOnlyInstancesOf(DocumentationPage::class, $collection); + } + + protected function withFile(string $path): void + { + $this->file($path); + + HydeKernel::getInstance()->boot(); + } + + protected function tearDown(): void + { + $this->cleanupFilesystem(); + } +} diff --git a/packages/framework/tests/Unit/Pages/PageModelGetHelperTest.php b/packages/framework/tests/Unit/Pages/PageModelGetHelperTest.php deleted file mode 100644 index cf6232c2d1e..00000000000 --- a/packages/framework/tests/Unit/Pages/PageModelGetHelperTest.php +++ /dev/null @@ -1,97 +0,0 @@ -filesystem = $this->mockFilesystemStrict() - ->shouldReceive('glob')->once()->with(Hyde::path('_pages/{*,**/*}.html'), GLOB_BRACE)->andReturn([])->byDefault() - ->shouldReceive('glob')->once()->with(Hyde::path('_pages/{*,**/*}.blade.php'), GLOB_BRACE)->andReturn([])->byDefault() - ->shouldReceive('glob')->once()->with(Hyde::path('_pages/{*,**/*}.md'), GLOB_BRACE)->andReturn([])->byDefault() - ->shouldReceive('glob')->once()->with(Hyde::path('_posts/{*,**/*}.md'), GLOB_BRACE)->andReturn([])->byDefault() - ->shouldReceive('glob')->once()->with(Hyde::path('_docs/{*,**/*}.md'), GLOB_BRACE)->andReturn([])->byDefault(); - } - - protected function tearDown(): void - { - $this->verifyMockeryExpectations(); - } - - public function testBladePageGetHelperReturnsBladePageCollection() - { - $this->shouldReceiveGlob('_pages/{*,**/*}.blade.php')->andReturn(['_pages/test-page.blade.php']); - $this->shouldFindFile('_pages/test-page.blade.php'); - - $collection = BladePage::all(); - $this->assertCount(1, $collection); - $this->assertInstanceOf(Collection::class, $collection); - $this->assertContainsOnlyInstancesOf(BladePage::class, $collection); - } - - public function testMarkdownPageGetHelperReturnsMarkdownPageCollection() - { - $this->shouldReceiveGlob('_pages/{*,**/*}.md')->andReturn(['_pages/test-page.md']); - $this->shouldFindFile('_pages/test-page.md'); - - $collection = MarkdownPage::all(); - $this->assertCount(1, $collection); - $this->assertInstanceOf(Collection::class, $collection); - $this->assertContainsOnlyInstancesOf(MarkdownPage::class, $collection); - } - - public function testMarkdownPostGetHelperReturnsMarkdownPostCollection() - { - $this->shouldReceiveGlob('_posts/{*,**/*}.md')->andReturn(['_posts/test-post.md']); - $this->shouldFindFile('_posts/test-post.md'); - - $collection = MarkdownPost::all(); - $this->assertCount(1, $collection); - $this->assertInstanceOf(Collection::class, $collection); - $this->assertContainsOnlyInstancesOf(MarkdownPost::class, $collection); - } - - public function testDocumentationPageGetHelperReturnsDocumentationPageCollection() - { - $this->shouldReceiveGlob('_docs/{*,**/*}.md')->andReturn(['_docs/test-page.md']); - $this->shouldFindFile('_docs/test-page.md'); - - $collection = DocumentationPage::all(); - $this->assertCount(1, $collection); - $this->assertInstanceOf(Collection::class, $collection); - $this->assertContainsOnlyInstancesOf(DocumentationPage::class, $collection); - } - - protected function shouldReceiveGlob(string $withPath): ExpectationInterface - { - return $this->filesystem->shouldReceive('glob')->once()->with(Hyde::path($withPath), GLOB_BRACE); - } - - protected function shouldFindFile(string $file): void - { - $this->filesystem->shouldReceive('missing')->once()->with(Hyde::path($file))->andReturnFalse(); - $this->filesystem->shouldReceive('get')->once()->with(Hyde::path($file))->andReturn('content'); - } -} From 3dc33838dddc2d5ac67735ea26dfa833ef87b678 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 11:51:54 +0100 Subject: [PATCH 47/80] Use better file finder instead of glob brace --- .../src/Framework/Actions/PreBuildTasks/CleanSiteDirectory.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/framework/src/Framework/Actions/PreBuildTasks/CleanSiteDirectory.php b/packages/framework/src/Framework/Actions/PreBuildTasks/CleanSiteDirectory.php index 849f077b7cb..a0edd4d800d 100644 --- a/packages/framework/src/Framework/Actions/PreBuildTasks/CleanSiteDirectory.php +++ b/packages/framework/src/Framework/Actions/PreBuildTasks/CleanSiteDirectory.php @@ -10,7 +10,6 @@ use Hyde\Framework\Features\BuildTasks\PreBuildTask; use function basename; -use function glob; use function in_array; use function sprintf; @@ -21,7 +20,7 @@ class CleanSiteDirectory extends PreBuildTask public function handle(): void { if ($this->isItSafeToCleanOutputDirectory()) { - Filesystem::unlink(glob(Hyde::sitePath('*.{html,json}'), GLOB_BRACE)); + Filesystem::unlink(Filesystem::findFiles(Hyde::sitePath(), ['html', 'json'])->all()); Filesystem::cleanDirectory(Hyde::siteMediaPath()); } } From 472d29f8ec14f4cdfb3c8098d152b734b57edc66 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 12:00:06 +0100 Subject: [PATCH 48/80] Annotate the parameter type --- packages/framework/src/Foundation/Kernel/Filesystem.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index b480e204f64..1efc0633101 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -185,7 +185,10 @@ public function smartGlob(string $pattern, int $flags = 0): Collection return $files->map(fn (string $path): string => $this->pathToRelative($path)); } - /** @return \Illuminate\Support\Collection */ + /** + * @param string|array|false $matchExtensions + * @return \Illuminate\Support\Collection + */ public function findFiles(string $directory, string|array|false $matchExtensions = false, bool $recursive = false): Collection { return app(FileFinder::class)->handle($directory, $matchExtensions, $recursive); From 665340f49cd946c5ae2cbae8b2e5f4a80a72de56 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 12:03:16 +0100 Subject: [PATCH 49/80] Use explicit type conversion --- .../framework/src/Framework/Actions/Internal/FileFinder.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/framework/src/Framework/Actions/Internal/FileFinder.php b/packages/framework/src/Framework/Actions/Internal/FileFinder.php index 014755b1c22..7ca447bde72 100644 --- a/packages/framework/src/Framework/Actions/Internal/FileFinder.php +++ b/packages/framework/src/Framework/Actions/Internal/FileFinder.php @@ -7,6 +7,7 @@ use Hyde\Facades\Filesystem; use Hyde\Hyde; use Illuminate\Support\Collection; +use SplFileInfo; use Symfony\Component\Finder\Finder; /** @@ -40,8 +41,8 @@ public static function handle(string $directory, string|array|false $matchExtens }, $matchExtensions)).')$/i'); } - return collect($finder)->map(function (string $file): string { - return Hyde::pathToRelative($file); + return collect($finder)->map(function (SplFileInfo $file): string { + return Hyde::pathToRelative($file->getPathname()); })->sort()->values(); } } From 104eb76405d81aeccd96eaa5517943610bf12221 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 12:10:56 +0100 Subject: [PATCH 50/80] Explicitly annotate type as Psalm is not reading stub well --- packages/framework/src/Foundation/Kernel/Filesystem.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Foundation/Kernel/Filesystem.php b/packages/framework/src/Foundation/Kernel/Filesystem.php index 1efc0633101..c4532c40a22 100644 --- a/packages/framework/src/Foundation/Kernel/Filesystem.php +++ b/packages/framework/src/Foundation/Kernel/Filesystem.php @@ -191,6 +191,9 @@ public function smartGlob(string $pattern, int $flags = 0): Collection */ public function findFiles(string $directory, string|array|false $matchExtensions = false, bool $recursive = false): Collection { - return app(FileFinder::class)->handle($directory, $matchExtensions, $recursive); + /** @var \Hyde\Framework\Actions\Internal\FileFinder $finder */ + $finder = app(FileFinder::class); + + return $finder->handle($directory, $matchExtensions, $recursive); } } From cf70b97a04e4e9e86caf90d6b12e60838fa610a2 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 12:17:09 +0100 Subject: [PATCH 51/80] Annotate full finder types --- .../framework/src/Framework/Actions/Internal/FileFinder.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/framework/src/Framework/Actions/Internal/FileFinder.php b/packages/framework/src/Framework/Actions/Internal/FileFinder.php index 7ca447bde72..f8fd8fb3dbc 100644 --- a/packages/framework/src/Framework/Actions/Internal/FileFinder.php +++ b/packages/framework/src/Framework/Actions/Internal/FileFinder.php @@ -25,6 +25,8 @@ public static function handle(string $directory, string|array|false $matchExtens return collect(); } + /** @var \Symfony\Component\Finder\Finder&\Traversable $finder + */ $finder = Finder::create()->files()->in(Hyde::path($directory)); if ($recursive === false) { From bb4f839c2034fccf8bd260646baf3e2575a1e581 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 12:21:28 +0100 Subject: [PATCH 52/80] Revert "Annotate full finder types" This reverts commit 50b6ac1136f66d3e3b3f07c21817b5b05b7a7a54. --- .../framework/src/Framework/Actions/Internal/FileFinder.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/framework/src/Framework/Actions/Internal/FileFinder.php b/packages/framework/src/Framework/Actions/Internal/FileFinder.php index f8fd8fb3dbc..7ca447bde72 100644 --- a/packages/framework/src/Framework/Actions/Internal/FileFinder.php +++ b/packages/framework/src/Framework/Actions/Internal/FileFinder.php @@ -25,8 +25,6 @@ public static function handle(string $directory, string|array|false $matchExtens return collect(); } - /** @var \Symfony\Component\Finder\Finder&\Traversable $finder - */ $finder = Finder::create()->files()->in(Hyde::path($directory)); if ($recursive === false) { From 1cd16f34b25d3e3eac24c6b5868f0a5f122e7d0e Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 15:17:02 +0100 Subject: [PATCH 53/80] Extract helper method --- .../Framework/Actions/Internal/FileFinder.php | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/framework/src/Framework/Actions/Internal/FileFinder.php b/packages/framework/src/Framework/Actions/Internal/FileFinder.php index 7ca447bde72..bf5fff23a03 100644 --- a/packages/framework/src/Framework/Actions/Internal/FileFinder.php +++ b/packages/framework/src/Framework/Actions/Internal/FileFinder.php @@ -32,17 +32,23 @@ public static function handle(string $directory, string|array|false $matchExtens } if ($matchExtensions !== false) { - if (is_string($matchExtensions)) { - $matchExtensions = array_map('trim', explode(',', $matchExtensions)); - } - - $finder->name('/\.('.implode('|', array_map(function (string $extension): string { - return preg_quote(ltrim($extension, '.'), '/'); - }, $matchExtensions)).')$/i'); + $finder->name(static::buildFileExtensionPattern($matchExtensions)); } return collect($finder)->map(function (SplFileInfo $file): string { return Hyde::pathToRelative($file->getPathname()); })->sort()->values(); } + + /** @param string|array $extensions */ + protected static function buildFileExtensionPattern(string|array $extensions): string + { + if (is_string($extensions)) { + $extensions = array_map('trim', explode(',', $extensions)); + } + + return '/\.(' . implode('|', array_map(function (string $extension): string { + return preg_quote(ltrim($extension, '.'), '/'); + }, $extensions)) . ')$/i'; + } } From ada1f4b371c6d495867e201743a4de94956b96b9 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 15:20:44 +0100 Subject: [PATCH 54/80] Expand mixed comma separated strings and array input --- .../src/Framework/Actions/Internal/FileFinder.php | 7 +++++++ packages/framework/tests/Unit/FileFinderTest.php | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/packages/framework/src/Framework/Actions/Internal/FileFinder.php b/packages/framework/src/Framework/Actions/Internal/FileFinder.php index bf5fff23a03..bf7a928472d 100644 --- a/packages/framework/src/Framework/Actions/Internal/FileFinder.php +++ b/packages/framework/src/Framework/Actions/Internal/FileFinder.php @@ -44,9 +44,16 @@ public static function handle(string $directory, string|array|false $matchExtens protected static function buildFileExtensionPattern(string|array $extensions): string { if (is_string($extensions)) { + // Convert single CSV string into an array $extensions = array_map('trim', explode(',', $extensions)); + } else { + // Normalize array by splitting any CSV strings within + $extensions = array_merge(...array_map(function ($item) { + return array_map('trim', explode(',', $item)); + }, $extensions)); } + // Remove leading dots, escape extensions, and build the regex pattern return '/\.(' . implode('|', array_map(function (string $extension): string { return preg_quote(ltrim($extension, '.'), '/'); }, $extensions)) . ')$/i'; diff --git a/packages/framework/tests/Unit/FileFinderTest.php b/packages/framework/tests/Unit/FileFinderTest.php index 852daddfa5d..fadf155decc 100644 --- a/packages/framework/tests/Unit/FileFinderTest.php +++ b/packages/framework/tests/Unit/FileFinderTest.php @@ -249,6 +249,18 @@ public function testFindFilesWithCsvStringExtensionsMixedCase() $this->assertSameArray(['file1.MD', 'file2.TXT'], 'directory', 'md,TXT'); } + public function testFindFilesWithCsvStringExtensionsInArray() + { + $this->files(['directory/file1.md', 'directory/file2.txt', 'directory/file3.jpg']); + $this->assertSameArray(['file1.md', 'file2.txt'], 'directory', ['md,txt']); + } + + public function testFindFilesWithCsvStringExtensionsInMixedArray() + { + $this->files(['directory/file1.md', 'directory/file2.txt', 'directory/file3.jpg']); + $this->assertSameArray(['file1.md', 'file2.txt', 'file3.jpg'], 'directory', ['md,txt', 'jpg']); + } + protected function assertSameArray(array $expected, string $directory, string|array|false $matchExtensions = false, bool $recursive = false): void { $files = (new Filesystem(Hyde::getInstance()))->findFiles($directory, $matchExtensions, $recursive); From be16f73db2a530edd23f0650237184d0fc6d2ee8 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 15:21:32 +0100 Subject: [PATCH 55/80] Merge code by casting to array --- .../src/Framework/Actions/Internal/FileFinder.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/framework/src/Framework/Actions/Internal/FileFinder.php b/packages/framework/src/Framework/Actions/Internal/FileFinder.php index bf7a928472d..55589aa6b97 100644 --- a/packages/framework/src/Framework/Actions/Internal/FileFinder.php +++ b/packages/framework/src/Framework/Actions/Internal/FileFinder.php @@ -43,15 +43,12 @@ public static function handle(string $directory, string|array|false $matchExtens /** @param string|array $extensions */ protected static function buildFileExtensionPattern(string|array $extensions): string { - if (is_string($extensions)) { - // Convert single CSV string into an array - $extensions = array_map('trim', explode(',', $extensions)); - } else { - // Normalize array by splitting any CSV strings within - $extensions = array_merge(...array_map(function ($item) { - return array_map('trim', explode(',', $item)); - }, $extensions)); - } + $extensions = (array) $extensions; + + // Normalize array by splitting any CSV strings within + $extensions = array_merge(...array_map(function ($item) { + return array_map('trim', explode(',', $item)); + }, $extensions)); // Remove leading dots, escape extensions, and build the regex pattern return '/\.(' . implode('|', array_map(function (string $extension): string { From f0b85d962157702c70a7eb3731e97af993efb995 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 15:21:57 +0100 Subject: [PATCH 56/80] Add earlier array cast --- .../src/Framework/Actions/Internal/FileFinder.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/framework/src/Framework/Actions/Internal/FileFinder.php b/packages/framework/src/Framework/Actions/Internal/FileFinder.php index 55589aa6b97..9f4c80beee6 100644 --- a/packages/framework/src/Framework/Actions/Internal/FileFinder.php +++ b/packages/framework/src/Framework/Actions/Internal/FileFinder.php @@ -32,7 +32,7 @@ public static function handle(string $directory, string|array|false $matchExtens } if ($matchExtensions !== false) { - $finder->name(static::buildFileExtensionPattern($matchExtensions)); + $finder->name(static::buildFileExtensionPattern((array) $matchExtensions)); } return collect($finder)->map(function (SplFileInfo $file): string { @@ -40,11 +40,9 @@ public static function handle(string $directory, string|array|false $matchExtens })->sort()->values(); } - /** @param string|array $extensions */ - protected static function buildFileExtensionPattern(string|array $extensions): string + /** @param array $extensions */ + protected static function buildFileExtensionPattern(array $extensions): string { - $extensions = (array) $extensions; - // Normalize array by splitting any CSV strings within $extensions = array_merge(...array_map(function ($item) { return array_map('trim', explode(',', $item)); From 396b83df53d3a317500535087f8036b854474b1d Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 15:23:12 +0100 Subject: [PATCH 57/80] Type the closure values --- .../framework/src/Framework/Actions/Internal/FileFinder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/Framework/Actions/Internal/FileFinder.php b/packages/framework/src/Framework/Actions/Internal/FileFinder.php index 9f4c80beee6..bedc161a07f 100644 --- a/packages/framework/src/Framework/Actions/Internal/FileFinder.php +++ b/packages/framework/src/Framework/Actions/Internal/FileFinder.php @@ -44,7 +44,7 @@ public static function handle(string $directory, string|array|false $matchExtens protected static function buildFileExtensionPattern(array $extensions): string { // Normalize array by splitting any CSV strings within - $extensions = array_merge(...array_map(function ($item) { + $extensions = array_merge(...array_map(function (string $item): array { return array_map('trim', explode(',', $item)); }, $extensions)); From 3ae5df01c269b7fb6caf91c0b544f2c1307282f9 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 15:24:41 +0100 Subject: [PATCH 58/80] Expand array map shorthand due to Psalm not understanding it --- .../framework/src/Framework/Actions/Internal/FileFinder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/Framework/Actions/Internal/FileFinder.php b/packages/framework/src/Framework/Actions/Internal/FileFinder.php index bedc161a07f..a2d4f6dc62e 100644 --- a/packages/framework/src/Framework/Actions/Internal/FileFinder.php +++ b/packages/framework/src/Framework/Actions/Internal/FileFinder.php @@ -45,7 +45,7 @@ protected static function buildFileExtensionPattern(array $extensions): string { // Normalize array by splitting any CSV strings within $extensions = array_merge(...array_map(function (string $item): array { - return array_map('trim', explode(',', $item)); + return array_map(fn (string $item): string => trim($item), explode(',', $item)); }, $extensions)); // Remove leading dots, escape extensions, and build the regex pattern From 2aeabf74bb138dcc57acc68a48808fff4b3290f3 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 15:26:30 +0100 Subject: [PATCH 59/80] Refactor and cleanup --- .../Framework/Actions/Internal/FileFinder.php | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/framework/src/Framework/Actions/Internal/FileFinder.php b/packages/framework/src/Framework/Actions/Internal/FileFinder.php index a2d4f6dc62e..7ba9c556812 100644 --- a/packages/framework/src/Framework/Actions/Internal/FileFinder.php +++ b/packages/framework/src/Framework/Actions/Internal/FileFinder.php @@ -16,10 +16,10 @@ class FileFinder { /** - * @param string|array|false $matchExtensions + * @param array|string|false $matchExtensions * @return \Illuminate\Support\Collection */ - public static function handle(string $directory, string|array|false $matchExtensions = false, bool $recursive = false): Collection + public static function handle(string $directory, array|string|false $matchExtensions = false, bool $recursive = false): Collection { if (! Filesystem::isDirectory($directory)) { return collect(); @@ -43,14 +43,24 @@ public static function handle(string $directory, string|array|false $matchExtens /** @param array $extensions */ protected static function buildFileExtensionPattern(array $extensions): string { - // Normalize array by splitting any CSV strings within - $extensions = array_merge(...array_map(function (string $item): array { + $extensions = self::expandCommaSeparatedValues($extensions); + + return '/\.('.self::normalizeExtensionForRegexPattern($extensions).')$/i'; + } + + /** @param array $extensions */ + private static function expandCommaSeparatedValues(array $extensions): array + { + return array_merge(...array_map(function (string $item): array { return array_map(fn (string $item): string => trim($item), explode(',', $item)); }, $extensions)); + } - // Remove leading dots, escape extensions, and build the regex pattern - return '/\.(' . implode('|', array_map(function (string $extension): string { - return preg_quote(ltrim($extension, '.'), '/'); - }, $extensions)) . ')$/i'; + /** @param array $extensions */ + private static function normalizeExtensionForRegexPattern(array $extensions): string + { + return implode('|', array_map(function (string $extension): string { + return preg_quote(ltrim($extension, '.'), '/'); + }, $extensions)); } } From 96ba073d400dd275b123a1a07253503b42d6cb5f Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 15:29:00 +0100 Subject: [PATCH 60/80] Annotate return types --- packages/framework/src/Support/Filesystem/MediaFile.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 1237a95baad..1bf39274c6f 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -102,11 +102,13 @@ protected static function discoverMediaAssetFiles(): array })->all(); } + /** @return array */ protected static function getMediaAssetFiles(): array { return Filesystem::findFiles(Hyde::getMediaDirectory(), static::getMediaFileExtensions(), true)->all(); } + /** @return array|string */ protected static function getMediaFileExtensions(): array|string { return Config::get('hyde.media_extensions', self::EXTENSIONS); From 3ef777e5a9b6c259ce50dbf8dde951c9d899ec2b Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 15:32:49 +0100 Subject: [PATCH 61/80] Annotate type for Psalm --- packages/framework/src/Support/Filesystem/MediaFile.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 1bf39274c6f..09ab5247ad6 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -111,6 +111,9 @@ protected static function getMediaAssetFiles(): array /** @return array|string */ protected static function getMediaFileExtensions(): array|string { - return Config::get('hyde.media_extensions', self::EXTENSIONS); + /** @var array|string $config */ + $config = Config::get('hyde.media_extensions', self::EXTENSIONS); + + return $config; } } From 7a86073066cbff2271c4d4aa1b9c233ccfb21e23 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 16:12:19 +0100 Subject: [PATCH 62/80] Clarify internal policy --- .../framework/src/Framework/Actions/Internal/FileFinder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/Framework/Actions/Internal/FileFinder.php b/packages/framework/src/Framework/Actions/Internal/FileFinder.php index 7ba9c556812..7647b23a2fd 100644 --- a/packages/framework/src/Framework/Actions/Internal/FileFinder.php +++ b/packages/framework/src/Framework/Actions/Internal/FileFinder.php @@ -11,7 +11,7 @@ use Symfony\Component\Finder\Finder; /** - * @interal This class is used internally by the framework and is not part of the public API unless requested on GitHub. + * @interal This class is used internally by the framework and is not part of the public API, unless that is requested on GitHub with a valid use case. */ class FileFinder { From b41253ee6997f5de9994f685e249fb48b6482a00 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 15 Dec 2024 16:15:17 +0100 Subject: [PATCH 63/80] Update RELEASE_NOTES.md --- RELEASE_NOTES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 3004d5e7b2c..e2f970a3d27 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -14,6 +14,7 @@ This serves two purposes: - Registered the `cache:clear` command to make it easier to clear the cache in https://github.com/hydephp/develop/pull/1881 - Added a new `Hyperlinks::isRemote()` helper method to check if a URL is remote in https://github.com/hydephp/develop/pull/1882 - All page types now support the `description` front matter field (used in page metadata) in https://github.com/hydephp/develop/pull/1884 +- Added a new `Filesystem::findFiles()` method to find files in a directory in https://github.com/hydephp/develop/pull/2064 ### Changed - Changed the `Hyde` facade to use a `@mixin` annotation instead of single method annotations in https://github.com/hydephp/develop/pull/1919 @@ -24,6 +25,7 @@ This serves two purposes: - The `torchlight:install` command is now hidden from the command list as it's already installed in https://github.com/hydephp/develop/pull/1879 - Updated the home page fallback link in the 404 template to lead to the site root in https://github.com/hydephp/develop/pull/1880 (fixes https://github.com/hydephp/develop/issues/1781) - Normalized remote URL checks so that protocol relative URLs `//` are consistently considered to be remote in all places in https://github.com/hydephp/develop/pull/1882 (fixes https://github.com/hydephp/develop/issues/1788) +- Replaced internal usages of glob functions with our improved file finder in https://github.com/hydephp/develop/pull/2064 - Updated to HydeFront v3.4 in https://github.com/hydephp/develop/pull/1803 - Realtime Compiler: Virtual routes are now managed through the service container in https://github.com/hydephp/develop/pull/1858 - Realtime Compiler: Improved the dashboard layout in https://github.com/hydephp/develop/pull/1866 @@ -44,6 +46,8 @@ This serves two purposes: - Fixed routing issues with nested 404 pages where an index page does not exist https://github.com/hydephp/develop/issues/1781 in https://github.com/hydephp/develop/pull/1880 - Fixed URL metadata for blog posts not using customized post output directories in https://github.com/hydephp/develop/pull/1889 - Improved printed documentation views in https://github.com/hydephp/develop/pull/2005 +- Fixed "BuildService finding non-existent files to copy in Debian" https://github.com/hydephp/framework/issues/662 in https://github.com/hydephp/develop/pull/2064 +- Fixed "Undefined constant `Hyde\Foundation\Kernel\GLOB_BRACE`" https://github.com/hydephp/hyde/issues/270 in https://github.com/hydephp/develop/pull/2064 - Realtime Compiler: Updated the exception handler to match HTTP exception codes when sending error responses in https://github.com/hydephp/develop/pull/1853 - Realtime Compiler: Improved routing for nested index pages in https://github.com/hydephp/develop/pull/1852 - Realtime Compiler: Improved the dashboard https://github.com/hydephp/develop/pull/1866 fixing https://github.com/hydephp/realtime-compiler/issues/22 and https://github.com/hydephp/realtime-compiler/issues/29 From 93c16704558c996b8215441692ad2ea953274eff Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 21 Dec 2024 13:41:43 +0100 Subject: [PATCH 64/80] Retain commit authors for split monorepo --- .github/workflows/split-monorepo.yml | 42 ++++++++++++++++++---------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/.github/workflows/split-monorepo.yml b/.github/workflows/split-monorepo.yml index 90dac65a081..6ae727cc3a3 100644 --- a/.github/workflows/split-monorepo.yml +++ b/.github/workflows/split-monorepo.yml @@ -65,6 +65,8 @@ jobs: - name: Commit and push changes env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} + COMMIT_AUTHOR_NAME: ${{ github.event.head_commit.author.name }} + COMMIT_AUTHOR_EMAIL: ${{ github.event.head_commit.author.email }} run: | cd hyde if ! [[ `git status --porcelain` ]]; then @@ -72,8 +74,8 @@ jobs: exit 0; fi - git config user.name github-actions - git config user.email github-actions@github.com + git config user.name "$COMMIT_AUTHOR_NAME" + git config user.email "$COMMIT_AUTHOR_EMAIL" git remote add upstream https://oauth2:${{ secrets.SPLIT_MONOREPO_TOKEN }}@github.com/hydephp/hyde.git git add . @@ -114,6 +116,8 @@ jobs: - name: Commit and push changes env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} + COMMIT_AUTHOR_NAME: ${{ github.event.head_commit.author.name }} + COMMIT_AUTHOR_EMAIL: ${{ github.event.head_commit.author.email }} run: | cd framework if ! [[ `git status --porcelain` ]]; then @@ -121,8 +125,8 @@ jobs: exit 0; fi - git config user.name github-actions - git config user.email github-actions@github.com + git config user.name "$COMMIT_AUTHOR_NAME" + git config user.email "$COMMIT_AUTHOR_EMAIL" git remote add upstream https://oauth2:${{ secrets.SPLIT_MONOREPO_TOKEN }}@github.com/hydephp/framework.git git add . @@ -163,6 +167,8 @@ jobs: - name: Commit and push changes env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} + COMMIT_AUTHOR_NAME: ${{ github.event.head_commit.author.name }} + COMMIT_AUTHOR_EMAIL: ${{ github.event.head_commit.author.email }} run: | cd realtime-compiler if ! [[ `git status --porcelain` ]]; then @@ -170,8 +176,8 @@ jobs: exit 0; fi - git config user.name github-actions - git config user.email github-actions@github.com + git config user.name "$COMMIT_AUTHOR_NAME" + git config user.email "$COMMIT_AUTHOR_EMAIL" git remote add upstream https://oauth2:${{ secrets.SPLIT_MONOREPO_TOKEN }}@github.com/hydephp/realtime-compiler.git git add . @@ -211,6 +217,8 @@ jobs: - name: Commit and push changes env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} + COMMIT_AUTHOR_NAME: ${{ github.event.head_commit.author.name }} + COMMIT_AUTHOR_EMAIL: ${{ github.event.head_commit.author.email }} run: | cd hydefront if ! [[ `git status --porcelain` ]]; then @@ -218,8 +226,8 @@ jobs: exit 0; fi - git config user.name github-actions - git config user.email github-actions@github.com + git config user.name "$COMMIT_AUTHOR_NAME" + git config user.email "$COMMIT_AUTHOR_EMAIL" git remote add upstream https://oauth2:${{ secrets.SPLIT_MONOREPO_TOKEN }}@github.com/hydephp/hydefront.git git add . @@ -263,6 +271,8 @@ jobs: - name: Commit and push changes env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} + COMMIT_AUTHOR_NAME: ${{ github.event.head_commit.author.name }} + COMMIT_AUTHOR_EMAIL: ${{ github.event.head_commit.author.email }} run: | cd website if ! [[ `git status --porcelain` ]]; then @@ -270,8 +280,8 @@ jobs: exit 0; fi - git config user.name github-actions - git config user.email github-actions@github.com + git config user.name "$COMMIT_AUTHOR_NAME" + git config user.email "$COMMIT_AUTHOR_EMAIL" git remote add upstream https://oauth2:${{ secrets.SPLIT_MONOREPO_TOKEN }}@github.com/hydephp/hydephp.com.git git add . @@ -312,6 +322,8 @@ jobs: - name: Commit and push changes env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} + COMMIT_AUTHOR_NAME: ${{ github.event.head_commit.author.name }} + COMMIT_AUTHOR_EMAIL: ${{ github.event.head_commit.author.email }} run: | cd testing if ! [[ `git status --porcelain` ]]; then @@ -319,8 +331,8 @@ jobs: exit 0; fi - git config user.name github-actions - git config user.email github-actions@github.com + git config user.name "$COMMIT_AUTHOR_NAME" + git config user.email "$COMMIT_AUTHOR_EMAIL" git remote add upstream https://oauth2:${{ secrets.SPLIT_MONOREPO_TOKEN }}@github.com/hydephp/testing.git git add . @@ -360,6 +372,8 @@ jobs: - name: Commit and push changes env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} + COMMIT_AUTHOR_NAME: ${{ github.event.head_commit.author.name }} + COMMIT_AUTHOR_EMAIL: ${{ github.event.head_commit.author.email }} run: | cd ui-kit @@ -368,8 +382,8 @@ jobs: exit 0; fi - git config user.name github-actions - git config user.email github-actions@github.com + git config user.name "$COMMIT_AUTHOR_NAME" + git config user.email "$COMMIT_AUTHOR_EMAIL" git remote add upstream https://oauth2:${{ secrets.SPLIT_MONOREPO_TOKEN }}@github.com/hydephp/ui-kit.git git add . From ddc98b6ae2f22b608d010d17aef38d4a43e8eb53 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 21 Dec 2024 13:50:10 +0100 Subject: [PATCH 65/80] Experimental: Retain original author but commit as Actions user --- .github/workflows/split-monorepo.yml | 42 ++++++++++++++-------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/split-monorepo.yml b/.github/workflows/split-monorepo.yml index 6ae727cc3a3..bf45381112b 100644 --- a/.github/workflows/split-monorepo.yml +++ b/.github/workflows/split-monorepo.yml @@ -74,12 +74,12 @@ jobs: exit 0; fi - git config user.name "$COMMIT_AUTHOR_NAME" - git config user.email "$COMMIT_AUTHOR_EMAIL" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git remote add upstream https://oauth2:${{ secrets.SPLIT_MONOREPO_TOKEN }}@github.com/hydephp/hyde.git git add . - git commit -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}" + git commit --author="$COMMIT_AUTHOR_NAME <$COMMIT_AUTHOR_EMAIL>" -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}" git push upstream develop echo "No changes to this package. Exiting gracefully." @@ -125,12 +125,12 @@ jobs: exit 0; fi - git config user.name "$COMMIT_AUTHOR_NAME" - git config user.email "$COMMIT_AUTHOR_EMAIL" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git remote add upstream https://oauth2:${{ secrets.SPLIT_MONOREPO_TOKEN }}@github.com/hydephp/framework.git git add . - git commit -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}" + git commit --author="$COMMIT_AUTHOR_NAME <$COMMIT_AUTHOR_EMAIL>" -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}" git push upstream develop echo "No changes to this package. Exiting gracefully." @@ -176,12 +176,12 @@ jobs: exit 0; fi - git config user.name "$COMMIT_AUTHOR_NAME" - git config user.email "$COMMIT_AUTHOR_EMAIL" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git remote add upstream https://oauth2:${{ secrets.SPLIT_MONOREPO_TOKEN }}@github.com/hydephp/realtime-compiler.git git add . - git commit -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}" + git commit --author="$COMMIT_AUTHOR_NAME <$COMMIT_AUTHOR_EMAIL>" -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}" git push upstream master @@ -226,12 +226,12 @@ jobs: exit 0; fi - git config user.name "$COMMIT_AUTHOR_NAME" - git config user.email "$COMMIT_AUTHOR_EMAIL" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git remote add upstream https://oauth2:${{ secrets.SPLIT_MONOREPO_TOKEN }}@github.com/hydephp/hydefront.git git add . - git commit -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}" + git commit --author="$COMMIT_AUTHOR_NAME <$COMMIT_AUTHOR_EMAIL>" -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}" git push upstream master @@ -280,12 +280,12 @@ jobs: exit 0; fi - git config user.name "$COMMIT_AUTHOR_NAME" - git config user.email "$COMMIT_AUTHOR_EMAIL" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git remote add upstream https://oauth2:${{ secrets.SPLIT_MONOREPO_TOKEN }}@github.com/hydephp/hydephp.com.git git add . - git commit -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}" + git commit --author="$COMMIT_AUTHOR_NAME <$COMMIT_AUTHOR_EMAIL>" -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}" git push upstream upcoming echo "No changes to this package. Exiting gracefully." @@ -331,12 +331,12 @@ jobs: exit 0; fi - git config user.name "$COMMIT_AUTHOR_NAME" - git config user.email "$COMMIT_AUTHOR_EMAIL" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git remote add upstream https://oauth2:${{ secrets.SPLIT_MONOREPO_TOKEN }}@github.com/hydephp/testing.git git add . - git commit -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}" + git commit --author="$COMMIT_AUTHOR_NAME <$COMMIT_AUTHOR_EMAIL>" -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}" git push upstream master @@ -382,11 +382,11 @@ jobs: exit 0; fi - git config user.name "$COMMIT_AUTHOR_NAME" - git config user.email "$COMMIT_AUTHOR_EMAIL" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git remote add upstream https://oauth2:${{ secrets.SPLIT_MONOREPO_TOKEN }}@github.com/hydephp/ui-kit.git git add . - git commit -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}" + git commit --author="$COMMIT_AUTHOR_NAME <$COMMIT_AUTHOR_EMAIL>" -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}" git push upstream master From 87beda64c8515e8440aea887f2895a4d2f64f6a3 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 21 Dec 2024 14:01:00 +0100 Subject: [PATCH 66/80] Sync back with subpackage --- .../framework/.github/workflows/run-tests.yml | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/packages/framework/.github/workflows/run-tests.yml b/packages/framework/.github/workflows/run-tests.yml index 76b1488c7fe..c78208af9be 100644 --- a/packages/framework/.github/workflows/run-tests.yml +++ b/packages/framework/.github/workflows/run-tests.yml @@ -26,46 +26,41 @@ jobs: - name: Install Hyde shell: bash - run: | - if [ "${{ github.ref }}" == "refs/heads/master" ]; then - git clone -b master https://github.com/hydephp/hyde.git - else - git clone -b develop https://github.com/hydephp/hyde.git - fi + run: git clone -b master https://github.com/hydephp/develop.git --depth 1 runner - - name: Copy over framework source code + - name: Copy over framework code shell: bash run: | - mkdir -p ./hyde/packages/hyde/framework/src + rm -rf ./runner/packages/framework/src + rm -rf ./runner/packages/framework/tests + mkdir -p ./runner/packages/framework/src + mkdir -p ./runner/packages/framework/tests - # Since we can't use rsync on Windows, we need to copy the files to a temporary directory and then copy them back if [ "${{ matrix.os }}" == "windows-latest" ]; then + # For Windows, copy to temp then back to preserve structure mkdir ../temp cp -r ./ ../temp - rm -rf ../temp/hyde - cp -r ../temp/. ./hyde/packages/hyde/framework/src + rm -rf ../temp/runner + cp -r ../temp/src/. ./runner/packages/framework/src + cp -r ../temp/tests/. ./runner/packages/framework/tests else - rsync -a --exclude=hyde ./. ./hyde/packages/hyde/framework/src + # For Unix systems, use rsync + rsync -a --exclude=runner ./src/. ./runner/packages/framework/src + rsync -a --exclude=runner ./tests/. ./runner/packages/framework/tests fi - - name: Update composer.json to load framework from local source - run: | - cd hyde - composer config repositories.framework path ./packages/hyde/framework - composer require hyde/testing:dev-master hyde/framework:dev-develop - - - name: Download test runner configuration - run: cd hyde && curl https://raw.githubusercontent.com/hydephp/develop/master/packages/hyde/phpunit.xml.dist -o phpunit.xml.dist + - name: Install dependencies + run: cd runner && composer install - name: Set environment to testing - run: cd hyde && echo "ENV=testing" > .env + run: cd runner && echo "ENV=testing" > .env - name: Execute tests (Unit and Feature tests) via PHPUnit/Pest - run: cd hyde && vendor/bin/pest --log-junit report.xml + run: cd runner && vendor/bin/pest --log-junit report.xml env: ENV: testing - name: Ping statistics server with test results run: | - cd hyde + cd runner curl https://raw.githubusercontent.com/hydephp/develop/6e9d17f31879f4ccda13a3fec4029c9663bccec0/monorepo/scripts/ping-openanalytics-testrunner.php -o ping.php php ping.php "Framework CI Matrix" ${{ secrets.OPENANALYTICS_TOKEN }} From deaad281091a3014da7484a953389793e582867a Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 21 Dec 2024 14:04:40 +0100 Subject: [PATCH 67/80] Framework version v1.7.4 --- packages/framework/src/Foundation/HydeKernel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/Foundation/HydeKernel.php b/packages/framework/src/Foundation/HydeKernel.php index e6789e939ee..33d109e8080 100644 --- a/packages/framework/src/Foundation/HydeKernel.php +++ b/packages/framework/src/Foundation/HydeKernel.php @@ -58,7 +58,7 @@ class HydeKernel implements SerializableContract use Serializable; use Macroable; - final public const VERSION = '1.7.3'; + final public const VERSION = '1.7.4'; protected static self $instance; From 7d744ded1919cf191b7facccbb9a9de567ce3a9d Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 21 Dec 2024 20:20:57 +0100 Subject: [PATCH 68/80] Sync back with framework subpackage --- RELEASE_NOTES.md | 1 + packages/framework/.github/bin/pick.php | 58 +++++++++++++++++++ .../src/Support/Filesystem/MediaFile.php | 2 +- 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 packages/framework/.github/bin/pick.php diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e2f970a3d27..d0222bf5e85 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -15,6 +15,7 @@ This serves two purposes: - Added a new `Hyperlinks::isRemote()` helper method to check if a URL is remote in https://github.com/hydephp/develop/pull/1882 - All page types now support the `description` front matter field (used in page metadata) in https://github.com/hydephp/develop/pull/1884 - Added a new `Filesystem::findFiles()` method to find files in a directory in https://github.com/hydephp/develop/pull/2064 +- Added `webp` to the list of default media extensions in https://github.com/hydephp/framework/pull/663 ### Changed - Changed the `Hyde` facade to use a `@mixin` annotation instead of single method annotations in https://github.com/hydephp/develop/pull/1919 diff --git a/packages/framework/.github/bin/pick.php b/packages/framework/.github/bin/pick.php new file mode 100644 index 00000000000..c0303b09101 --- /dev/null +++ b/packages/framework/.github/bin/pick.php @@ -0,0 +1,58 @@ +#!/usr/bin/env php + [--pretend]\n"; + echo "\033[33mExample:\033[0m php bin/pick.php abc123 feature-branch\n"; + exit(1); +} + +// Get arguments +$hash = $argv[1]; +$branch = $argv[2]; +$pretend = ($argv[3] ?? false) === '--pretend'; + +// Get the commit message +exec("git show $hash --pretty=format:\"%s%n%b\" -s", $output, $returnCode); + +if ($returnCode === 0 && !empty($output)) { + $commitMessage = implode("\n", $output); + + // Check if this matches the subrepo sync format + if (preg_match('/^Merge pull request #(\d+).*\n(.*?)https:\/\/github\.com\/hydephp\/develop\/commit/', $commitMessage, $matches)) { + $prNumber = $matches[1]; + $title = trim($matches[2]); + $body = "Merges pull request https://github.com/hydephp/develop/pull/$prNumber"; + + $printWhenDone = "\n\033[33mSuggested PR format: (Line 1: title, Line 2: description, Line 3: command)\033[0m\n"; + $printWhenDone .= "$title\n$body\n"; + + $printWhenDone .= "\033[37mgh pr create --title \"$title\" --body \"$body\"\033[0m\n"; + } +} + +// Create new branch from master +exec(($pretend ? 'echo ' : '') . "git checkout -b $branch master", $output, $returnCode); + +if ($returnCode !== 0) { + echo "\033[31mError creating new branch: $branch\033[0m\n"; + exit(1); +} + +// Cherry-pick the commit +exec(($pretend ? 'echo ' : '') . "git cherry-pick $hash", $output, $returnCode); + +if ($returnCode !== 0) { + echo "\033[31mError cherry-picking commit: $hash\033[0m\n"; + exit(1); +} + +echo "\033[32mSuccessfully created branch '$branch' and cherry-picked commit '$hash'\033[0m\n"; + +if (isset($printWhenDone)) { + echo $printWhenDone; +} diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 09ab5247ad6..8574c4ed07a 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -25,7 +25,7 @@ class MediaFile extends ProjectFile { /** @var array The default extensions for media types */ - final public const EXTENSIONS = ['png', 'svg', 'jpg', 'jpeg', 'gif', 'ico', 'css', 'js']; + final public const EXTENSIONS = ['png', 'svg', 'jpg', 'jpeg', 'webp', 'gif', 'ico', 'css', 'js']; /** @return array The array keys are the filenames relative to the _media/ directory */ public static function all(): array From 56940818c9b03f9e5cefd9464c602c88708cbbdd Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 21 Dec 2024 22:43:57 +0100 Subject: [PATCH 69/80] Create a new `Hyde::makeSlug()` helper --- .../src/Foundation/Concerns/ImplementsStringHelpers.php | 5 +++++ packages/framework/tests/Feature/HydeKernelTest.php | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php b/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php index a5910e8bf71..d89fb58f49e 100644 --- a/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php +++ b/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php @@ -38,6 +38,11 @@ public static function makeTitle(string $value): string )); } + public static function makeSlug(string $value): string + { + return Str::slug($value); + } + public static function normalizeNewlines(string $string): string { return str_replace("\r\n", "\n", $string); diff --git a/packages/framework/tests/Feature/HydeKernelTest.php b/packages/framework/tests/Feature/HydeKernelTest.php index d2e58f58abc..feb93d38c52 100644 --- a/packages/framework/tests/Feature/HydeKernelTest.php +++ b/packages/framework/tests/Feature/HydeKernelTest.php @@ -108,6 +108,11 @@ public function testMakeTitleHelperReturnsTitleFromPageSlug() $this->assertSame('Foo Bar', Hyde::makeTitle('foo-bar')); } + public function testMakeSlugHelperReturnsSlugFromTitle() + { + $this->assertSame('foo-bar', Hyde::makeSlug('Foo Bar')); + } + public function testNormalizeNewlinesReplacesCarriageReturnsWithUnixEndings() { $this->assertSame("foo\nbar\nbaz", Hyde::normalizeNewlines("foo\nbar\r\nbaz")); From 8b1f0d0013c81950da2bed67064dbe6f571e3c19 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 21 Dec 2024 22:45:54 +0100 Subject: [PATCH 70/80] Create unit test for the slug generation helper --- .../tests/Feature/HydeKernelTest.php | 1 + .../Unit/HydeHelperFacadeMakeSlugTest.php | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 packages/framework/tests/Unit/HydeHelperFacadeMakeSlugTest.php diff --git a/packages/framework/tests/Feature/HydeKernelTest.php b/packages/framework/tests/Feature/HydeKernelTest.php index feb93d38c52..ea18c156855 100644 --- a/packages/framework/tests/Feature/HydeKernelTest.php +++ b/packages/framework/tests/Feature/HydeKernelTest.php @@ -32,6 +32,7 @@ * @covers \Hyde\Hyde * * @see \Hyde\Framework\Testing\Unit\HydeHelperFacadeMakeTitleTest + * @see \Hyde\Framework\Testing\Unit\HydeHelperFacadeMakeSlugTest * @see \Hyde\Framework\Testing\Feature\HydeExtensionFeatureTest */ class HydeKernelTest extends TestCase diff --git a/packages/framework/tests/Unit/HydeHelperFacadeMakeSlugTest.php b/packages/framework/tests/Unit/HydeHelperFacadeMakeSlugTest.php new file mode 100644 index 00000000000..b82ca5b1f4d --- /dev/null +++ b/packages/framework/tests/Unit/HydeHelperFacadeMakeSlugTest.php @@ -0,0 +1,61 @@ +assertSame('hello-world', Hyde::makeSlug('Hello World')); + } + + public function testMakeSlugHelperConvertsKebabCaseToSlug() + { + $this->assertSame('hello-world', Hyde::makeSlug('hello-world')); + } + + public function testMakeSlugHelperConvertsSnakeCaseToSlug() + { + $this->assertSame('hello-world', Hyde::makeSlug('hello_world')); + } + + public function testMakeSlugHelperConvertsCamelCaseToSlug() + { + $this->markTestSkipped('Not supported yet.'); + $this->assertSame('hello-world', Hyde::makeSlug('helloWorld')); + } + + public function testMakeSlugHelperConvertsPascalCaseToSlug() + { + $this->markTestSkipped('Not supported yet.'); + $this->assertSame('hello-world', Hyde::makeSlug('HelloWorld')); + } + + public function testMakeSlugHelperHandlesMultipleSpaces() + { + $this->assertSame('hello-world', Hyde::makeSlug('Hello World')); + } + + public function testMakeSlugHelperHandlesSpecialCharacters() + { + $this->assertSame('hello-world', Hyde::makeSlug('Hello & World!')); + } + + public function testMakeSlugHelperConvertsUppercaseToLowercase() + { + $this->assertSame('hello-world', Hyde::makeSlug('HELLO WORLD')); + $this->assertSame('hello-world', Hyde::makeSlug('HELLO_WORLD')); + } + + public function testMakeSlugHelperHandlesNumbers() + { + $this->assertSame('hello-world-123', Hyde::makeSlug('Hello World 123')); + } +} From cb90a4af9c229b809ca5aa800d6018f6422f4e78 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 21 Dec 2024 22:47:40 +0100 Subject: [PATCH 71/80] Use our slug generation helper --- .../src/Framework/Actions/CreatesNewMarkdownPostFile.php | 4 ++-- .../src/Framework/Actions/CreatesNewPageSourceFile.php | 2 +- .../Framework/Features/Navigation/DocumentationSidebar.php | 5 ++--- .../framework/src/Framework/Features/Navigation/NavItem.php | 3 +-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/framework/src/Framework/Actions/CreatesNewMarkdownPostFile.php b/packages/framework/src/Framework/Actions/CreatesNewMarkdownPostFile.php index 3f1f4ea9625..f524ded7c5b 100644 --- a/packages/framework/src/Framework/Actions/CreatesNewMarkdownPostFile.php +++ b/packages/framework/src/Framework/Actions/CreatesNewMarkdownPostFile.php @@ -6,9 +6,9 @@ use Hyde\Framework\Exceptions\FileConflictException; use Hyde\Facades\Filesystem; +use Hyde\Hyde; use Hyde\Pages\MarkdownPost; use Illuminate\Support\Carbon; -use Illuminate\Support\Str; /** * Offloads logic for the make:post command. @@ -48,7 +48,7 @@ public function __construct(string $title, ?string $description, ?string $catego $this->customContent = $customContent; $this->date = Carbon::make($date ?? Carbon::now())->format('Y-m-d H:i'); - $this->identifier = Str::slug($title); + $this->identifier = Hyde::makeSlug($title); } /** diff --git a/packages/framework/src/Framework/Actions/CreatesNewPageSourceFile.php b/packages/framework/src/Framework/Actions/CreatesNewPageSourceFile.php index ccb0fb6f809..aa9355a6f46 100644 --- a/packages/framework/src/Framework/Actions/CreatesNewPageSourceFile.php +++ b/packages/framework/src/Framework/Actions/CreatesNewPageSourceFile.php @@ -81,7 +81,7 @@ protected function fileName(string $title): string } // And return a slug made from just the title without the subdirectory - return Str::slug(basename($title)); + return Hyde::makeSlug(basename($title)); } protected function normalizeSubdirectory(string $title): string diff --git a/packages/framework/src/Framework/Features/Navigation/DocumentationSidebar.php b/packages/framework/src/Framework/Features/Navigation/DocumentationSidebar.php index 919b93434a6..2808fccf51d 100644 --- a/packages/framework/src/Framework/Features/Navigation/DocumentationSidebar.php +++ b/packages/framework/src/Framework/Features/Navigation/DocumentationSidebar.php @@ -11,7 +11,6 @@ use Hyde\Support\Facades\Render; use Hyde\Support\Models\Route; use Illuminate\Support\Collection; -use Illuminate\Support\Str; use function collect; @@ -48,13 +47,13 @@ public function getGroups(): array public function getItemsInGroup(?string $group): Collection { return $this->items->filter(function (NavItem $item) use ($group): bool { - return ($item->getGroup() === $group) || ($item->getGroup() === Str::slug($group)); + return ($item->getGroup() === $group) || ($item->getGroup() === Hyde::makeSlug($group)); })->sortBy('navigation.priority')->values(); } public function isGroupActive(string $group): bool { - return Str::slug(Render::getPage()->navigationMenuGroup()) === $group + return Hyde::makeSlug(Render::getPage()->navigationMenuGroup()) === $group || $this->isPageIndexPage() && $this->shouldIndexPageBeActive($group); } diff --git a/packages/framework/src/Framework/Features/Navigation/NavItem.php b/packages/framework/src/Framework/Features/Navigation/NavItem.php index 7a57b554282..a3fe8932c1b 100644 --- a/packages/framework/src/Framework/Features/Navigation/NavItem.php +++ b/packages/framework/src/Framework/Features/Navigation/NavItem.php @@ -7,7 +7,6 @@ use Hyde\Foundation\Facades\Routes; use Hyde\Hyde; use Hyde\Support\Models\Route; -use Illuminate\Support\Str; use Stringable; /** @@ -133,6 +132,6 @@ protected static function getRouteGroup(Route $route): ?string protected static function normalizeGroupKey(?string $group): ?string { - return $group ? Str::slug($group) : null; + return $group ? Hyde::makeSlug($group) : null; } } From a0a8632366391074ec7954e2ec6c08c1666438b1 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 21 Dec 2024 22:50:46 +0100 Subject: [PATCH 72/80] Expand slug generation helper to support more input cases --- .../src/Foundation/Concerns/ImplementsStringHelpers.php | 3 +++ packages/framework/tests/Unit/HydeHelperFacadeMakeSlugTest.php | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php b/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php index d89fb58f49e..ab6c2496cbb 100644 --- a/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php +++ b/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php @@ -40,6 +40,9 @@ public static function makeTitle(string $value): string public static function makeSlug(string $value): string { + // Expand camelCase and PascalCase to separate words + $value = preg_replace('/([a-z])([A-Z])/', '$1 $2', $value); + return Str::slug($value); } diff --git a/packages/framework/tests/Unit/HydeHelperFacadeMakeSlugTest.php b/packages/framework/tests/Unit/HydeHelperFacadeMakeSlugTest.php index b82ca5b1f4d..d4e4b724525 100644 --- a/packages/framework/tests/Unit/HydeHelperFacadeMakeSlugTest.php +++ b/packages/framework/tests/Unit/HydeHelperFacadeMakeSlugTest.php @@ -28,13 +28,11 @@ public function testMakeSlugHelperConvertsSnakeCaseToSlug() public function testMakeSlugHelperConvertsCamelCaseToSlug() { - $this->markTestSkipped('Not supported yet.'); $this->assertSame('hello-world', Hyde::makeSlug('helloWorld')); } public function testMakeSlugHelperConvertsPascalCaseToSlug() { - $this->markTestSkipped('Not supported yet.'); $this->assertSame('hello-world', Hyde::makeSlug('HelloWorld')); } From db4a454817aa0296e942efd7a2154ee2cfef0bd5 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 22 Dec 2024 10:12:18 +0100 Subject: [PATCH 73/80] Transliterate international characters when generating slugs --- .../Concerns/ImplementsStringHelpers.php | 3 + .../Unit/HydeHelperFacadeMakeSlugTest.php | 72 +++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php b/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php index ab6c2496cbb..f95dc622fb3 100644 --- a/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php +++ b/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php @@ -43,6 +43,9 @@ public static function makeSlug(string $value): string // Expand camelCase and PascalCase to separate words $value = preg_replace('/([a-z])([A-Z])/', '$1 $2', $value); + // Transliterate international characters to ASCII + $value = Str::transliterate($value); + return Str::slug($value); } diff --git a/packages/framework/tests/Unit/HydeHelperFacadeMakeSlugTest.php b/packages/framework/tests/Unit/HydeHelperFacadeMakeSlugTest.php index d4e4b724525..0d1279ccb9c 100644 --- a/packages/framework/tests/Unit/HydeHelperFacadeMakeSlugTest.php +++ b/packages/framework/tests/Unit/HydeHelperFacadeMakeSlugTest.php @@ -56,4 +56,76 @@ public function testMakeSlugHelperHandlesNumbers() { $this->assertSame('hello-world-123', Hyde::makeSlug('Hello World 123')); } + + public function testMakeSlugHelperTransliteratesChineseCharacters() + { + $this->assertSame('ni-hao-shi-jie', Hyde::makeSlug('你好世界')); + } + + public function testMakeSlugHelperTransliteratesJapaneseCharacters() + { + $this->assertSame('konnichihashi-jie', Hyde::makeSlug('こんにちは世界')); + } + + public function testMakeSlugHelperTransliteratesKoreanCharacters() + { + $this->assertSame('annyeongsegye', Hyde::makeSlug('안녕세계')); + } + + public function testMakeSlugHelperTransliteratesArabicCharacters() + { + $this->assertSame('mrhb-bllm', Hyde::makeSlug('مرحبا بالعالم')); + } + + public function testMakeSlugHelperTransliteratesRussianCharacters() + { + $this->assertSame('privet-mir', Hyde::makeSlug('Привет мир')); + } + + public function testMakeSlugHelperTransliteratesAccentedLatinCharacters() + { + $this->assertSame('hello-world', Hyde::makeSlug('hèllô wórld')); + $this->assertSame('uber-strasse', Hyde::makeSlug('über straße')); + } + + public function testMakeSlugHelperHandlesMixedScripts() + { + $this->assertSame('hello-ni-hao-world', Hyde::makeSlug('Hello 你好 World')); + $this->assertSame('privet-world', Hyde::makeSlug('Привет World')); + } + + public function testMakeSlugHelperHandlesEmojis() + { + $this->assertSame('hello-world', Hyde::makeSlug('Hello 👋 World')); + $this->assertSame('world', Hyde::makeSlug('😊 World')); + } + + public function testMakeSlugHelperHandlesComplexMixedInput() + { + $this->assertSame( + 'hello-ni-hao-privet-bonjour-world-123', + Hyde::makeSlug('Hello 你好 Привет Bonjóur World 123!') + ); + } + + public function testMakeSlugHelperHandlesEdgeCases() + { + $this->assertSame('', Hyde::makeSlug('')); + $this->assertSame('at', Hyde::makeSlug('!@#$%^&*()')); + $this->assertSame('', Hyde::makeSlug('... ...')); + $this->assertSame('multiple-dashes', Hyde::makeSlug('multiple---dashes')); + } + + public function testMakeSlugHelperPreservesValidCharacters() + { + $this->assertSame('abc-123', Hyde::makeSlug('abc-123')); + $this->assertSame('test-slug', Hyde::makeSlug('test-slug')); + } + + public function testMakeSlugHelperHandlesWhitespace() + { + $this->assertSame('trim-spaces', Hyde::makeSlug(' trim spaces ')); + $this->assertSame('newline-test', Hyde::makeSlug("newline\ntest")); + $this->assertSame('tab-test', Hyde::makeSlug("tab\ttest")); + } } From 5b201eba5b37b9a23f3b3dd0ac3cdcd661573359 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 22 Dec 2024 10:19:03 +0100 Subject: [PATCH 74/80] Refactor method to make it more readable --- .../Framework/Features/Navigation/DocumentationSidebar.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/framework/src/Framework/Features/Navigation/DocumentationSidebar.php b/packages/framework/src/Framework/Features/Navigation/DocumentationSidebar.php index 2808fccf51d..b9eeccf4e05 100644 --- a/packages/framework/src/Framework/Features/Navigation/DocumentationSidebar.php +++ b/packages/framework/src/Framework/Features/Navigation/DocumentationSidebar.php @@ -53,8 +53,9 @@ public function getItemsInGroup(?string $group): Collection public function isGroupActive(string $group): bool { - return Hyde::makeSlug(Render::getPage()->navigationMenuGroup()) === $group - || $this->isPageIndexPage() && $this->shouldIndexPageBeActive($group); + $normalized = Hyde::makeSlug(Render::getPage()->navigationMenuGroup()); + + return ($normalized === $group) || ($this->isPageIndexPage() && $this->shouldIndexPageBeActive($group)); } public function makeGroupTitle(string $group): string From 48213a376eeebea0801dac6a58bff8574d7ba92d Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 22 Dec 2024 10:19:23 +0100 Subject: [PATCH 75/80] Add comparison fallback instead of null value --- .../src/Framework/Features/Navigation/DocumentationSidebar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/Framework/Features/Navigation/DocumentationSidebar.php b/packages/framework/src/Framework/Features/Navigation/DocumentationSidebar.php index b9eeccf4e05..f9fc088a82f 100644 --- a/packages/framework/src/Framework/Features/Navigation/DocumentationSidebar.php +++ b/packages/framework/src/Framework/Features/Navigation/DocumentationSidebar.php @@ -53,7 +53,7 @@ public function getItemsInGroup(?string $group): Collection public function isGroupActive(string $group): bool { - $normalized = Hyde::makeSlug(Render::getPage()->navigationMenuGroup()); + $normalized = Hyde::makeSlug(Render::getPage()->navigationMenuGroup() ?? 'other'); return ($normalized === $group) || ($this->isPageIndexPage() && $this->shouldIndexPageBeActive($group)); } From 586492a5cb0315cbc6aeb4662ffeff189062fd7d Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 22 Dec 2024 10:19:37 +0100 Subject: [PATCH 76/80] Regenerate documentation for added method --- .../hyde-pages-api/hyde-kernel-string-methods.md | 10 +++++++++- docs/architecture-concepts/the-hydekernel.md | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/_data/partials/hyde-pages-api/hyde-kernel-string-methods.md b/docs/_data/partials/hyde-pages-api/hyde-kernel-string-methods.md index 4659a1ed2f2..60c1f74ed80 100644 --- a/docs/_data/partials/hyde-pages-api/hyde-kernel-string-methods.md +++ b/docs/_data/partials/hyde-pages-api/hyde-kernel-string-methods.md @@ -1,7 +1,7 @@
- + #### `makeTitle()` @@ -11,6 +11,14 @@ No description provided. Hyde::makeTitle(string $value): string ``` +#### `makeSlug()` + +No description provided. + +```php +Hyde::makeSlug(string $value): string +``` + #### `normalizeNewlines()` No description provided. diff --git a/docs/architecture-concepts/the-hydekernel.md b/docs/architecture-concepts/the-hydekernel.md index 9f470ed3835..e7cd81eecb4 100644 --- a/docs/architecture-concepts/the-hydekernel.md +++ b/docs/architecture-concepts/the-hydekernel.md @@ -140,7 +140,7 @@ Hyde::routes(): Hyde\Foundation\Kernel\RouteCollection
- + #### `makeTitle()` @@ -150,6 +150,14 @@ No description provided. Hyde::makeTitle(string $value): string ``` +#### `makeSlug()` + +No description provided. + +```php +Hyde::makeSlug(string $value): string +``` + #### `normalizeNewlines()` No description provided. From 011d4a0788e34ae6d84b26b0c76ea550bde25a79 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 22 Dec 2024 11:40:44 +0100 Subject: [PATCH 77/80] Add todo to match normalization to v2 generation Want to match https://github.com/hydephp/develop/pull/2059, but that would change output so deferring to v2. --- .../src/Foundation/Concerns/ImplementsStringHelpers.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php b/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php index f95dc622fb3..910960488a2 100644 --- a/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php +++ b/packages/framework/src/Foundation/Concerns/ImplementsStringHelpers.php @@ -46,6 +46,8 @@ public static function makeSlug(string $value): string // Transliterate international characters to ASCII $value = Str::transliterate($value); + // Todo: In v2.0 we will use the following dictionary: ['@' => 'at', '&' => 'and'] + return Str::slug($value); } From 7f2ae3c584d717b28d1d8b25a153d3e240647186 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 22 Dec 2024 11:54:22 +0100 Subject: [PATCH 78/80] Create high level internationalization test --- .../Feature/InternationalizationTest.php | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 packages/framework/tests/Feature/InternationalizationTest.php diff --git a/packages/framework/tests/Feature/InternationalizationTest.php b/packages/framework/tests/Feature/InternationalizationTest.php new file mode 100644 index 00000000000..75738b2877c --- /dev/null +++ b/packages/framework/tests/Feature/InternationalizationTest.php @@ -0,0 +1,70 @@ +save(); + + $this->assertSame('_posts/ni-hao-shi-jie.md', $path); + $this->assertSame('ni-hao-shi-jie', $creator->getIdentifier()); + $this->assertSame($creator->getIdentifier(), Hyde::makeSlug('你好世界')); + $this->assertFileExists($path); + + $contents = file_get_contents($path); + $this->assertStringContainsString('title: 你好世界', $contents); + $this->assertSame(<<<'EOF' + --- + title: 你好世界 + description: 简短描述 + category: blog + author: default + date: '2024-12-22 10:45' + --- + + ## Write something awesome. + + EOF, $contents); + + Filesystem::unlink($path); + } + + public function testCanCompileBlogPostFilesWithInternationalCharacterSets() + { + $page = new MarkdownPost('ni-hao-shi-jie', [ + 'title' => '你好世界', + 'description' => '简短描述', + 'category' => 'blog', + 'author' => 'default', + 'date' => '2024-12-22 10:45', + ]); + + $path = StaticPageBuilder::handle($page); + + $this->assertSame(Hyde::path('_site/posts/ni-hao-shi-jie.html'), $path); + $this->assertFileExists($path); + + $contents = file_get_contents($path); + + $this->assertStringContainsString('HydePHP - 你好世界', $contents); + $this->assertStringContainsString('

你好世界

', $contents); + $this->assertStringContainsString('', $contents); + + Filesystem::unlink($path); + } +} From 51d4198605e81b379968103e1616587ab83dc34c Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 22 Dec 2024 12:04:12 +0100 Subject: [PATCH 79/80] Use data provider to test more character sets --- .../Feature/InternationalizationTest.php | 85 ++++++++++++++----- 1 file changed, 66 insertions(+), 19 deletions(-) diff --git a/packages/framework/tests/Feature/InternationalizationTest.php b/packages/framework/tests/Feature/InternationalizationTest.php index 75738b2877c..04e6d6fa861 100644 --- a/packages/framework/tests/Feature/InternationalizationTest.php +++ b/packages/framework/tests/Feature/InternationalizationTest.php @@ -16,22 +16,38 @@ */ class InternationalizationTest extends TestCase { - public function testCanCreateBlogPostFilesWithInternationalCharacterSets() - { - $creator = new CreatesNewMarkdownPostFile('你好世界', '简短描述', 'blog', 'default', '2024-12-22 10:45'); + /** + * @dataProvider internationalCharacterSetsProvider + */ + public function testCanCreateBlogPostFilesWithInternationalCharacterSets( + string $title, + string $description, + string $expectedSlug, + string $expectedTitle + ) { + $creator = new CreatesNewMarkdownPostFile($title, $description, 'blog', 'default', '2024-12-22 10:45'); $path = $creator->save(); - $this->assertSame('_posts/ni-hao-shi-jie.md', $path); - $this->assertSame('ni-hao-shi-jie', $creator->getIdentifier()); - $this->assertSame($creator->getIdentifier(), Hyde::makeSlug('你好世界')); + $this->assertSame("_posts/$expectedSlug.md", $path); + $this->assertSame($expectedSlug, $creator->getIdentifier()); + $this->assertSame($creator->getIdentifier(), Hyde::makeSlug($title)); $this->assertFileExists($path); $contents = file_get_contents($path); - $this->assertStringContainsString('title: 你好世界', $contents); - $this->assertSame(<<<'EOF' + + if (str_contains($title, ' ')) { + $expectedTitle = "'$expectedTitle'"; + } + + if (str_contains($description, ' ')) { + $description = "'$description'"; + } + + $this->assertStringContainsString("title: $expectedTitle", $contents); + $this->assertSame(<< '你好世界', - 'description' => '简短描述', + /** + * @dataProvider internationalCharacterSetsProvider + */ + public function testCanCompileBlogPostFilesWithInternationalCharacterSets( + string $title, + string $description, + string $expectedSlug, + string $expectedTitle + ) { + $page = new MarkdownPost($expectedSlug, [ + 'title' => $title, + 'description' => $description, 'category' => 'blog', 'author' => 'default', 'date' => '2024-12-22 10:45', @@ -56,15 +79,39 @@ public function testCanCompileBlogPostFilesWithInternationalCharacterSets() $path = StaticPageBuilder::handle($page); - $this->assertSame(Hyde::path('_site/posts/ni-hao-shi-jie.html'), $path); + $this->assertSame(Hyde::path("_site/posts/$expectedSlug.html"), $path); $this->assertFileExists($path); $contents = file_get_contents($path); - $this->assertStringContainsString('HydePHP - 你好世界', $contents); - $this->assertStringContainsString('

你好世界

', $contents); - $this->assertStringContainsString('', $contents); + $this->assertStringContainsString("HydePHP - $expectedTitle", $contents); + $this->assertStringContainsString("

$expectedTitle

", $contents); + $this->assertStringContainsString("", $contents); Filesystem::unlink($path); } + + public static function internationalCharacterSetsProvider(): array + { + return [ + 'Chinese (Simplified)' => [ + '你好世界', + '简短描述', + 'ni-hao-shi-jie', + '你好世界', + ], + 'Japanese' => [ + 'こんにちは世界', + '短い説明', + 'konnichihashi-jie', + 'こんにちは世界', + ], + 'Korean' => [ + '안녕하세요 세계', + '짧은 설명', + 'annyeonghaseyo-segye', + '안녕하세요 세계', + ], + ]; + } } From 829f0e46637a84a5fceb36787ac6d2e422631d75 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 22 Dec 2024 12:00:28 +0100 Subject: [PATCH 80/80] Update RELEASE_NOTES.md --- RELEASE_NOTES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index d0222bf5e85..9300bb0087a 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -16,6 +16,7 @@ This serves two purposes: - All page types now support the `description` front matter field (used in page metadata) in https://github.com/hydephp/develop/pull/1884 - Added a new `Filesystem::findFiles()` method to find files in a directory in https://github.com/hydephp/develop/pull/2064 - Added `webp` to the list of default media extensions in https://github.com/hydephp/framework/pull/663 +- Added a new slug generation helper to improve internationalization support in https://github.com/hydephp/develop/pull/2070 ### Changed - Changed the `Hyde` facade to use a `@mixin` annotation instead of single method annotations in https://github.com/hydephp/develop/pull/1919 @@ -26,6 +27,7 @@ This serves two purposes: - The `torchlight:install` command is now hidden from the command list as it's already installed in https://github.com/hydephp/develop/pull/1879 - Updated the home page fallback link in the 404 template to lead to the site root in https://github.com/hydephp/develop/pull/1880 (fixes https://github.com/hydephp/develop/issues/1781) - Normalized remote URL checks so that protocol relative URLs `//` are consistently considered to be remote in all places in https://github.com/hydephp/develop/pull/1882 (fixes https://github.com/hydephp/develop/issues/1788) +- Page slugs are now generated using our automatically internationalizing slug generator to transliterate input to ASCII in https://github.com/hydephp/develop/pull/2070 - Replaced internal usages of glob functions with our improved file finder in https://github.com/hydephp/develop/pull/2064 - Updated to HydeFront v3.4 in https://github.com/hydephp/develop/pull/1803 - Realtime Compiler: Virtual routes are now managed through the service container in https://github.com/hydephp/develop/pull/1858 @@ -46,6 +48,7 @@ This serves two purposes: - Fixed heading permalinks button text showing in Google Search previews https://github.com/hydephp/develop/issues/1801 in https://github.com/hydephp/develop/pull/1803 - Fixed routing issues with nested 404 pages where an index page does not exist https://github.com/hydephp/develop/issues/1781 in https://github.com/hydephp/develop/pull/1880 - Fixed URL metadata for blog posts not using customized post output directories in https://github.com/hydephp/develop/pull/1889 +- Fixed lacking support for logographic slug generation https://github.com/hydephp/hyde/issues/269 in https://github.com/hydephp/develop/pull/2070 - Improved printed documentation views in https://github.com/hydephp/develop/pull/2005 - Fixed "BuildService finding non-existent files to copy in Debian" https://github.com/hydephp/framework/issues/662 in https://github.com/hydephp/develop/pull/2064 - Fixed "Undefined constant `Hyde\Foundation\Kernel\GLOB_BRACE`" https://github.com/hydephp/hyde/issues/270 in https://github.com/hydephp/develop/pull/2064