Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.vscode
.phel-repl-history
.phpunit.result.cache

/content/documentation/api.md
/public
Expand Down
155 changes: 5 additions & 150 deletions build/api-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,146 +2,11 @@

declare(strict_types=1);

use Gacela\Framework\Gacela;
use Phel\Lang\Collections\Map\PersistentMapInterface;
use Phel\Lang\Keyword;
use Phel\Lang\TypeFactory;
use Phel\Run\RunFacade;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\ConsoleOutput;

require __DIR__ . '/../vendor/autoload.php';

/**
* @return array<string,PersistentMapInterface>
*/
function normalizeDataFromPhel(): array
{
$normalizedData = [];
foreach ($GLOBALS['__phel'] as $ns => $functions) {
$normalizedNs = str_replace('phel\\', '', $ns);
$moduleName = $normalizedNs === 'core' ? '' : $normalizedNs . '/';
foreach ($functions as $fnName => $fn) {
$fullFnName = $moduleName . $fnName;

$normalizedData[$fullFnName] = $GLOBALS['__phel_meta'][$ns][$fnName]
?? TypeFactory::getInstance()->emptyPersistentMap();
}
}
ksort($normalizedData);

return $normalizedData;
}

/**
* @param array<string,PersistentMapInterface> $normalizedData
*
* @return array<string,array{fnName:string,doc:string}>
*/
function groupNormalizedData(array $normalizedData): array
{
$result = [];
foreach ($normalizedData as $fnName => $meta) {
$isPrivate = $meta[Keyword::create('private')] ?? false;
if ($isPrivate) {
continue;
}

$groupKey = preg_replace(
'/[^a-zA-Z0-9\-]+/',
'',
str_replace('/', '-', $fnName)
);

$doc = $meta[Keyword::create('doc')] ?? '';
$pattern = '#(```phel\n(?<fnSignature>.*)\n```\n)?(?<desc>.*)#';
preg_match($pattern, $doc, $matches);

$result[$groupKey][] = [
'fnName' => $fnName,
'doc' => $meta[Keyword::create('doc')] ?? '',
'fnSignature' => $matches['fnSignature'] ?? '',
'desc' => $matches['desc'] ?? '',
];
}

foreach ($result as $values) {
usort($values, static fn(array $a, array $b) => $a['fnName'] <=> $b['fnName']);
}

return $result;
}

/**
* @param array<string,array{fnName:string,doc:string}> $groupNormalizedData
*/
function renderMdPage(array $groupNormalizedData): void
{
echo "+++\n";
echo "title = \"API\"\n";
echo "weight = 110\n";
echo "template = \"page-api.html\"\n";
echo "+++\n\n";

foreach ($groupNormalizedData as $values) {
foreach ($values as ['fnName' => $fnName, 'doc' => $doc]) {
echo "## `$fnName`\n\n";
echo $doc;
echo "\n\n";
}
}
}

/**
* @param array<string,array{fnName:string,doc:string}> $groupNormalizedData
*
* @return array<string,array{fnName:string,doc:string,anchor:string}>
*/
function generateSearchIndex(array $groupNormalizedData): array
{
$searchIndex = [];
/**
* Zola ignores the especial chars, and uses instead a number. This variable keep track
* of the appearances and uses an autoincrement number to follow the proper link.
*
* For example, consider the two functions: `table` and `table?`
* They belong to the same group `table`, and their anchor will be such as:
* table -> table
* table? -> table-1
*/
$groupFnNameAppearances = [];

foreach ($groupNormalizedData as $groupKey => $values) {
$groupFnNameAppearances[$groupKey] = 0;

foreach ($values as ['fnName' => $fnName, 'fnSignature' => $fnSignature, 'desc' => $desc]) {
$specialEndingChars = ['/', '=', '*', '?', '+', '>', '<', '-'];

if ($groupFnNameAppearances[$groupKey] === 0) {
$anchor = $groupKey;
$groupFnNameAppearances[$groupKey]++;
} else {
$fnName2 = str_replace($specialEndingChars, '', $fnName);
$anchor = $fnName2 . '-' . $groupFnNameAppearances[$groupKey]++;
}

$searchIndex[] = [
'fnName' => $fnName,
'fnSignature' => $fnSignature,
'desc' => $desc,
'anchor' => $anchor,
];
}
}

return $searchIndex;
}
use Gacela\Framework\Gacela;
use PhelDocBuild\FileGenerator\Facade;

/**
* ============================================
* ================== MAIN ====================
* ============================================
*/
Gacela::bootstrap(__DIR__, [
'config' => [
'type' => 'php',
Expand All @@ -150,16 +15,6 @@ function generateSearchIndex(array $groupNormalizedData): array
],
]);

(new RunFacade())
->getRunCommand()
->run(new ArrayInput(['path' => __DIR__ . '/src/doc.phel']), new ConsoleOutput());

$normalizedData = normalizeDataFromPhel();
$groupNormalizedData = groupNormalizedData($normalizedData);
renderMdPage($groupNormalizedData);
$searchIndex = generateSearchIndex($groupNormalizedData);

file_put_contents(
__DIR__ . '/../static/api_search.js',
"window.searchIndexApi = " . \json_encode($searchIndex)
);
$fileGeneratorFacade = new Facade();
$fileGeneratorFacade->generateMdPage();
$fileGeneratorFacade->generateApiSearch();
22 changes: 22 additions & 0 deletions build/src/FileGenerator/DependencyProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace PhelDocBuild\FileGenerator;

use Gacela\Framework\AbstractDependencyProvider;
use Gacela\Framework\Container\Container;
use Phel\Run\RunFacade;

/**
* @method Factory getFactory()
*/
final class DependencyProvider extends AbstractDependencyProvider
{
public const FACADE_PHEL_RUN = 'FACADE_PHEL_RUN';

public function provideModuleDependencies(Container $container): void
{
$container->set(self::FACADE_PHEL_RUN, fn() => new RunFacade());
}
}
51 changes: 51 additions & 0 deletions build/src/FileGenerator/Domain/ApiSearchGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

namespace PhelDocBuild\FileGenerator\Domain;

final class ApiSearchGenerator
{
/**
* @return array<string,array{fnName:string,doc:string,anchor:string}>
*/
public function generateSearchIndex(array $groupNormalizedData): array
{
$searchIndex = [];
/**
* Zola ignores the especial chars, and uses instead a number. This variable keep track
* of the appearances and uses an autoincrement number to follow the proper link.
*
* For example, consider the two functions: `table` and `table?`
* They belong to the same group `table`, and their anchor will be such as:
* table -> table
* table? -> table-1
*/
$groupFnNameAppearances = [];

foreach ($groupNormalizedData as $groupKey => $values) {
$groupFnNameAppearances[$groupKey] = 0;

foreach ($values as ['fnName' => $fnName, 'fnSignature' => $fnSignature, 'desc' => $desc]) {
$specialEndingChars = ['/', '=', '*', '?', '+', '>', '<', '-'];

if ($groupFnNameAppearances[$groupKey] === 0) {
$anchor = $groupKey;
$groupFnNameAppearances[$groupKey]++;
} else {
$fnName2 = str_replace($specialEndingChars, '', $fnName);
$anchor = $fnName2 . '-' . $groupFnNameAppearances[$groupKey]++;
}

$searchIndex[] = [
'fnName' => $fnName,
'fnSignature' => $fnSignature,
'desc' => $desc,
'anchor' => $anchor,
];
}
}

return $searchIndex;
}
}
32 changes: 32 additions & 0 deletions build/src/FileGenerator/Domain/MdPageRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace PhelDocBuild\FileGenerator\Domain;

final class MdPageRenderer
{
private OutputInterface $output;

public function __construct(OutputInterface $output)
{
$this->output = $output;
}

public function renderMdPage(array $groupNormalizedData): void
{
$this->output->writeln("+++");
$this->output->writeln("title = \"API\"");
$this->output->writeln("weight = 110");
$this->output->writeln("template = \"page-api.html\"");
$this->output->writeln("+++\n");

foreach ($groupNormalizedData as $values) {
foreach ($values as ['fnName' => $fnName, 'doc' => $doc]) {
$this->output->writeln("## `$fnName`\n");
$this->output->write($doc);
$this->output->writeln("\n");
}
}
}
}
12 changes: 12 additions & 0 deletions build/src/FileGenerator/Domain/OutputInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace PhelDocBuild\FileGenerator\Domain;

interface OutputInterface
{
public function write(string $line): void;

public function writeln(string $line): void;
}
15 changes: 15 additions & 0 deletions build/src/FileGenerator/Domain/PhelFnLoaderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace PhelDocBuild\FileGenerator\Domain;

use Phel\Lang\Collections\Map\PersistentMapInterface;

interface PhelFnLoaderInterface
{
/**
* @return array<string,PersistentMapInterface>
*/
public function getNormalizedPhelFunctions(): array;
}
56 changes: 56 additions & 0 deletions build/src/FileGenerator/Domain/PhelFnNormalizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

namespace PhelDocBuild\FileGenerator\Domain;

use Phel\Lang\Keyword;

final class PhelFnNormalizer
{
private PhelFnLoaderInterface $phelFnLoader;

public function __construct(PhelFnLoaderInterface $phelFnLoader)
{
$this->phelFnLoader = $phelFnLoader;
}

/**
* @return array<string,array{fnName:string,doc:string}>
*/
public function getNormalizedGroupedPhelFns(): array
{
$normalizedData = $this->phelFnLoader->getNormalizedPhelFunctions();

$result = [];
foreach ($normalizedData as $fnName => $meta) {
$isPrivate = $meta[Keyword::create('private')] ?? false;
if ($isPrivate) {
continue;
}

$groupKey = preg_replace(
'/[^a-zA-Z0-9\-]+/',
'',
str_replace('/', '-', $fnName)
);

$doc = $meta[Keyword::create('doc')] ?? '';
$pattern = '#(```phel\n(?<fnSignature>.*)\n```\n)?(?<desc>.*)#s';
preg_match($pattern, $doc, $matches);

$result[$groupKey][] = [
'fnName' => $fnName,
'doc' => $meta[Keyword::create('doc')] ?? '',
'fnSignature' => $matches['fnSignature'] ?? '',
'desc' => $matches['desc'] ?? '',
];
}

foreach ($result as $values) {
usort($values, static fn(array $a, array $b) => $a['fnName'] <=> $b['fnName']);
}

return $result;
}
}
27 changes: 27 additions & 0 deletions build/src/FileGenerator/Facade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace PhelDocBuild\FileGenerator;

use Gacela\Framework\AbstractFacade;

/**
* @method Factory getFactory()
*/
final class Facade extends AbstractFacade
{
public function generateMdPage(): void
{
$this->getFactory()
->createDocFileGenerator()
->renderMdPage();
}

public function generateApiSearch(): void
{
$this->getFactory()
->createDocFileGenerator()
->generateApiSearch();
}
}
Loading