diff --git a/.idea/develop.iml b/.idea/develop.iml index b5e53b44ef0..f357c61d82f 100644 --- a/.idea/develop.iml +++ b/.idea/develop.iml @@ -8,8 +8,6 @@ - - diff --git a/composer.lock b/composer.lock index 62f95e14593..9a899f6d904 100644 --- a/composer.lock +++ b/composer.lock @@ -1129,7 +1129,7 @@ "illuminate/view": "^10.0", "league/commonmark": "^2.2", "php": "^8.1", - "spatie/yaml-front-matter": "^2.0.7", + "spatie/yaml-front-matter": "^2.0.9", "symfony/yaml": "^6.0", "torchlight/torchlight-commonmark": "^0.5.5" }, @@ -4429,16 +4429,16 @@ }, { "name": "spatie/yaml-front-matter", - "version": "2.0.8", + "version": "2.0.9", "source": { "type": "git", "url": "https://github.com/spatie/yaml-front-matter.git", - "reference": "f2f1f749a405fafc9d6337067c92c062d51a581c" + "reference": "cbe67e1cdd0a29a96d74ccab9400fe663e078392" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/yaml-front-matter/zipball/f2f1f749a405fafc9d6337067c92c062d51a581c", - "reference": "f2f1f749a405fafc9d6337067c92c062d51a581c", + "url": "https://api.github.com/repos/spatie/yaml-front-matter/zipball/cbe67e1cdd0a29a96d74ccab9400fe663e078392", + "reference": "cbe67e1cdd0a29a96d74ccab9400fe663e078392", "shasum": "" }, "require": { @@ -4475,7 +4475,7 @@ "yaml" ], "support": { - "source": "https://github.com/spatie/yaml-front-matter/tree/2.0.8" + "source": "https://github.com/spatie/yaml-front-matter/tree/2.0.9" }, "funding": [ { @@ -4487,7 +4487,7 @@ "type": "github" } ], - "time": "2023-12-04T10:02:52+00:00" + "time": "2024-06-13T10:20:51+00:00" }, { "name": "symfony/console", diff --git a/package-lock.json b/package-lock.json index c163c347a65..e9232a7eb9a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,8 @@ "hydefront": "^3.3.0", "laravel-mix": "^6.0.49", "postcss": "^8.4.38", - "prettier": "3.3.0", - "tailwindcss": "^3.4.3" + "prettier": "3.3.2", + "tailwindcss": "^3.4.4" } }, "node_modules/@alloc/quick-lru": { @@ -2968,12 +2968,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -4662,9 +4662,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -7529,9 +7529,9 @@ "dev": true }, "node_modules/prettier": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.0.tgz", - "integrity": "sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -8732,9 +8732,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", - "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz", + "integrity": "sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==", "dev": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", @@ -9760,16 +9760,16 @@ "dev": true }, "node_modules/ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -12099,12 +12099,12 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "brorand": { @@ -13411,9 +13411,9 @@ "dev": true }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -15447,9 +15447,9 @@ "dev": true }, "prettier": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.0.tgz", - "integrity": "sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", "dev": true }, "pretty-time": { @@ -16385,9 +16385,9 @@ } }, "tailwindcss": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", - "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz", + "integrity": "sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==", "dev": true, "requires": { "@alloc/quick-lru": "^5.2.0", @@ -17107,9 +17107,9 @@ "dev": true }, "ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index 2e397a2a96e..dbde79ff5c2 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "hydefront": "^3.3.0", "laravel-mix": "^6.0.49", "postcss": "^8.4.38", - "prettier": "3.3.0", - "tailwindcss": "^3.4.3" + "prettier": "3.3.2", + "tailwindcss": "^3.4.4" } } diff --git a/packages/framework/composer.json b/packages/framework/composer.json index bc45ee2fb61..f716759c2d4 100644 --- a/packages/framework/composer.json +++ b/packages/framework/composer.json @@ -27,7 +27,7 @@ "illuminate/view": "^10.0", "symfony/yaml": "^6.0", "league/commonmark": "^2.2", - "spatie/yaml-front-matter": "^2.0.7", + "spatie/yaml-front-matter": "^2.0.9", "torchlight/torchlight-commonmark": "^0.5.5" }, "suggest": { diff --git a/packages/framework/src/Console/Commands/RouteListCommand.php b/packages/framework/src/Console/Commands/RouteListCommand.php index 0eb86431379..1c1937b432c 100644 --- a/packages/framework/src/Console/Commands/RouteListCommand.php +++ b/packages/framework/src/Console/Commands/RouteListCommand.php @@ -5,11 +5,12 @@ namespace Hyde\Console\Commands; use Hyde\Hyde; +use Illuminate\Support\Arr; use Hyde\Console\Concerns\Command; use Hyde\Support\Internal\RouteListItem; -use function array_map; use function array_keys; +use function json_encode; use function array_values; /** @@ -18,7 +19,7 @@ class RouteListCommand extends Command { /** @var string */ - protected $signature = 'route:list'; + protected $signature = 'route:list {--format=txt : The output format (txt or json)}'; /** @var string */ protected $description = 'Display all the registered routes'; @@ -27,20 +28,29 @@ public function handle(): int { $routes = $this->generate(); - $this->table($this->makeHeader($routes), $routes); - - return Command::SUCCESS; + return match ($this->option('format')) { + 'txt' => $this->table($this->makeHeader($routes), $routes) ?? Command::SUCCESS, + 'json' => $this->writeRaw(json_encode($routes, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) ?? Command::SUCCESS, + default => $this->error("Invalid format provided. Only 'txt' and 'json' are supported.") ?? Command::FAILURE, + }; } /** @return array> */ protected function generate(): array { - return array_map(RouteListItem::format(...), array_values(Hyde::routes()->all())); + return Arr::map(array_values(Hyde::routes()->all()), RouteListItem::format(...)); } /** @param array> $routes */ protected function makeHeader(array $routes): array { - return array_map(Hyde::makeTitle(...), array_keys($routes[0])); + return Arr::map(array_keys($routes[0]), Hyde::makeTitle(...)); + } + + /** Write a message without ANSI formatting */ + protected function writeRaw(string $message): void + { + $this->output->setDecorated(false); + $this->output->writeln($message); } } diff --git a/packages/framework/src/Foundation/Kernel/Hyperlinks.php b/packages/framework/src/Foundation/Kernel/Hyperlinks.php index 9755841439d..9cec5ca989c 100644 --- a/packages/framework/src/Foundation/Kernel/Hyperlinks.php +++ b/packages/framework/src/Foundation/Kernel/Hyperlinks.php @@ -126,27 +126,38 @@ public function asset(string $name, bool $preferQualifiedUrl = false): string /** * Check if a site base URL has been set in config (or .env). + * + * The default value is `http://localhost`, which is not considered a valid site URL. */ public function hasSiteUrl(): bool { - return ! blank(Config::getNullableString('hyde.url')); + $value = Config::getNullableString('hyde.url'); + + return ! blank($value) && $value !== 'http://localhost'; } /** * Return a qualified URL to the supplied path if a base URL is set. * - * @param string $path optional relative path suffix. Omit to return base url. + * @param string $path An optional relative path suffix. Omit to return the base URL. * - * @throws BaseUrlNotSetException If no site URL is set and no default is provided + * @throws BaseUrlNotSetException If no site URL is set and no path is provided. */ public function url(string $path = ''): string { $path = $this->formatLink(trim($path, '/')); if ($this->hasSiteUrl()) { - return rtrim(rtrim((string) Config::getNullableString('hyde.url'), '/')."/$path", '/'); + return rtrim(rtrim(Config::getString('hyde.url'), '/')."/$path", '/'); + } + + // Since v1.7.0, we return the relative path even if the base URL is not set, + // as this is more likely to be the desired behavior the user's expecting. + if (! blank($path)) { + return $path; } + // User is trying to get the base URL, but it's not set throw new BaseUrlNotSetException(); } diff --git a/packages/framework/src/Framework/Actions/PostBuildTasks/GenerateSitemap.php b/packages/framework/src/Framework/Actions/PostBuildTasks/GenerateSitemap.php index e2e15c55809..4409ede2934 100644 --- a/packages/framework/src/Framework/Actions/PostBuildTasks/GenerateSitemap.php +++ b/packages/framework/src/Framework/Actions/PostBuildTasks/GenerateSitemap.php @@ -9,7 +9,6 @@ use Hyde\Framework\Concerns\InteractsWithDirectories; use Hyde\Framework\Features\XmlGenerators\SitemapGenerator; -use function blank; use function file_put_contents; class GenerateSitemap extends PostBuildTask @@ -22,7 +21,7 @@ class GenerateSitemap extends PostBuildTask public function handle(): void { - if (blank(Hyde::url()) || str_starts_with(Hyde::url(), 'http://localhost')) { + if (! Hyde::hasSiteUrl()) { $this->skip('Cannot generate sitemap without a valid base URL'); } diff --git a/packages/framework/src/Support/DataCollections.php b/packages/framework/src/Support/DataCollections.php index a6ea6e41466..b5ab786edef 100644 --- a/packages/framework/src/Support/DataCollections.php +++ b/packages/framework/src/Support/DataCollections.php @@ -51,7 +51,7 @@ public static function markdown(string $name): static { static::needsDirectory(static::$sourceDirectory); - return new static(DataCollections::findFiles($name, 'md')->mapWithKeys(function (string $file): array { + return new static(static::findFiles($name, 'md')->mapWithKeys(function (string $file): array { return [static::makeIdentifier($file) => MarkdownFileParser::parse($file)]; })); } @@ -67,7 +67,7 @@ public static function yaml(string $name): static { static::needsDirectory(static::$sourceDirectory); - return new static(DataCollections::findFiles($name, ['yaml', 'yml'])->mapWithKeys(function (string $file): array { + return new static(static::findFiles($name, ['yaml', 'yml'])->mapWithKeys(function (string $file): array { return [static::makeIdentifier($file) => MarkdownFileParser::parse($file)->matter()]; })); } @@ -83,7 +83,7 @@ public static function json(string $name, bool $asArray = false): static { static::needsDirectory(static::$sourceDirectory); - return new static(DataCollections::findFiles($name, 'json')->mapWithKeys(function (string $file) use ($asArray): array { + return new static(static::findFiles($name, 'json')->mapWithKeys(function (string $file) use ($asArray): array { return [static::makeIdentifier($file) => json_decode(Filesystem::get($file), $asArray)]; })); } diff --git a/packages/framework/tests/Feature/Commands/RouteListCommandTest.php b/packages/framework/tests/Feature/Commands/RouteListCommandTest.php index 95edc551478..b715501c251 100644 --- a/packages/framework/tests/Feature/Commands/RouteListCommandTest.php +++ b/packages/framework/tests/Feature/Commands/RouteListCommandTest.php @@ -98,6 +98,49 @@ public function testConsoleRouteListWithTypeLabel() ]])->assertExitCode(0); } + public function testConsoleRouteListWithTextFormatOption() + { + $this->artisan('route:list --format=txt') + ->expectsTable($this->headers(), [[ + 'BladePage', + '_pages/404.blade.php', + '_site/404.html', + '404', + ], [ + 'BladePage', + '_pages/index.blade.php', + '_site/index.html', + 'index', + ]])->assertExitCode(0); + } + + public function testConsoleRouteListWithJsonFormatOption() + { + $this->artisan('route:list --format=json') + ->expectsOutput(json_encode([ + [ + 'page_type' => 'BladePage', + 'source_file' => '_pages/404.blade.php', + 'output_file' => '_site/404.html', + 'route_key' => '404', + ], + [ + 'page_type' => 'BladePage', + 'source_file' => '_pages/index.blade.php', + 'output_file' => '_site/index.html', + 'route_key' => 'index', + ], + ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) + ->assertExitCode(0); + } + + public function testConsoleRouteListWithInvalidFormatOption() + { + $this->artisan('route:list --format=foo') + ->expectsOutput("Invalid format provided. Only 'txt' and 'json' are supported.") + ->assertExitCode(1); + } + protected function headers(): array { return ['Page Type', 'Source File', 'Output File', 'Route Key']; diff --git a/packages/framework/tests/Feature/Foundation/HyperlinksTest.php b/packages/framework/tests/Feature/Foundation/HyperlinksTest.php index 584b8e33d98..bd811f612e1 100644 --- a/packages/framework/tests/Feature/Foundation/HyperlinksTest.php +++ b/packages/framework/tests/Feature/Foundation/HyperlinksTest.php @@ -35,7 +35,7 @@ public function testAssetHelperGetsRelativeWebLinkToImageStoredInSiteMediaFolder ]; foreach ($tests as $input => $expected) { - $this->assertEquals($this->class->asset($input), $expected); + $this->assertSame($this->class->asset($input), $expected); } } @@ -50,30 +50,42 @@ public function testAssetHelperResolvesPathsForNestedPages() foreach ($tests as $input => $expected) { $this->mockCurrentPage('foo/bar'); - $this->assertEquals($this->class->asset($input), $expected); + $this->assertSame($this->class->asset($input), $expected); } } public function testAssetHelperReturnsQualifiedAbsoluteUriWhenRequestedAndSiteHasBaseUrl() { - $this->assertEquals('http://localhost/media/test.jpg', $this->class->asset('test.jpg', true)); + config(['hyde.url' => 'https://example.org']); + $this->assertSame('https://example.org/media/test.jpg', $this->class->asset('test.jpg', true)); } public function testAssetHelperReturnsDefaultRelativePathWhenQualifiedAbsoluteUriIsRequestedButSiteHasNoBaseUrl() { config(['hyde.url' => null]); - $this->assertEquals('media/test.jpg', $this->class->asset('test.jpg', true)); + $this->assertSame('media/test.jpg', $this->class->asset('test.jpg', true)); + } + + public function testAssetHelperReturnsDefaultRelativePathWhenQualifiedAbsoluteUriIsRequestedButSiteBaseUrlIsLocalhost() + { + $this->assertSame('media/test.jpg', $this->class->asset('test.jpg', true)); } public function testAssetHelperReturnsInputWhenQualifiedAbsoluteUriIsRequestedButImageIsAlreadyQualified() { - $this->assertEquals('http://localhost/media/test.jpg', $this->class->asset('http://localhost/media/test.jpg', true)); + $this->assertSame('http://localhost/media/test.jpg', $this->class->asset('http://localhost/media/test.jpg', true)); + } + + public function testAssetHelperReturnsInputWhenQualifiedAbsoluteUriIsRequestedButImageIsAlreadyQualifiedRegardlessOfMatchingTheConfiguredUrl() + { + config(['hyde.url' => 'https://example.org']); + $this->assertSame('http://localhost/media/test.jpg', $this->class->asset('http://localhost/media/test.jpg', true)); } public function testAssetHelperUsesConfiguredMediaDirectory() { Hyde::setMediaDirectory('_assets'); - $this->assertEquals('assets/test.jpg', $this->class->asset('test.jpg')); + $this->assertSame('assets/test.jpg', $this->class->asset('test.jpg')); } public function testMediaLinkHelper() diff --git a/packages/framework/tests/Feature/HelpersTest.php b/packages/framework/tests/Feature/HelpersTest.php index a28e49e9497..733a832e7ec 100644 --- a/packages/framework/tests/Feature/HelpersTest.php +++ b/packages/framework/tests/Feature/HelpersTest.php @@ -77,7 +77,14 @@ public function testAssetFunction() public function testAssetFunctionWithQualifiedUrl() { $this->assertSame(Hyde::asset('foo', true), asset('foo', true)); - $this->assertSame('http://localhost/media/foo', asset('foo', true)); + $this->assertSame('media/foo', asset('foo', true)); + } + + /** @covers ::asset */ + public function testAssetFunctionWithQualifiedUrlAndSetBaseUrl() + { + $this->app['config']->set(['hyde.url' => 'https://example.com']); + $this->assertSame('https://example.com/media/foo', asset('foo', true)); } /** @covers ::asset */ @@ -94,6 +101,13 @@ public function testAssetFunctionWithQualifiedUrlAndNoBaseUrl() $this->assertSame('media/foo', asset('foo', true)); } + /** @covers ::asset */ + public function testAssetFunctionWithQualifiedUrlAndLocalhostBaseUrl() + { + $this->app['config']->set(['hyde.url' => 'http://localhost']); + $this->assertSame('media/foo', asset('foo', true)); + } + /** @covers ::asset */ public function testAssetFunctionFromNestedPage() { @@ -145,17 +159,39 @@ public function testUrlFunction() /** @covers ::url */ public function testUrlFunctionWithBaseUrl() + { + $this->app['config']->set(['hyde.url' => 'https://example.com']); + $this->assertSame('https://example.com/foo', url('foo')); + } + + /** @covers ::url */ + public function testUrlFunctionWithLocalhostBaseUrl() { $this->app['config']->set(['hyde.url' => 'http://localhost']); - $this->assertSame('http://localhost/foo', url('foo')); + $this->assertSame('foo', url('foo')); } /** @covers ::url */ public function testUrlFunctionWithoutBaseUrl() { $this->app['config']->set(['hyde.url' => null]); + $this->assertSame('foo', url('foo')); + } + + /** @covers ::url */ + public function testUrlFunctionWithoutBaseUrlOrPath() + { + $this->app['config']->set(['hyde.url' => null]); + $this->expectException(\Hyde\Framework\Exceptions\BaseUrlNotSetException::class); + $this->assertNull(url()); + } + + /** @covers ::url */ + public function testUrlFunctionWithLocalhostBaseUrlButNoPath() + { + $this->app['config']->set(['hyde.url' => 'http://localhost']); $this->expectException(\Hyde\Framework\Exceptions\BaseUrlNotSetException::class); - $this->assertNull(url('foo')); + $this->assertNull(url()); } /** @covers ::url */ diff --git a/packages/framework/tests/Feature/MarkdownFileParserTest.php b/packages/framework/tests/Feature/MarkdownFileParserTest.php index 2586eb70dab..09e5b1dc06e 100644 --- a/packages/framework/tests/Feature/MarkdownFileParserTest.php +++ b/packages/framework/tests/Feature/MarkdownFileParserTest.php @@ -84,4 +84,19 @@ public function testParsedMarkdownPostContainsValidFrontMatter() $this->assertSame('Mr. Hyde', $post->matter('author')); $this->assertSame('blog', $post->matter('category')); } + + public function testCanParseMarkdownFileWithFrontMatterAndNoMarkdownBody() + { + file_put_contents(Hyde::path('_posts/test-post.md'), "---\nfoo: bar\n---"); + + $document = MarkdownFileParser::parse('_posts/test-post.md'); + + $this->assertInstanceOf(MarkdownDocument::class, $document); + $this->assertEquals('', $document->markdown); + $this->assertSame('', $document->markdown->body()); + + $this->assertEquals(FrontMatter::fromArray([ + 'foo' => 'bar', + ]), $document->matter); + } } diff --git a/packages/framework/tests/Feature/SitesWithoutBaseUrlAreHandledGracefullyTest.php b/packages/framework/tests/Feature/SitesWithoutBaseUrlAreHandledGracefullyTest.php new file mode 100644 index 00000000000..cd4e9373605 --- /dev/null +++ b/packages/framework/tests/Feature/SitesWithoutBaseUrlAreHandledGracefullyTest.php @@ -0,0 +1,77 @@ + null]); + + $this->assertStringNotContainsString('http://localhost', $this->getHtml($class)); + } + + /** @dataProvider pageClassProvider */ + public function testLocalhostLinksAreNotAddedToCompiledHtmlWhenBaseUrlIsNotSet(string $class) + { + config(['hyde.url' => '']); + + $this->assertStringNotContainsString('http://localhost', $this->getHtml($class)); + } + + /** @dataProvider pageClassProvider */ + public function testLocalhostLinksAreNotAddedToCompiledHtmlWhenBaseUrlIsSetToLocalhost(string $class) + { + config(['hyde.url' => 'http://localhost']); + + $this->assertStringNotContainsString('http://localhost', $this->getHtml($class)); + } + + /** @dataProvider pageClassProvider */ + public function testSiteUrlLinksAreAddedToCompiledHtmlWhenBaseUrlIsSetToValidUrl(string $class) + { + config(['hyde.url' => 'https://example.com']); + + $this->assertStringNotContainsString('http://localhost', $this->getHtml($class)); + } + + protected function getHtml(string $class): string + { + $page = new $class('foo'); + + Hyde::shareViewData($page); + + return $page->compile(); + } +} diff --git a/packages/framework/tests/Feature/Views/MetadataViewTest.php b/packages/framework/tests/Feature/Views/MetadataViewTest.php index 199759644d4..54ba018d2d4 100644 --- a/packages/framework/tests/Feature/Views/MetadataViewTest.php +++ b/packages/framework/tests/Feature/Views/MetadataViewTest.php @@ -25,7 +25,7 @@ protected function setUp(): void { parent::setUp(); - config(['hyde.url' => 'http://localhost']); + config(['hyde.url' => 'https://example.com']); config(['hyde.enable_cache_busting' => false]); } @@ -79,7 +79,7 @@ protected function getDefaultTags(): array '', '', '', - '', + '', '', '', ]; @@ -93,7 +93,7 @@ public function testMetadataTagsInEmptyBladePage() $assertions = $this->assertSee('test', array_merge($this->getDefaultTags(), [ 'HydePHP - Test', '', - '', + '', '', '', ])); @@ -109,7 +109,7 @@ public function testMetadataTagsInEmptyMarkdownPage() $assertions = $this->assertSee('test', array_merge($this->getDefaultTags(), [ 'HydePHP - Test', '', - '', + '', '', '', ])); @@ -125,7 +125,7 @@ public function testMetadataTagsInEmptyDocumentationPage() $assertions = $this->assertSee('docs/test', array_merge($this->getDefaultTags(), [ 'HydePHP - Test', '', - '', + '', '', '', ])); @@ -140,16 +140,16 @@ public function testMetadataTagsInEmptyMarkdownPost() $assertions = $this->assertSee('posts/test', array_merge($this->getDefaultTags(), [ 'HydePHP - Test', - '', + '', '', - '', + '', '', - '', + '', '', - '', + '', '', '', - '', + '', ])); $this->assertAllTagsWereCovered('posts/test', $assertions); @@ -177,25 +177,92 @@ public function testMetadataTagsInMarkdownPostWithFlatFrontMatter() $assertions = $this->assertSee('posts/test', array_merge($this->getDefaultTags(), [ 'HydePHP - My title', - '', + '', '', - '', + '', '', '', '', '', - '', + '', '', - '', + '', '', '', '', '', - '', + '', '', '', ])); $this->assertAllTagsWereCovered('posts/test', $assertions); } + + public function testCanonicalUrlTagsAreNotAddedWhenCanonicalUrlIsNotSet() + { + config(['hyde.url' => 'http://localhost']); + + $this->file('_posts/test.md', <<<'MARKDOWN' + --- + title: "My title" + description: "My description" + category: "My category" + date: "2022-01-01" + author: "Mr. Hyde" + image: image.jpg + --- + + ## Hello World + + Lorem Ipsum Dolor Amet. + MARKDOWN + ); + $this->build('_posts/test.md'); + + $assertions = $this->assertSee('posts/test', [ + '', + '', + '', + '', + '', + 'HydePHP - My title', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + + // '', + // '', + // '', + // '', + // '', + // '', + ]); + + $this->assertAllTagsWereCovered('posts/test', $assertions); + + $dontSee = [ + '= 8" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/immutable": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", - "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/sass": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.50.0.tgz", - "integrity": "sha512-cLsD6MEZ5URXHStxApajEh7gW189kkjn4Rc8DQweMyF+o5HF5nfEz8QYLMlPsTOD88DknatTmBWkOcw5/LnJLQ==", - "dev": true, - "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - } + "name": "hydefront", + "version": "3.3.4", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "hydefront", + "version": "3.3.4", + "license": "MIT", + "devDependencies": { + "sass": "1.50.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "dependencies": { - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "immutable": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", - "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "sass": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.50.0.tgz", - "integrity": "sha512-cLsD6MEZ5URXHStxApajEh7gW189kkjn4Rc8DQweMyF+o5HF5nfEz8QYLMlPsTOD88DknatTmBWkOcw5/LnJLQ==", - "dev": true, - "requires": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - } - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/immutable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", + "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/sass": { + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.50.0.tgz", + "integrity": "sha512-cLsD6MEZ5URXHStxApajEh7gW189kkjn4Rc8DQweMyF+o5HF5nfEz8QYLMlPsTOD88DknatTmBWkOcw5/LnJLQ==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + } + }, + "dependencies": { + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "requires": { + "fill-range": "^7.1.1" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "immutable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", + "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "sass": { + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.50.0.tgz", + "integrity": "sha512-cLsD6MEZ5URXHStxApajEh7gW189kkjn4Rc8DQweMyF+o5HF5nfEz8QYLMlPsTOD88DknatTmBWkOcw5/LnJLQ==", + "dev": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } } + } }