ReMe/reme2/memory/schema/parser.py
huangsen 8465f6d06e ```
docs(protocol): add typed edge link protocol documentation

Add comprehensive documentation for the link protocol supporting
typed edges in body text. This includes specification for three
legal inline forms (bare wikilink, line-level Dataview,
inline-bracketed Dataview), predicate syntax rules, and the
machine-managed Relations section convention for organizing
discovered edges.

fix(memory): update path reference from vault_root to working_dir

Change the memory_create operation's path anchoring from
vault_root to working_dir to maintain consistency with the
current working directory configuration.

refactor(components): remove edge_extractor module and simplify parsing

Remove the edge_extractor component module entirely and
inline edge extraction logic directly into LinkedFileParser
using parse_wikilinks utility. This simplifies the architecture
by eliminating the separate edge extraction component and
delegating edge discovery to the maintainer's enrichment operations.

feat(parser): update parse method signature and simplify edge extraction

Modify LinkedFileParser to return (FileNode, list[FileChunk])
tuple instead of ParsedFile, remove dependency on BaseEdgeExtractor,
and implement direct wikilink parsing from body text only.
```
2026-05-11 19:45:53 +08:00

39 lines
1.5 KiB
Python

"""Tolerant parser — never raises, always returns (memory_or_None, errors).
Used by:
- Maintainer.lint : surfaces schema violations on existing files
- any read path : turn raw frontmatter into a typed view when possible
For *write* paths (`sync`, Ingestor) call `MemoryFileNode.model_validate`
directly so validation errors propagate as exceptions and stop the write.
"""
from __future__ import annotations
from pydantic import ValidationError
from .memory import MemoryFileNode
def parse_frontmatter(raw: dict) -> tuple[MemoryFileNode | None, list[str]]:
"""Tolerant parse. Returns (parsed, errors).
Success → (MemoryFileNode(...), [])
Failure → (None, ["loc: msg", ...])
Migration is automatic via MemoryFileNode's `model_validator(mode='before')`,
so frontmatter that only carries the legacy `category` field still
parses successfully.
"""
if not isinstance(raw, dict):
return None, [f"frontmatter must be a dict, got {type(raw).__name__}"]
try:
return MemoryFileNode.model_validate(raw), []
except ValidationError as e:
msgs: list[str] = []
for err in e.errors(include_context=False, include_url=False):
loc = ".".join(str(x) for x in err.get("loc", ()))
msgs.append(f"{loc}: {err.get('msg', '')}".strip(": "))
return None, msgs
except Exception as e: # noqa: BLE001 — defensive: never raise from a tolerant parser
return None, [f"{type(e).__name__}: {e}"]