Skip to content

Commit

Permalink
- output path can be remapped
Browse files Browse the repository at this point in the history
  • Loading branch information
horuskol committed Aug 14, 2023
1 parent e5c41d2 commit 7ba95d7
Show file tree
Hide file tree
Showing 11 changed files with 329 additions and 206 deletions.
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,50 @@ You can specify files for inclusion or exclusion in the `caxton.json` configurat
}
```

### Output mapping

By default, the output URLs will follow the same structure as the folder paths within your public and content directories.

If you like to organise your files differently, then you can use the `output.maps` configuration to map the URLs accordingly.

For example:

```
+ content
|-+ blog
|-+ 2018
|-+ 10-22-it-begins
|- index.blade.md
|- pretty-picture.png
```

To output this document as `/blog/2018-10-22/it-begins`, you can use this in your `caxton.json` file:

```
{
"output": {
"maps": [
{
"path": "/blog/*/*/",
"url": "/blog/{{ date }}/{{ slug }}/"
}
]
}
}
```

`date` and `slug` are read from the front matter of the template file.

```
---
date: 2018-10-22
slug: it-begins
---
```

Caxton will then store an internal map for all output for paths starting with `/blog/2018/10-22-it-begins/` and rewrite them as `/blog/2018-10-22/it-begins`.
This means that any resources related to the blog post (such as the `png` file) will be written to the same output URL.

### Sitemap

Caxton will generate a `sitemap.xml` and add it to the root of your output directory.
Expand Down
14 changes: 8 additions & 6 deletions caxton
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require_once 'vendor/autoload.php';
use SavvyWombat\Caxton\Config;
use SavvyWombat\Caxton\ConfigFile;
use SavvyWombat\Caxton\Middleware;
use SavvyWombat\Caxton\FileList;
use SavvyWombat\Caxton\Site;

$config = [];
$config['verbose'] = in_array('-v', $argv) || in_array('--verbose', $argv);
Expand All @@ -29,6 +29,8 @@ $config['paths']['public'] = $config['paths']['base'] . ($_ENV['PUBLIC_DIR'] ??
$config['paths']['cache'] = $config['paths']['base'] . '/build' . ($_ENV['CACHE_DIR'] ?? '/cache');
$config['paths']['output'] = $config['paths']['base'] . '/build' . ($_ENV['OUTPUT_DIR'] ?? '/' . $config['environment']);

$config['blade']['extensions'] = '.blade.(md|php)';

$config = Config::instance(
$config,
ConfigFile::read($config['paths']['base'] . '/caxton.json', []),
Expand Down Expand Up @@ -57,14 +59,14 @@ if (file_exists(Config::instance()->get('paths.output'))) {
}

$middlewares = [
Middleware\CopyPublicFiles::class,
Middleware\ScanFiles::class,
Middleware\CopyStaticFiles::class,
Middleware\BuildContentFiles::class,
Middleware\GenerateSiteMap::class,
];

$action = fn (FileList $files): FileList => $files;
$action = fn (Site $site): Site => $site;
foreach (array_reverse($middlewares) as $m) {
$middleware = new $m();
$action = fn (FileList $files): FileList => $middleware->run($files, $action);
$action = fn (Site $site): Site => $middleware->run($site, $action);
}
$action(new FileList());
$action(Site::instance());
50 changes: 0 additions & 50 deletions src/File.php

This file was deleted.

45 changes: 0 additions & 45 deletions src/FileList.php

This file was deleted.

97 changes: 43 additions & 54 deletions src/Middleware/BuildContentFiles.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,72 +4,61 @@

use SavvyWombat\Caxton\Blade\ViewFactory;
use SavvyWombat\Caxton\Config;
use SavvyWombat\Caxton\ContentFileFilter;
use SavvyWombat\Caxton\File;
use SavvyWombat\Caxton\FileList;
use SavvyWombat\Caxton\Markdown\MarkdownConverter;
use SavvyWombat\Caxton\Site;
use SavvyWombat\Caxton\SourceFile;

class BuildContentFiles implements Middleware
{
public function run(FileList $files, callable $next): FileList
{
$contentFiles = new \RecursiveIteratorIterator(
new ContentFileFilter(
new \RecursiveDirectoryIterator(
Config::instance()->get('paths.content'),
\FilesystemIterator::SKIP_DOTS
)
),
\RecursiveIteratorIterator::SELF_FIRST
);
protected $markdown = null;

foreach ($contentFiles as $contentFile) {
$subpath = str_replace(
Config::instance()->get('paths.content'),
'',
$contentFile->getRealPath()
);
public function __construct() {
$this->markdown = new MarkdownConverter();
}

if (!file_exists(Config::instance()->get('paths.output') . dirname($subpath))) {
// directories need the 'execute/search' bit
// permissions are subject to the umask value in the running environment
mkdir(Config::instance()->get('paths.output') . dirname($subpath), 0775, true);
public function run(Site $site, callable $next): Site
{
$extensions = str_replace('.', '\.', Config::instance()->get('blade.extensions'));

foreach ($site->sourceFiles() as $file) {
if (preg_match('#(.*)' . $extensions . '$#', $file->sourcePath())) {
$this->buildFromTemplate($file, $file->outputPath());
}
}

$matches = [];
if (preg_match('#(.*)\.blade\.(md|php)$#', $subpath, $matches)) {
$markdown = new MarkdownConverter();
$frontMatter = $markdown->extractFrontMatter(
file_get_contents(Config::instance()->get('paths.content') . $subpath)
);
return $next($site);
}

$data = yaml_parse($frontMatter) ?? [];
protected function buildFromTemplate(SourceFile $sourceFile, string $outputPath)
{
$extensions = str_replace('.', '\.', Config::instance()->get('blade.extensions'));

$subpath = $matches[1];
$output = ViewFactory::instance()->make(
str_replace('/', '.', $subpath),
[
'page' => null,
'url' => Config::instance()->get('base_url') . (str_ends_with($subpath, '/index') ? substr($subpath, 0, -6) : $subpath),
...$data,
]
)->render();
$templateName = str_replace(
'/',
'.',
str_replace(
Config::instance()->get('paths.content') . '/',
'',
preg_replace(
'#' . $extensions . '$#',
'',
$sourceFile->sourcePath(),
),

file_put_contents(Config::instance()->get('paths.output') . $subpath . '.html', $output);
$files->add(new File(
filename: $subpath . '.html',
url: (str_ends_with($subpath, '/index')) ? substr($subpath, 0, -6) : $subpath,
source: $contentFile->getRealPath(),
));
} else if (!is_dir($contentFile->getRealPath())) {
copy($contentFile->getRealPath(), Config::instance()->get('paths.output') . $subpath);
$files->add(new File(
filename: $subpath,
source: $contentFile->getRealPath(),
));
}
)
);

$output = ViewFactory::instance()->make(
str_replace('/', '.', $templateName),
$sourceFile->data()
)->render();

if (!file_exists(Config::instance()->get('paths.output') . dirname($outputPath))) {
// directories need the 'execute/search' bit
// permissions are subject to the umask value in the running environment
mkdir(Config::instance()->get('paths.output') . dirname($outputPath), 0775, true);
}

return $next($files);
file_put_contents(Config::instance()->get('paths.output') . $outputPath, $output);
}
}
49 changes: 0 additions & 49 deletions src/Middleware/CopyPublicFiles.php

This file was deleted.

27 changes: 27 additions & 0 deletions src/Middleware/CopyStaticFiles.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace SavvyWombat\Caxton\Middleware;

use SavvyWombat\Caxton\Config;
use SavvyWombat\Caxton\Site;

class CopyStaticFiles implements Middleware
{
public function run(Site $site, callable $next): Site
{
$extensions = str_replace('.', '\.', Config::instance()->get('blade.extensions'));

foreach ($site->sourceFiles() as $file) {
if (! preg_match('#(.*)' . $extensions . '$#', $file->sourcePath())) {
$outputPath = $file->outputPath();

if (! file_exists(dirname(Config::instance()->get('paths.output') . '/' . $outputPath))) {
mkdir(dirname(Config::instance()->get('paths.output') . '/' . $outputPath), 0775, true);
}
copy($file->sourcePath(), Config::instance()->get('paths.output') . '/' . $outputPath);
}
}

return $next($site);
}
}
4 changes: 2 additions & 2 deletions src/Middleware/Middleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace SavvyWombat\Caxton\Middleware;

use SavvyWombat\Caxton\FileList;
use SavvyWombat\Caxton\Site;

interface Middleware
{
public function run(FileList $files, callable $next): FileList;
public function run(Site $site, callable $next): Site;
}
Loading

0 comments on commit 7ba95d7

Please sign in to comment.