Compare commits
2 Commits
e3e27708ef
...
6809268fb1
Author | SHA1 | Date | |
---|---|---|---|
6809268fb1 | |||
38da57caad |
56
run.php
56
run.php
@ -4,12 +4,56 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
require __DIR__ . '/vendor/autoload.php';
|
require __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
$parser = new LogseqGem\Parser;
|
$opts = getopt('o:', rest_index: $rest_index);
|
||||||
|
$rest = array_slice($argv, $rest_index);
|
||||||
|
|
||||||
$page = file_get_contents("/Users/annika/sync/BTSync/logseq/pages/Gemlog.md");
|
$gemlog_input_path = $rest[0] ?? null;
|
||||||
$page = file_get_contents("/Users/annika/sync/BTSync/logseq/pages/Publishing to the Gemlog with logseq.md");
|
$gemlog_output_path = $opts['o'] ?? null;
|
||||||
|
|
||||||
$document = $parser->parse($page);
|
if (is_null($gemlog_input_path) || !file_exists($gemlog_input_path)) {
|
||||||
foreach ($document->iterator() as $node) {
|
throw new \Exception('Please provide an input gemlog file listing some articles. Got: ' . $gemlog_input_path);
|
||||||
echo 'Current node: ' . get_class($node) . "\n";
|
}
|
||||||
|
|
||||||
|
if (is_null($gemlog_output_path) || !is_dir($gemlog_output_path)) {
|
||||||
|
throw new \Exception('Please provide a destination directory using -o');
|
||||||
|
}
|
||||||
|
|
||||||
|
$dir = dirname($gemlog_input_path);
|
||||||
|
|
||||||
|
$gemlog = new LogseqGem\GemlogParser;
|
||||||
|
$article = new LogseqGem\ArticleParser;
|
||||||
|
|
||||||
|
$gemlog->load($gemlog_input_path);
|
||||||
|
$titles = $gemlog->getTitles();
|
||||||
|
|
||||||
|
foreach ($titles as $title) {
|
||||||
|
$article_path = $dir . '/' . $title . '.md';
|
||||||
|
$article->load($article_path);
|
||||||
|
$gemtext = $article->convert();
|
||||||
|
|
||||||
|
if (!$article->isPublished() || empty($gemtext)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sanitize_title = strtolower($title);
|
||||||
|
$sanitize_title = str_replace(' ', '-', $sanitize_title);
|
||||||
|
$sanitize_title .= '.gmi';
|
||||||
|
|
||||||
|
$output_path = $gemlog_output_path . '/' . $sanitize_title;
|
||||||
|
|
||||||
|
echo "Writing to ", $sanitize_title, "...\n";
|
||||||
|
|
||||||
|
$date = strtotime($article->getProperties()['date'] ?? null);
|
||||||
|
if (empty($date)) {
|
||||||
|
throw new Exception('Article ' . $title . ' has no date property');
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = sprintf(
|
||||||
|
"# %s\n\n%s\n\n%s\n\n=> /gemlog.gmi gemlog\n=> / home\n",
|
||||||
|
$title,
|
||||||
|
date('j F Y', $date),
|
||||||
|
$gemtext
|
||||||
|
);
|
||||||
|
|
||||||
|
file_put_contents($output_path, $output);
|
||||||
}
|
}
|
||||||
|
@ -7,20 +7,42 @@ namespace LogseqGem;
|
|||||||
use League\CommonMark\Node\NodeWalker;
|
use League\CommonMark\Node\NodeWalker;
|
||||||
use League\CommonMark\Node\Inline\Text;
|
use League\CommonMark\Node\Inline\Text;
|
||||||
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
|
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
|
||||||
|
use League\CommonMark\Extension\CommonMark\Node\Block\ListBlock;
|
||||||
|
|
||||||
class ArticleParser extends Parser {
|
class ArticleParser extends Parser {
|
||||||
public function convert() {
|
private ?array $properties;
|
||||||
$gemtext = [];
|
|
||||||
|
|
||||||
$link = 0;
|
public function convert(): string {
|
||||||
|
$gemtext = [];
|
||||||
|
$this->properties = [];
|
||||||
|
|
||||||
|
$in_frontmatter = true;
|
||||||
|
|
||||||
$walker = $this->document->walker();
|
$walker = $this->document->walker();
|
||||||
while ($event = $walker->next()) {
|
while ($event = $walker->next()) {
|
||||||
$entering = $event->isEntering();
|
$entering = $event->isEntering();
|
||||||
$node = $event->getNode();
|
$node = $event->getNode();
|
||||||
|
|
||||||
|
if ($entering && $node instanceof ListBlock) {
|
||||||
|
$in_frontmatter = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if ($entering && $node instanceof Text) {
|
if ($entering && $node instanceof Text) {
|
||||||
$gemtext[] = $node->getLiteral();
|
$text = $node->getLiteral();
|
||||||
|
|
||||||
|
if ($in_frontmatter) {
|
||||||
|
if (preg_match('/^([A-Za-z-]+):: (.*)/', $text, $matches)) {
|
||||||
|
$this->properties[$matches[1]] = $matches[2];
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
$in_frontmatter = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$gemtext[] = $text;
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($entering && $node instanceof Link) {
|
if ($entering && $node instanceof Link) {
|
||||||
@ -30,9 +52,22 @@ class ArticleParser extends Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$gemtext[] = sprintf('=> %s %s', $node->getUrl(), $label->getLiteral());
|
$gemtext[] = sprintf('=> %s %s', $node->getUrl(), $label->getLiteral());
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return implode("\n\n", $gemtext);
|
return implode("\n\n", $gemtext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getProperties(): array {
|
||||||
|
if (is_null($this->properties)) {
|
||||||
|
throw new \Exception("Cannot get properties before converting a document");
|
||||||
|
}
|
||||||
|
return $this->properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isPublished(): bool {
|
||||||
|
return (($this->getProperties()['status'] ?? '') === 'published');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
98
tests/ArticleParserTest.php
Normal file
98
tests/ArticleParserTest.php
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LogseqGem\Tests;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use Exception;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use org\bovigo\vfs\vfsStream;
|
||||||
|
use org\bovigo\vfs\vfsStreamDirectory;
|
||||||
|
|
||||||
|
use LogseqGem\ArticleParser;
|
||||||
|
use RuntimeException;
|
||||||
|
use SebastianBergmann\RecursionContext\InvalidArgumentException as RecursionContextInvalidArgumentException;
|
||||||
|
use PHPUnit\Framework\ExpectationFailedException;
|
||||||
|
|
||||||
|
class ArticleParserTest extends TestCase {
|
||||||
|
private vfsStreamDirectory $root;
|
||||||
|
|
||||||
|
private ArticleParser $parser;
|
||||||
|
|
||||||
|
public function setUp(): void {
|
||||||
|
$this->parser = new ArticleParser;
|
||||||
|
$this->root = vfsStream::setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setArticleText(string $text) {
|
||||||
|
vfsStream::newFile('article.md')
|
||||||
|
->withContent($text)
|
||||||
|
->at($this->root);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConvertSimple() {
|
||||||
|
$this->setArticleText("- This is a test line.");
|
||||||
|
$this->parser->load(vfsStream::url('root/article.md'));
|
||||||
|
$this->assertSame('This is a test line.', $this->parser->convert());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConvertLink() {
|
||||||
|
$this->setArticleText("- [foo](bar)");
|
||||||
|
$this->parser->load(vfsStream::url('root/article.md'));
|
||||||
|
$this->assertSame('=> bar foo', $this->parser->convert());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMultiParagraph() {
|
||||||
|
$this->setArticleText("- Block 1\n- Block 2");
|
||||||
|
$this->parser->load(vfsStream::url('root/article.md'));
|
||||||
|
$this->assertSame("Block 1\n\nBlock 2", $this->parser->convert());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEmpty() {
|
||||||
|
$this->setArticleText("-");
|
||||||
|
$this->parser->load(vfsStream::url('root/article.md'));
|
||||||
|
$this->assertSame("", $this->parser->convert());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInterleavedParagraphsAndLinks() {
|
||||||
|
$this->setArticleText("- Block 1\n- [foo](bar)\n- Block 2");
|
||||||
|
$this->parser->load(vfsStream::url('root/article.md'));
|
||||||
|
$this->assertSame("Block 1\n\n=> bar foo\n\nBlock 2", $this->parser->convert());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSequentialLinks() {
|
||||||
|
$this->markTestSkipped('not yet implemented');
|
||||||
|
$this->setArticleText("\n- [foo](bar)\n- [bar](foo)");
|
||||||
|
$this->parser->load(vfsStream::url('root/article.md'));
|
||||||
|
$this->assertSame("=> bar foo\n=> foo bar", $this->parser->convert());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFrontmatter() {
|
||||||
|
$this->setArticleText("foo:: bar\nanother:: prop\n\n- first line");
|
||||||
|
$this->parser->load(vfsStream::url('root/article.md'));
|
||||||
|
$this->assertSame("first line", $this->parser->convert());
|
||||||
|
$this->assertSame(["foo" => "bar", "another" => "prop"], $this->parser->getProperties());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDraftIsNotPublished() {
|
||||||
|
$this->setArticleText("status:: draft\n\n- my article");
|
||||||
|
$this->parser->load(vfsStream::url('root/article.md'));
|
||||||
|
$this->parser->convert();
|
||||||
|
$this->assertFalse($this->parser->isPublished());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMissingStatusIsNotPublished() {
|
||||||
|
$this->setArticleText("status:: draft\n\n- my article");
|
||||||
|
$this->parser->load(vfsStream::url('root/article.md'));
|
||||||
|
$this->parser->convert();
|
||||||
|
$this->assertFalse($this->parser->isPublished());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPublished() {
|
||||||
|
$this->setArticleText("status:: published\n\n- my article");
|
||||||
|
$this->parser->load(vfsStream::url('root/article.md'));
|
||||||
|
$this->parser->convert();
|
||||||
|
$this->assertTrue($this->parser->isPublished());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user