wip: 2024-11-28T17:44:40+0100 (1732812280)

This commit is contained in:
Victor Westerlund 2024-11-28 22:03:52 +01:00
parent ff7d4f5397
commit 4f3557a817
7 changed files with 278 additions and 16 deletions

View file

@ -6,3 +6,6 @@ pass = ""
[databases]
vlw = ""
battlestation = ""
[notes]
md_file_dir = ""

20
api/composer.lock generated
View file

@ -8,17 +8,11 @@
"packages": [
{
"name": "reflect/plugin-rules",
"version": "1.5.0",
"version": "1.5.2",
"source": {
"type": "git",
"url": "https://github.com/VictorWesterlund/reflect-rules-plugin.git",
"reference": "9c837fd1944133edfed70a63ce8b32bf67f0d94b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/VictorWesterlund/reflect-rules-plugin/zipball/9c837fd1944133edfed70a63ce8b32bf67f0d94b",
"reference": "9c837fd1944133edfed70a63ce8b32bf67f0d94b",
"shasum": ""
"url": "https://codeberg.org/reflect/reflect-rules-plugin",
"reference": "aa7d969350f50d00d7dce01b948276946fcc0e81"
},
"type": "library",
"autoload": {
@ -37,11 +31,7 @@
}
],
"description": "Add request search paramter and request body constraints to an API built with Reflect",
"support": {
"issues": "https://github.com/VictorWesterlund/reflect-rules-plugin/issues",
"source": "https://github.com/VictorWesterlund/reflect-rules-plugin/tree/1.5.0"
},
"time": "2024-01-17T11:07:44+00:00"
"time": "2024-11-28T17:05:16+00:00"
},
{
"name": "victorwesterlund/xenum",
@ -121,5 +111,5 @@
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.0.0"
"plugin-api-version": "2.3.0"
}

View file

@ -0,0 +1,46 @@
<?php
use Reflect\Path;
use Reflect\Response;
use ReflectRules\Type;
use ReflectRules\Rules;
use ReflectRules\Ruleset;
const GET_PARAM_NOTE = "id";
class GET_Notes {
protected readonly Ruleset $ruleset;
public function __construct() {
$this->ruleset = new Ruleset(strict: true);
$this->ruleset->GET([
(new Rules(GET_PARAM_NOTE))
->required()
->type(Type::STRING)
->min(1)
]);
$this->ruleset->validate_or_exit();
}
private function get_path(): string {
$base_path = substr($_ENV["notes"]["md_file_dir"], -1, 1) === "/" ? $_ENV["notes"]["md_file_dir"] : $_ENV["notes"]["md_file_dir"] . "/";
return "{$base_path}{$_GET[GET_PARAM_NOTE]}.md";
}
public function exists(): bool {
return is_readable($this->get_path());
}
public function read(): string {
return file_get_contents($this->get_path());
}
public function main(): Response {
return $this->exists()
? new Response($this->read(), 200, "text/plain")
: new Response("Note not found", 404);
}
}

View file

@ -11,6 +11,8 @@
case MESSAGES = "/messages";
case NOTES = "/notes";
case WORK = "/work";
case WORK_TAGS = "/work/tags";
case WORK_ACTIONS = "/work/actions";

12
public/notes/blog.php Normal file
View file

@ -0,0 +1,12 @@
<?php
use VLW\Helpers\Notes\Notes;
require_once VV::root("src/helpers/Notes.php");
$note = new Notes("blog");
?>
<?php foreach ($note->lex() as $line): ?>
<?= $line ?>
<?php endforeach; ?>

0
public/notes/index.php Normal file
View file

209
src/helpers/Notes.php Normal file
View file

@ -0,0 +1,209 @@
<?php
namespace VLW\Helpers\Notes;
use Reflect\Response;
use \VV;
use \Generator;
use \SplObjectStorage;
use VLW\Client\API;
use VLW\API\Endpoints;
require_once VV::root("src/client/API.php");
require_once VV::root("api/src/Endpoints.php");
enum HTML: string {
public const EMPTY_LINE = "&ZeroWidthSpace;";
case NOOP = "";
case ANCHOR = "a";
case PARAGRAPH = "p";
case HEADING_1 = "h1";
case HEADING_2 = "h2";
case HEADING_3 = "h3";
case IMAGE = "img";
case CODE = "code";
case QUOTE = "quote";
case ITALIC = "italic";
case BOLD = "strong";
case UNORDERED_LIST = "li";
case THEMATIC_BREAK = "hr";
}
const LEX_TOKENS = [
"-" => HTML::NOOP,
"--" => HTML::NOOP,
"`" => HTML::CODE,
"**" => HTML::BOLD,
">" => HTML::QUOTE,
"*" => HTML::ITALIC,
"![" => HTML::ANCHOR,
"[" => HTML::ANCHOR,
"]" => HTML::ANCHOR,
"(" => HTML::ANCHOR,
")" => HTML::ANCHOR,
"#" => HTML::HEADING_1,
"##" => HTML::HEADING_2,
"###" => HTML::HEADING_3,
"- " => HTML::UNORDERED_LIST,
"---" => HTML::THEMATIC_BREAK
];
class Notes extends API {
private string $html;
private ?HTML $token;
private readonly SplObjectStorage $open;
private readonly Response $resp;
public function __construct(string $note_id) {
parent::__construct();
$this->open = new SplObjectStorage();
$this->resp = $this->call(Endpoints::NOTES->value)->params([
"id" => $note_id
])->get();
$this->init();
}
private function init(): object {
$this->html = "";
$this->token = null;
return $this->tokens();
}
private function push(string $text): self {
$this->html .= $text;
return $this;
}
private function open(HTML $tag): self {
$this->push("<{$tag->value}>");
$this->token = null;
$this->open[$tag] = true;
return $this;
}
private function close(HTML $tag): self {
unset($this->open[$tag]);
$this->token = null;
$this->push("</{$tag->value}>");
return $this;
}
private function tokens(): object {
return new class {
private array $lexed = [];
public function __construct() {}
public function push(string $token): void {
$this->lexed[] = $token;
}
// Return last lexed token by offset
public function offset(int $offset): ?string {
$len = count($this->lexed);
return $offset <= $len ? $this->lexed[$len - $offset] : null;
}
public function combine(int $offset): string {
$output = "";
for ($i = 1; $i <= $offset; $i++) {
if (!$this->offset($i)) {
continue;
}
$output .= $this->offset($i);
}
return $output;
}
};
}
public function line(): Generator|array {
if (!$this->resp->ok) {
return [];
}
foreach (explode(PHP_EOL, $this->resp->output()) as $line) {
yield $line;
}
}
public function lex(): Generator {
foreach ($this->line() as $line) {
$lexed = $this->init();
// Create
foreach (str_split($line) as $idx => $token) {
$lexed->push($token);
if ($this->token === HTML::NOOP) {
$this->push($token);
}
if (!array_key_exists($token, LEX_TOKENS)) {
// Open a new tag
if ($this->token) {
// Close an already open tag
if (isset($this->open[$this->token])) {
$this->close($this->token);
// Push current literal and continue with next char
$this->push($token);
continue;
}
$this->open($this->token);
}
// Open a paragraph if first char of line is not a token
if ($idx === 0) {
$this->open(HTML::PARAGRAPH);
}
// Push literal to output
$this->push($token);
continue;
}
$this->token = LEX_TOKENS[$token];
// Backtrack in lex history until we find the first literal
$offset = 1;
while (array_key_exists($lexed->offset($offset), LEX_TOKENS)) {
// Update current token if we're still matching a keyword
if (array_key_exists($lexed->combine($offset), LEX_TOKENS)) {
$this->token = LEX_TOKENS[$lexed->combine($offset)];
}
$offset++;
}
}
// Create a paragraph for empty lines
if (empty($this->html)) {
$this->open(HTML::PARAGRAPH)->push(HTML::EMPTY_LINE);
}
// Close all remaining tags
foreach ($this->open as $tag) {
$this->close($tag);
}
yield $this->html;
}
}
}