added source maps

This commit is contained in:
2026-05-15 18:58:03 -05:00
parent ac745dd4a6
commit e11d9007ec
2 changed files with 30 additions and 19 deletions

View File

@@ -1,15 +1,13 @@
from __future__ import annotations from __future__ import annotations
import runpy
import sys import sys
import tempfile
from pathlib import Path from pathlib import Path
import click import click
from . import __version__ from . import __version__
from .errors import activate from .errors import activate
from .transpiler import transpile_file from .transpiler import transpile_file, run_transpiled
@click.group() @click.group()
@@ -26,15 +24,13 @@ def main():
def run(file: Path, lang: str | None, keep: bool): def run(file: Path, lang: str | None, keep: bool):
"""Transpile and run a foreign-language Python file.""" """Transpile and run a foreign-language Python file."""
if lang: if lang:
# Inject shebang override so transpiler picks it up
source = file.read_text(encoding="utf-8") source = file.read_text(encoding="utf-8")
if not source.startswith("# foreignthon:"): if not source.startswith("# foreignthon:"):
source = f"# foreignthon: {lang}\n" + source source = f"# foreignthon: {lang}\n" + source
file.write_text(source, encoding="utf-8") file.write_text(source, encoding="utf-8")
transpiled = transpile_file(file) transpiled = transpile_file(file)
# Detect lang for error hook
detected_lang = lang or _lang_from_file(file) detected_lang = lang or _lang_from_file(file)
activate(detected_lang) activate(detected_lang)
@@ -43,17 +39,7 @@ def run(file: Path, lang: str | None, keep: bool):
out_path.write_text(transpiled, encoding="utf-8") out_path.write_text(transpiled, encoding="utf-8")
click.echo(f"Compiled: {out_path}") click.echo(f"Compiled: {out_path}")
# Write to a temp file and run it — runpy keeps __file__ correct run_transpiled(file, transpiled)
with tempfile.NamedTemporaryFile(
suffix=".py", mode="w", encoding="utf-8", delete=False
) as tmp:
tmp.write(transpiled)
tmp_path = tmp.name
try:
runpy.run_path(tmp_path, run_name="__main__")
finally:
Path(tmp_path).unlink(missing_ok=True)
@main.command() @main.command()

View File

@@ -52,7 +52,7 @@ def transpile(source: str, lang_code: str) -> str:
def transpile_file(path: Path) -> str: def transpile_file(path: Path) -> str:
""" """
Detect language from file extension (.es.py es), Detect language from file extension (.es.py -> es),
read the file, and return transpiled Python source. read the file, and return transpiled Python source.
""" """
lang_code = _detect_lang(path) lang_code = _detect_lang(path)
@@ -64,8 +64,33 @@ def transpile_file(path: Path) -> str:
return transpile(source, lang_code) return transpile(source, lang_code)
def run_transpiled(original_path: Path, transpiled: str) -> None:
"""
Execute transpiled source while making tracebacks point
to the original .es.py file, not a temp file.
"""
import linecache
filename = str(original_path.resolve())
# Register original source lines so traceback displays them correctly
original_lines = original_path.read_text(encoding="utf-8").splitlines(keepends=True)
linecache.cache[filename] = (
len(original_lines),
None,
original_lines,
filename,
)
# Compile with original filename — this is what sets it in the traceback
code = compile(transpiled, filename, "exec")
glob = {"__file__": filename, "__name__": "__main__"}
exec(code, glob)
def _detect_lang(path: Path) -> str: def _detect_lang(path: Path) -> str:
"""Extract lang code from extension, e.g. script.es.py es.""" """Extract lang code from extension, e.g. script.es.py -> es."""
suffixes = path.suffixes # e.g. ['.es', '.py'] suffixes = path.suffixes # e.g. ['.es', '.py']
if len(suffixes) >= 2 and suffixes[-1] == ".py": if len(suffixes) >= 2 and suffixes[-1] == ".py":
return suffixes[-2].lstrip(".") return suffixes[-2].lstrip(".")