Spaces:
Sleeping
Sleeping
| """Parse-only validator. | |
| Calls Python's own ``compile()`` on each materialized file and reports any | |
| syntax / lexer errors. This is the cheapest gate; the agent receives this | |
| feedback as part of ``materialize_and_validate``. | |
| Heavier checks (import-resolution, ``mypy --strict``, behavioral tests) live | |
| elsewhere in :mod:`graphforge.validator` and :mod:`graphforge.behavioral` — | |
| intentionally separated so the agent can pay for verification incrementally. | |
| """ | |
| from __future__ import annotations | |
| from dataclasses import dataclass, field | |
| class ParseError: | |
| filename: str | |
| line: int | None | |
| column: int | None | |
| message: str | |
| class ValidationReport: | |
| parse_errors: list[ParseError] = field(default_factory=list) | |
| def ok(self) -> bool: | |
| return not self.parse_errors | |
| def to_dict(self) -> dict[str, object]: | |
| return { | |
| "ok": self.ok, | |
| "parse_errors": [ | |
| { | |
| "filename": e.filename, | |
| "line": e.line, | |
| "column": e.column, | |
| "message": e.message, | |
| } | |
| for e in self.parse_errors | |
| ], | |
| } | |
| def parse_check(files: dict[str, str]) -> list[ParseError]: | |
| """Compile each ``files[name]`` source. Return collected errors. | |
| An empty list means every file parsed cleanly. | |
| """ | |
| errors: list[ParseError] = [] | |
| for filename, source in files.items(): | |
| try: | |
| compile(source, filename, "exec") | |
| except SyntaxError as e: | |
| errors.append( | |
| ParseError( | |
| filename=filename, | |
| line=e.lineno, | |
| column=e.offset, | |
| message=e.msg, | |
| ) | |
| ) | |
| return errors | |
| def full_check(files: dict[str, str]) -> ValidationReport: | |
| """Run every validator gate that's currently implemented. | |
| Today: parse-only. ``mypy --strict`` and import-resolution are added in | |
| follow-up commits but the report shape stays the same. | |
| """ | |
| return ValidationReport(parse_errors=parse_check(files)) | |