mirror of
https://github.com/LiteyukiStudio/LiteyukiBot.git
synced 2024-11-11 05:17:24 +08:00
137 lines
3.7 KiB
Python
137 lines
3.7 KiB
Python
|
"""
|
||
|
从markdown提取插件/资源信息
|
||
|
"""
|
||
|
from typing import Any
|
||
|
|
||
|
from liteyuki_flow.typ import Nil, err, nil # type: ignore
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
# # xxx
|
||
|
class Header:
|
||
|
def __init__(self, level: int, content: str):
|
||
|
self.level = level
|
||
|
self.content = content
|
||
|
|
||
|
def __str__(self):
|
||
|
return f'Header({self.level}, {self.content})'
|
||
|
|
||
|
def __repr__(self):
|
||
|
return self.__str__()
|
||
|
|
||
|
|
||
|
# - xxx
|
||
|
class List:
|
||
|
def __init__(self, level: int, content: str):
|
||
|
self.level = level
|
||
|
self.content = content
|
||
|
|
||
|
def __str__(self):
|
||
|
return f'List({self.level}, {self.content})'
|
||
|
|
||
|
def __repr__(self):
|
||
|
return self.__str__()
|
||
|
|
||
|
|
||
|
class FrontMatter:
|
||
|
def __init__(self, content: dict[str, str]):
|
||
|
self.content = content
|
||
|
|
||
|
def __setitem__(self, key: str, value: str):
|
||
|
self.content[key] = value
|
||
|
|
||
|
def get(self, key, default=None) -> Any:
|
||
|
return self.content.get(key, default)
|
||
|
|
||
|
def __str__(self):
|
||
|
return "\n".join([f'{k}: {v}' for k, v in self.content.items()])
|
||
|
|
||
|
|
||
|
class MarkdownParser:
|
||
|
def __init__(self, content: str):
|
||
|
self.content = content
|
||
|
self.content_lines = content.split('\n')
|
||
|
self.front_matters: FrontMatter = FrontMatter({})
|
||
|
|
||
|
self._content_list: list[Any] = [self.front_matters]
|
||
|
|
||
|
self.lineno = 0
|
||
|
|
||
|
self._parsed = False
|
||
|
|
||
|
def parse_front_matters(self) -> err:
|
||
|
if self.content_lines[self.lineno].strip() != '---':
|
||
|
return ValueError('Invalid front matter')
|
||
|
while self.lineno < len(self.content_lines):
|
||
|
self._next_line()
|
||
|
line = self.content_lines[self.lineno]
|
||
|
if line.strip() == '---':
|
||
|
break
|
||
|
if line.strip().startswith('#'):
|
||
|
# fm注释
|
||
|
continue
|
||
|
try:
|
||
|
key, value = line.split(':', 1)
|
||
|
except ValueError:
|
||
|
return Exception(f'Invalid front matter: {line}')
|
||
|
self.front_matters[key.strip()] = value.strip()
|
||
|
return nil
|
||
|
|
||
|
def _parse_content(self) -> tuple[list[Any], err]:
|
||
|
content: list[Any] = []
|
||
|
while self.lineno < len(self.content_lines):
|
||
|
item, e = self._parse_line()
|
||
|
if e != nil:
|
||
|
return nil, e
|
||
|
content.append(item)
|
||
|
return content, nil
|
||
|
|
||
|
def _parse_line(self) -> tuple[Any, err]:
|
||
|
line = self.content_lines[self.lineno]
|
||
|
if line.startswith('#'):
|
||
|
# 计算start有几个#
|
||
|
start = 0
|
||
|
while line[start] == '#':
|
||
|
start += 1
|
||
|
return Header(start, line[start:].strip()), nil
|
||
|
elif line.startswith('-'):
|
||
|
start = 0
|
||
|
while line[start] == '-':
|
||
|
start += 1
|
||
|
return List(start, line[start:].strip()), nil
|
||
|
|
||
|
# 处理<!--注释 continue
|
||
|
elif line.strip().startswith('<!--'):
|
||
|
while not line.strip().endswith('-->'):
|
||
|
self._next_line()
|
||
|
line = self.content_lines[self.lineno]
|
||
|
return None, nil
|
||
|
# 处理[//]: # (注释) continue
|
||
|
elif line.strip().startswith('[//]: #'):
|
||
|
self._next_line()
|
||
|
return None, nil
|
||
|
|
||
|
self._next_line()
|
||
|
return nil, ValueError(f'Invalid line: {line}')
|
||
|
|
||
|
def _next_line(self):
|
||
|
self.lineno += 1
|
||
|
|
||
|
def parse(self) -> tuple[list[Any] | Nil, err]:
|
||
|
if self._parsed:
|
||
|
return self._content_list, nil
|
||
|
|
||
|
e = self.parse_front_matters()
|
||
|
if e != nil:
|
||
|
return nil, e
|
||
|
|
||
|
ls, e = self._parse_content()
|
||
|
if e != nil:
|
||
|
return nil, e
|
||
|
|
||
|
self._content_list.extend(ls)
|
||
|
self._parsed = True
|
||
|
|
||
|
return self._content_list, nil
|