""" 从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 # 处理'): 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