mirror of
https://codeberg.org/vlw/vlw.se.git
synced 2025-09-14 05:13:46 +02:00
wip: 2024-11-28T17:44:40+0100 (1732812280)
This commit is contained in:
parent
ff7d4f5397
commit
4f3557a817
7 changed files with 278 additions and 16 deletions
|
@ -5,4 +5,7 @@ pass = ""
|
|||
|
||||
[databases]
|
||||
vlw = ""
|
||||
battlestation = ""
|
||||
battlestation = ""
|
||||
|
||||
[notes]
|
||||
md_file_dir = ""
|
20
api/composer.lock
generated
20
api/composer.lock
generated
|
@ -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"
|
||||
}
|
||||
|
|
46
api/endpoints/notes/GET.php
Normal file
46
api/endpoints/notes/GET.php
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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
12
public/notes/blog.php
Normal 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
0
public/notes/index.php
Normal file
209
src/helpers/Notes.php
Normal file
209
src/helpers/Notes.php
Normal 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 = "​";
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue