Skip to content

Commit

Permalink
Merge pull request #5 from 8fold/working
Browse files Browse the repository at this point in the history
Next minor
  • Loading branch information
joshbruce authored Oct 27, 2021
2 parents ae5b82a + fef49e4 commit 9bcc2e4
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 55 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,23 @@ One of my favorite principles from The Manifesto for Agile Software Development

## Minimal dependencies

There's a double-edged sword here.

On the one hand, leveraging libraries, packages, and frameworks created and maintained by others increases the amount of work I didn't have to do. However, it also increases risk and potentially limits the upgrade path of the code I *did* write.

For example:

As of October 28th, 2021, I'm listed as a maintainer of [Marked](https://github.com/markedjs/marked). This happened because a library I wanted to use, used Marked. Not only that, but it always used the latest version of Marked. A denial of service vulnerability was discovered and Marked had fallen into disrepair and it didn't seem like the maintainer of the library I directly wanated to use wanted to switch to the something different. After a little back-and-forth figuring out how to do it (first time "taking over" a project) and [a bit of a ruckus](https://github.com/markedjs/marked/issues/1522) in the community, a small group formed to become the core team and to be stewards of the codebase for a community-led project. The core also serves to increase the developer experience.

Marked fixed the vulnerabilities and the community and library have been pushing forward ever since.

Right now some of the sites I maintain use [Laravel](https://laravel.com), which is a wonderful framework. With that said, at present I maintain a library that helps facilitate the flat-file system used by the sites. That library depends on the [FlySystem](https://flysystem.thephpleague.com/v2/docs/) from the PHP League. My library is mainly a proxy into FlySystem and they release version 2 of that codebase. I updated my library to use version 2. Laravel also depends on FlySystem. Unfortunately, Laravel won't be upgrading until version 9 of Laravel. Laravel 9 was scheduled to be released in November of 2021. Much of the Laravel codebase leverages [Symfony components](https://symfony.com). Symfony releases after Laravel, which the major version of Laravel could not take advantage of the latest Symfony components; so, Laravel changed its release to [January](https://laravel-news.com/laravel-9) instead of September (?? could be wrong on what it used to be). This means I couldn't use the latest version of my library until January 2022; or, I could do what I ended up doing which was to support both version 1 and 2 of FlySystem.

I plan to remove the dependency on Laravel and FlySystem for all the sites I maintain unless explicitly asked. As most of the sites I maintain no longer require databases or direct authentication and even one of the maintainers of FlySystem said it creates more overhead than it's worth when only working in local files, I think we're good.

I was experimenting with a lot of other approaches for decoupling and wrapping over the last few years. I've run into a few issues with this and versioning. This version collision and the performance degredations it caused has led me to flag many of these other libraries for deprecation and abandonment. As this writing, we have 5 required libraries. Generally speaking they have no common dependencies and I maintain two of them.

This frees me up a great deal to move about the cabin as I see fit.

## History

Expand Down
33 changes: 21 additions & 12 deletions src/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,6 @@ public function content(): Content

public function response(): Response|ResponseFile
{
if ($this->requestMethod() === 'post') {
// used for navigation only
// no CSRF token needed
$path = $_POST['change-page-select'];

// could not figure out a proper response code for this
// just redirecting without a response code
header('Location:' . $this->requestDomain() . $path);
exit;
}

$status = 200;
$headers = [
'Cache-Control' => ['max-age=600']
Expand All @@ -59,6 +48,12 @@ public function response(): Response|ResponseFile
$content = $this->content()
->for(path: $this->localFilePathWithoutRoot());
if ($content->notFound()) {
// MANUAL: Our tests don't run in a browser environemtn; therefore,
// don't believe it's possible to write an automated test for
// this given current setup.
// don't like that this path doesn't return early.
// TODO: refactor this
// - believe a defalt page template would resolve the issue
$content = $this->content()->for(path: '/.errors/404.md');

$status = 404;
Expand All @@ -80,14 +75,23 @@ public function response(): Response|ResponseFile
headers: $headers,
file: $content->filePath()
);

} elseif ($this->isRedirecting()) {
return Response::create(
status: 301,
headers: [
'Location' => $this->requestDomain() .
$this->content()->redirectPath()
]
);
}

$headers['Content-Type'] = $content->mimeType();

$headElements = Favicons::create();
$headElements[] = HtmlElement::link()
->props('rel stylesheet', 'href /css/main.css');
$headElements[] = HtmlElement::script()->props('src /js/menu.js');
// $headElements[] = HtmlElement::script()->props('src /js/menu.js');

$body = HtmlDocument::create($content->title())
->head(...$headElements)
Expand All @@ -110,6 +114,11 @@ private function isRequestingFile(): bool
return strpos($this->requestUri(), '.') > 0;
}

private function isRedirecting(): bool
{
return strlen($this->content()->redirectPath()) > 0;
}

private function environment(): Environment
{
return $this->environment;
Expand Down
16 changes: 15 additions & 1 deletion src/Content.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@ public function title(): string
return '';
}

public function redirectPath(): string
{
$fm = $this->frontMatter();
if (
array_key_exists('redirect', $fm) and
$redirect = $fm['redirect'] and
is_string($redirect)
) {
return $redirect;
}
return '';
}

public function html(): string
{
return $this->markdownConverter()->convert($this->markdown());
Expand Down Expand Up @@ -191,7 +204,8 @@ private function markdownConverter(): Markdown
if (! isset($this->markdownConverter)) {
$this->markdownConverter = Markdown::create()
->minified()
->smartPunctuation();
->smartPunctuation()
->tables();
}
return $this->markdownConverter;
}
Expand Down
91 changes: 52 additions & 39 deletions src/PageComponents/Navigation.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,55 +18,68 @@ public static function create(Content $content): Navigation

public function __construct(private Content $content)
{
$this->content = clone $content;
}

private function content(): Content
{
return $this->content;
}

private function listItem(string $for): HtmlElement
{
return HtmlElement::li(
$this->anchor(for: $for)
);
}

private function anchor(string $for): HtmlElement
{
list($href, $text) = explode(' ', $for, 2);
return HtmlElement::a($text)->props('href ' . $href);
}

/**
* @return array<string|array<string>>
*/
private function navigation(): array
{
$nav = $this->content()->for(path: '/.navigation/main.md')
->frontMatter();
$nav = $nav['navigation'];
if (is_array($nav)) {
return $nav;
}
return [];
}

public function build(): string
{
$li = [];
$nav = $this->navigation();
foreach ($nav as $item) {
if (is_string($item)) {
$li[] = $this->listItem(for: $item);

} elseif (is_array($item)) {
$l = '';
$s = [];
for ($i = 0; $i < count($item); $i++) {
if ($i === 0) {
$l = $this->anchor($item[$i]);

} else {
$s[] = $this->listItem($item[$i]);

}
}

$li[] = HtmlElement::li($l, HtmlElement::ul(...$s));
}
}
return HtmlElement::nav(
HtmlElement::form(
HtmlElement::div(
HtmlElement::label('navigation: ')->props(
'id change-page-select-label',
'for change-page-select'
),
HtmlElement::select(
HtmlElement::option('home')->props(
'value /',
'selected selected'
),
HtmlElement::optgroup(
HtmlElement::option('Overview')
->props('value /finances'),
HtmlElement::option('Investment policy')
->props('value /finances/investment-policy'),
HtmlElement::option('Paycheck to paycheck')
->props('value /finances/building-wealth-paycheck-to-paycheck')
)->props('label Finances'),
HtmlElement::optgroup(
HtmlElement::option('Overview')
->props('value /design-your-life'),
HtmlElement::option('Motivators')
->props('value /design-your-life/motivators')
)->props('label Design your life'),
HtmlElement::optgroup(
HtmlElement::option('Overview')
->props('value /software-development'),
HtmlElement::option('Why donʼt you use')
->props('value /software-development/why-dont-you-use')
)->props('label Software development')
)->props(
'id change-page-select',
'name change-page-select'
)
)->props('is form-control'),
HtmlElement::button('Go!')
)->props('action /', 'method post'),
)->props('id main-nav-form');
HtmlElement::ul(...$li)
);
}

public function __toString(): string
Expand Down
6 changes: 3 additions & 3 deletions tests/AppTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
$body
)->toBe(<<<html
<!doctype html>
<html lang="en"><head><title>sub-folder | Josh Bruce's personal site</title><meta charset="utf-8"><link type="image/x-icon" rel="icon" href="/assets/favicons/favicon.ico"></link><link rel="apple-touch-icon" href="/assets/favicons/apple-touch-icon.png" sizes="180x180"></link><link rel="image/png" href="/assets/favicons/favicon-32x32.png" sizes="32x32"></link><link rel="image/png" href="/assets/favicons/favicon-16x16.png" sizes="16x16"></link><link rel="stylesheet" href="/css/main.css"></link><script src="/js/menu.js"></script></head><body><nav id="main-nav-form"><form action="/" method="post"><div is="form-control"><label id="change-page-select-label" for="change-page-select">navigation: </label><select id="change-page-select" name="change-page-select"><option value="/" selected>home</option><optgroup label="Finances"><option value="/finances">Overview</option><option value="/finances/investment-policy">Investment policy</option><option value="/finances/building-wealth-paycheck-to-paycheck">Paycheck to paycheck</option></optgroup><optgroup label="Design your life"><option value="/design-your-life">Overview</option><option value="/design-your-life/motivators">Motivators</option></optgroup><optgroup label="Software development"><option value="/software-development">Overview</option><option value="/software-development/why-dont-you-use">Why donʼt you use</option></optgroup></select></div><button>Go!</button></form></nav><h1>A sub-folder content</h1><p>This content was successfully found.</p></body></html>
<html lang="en"><head><title>sub-folder | Josh Bruce's personal site</title><meta charset="utf-8"><link type="image/x-icon" rel="icon" href="/assets/favicons/favicon.ico"></link><link rel="apple-touch-icon" href="/assets/favicons/apple-touch-icon.png" sizes="180x180"></link><link rel="image/png" href="/assets/favicons/favicon-32x32.png" sizes="32x32"></link><link rel="image/png" href="/assets/favicons/favicon-16x16.png" sizes="16x16"></link><link rel="stylesheet" href="/css/main.css"></link></head><body><nav><ul><li><a href="/">home</a></li><li><a href="/finances">Finances</a><ul><li><a href="/finances/investment-policy">Investment policy</a></li><li><a href="/finances/building-wealth-paycheck-to-paycheck">Paycheck to paycheck</a></li></ul></li><li><a href="/design-your-life">Design your life</a><ul><li><a href="/design-your-life/motivators">Motivators</a></li></ul></li><li><a href="/software-development">Software development</a><ul><li><a href="/software-development/why-dont-you-use">Why don't you use</a></li></ul></li></ul></nav><h1>A sub-folder content</h1><p>This content was successfully found.</p></body></html>
html
);
});
Expand All @@ -39,7 +39,7 @@
$body
)->toBe(<<<html
<!doctype html>
<html lang="en"><head><title>Josh Bruce's personal site</title><meta charset="utf-8"><link type="image/x-icon" rel="icon" href="/assets/favicons/favicon.ico"></link><link rel="apple-touch-icon" href="/assets/favicons/apple-touch-icon.png" sizes="180x180"></link><link rel="image/png" href="/assets/favicons/favicon-32x32.png" sizes="32x32"></link><link rel="image/png" href="/assets/favicons/favicon-16x16.png" sizes="16x16"></link><link rel="stylesheet" href="/css/main.css"></link><script src="/js/menu.js"></script></head><body><nav id="main-nav-form"><form action="/" method="post"><div is="form-control"><label id="change-page-select-label" for="change-page-select">navigation: </label><select id="change-page-select" name="change-page-select"><option value="/" selected>home</option><optgroup label="Finances"><option value="/finances">Overview</option><option value="/finances/investment-policy">Investment policy</option><option value="/finances/building-wealth-paycheck-to-paycheck">Paycheck to paycheck</option></optgroup><optgroup label="Design your life"><option value="/design-your-life">Overview</option><option value="/design-your-life/motivators">Motivators</option></optgroup><optgroup label="Software development"><option value="/software-development">Overview</option><option value="/software-development/why-dont-you-use">Why donʼt you use</option></optgroup></select></div><button>Go!</button></form></nav><h1>The domain of Josh Bruce</h1><p>This content was successfully found.</p></body></html>
<html lang="en"><head><title>Josh Bruce's personal site</title><meta charset="utf-8"><link type="image/x-icon" rel="icon" href="/assets/favicons/favicon.ico"></link><link rel="apple-touch-icon" href="/assets/favicons/apple-touch-icon.png" sizes="180x180"></link><link rel="image/png" href="/assets/favicons/favicon-32x32.png" sizes="32x32"></link><link rel="image/png" href="/assets/favicons/favicon-16x16.png" sizes="16x16"></link><link rel="stylesheet" href="/css/main.css"></link></head><body><nav><ul><li><a href="/">home</a></li><li><a href="/finances">Finances</a><ul><li><a href="/finances/investment-policy">Investment policy</a></li><li><a href="/finances/building-wealth-paycheck-to-paycheck">Paycheck to paycheck</a></li></ul></li><li><a href="/design-your-life">Design your life</a><ul><li><a href="/design-your-life/motivators">Motivators</a></li></ul></li><li><a href="/software-development">Software development</a><ul><li><a href="/software-development/why-dont-you-use">Why don't you use</a></li></ul></li></ul></nav><h1>The domain of Josh Bruce</h1><p>This content was successfully found.</p></body></html>
html
);

Expand All @@ -58,7 +58,7 @@
$body
)->toBe(<<<html
<!doctype html>
<html lang="en"><head><title>Not found</title><meta charset="utf-8"><link type="image/x-icon" rel="icon" href="/assets/favicons/favicon.ico"></link><link rel="apple-touch-icon" href="/assets/favicons/apple-touch-icon.png" sizes="180x180"></link><link rel="image/png" href="/assets/favicons/favicon-32x32.png" sizes="32x32"></link><link rel="image/png" href="/assets/favicons/favicon-16x16.png" sizes="16x16"></link><link rel="stylesheet" href="/css/main.css"></link><script src="/js/menu.js"></script></head><body><nav id="main-nav-form"><form action="/" method="post"><div is="form-control"><label id="change-page-select-label" for="change-page-select">navigation: </label><select id="change-page-select" name="change-page-select"><option value="/" selected>home</option><optgroup label="Finances"><option value="/finances">Overview</option><option value="/finances/investment-policy">Investment policy</option><option value="/finances/building-wealth-paycheck-to-paycheck">Paycheck to paycheck</option></optgroup><optgroup label="Design your life"><option value="/design-your-life">Overview</option><option value="/design-your-life/motivators">Motivators</option></optgroup><optgroup label="Software development"><option value="/software-development">Overview</option><option value="/software-development/why-dont-you-use">Why donʼt you use</option></optgroup></select></div><button>Go!</button></form></nav><h1>404: Not found</h1><p>We still haven’t found what you’re looking for.</p></body></html>
<html lang="en"><head><title>Not found</title><meta charset="utf-8"><link type="image/x-icon" rel="icon" href="/assets/favicons/favicon.ico"></link><link rel="apple-touch-icon" href="/assets/favicons/apple-touch-icon.png" sizes="180x180"></link><link rel="image/png" href="/assets/favicons/favicon-32x32.png" sizes="32x32"></link><link rel="image/png" href="/assets/favicons/favicon-16x16.png" sizes="16x16"></link><link rel="stylesheet" href="/css/main.css"></link></head><body><nav><ul><li><a href="/">home</a></li><li><a href="/finances">Finances</a><ul><li><a href="/finances/investment-policy">Investment policy</a></li><li><a href="/finances/building-wealth-paycheck-to-paycheck">Paycheck to paycheck</a></li></ul></li><li><a href="/design-your-life">Design your life</a><ul><li><a href="/design-your-life/motivators">Motivators</a></li></ul></li><li><a href="/software-development">Software development</a><ul><li><a href="/software-development/why-dont-you-use">Why don't you use</a></li></ul></li></ul></nav><h1>404: Not found</h1><p>We still haven’t found what you’re looking for.</p></body></html>
html
);
});
Expand Down
15 changes: 15 additions & 0 deletions tests/test-content/.navigation/main.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
navigation: [
/ home, [
/finances Finances,
/finances/investment-policy Investment policy,
/finances/building-wealth-paycheck-to-paycheck Paycheck to paycheck
], [
/design-your-life Design your life,
/design-your-life/motivators Motivators
], [
/software-development Software development,
/software-development/why-dont-you-use Why don't you use
]
]
---

0 comments on commit 9bcc2e4

Please sign in to comment.