Skip to content

Conversation

@tovrstra
Copy link
Contributor

@tovrstra tovrstra commented Oct 28, 2025

This branch shows how to use a feature proposed in the following issue and PR of Typst:

To do:

  • If/when the above PR is merged, update Typst version in docs, comments and continuous integration
  • Deprecate the tile_pdf feature and add an equivalent example with Typst

@sourcery-ai
Copy link

sourcery-ai bot commented Oct 28, 2025

Reviewer's Guide

This PR updates the compile_typst command to use Typst’s JSON-format dependency files (including both inputs and outputs), adds support for HTML outputs, and bumps required Typst version to 0.14, with corresponding test and documentation updates.

Entity relationship diagram for Typst dependency file format change

erDiagram
    DEP_FILE_JSON {
        string[] inputs
        string[] outputs
    }
    COMPILE_TYPST {
        uses DEP_FILE_JSON
    }
    COMPILE_TYPST ||--|| DEP_FILE_JSON : reads
Loading

Class diagram for updated Typst compilation logic

classDiagram
    class compile_typst {
        +main(argv, work_thread)
        -args: Namespace
        -typargs: list
        -path_dep: Path
        +filter_dependencies(inp_paths)
        +amend(inp)
    }
    class WorkThread {
        +runsh(command)
    }
    compile_typst --> WorkThread : uses
    compile_typst : +support for .html output
    compile_typst : +uses JSON dep file (inputs, outputs)
    compile_typst : -removes legacy dep file parsing
    compile_typst : +parses depinfo["inputs"], depinfo["outputs"]
Loading

File-Level Changes

Change Details Files
Add support for HTML output in compile_typst
  • Allow .html suffix in output validation
  • Append "--features=html" when HTML output is requested
  • Include ".html" in make_path_out allowed extensions
  • Add HTML example and integrate it into the test matrix
stepup/reprep/compile_typst.py
stepup/reprep/api.py
tests/test_examples.py
tests/examples/compile_typst_html/main.sh
tests/examples/compile_typst_html/plan.py
Migrate dependency file handling to JSON format
  • Rename dependency files from .dep to .dep.json in both keep-deps and temp paths
  • Replace --make-deps flag with --deps and --deps-format json
  • Parse dependency outputs by json.load to extract inputs and outputs
  • Remove manual splitting and error-based input discovery logic
stepup/reprep/compile_typst.py
stepup/reprep/api.py
tests/examples/compile_typst_dep/main.sh
tests/examples/compile_typst_dep_error/main.sh
tests/examples/compile_typst_svg_deps/main.sh
tests/examples/compile_typst_png_multi/main.sh
tests/examples/compile_typst_svg_multi/main.sh
tests/examples/compile_typst_relpath/main.sh
Bump and document Typst version requirement to 0.14
  • Update GitHub Actions to install Typst v0.14-rc2
  • Change API warning to require Typst 0.14
  • Note the compile_typst update in the changelog
  • Adjust documentation comments to reference Typst 0.14
.github/workflows/pytest.yaml
stepup/reprep/api.py
docs/changelog.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@deepsource-io
Copy link
Contributor

deepsource-io bot commented Oct 28, 2025

Here's the code health analysis summary for commits ee9636d..82d0b53. View details on DeepSource ↗.

Analysis Summary

AnalyzerStatusSummaryLink
DeepSource Shell LogoShell✅ Success
❗ 1 occurence introduced
View Check ↗
DeepSource Python LogoPython✅ Success
❗ 9 occurences introduced
🎯 1 occurence resolved
View Check ↗

💡 If you’re a repository administrator, you can configure the quality gates from the settings.

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • Consider using Path.with_suffix('.dep.json') instead of slicing off 4 characters for building the dep file path to avoid hard‐coding the extension length.
  • You’re parsing both inputs and outputs from the JSON deps file but only using inputs; make sure to handle or surface out_paths for multi-output use cases or remove the misleading comment.
  • The CI is currently pinned to the 0.14-rc2 release—either switch to the stable 0.14 release or add a runtime version check to guard against RC-only flags.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider using Path.with_suffix('.dep.json') instead of slicing off 4 characters for building the dep file path to avoid hard‐coding the extension length.
- You’re parsing both inputs and outputs from the JSON deps file but only using inputs; make sure to handle or surface out_paths for multi-output use cases or remove the misleading comment.
- The CI is currently pinned to the 0.14-rc2 release—either switch to the stable 0.14 release or add a runtime version check to guard against RC-only flags.

## Individual Comments

### Comment 1
<location> `stepup/reprep/compile_typst.py:99-100` </location>
<code_context>
-                out_paths.extend(shlex.split(dep_out))
-                inp_paths.extend(shlex.split(dep_inp))
+                depinfo = json.load(fh)
+            inp_paths = depinfo["inputs"]
+            out_paths = depinfo["outputs"]
         else:
             print(f"Dependency file not created: {path_dep}.", file=sys.stderr)
</code_context>

<issue_to_address>
**suggestion:** No error handling for malformed dependency JSON.

Currently, if the dependency file is not valid JSON or lacks 'inputs' or 'outputs', an exception will be raised. Please add error handling to manage these cases and provide informative error messages.
</issue_to_address>

### Comment 2
<location> `stepup/reprep/api.py:349` </location>
<code_context>
     if not path_typ.endswith(".typ"):
         raise ValueError(f"The input of the typst command must end with .typ, got {path_typ}.")
-    path_out = make_path_out(path_typ, dest, ".pdf", [".svg", ".png"])
+    path_out = make_path_out(path_typ, dest, ".pdf", [".svg", ".png", ".html"])

     stem = path_typ[:-4]
</code_context>

<issue_to_address>
**suggestion:** Consider centralizing supported output formats.

Duplicating the list increases the chance of inconsistencies and makes updates harder. Centralizing it will simplify future changes.

Suggested implementation:

```python
    path_out = make_path_out(path_typ, dest, ".pdf", SUPPORTED_TYPST_OUTPUT_FORMATS)

```

```python
SUPPORTED_TYPST_OUTPUT_FORMATS = [".svg", ".png", ".html"]

          (Referenced bitmaps are handled correctly.)
          These referenced SVG figures are not rendered, neither are they included in the dep file.
          See: https://github.com/typst/typst/issues/6858

    Parameters
    ----------

```
</issue_to_address>

### Comment 3
<location> `stepup/reprep/compile_typst.py:53` </location>
<code_context>
def main(argv: list[str] | None = None, work_thread: WorkThread | None = None):
    """Main program."""
    args = parse_args(argv)
    if work_thread is None:
        work_thread = WorkThread("stub")

    if not args.path_typ.endswith(".typ"):
        raise ValueError("The Typst source must have extension .typ")
    if not (args.path_out is None or args.path_out.suffix in (".pdf", ".png", ".svg", ".html")):
        raise ValueError("The Typst output must be a PDF, PNG, SVG, or HTML file.")

    # Get Typst executable and prepare some arguments that
    if args.typst is None:
        args.typst = getenv("REPREP_TYPST", "typst")

    # Prepare the command to run Typst
    typargs = [args.typst, "compile", args.path_typ]
    if args.path_out is not None:
        typargs.append(args.path_out)
    else:
        args.path_out = Path(args.path_typ[:-4] + ".pdf")
    if args.path_out.suffix == ".png":
        resolution = args.resolution
        if resolution is None:
            resolution = int(getenv("REPREP_TYPST_RESOLUTION", "144"))
        typargs.append(f"--ppi={resolution}")
    elif args.path_out.suffix == ".html":
        typargs.append("--features=html")
    for keyval in args.sysinp:
        typargs.append("--input")
        typargs.append(keyval)
    if len(args.typst_args) == 0:
        args.typst_args = shlex.split(getenv("REPREP_TYPST_ARGS", ""))
    typargs.extend(args.typst_args)

    with contextlib.ExitStack() as stack:
        if args.keep_deps:
            # Remove any existing make-deps output from a previous run.
            path_dep = Path(args.path_typ[:-4] + ".dep.json")
            path_dep.remove_p()
        else:
            # Use a temporary file for the make-deps output.
            path_dep = stack.enter_context(TempDir()) / "typst.dep.json"
        typargs.extend(["--deps", path_dep, "--deps-format", "json"])

        # Run typst compile
        returncode, stdout, stderr = work_thread.runsh(shlex.join(typargs))
        print(stdout)
        # Assume there is a single output file, which is the one specified.
        # This is not correct when there are multiple outputs, e.g. as with SVG and PNG outputs.
        # Get required input files from the dependency file.
        if path_dep.is_file():
            with open(path_dep) as fh:
                depinfo = json.load(fh)
            inp_paths = depinfo["inputs"]
            out_paths = depinfo["outputs"]
        else:
            print(f"Dependency file not created: {path_dep}.", file=sys.stderr)
            out_paths = []
            inp_paths = []

    sys.stderr.write(stderr)
    inp_paths = filter_dependencies(inp_paths)
    amend(inp=inp_paths)

    # Write inventory
    if args.inventory is not None:
        inventory_paths = sorted(inp_paths) + out_paths
        write_inventory(args.inventory, inventory_paths, do_amend=False)

    # If the output path contains placeholders `{p}`, `{0p}`, or `{t}`,
    # we need to amend the output.
    if any(p in args.path_out for p in ("{p}", "{0p}", "{t}")):
        amend(out=out_paths)

    if returncode != 0:
        # Only use sys.exit in cases of an error,
        # so other programs may call this function without exiting.
        sys.exit(returncode)

</code_context>

<issue_to_address>
**issue (code-quality):** We've found these issues:

- Simplify logical expression using De Morgan identities ([`de-morgan`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/de-morgan/))
- Use f-string instead of string concatenation [×2] ([`use-fstring-for-concatenation`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/use-fstring-for-concatenation/))
- Merge consecutive list appends into a single extend ([`merge-list-appends-into-extend`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/merge-list-appends-into-extend/))
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines 99 to 100
inp_paths = depinfo["inputs"]
out_paths = depinfo["outputs"]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: No error handling for malformed dependency JSON.

Currently, if the dependency file is not valid JSON or lacks 'inputs' or 'outputs', an exception will be raised. Please add error handling to manage these cases and provide informative error messages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant