Full Code of loqusion/typix for AI

main f3dd958107de cached
104 files
120.5 KB
36.6k tokens
11 symbols
1 requests
Download .txt
Repository: loqusion/typix
Branch: main
Commit: f3dd958107de
Files: 104
Total size: 120.5 KB

Directory structure:
gitextract_u9nhbyq8/

├── .editorconfig
├── .envrc
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── 1-bug_report.md
│   │   ├── 2-feature_request.md
│   │   └── 3-typst_packages.md
│   └── workflows/
│       ├── pages.yml
│       ├── publish.yml
│       ├── test.yml
│       └── update-lockfile.yml
├── .gitignore
├── .markdownlint-cli2.jsonc
├── .markdownlint.json
├── .prettierignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── checks/
│   ├── .gitignore
│   ├── build-local.nix
│   ├── check-emojis.py
│   ├── clean/
│   │   ├── bad.c
│   │   ├── lib.typ
│   │   ├── metadata.toml
│   │   ├── sub/
│   │   │   ├── bad.py
│   │   │   ├── sub.typ
│   │   │   └── typst.toml
│   │   ├── typst.toml
│   │   └── works.bib
│   ├── clean-expected/
│   │   ├── lib.typ
│   │   ├── metadata.toml
│   │   ├── sub/
│   │   │   ├── sub.typ
│   │   │   └── typst.toml
│   │   ├── typst.toml
│   │   └── works.bib
│   ├── date/
│   │   └── main.typ
│   ├── default.nix
│   ├── emoji/
│   │   └── main.typ
│   ├── overlapping-virtual-paths/
│   │   └── main.typ
│   ├── simple/
│   │   └── main.typ
│   ├── simple-with-fonts/
│   │   └── main.typ
│   ├── simple-with-multiple-parameters/
│   │   └── main.typ
│   ├── simple-with-virtual-paths/
│   │   └── main.typ
│   ├── typst-packages/
│   │   └── main.typ
│   ├── virtual-paths.nix
│   └── watch.nix
├── docs/
│   ├── .gitignore
│   ├── SUMMARY.md
│   ├── api/
│   │   ├── derivations/
│   │   │   ├── build-typst-project-local.md
│   │   │   ├── build-typst-project.md
│   │   │   ├── common/
│   │   │   │   ├── emoji-font.md
│   │   │   │   ├── font-paths-example.md
│   │   │   │   ├── font-paths.md
│   │   │   │   ├── install-phase-command.md
│   │   │   │   ├── script-name.md
│   │   │   │   ├── src.md
│   │   │   │   ├── typst-compile-command.md
│   │   │   │   ├── typst-opts-example.md
│   │   │   │   ├── typst-opts.md
│   │   │   │   ├── typst-packages.md
│   │   │   │   ├── typst-project-output.md
│   │   │   │   ├── typst-project-source.md
│   │   │   │   ├── virtual-paths-example.md
│   │   │   │   └── virtual-paths.md
│   │   │   ├── dev-shell.md
│   │   │   ├── mk-typst-derivation.md
│   │   │   └── watch-typst-project.md
│   │   ├── derivations.md
│   │   ├── utilities/
│   │   │   └── clean-typst-source.md
│   │   └── utilities.md
│   ├── book.toml
│   ├── getting-started.md
│   └── recipes/
│       ├── adding-dependencies.md
│       ├── declaring-a-shell-environment.md
│       ├── specifying-sources.md
│       └── using-typst-packages.md
├── examples/
│   ├── .gitignore
│   ├── quick-start/
│   │   ├── .gitignore
│   │   ├── flake.nix
│   │   └── main.typ
│   ├── typst-packages/
│   │   ├── flake.nix
│   │   └── main.typ
│   └── typst-packages-unpublished/
│       ├── flake.nix
│       └── main.typ
├── flake.nix
├── lib/
│   ├── buildTypstProject.nix
│   ├── buildTypstProjectLocal.nix
│   ├── cleanTypstSource.nix
│   ├── coerceVirtualPathAttr.nix
│   ├── default.nix
│   ├── devShell.nix
│   ├── emojiFontPathFromString.nix
│   ├── fetchTypstPackages.nix
│   ├── inferTypstProjectOutput.nix
│   ├── linkVirtualPaths.nix
│   ├── mkTypstDerivation.nix
│   ├── setupHooks/
│   │   ├── copyVirtualPaths.nix
│   │   ├── copyVirtualPathsHook.sh
│   │   ├── unsetSourceDateEpoch.nix
│   │   ├── unsetSourceDateEpochHook.sh
│   │   └── unsetSourceDateEpochScript.sh
│   ├── typstOptsFromArgs.nix
│   └── watchTypstProject.nix
├── pkgs.nix
└── release.nix

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
env_of_line = lf
indent_style = space
trim_trailing_whitespace = true
insert_final_newline = true

[*.nix]
indent_size = 2


================================================
FILE: .envrc
================================================
use flake . --impure


================================================
FILE: .github/FUNDING.yml
================================================
ko_fi: loqusion


================================================
FILE: .github/ISSUE_TEMPLATE/1-bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Versions**
- OS:

**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/2-feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .github/ISSUE_TEMPLATE/3-typst_packages.md
================================================
---
name: Typst packages
about: For issues related to Typst packages
title: "[Typst packages]: "
labels: typst packages
assignees: ''

---




================================================
FILE: .github/workflows/pages.yml
================================================
name: Build and deploy documentation

on:
  push:
    branches:
      - main
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: pages
  cancel-in-progress: false

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: cachix/install-nix-action@v31
      - uses: cachix/cachix-action@v16
        with:
          name: typst-nix
          authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
      - name: Setup Pages
        id: pages
        uses: actions/configure-pages@v5
      - name: Build with mdBook
        run: |
          nix build --accept-flake-config .#docs --out-link result --print-build-logs
          cp -RLT result book
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v4
        with:
          path: ./book

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4


================================================
FILE: .github/workflows/publish.yml
================================================
name: Publish flake to FlakeHub

on:
  release:
    types: [published]
  workflow_dispatch:
    inputs:
      tag:
        description: "The existing tag to publish to FlakeHub"
        type: "string"
        required: true

jobs:
  publish-flakehub:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Get git tag
        id: git-tag
        run: |
          if [ -z "$TAG" ]; then
            echo "::error::Could not determine git tag"
            exit 1
          fi
          echo "tag=$TAG" >>"$GITHUB_OUTPUT"
        env:
          TAG: ${{ inputs.tag || github.ref_name }}
      - uses: actions/checkout@v4
        with:
          ref: ${{ format('refs/tags/{0}', steps.git-tag.outputs.tag) }}
      - uses: cachix/install-nix-action@v31
      - uses: DeterminateSystems/flakehub-push@v6
        with:
          visibility: public
          name: loqusion/typix
          tag: ${{ steps.git-tag.outputs.tag }}


================================================
FILE: .github/workflows/test.yml
================================================
name: Run flake checks
on:
  pull_request:
    types: [opened, reopened, synchronize]
  push:
    branches:
      - main
      - "ci*"

permissions:
  contents: read

jobs:
  checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: cachix/install-nix-action@v31
      - name: flake check
        run: nix flake check

  examples:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: cachix/install-nix-action@v31
      - name: check examples
        run: |
          set -euo pipefail
          for f in $(find ./examples -maxdepth 1 -mindepth 1 -type d | sort -u); do
            nix flake check --no-write-lock-file "$f"
          done


================================================
FILE: .github/workflows/update-lockfile.yml
================================================
name: Update flake lockfile
on:
  workflow_dispatch:
  schedule:
    - cron: "39 8 7,22 * *"

permissions:
  contents: read

jobs:
  update:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: cachix/install-nix-action@v31
      - uses: cachix/cachix-action@v16
        with:
          name: typst-nix
          authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
      - name: Update flake.lock
        id: update
        uses: DeterminateSystems/update-flake-lock@v27
        with:
          token: ${{ secrets.GH_TOKEN_FOR_UPDATES }}
          commit-msg: "chore: update flake.lock"
          pr-title: "chore: update flake.lock"
          pr-body: |
            Automated changes by the [update-flake-lock](https://github.com/DeterminateSystems/update-flake-lock) GitHub Action.

            ```
            {{ env.GIT_COMMIT_MESSAGE }}
            ```

          pr-labels: |
            dependencies
            automated
          nix-options: --accept-flake-config
      - name: Merge PR
        run: |
          gh pr merge --squash --delete-branch --auto "$PR_NUMBER"
        env:
          GH_TOKEN: ${{ secrets.GH_TOKEN_FOR_UPDATES }}
          PR_NUMBER: ${{ steps.update.outputs.pull-request-number }}


================================================
FILE: .gitignore
================================================
/result
.direnv/
*.pdf


================================================
FILE: .markdownlint-cli2.jsonc
================================================
{
  "ignores": ["CHANGELOG.md"],
}


================================================
FILE: .markdownlint.json
================================================
{
  "no-inline-html": false
}


================================================
FILE: .prettierignore
================================================
docs/book
docs/theme
flake.lock


================================================
FILE: CHANGELOG.md
================================================
# [0.3.2] (June 27, 2025)

### Added

- `typstOpts` repeatable flags ([#59])

[#59]: https://github.com/loqusion/typix/pull/59

# [0.3.1] (April 02, 2025)

### Added

- Typst packages support (unstable) ([#51])
- `with-typst-packages-unpublished` template ([#51])

### Changed

- Use `unstable_typstPackages` in `with-typst-packages` template ([#51])

[#51]: https://github.com/loqusion/typix/pull/51

# [0.3.0] (January 27, 2025)

### Added

- **BREAKING CHANGE:** Include an emoji font in all derivations by default ([#44])
- Add `emojiFont` attribute in all derivations ([#44])

[#44]: https://github.com/loqusion/typix/pull/44

# [0.2.0] (January 3, 2025)

### Fixed

- **BREAKING CHANGE:** Unset `SOURCE_DATE_EPOCH` environment variable in all derivations
  ([#40])

[#40]: https://github.com/loqusion/typix/pull/40

# [0.1.7] (December 29, 2024)

### Changed

- Improve build times ([#38])

[#38]: https://github.com/loqusion/typix/pull/38

# [0.1.6] (October 30, 2024)

### Fixed

- Include `metadata.toml` in `cleanTypstSource` ([#29])

[#29]: https://github.com/loqusion/typix/pull/29

# [0.1.5] (July 13, 2024)

### Fixed

- Include `typst.toml` in `cleanTypstSource` ([#20])

[#20]: https://github.com/loqusion/typix/pull/20

# [0.1.4] (May 2, 2024)

### Fixed

- Handle `src` attribute correctly in `virtualPaths` ([#12])

[#12]: https://github.com/loqusion/typix/pull/12

# [0.1.3] (March 26, 2024)

### Fixed

- Include missing dependencies in `buildTypstProjectLocal` and `watchTypstProject`

# [0.1.2] (February 29, 2024)

- Test release

# [0.1.1] (February 29, 2024)

- Add release script
- Add `description` attribute to `flake.nix`

# [0.1.0] (February 29, 2024)

- First release

[0.3.2]: https://github.com/loqusion/typix/compare/0.3.1...0.3.2
[0.3.1]: https://github.com/loqusion/typix/compare/0.3.0...0.3.1
[0.3.0]: https://github.com/loqusion/typix/compare/0.2.0...0.3.0
[0.2.0]: https://github.com/loqusion/typix/compare/0.1.7...0.2.0
[0.1.7]: https://github.com/loqusion/typix/compare/0.1.6...0.1.7
[0.1.6]: https://github.com/loqusion/typix/compare/0.1.5...0.1.6
[0.1.5]: https://github.com/loqusion/typix/compare/0.1.4...0.1.5
[0.1.4]: https://github.com/loqusion/typix/compare/0.1.3...0.1.4
[0.1.3]: https://github.com/loqusion/typix/compare/0.1.2...0.1.3
[0.1.2]: https://github.com/loqusion/typix/compare/0.1.1...0.1.2
[0.1.1]: https://github.com/loqusion/typix/compare/0.1.0...0.1.1
[0.1.0]: https://github.com/loqusion/typix/commits/0.1.0-1/


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2023 loqusion

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
<h1 align="center">
  <img
    src="https://raw.githubusercontent.com/loqusion/typix/main/.github/assets/logo_1544x1544.png"
    alt="Typix Logo"
    width="150"
  /><br />
  Typix
</h1>

<p align="center">
  <a href="https://flakehub.com/flake/loqusion/typix">
    <img
      src="https://img.shields.io/endpoint?style=for-the-badge&color=95b6f9&labelColor=302D41&url=https://flakehub.com/f/loqusion/typix/badge"
      alt="FlakeHub version"
    ></a>
</p>

Typix aims to make it easier to use [Nix](https://nixos.org/) in
[Typst](https://github.com/typst/typst) projects.

- **Dependency management**: supports arbitrary dependencies including fonts,
  images, and data
- **Reproducible**: via a hermetically sealed build environment
- **Extensible**: full support for [Typst packages](https://loqusion.github.io/typix/recipes/using-typst-packages.html)

## Features

- Automatically fetch dependencies and compile in a single command (`nix run
.#build`)
- Watch input files and recompile on changes (`nix run .#watch`)
- Set up a shell environment with all dependencies made available via
  environment variables and symlinks
- Extensible via
  [`mkTypstDerivation`](https://loqusion.github.io/typix/api/derivations/mk-typst-derivation.html)
- Support for dependencies such as [fonts](https://typst.app/docs/reference/text/text/#parameters-font),
  [images](https://typst.app/docs/reference/visualize/image/), and [data](https://typst.app/docs/reference/data-loading/)
- [Typst packages](https://loqusion.github.io/typix/recipes/using-typst-packages.html)
  fetched from the official Typst packages CDN

## Getting Started

After [installing Nix](https://github.com/DeterminateSystems/nix-installer) and
[enabling
flakes](https://nixos.wiki/wiki/Flakes#Enable_flakes_permanently_in_NixOS), you
can initialize a flake from the default template:

```bash
nix flake init --refresh -t github:loqusion/typix
```

> Alternatively, you can use a template demonstrating [Typst packages](https://loqusion.github.io/typix/recipes/using-typst-packages.html)
> usage:
>
> ```bash
> nix flake init --refresh -t 'github:loqusion/typix#with-typst-packages'
> ```

Here are some commands you can run from any template:

- `nix run .#watch` — watch the input files and recompile on changes
- `nix run .#build` — compile and copy the output to the current directory

---

For more information, check out [the docs](https://loqusion.github.io/typix/).


================================================
FILE: checks/.gitignore
================================================
*.pdf


================================================
FILE: checks/build-local.nix
================================================
{
  lib,
  pkgs,
  buildTypstProjectLocal,
}: runCommandDrvAttr: args: let
  build-local-drv = buildTypstProjectLocal ({
      name = "build-local-check";
    }
    // args
    // runCommandDrvAttr);
in
  pkgs.runCommand "build-local" (runCommandDrvAttr
    // {
      nativeBuildInputs =
        (runCommandDrvAttr.nativeBuildInputs or [])
        ++ [
          build-local-drv
        ];
    }) ''
    ${lib.getExe build-local-drv} "$out"
  ''


================================================
FILE: checks/check-emojis.py
================================================
"""
Checks if emoji characters in a PDF file are rendered with an appropriate font face.

This script is dumb, and only checks if the font face name for text with an
emoji matches one of a set of patterns given on the command line. This
assumption is naive, and may not hold if the font names change, or if a font
name not supporting emoji happens to match any of the patterns.
"""

import re
import sys
from collections.abc import Iterator
from dataclasses import dataclass
from typing import Final

import emoji
import pdfplumber


@dataclass
class TextElement:
    text: str
    font: str


class InvalidEmojiFontException(Exception):
    def __init__(self, text_element: TextElement, font_patterns: list[re.Pattern]):
        self.text_element = text_element
        self.font_patterns = font_patterns
        self.message = (
            f'Detected invalid font for text containing emoji character: "{text_element.text}"\n'
            f'Font: "{text_element.font}"\n'
            f"Font did not match any of the following patterns: {', '.join((f"'{pat.pattern}'" for pat in font_patterns))}"
        )
        super().__init__(self.message)


class PDFChecker:
    pdf_path: str

    def __init__(self, pdf_path: str):
        self.pdf_path = pdf_path

    def check_emojis(self, font_patterns: list[re.Pattern]):
        text_elements = self._extract_text_elements()

        for text_element in text_elements:
            if emoji.emoji_count(text_element.text) == 0:
                continue

            if not any(pat.search(text_element.font) for pat in font_patterns):
                raise InvalidEmojiFontException(text_element, font_patterns)

    def _extract_text_elements(self) -> Iterator[TextElement]:
        with pdfplumber.open(self.pdf_path) as pdf:
            for page in pdf.pages:
                words = page.extract_words(
                    keep_blank_chars=True,
                    use_text_flow=True,
                    extra_attrs=["fontname"],
                )

                for word in words:
                    yield TextElement(
                        text=word["text"],
                        font=word["fontname"],
                    )


class InvalidArgumentException(Exception):
    USAGE: Final = f"usage: {sys.argv[0]} <pdf_path> <pattern> [<pattern>...]"

    def __init__(self, message: str):
        self.message = message + "\n" + InvalidArgumentException.USAGE
        super().__init__(self.message)


def main():
    pdf_path = sys.argv[1]
    checker = PDFChecker(pdf_path)

    font_patterns = list(map(lambda pat: re.compile(pat, re.IGNORECASE), sys.argv[2:]))
    if len(font_patterns) == 0:
        raise InvalidArgumentException(
            "expected one or more patterns given as arguments"
        )

    checker.check_emojis(font_patterns)


if __name__ == "__main__":
    try:
        main()
    except InvalidEmojiFontException as err:
        print(f"test failed: {err}", file=sys.stderr)
        sys.exit(1)
    except InvalidArgumentException as err:
        print(f"error: {err}", file=sys.stderr)
        sys.exit(2)
    except Exception:
        raise


================================================
FILE: checks/clean/bad.c
================================================
#include <stdio.h>

int main(void) {
    printf("Hello, World!\n");
    return 0;
}


================================================
FILE: checks/clean/lib.typ
================================================
#bibliography("works.bib")


================================================
FILE: checks/clean/metadata.toml
================================================
#:schema https://raw.githubusercontent.com/mintyfrankie/brilliant-CV/main/metadata.toml.schema.json

# Set the output language
# INFO: value must matches folder suffix; i.e "zh" -> "./modules_zh"
language = "en"

[layout]
# Optional values: skyblue, red, nephritis, concrete, darknight
# You can also use a custom color by hex code i.e. "#1E90FF"
awesome_color = "skyblue"

# Skips are for controlling the spacing between sections and entries
before_section_skip = "1pt"
before_entry_skip = "1pt"
before_entry_description_skip = "1pt"

[layout.fonts]
regular_fonts = ["Source Sans Pro", "Source Sans 3"]
header_font = "Roboto"

[layout.header]
# Optional values: left, center, right
header_align = "left"

# Decide if you want to display profile photo or not
display_profile_photo = true

[layout.entry]
# Decide if you want to put your company in bold or your position in bold
display_entry_society_first = true

# Decide if you want to display organisation logo or not
display_logo = true

[inject]
# Decide if you want to inject AI prompt or not
inject_ai_prompt = false

# Decide if you want to inject keywords or not
inject_keywords = true
injected_keywords_list = ["Data Analyst", "GCP", "Python", "SQL", "Tableau"]

[personal]
first_name = "John"
last_name = "Doe"

# The order of this section will affect how the entries are displayed
# The custom value is for any additional information you want to add, name it as custom-1, custom-2, etc.
[personal.info]
github = "mintyfrankie"
phone = "+33 6 12 34 56 78"
email = "john.doe@me.org"
linkedin = "johndoe"
# gitlab = "mintyfrankie"
# homepage = "jd.me.org"
# orcid = "0000-0000-0000-0000"
# researchgate = "John-Doe"
# extraInfo = "I am a cool kid"
[personal.info.custom-1]
# image = "" # Example: image("./path/to/image.png")
awesomeIcon = "graduation-cap"   # Example: "graduation-cap" see https://typst.app/universe/package/fontawesome/
text = "PhD"
link = "https://www.example.com"

# add a new section if you want to include the language of your choice
# i.e. [[lang.ru]]
# each section must contains the following fields
[lang.en]
header_quote = "Experienced Data Analyst looking for a full time job starting from now"
cv_footer = "Curriculum vitae"
letter_footer = "Cover letter"

[lang.fr]
header_quote = "Analyste de données expérimenté à la recherche d'un emploi à temps plein disponible dès maintenant"
cv_footer = "Résumé"
letter_footer = "Lettre de motivation"

[lang.zh]
header_quote = "具有丰富经验的数据分析师,随时可入职"
cv_footer = "简历"
letter_footer = "申请信"

# For languages that are not written in Latin script
# Currently supported non-latin language codes: ("zh", "ja", "ko", "ru")
[lang.non_latin]
name = "王道尔"
font = "Heiti SC"


================================================
FILE: checks/clean/sub/bad.py
================================================
if __name__ == "__main__":
    print("Hello, World!")


================================================
FILE: checks/clean/sub/sub.typ
================================================


================================================
FILE: checks/clean/sub/typst.toml
================================================
[package]
name = "sub"
version = "0.1.0"
entrypoint = "sub.typ"


================================================
FILE: checks/clean/typst.toml
================================================
[package]
name = "clean"
version = "0.1.0"
entrypoint = "lib.typ"


================================================
FILE: checks/clean/works.bib
================================================
\begin{thebibliography}{9}
\bibitem{texbook}
Donald E. Knuth (1986) \emph{The \TeX{} Book}, Addison-Wesley Professional.

\bibitem{lamport94}
Leslie Lamport (1994) \emph{\LaTeX: a document preparation system}, Addison
Wesley, Massachusetts, 2nd ed.
\end{thebibliography}


================================================
FILE: checks/clean-expected/lib.typ
================================================
#bibliography("works.bib")


================================================
FILE: checks/clean-expected/metadata.toml
================================================
#:schema https://raw.githubusercontent.com/mintyfrankie/brilliant-CV/main/metadata.toml.schema.json

# Set the output language
# INFO: value must matches folder suffix; i.e "zh" -> "./modules_zh"
language = "en"

[layout]
# Optional values: skyblue, red, nephritis, concrete, darknight
# You can also use a custom color by hex code i.e. "#1E90FF"
awesome_color = "skyblue"

# Skips are for controlling the spacing between sections and entries
before_section_skip = "1pt"
before_entry_skip = "1pt"
before_entry_description_skip = "1pt"

[layout.fonts]
regular_fonts = ["Source Sans Pro", "Source Sans 3"]
header_font = "Roboto"

[layout.header]
# Optional values: left, center, right
header_align = "left"

# Decide if you want to display profile photo or not
display_profile_photo = true

[layout.entry]
# Decide if you want to put your company in bold or your position in bold
display_entry_society_first = true

# Decide if you want to display organisation logo or not
display_logo = true

[inject]
# Decide if you want to inject AI prompt or not
inject_ai_prompt = false

# Decide if you want to inject keywords or not
inject_keywords = true
injected_keywords_list = ["Data Analyst", "GCP", "Python", "SQL", "Tableau"]

[personal]
first_name = "John"
last_name = "Doe"

# The order of this section will affect how the entries are displayed
# The custom value is for any additional information you want to add, name it as custom-1, custom-2, etc.
[personal.info]
github = "mintyfrankie"
phone = "+33 6 12 34 56 78"
email = "john.doe@me.org"
linkedin = "johndoe"
# gitlab = "mintyfrankie"
# homepage = "jd.me.org"
# orcid = "0000-0000-0000-0000"
# researchgate = "John-Doe"
# extraInfo = "I am a cool kid"
[personal.info.custom-1]
# image = "" # Example: image("./path/to/image.png")
awesomeIcon = "graduation-cap"   # Example: "graduation-cap" see https://typst.app/universe/package/fontawesome/
text = "PhD"
link = "https://www.example.com"

# add a new section if you want to include the language of your choice
# i.e. [[lang.ru]]
# each section must contains the following fields
[lang.en]
header_quote = "Experienced Data Analyst looking for a full time job starting from now"
cv_footer = "Curriculum vitae"
letter_footer = "Cover letter"

[lang.fr]
header_quote = "Analyste de données expérimenté à la recherche d'un emploi à temps plein disponible dès maintenant"
cv_footer = "Résumé"
letter_footer = "Lettre de motivation"

[lang.zh]
header_quote = "具有丰富经验的数据分析师,随时可入职"
cv_footer = "简历"
letter_footer = "申请信"

# For languages that are not written in Latin script
# Currently supported non-latin language codes: ("zh", "ja", "ko", "ru")
[lang.non_latin]
name = "王道尔"
font = "Heiti SC"


================================================
FILE: checks/clean-expected/sub/sub.typ
================================================


================================================
FILE: checks/clean-expected/sub/typst.toml
================================================
[package]
name = "sub"
version = "0.1.0"
entrypoint = "sub.typ"


================================================
FILE: checks/clean-expected/typst.toml
================================================
[package]
name = "clean"
version = "0.1.0"
entrypoint = "lib.typ"


================================================
FILE: checks/clean-expected/works.bib
================================================
\begin{thebibliography}{9}
\bibitem{texbook}
Donald E. Knuth (1986) \emph{The \TeX{} Book}, Addison-Wesley Professional.

\bibitem{lamport94}
Leslie Lamport (1994) \emph{\LaTeX: a document preparation system}, Addison
Wesley, Massachusetts, 2nd ed.
\end{thebibliography}


================================================
FILE: checks/date/main.typ
================================================
#let UNIX_EPOCH = datetime(
  year: 1980,
  month: 1,
  day: 1,
)
#assert.ne(
  datetime.today(),
  UNIX_EPOCH,
)


================================================
FILE: checks/default.nix
================================================
{
  pkgs,
  myLib,
}: let
  inherit (pkgs) lib;
  inherit (lib.strings) escapeShellArg concatMapStringsSep;
  onlyDrvs = lib.filterAttrs (_: lib.isDerivation);
in
  onlyDrvs (lib.makeScope myLib.newScope (self: let
    callPackage = self.newScope {};
    typstSource = "main.typ";
    fontPaths = [
      "${pkgs.roboto}/share/fonts/truetype"
    ];
    virtualPaths = [
      {
        src = ./fixtures/icons;
        dest = "icons";
      }
    ];
    unstable_typstPackages = [
      {
        name = "example";
        version = "0.1.0";
        hash = "sha256-R18Xv3AoZsTtMycRasczTsje5yIfiURIxtDICQ4mvho=";
      }
      {
        name = "cetz";
        version = "0.3.4";
        hash = "sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=";
      }
      {
        name = "polylux";
        version = "0.4.0";
        hash = "sha256-4owP2KiyaaASS1YZ0Hs58k6UEVAqsRR3YdGF26ikosk=";
      }
      # Required by cetz
      {
        name = "oxifmt";
        version = "0.2.1";
        hash = "sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=";
      }
    ];
  in rec {
    buildLocal = callPackage ./build-local.nix {};
    buildLocalSimple = buildLocal {} {
      inherit typstSource;
      src = myLib.cleanTypstSource ./simple;
    };
    buildLocalSimpleWithFonts = buildLocal {} {
      inherit fontPaths typstSource;
      src = myLib.cleanTypstSource ./simple-with-fonts;
    };
    buildLocalSimpleWithVirtualPaths = buildLocal {} {
      inherit virtualPaths typstSource;
      src = myLib.cleanTypstSource ./simple-with-virtual-paths;
    };
    buildLocalWithMultipleParameters = buildLocal {} {
      inherit typstSource;
      src = myLib.cleanTypstSource ./simple-with-multiple-parameters;
      typstOpts = {
        input = ["key1=value1" "key2=value2" "key3= --spaces-are-properly-escaped" "key4='quotes-are-properly-escaped\""];
      };
    };
    buildLocalWithTypstPackages = buildLocal {} {
      inherit typstSource;
      src = myLib.cleanTypstSource ./typst-packages;
      inherit unstable_typstPackages;
    };

    clean = myLib.mkTypstDerivation {
      src = myLib.cleanTypstSource ./clean;
      EXPECTED_SRC = ./clean-expected;
      buildPhaseTypstCommand = ''
        diff -r "$src" "$EXPECTED_SRC"
        touch $out
      '';
    };

    date = myLib.buildTypstProject {
      inherit typstSource;
      src = myLib.cleanTypstSource ./date;
    };
    dateWatch = watch {} {
      inherit typstSource;
      src = myLib.cleanTypstSource ./date;
    };

    devShell = myLib.devShell {
      inherit virtualPaths;
      checks = {
        simple = myLib.buildTypstProject {
          inherit virtualPaths typstSource;
          src = myLib.cleanTypstSource ./simple;
        };
      };
    };

    checkEmojiScript = {
      inputs =
        (with pkgs; [
          python312
          python312Packages.emoji
        ])
        ++ (
          with pkgs.python312Packages; [
            # Referencing `emoji` doesn't work here because an attribute of that
            # name already exists in a recursive attribute set (`rec {...}`)
            pdfplumber
          ]
        );
      script = patterns: ''
        python3.12 ${./check-emojis.py} "$out" ${concatMapStringsSep " " escapeShellArg patterns}
      '';
    };

    emoji = {
      emojiFont,
      fontPaths ? [],
      patterns,
    }: (myLib.buildTypstProject ({
        inherit typstSource fontPaths;
        src = myLib.cleanTypstSource ./emoji;
        doCheck = true;
        nativeCheckInputs = checkEmojiScript.inputs;
        checkPhase = checkEmojiScript.script patterns;
      }
      // lib.optionalAttrs (emojiFont != "__OMIT__") {
        inherit emojiFont;
      }));
    emojiOmit = emoji {
      emojiFont = "__OMIT__";
      patterns = ["emoji"];
    };
    emojiTwemoji = emoji {
      emojiFont = "twemoji";
      patterns = ["emoji"];
    };
    emojiTwemojiCbdt = emoji {
      emojiFont = "twemoji-cbdt";
      patterns = ["emoji"];
    };
    emojiNoto = emoji {
      emojiFont = "noto";
      patterns = ["emoji"];
    };
    emojiNotoMonochrome = emoji {
      emojiFont = "noto-monochrome";
      patterns = ["emoji"];
    };
    # FIXME: https://github.com/loqusion/typix/issues/79
    # emojiEmojiOne = emoji {
    #   emojiFont = "emojione";
    #   patterns = ["emoji"];
    # };
    emojiFontOverride = emoji {
      emojiFont = null;
      fontPaths = ["${pkgs.noto-fonts-color-emoji}/share/fonts/noto"];
      patterns = ["emoji"];
    };

    emojiWatch = {
      emojiFont,
      fontPaths ? [],
      patterns,
    }: (watch {
        nativeBuildInputs = checkEmojiScript.inputs;
        postBuild = checkEmojiScript.script patterns;
      } ({
          inherit typstSource fontPaths;
          src = myLib.cleanTypstSource ./emoji;
        }
        // lib.optionalAttrs (emojiFont != "__OMIT__") {
          inherit emojiFont;
        }));
    emojiWatchOmit = emojiWatch {
      emojiFont = "__OMIT__";
      patterns = ["emoji"];
    };
    emojiWatchTwemoji = emojiWatch {
      emojiFont = "twemoji";
      patterns = ["emoji"];
    };
    emojiWatchTwemojiCbdt = emojiWatch {
      emojiFont = "twemoji-cbdt";
      patterns = ["emoji"];
    };
    emojiWatchNoto = emojiWatch {
      emojiFont = "noto";
      patterns = ["emoji"];
    };
    emojiWatchNotoMonochrome = emojiWatch {
      emojiFont = "noto-monochrome";
      patterns = ["emoji"];
    };
    # FIXME: https://github.com/loqusion/typix/issues/79
    # emojiWatchEmojiOne = emojiWatch {
    #   emojiFont = "emojione";
    #   patterns = ["emoji"];
    # };
    emojiWatchFontOverride = emojiWatch {
      emojiFont = null;
      fontPaths = ["${pkgs.noto-fonts-color-emoji}/share/fonts/noto"];
      patterns = ["emoji"];
    };

    overlappingVirtualPaths = isInvariant: util: file:
      util (let
        op =
          if isInvariant
          then "!="
          else "=";
        errorMsg =
          if isInvariant
          then ''$FILE_TO_CHECK was overwritten\; it should stay the same when forceVirtualPaths is false''
          else ''$FILE_TO_CHECK was not overwritten\; it should be overwritten when forceVirtualPaths is true'';
      in {
        FILE_TO_CHECK = file;
        preBuild = ''
          if [ ! -e "$FILE_TO_CHECK" ]; then
            echo "$FILE_TO_CHECK does not exist; unable to run check"
            exit 1
          fi
          hash=$(sha256sum "$FILE_TO_CHECK" | awk '{ print $1 }')
          if [ -z "$hash" ]; then
            echo "unable to obtain hash for $FILE_TO_CHECK"
            exit 1
          fi
        '';
        postBuild = ''
          hash=''${hash:?not defined}
          new_hash=$(sha256sum "$FILE_TO_CHECK" | awk '{ print $1 }')
          if [ -z "$new_hash" ]; then
            echo "unable to obtain hash for $FILE_TO_CHECK"
            exit 1
          fi
          if [ "$hash" ${op} "$new_hash" ]; then
            echo ${errorMsg}
            echo
            echo "old hash: $hash"
            echo "new hash: $new_hash"
            exit 1
          fi
        '';
      }) {
        inherit virtualPaths typstSource;
        src = ./overlapping-virtual-paths;
        forceVirtualPaths = !isInvariant;
      };
    overlappingVirtualPathsInvariant = overlappingVirtualPaths true;
    overlappingVirtualPathsForce = overlappingVirtualPaths false;

    simple = myLib.buildTypstProject {
      inherit typstSource;
      src = myLib.cleanTypstSource ./simple;
    };
    simpleWithFonts = myLib.buildTypstProject {
      inherit fontPaths typstSource;
      src = myLib.cleanTypstSource ./simple-with-fonts;
    };
    simpleWithMultipleParameters = myLib.buildTypstProject {
      inherit typstSource;
      src = myLib.cleanTypstSource ./simple-with-multiple-parameters;
      typstOpts = {
        input = ["key1=value1" "key2=value2" "key3= --spaces-are-properly-escaped" "key4='quotes-are-properly-escaped\""];
      };
    };
    simpleWithVirtualPaths = myLib.buildTypstProject {
      inherit virtualPaths typstSource;
      src = myLib.cleanTypstSource ./simple-with-virtual-paths;
    };

    withTypstPackages = myLib.buildTypstProject {
      inherit typstSource;
      src = myLib.cleanTypstSource ./typst-packages;
      inherit unstable_typstPackages;
    };

    virtualPathsChecks = callPackage ./virtual-paths.nix {};

    watch = callPackage ./watch.nix {};
    watchSimple = watch {} {
      inherit typstSource;
      src = myLib.cleanTypstSource ./simple;
    };
    watchSimpleWithFonts = watch {} {
      inherit fontPaths typstSource;
      src = myLib.cleanTypstSource ./simple-with-fonts;
    };
    watchWithMultipleParameters = watch {} {
      inherit typstSource;
      src = myLib.cleanTypstSource ./simple-with-multiple-parameters;
      typstOpts = {
        input = ["key1=value1" "key2=value2" "key3= --spaces-are-properly-escaped" "key4='quotes-are-properly-escaped\""];
      };
    };
    # TODO: see above
    # watchSimpleWithTypstPackages = watch {} {
    #   inherit typstSource;
    #   src = myLib.cleanTypstSource ./simple-with-typst-packages;
    # };
    watchSimpleWithVirtualPaths = watch {} {
      inherit virtualPaths typstSource;
      src = myLib.cleanTypstSource ./simple-with-virtual-paths;
    };

    watchOverlappingVirtualPaths = overlappingVirtualPathsInvariant watch "icons/link.svg";
    watchOverlappingVirtualPathsForce = overlappingVirtualPathsForce watch "icons/link.svg";
  }))


================================================
FILE: checks/emoji/main.typ
================================================
#(emoji.tangerine)hell#(emoji.o) w#(emoji.o)rld#(emoji.face)


================================================
FILE: checks/overlapping-virtual-paths/main.typ
================================================
#lorem(100)

#image("icons/link.svg")


================================================
FILE: checks/simple/main.typ
================================================
#lorem(100)


================================================
FILE: checks/simple-with-fonts/main.typ
================================================
#set text(font: "Roboto")

#lorem(100)


================================================
FILE: checks/simple-with-multiple-parameters/main.typ
================================================
#sys.inputs.key1
#sys.inputs.key2


================================================
FILE: checks/simple-with-virtual-paths/main.typ
================================================
#lorem(100)

#image("icons/link.svg")
#image("icons/paper-plane-tilt.svg")


================================================
FILE: checks/typst-packages/main.typ
================================================
#import "@preview/example:0.1.0": add
#import "@preview/cetz:0.3.4"
#import "@preview/polylux:0.4.0": slide, uncover

// example

2 + 2 = #[add(2 + 2)]

// cetz

#cetz.canvas({
  import cetz.draw: *

  circle((0, 0))
  line((0, 0), (2, 1))
})

// polylux

// Make the paper dimensions fit for a presentation and the text larger
#set page(paper: "presentation-16-9")
#set text(size: 25pt)

// Use #slide to create a slide and style it using your favourite Typst functions
#slide[
  #set align(horizon)
  = Very minimalist slides

  A lazy author

  July 23, 2023
]

#slide[
  == First slide

  Some static text on this slide.
]

#slide[
  == This slide changes!

  You can always see this.
  // Make use of features like #uncover, #only, and others to create dynamic content
  #uncover(2)[But this appears later!]
]


================================================
FILE: checks/virtual-paths.nix
================================================
{
  cleanTypstSource,
  copyVirtualPathsHook,
  lib,
  linkFarmFromDrvs,
  linkVirtualPaths,
  pkgs,
}: let
  inherit (lib.attrsets) filterAttrs mapAttrsToList;
  inherit (lib.lists) all;
  inherit (lib.strings) toShellVars;

  cleanArgs = args:
    builtins.removeAttrs args [
      "virtualPaths"
      "assertionCommand"
      "linkAssertionCommnad"
    ];

  copyVirtualPathsHookAssertion = args @ {
    virtualPaths,
    assertionCommand,
    ...
  }:
    pkgs.stdenvNoCC.mkDerivation ((cleanArgs args)
      // {
        src = cleanTypstSource ./simple;
        nativeBuildInputs = [
          (copyVirtualPathsHook virtualPaths)
        ];
        buildPhase = ''
          runHook preBuild
          runHook postBuild
        '';
        postBuild = ''
          set -euo pipefail

          assertionCommand() {
            ${assertionCommand}
          }

          if ! assertionCommand; then
            ${toShellVars {assertionText = assertionCommand;}}
            echo "assertion \`$assertionText\` failed"
            exit 1
          fi

          touch "$out"
        '';
      });

  linkVirtualPathsAssertion = args @ {
    virtualPaths,
    assertionCommand,
    linkAssertionCommand ? "true",
    ...
  }:
    pkgs.stdenvNoCC.mkDerivation ((cleanArgs args)
      // {
        src = cleanTypstSource ./simple;
        buildPhase = ''
          ${linkVirtualPaths {inherit virtualPaths;}}
          runHook postBuild
        '';
        postBuild = ''
          set -euo pipefail

          assertionCommand() {
            ${assertionCommand}
          }

          linkAssertionCommand() {
            ${linkAssertionCommand}
          }

          if ! assertionCommand; then
            ${toShellVars {assertionText = assertionCommand;}}
            echo "assertion \`$assertionText\` failed"
            exit 1
          fi
          if ! linkAssertionCommand; then
            ${toShellVars {assertionText = linkAssertionCommand;}}
            echo "assertion \`$assertionText\` failed"
            exit 1
          fi

          touch "$out"
        '';
      });

  virtualPathsTestAttrs = {
    fileSource = {
      virtualPaths = ["${./fixtures/icons}/link.svg"];
      assertionCommand = ''[ -f ./link.svg ]'';
      linkAssertionCommand = ''[ -L ./link.svg ]'';
    };

    directorySource = {
      virtualPaths = [./fixtures/icons];
      assertionCommand = ''[ -f ./main.typ ] && [ -f ./link.svg ]'';
      linkAssertionCommand = ''[ -L ./link.svg ]'';
    };

    fileSourceWithDest = {
      virtualPaths = [
        {
          src = ./fixtures/icons/link.svg;
          dest = "link.svg";
        }
      ];
      assertionCommand = ''[ -f ./link.svg ]'';
      linkAssertionCommand = ''[ -L ./link.svg ]'';
    };

    directorySourceWithDest = {
      virtualPaths = [
        {
          src = ./fixtures/icons;
          dest = "icons";
        }
      ];
      assertionCommand = ''[ -d ./icons ] && [ -f ./icons/link.svg ]'';
      linkAssertionCommand = ''[ ! -L ./icons ] && [ -L ./icons/link.svg ]'';
    };

    fileSourceWithDeepDest = {
      virtualPaths = [
        {
          src = ./fixtures/icons/link.svg;
          dest = "assets/icons/link.svg";
        }
      ];
      assertionCommand = ''[ -d ./assets/icons ] && [ -f ./assets/icons/link.svg ]'';
      linkAssertionCommand = ''[ ! -L ./assets ] && [ ! -L ./assets/icons ] && [ -L ./assets/icons/link.svg ]'';
    };

    directorySourceWithDeepDest = {
      virtualPaths = [
        {
          src = ./fixtures/icons;
          dest = "assets/icons";
        }
      ];
      assertionCommand = ''[ -d ./assets/icons ] && [ -f ./assets/icons/link.svg ]'';
      linkAssertionCommand = ''[ ! -L ./assets ] && [ ! -L ./assets/icons ] && [ -L ./assets/icons/link.svg ]'';
    };

    mergedSources = {
      virtualPaths = [
        {
          src = ./fixtures/icons;
          dest = "icons";
        }
        {
          src = ./fixtures/more-icons;
          dest = "icons";
        }
      ];
      assertionCommand = ''[ -d ./icons ] && [ -f ./icons/link.svg ] && [ -f ./icons/another-link.svg ]'';
      linkAssertionCommand = ''[ ! -L ./icons ] && [ -L ./icons/link.svg ] && [ -L ./icons/another-link.svg ]'';
    };
  };

  skip = {
    copyVirtualPathsHook = [];
    linkVirtualPaths = [];
  };
  filterSkip = skipNames:
    filterAttrs
    (name: _: all (skipName: name != skipName) skipNames);

  mapTestAttrs = f: skipAttrs: testGroupName:
    mapAttrsToList
    (name: attrs: f (attrs // {name = "${testGroupName}-${name}";}))
    (filterSkip skipAttrs virtualPathsTestAttrs);
in
  linkFarmFromDrvs "virtualPathsTests"
  (
    (mapTestAttrs copyVirtualPathsHookAssertion skip.copyVirtualPathsHook "copyVirtualPathsHook")
    ++ (mapTestAttrs linkVirtualPathsAssertion skip.linkVirtualPaths "linkVirtualPaths")
  )


================================================
FILE: checks/watch.nix
================================================
{
  lib,
  pkgs,
  watchTypstProject,
}: runCommandDrvAttr: args: let
  cleanedArgs = builtins.removeAttrs args [
    "src"
  ];
  watch-drv = watchTypstProject ({
      name = "watch-check";
      # `typst watch` will never exit itself, but we can still check the exit status of `typst compile` for errors
      typstWatchCommand = "typst compile";
    }
    // cleanedArgs);
in
  pkgs.runCommand "watch" (runCommandDrvAttr
    // {
      nativeBuildInputs =
        (runCommandDrvAttr.nativeBuildInputs or [])
        ++ [
          watch-drv
        ];
    }) ''
    # This is needed to imitate a user's project directory
    cp -RLT --no-preserve=mode ${args.src} .

    runHook preBuild
    ${lib.getExe watch-drv} "$out"
    runHook postBuild
  ''


================================================
FILE: docs/.gitignore
================================================
book


================================================
FILE: docs/SUMMARY.md
================================================
<!-- markdownlint-disable MD025 -->

# Summary

- [Introduction](README.md)
- [Getting Started](getting-started.md)

# Recipes

- [Adding dependencies](recipes/adding-dependencies.md)
- [Specifying sources](recipes/specifying-sources.md)
- [Declaring a shell environment](recipes/declaring-a-shell-environment.md)
- [Using Typst packages](recipes/using-typst-packages.md)

# API Reference

- [Derivations](api/derivations.md)
  - [buildTypstProject](api/derivations/build-typst-project.md)
  - [buildTypstProjectLocal](api/derivations/build-typst-project-local.md)
  - [devShell](api/derivations/dev-shell.md)
  - [mkTypstDerivation](api/derivations/mk-typst-derivation.md)
  - [watchTypstProject](api/derivations/watch-typst-project.md)
- [Utilities](api/utilities.md)
  - [cleanTypstSource](api/utilities/clean-typst-source.md)


================================================
FILE: docs/api/derivations/build-typst-project-local.md
================================================
# buildTypstProjectLocal

Returns a derivation for compiling a Typst project and copying the output to the
current directory.

This is essentially a script which wraps
[`buildTypstProject`](build-typst-project.md).

<div class="warning">

Using this derivation requires
[`allow-import-from-derivation`](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-allow-import-from-derivation)
to be `true` (which is the default at the time of writing).

More info: <https://nixos.org/manual/nix/stable/language/import-from-derivation>

</div>

<div class="warning">

Invoking the script produced by this derivation directly is currently
unsupported. Instead, use `nix run`.

See [this issue](https://github.com/loqusion/typix/issues/2) for more
information.

</div>

## Parameters

All parameters accepted by
[`buildTypstProject`](build-typst-project.md#parameters) are also accepted by
`buildTypstProjectLocal`. They are repeated below for convenience.

### `src`

{{#include common/src.md}}

### `emojiFont` <sup><em>optional</em></sup> { #emojifont }

{{#include common/emoji-font.md}}

### `fontPaths` <sup><em>optional</em></sup> { #fontpaths }

{{#include common/font-paths.md}}

#### Example { #fontpaths-example }

{{#include common/font-paths-example.md:buildtypstprojectlocal_example}}

### `installPhaseCommand` <sup><em>optional</em></sup> { #installphasecommand }

{{#include common/install-phase-command.md}}

### `scriptName` <sup><em>optional</em></sup> { #scriptname }

{{#include common/script-name.md}}

Default is `typst-build`.

### `typstCompileCommand` <sup><em>optional</em></sup> { #typstcompilecommand }

{{#include common/typst-compile-command.md}}

Default is `typst compile`.

### `typstOpts` <sup><em>optional</em></sup> { #typstopts }

{{#include common/typst-opts.md:head}}

<!-- markdownlint-disable link-fragments -->

These are in addition to any options you manually pass in
[`typstCompileCommand`](#typstcompilecommand).

<!-- markdownlint-restore -->

{{#include common/typst-opts.md:tail}}

#### Example { #typstopts-example }

{{#include common/typst-opts-example.md:buildtypstprojectlocal}}
{{#include common/typst-opts-example.md:typstcompile}}

### `typstOutput` <sup><em>optional</em></sup> { #typstoutput }

{{#include common/typst-project-output.md:head}}
{{#include common/typst-project-output.md:buildtypstprojectlocal}}

### `typstSource` <sup><em>optional</em></sup> { #typstsource }

{{#include common/typst-project-source.md}}

Default is `main.typ`.

### `unstable_typstPackages` <sup><em>optional</em></sup> { #typstpackages }

{{#include common/typst-packages.md:body}}

#### Example { #typstpackages-example }

{{#include common/typst-packages.md:example_buildtypstprojectlocal}}
{{#include common/typst-packages.md:example_typst}}

### `virtualPaths` <sup><em>optional</em></sup> { #virtualpaths }

{{#include common/virtual-paths.md}}

#### Example { #virtualpaths-example }

{{#include common/virtual-paths-example.md:head}}
{{#include common/virtual-paths-example.md:buildtypstprojectlocal_example}}
{{#include common/virtual-paths-example.md:tail}}

## Source

- [`buildTypstProjectLocal`](https://github.com/loqusion/typix/blob/main/lib/buildTypstProjectLocal.nix)


================================================
FILE: docs/api/derivations/build-typst-project.md
================================================
# buildTypstProject

Returns a derivation for compiling a Typst project.

If you want to build to the project directory, use
[`buildTypstProjectLocal`](build-typst-project-local.md) instead.

## Parameters

All parameters accepted by
[`mkTypstDerivation`](mk-typst-derivation.md#parameters) are also accepted by
`buildTypstProject`. They are repeated below for convenience.

### `src`

{{#include common/src.md}}

### `emojiFont` <sup><em>optional</em></sup> { #emojifont }

{{#include common/emoji-font.md}}

### `fontPaths` <sup><em>optional</em></sup> { #fontpaths }

{{#include common/font-paths.md}}

#### Example { #fontpaths-example }

{{#include common/font-paths-example.md:buildtypstproject_example}}

### `installPhaseCommand` <sup><em>optional</em></sup> { #installphasecommand }

{{#include common/install-phase-command.md}}

### `typstCompileCommand` <sup><em>optional</em></sup> { #typstcompilecommand }

{{#include common/typst-compile-command.md}}

Default is `typst compile`.

### `typstOpts` <sup><em>optional</em></sup> { #typstopts }

{{#include common/typst-opts.md:head}}

<!-- markdownlint-disable link-fragments -->

These are in addition to any options you manually pass in
[`typstCompileCommand`](#typstcompilecommand).

<!-- markdownlint-restore -->

{{#include common/typst-opts.md:tail}}

#### Example { #typstopts-example }

{{#include common/typst-opts-example.md:buildtypstproject}}
{{#include common/typst-opts-example.md:typstcompile}}

### `typstSource` <sup><em>optional</em></sup> { #typstsource }

{{#include common/typst-project-source.md}}

Default is `main.typ`.

### `unstable_typstPackages` <sup><em>optional</em></sup> { #typstpackages }

{{#include common/typst-packages.md:body}}

#### Example { #typstpackages-example }

{{#include common/typst-packages.md:example_buildtypstproject}}
{{#include common/typst-packages.md:example_typst}}

### `virtualPaths` <sup><em>optional</em></sup> { #virtualpaths }

{{#include common/virtual-paths.md}}

#### Example { #virtualpaths-example }

{{#include common/virtual-paths-example.md:head}}
{{#include common/virtual-paths-example.md:buildtypstproject_example}}
{{#include common/virtual-paths-example.md:tail}}

## Source

- [`buildTypstProject`](https://github.com/loqusion/typix/blob/main/lib/buildTypstProject.nix)


================================================
FILE: docs/api/derivations/common/emoji-font.md
================================================
Specify which emoji font to use. If `emojiFont` is `null`, no emoji font will
be included.

May be any of the following:

- [`"twemoji"`](https://search.nixos.org/packages?channel=unstable&show=twemoji-color-font) (default)
- [`"twemoji-cbdt"`](https://search.nixos.org/packages?channel=unstable&show=twitter-color-emoji)
- [`"noto"`](https://search.nixos.org/packages?channel=unstable&show=noto-fonts-color-emoji)
- [`"noto-monochrome"`](https://search.nixos.org/packages?channel=unstable&show=noto-fonts-monochrome-emoji)
- [`"emojione"`](https://search.nixos.org/packages?channel=unstable&show=emojione)
- `null` — Don't include any emoji font (e.g. so you can include your own)

<details>
<summary>Note about difference between <code>"twemoji"</code> and <code>"twemoji-cbdt"</code></summary>

The default Twemoji font displays color emojis using the SVG [font format],
which may not be supported by some systems. If emojis aren't displaying
properly, using `"twemoji-cbdt"` may fix it.

[font format]: https://www.colorfonts.wtf/

</details>


================================================
FILE: docs/api/derivations/common/font-paths-example.md
================================================
<!-- markdownlint-disable-file first-line-h1 -->

<!-- ANCHOR: buildtypstprojectlocal_example -->

```nix
{
  outputs = { nixpkgs, typix }: let
    system = "x86_64-linux";
    pkgs = nixpkgs.legacyPackages.${system};
    inherit (pkgs) lib;

    build-script = typix.lib.${system}.buildTypstProjectLocal {
      fontPaths = [
        "${pkgs.roboto}/share/fonts/truetype"
      ];
    };
  in {
    apps.${system}.default = {
      type = "app";
      program = lib.getExe build-script;
    };
  };
}
```

<!-- ANCHOR_END: buildtypstprojectlocal_example -->

<!-- ANCHOR: buildtypstproject_example -->

```nix
{
  outputs = { nixpkgs, typix }: let
    system = "x86_64-linux";
    pkgs = nixpkgs.legacyPackages.${system};
  in {
    packages.${system}.default = typix.lib.${system}.buildTypstProject {
      fontPaths = [
        "${pkgs.roboto}/share/fonts/truetype"
      ];
    };
  };
}
```

<!-- ANCHOR_END: buildtypstproject_example -->

<!-- ANCHOR: devshell_example -->

```nix
{
  outputs = { nixpkgs, typix }: let
    system = "x86_64-linux";
    pkgs = nixpkgs.legacyPackages.${system};
  in {
    devShells.${system}.default = typix.lib.${system}.devShell {
      fontPaths = [
        "${pkgs.roboto}/share/fonts/truetype"
      ];
    };
  };
}
```

<!-- ANCHOR_END: devshell_example -->

<!-- ANCHOR: mktypstderivation_example -->

```nix
{
  outputs = { nixpkgs, typix }: let
    system = "x86_64-linux";
    pkgs = nixpkgs.legacyPackages.${system};
  in {
    packages.${system}.default = typix.lib.${system}.mkTypstDerivation {
      fontPaths = [
        "${pkgs.roboto}/share/fonts/truetype"
      ];
    };
  };
}
```

<!-- ANCHOR_END: mktypstderivation_example -->

<!-- ANCHOR: watchtypstproject_example -->

```nix
{
  outputs = { nixpkgs, typix }: let
    system = "x86_64-linux";
    pkgs = nixpkgs.legacyPackages.${system};
    inherit (pkgs) lib;

    watch-script = typix.lib.${system}.watchTypstProject {
      fontPaths = [
        "${pkgs.roboto}/share/fonts/truetype"
      ];
    };
  in {
    apps.${system}.default = {
      type = "app";
      program = lib.getExe watch-script;
    };
  };
}
```

<!-- ANCHOR_END: watchtypstproject_example -->


================================================
FILE: docs/api/derivations/common/font-paths.md
================================================
<!-- markdownlint-disable-file first-line-h1 -->

List of sources specifying paths to font files that will be made available to
your Typst project. With this, you can compile Typst projects even when the
fonts it uses are not available on your system.

Used for setting `TYPST_FONT_PATHS` (see [`text#font`][typst-ref-text--font]).

[typst-ref-text--font]: https://typst.app/docs/reference/text/text/#parameters-font


================================================
FILE: docs/api/derivations/common/install-phase-command.md
================================================
<!-- markdownlint-disable first-line-h1 -->

Command (or commands) to run during
[`installPhase`][nixpkgs-installphase].

[nixpkgs-installphase]: https://nixos.org/manual/nixpkgs/stable/#ssec-install-phase


================================================
FILE: docs/api/derivations/common/script-name.md
================================================
<!-- markdownlint-disable-file first-line-h1 -->

Name of the script that will be added to the Nix store. You can use this name
after entering a development shell to invoke the script.


================================================
FILE: docs/api/derivations/common/src.md
================================================
<!-- markdownlint-disable-file first-line-h1 -->

[Source](../../recipes/specifying-sources.md) containing all local files
needed in your Typst project.


================================================
FILE: docs/api/derivations/common/typst-compile-command.md
================================================
<!-- markdownlint-disable first-line-h1 -->

Base Typst command to run to compile the project. Other arguments will be
appended based on the parameters you supply.


================================================
FILE: docs/api/derivations/common/typst-opts-example.md
================================================
<!-- markdownlint-disable-file first-line-h1 -->

<!-- ANCHOR: head -->

```nix
{
  format = "png";
  ppi = 300;
  input = ["key1=value1" "key2=value2"];
}
```

...will result in a command like:

<!-- ANCHOR_END: head -->

<!-- ANCHOR: buildtypstproject -->

```nix
{
  outputs = { typix }: let
    system = "x86_64-linux";
  in {
    packages.${system}.default = typix.lib.${system}.buildTypstProject {
      typstOpts = {
        format = "png";
        ppi = 300;
        input = ["key1=value1" "key2=value2"];
      };
    };
  };
}
```

...will result in a command like:

<!-- ANCHOR_END: buildtypstproject -->

<!-- ANCHOR: buildtypstprojectlocal -->

```nix
{
  outputs = { typix }: let
    system = "x86_64-linux";
    inherit (nixpkgs) lib;

    build-script = typix.lib.${system}.buildTypstProjectLocal {
      typstOpts = {
        format = "png";
        ppi = 300;
        input = ["key1=value1" "key2=value2"];
      };
    };
  in {
    apps.${system}.default = {
      type = "app";
      program = lib.getExe build-script;
    };
  };
}
```

...will result in a command like:

<!-- ANCHOR_END: buildtypstprojectlocal -->

<!-- ANCHOR: watchtypstproject -->

```nix
{
  outputs = { typix }: let
    system = "x86_64-linux";
    inherit (nixpkgs) lib;

    watch-script = typix.lib.${system}.watchTypstProject {
      typstOpts = {
        format = "png";
        ppi = 300;
        input = ["key1=value1" "key2=value2"];
      };
    };
  in {
    apps.${system}.default = {
      type = "app";
      program = lib.getExe watch-script;
    };
  };
}
```

...will result in a command like:

<!-- ANCHOR_END: watchtypstproject -->

<!-- ANCHOR: typstcompile -->

```sh
typst compile --format png --ppi 300 --input key1=value1 --input key2=value2 <source> <output>
```

<!-- ANCHOR_END: typstcompile -->

<!-- ANCHOR: typstwatch -->

```sh
typst watch --format png --ppi 300 --input key1=value1 --input key2=value2 <source> <output>
```

<!-- ANCHOR_END: typstwatch -->


================================================
FILE: docs/api/derivations/common/typst-opts.md
================================================
<!-- markdownlint-disable-file first-line-h1 -->

<!-- ANCHOR: head -->

Attrset specifying command-line options to pass to the `typst` command.

<!-- ANCHOR_END: head -->

<!-- ANCHOR: tail -->

Default:

```nix
{
  format = "pdf";
}
```

<!-- ANCHOR_END: tail -->


================================================
FILE: docs/api/derivations/common/typst-packages.md
================================================
<!-- markdownlint-disable first-line-h1 -->

<!-- ANCHOR: body -->

<div class="warning">

This is an **unstable** feature. Its API does not follow Semantic Versioning, and
derivations relying on this feature may break at any time, even if you don't
update Typst or Typix.

When this feature reaches stability, it will be renamed to `typstPackages`.
(The old name will be kept as an undocumented alias, to avoid unnecessary
breakage.)

</div>

List of [Typst packages] to use in your Typst project, fetched from the
official Typst packages CDN at `https://packages.typst.org`.

Each element of the list is an attribute set with the following keys:

- `name`: the package's identifier in its namespace
- `version`: the package's version as a full major-minor-patch triple
- `namespace` _(optional)_: the package's namespace (defaults to `preview`)
- `hash`: hash of the downloaded package tarball

`hash` must be manually updated to match the hash of the package tarball downloaded
from the registry, using the "fake hash method". See [Updating source hashes][fetchers-hash]
for how to do this.

Sometimes, you might encounter a Typst compilation error that looks like this:

```text
> help: error occurred while importing this module
>   ┌─ @preview/cetz:0.3.4/src/canvas.typ:3:8
>   │
> 3 │ #import "util.typ"
>   │         ^^^^^^^^^^
> help: error occurred while importing this module
>   ┌─ @preview/cetz:0.3.4/src/lib.typ:3:8
>   │
> 3 │ #import "canvas.typ": canvas
>   │         ^^^^^^^^^^^^
> help: error occurred while importing this module
>   ┌─ main.typ:1:8
>   │
> 1 │ #import "@preview/cetz:0.3.4"
>   │         ^^^^^^^^^^^^^^^^^^^^^
>
For full logs, run 'nix log /nix/store/6jhjxbl7glmy4adpr5wzfgn9jvsyyipf-typst.drv'.
```

In this example, Nix is hiding too much output for us to diagnose the issue.
Run the command again with the [`-L` flag] (in our case, `nix run .#build -L`):

[`-L` flag]: https://nix.dev/manual/nix/2.18/command-ref/new-cli/nix3-run#opt-print-build-logs

```text
> downloading @preview/oxifmt:0.2.1
> error: failed to download package (Network Error: OpenSSL error)
>   ┌─ @preview/cetz:0.3.4/src/deps.typ:1:8
>   │
> 1 │ #import "@preview/oxifmt:0.2.1"
>   │         ^^^^^^^^^^^^^^^^^^^^^^^
> help: error occurred while importing this module
>   ┌─ @preview/cetz:0.3.4/src/util.typ:1:8
>   │
> 1 │ #import "deps.typ"
>   │         ^^^^^^^^^^
> help: error occurred while importing this module
>   ┌─ @preview/cetz:0.3.4/src/canvas.typ:3:8
>   │
> 3 │ #import "util.typ"
>   │         ^^^^^^^^^^
> help: error occurred while importing this module
>   ┌─ @preview/cetz:0.3.4/src/lib.typ:3:8
>   │
> 3 │ #import "canvas.typ": canvas
>   │         ^^^^^^^^^^^^
> help: error occurred while importing this module
>   ┌─ main.typ:1:8
>   │
> 1 │ #import "@preview/cetz:0.3.4"
>   │         ^^^^^^^^^^^^^^^^^^^^^
```

We can see that `cetz` is trying to import `oxifmt` 0.2.1, but Typst can't
download it because Nix derivations are (by design) run in an environment
which does not support networking. To fix this, add `oxifmt` 0.2.1 to
`unstable_typstPackages` alongside your direct dependencies.
(Make sure to match the exact version shown in your error message!!)

There is currently no official support for [unpublished Typst packages].
However, there is a [workaround].

[Typst packages]: https://github.com/typst/packages
[fetchers-hash]: https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-fetchers-updating-source-hashes
[unpublished Typst packages]: https://github.com/typst/packages#local-packages
[workaround]: ../../recipes/using-typst-packages.md#unpublished-typst-packages

<!-- ANCHOR_END: body -->

<!-- ANCHOR: example_buildtypstproject -->

```nix
{
  outputs = { typix }: let
    system = "x86_64-linux";
  in {
    packages.${system}.default = typix.lib.${system}.buildTypstProject {
      unstable_typstPackages = [
        {
          name = "cetz";
          version = "0.3.4";
          hash = "sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=";
        }
        # Transitive dependencies must be manually specified
        # `oxifmt` is required by `cetz`
        {
          name = "oxifmt";
          version = "0.2.1";
          hash = "sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=";
        }
      ];
    };
  };
}
```

<!-- ANCHOR_END: example_buildtypstproject -->

<!-- ANCHOR: example_buildtypstprojectlocal -->

```nix
{
  outputs = { nixpkgs, typix }: let
    inherit (nixpkgs) lib;
    system = "x86_64-linux";

    build-script = typix.lib.${system}.buildTypstProjectLocal {
      unstable_typstPackages = [
        {
          name = "cetz";
          version = "0.3.4";
          hash = "sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=";
        }
        # Transitive dependencies must be manually specified
        # `oxifmt` is required by `cetz`
        {
          name = "oxifmt";
          version = "0.2.1";
          hash = "sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=";
        }
      ];
    };
  in {
    apps.${system}.default = {
      type = "app";
      program = lib.getExe build-script;
    };
  };
}
```

<!-- ANCHOR_END: example_buildtypstprojectlocal -->

<!-- ANCHOR: example_mktypstderivation -->

```nix
{
  outputs = { typix }: let
    system = "x86_64-linux";
  in {
    packages.${system}.default = typix.lib.${system}.mkTypstDerivation {
      unstable_typstPackages = [
        {
          name = "cetz";
          version = "0.3.4";
          hash = "sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=";
        }
        # Transitive dependencies must be manually specified
        # `oxifmt` is required by `cetz`
        {
          name = "oxifmt";
          version = "0.2.1";
          hash = "sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=";
        }
      ];
    };
  };
}
```

<!-- ANCHOR_END: example_mktypstderivation -->

<!-- ANCHOR: example_typst -->

Then you can import and use the package in Typst:

```typst
#import "@preview/cetz:0.3.4"

#cetz.canvas({
  import cetz.draw: *

  circle((0, 0))
  line((0, 0), (2, 1))
})
```

<!-- ANCHOR_END: example_typst -->


================================================
FILE: docs/api/derivations/common/typst-project-output.md
================================================
<!-- markdownlint-disable-file first-line-h1 -->

<!-- ANCHOR: head -->

Destination path for Typst output.

<!-- ANCHOR_END: head -->

<!-- ANCHOR: buildtypstprojectlocal -->

<!-- markdownlint-disable link-fragments -->

If omitted, it will be inferred from
[`typstSource`](#typstsource) — for example,
`page.typ` will become `page.pdf` for PDF output.

<!-- markdownlint-restore -->

<!-- ANCHOR_END: buildtypstprojectlocal -->

<!-- ANCHOR: watchtypstproject -->

<!-- markdownlint-disable link-fragments -->

If omitted, it will be inferred from
[`typstSource`](#typstsource) — for example,
`page.typ` will become `page.pdf` for PDF output.

<!-- markdownlint-restore -->

<!-- ANCHOR_END: watchtypstproject -->


================================================
FILE: docs/api/derivations/common/typst-project-source.md
================================================
<!-- markdownlint-disable-file first-line-h1 -->

Typst input file to compile.


================================================
FILE: docs/api/derivations/common/virtual-paths-example.md
================================================
<!-- markdownlint-disable-file first-line-h1 -->

<!-- ANCHOR: head -->

You can specify dependencies in your flake input, and then use them in your
project with something like:

<!-- ANCHOR_END: head -->

<!-- ANCHOR: buildtypstprojectlocal_example -->

```nix
{
  inputs = {
    font-awesome = {
      url = "github:FortAwesome/Font-Awesome";
      flake = false;
    };
  };

  outputs = { nixpkgs, typix, font-awesome }: let
    system = "x86_64-linux";
    inherit (nixpkgs) lib;

    build-script = typix.lib.${system}.buildTypstProjectLocal {
      virtualPaths = [
        {
          dest = "icons";
          src = "${font-awesome}/svgs/regular";
        }
      ];
    };
  in {
    apps.${system}.default = {
      type = "app";
      program = lib.getExe build-script;
    };
  };
}
```

<!-- ANCHOR_END: buildtypstprojectlocal_example -->

<!-- ANCHOR: buildtypstproject_example -->

```nix
{
  inputs = {
    font-awesome = {
      url = "github:FortAwesome/Font-Awesome";
      flake = false;
    };
  };

  outputs = { typix, font-awesome }: let
    system = "x86_64-linux";
  in {
    packages.${system}.default = typix.lib.${system}.buildTypstProject {
      virtualPaths = [
        {
          dest = "icons";
          src = "${font-awesome}/svgs/regular";
        }
      ];
    };
  };
}
```

<!-- ANCHOR_END: buildtypstproject_example -->

<!-- ANCHOR: devshell_example -->

```nix
{
  inputs = {
    font-awesome = {
      url = "github:FortAwesome/Font-Awesome";
      flake = false;
    };
  };

  outputs = { typix, font-awesome }: let
    system = "x86_64-linux";
  in {
    devShells.${system}.default = typix.lib.${system}.devShell {
      virtualPaths = [
        {
          dest = "icons";
          src = "${font-awesome}/svgs/regular";
        }
      ];
    };
  };
}
```

<!-- ANCHOR_END: devshell_example -->

<!-- ANCHOR: mktypstderivation_example -->

```nix
{
  inputs = {
    font-awesome = {
      url = "github:FortAwesome/Font-Awesome";
      flake = false;
    };
  };

  outputs = { typix, font-awesome }: let
    system = "x86_64-linux";
  in {
    packages.${system}.default = typix.lib.${system}.mkTypstDerivation {
      virtualPaths = [
        {
          dest = "icons";
          src = "${font-awesome}/svgs/regular";
        }
      ];
    };
  };
}
```

<!-- ANCHOR_END: mktypstderivation_example -->

<!-- ANCHOR: watchtypstproject_example -->

```nix
{
  inputs = {
    font-awesome = {
      url = "github:FortAwesome/Font-Awesome";
      flake = false;
    };
  };

  outputs = { nixpkgs, typix, font-awesome }: let
    system = "x86_64-linux";
    inherit (nixpkgs) lib;

    watch-script = typix.lib.${system}.watchTypstProject {
      virtualPaths = [
        {
          dest = "icons";
          src = "${font-awesome}/svgs/regular";
        }
      ];
    };
  in {
    apps.${system}.default = {
      type = "app";
      program = lib.getExe watch-script;
    };
  };
}
```

<!-- ANCHOR_END: watchtypstproject_example -->

<!-- ANCHOR: typst_example -->

```typst
#image("icons/heart.svg")
```

<!-- ANCHOR_END: typst_example -->

<!-- ANCHOR: tail -->

Then, reference the files in Typst:

```typst
#image("icons/heart.svg")
```

<!-- ANCHOR_END: tail -->


================================================
FILE: docs/api/derivations/common/virtual-paths.md
================================================
<!-- markdownlint-disable-file first-line-h1 -->

List of sources that will be made virtually available to your Typst project.
Useful for projects which rely on remote resources, such as
[images][typst-ref-image] or [data][typst-ref-data-loading].

Each element of the list is an attribute set with the following keys:

- `src`: path to source file or directory
- `dest` _(optional)_: path where file(s) will be made available (defaults to `.`)
  - If `src` is a directory, `dest` will be a directory containing the files in that directory.
    - Specifying the same `dest` for multiple `src` directories will merge them.
  - If `src` is a file, `dest` will be a copy of that file.

Instead of an attrset, you may use a path which will be interpreted the same as
if you had specified an attrset with just `src`.

[typst-ref-data-loading]: https://typst.app/docs/reference/data-loading/
[typst-ref-image]: https://typst.app/docs/reference/visualize/image/


================================================
FILE: docs/api/derivations/dev-shell.md
================================================
# devShell

Sets up a shell environment that activates with [`nix develop`][nix-ref-develop]
or [`direnv`][direnv].

## Parameters

**Note:** All parameters for [`mkShell`][nixpkgs-mkshell] are also
supported.

### `emojiFont` <sup><em>optional</em></sup> { #emojifont }

{{#include common/emoji-font.md}}

### extraShellHook <sup><em>optional</em></sup> { #extrashellhook }

Bash statements added to the [`shellHook`][nixpkgs-mkshell-attributes]
attribute.

### `fontPaths` <sup><em>optional</em></sup> { #fontpaths }

{{#include common/font-paths.md}}

#### Example { #fontpaths-example }

{{#include common/font-paths-example.md:devshell_example}}

### `forceVirtualPaths` <sup><em>optional</em></sup> { #forcevirtualpaths }

<!-- markdownlint-disable link-fragments -->

If there are any conflicts between [`virtualPaths`](#virtualpaths) and files in your
project directory, they will not be overwritten unless `forceVirtualPaths` is
`true`.

Default is `false`.

<!-- markdownlint-restore -->

### `virtualPaths` <sup><em>optional</em></sup> { #virtualpaths }

{{#include common/virtual-paths.md}}

<!-- markdownlint-disable link-fragments -->

**NOTE:** Any paths specified here will not overwrite files in your project
directory, unless you set [`forceVirtualPaths`](#forcevirtualpaths) to `true`.

<!-- markdownlint-restore -->

#### Example { #virtualpaths-example }

{{#include common/virtual-paths-example.md:head}}
{{#include common/virtual-paths-example.md:devshell_example}}
{{#include common/virtual-paths-example.md:tail}}

## Source

- [`devShell`](https://github.com/loqusion/typix/blob/main/lib/devShell.nix)

[direnv]: https://direnv.net/
[nix-ref-develop]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-develop
[nixpkgs-mkshell-attributes]: https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-mkShell-attributes
[nixpkgs-mkshell]: https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-mkShell


================================================
FILE: docs/api/derivations/mk-typst-derivation.md
================================================
# mkTypstDerivation

A generic derivation constructor for running Typst commands.

## Parameters

**Note:** All parameters for `stdenv.mkDerivation`[^stdenv] are also available.

### `buildPhaseTypstCommand`

Command (or commands) to run during [`buildPhase`][nixpkgs-buildphase]. Any
output should typically be written to `$out`, e.g. `typst compile <source>
"$out"`.

See also: [Typst CLI Usage][typst-cli-usage]

### `src`

{{#include common/src.md}}

### `emojiFont` <sup><em>optional</em></sup> { #emojifont }

{{#include common/emoji-font.md}}

### `fontPaths` <sup><em>optional</em></sup> { #fontpaths }

{{#include common/font-paths.md}}

#### Example { #fontpaths-example }

{{#include common/font-paths-example.md:mktypstderivation_example}}

### `installPhaseCommand` <sup><em>optional</em></sup> { #installphasecommand }

{{#include common/install-phase-command.md}}

### `unstable_typstPackages` <sup><em>optional</em></sup> { #typstpackages }

{{#include common/typst-packages.md:body}}

#### Example { #typstpackages-example }

{{#include common/typst-packages.md:example_mktypstderivation}}
{{#include common/typst-packages.md:example_typst}}

### `virtualPaths` <sup><em>optional</em></sup> { #virtualpaths }

{{#include common/virtual-paths.md}}

#### Example { #virtualpaths-example }

{{#include common/virtual-paths-example.md:head}}
{{#include common/virtual-paths-example.md:mktypstderivation_example}}
{{#include common/virtual-paths-example.md:tail}}

## Source

- [`mkTypstDerivation`](https://github.com/loqusion/typix/blob/main/lib/mkTypstDerivation.nix)

## Footnotes

[^stdenv]: [`stdenv`][nixpkgs-stdenv] (not for the faint of heart)

[nixpkgs-buildphase]: https://nixos.org/manual/nixpkgs/stable/#build-phase
[nixpkgs-stdenv]: https://nixos.org/manual/nixpkgs/stable/#chap-stdenv
[typst-cli-usage]: https://github.com/typst/typst#usage


================================================
FILE: docs/api/derivations/watch-typst-project.md
================================================
# watchTypstProject

Returns a derivation for a script that watches an input file and recompiles on
changes.

## Parameters

**Note:** All parameters for
[`writeShellApplication`][nixpkgs-writeshellapplication] are also supported
(besides `text`).

### `emojiFont` <sup><em>optional</em></sup> { #emojifont }

{{#include common/emoji-font.md}}

### `fontPaths` <sup><em>optional</em></sup> { #fontpaths }

{{#include common/font-paths.md}}

#### Example { #fontpaths-example }

{{#include common/font-paths-example.md:watchtypstproject_example}}

### `forceVirtualPaths` <sup><em>optional</em></sup> { #forcevirtualpaths }

<!-- markdownlint-disable link-fragments -->

If there are any conflicts between [`virtualPaths`](#virtualpaths) and files in your
project directory, they will not be overwritten unless `forceVirtualPaths` is
`true`.

Default is `false`.

<!-- markdownlint-restore -->

### `scriptName` <sup><em>optional</em></sup> { #scriptname }

{{#include common/script-name.md}}

Default is `typst-watch`.

### `typstOpts` <sup><em>optional</em></sup> { #typstopts }

{{#include common/typst-opts.md:head}}

<!-- markdownlint-disable link-fragments -->

These are in addition to any options you manually pass in
[`typstWatchCommand`](#typstwatchcommand).

<!-- markdownlint-restore -->

{{#include common/typst-opts.md:tail}}

#### Example { #typstopts-example }

{{#include common/typst-opts-example.md:watchtypstproject}}
{{#include common/typst-opts-example.md:typstwatch}}

### `typstOutput` <sup><em>optional</em></sup> { #typstoutput }

{{#include common/typst-project-output.md:head}}
{{#include common/typst-project-output.md:watchtypstproject}}

### `typstSource` <sup><em>optional</em></sup> { #typstsource }

{{#include common/typst-project-source.md}}

Default is `main.typ`.

### `typstWatchCommand` <sup><em>optional</em></sup> { #typstwatchcommand }

Base Typst command to run to watch the project. Other arguments will be appended
based on the other parameters you supply.

Default is `typst watch`.

### `virtualPaths` <sup><em>optional</em></sup> { #virtualpaths }

{{#include common/virtual-paths.md}}

<!-- markdownlint-disable link-fragments -->

**NOTE:** Any paths specified here will not overwrite files in your project
directory, unless you set [`forceVirtualPaths`](#forcevirtualpaths) to `true`.

<!-- markdownlint-restore -->

#### Example { #virtualpaths-example }

{{#include common/virtual-paths-example.md:head}}
{{#include common/virtual-paths-example.md:watchtypstproject_example}}
{{#include common/virtual-paths-example.md:tail}}

## Source

- [`watchTypstProject`](https://github.com/loqusion/typix/blob/main/lib/watchTypstProject.nix)

[nixpkgs-writeshellapplication]: https://nixos.org/manual/nixpkgs/stable/#trivial-builder-writeShellApplication


================================================
FILE: docs/api/derivations.md
================================================
# Derivations

As paraphrased from [the Nix Reference Manual][nix-ref-derivations]:

> A derivation is a specification for running an executable on precisely defined
> input files to repeatably produce output files at uniquely determined file
> system paths.

The derivation constructors defined in Typix extend this behavior by running
`typst compile`/`typst watch` in a context where all the dependencies of your
Typst project (fonts, images, etc.) will be made available to the Typst
compiler, regardless of if they're already present on the system it runs on.

- [`buildTypstProjectLocal`](derivations/build-typst-project-local.md) — Returns
  a derivation for compiling a Typst project and copying the output to the
  current directory.
- [`buildTypstProject`](derivations/build-typst-project.md) — Returns a
  derivation for compiling a Typst project.
- [`devShell`](derivations/dev-shell.md) — Sets up a shell environment that
  activates with [`nix develop`][nix-ref-develop] or [`direnv`][direnv].
- [`mkTypstDerivation`](derivations/mk-typst-derivation.md) — A generic
  derivation constructor for running Typst commands.
- [`watchTypstDerivation`](derivations/watch-typst-project.md) — Returns a
  derivation for a script that watches an input file and recompiles on changes.

[direnv]: https://direnv.net/
[nix-ref-derivations]: https://nixos.org/manual/nix/stable/language/derivations.html
[nix-ref-develop]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-develop


================================================
FILE: docs/api/utilities/clean-typst-source.md
================================================
# cleanTypstSource

Filters a source tree to only contain files that are usually pertinent to a
Typst project.

<!-- markdownlint-disable heading-increment -->

#### Example

<!-- markdownlint-restore -->

```nix
{
  outputs = {
    nixpkgs,
    typix,
  }: let
    system = "x86_64-linux";
    typixLib = typix.lib.${system};
  in {
    packages.${system}.default = typixLib.mkTypstDerivation {
      src = typixLib.cleanTypstSource ./.;
    };
  };
}
```


================================================
FILE: docs/api/utilities.md
================================================
# Utilities

- [`cleanTypstSource`](./utilities/clean-typst-source.md)


================================================
FILE: docs/book.toml
================================================
[book]
authors = ["loqusion"]
language = "en"
src = "."
title = "Typix"

[output.html]
default-theme = "ayu"
preferred-dark-theme = "ayu"
git-repository-url = "https://github.com/loqusion/typix"
edit-url-template = "https://github.com/loqusion/typix/edit/main/docs/{path}"


================================================
FILE: docs/getting-started.md
================================================
# Getting Started

First, [install Nix][install-nix]:

[install-nix]: https://github.com/DeterminateSystems/nix-installer

<!-- markdownlint-disable MD013 -->

```bash
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
```

<!-- markdownlint-enable MD013 -->

Make sure `nix-command` and `flakes` are enabled:

`~/.config/nix/nix.conf`

```ini
experimental-features = nix-command flakes
```

Finally, you can initialize a flake from the default template:

```bash
nix flake init --refresh -t github:loqusion/typix
```

> Alternatively, you can use a template demonstrating [Typst packages] usage:
>
> ```bash
> nix flake init --refresh -t 'github:loqusion/typix#with-typst-packages'
> ```
>
> [Typst packages]: ./recipes/using-typst-packages.md

---

Here are some commands you can run from any template:

- `nix run .#watch` — watch the input files and recompile on changes
- `nix run .#build` — compile and copy the output to the current directory

For more info, see [`nix run --help`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-run).


================================================
FILE: docs/recipes/adding-dependencies.md
================================================
# Adding dependencies

You can add dependencies to your [flake
inputs][nix-ref-flake-inputs][^zero-to-nix-flakes] so that Typst compilation
does not depend on the transient state of the local system: instead, any
dependencies are automatically fetched and made available in a sandboxed
environment.

Examples of dependencies you might want to add:

- [Font files][typst-ref-text--font] —
  [`fontPaths`](../api/derivations/mk-typst-derivation.md#fontpaths)
- [Image files][typst-ref-image] —
  [`virtualPaths`](../api/derivations/mk-typst-derivation.md#virtualpaths)
- [Data files][typst-ref-data-loading] (e.g. [JSON][typst-ref-data-json],
  [TOML][typst-ref-data-toml], [XML][typst-ref-data-xml]) —
  [`virtualPaths`](../api/derivations/mk-typst-derivation.md#virtualpaths)

For a more complete description of how to specify flake inputs, see the Nix
Reference Manual [section on flakerefs][nix-ref-flake-references].

[^zero-to-nix-flakes]: See also: <https://zero-to-nix.com/concepts/flakes>

## nixpkgs

Many popular fonts are available as packages to [nixpkgs][nixpkgs], so if you're
wanting to add a font it's good to try that before anything else.

To determine the path(s) to the files you wish to include, first run the
following command (which creates a symbolic link named `result` in the current
directory):

```bash
nix-build '<nixpkgs>' --out-link result --attr PACKAGE_NAME
```

Then explore the `result` with whichever commands you like — for instance, using
[`unix-tree`][unix-tree]:

```bash
tree ./result
```

```text
result
└── share
    └── fonts
        └── truetype
            ├── Roboto-BlackItalic.ttf
            ├── Roboto-Black.ttf
            ├── Roboto-BoldItalic.ttf
            ├── Roboto-Bold.ttf
            ├── RobotoCondensed-BoldItalic.ttf
            ├── RobotoCondensed-Bold.ttf
            ├── RobotoCondensed-Italic.ttf
            ├── RobotoCondensed-LightItalic.ttf
            ├── RobotoCondensed-Light.ttf
            ├── RobotoCondensed-MediumItalic.ttf
            ├── RobotoCondensed-Medium.ttf
            ├── RobotoCondensed-Regular.ttf
            ├── Roboto-Italic.ttf
            ├── Roboto-LightItalic.ttf
            ├── Roboto-Light.ttf
            ├── Roboto-MediumItalic.ttf
            ├── Roboto-Medium.ttf
            ├── Roboto-Regular.ttf
            ├── Roboto-ThinItalic.ttf
            └── Roboto-Thin.ttf
```

Here, we can see that the relative path should be `share/fonts/truetype`, so in
`flake.nix` we use that information like so:

{{#include ../api/derivations/common/font-paths-example.md:mktypstderivation_example}}

## GitHub

[GitHub](https://github.com) hosts a great deal of fonts and icon libraries, and
Nix makes it easy to add GitHub repositories as flake inputs with [URL-like
syntax][nix-ref-flake-url].

Here's an example of specifying a GitHub URL as a flake input and adding it to
[`virtualPaths`](../api/derivations/mk-typst-derivation.md#virtualpaths), specifying
that we want the `svgs/regular` directory to be accessible from `icons`:

{{#include ../api/derivations/common/virtual-paths-example.md:mktypstderivation_example}}

With this, we can use it in Typst as if it were any other local path:

{{#include ../api/derivations/common/virtual-paths-example.md:typst_example}}

## Using local files

If all else fails, you can always manually download what you need and move it to
your Typst project directory.

Here's what you need to know:

- The Typst compiler invoked by
  [`buildTypstProject`](../api/derivations/build-typst-project.md),
  [`buildTypstProjectLocal`](../api/derivations/build-typst-project-local.md),
  etc. won't see the files you've added unless they're present in one of the
  source tree parameters — in practice, these are
  [`src`](../api/derivations/mk-typst-derivation.md#src),
  [`fontPaths`](../api/derivations/mk-typst-derivation.md#fontpaths), and
  [`virtualPaths`](../api/derivations/mk-typst-derivation.md#virtualpaths). (This
  doesn't apply to
  [`watchTypstProject`](../api/derivations/watch-typst-project.md).)
- Paths to font files must still be passed in
  [`fontPaths`](../api/derivations/mk-typst-derivation.md#fontpaths) or
  otherwise made known to the Typst compiler (e.g. via
  [`--font-path`][typst-man-compile--font-path]).

See ["Specifying sources"](./specifying-sources.md#expanding-a-source-tree) for
information on how to expand a source tree to include the files you need.

[nix-ref-flake-inputs]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake#flake-inputs
[nix-ref-flake-references]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake#flake-references
[nix-ref-flake-url]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake#url-like-syntax
[nixpkgs]: https://search.nixos.org/packages
[typst-man-compile--font-path]: https://man.archlinux.org/man/typst-compile.1.en#font
[typst-ref-data-json]: https://typst.app/docs/reference/data-loading/json/
[typst-ref-data-loading]: https://typst.app/docs/reference/data-loading/
[typst-ref-data-toml]: https://typst.app/docs/reference/data-loading/toml/
[typst-ref-data-xml]: https://typst.app/docs/reference/data-loading/xml/
[typst-ref-image]: https://typst.app/docs/reference/visualize/image/
[typst-ref-text--font]: https://typst.app/docs/reference/text/text/#parameters-font
[unix-tree]: https://gitlab.com/OldManProgrammer/unix-tree


================================================
FILE: docs/recipes/declaring-a-shell-environment.md
================================================
# Declaring a shell environment

You can automatically pull your project's dependencies into your shell by
declaring a [shell environment][nix-dev-declarative-shell] and then activating
it with [`nix develop`][nix-ref-develop] or [`direnv`][direnv].

Here's an example in a flake using Typix's
[`devShell`](../api/derivations/dev-shell.md):

```nix
{
  outputs = { typix }: let
    system = "x86_64-linux";
    typixLib = typix.lib.${system};

    watch-script = typixLib.watchTypstProject {/* ... */};
  in {
    # packages, apps, etc. omitted

    devShells.${system}.default = typixLib.devShell {
      fontPaths = [/* ... */];
      virtualPaths = [/* ... */];
      packages = [
        watch-script
      ];
    };
  };
}
```

What this example does:

- Fonts added to [`fontPaths`](../api/derivations/dev-shell.md#fontpaths) will
  be made available to `typst` commands via the `TYPST_FONT_PATHS` environment
  variable.
- Files in [`virtualPaths`](../api/derivations/dev-shell.md#virtualpaths) will be
  recursively symlinked to the current directory (only overwriting existing
  files when
  [`forceVirtualPaths`](../api/derivations/dev-shell.md#forcevirtualpaths) is
  `true`).
- For convenience, the
  [`typst-watch`](../api/derivations/watch-typst-project.md#scriptname) script
  is added, which will run
  [`watchTypstProject`](../api/derivations/watch-typst-project.md).

[direnv]: https://direnv.net/
[nix-dev-declarative-shell]: https://nix.dev/tutorials/first-steps/declarative-shell
[nix-ref-develop]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-develop


================================================
FILE: docs/recipes/specifying-sources.md
================================================
# Specifying sources

A number of derivations in Typix accept source trees as parameters, such as
[`src`](../api/derivations/mk-typst-derivation.md#src),
[`fontPaths`](../api/derivations/mk-typst-derivation.md#fontpaths), and
[`virtualPaths`](../api/derivations/mk-typst-derivation.md#virtualpaths). Specifying
these is usually as simple as
[`cleanTypstSource`](../api/utilities/clean-typst-source.md) in the case of
`src` and string interpolation (via `${...}`) in the case of `fontPaths` and
`virtualPaths`, but there are situations where more is required or desirable.

## Expanding a source tree

> TL;DR: you can use [`lib.sources.cleanSource`][nixpkgs-sources-cleansource],
> but the problem with this approach is that every change to a file tracked by
> git will invalidate the cache and trigger a rebuild.

To include more _local files_[^fileset-note] in a source tree, you can use a
combination of different functions in [`lib.fileset`][nixpkgs-fileset]
such as [`lib.fileset.unions`][nixpkgs-fileset-unions],
[`lib.fileset.fromSource`][nixpkgs-fileset-fromsource], and
[`lib.fileset.toSource`][nixpkgs-fileset-tosource], like so:

```nix
{
  outputs = { nixpkgs, typix }: let
    system = "x86_64-linux";
    pkgs = nixpkgs.legacyPackages.${system};
    inherit (pkgs) lib;
    typixLib = typix.lib.${system};
    myTypstSource = typixLib.cleanTypstSource ./.;
  in {
    packages.${system}.default = typixLib.mkTypstDerivation {
      src = lib.fileset.toSource {
        root = ./.;
        fileset = lib.fileset.unions [
          (lib.fileset.fromSource myTypstSource)
          ./path.svg
          ./other/path.svg
          ./another
        ];
      };
    };
  };
}
```

This will create a source tree that looks something like:

```text
/nix/store/...
├── another
│  ├── path1.svg
│  ├── path2.svg
│  └── path3.svg
├── path.svg
├── other
│  └── path.svg
└── ...
```

<!-- prettier-ignore-start -->
[^fileset-note]: `lib.fileset` functions can only be used with local files, not
e.g. flake inputs, which is what
[`virtualPaths`](../api/derivations/mk-typst-derivation.md#virtualpaths) is for.
<!-- prettier-ignore-end -->

## Source filtering

You can do source filtering primarily using
[`builtins.filterSource`][nix-ref-builtins-filtersource] and functions in
[`lib.sources`][nixpkgs-sources] such as
[`lib.sources.cleanSourceWith`][nixpkgs-sources-cleansourcewith].

A more detailed explanation can be found in the Nix discussion: ["Filtering
Source Trees with Nix and Nixpkgs"][nix-discussion-source-filtering].

Here's an example which picks specific files by name:

```nix
{
  outputs = { nixpkgs, typix, font-awesome }: let
    system = "x86_64-linux";
    pkgs = nixpkgs.legacyPackages.${system};

    fontAwesomeSubset = let
      icons = [
        "gem.svg"
        "heart.svg"
        "lightbulb.svg"
      ];
    in lib.sources.cleanSourceWith {
      src = "${font-awesome}/svgs/regular";
      filter = path: type:
        builtins.any (icon: builtins.baseNameOf path == icon) icons;
    };
  in {
    packages.${system}.default = typix.lib.${system}.mkTypstDerivation {
      virtualPaths = [
        fontAwesomeSubset
      ];
    };
  };
}
```

[nix-discussion-source-filtering]: https://discourse.nixos.org/t/filtering-source-trees-with-nix-and-nixpkgs/19148
[nix-ref-builtins-filtersource]: https://nixos.org/manual/nix/stable/language/builtins.html#builtins-filterSource
[nixpkgs-fileset-fromsource]: https://nixos.org/manual/nixpkgs/stable/#function-library-lib.fileset.fromSource
[nixpkgs-fileset-tosource]: https://nixos.org/manual/nixpkgs/stable/#function-library-lib.fileset.toSource
[nixpkgs-fileset-unions]: https://nixos.org/manual/nixpkgs/stable/#function-library-lib.fileset.unions
[nixpkgs-fileset]: https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-fileset
[nixpkgs-sources-cleansource]: https://nixos.org/manual/nixpkgs/stable/#function-library-lib.sources.cleanSource
[nixpkgs-sources-cleansourcewith]: https://nixos.org/manual/nixpkgs/stable/#function-library-lib.sources.cleanSourceWith
[nixpkgs-sources]: https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-sources


================================================
FILE: docs/recipes/using-typst-packages.md
================================================
# Using Typst packages

> TL;DR: Use [this example][published-example] as a template:
>
> ```bash
> nix flake init --refresh -t 'github:loqusion/typix#with-typst-packages'
> ```
>
> [published-example]: https://github.com/loqusion/typix/blob/main/examples/typst-packages/flake.nix

<div class="warning">

Typst packages are considered experimental at the time of writing, and the
methods documented here may become outdated at any point if breaking changes are
made upstream.

If you experience any unexpected errors or bugs, and there are no [open issues]
related to your problem, feel free to [open an issue].

[open issues]: https://github.com/loqusion/typix/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22typst+packages%22
[open an issue]: https://github.com/loqusion/typix/issues/new?assignees=&labels=typst+packages&projects=&template=3-typst_packages.md&title=%5BTypst+packages%5D%3A+

</div>

There are two types of [Typst packages][typst-packages]: _published_ and _unpublished_:

- [_Published_ packages](#published-typst-packages) are those submitted to the
  [Typst Packages repository][typst-packages] and can be browsed on [Typst Universe].
- [_Unpublished_ packages](#unpublished-typst-packages) are packages that are
  only available from unofficial sources.
  They can be stored locally on your system, on a GitHub repository, or elsewhere.
  ("Unpublished" can also refer to unpublished versions of a package which has
  published versions.)

[Typst Universe]: https://typst.app/universe/

[Transitive dependencies] — that is, a _dependency's_ dependencies — must be
added explicitly, in addition to any direct dependencies you have. For
instance, `cetz` 0.3.4 depends on `oxifmt` 0.2.1, so if you use `cetz` 0.3.4 you
must also ensure `oxifmt` 0.2.1 is provided. This applies recursively: if you
depend on `A` which depends on `B` and `B` depends on `C`, you must explicitly
specify both `B` _and_ `C`, in addition to `A`. Also, the precise version is
important: if different versions of the same package are imported, _both
versions_ must be specified.

[Transitive dependencies]: https://en.wikipedia.org/wiki/Transitive_dependency

The method to add Typst packages differs depending on whether they are published
or unpublished.

## Published Typst packages

Published Typst packages work out of the box for for [`watchTypstProject`] and
commands executed while [`devShell`] is active.

For [`buildTypstProject`], [`buildTypstProjectLocal`], and [`mkTypstDerivation`],
there are two methods:

<!-- markdownlint-disable link-fragments -->

- [`unstable_typstPackages`](#the-typstpackages-attribute) _(recommended)_
- [`TYPST_PACKAGE_CACHE_PATH`](#the-typst_package_cache_path-environment-variable)

<!-- markdownlint-enable link-fragments -->

It is recommended to use `unstable_typstPackages`, as it is faster and consumes
less disk space.

### The `unstable_typstPackages` attribute { #the-typstpackages-attribute }

The `unstable_typstPackages` attribute is used to fetch packages from the official
Typst packages CDN at `https://packages.typst.org`.

For more information, see the respective documentation for the attribute on
[`buildTypstProject`], [`buildTypstProjectLocal`], and [`mkTypstDerivation`].

```nix
{
  outputs = {
    nixpkgs,
    typix,
  }: let
    inherit (nixpkgs) lib;
    system = "x86_64-linux";

    unstable_typstPackages = [
      {
        name = "cetz";
        version = "0.3.4";
        hash = "sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=";
      }
      # Transitive dependencies must be manually specified
      # `oxifmt` is required by `cetz`
      {
        name = "oxifmt";
        version = "0.2.1";
        hash = "sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=";
      }
    ];

    build-drv = typix.lib.${system}.buildTypstProject {
      inherit unstable_typstPackages;
      # ...
    };

    build-script = typix.lib.${system}.buildTypstProjectLocal {
      inherit unstable_typstPackages;
      # ...
    };
  in {
    packages.${system}.default = build-drv;
    apps.${system}.default = {
      type = "app";
      program = lib.getExe build-script;
    };
  };
}
```

### The `TYPST_PACKAGE_CACHE_PATH` environment variable

This method downloads the _entire_ contents of the [Typst Packages repository][typst-packages],
making all packages available in your Typst project.

First, add the repository to flake inputs:

```nix
{
  inputs.typst-packages = {
    url = "github:typst/packages";
    flake = false;
  };
}
```

Then, use it in flake outputs:

```nix
{
  outputs = {
    nixpkgs,
    typix,
    typst-packages,
  }: let
    inherit (nixpkgs) lib;
    system = "x86_64-linux";

    build-drv = typix.lib.${system}.buildTypstProject {
      TYPST_PACKAGE_CACHE_PATH = "${typst-packages}/packages";
      # ...
    };

    build-script = typix.lib.${system}.buildTypstProjectLocal {
      TYPST_PACKAGE_CACHE_PATH = "${typst-packages}/packages";
      # ...
    };
  in {
    packages.${system}.default = build-drv;
    apps.${system}.default = {
      type = "app";
      program = lib.getExe build-script;
    };
  };
}
```

## Unpublished Typst packages

If the Typst package you want to use is stored locally — in the same repository
as your flake — all you have to do is directly [import] the entrypoint module:

[import]: https://typst.app/docs/reference/foundations/module/

```typst
#import "my-typst-package/src/lib.typ": my-item

#my-item
```

You may want to [expand the source tree] or [filter certain files].

[expand the source tree]: ../recipes/specifying-sources.md#expanding-a-source-tree
[filter certain files]: ../recipes/specifying-sources.md#source-filtering

If the imported module imports any packages, those packages must be specified
using one of the methods documented in this chapter.

If you need to fetch an unpublished Typst package from a GitHub repository instead,
see below.

### Fetching from a GitHub repository

> You can use [this example][unpublished-example] as a template:
>
> ```bash
> nix flake init --refresh -t 'github:loqusion/typix#with-typst-packages-unpublished'
> ```
>
> [unpublished-example]: https://github.com/loqusion/typix/blob/main/examples/typst-packages-unpublished/flake.nix

Add the GitHub repository containing the unpublished Typst package to [flake inputs]:

[flake inputs]: https://nix.dev/manual/nix/2.24/command-ref/new-cli/nix3-flake#flake-references

```nix
{
  inputs = {
    my-typst-package = {
      url = "github:loqusion/my-typst-package";
      flake = false;
    };
  };
}
```

Then, create a derivation containing the inputs and pass it to Typst with
the `TYPST_PACKAGE_PATH` environment variable:

<!-- markdownlint-disable line-length -->

```nix
{
  outputs = {
    nixpkgs,
    typix,
    my-typst-package,
  }: let
    system = "x86_64-linux";
    pkgs = nixpkgs.legacyPackages.${system};
    inherit (pkgs) lib;
    inherit (lib.strings) escapeShellArg;

    mkTypstPackagesDrv = name: entries: let
      linkFarmEntries =
        lib.foldl (set: {
          name,
          version,
          namespace,
          input,
        }:
          set
          // {
            "${namespace}/${name}/${version}" = input;
          })
        {}
        entries;
    in
      pkgs.linkFarm name linkFarmEntries;

    unpublishedTypstPackages = mkTypstPackagesDrv "unpublished-typst-packages" [
      # Unpublished packages can be added here
      {
        name = "my-typst-package";
        version = "0.1.0";
        namespace = "local";
        input = my-typst-package;
      }
    ];

    # Any transitive dependencies on published packages must be added here
    unstable_typstPackages = [
      {
        name = "oxifmt";
        version = "0.2.1";
        hash = "sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=";
      }
    ];

    build-drv = typix.lib.${system}.buildTypstProject {
      inherit unstable_typstPackages;
      TYPST_PACKAGE_PATH = unpublishedTypstPackages;
      # ...
    };

    build-script = typix.lib.${system}.buildTypstProjectLocal {
      inherit unstable_typstPackages;
      TYPST_PACKAGE_PATH = unpublishedTypstPackages;
      # ...
    };

    watch-script = typix.lib.${system}.watchTypstProject {
      # `watchTypstProject` can already access published packages, so
      # `unstable_typstPackages` is not needed here
      typstWatchCommand = "TYPST_PACKAGE_PATH=${escapeShellArg unpublishedTypstPackages} typst watch";
      # ...
    };
  in {
    packages.${system}.default = build-drv;
    apps.${system}.default = {
      type = "app";
      program = lib.getExe build-script;
    };
    apps.${system}.watch = {
      type = "app";
      program = lib.getExe watch-script;
    };
  };
}
```

Finally, you can use the package in a Typst file:

```typst
#import "@local/my-typst-package:0.1.0": *

#nothing
```

<!-- markdownlint-enable line-length -->

[typst-packages]: https://github.com/typst/packages
[`buildTypstProjectLocal`]: ../api/derivations/build-typst-project-local.md#typstpackages
[`buildTypstProject`]: ../api/derivations/build-typst-project.md#typstpackages
[`devShell`]: ../api/derivations/dev-shell.md
[`mkTypstDerivation`]: ../api/derivations/mk-typst-derivation.md#typstpackages
[`watchTypstProject`]: ../api/derivations/watch-typst-project.md


================================================
FILE: examples/.gitignore
================================================
/*/flake.lock
/*/result


================================================
FILE: examples/quick-start/.gitignore
================================================
result*


================================================
FILE: examples/quick-start/flake.nix
================================================
{
  description = "A Typst project";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";

    typix = {
      url = "github:loqusion/typix";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    flake-utils.url = "github:numtide/flake-utils";

    # Example of downloading icons from a non-flake source
    # font-awesome = {
    #   url = "github:FortAwesome/Font-Awesome";
    #   flake = false;
    # };
  };

  outputs = inputs @ {
    nixpkgs,
    typix,
    flake-utils,
    ...
  }:
    flake-utils.lib.eachDefaultSystem (system: let
      pkgs = nixpkgs.legacyPackages.${system};
      inherit (pkgs) lib;

      typixLib = typix.lib.${system};

      src = typixLib.cleanTypstSource ./.;
      commonArgs = {
        typstSource = "main.typ";

        fontPaths = [
          # Add paths to fonts here
          # "${pkgs.roboto}/share/fonts/truetype"
        ];

        virtualPaths = [
          # Add paths that must be locally accessible to typst here
          # {
          #   dest = "icons";
          #   src = "${inputs.font-awesome}/svgs/regular";
          # }
        ];
      };

      # Compile a Typst project, *without* copying the result
      # to the current directory
      build-drv = typixLib.buildTypstProject (commonArgs
        // {
          inherit src;
        });

      # Compile a Typst project, and then copy the result
      # to the current directory
      build-script = typixLib.buildTypstProjectLocal (commonArgs
        // {
          inherit src;
        });

      # Watch a project and recompile on changes
      watch-script = typixLib.watchTypstProject commonArgs;
    in {
      checks = {
        inherit build-drv build-script watch-script;
      };

      packages.default = build-drv;

      apps = rec {
        default = watch;
        build = flake-utils.lib.mkApp {
          drv = build-script;
        };
        watch = flake-utils.lib.mkApp {
          drv = watch-script;
        };
      };

      devShells.default = typixLib.devShell {
        inherit (commonArgs) fontPaths virtualPaths;
        packages = [
          # WARNING: Don't run `typst-build` directly, instead use `nix run .#build`
          # See https://github.com/loqusion/typix/issues/2
          # build-script
          watch-script
          # More packages can be added here, like typstfmt
          # pkgs.typstfmt
        ];
      };
    });
}


================================================
FILE: examples/quick-start/main.typ
================================================
= Lorem ipsum
#lorem(30)


================================================
FILE: examples/typst-packages/flake.nix
================================================
{
  description = "A Typst project that uses Typst packages";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";

    typix = {
      url = "github:loqusion/typix";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    flake-utils.url = "github:numtide/flake-utils";

    # Example of downloading icons from a non-flake source
    # font-awesome = {
    #   url = "github:FortAwesome/Font-Awesome";
    #   flake = false;
    # };
  };

  outputs = inputs @ {
    nixpkgs,
    typix,
    flake-utils,
    ...
  }:
    flake-utils.lib.eachDefaultSystem (system: let
      pkgs = nixpkgs.legacyPackages.${system};
      inherit (pkgs) lib;

      typixLib = typix.lib.${system};

      src = typixLib.cleanTypstSource ./.;
      commonArgs = {
        typstSource = "main.typ";

        fontPaths = [
          # Add paths to fonts here
          # "${pkgs.roboto}/share/fonts/truetype"
        ];

        virtualPaths = [
          # Add paths that must be locally accessible to typst here
          # {
          #   dest = "icons";
          #   src = "${inputs.font-awesome}/svgs/regular";
          # }
        ];
      };

      unstable_typstPackages = [
        {
          name = "cetz";
          version = "0.3.4";
          hash = "sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=";
        }
        # Required by cetz
        {
          name = "oxifmt";
          version = "0.2.1";
          hash = "sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=";
        }
      ];

      # Compile a Typst project, *without* copying the result
      # to the current directory
      build-drv = typixLib.buildTypstProject (commonArgs
        // {
          inherit src unstable_typstPackages;
        });

      # Compile a Typst project, and then copy the result
      # to the current directory
      build-script = typixLib.buildTypstProjectLocal (commonArgs
        // {
          inherit src unstable_typstPackages;
        });

      # Watch a project and recompile on changes
      watch-script = typixLib.watchTypstProject commonArgs;
    in {
      checks = {
        inherit build-drv build-script watch-script;
      };

      packages.default = build-drv;

      apps = rec {
        default = watch;
        build = flake-utils.lib.mkApp {
          drv = build-script;
        };
        watch = flake-utils.lib.mkApp {
          drv = watch-script;
        };
      };

      devShells.default = typixLib.devShell {
        inherit (commonArgs) fontPaths virtualPaths;
        packages = [
          # WARNING: Don't run `typst-build` directly, instead use `nix run .#build`
          # See https://github.com/loqusion/typix/issues/2
          # build-script
          watch-script
          # More packages can be added here, like typstfmt
          # pkgs.typstfmt
        ];
      };
    });
}


================================================
FILE: examples/typst-packages/main.typ
================================================
#import "@preview/cetz:0.3.4"

#cetz.canvas({
  import cetz.draw: *

  circle((0, 0))
  line((0, 0), (2, 1))
})


================================================
FILE: examples/typst-packages-unpublished/flake.nix
================================================
{
  description = "A Typst project that uses unpublished Typst packages";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";

    typix = {
      url = "github:loqusion/typix";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    flake-utils.url = "github:numtide/flake-utils";

    # TODO: Change this and the list in `unpublishedTypstPackages`
    my-typst-package = {
      url = "github:loqusion/my-typst-package";
      flake = false;
    };

    # Example of downloading icons from a non-flake source
    # font-awesome = {
    #   url = "github:FortAwesome/Font-Awesome";
    #   flake = false;
    # };
  };

  outputs = inputs @ {
    nixpkgs,
    typix,
    flake-utils,
    ...
  }:
    flake-utils.lib.eachDefaultSystem (system: let
      pkgs = nixpkgs.legacyPackages.${system};
      inherit (pkgs) lib;
      inherit (lib.strings) escapeShellArg;

      typixLib = typix.lib.${system};

      src = typixLib.cleanTypstSource ./.;
      commonArgs = {
        typstSource = "main.typ";

        fontPaths = [
          # Add paths to fonts here
          # "${pkgs.roboto}/share/fonts/truetype"
        ];

        virtualPaths = [
          # Add paths that must be locally accessible to typst here
          # {
          #   dest = "icons";
          #   src = "${inputs.font-awesome}/svgs/regular";
          # }
        ];
      };

      mkTypstPackagesDrv = name: entries: let
        linkFarmEntries =
          lib.foldl (set: {
            name,
            version,
            namespace,
            input,
          }:
            set
            // {
              "${namespace}/${name}/${version}" = input;
            })
          {}
          entries;
      in
        pkgs.linkFarm name linkFarmEntries;

      unpublishedTypstPackages = mkTypstPackagesDrv "unpublished-typst-packages" [
        {
          name = "my-typst-package";
          version = "0.1.0";
          namespace = "local";
          input = inputs.my-typst-package;
        }
      ];

      # Any transitive dependencies must be added here
      # See https://loqusion.github.io/typix/recipes/using-typst-packages.html#the-typstpackages-attribute
      unstable_typstPackages = [
        {
          name = "oxifmt";
          version = "0.2.1";
          hash = "sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=";
        }
      ];

      # Compile a Typst project, *without* copying the result
      # to the current directory
      build-drv = typixLib.buildTypstProject (commonArgs
        // {
          inherit src;
          inherit unstable_typstPackages;
          TYPST_PACKAGE_PATH = unpublishedTypstPackages;
        });

      # Compile a Typst project, and then copy the result
      # to the current directory
      build-script = typixLib.buildTypstProjectLocal (commonArgs
        // {
          inherit src;
          inherit unstable_typstPackages;
          TYPST_PACKAGE_PATH = unpublishedTypstPackages;
        });

      # Watch a project and recompile on changes
      watch-script = typixLib.watchTypstProject (commonArgs
        // {
          typstWatchCommand = "TYPST_PACKAGE_PATH=${escapeShellArg unpublishedTypstPackages} typst watch";
        });
    in {
      checks = {
        inherit build-drv build-script watch-script;
      };

      packages.default = build-drv;

      apps = rec {
        default = watch;
        build = flake-utils.lib.mkApp {
          drv = build-script;
        };
        watch = flake-utils.lib.mkApp {
          drv = watch-script;
        };
      };

      devShells.default = typixLib.devShell {
        inherit (commonArgs) fontPaths virtualPaths;
        packages = [
          # WARNING: Don't run `typst-build` directly, instead use `nix run .#build`
          # See https://github.com/loqusion/typix/issues/2
          # build-script
          watch-script
          # More packages can be added here, like typstfmt
          # pkgs.typstfmt
        ];
      };
    });
}


================================================
FILE: examples/typst-packages-unpublished/main.typ
================================================
#import "@local/my-typst-package:0.1.0": *

#nothing


================================================
FILE: flake.nix
================================================
{
  description = "Deterministic Typst compilation with Nix";

  nixConfig = {
    extra-substituters = ["https://typst-nix.cachix.org"];
    extra-trusted-public-keys = ["typst-nix.cachix.org-1:OzDUMt0nd4wlI1AHucBPnchl4utWXeFTtUFt8XZ3DbA="];
  };

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
  };

  outputs = {nixpkgs, ...}: let
    inherit (nixpkgs) lib;

    linux32BitSystems = ["i686-linux"];
    linux64BitSystems = ["x86_64-linux" "aarch64-linux"];
    linuxSystems = linux32BitSystems ++ linux64BitSystems;
    darwinSystems = ["x86_64-darwin" "aarch64-darwin"];
    systems = linuxSystems ++ darwinSystems;

    forAllSystems = lib.genAttrs systems;

    pkgsFor = lib.genAttrs systems (system: nixpkgs.legacyPackages.${system});

    mkLib = pkgs:
      import ./lib {
        inherit (pkgs) lib newScope;
      };

    mkReleaseScript = pkgs:
      import ./release.nix {
        inherit pkgs;
      };
  in {
    inherit mkLib;

    overlays.default = _final: _prev: {};

    templates = rec {
      default = quick-start;
      quick-start = {
        description = "A Typst project";
        path = ./examples/quick-start;
      };
      with-typst-packages = {
        description = "A Typst project (with packages)";
        path = ./examples/typst-packages;
      };
      with-typst-packages-unpublished = {
        description = "A Typst project (with unpublished packages)";
        path = ./examples/typst-packages-unpublished;
      };
    };

    checks = forAllSystems (system: let
      pkgs = pkgsFor.${system};
    in (pkgs.callPackages ./checks {
      inherit pkgs;
      myLib = mkLib pkgs;
    }));

    lib = forAllSystems (system: mkLib pkgsFor.${system});

    packages = forAllSystems (system: (
      import ./pkgs.nix {pkgs = pkgsFor.${system};}
    ));

    apps = forAllSystems (system: {
      release = {
        type = "app";
        program = lib.getExe (mkReleaseScript pkgsFor.${system});
      };
    });

    formatter = forAllSystems (system: pkgsFor.${system}.alejandra);

    devShells = forAllSystems (system: let
      pkgs = pkgsFor.${system};
    in {
      default = pkgs.mkShellNoCC {
        nativeBuildInputs = with pkgs; [
          alejandra
          markdownlint-cli
          mdbook
          nodePackages.prettier
        ];
      };
    });
  };
}


================================================
FILE: lib/buildTypstProject.nix
================================================
{
  lib,
  mkTypstDerivation,
  typstOptsFromArgs,
}: args @ {
  typstCompileCommand ? "typst compile",
  typstSource ? "main.typ",
  ...
}: let
  inherit (builtins) removeAttrs;
  inherit (lib.strings) escapeShellArg;

  typstOptsString = args.typstOptsString or (typstOptsFromArgs args);
  cleanedArgs = removeAttrs args [
    "typstCompileCommand"
    "typstOpts"
    "typstOptsString"
    "typstOutput"
    "typstSource"
  ];
in
  mkTypstDerivation (cleanedArgs
    // {
      buildPhaseTypstCommand =
        args.buildPhaseTypstCommand
        or ''
          ${typstCompileCommand} ${typstOptsString} ${escapeShellArg typstSource} "$out"
        '';
    })


================================================
FILE: lib/buildTypstProjectLocal.nix
================================================
{
  buildTypstProject,
  inferTypstProjectOutput,
  lib,
  pkgs,
  typstOptsFromArgs,
}: args @ {typstSource ? "main.typ", ...}: let
  inherit (builtins) removeAttrs;
  inherit (lib.strings) toShellVars;

  typstOptsString = args.typstOptsString or (typstOptsFromArgs args);
  typstOutput =
    args.typstOutput
    or (inferTypstProjectOutput (
      {inherit typstSource;} // args
    ));

  buildTypstProjectDerivation = buildTypstProject (
    cleanedArgs // {inherit typstOptsString typstSource;}
  );
  buildTypstProjectImport = builtins.path {path = buildTypstProjectDerivation;};

  cleanedArgs = removeAttrs args [
    "scriptName"
  ];
in
  pkgs.writeShellApplication {
    name = args.scriptName or "typst-build";

    runtimeInputs = [
      pkgs.coreutils
    ];

    text = ''
      ${toShellVars {inherit typstOutput;}}
      out=''${1:-''${typstOutput:?not defined}}
      mkdir -p "$(dirname "$out")"
      cp -LT --no-preserve=mode ${buildTypstProjectImport} "$out"
    '';
  }


================================================
FILE: lib/cleanTypstSource.nix
================================================
{lib}: src:
lib.cleanSourceWith {
  src = lib.cleanSource src;
  filter = path: type: let
    hasAcceptedSuffix = builtins.any (lib.flip lib.hasSuffix path) [
      ".typ" # Typst files
      ".bib" # BibLaTeX files
    ];
    isSpecialFile = builtins.elem (builtins.baseNameOf path) [
      "typst.toml"
      "metadata.toml"
    ];
  in
    builtins.any lib.id [
      (type == "directory")
      hasAcceptedSuffix
      isSpecialFile
    ];
}


================================================
FILE: lib/coerceVirtualPathAttr.nix
================================================
{lib}: let
  inherit (builtins) isAttrs;
  inherit (lib.strings) isStringLike;
in
  virtualPath:
    if isStringLike virtualPath
    then {
      src = "${virtualPath}";
      dest = ".";
    }
    else if isAttrs virtualPath
    then {
      src = "${virtualPath.src}";
      dest = virtualPath.dest or ".";
    }
    else throw "Invalid virtualPath: must be string or attrset"


================================================
FILE: lib/default.nix
================================================
{
  lib,
  newScope,
}:
lib.makeScope newScope (self: let
  inherit (self) callPackage;
in {
  buildTypstProjectLocal = callPackage ./buildTypstProjectLocal.nix {};
  buildTypstProject = callPackage ./buildTypstProject.nix {};
  cleanTypstSource = callPackage ./cleanTypstSource.nix {};
  coerceVirtualPathAttr = callPackage ./coerceVirtualPathAttr.nix {};
  copyVirtualPathsHook = callPackage ./setupHooks/copyVirtualPaths.nix {};
  devShell = callPackage ./devShell.nix {};
  emojiFontPathFromString = callPackage ./emojiFontPathFromString.nix {};
  inferTypstProjectOutput = callPackage ./inferTypstProjectOutput.nix {};
  linkVirtualPaths = callPackage ./linkVirtualPaths.nix {};
  mkTypstDerivation = callPackage ./mkTypstDerivation.nix {};
  typstOptsFromArgs = callPackage ./typstOptsFromArgs.nix {};
  unsetSourceDateEpochHook = callPackage ./setupHooks/unsetSourceDateEpoch.nix {};
  watchTypstProject = callPackage ./watchTypstProject.nix {};
  fetchTypstPackages = callPackage ./fetchTypstPackages.nix {};
})


================================================
FILE: lib/devShell.nix
================================================
{
  emojiFontPathFromString,
  lib,
  linkVirtualPaths,
  mkShellNoCC,
  typst,
}: args @ {
  checks ? {},
  emojiFont ? "default",
  extraShellHook ? "",
  fontPaths ? [],
  forceVirtualPaths ? false,
  inputsFrom ? [],
  packages ? [],
  virtualPaths ? [],
  ...
}: let
  inherit (builtins) isNull removeAttrs;
  inherit (lib) lists optionalAttrs optionalString;
  inherit (lib.strings) concatStringsSep;

  emojiFontPath = emojiFontPathFromString emojiFont;
  allFontPaths = fontPaths ++ lists.optional (!isNull emojiFontPath) emojiFontPath;

  unsetSourceDateEpochScript = builtins.readFile ./setupHooks/unsetSourceDateEpochScript.sh;

  cleanedArgs = removeAttrs args [
    "checks"
    "emojiFont"
    "extraShellHook"
    "fontPaths"
    "forceVirtualPaths"
    "inputsFrom"
    "virtualPaths"
  ];
in
  mkShellNoCC (cleanedArgs
    // optionalAttrs (allFontPaths != []) {
      TYPST_FONT_PATHS = concatStringsSep ":" allFontPaths;
    }
    // {
      inputsFrom = builtins.attrValues checks ++ inputsFrom;

      packages =
        [
          typst
        ]
        ++ packages;

      shellHook =
        args.shellHook
        or (optionalString (virtualPaths != []) (linkVirtualPaths {
          inherit virtualPaths forceVirtualPaths;
        }))
        + ''
          ${unsetSourceDateEpochScript}
        ''
        + optionalString (extraShellHook != "") ''

          ${extraShellHook}
        '';
    })


================================================
FILE: lib/emojiFontPathFromString.nix
================================================
{
  lib,
  pkgs,
}: emojiFont: let
  inherit (builtins) isNull isString typeOf;
in
  if isString emojiFont
  then
    (
      if emojiFont == "default"
      then "${pkgs.twemoji-color-font}/share/fonts/truetype"
      else if emojiFont == "twemoji"
      then "${pkgs.twemoji-color-font}/share/fonts/truetype"
      else if emojiFont == "twemoji-cbdt"
      then "${pkgs.twitter-color-emoji}/share/fonts/truetype"
      else if emojiFont == "noto"
      then "${pkgs.noto-fonts-color-emoji}/share/fonts/noto"
      else if emojiFont == "noto-monochrome"
      then "${pkgs.noto-fonts-monochrome-emoji}/share/fonts/noto"
      else if emojiFont == "emojione"
      then "${pkgs.emojione}/share/fonts/truetype"
      else throw ''invalid value for `emojiFont`: "${emojiFont}". Must be one of: "twemoji", "twemoji-cbdt", "noto", "noto-monochrome", "emojione", null.''
    )
  else if isNull emojiFont
  then null
  else throw ''invalid type for `emojiFont`: ${typeOf emojiFont}. Must be string or null.''


================================================
FILE: lib/fetchTypstPackages.nix
================================================
{
  fetchurl,
  runCommand,
  lib,
  symlinkJoin,
  stdenvNoCC,
}: let
  inherit (lib.lists) forEach;

  typstPackageRegistry = "https://packages.typst.org";

  # Downloads a tarball from the Typst package registry
  fetchTypstTarball = {
    namespace ? "preview",
    name,
    version,
    hash,
  } @ args:
    fetchurl {
      url = "${typstPackageRegistry}/${namespace}/${name}-${version}.tar.gz";
      inherit hash;
      downloadToTemp = true;

      # The Typst package registry does not produce reproducible tarballs
      # We modify the tarball *before* Nix computes the output hash,
      # per instructions at https://reproducible-builds.org/docs/archives/
      postFetch = ''
        pushd $(mktemp -d)
        mkdir extracted
        tar -xzf $downloadedFile -C extracted
        tar --owner=0 --group=0 --numeric-owner --format=gnu \
                --sort=name --mtime="@1" \
                -czf extracted.tar.gz -C extracted .
        mv ./extracted.tar.gz $out
        popd
      '';
    };

  # Downloads a Typst package from the package registry
  # Places the downloaded package to $out/${namespace}/${name}/${version}
  fetchTypstPackage = {
    namespace ? "preview",
    name,
    version,
    ...
  } @ args: let
    tarball = fetchTypstTarball args;
    packageSubdir = "${namespace}/${name}/${version}";
  in
    runCommand "fetch-typst-package-${namespace}-${name}-${version}" {} ''
      tarball=${tarball}
      mkdir -p $out/${packageSubdir}
      tar -xzf $tarball -C $out/${packageSubdir}
    '';
in
  typstPackages:
    symlinkJoin {
      name = "typst-packages";
      paths = forEach typstPackages fetchTypstPackage;
    }


================================================
FILE: lib/inferTypstProjectOutput.nix
================================================
{lib}: args_: let
  args =
    if builtins.isString args_
    then {typstSource = args_;}
    else args_;
  supportedFormats = ["pdf" "svg" "png" "html"];
  format = ({format = "pdf";} // args.typstOpts or {}).format;
  name = lib.strings.removeSuffix ".typ" (builtins.baseNameOf args.typstSource);
  extension =
    if builtins.elem format supportedFormats
    then format
    else
      lib.flip lib.trivial.warn "" ''
        typix could not infer the typst output extension since ${format} is unsupported
        to silence this warning consider one of the following:
        - set the format option to one of: pdf, svg, png, html
        - set `typstOutput` explicitly
        - if ${format} is supported by typst but not by typix, please open a
          PR at https://github.com/loqusion/typix
      '';
in
  name + lib.optionalString (extension != "") ".${extension}"


================================================
FILE: lib/linkVirtualPaths.nix
================================================
{
  coerceVirtualPathAttr,
  lib,
  pkgs,
}: let
  inherit (builtins) toString;
  inherit (pkgs) symlinkJoin;
  inherit (lib) optionalString;
  inherit (lib.filesystem) pathIsDirectory;
  inherit (lib.strings) concatMapStringsSep toShellVars;

  shellUtils = ''
    _same_path() {
      [ "$(realpath "$1")" = "$(realpath "$2")" ]
    }

    _ensure_parent_exists() {
      mkdir -p "$(dirname "$1")"
    }

    _cleanup_parent() {
      local parent
      parent=$(dirname "$1")
      if ! _same_path "." "$1" && ! _same_path "." "$parent"; then
        rmdir -p --ignore-fail-on-non-empty "$parent"
      fi
    }
  '';
in
  {
    forceVirtualPaths ? false,
    virtualPaths,
  }:
    shellUtils
    + "\n"
    + (concatMapStringsSep
      "\n" (virtualPath_: let
        virtualPath = coerceVirtualPathAttr virtualPath_;
        source =
          if !pathIsDirectory (toString virtualPath.src)
          then virtualPath.src
          else
            (symlinkJoin {
              name = "symlink" + optionalString (virtualPath ? dest) "-${virtualPath.dest}";
              paths = [virtualPath.src];
            });
        lnAdditionalOpts = optionalString forceVirtualPaths "--force";
        cpAdditionalOpts =
          if forceVirtualPaths
          then "--force"
          else "--no-clobber";
      in
        # We don't want a refusal to overwrite existing files to cause nix to fail, so we add `|| true`
        # to the commands this applies to
        ''
          ${toShellVars {
            virtualPathSrc = source;
            virtualPathDest = virtualPath.dest;
          }}

          _ensure_parent_exists "$virtualPathDest"

          if [ -f "$virtualPathSrc" ]; then
            echo "typix: linking ${virtualPath.src} to $virtualPathDest"
            if _same_path "." "$virtualPathDest"; then
              ln ${lnAdditionalOpts} -sv "$virtualPathSrc" "$virtualPathDest" ||
                true
            else
              ln ${lnAdditionalOpts} -sTv "$virtualPathSrc" "$virtualPathDest" ||
                true
            fi
          else
            echo "typix: linking ${virtualPath.src} to $virtualPathDest recursively"
            cp ${cpAdditionalOpts} -RTv --no-dereference --no-preserve=mode "$virtualPathSrc" "$virtualPathDest" ||
              true
          fi

          _cleanup_parent "$virtualPathDest"
        '')
      virtualPaths)


================================================
FILE: lib/mkTypstDerivation.nix
================================================
{
  copyVirtualPathsHook,
  emojiFontPathFromString,
  lib,
  stdenvNoCC,
  typst,
  unsetSourceDateEpochHook,
  fetchTypstPackages,
}: args @ {
  buildPhaseTypstCommand,
  emojiFont ? "default",
  fontPaths ? [],
  installPhaseCommand ? "",
  virtualPaths ? [],
  unstable_typstPackages ? [],
  ...
}:
assert lib.assertMsg (!(builtins.hasAttr "unstableTypstPackages" args)) ''
  `unstableTypstPackages` has been renamed to `unstable_typstPackages`.
''; let
  inherit (builtins) baseNameOf getEnv isNull removeAttrs;
  inherit (lib) lists optionalAttrs;
  inherit (lib.strings) concatStringsSep;

  emojiFontPath = emojiFontPathFromString emojiFont;
  allFontPaths = fontPaths ++ lists.optional (!isNull emojiFontPath) emojiFontPath;

  cleanedArgs = removeAttrs args [
    "buildPhaseTypstCommand"
    "emojiFont"
    "fontPaths"
    "installPhaseCommand"
    "virtualPaths"
    "unstable_typstPackages"
  ];

  name =
    args.name
    or (let
      pwd = getEnv "PWD";
    in
      if pwd != ""
      then baseNameOf pwd
      else "typst");
  nameArgs =
    if args ? version
    then {
      pname = args.pname or name;
      inherit (args) version;
    }
    else {inherit name;};
in
  stdenvNoCC.mkDerivation (cleanedArgs
    // nameArgs
    // optionalAttrs (allFontPaths != []) {
      TYPST_FONT_PATHS = concatStringsSep ":" allFontPaths;
    }
    // optionalAttrs (unstable_typstPackages != []) {
      TYPST_PACKAGE_CACHE_PATH = fetchTypstPackages unstable_typstPackages;
    }
    // {
      nativeBuildInputs =
        (args.nativeBuildInputs or [])
        ++ [
          typst
          (copyVirtualPathsHook virtualPaths)
          unsetSourceDateEpochHook
        ];

      buildPhase =
        args.buildPhase
        or ''
          runHook preBuild
          ${buildPhaseTypstCommand}
          runHook postBuild
        '';

      installPhase =
        args.installPhase
        or ''
          runHook preInstall
          ${installPhaseCommand}
          runHook postInstall
        '';
    })


================================================
FILE: lib/setupHooks/copyVirtualPaths.nix
================================================
{
  coerceVirtualPathAttr,
  lib,
  makeSetupHook,
}: virtualPaths: let
  inherit (lib.strings) concatMapStringsSep toShellVars;
  copyAllVirtualPaths =
    concatMapStringsSep
    "\n" (virtualPath_: let
      virtualPath = coerceVirtualPathAttr virtualPath_;
    in ''
      ${toShellVars {
        virtualPathSrc = virtualPath.src;
        virtualPathDest = virtualPath.dest;
      }}

      echo "Copying $virtualPathSrc to $virtualPathDest"

      _ensure_parent_exists "$virtualPathDest"

      if [ -f "$virtualPathSrc" ] && _same_path "." "$virtualPathDest"; then
        cp -Lv --reflink=auto --no-preserve=mode "$virtualPathSrc" "$virtualPathDest"
      else
        cp -LTRv --reflink=auto --no-preserve=mode "$virtualPathSrc" "$virtualPathDest"
      fi

      _cleanup_parent "$virtualPathDest"
    '')
    virtualPaths;
in
  makeSetupHook {
    name = "copyVirtualPaths";
    substitutions = {
      inherit copyAllVirtualPaths;
    };
  }
  ./copyVirtualPathsHook.sh


================================================
FILE: lib/setupHooks/copyVirtualPathsHook.sh
================================================
_same_path() {
    [ "$(realpath "$1")" = "$(realpath "$2")" ]
}

_ensure_parent_exists() {
    mkdir -p "$(dirname "$1")"
}

_cleanup_parent() {
    local parent
    parent=$(dirname "$1")
    if ! _same_path "." "$1" && ! _same_path "." "$parent"; then
        rmdir -p --ignore-fail-on-non-empty "$parent"
    fi
}

copyVirtualPaths() {
	:
	@copyAllVirtualPaths@
}

preBuildHooks+=(copyVirtualPaths)


================================================
FILE: lib/setupHooks/unsetSourceDateEpoch.nix
================================================
{makeSetupHook}: let
  unsetSourceDateEpochScript = builtins.readFile ./unsetSourceDateEpochScript.sh;
in
  makeSetupHook {
    name = "unsetSourceDateEpoch";
    substitutions = {
      inherit unsetSourceDateEpochScript;
    };
  }
  ./unsetSourceDateEpochHook.sh


================================================
FILE: lib/setupHooks/unsetSourceDateEpochHook.sh
================================================
unsetSourceDateEpoch() {
    @unsetSourceDateEpochScript@
}

preBuildHooks+=(unsetSourceDateEpoch)


================================================
FILE: lib/setupHooks/unsetSourceDateEpochScript.sh
================================================
unset SOURCE_DATE_EPOCH


================================================
FILE: lib/typstOptsFromArgs.nix
================================================
{lib}: origArgs: let
  inherit (builtins) elem isBool isNull tail;
  inherit (lib) optionalAttrs optionalString;
  inherit (lib.attrsets) filterAttrs mapAttrsToList recursiveUpdate;
  inherit (lib.lists) last;
  inherit (lib.strings) concatMapStringsSep concatStringsSep escapeShellArg splitString;

  pathExtension = path: let
    splitPathTail = tail (splitString "." path);
  in
    if (splitPathTail != [])
    then last splitPathTail
    else null;

  inferredFormatFromTypstProjectOutput =
    if ((origArgs ? typstOpts.format) || (! origArgs ? typstOutput))
    then null
    else let
      inherit (origArgs) typstOutput;
      supportedExtensions = ["pdf" "svg" "png" "html"];
      extension = pathExtension typstOutput;
    in
      if (elem extension supportedExtensions)
      then extension
      else null;

  inferredTypstOpts = optionalAttrs (!isNull inferredFormatFromTypstProjectOutput) {
    typstOpts.format = inferredFormatFromTypstProjectOutput;
  };
  defaultArgs = optionalAttrs (! origArgs ? typstOutput) {
    typstOpts.format = "pdf";
  };

  args =
    recursiveUpdate (
      recursiveUpdate defaultArgs inferredTypstOpts
    )
    origArgs;

  parametersFrom = opt: value:
    "--${opt}"
    + optionalString (!isBool value) " ${escapeShellArg value}";
in
  concatStringsSep " " (
    mapAttrsToList
    (
      opt: value:
        if builtins.isList value
        then (concatMapStringsSep " " (parametersFrom opt) value)
        else (parametersFrom opt value)
    )
    (filterAttrs (_: v: v != false && !isNull v) args.typstOpts)
  )


================================================
FILE: lib/watchTypstProject.nix
================================================
{
  emojiFontPathFromString,
  inferTypstProjectOutput,
  lib,
  linkVirtualPaths,
  pkgs,
  typst,
  typstOptsFromArgs,
}: args @ {
  emojiFont ? "default",
  fontPaths ? [],
  forceVirtualPaths ? false,
  typstSource ? "main.typ",
  typstWatchCommand ? "typst watch",
  virtualPaths ? [],
  ...
}: let
  inherit (builtins) isNull removeAttrs;
  inherit (lib) lists optionalString;
  inherit (lib.strings) concatStringsSep toShellVars;

  emojiFontPath = emojiFontPathFromString emojiFont;
  allFontPaths = fontPaths ++ lists.optional (!isNull emojiFontPath) emojiFontPath;
  typstOptsString = args.typstOptsString or (typstOptsFromArgs args);
  typstOutput =
    args.typstOutput
    or (inferTypstProjectOutput (
      {inherit typstSource;} // args
    ));

  unsetSourceDateEpochScript = builtins.readFile ./setupHooks/unsetSourceDateEpochScript.sh;

  cleanedArgs = removeAttrs args [
    "emojiFont"
    "fontPaths"
    "forceVirtualPaths"
    "scriptName"
    "text"
    "typstOpts"
    "typstOptsString"
    "typstOutput"
    "typstSource"
    "typstWatchCommand"
    "virtualPaths"
  ];
in
  pkgs.writeShellApplication (cleanedArgs
    // {
      name = args.scriptName or args.name or "typst-watch";

      runtimeInputs =
        (args.runtimeInputs or [])
        ++ [
          pkgs.coreutils
          typst
        ];

      text =
        optionalString (allFontPaths != []) ''
          export TYPST_FONT_PATHS=${concatStringsSep ":" allFontPaths}
        ''
        + optionalString (virtualPaths != []) (linkVirtualPaths {
          inherit virtualPaths forceVirtualPaths;
        })
        + ''

          ${toShellVars {inherit typstOutput typstSource;}}
          out=''${1:-''${typstOutput:?not defined}}
          mkdir -p "$(dirname "$out")"

          ${unsetSourceDateEpochScript}

          ${typstWatchCommand} ${typstOptsString} "$typstSource" "$out"
        '';
    })


================================================
FILE: pkgs.nix
================================================
{pkgs}: {
  docs = let
    inherit (pkgs) lib;
    root = ./.;
    rootPrefix = builtins.toString root;
    src = lib.sources.cleanSourceWith {
      src = root;
      filter = path: _: let
        relativePath = lib.strings.removePrefix rootPrefix path;
      in
        builtins.any ((lib.flip lib.strings.hasPrefix) relativePath) [
          "/docs"
          "/README.md"
        ];
    };
  in
    pkgs.stdenvNoCC.mkDerivation {
      name = "typix-mdbook";

      inherit src;

      nativeBuildInputs = with pkgs; [mdbook];

      buildPhase = ''
        mdbook build docs --dest-dir "$out"
      '';
    };
}


================================================
FILE: release.nix
================================================
{pkgs}:
pkgs.writeShellApplication {
  name = "github-release";

  runtimeInputs = with pkgs; [
    gh
    git
    nodePackages.semver
  ];

  text = ''
    VALID_INCREMENT_TYPES="major minor patch premajor preminor prepatch prerelease"
    increment=''${1:-patch}
    # shellcheck disable=SC2076
    if [[ ! " $VALID_INCREMENT_TYPES " =~ " $increment " ]]; then
      echo "Invalid increment type: $increment" >&2
      echo "Expected one of: ''${VALID_INCREMENT_TYPES// /, }" >&2
      exit 1
    fi

    current_version=$(git describe --tags --abbrev=0)
    next_version=$(semver --increment "$increment" "$current_version")

    gh release create --generate-notes "$next_version"
  '';
}
Download .txt
gitextract_u9nhbyq8/

├── .editorconfig
├── .envrc
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── 1-bug_report.md
│   │   ├── 2-feature_request.md
│   │   └── 3-typst_packages.md
│   └── workflows/
│       ├── pages.yml
│       ├── publish.yml
│       ├── test.yml
│       └── update-lockfile.yml
├── .gitignore
├── .markdownlint-cli2.jsonc
├── .markdownlint.json
├── .prettierignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── checks/
│   ├── .gitignore
│   ├── build-local.nix
│   ├── check-emojis.py
│   ├── clean/
│   │   ├── bad.c
│   │   ├── lib.typ
│   │   ├── metadata.toml
│   │   ├── sub/
│   │   │   ├── bad.py
│   │   │   ├── sub.typ
│   │   │   └── typst.toml
│   │   ├── typst.toml
│   │   └── works.bib
│   ├── clean-expected/
│   │   ├── lib.typ
│   │   ├── metadata.toml
│   │   ├── sub/
│   │   │   ├── sub.typ
│   │   │   └── typst.toml
│   │   ├── typst.toml
│   │   └── works.bib
│   ├── date/
│   │   └── main.typ
│   ├── default.nix
│   ├── emoji/
│   │   └── main.typ
│   ├── overlapping-virtual-paths/
│   │   └── main.typ
│   ├── simple/
│   │   └── main.typ
│   ├── simple-with-fonts/
│   │   └── main.typ
│   ├── simple-with-multiple-parameters/
│   │   └── main.typ
│   ├── simple-with-virtual-paths/
│   │   └── main.typ
│   ├── typst-packages/
│   │   └── main.typ
│   ├── virtual-paths.nix
│   └── watch.nix
├── docs/
│   ├── .gitignore
│   ├── SUMMARY.md
│   ├── api/
│   │   ├── derivations/
│   │   │   ├── build-typst-project-local.md
│   │   │   ├── build-typst-project.md
│   │   │   ├── common/
│   │   │   │   ├── emoji-font.md
│   │   │   │   ├── font-paths-example.md
│   │   │   │   ├── font-paths.md
│   │   │   │   ├── install-phase-command.md
│   │   │   │   ├── script-name.md
│   │   │   │   ├── src.md
│   │   │   │   ├── typst-compile-command.md
│   │   │   │   ├── typst-opts-example.md
│   │   │   │   ├── typst-opts.md
│   │   │   │   ├── typst-packages.md
│   │   │   │   ├── typst-project-output.md
│   │   │   │   ├── typst-project-source.md
│   │   │   │   ├── virtual-paths-example.md
│   │   │   │   └── virtual-paths.md
│   │   │   ├── dev-shell.md
│   │   │   ├── mk-typst-derivation.md
│   │   │   └── watch-typst-project.md
│   │   ├── derivations.md
│   │   ├── utilities/
│   │   │   └── clean-typst-source.md
│   │   └── utilities.md
│   ├── book.toml
│   ├── getting-started.md
│   └── recipes/
│       ├── adding-dependencies.md
│       ├── declaring-a-shell-environment.md
│       ├── specifying-sources.md
│       └── using-typst-packages.md
├── examples/
│   ├── .gitignore
│   ├── quick-start/
│   │   ├── .gitignore
│   │   ├── flake.nix
│   │   └── main.typ
│   ├── typst-packages/
│   │   ├── flake.nix
│   │   └── main.typ
│   └── typst-packages-unpublished/
│       ├── flake.nix
│       └── main.typ
├── flake.nix
├── lib/
│   ├── buildTypstProject.nix
│   ├── buildTypstProjectLocal.nix
│   ├── cleanTypstSource.nix
│   ├── coerceVirtualPathAttr.nix
│   ├── default.nix
│   ├── devShell.nix
│   ├── emojiFontPathFromString.nix
│   ├── fetchTypstPackages.nix
│   ├── inferTypstProjectOutput.nix
│   ├── linkVirtualPaths.nix
│   ├── mkTypstDerivation.nix
│   ├── setupHooks/
│   │   ├── copyVirtualPaths.nix
│   │   ├── copyVirtualPathsHook.sh
│   │   ├── unsetSourceDateEpoch.nix
│   │   ├── unsetSourceDateEpochHook.sh
│   │   └── unsetSourceDateEpochScript.sh
│   ├── typstOptsFromArgs.nix
│   └── watchTypstProject.nix
├── pkgs.nix
└── release.nix
Download .txt
SYMBOL INDEX (11 symbols across 2 files)

FILE: checks/check-emojis.py
  class TextElement (line 21) | class TextElement:
  class InvalidEmojiFontException (line 26) | class InvalidEmojiFontException(Exception):
    method __init__ (line 27) | def __init__(self, text_element: TextElement, font_patterns: list[re.P...
  class PDFChecker (line 38) | class PDFChecker:
    method __init__ (line 41) | def __init__(self, pdf_path: str):
    method check_emojis (line 44) | def check_emojis(self, font_patterns: list[re.Pattern]):
    method _extract_text_elements (line 54) | def _extract_text_elements(self) -> Iterator[TextElement]:
  class InvalidArgumentException (line 70) | class InvalidArgumentException(Exception):
    method __init__ (line 73) | def __init__(self, message: str):
  function main (line 78) | def main():

FILE: checks/clean/bad.c
  function main (line 3) | int main(void) {
Condensed preview — 104 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (136K chars).
[
  {
    "path": ".editorconfig",
    "chars": 156,
    "preview": "root = true\n\n[*]\ncharset = utf-8\nenv_of_line = lf\nindent_style = space\ntrim_trailing_whitespace = true\ninsert_final_newl"
  },
  {
    "path": ".envrc",
    "chars": 21,
    "preview": "use flake . --impure\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 16,
    "preview": "ko_fi: loqusion\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/1-bug_report.md",
    "chars": 478,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/2-feature_request.md",
    "chars": 595,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your fea"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/3-typst_packages.md",
    "chars": 141,
    "preview": "---\nname: Typst packages\nabout: For issues related to Typst packages\ntitle: \"[Typst packages]: \"\nlabels: typst packages\n"
  },
  {
    "path": ".github/workflows/pages.yml",
    "chars": 1143,
    "preview": "name: Build and deploy documentation\n\non:\n  push:\n    branches:\n      - main\n  workflow_dispatch:\n\npermissions:\n  conten"
  },
  {
    "path": ".github/workflows/publish.yml",
    "chars": 978,
    "preview": "name: Publish flake to FlakeHub\n\non:\n  release:\n    types: [published]\n  workflow_dispatch:\n    inputs:\n      tag:\n     "
  },
  {
    "path": ".github/workflows/test.yml",
    "chars": 708,
    "preview": "name: Run flake checks\non:\n  pull_request:\n    types: [opened, reopened, synchronize]\n  push:\n    branches:\n      - main"
  },
  {
    "path": ".github/workflows/update-lockfile.yml",
    "chars": 1242,
    "preview": "name: Update flake lockfile\non:\n  workflow_dispatch:\n  schedule:\n    - cron: \"39 8 7,22 * *\"\n\npermissions:\n  contents: r"
  },
  {
    "path": ".gitignore",
    "chars": 23,
    "preview": "/result\n.direnv/\n*.pdf\n"
  },
  {
    "path": ".markdownlint-cli2.jsonc",
    "chars": 35,
    "preview": "{\n  \"ignores\": [\"CHANGELOG.md\"],\n}\n"
  },
  {
    "path": ".markdownlint.json",
    "chars": 30,
    "preview": "{\n  \"no-inline-html\": false\n}\n"
  },
  {
    "path": ".prettierignore",
    "chars": 32,
    "preview": "docs/book\ndocs/theme\nflake.lock\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 2476,
    "preview": "# [0.3.2] (June 27, 2025)\n\n### Added\n\n- `typstOpts` repeatable flags ([#59])\n\n[#59]: https://github.com/loqusion/typix/p"
  },
  {
    "path": "LICENSE",
    "chars": 1065,
    "preview": "MIT License\n\nCopyright (c) 2023 loqusion\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\no"
  },
  {
    "path": "README.md",
    "chars": 2436,
    "preview": "<h1 align=\"center\">\n  <img\n    src=\"https://raw.githubusercontent.com/loqusion/typix/main/.github/assets/logo_1544x1544."
  },
  {
    "path": "checks/.gitignore",
    "chars": 6,
    "preview": "*.pdf\n"
  },
  {
    "path": "checks/build-local.nix",
    "chars": 447,
    "preview": "{\n  lib,\n  pkgs,\n  buildTypstProjectLocal,\n}: runCommandDrvAttr: args: let\n  build-local-drv = buildTypstProjectLocal ({"
  },
  {
    "path": "checks/check-emojis.py",
    "chars": 3132,
    "preview": "\"\"\"\nChecks if emoji characters in a PDF file are rendered with an appropriate font face.\n\nThis script is dumb, and only "
  },
  {
    "path": "checks/clean/bad.c",
    "chars": 84,
    "preview": "#include <stdio.h>\n\nint main(void) {\n    printf(\"Hello, World!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "checks/clean/lib.typ",
    "chars": 27,
    "preview": "#bibliography(\"works.bib\")\n"
  },
  {
    "path": "checks/clean/metadata.toml",
    "chars": 2693,
    "preview": "#:schema https://raw.githubusercontent.com/mintyfrankie/brilliant-CV/main/metadata.toml.schema.json\n\n# Set the output la"
  },
  {
    "path": "checks/clean/sub/bad.py",
    "chars": 54,
    "preview": "if __name__ == \"__main__\":\n    print(\"Hello, World!\")\n"
  },
  {
    "path": "checks/clean/sub/sub.typ",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "checks/clean/sub/typst.toml",
    "chars": 64,
    "preview": "[package]\nname = \"sub\"\nversion = \"0.1.0\"\nentrypoint = \"sub.typ\"\n"
  },
  {
    "path": "checks/clean/typst.toml",
    "chars": 66,
    "preview": "[package]\nname = \"clean\"\nversion = \"0.1.0\"\nentrypoint = \"lib.typ\"\n"
  },
  {
    "path": "checks/clean/works.bib",
    "chars": 271,
    "preview": "\\begin{thebibliography}{9}\n\\bibitem{texbook}\nDonald E. Knuth (1986) \\emph{The \\TeX{} Book}, Addison-Wesley Professional."
  },
  {
    "path": "checks/clean-expected/lib.typ",
    "chars": 27,
    "preview": "#bibliography(\"works.bib\")\n"
  },
  {
    "path": "checks/clean-expected/metadata.toml",
    "chars": 2693,
    "preview": "#:schema https://raw.githubusercontent.com/mintyfrankie/brilliant-CV/main/metadata.toml.schema.json\n\n# Set the output la"
  },
  {
    "path": "checks/clean-expected/sub/sub.typ",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "checks/clean-expected/sub/typst.toml",
    "chars": 64,
    "preview": "[package]\nname = \"sub\"\nversion = \"0.1.0\"\nentrypoint = \"sub.typ\"\n"
  },
  {
    "path": "checks/clean-expected/typst.toml",
    "chars": 66,
    "preview": "[package]\nname = \"clean\"\nversion = \"0.1.0\"\nentrypoint = \"lib.typ\"\n"
  },
  {
    "path": "checks/clean-expected/works.bib",
    "chars": 271,
    "preview": "\\begin{thebibliography}{9}\n\\bibitem{texbook}\nDonald E. Knuth (1986) \\emph{The \\TeX{} Book}, Addison-Wesley Professional."
  },
  {
    "path": "checks/date/main.typ",
    "chars": 114,
    "preview": "#let UNIX_EPOCH = datetime(\n  year: 1980,\n  month: 1,\n  day: 1,\n)\n#assert.ne(\n  datetime.today(),\n  UNIX_EPOCH,\n)\n"
  },
  {
    "path": "checks/default.nix",
    "chars": 9431,
    "preview": "{\n  pkgs,\n  myLib,\n}: let\n  inherit (pkgs) lib;\n  inherit (lib.strings) escapeShellArg concatMapStringsSep;\n  onlyDrvs ="
  },
  {
    "path": "checks/emoji/main.typ",
    "chars": 61,
    "preview": "#(emoji.tangerine)hell#(emoji.o) w#(emoji.o)rld#(emoji.face)\n"
  },
  {
    "path": "checks/overlapping-virtual-paths/main.typ",
    "chars": 38,
    "preview": "#lorem(100)\n\n#image(\"icons/link.svg\")\n"
  },
  {
    "path": "checks/simple/main.typ",
    "chars": 12,
    "preview": "#lorem(100)\n"
  },
  {
    "path": "checks/simple-with-fonts/main.typ",
    "chars": 39,
    "preview": "#set text(font: \"Roboto\")\n\n#lorem(100)\n"
  },
  {
    "path": "checks/simple-with-multiple-parameters/main.typ",
    "chars": 34,
    "preview": "#sys.inputs.key1\n#sys.inputs.key2\n"
  },
  {
    "path": "checks/simple-with-virtual-paths/main.typ",
    "chars": 75,
    "preview": "#lorem(100)\n\n#image(\"icons/link.svg\")\n#image(\"icons/paper-plane-tilt.svg\")\n"
  },
  {
    "path": "checks/typst-packages/main.typ",
    "chars": 815,
    "preview": "#import \"@preview/example:0.1.0\": add\n#import \"@preview/cetz:0.3.4\"\n#import \"@preview/polylux:0.4.0\": slide, uncover\n\n//"
  },
  {
    "path": "checks/virtual-paths.nix",
    "chars": 4843,
    "preview": "{\n  cleanTypstSource,\n  copyVirtualPathsHook,\n  lib,\n  linkFarmFromDrvs,\n  linkVirtualPaths,\n  pkgs,\n}: let\n  inherit (l"
  },
  {
    "path": "checks/watch.nix",
    "chars": 754,
    "preview": "{\n  lib,\n  pkgs,\n  watchTypstProject,\n}: runCommandDrvAttr: args: let\n  cleanedArgs = builtins.removeAttrs args [\n    \"s"
  },
  {
    "path": "docs/.gitignore",
    "chars": 5,
    "preview": "book\n"
  },
  {
    "path": "docs/SUMMARY.md",
    "chars": 830,
    "preview": "<!-- markdownlint-disable MD025 -->\n\n# Summary\n\n- [Introduction](README.md)\n- [Getting Started](getting-started.md)\n\n# R"
  },
  {
    "path": "docs/api/derivations/build-typst-project-local.md",
    "chars": 3230,
    "preview": "# buildTypstProjectLocal\n\nReturns a derivation for compiling a Typst project and copying the output to the\ncurrent direc"
  },
  {
    "path": "docs/api/derivations/build-typst-project.md",
    "chars": 2309,
    "preview": "# buildTypstProject\n\nReturns a derivation for compiling a Typst project.\n\nIf you want to build to the project directory,"
  },
  {
    "path": "docs/api/derivations/common/emoji-font.md",
    "chars": 1047,
    "preview": "Specify which emoji font to use. If `emojiFont` is `null`, no emoji font will\nbe included.\n\nMay be any of the following:"
  },
  {
    "path": "docs/api/derivations/common/font-paths-example.md",
    "chars": 2183,
    "preview": "<!-- markdownlint-disable-file first-line-h1 -->\n\n<!-- ANCHOR: buildtypstprojectlocal_example -->\n\n```nix\n{\n  outputs = "
  },
  {
    "path": "docs/api/derivations/common/font-paths.md",
    "chars": 417,
    "preview": "<!-- markdownlint-disable-file first-line-h1 -->\n\nList of sources specifying paths to font files that will be made avail"
  },
  {
    "path": "docs/api/derivations/common/install-phase-command.md",
    "chars": 206,
    "preview": "<!-- markdownlint-disable first-line-h1 -->\n\nCommand (or commands) to run during\n[`installPhase`][nixpkgs-installphase]."
  },
  {
    "path": "docs/api/derivations/common/script-name.md",
    "chars": 185,
    "preview": "<!-- markdownlint-disable-file first-line-h1 -->\n\nName of the script that will be added to the Nix store. You can use th"
  },
  {
    "path": "docs/api/derivations/common/src.md",
    "chars": 153,
    "preview": "<!-- markdownlint-disable-file first-line-h1 -->\n\n[Source](../../recipes/specifying-sources.md) containing all local fil"
  },
  {
    "path": "docs/api/derivations/common/typst-compile-command.md",
    "chars": 164,
    "preview": "<!-- markdownlint-disable first-line-h1 -->\n\nBase Typst command to run to compile the project. Other arguments will be\na"
  },
  {
    "path": "docs/api/derivations/common/typst-opts-example.md",
    "chars": 1983,
    "preview": "<!-- markdownlint-disable-file first-line-h1 -->\n\n<!-- ANCHOR: head -->\n\n```nix\n{\n  format = \"png\";\n  ppi = 300;\n  input"
  },
  {
    "path": "docs/api/derivations/common/typst-opts.md",
    "chars": 266,
    "preview": "<!-- markdownlint-disable-file first-line-h1 -->\n\n<!-- ANCHOR: head -->\n\nAttrset specifying command-line options to pass"
  },
  {
    "path": "docs/api/derivations/common/typst-packages.md",
    "chars": 6107,
    "preview": "<!-- markdownlint-disable first-line-h1 -->\n\n<!-- ANCHOR: body -->\n\n<div class=\"warning\">\n\nThis is an **unstable** featu"
  },
  {
    "path": "docs/api/derivations/common/typst-project-output.md",
    "chars": 717,
    "preview": "<!-- markdownlint-disable-file first-line-h1 -->\n\n<!-- ANCHOR: head -->\n\nDestination path for Typst output.\n\n<!-- ANCHOR"
  },
  {
    "path": "docs/api/derivations/common/typst-project-source.md",
    "chars": 79,
    "preview": "<!-- markdownlint-disable-file first-line-h1 -->\n\nTypst input file to compile.\n"
  },
  {
    "path": "docs/api/derivations/common/virtual-paths-example.md",
    "chars": 3228,
    "preview": "<!-- markdownlint-disable-file first-line-h1 -->\n\n<!-- ANCHOR: head -->\n\nYou can specify dependencies in your flake inpu"
  },
  {
    "path": "docs/api/derivations/common/virtual-paths.md",
    "chars": 955,
    "preview": "<!-- markdownlint-disable-file first-line-h1 -->\n\nList of sources that will be made virtually available to your Typst pr"
  },
  {
    "path": "docs/api/derivations/dev-shell.md",
    "chars": 1923,
    "preview": "# devShell\n\nSets up a shell environment that activates with [`nix develop`][nix-ref-develop]\nor [`direnv`][direnv].\n\n## "
  },
  {
    "path": "docs/api/derivations/mk-typst-derivation.md",
    "chars": 1868,
    "preview": "# mkTypstDerivation\n\nA generic derivation constructor for running Typst commands.\n\n## Parameters\n\n**Note:** All paramete"
  },
  {
    "path": "docs/api/derivations/watch-typst-project.md",
    "chars": 2799,
    "preview": "# watchTypstProject\n\nReturns a derivation for a script that watches an input file and recompiles on\nchanges.\n\n## Paramet"
  },
  {
    "path": "docs/api/derivations.md",
    "chars": 1491,
    "preview": "# Derivations\n\nAs paraphrased from [the Nix Reference Manual][nix-ref-derivations]:\n\n> A derivation is a specification f"
  },
  {
    "path": "docs/api/utilities/clean-typst-source.md",
    "chars": 457,
    "preview": "# cleanTypstSource\n\nFilters a source tree to only contain files that are usually pertinent to a\nTypst project.\n\n<!-- mar"
  },
  {
    "path": "docs/api/utilities.md",
    "chars": 71,
    "preview": "# Utilities\n\n- [`cleanTypstSource`](./utilities/clean-typst-source.md)\n"
  },
  {
    "path": "docs/book.toml",
    "chars": 273,
    "preview": "[book]\nauthors = [\"loqusion\"]\nlanguage = \"en\"\nsrc = \".\"\ntitle = \"Typix\"\n\n[output.html]\ndefault-theme = \"ayu\"\npreferred-d"
  },
  {
    "path": "docs/getting-started.md",
    "chars": 1104,
    "preview": "# Getting Started\n\nFirst, [install Nix][install-nix]:\n\n[install-nix]: https://github.com/DeterminateSystems/nix-installe"
  },
  {
    "path": "docs/recipes/adding-dependencies.md",
    "chars": 5380,
    "preview": "# Adding dependencies\n\nYou can add dependencies to your [flake\ninputs][nix-ref-flake-inputs][^zero-to-nix-flakes] so tha"
  },
  {
    "path": "docs/recipes/declaring-a-shell-environment.md",
    "chars": 1589,
    "preview": "# Declaring a shell environment\n\nYou can automatically pull your project's dependencies into your shell by\ndeclaring a ["
  },
  {
    "path": "docs/recipes/specifying-sources.md",
    "chars": 4145,
    "preview": "# Specifying sources\n\nA number of derivations in Typix accept source trees as parameters, such as\n[`src`](../api/derivat"
  },
  {
    "path": "docs/recipes/using-typst-packages.md",
    "chars": 9300,
    "preview": "# Using Typst packages\n\n> TL;DR: Use [this example][published-example] as a template:\n>\n> ```bash\n> nix flake init --ref"
  },
  {
    "path": "examples/.gitignore",
    "chars": 24,
    "preview": "/*/flake.lock\n/*/result\n"
  },
  {
    "path": "examples/quick-start/.gitignore",
    "chars": 8,
    "preview": "result*\n"
  },
  {
    "path": "examples/quick-start/flake.nix",
    "chars": 2407,
    "preview": "{\n  description = \"A Typst project\";\n\n  inputs = {\n    nixpkgs.url = \"github:NixOS/nixpkgs/nixos-unstable\";\n\n    typix ="
  },
  {
    "path": "examples/quick-start/main.typ",
    "chars": 25,
    "preview": "= Lorem ipsum\n#lorem(30)\n"
  },
  {
    "path": "examples/typst-packages/flake.nix",
    "chars": 2842,
    "preview": "{\n  description = \"A Typst project that uses Typst packages\";\n\n  inputs = {\n    nixpkgs.url = \"github:NixOS/nixpkgs/nixo"
  },
  {
    "path": "examples/typst-packages/main.typ",
    "chars": 112,
    "preview": "#import \"@preview/cetz:0.3.4\"\n\n#cetz.canvas({\n  import cetz.draw: *\n\n  circle((0, 0))\n  line((0, 0), (2, 1))\n})\n"
  },
  {
    "path": "examples/typst-packages-unpublished/flake.nix",
    "chars": 3978,
    "preview": "{\n  description = \"A Typst project that uses unpublished Typst packages\";\n\n  inputs = {\n    nixpkgs.url = \"github:NixOS/"
  },
  {
    "path": "examples/typst-packages-unpublished/main.typ",
    "chars": 53,
    "preview": "#import \"@local/my-typst-package:0.1.0\": *\n\n#nothing\n"
  },
  {
    "path": "flake.nix",
    "chars": 2340,
    "preview": "{\n  description = \"Deterministic Typst compilation with Nix\";\n\n  nixConfig = {\n    extra-substituters = [\"https://typst-"
  },
  {
    "path": "lib/buildTypstProject.nix",
    "chars": 664,
    "preview": "{\n  lib,\n  mkTypstDerivation,\n  typstOptsFromArgs,\n}: args @ {\n  typstCompileCommand ? \"typst compile\",\n  typstSource ? "
  },
  {
    "path": "lib/buildTypstProjectLocal.nix",
    "chars": 996,
    "preview": "{\n  buildTypstProject,\n  inferTypstProjectOutput,\n  lib,\n  pkgs,\n  typstOptsFromArgs,\n}: args @ {typstSource ? \"main.typ"
  },
  {
    "path": "lib/cleanTypstSource.nix",
    "chars": 446,
    "preview": "{lib}: src:\nlib.cleanSourceWith {\n  src = lib.cleanSource src;\n  filter = path: type: let\n    hasAcceptedSuffix = builti"
  },
  {
    "path": "lib/coerceVirtualPathAttr.nix",
    "chars": 379,
    "preview": "{lib}: let\n  inherit (builtins) isAttrs;\n  inherit (lib.strings) isStringLike;\nin\n  virtualPath:\n    if isStringLike vir"
  },
  {
    "path": "lib/default.nix",
    "chars": 1020,
    "preview": "{\n  lib,\n  newScope,\n}:\nlib.makeScope newScope (self: let\n  inherit (self) callPackage;\nin {\n  buildTypstProjectLocal = "
  },
  {
    "path": "lib/devShell.nix",
    "chars": 1426,
    "preview": "{\n  emojiFontPathFromString,\n  lib,\n  linkVirtualPaths,\n  mkShellNoCC,\n  typst,\n}: args @ {\n  checks ? {},\n  emojiFont ?"
  },
  {
    "path": "lib/emojiFontPathFromString.nix",
    "chars": 1003,
    "preview": "{\n  lib,\n  pkgs,\n}: emojiFont: let\n  inherit (builtins) isNull isString typeOf;\nin\n  if isString emojiFont\n  then\n    (\n"
  },
  {
    "path": "lib/fetchTypstPackages.nix",
    "chars": 1665,
    "preview": "{\n  fetchurl,\n  runCommand,\n  lib,\n  symlinkJoin,\n  stdenvNoCC,\n}: let\n  inherit (lib.lists) forEach;\n\n  typstPackageReg"
  },
  {
    "path": "lib/inferTypstProjectOutput.nix",
    "chars": 876,
    "preview": "{lib}: args_: let\n  args =\n    if builtins.isString args_\n    then {typstSource = args_;}\n    else args_;\n  supportedFor"
  },
  {
    "path": "lib/linkVirtualPaths.nix",
    "chars": 2384,
    "preview": "{\n  coerceVirtualPathAttr,\n  lib,\n  pkgs,\n}: let\n  inherit (builtins) toString;\n  inherit (pkgs) symlinkJoin;\n  inherit "
  },
  {
    "path": "lib/mkTypstDerivation.nix",
    "chars": 2020,
    "preview": "{\n  copyVirtualPathsHook,\n  emojiFontPathFromString,\n  lib,\n  stdenvNoCC,\n  typst,\n  unsetSourceDateEpochHook,\n  fetchTy"
  },
  {
    "path": "lib/setupHooks/copyVirtualPaths.nix",
    "chars": 982,
    "preview": "{\n  coerceVirtualPathAttr,\n  lib,\n  makeSetupHook,\n}: virtualPaths: let\n  inherit (lib.strings) concatMapStringsSep toSh"
  },
  {
    "path": "lib/setupHooks/copyVirtualPathsHook.sh",
    "chars": 403,
    "preview": "_same_path() {\n    [ \"$(realpath \"$1\")\" = \"$(realpath \"$2\")\" ]\n}\n\n_ensure_parent_exists() {\n    mkdir -p \"$(dirname \"$1\""
  },
  {
    "path": "lib/setupHooks/unsetSourceDateEpoch.nix",
    "chars": 266,
    "preview": "{makeSetupHook}: let\n  unsetSourceDateEpochScript = builtins.readFile ./unsetSourceDateEpochScript.sh;\nin\n  makeSetupHoo"
  },
  {
    "path": "lib/setupHooks/unsetSourceDateEpochHook.sh",
    "chars": 99,
    "preview": "unsetSourceDateEpoch() {\n    @unsetSourceDateEpochScript@\n}\n\npreBuildHooks+=(unsetSourceDateEpoch)\n"
  },
  {
    "path": "lib/setupHooks/unsetSourceDateEpochScript.sh",
    "chars": 24,
    "preview": "unset SOURCE_DATE_EPOCH\n"
  },
  {
    "path": "lib/typstOptsFromArgs.nix",
    "chars": 1569,
    "preview": "{lib}: origArgs: let\n  inherit (builtins) elem isBool isNull tail;\n  inherit (lib) optionalAttrs optionalString;\n  inher"
  },
  {
    "path": "lib/watchTypstProject.nix",
    "chars": 1902,
    "preview": "{\n  emojiFontPathFromString,\n  inferTypstProjectOutput,\n  lib,\n  linkVirtualPaths,\n  pkgs,\n  typst,\n  typstOptsFromArgs,"
  },
  {
    "path": "pkgs.nix",
    "chars": 617,
    "preview": "{pkgs}: {\n  docs = let\n    inherit (pkgs) lib;\n    root = ./.;\n    rootPrefix = builtins.toString root;\n    src = lib.so"
  },
  {
    "path": "release.nix",
    "chars": 692,
    "preview": "{pkgs}:\npkgs.writeShellApplication {\n  name = \"github-release\";\n\n  runtimeInputs = with pkgs; [\n    gh\n    git\n    nodeP"
  }
]

About this extraction

This page contains the full source code of the loqusion/typix GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 104 files (120.5 KB), approximately 36.6k tokens, and a symbol index with 11 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!