scripts/generate-package-readmes.py
Rama main · réplica de lectura del repositorio original.
"""Generate packages/<pkg>/README.md from templates/package-purposes.yml.
Run from repo root:
python scripts/generate-package-readmes.py
Idempotent — overwrites existing READMEs.
"""
from __future__ import annotations
import posixpath
import sys
from pathlib import Path
try:
import yaml # type: ignore[import-untyped]
except ImportError:
sys.stderr.write(
"PyYAML missing. Install with `pip install pyyaml` (or `uv add pyyaml`).\n"
)
sys.exit(1)
REPO_ROOT = Path(__file__).resolve().parent.parent
PURPOSES_FILE = REPO_ROOT / "templates" / "package-purposes.yml"
PACKAGES_DIR = REPO_ROOT / "packages"
def link_from_package(pkg_path: str, target: str) -> str:
"""Return a repository-relative link target from a package README."""
return posixpath.relpath(target, posixpath.join("packages", pkg_path))
def test_command(pkg_path: str, language: str) -> str:
"""Return the package's test command block.
Every command is emitted on its own line rather than joined with ``&&``:
Windows PowerShell 5.1 has no ``&&`` operator, so a chained recipe is not
runnable on a supported platform.
Args:
pkg_path: Package path relative to ``packages/``, e.g. ``core/ticks``.
language: Language label from ``templates/package-purposes.yml``.
Returns:
A newline-separated command block, safe to paste into any shell.
"""
if pkg_path == "apps/site":
return (
"pnpm --filter @flinttrade/site typecheck\n"
"pnpm --filter @flinttrade/site test\n"
"pnpm --filter @flinttrade/site build"
)
if pkg_path == "apps/terminal":
return (
"pnpm --filter @flinttrade/terminal test:base\n"
"pnpm --filter @flinttrade/terminal build"
)
if pkg_path == "core/design-system":
return "cd packages/core/design-system\nnpx tsc --noEmit"
if language in {"Python", "Python + Numba"}:
return f"python -m pytest packages/{pkg_path}/tests/ -v --import-mode=importlib"
if language == "Rust + PyO3":
return f"cd packages/{pkg_path}\ncargo test"
return f"# See packages/{pkg_path}/ for test instructions"
def install_command(pkg_path: str, language: str) -> str:
"""Return the package's install command block.
One command per line, for the same cross-platform reason as
:func:`test_command`.
Args:
pkg_path: Package path relative to ``packages/``, e.g. ``core/ticks``.
language: Language label from ``templates/package-purposes.yml``.
Returns:
A newline-separated command block, safe to paste into any shell.
"""
if language.startswith("TypeScript"):
return "pnpm install"
if language == "Rust + PyO3":
return f"uv pip install -e packages/{pkg_path}\ncd packages/{pkg_path}\ncargo test"
return f"uv pip install -e packages/{pkg_path}"
def render_readme(pkg_name: str, info: dict[str, object]) -> str:
purpose = info["purpose"]
language = info["language"]
entry_points = info["entry_points"]
assert isinstance(purpose, str)
assert isinstance(language, str)
assert isinstance(entry_points, list)
# Human-friendly package title.
package_leaf = pkg_name.split("/")[-1]
title = package_leaf.replace("-", " ").title().replace("Ai", "AI")
if package_leaf == "ticks":
title = "Tick Engine"
if pkg_name == "services/backtest":
title = "Backtest Engine"
if pkg_name == "apps/site":
title = "@flinttrade/site"
if pkg_name == "apps/terminal":
title = "Terminal"
if pkg_name == "core/design-system":
title = "@flinttrade/design-system"
test_cmd_rendered = test_command(pkg_name, language)
install_cmd_rendered = install_command(pkg_name, language)
developer_guide = link_from_package(pkg_name, "docs/DEVELOPER_GUIDE.md")
architecture = link_from_package(pkg_name, "docs/ARCHITECTURE.md")
user_guide = link_from_package(pkg_name, "docs/USER_GUIDE.md")
contributing = link_from_package(pkg_name, "contributing.md")
license_path = link_from_package(pkg_name, "LICENSE")
entry_lines = "\n".join(f"- `{ep}`" for ep in entry_points)
return f"""# {title}
> {purpose}
**Part of [FlintTrade](https://github.com/navaneeshnagarajan/FlintTrade)** — the open-source self-hosted trading software monorepo built with Python, React, TypeScript, and Rust.
**Language:** {language}
## Public surface
{entry_lines}
(See the source for the full surface.)
## Install
This package is part of the FlintTrade monorepo. Install via the workspace from the repo root:
```bash
{install_cmd_rendered}
```
If you only want to use the package in isolation, the package's `pyproject.toml`,
`Cargo.toml`, or `package.json` lists its dependencies. The supported path is the
root workspace.
## Tests
```bash
{test_cmd_rendered}
```
Run one command per line. They work unchanged in bash, zsh and Windows
PowerShell — do not join them with `&&`, which Windows PowerShell 5.1 does not
support.
For the full test matrix, see the contributor guide at [docs/DEVELOPER_GUIDE.md]({developer_guide}).
## How this fits in
This package's role in the wider FlintTrade architecture is documented in
[docs/ARCHITECTURE.md]({architecture}). For end-user features it powers, see
[docs/USER_GUIDE.md]({user_guide}).
## Contributing
Contributions welcome. Please read [`contributing.md`]({contributing}) at the repo root before opening a pull request.
## License
AGPL-3.0 — same as the parent repository. See [`LICENSE`]({license_path}) for the full text.
"""
def main() -> int:
if not PURPOSES_FILE.exists():
sys.stderr.write(f"Purposes file not found: {PURPOSES_FILE}\n")
return 1
with PURPOSES_FILE.open("r", encoding="utf-8") as f:
data = yaml.safe_load(f)
written = 0
skipped = 0
for pkg_name, info in data.items():
pkg_dir = PACKAGES_DIR / Path(pkg_name)
if not pkg_dir.exists():
sys.stderr.write(f"Package directory missing: {pkg_dir}\n")
skipped += 1
continue
readme_path = pkg_dir / "README.md"
readme_path.write_text(render_readme(pkg_name, info), encoding="utf-8")
written += 1
print(f"Generated {written} package READMEs.")
if skipped:
print(f"Skipped {skipped} (missing package directories).")
return 0
if __name__ == "__main__":
sys.exit(main())