[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nenv_of_line = lf\nindent_style = space\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.nix]\nindent_size = 2\n"
  },
  {
    "path": ".envrc",
    "content": "use flake . --impure\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "ko_fi: loqusion\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/1-bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Versions**\n- OS:\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/2-feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/3-typst_packages.md",
    "content": "---\nname: Typst packages\nabout: For issues related to Typst packages\ntitle: \"[Typst packages]: \"\nlabels: typst packages\nassignees: ''\n\n---\n\n\n"
  },
  {
    "path": ".github/workflows/pages.yml",
    "content": "name: Build and deploy documentation\n\non:\n  push:\n    branches:\n      - main\n  workflow_dispatch:\n\npermissions:\n  contents: read\n  pages: write\n  id-token: write\n\nconcurrency:\n  group: pages\n  cancel-in-progress: false\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - uses: cachix/install-nix-action@v31\n      - uses: cachix/cachix-action@v16\n        with:\n          name: typst-nix\n          authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}\n      - name: Setup Pages\n        id: pages\n        uses: actions/configure-pages@v5\n      - name: Build with mdBook\n        run: |\n          nix build --accept-flake-config .#docs --out-link result --print-build-logs\n          cp -RLT result book\n      - name: Upload artifact\n        uses: actions/upload-pages-artifact@v4\n        with:\n          path: ./book\n\n  deploy:\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n    runs-on: ubuntu-latest\n    needs: build\n    steps:\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v4\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Publish flake to FlakeHub\n\non:\n  release:\n    types: [published]\n  workflow_dispatch:\n    inputs:\n      tag:\n        description: \"The existing tag to publish to FlakeHub\"\n        type: \"string\"\n        required: true\n\njobs:\n  publish-flakehub:\n    runs-on: ubuntu-latest\n    permissions:\n      id-token: write\n      contents: read\n    steps:\n      - name: Get git tag\n        id: git-tag\n        run: |\n          if [ -z \"$TAG\" ]; then\n            echo \"::error::Could not determine git tag\"\n            exit 1\n          fi\n          echo \"tag=$TAG\" >>\"$GITHUB_OUTPUT\"\n        env:\n          TAG: ${{ inputs.tag || github.ref_name }}\n      - uses: actions/checkout@v4\n        with:\n          ref: ${{ format('refs/tags/{0}', steps.git-tag.outputs.tag) }}\n      - uses: cachix/install-nix-action@v31\n      - uses: DeterminateSystems/flakehub-push@v6\n        with:\n          visibility: public\n          name: loqusion/typix\n          tag: ${{ steps.git-tag.outputs.tag }}\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Run flake checks\non:\n  pull_request:\n    types: [opened, reopened, synchronize]\n  push:\n    branches:\n      - main\n      - \"ci*\"\n\npermissions:\n  contents: read\n\njobs:\n  checks:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: cachix/install-nix-action@v31\n      - name: flake check\n        run: nix flake check\n\n  examples:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: cachix/install-nix-action@v31\n      - name: check examples\n        run: |\n          set -euo pipefail\n          for f in $(find ./examples -maxdepth 1 -mindepth 1 -type d | sort -u); do\n            nix flake check --no-write-lock-file \"$f\"\n          done\n"
  },
  {
    "path": ".github/workflows/update-lockfile.yml",
    "content": "name: Update flake lockfile\non:\n  workflow_dispatch:\n  schedule:\n    - cron: \"39 8 7,22 * *\"\n\npermissions:\n  contents: read\n\njobs:\n  update:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: cachix/install-nix-action@v31\n      - uses: cachix/cachix-action@v16\n        with:\n          name: typst-nix\n          authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}\n      - name: Update flake.lock\n        id: update\n        uses: DeterminateSystems/update-flake-lock@v27\n        with:\n          token: ${{ secrets.GH_TOKEN_FOR_UPDATES }}\n          commit-msg: \"chore: update flake.lock\"\n          pr-title: \"chore: update flake.lock\"\n          pr-body: |\n            Automated changes by the [update-flake-lock](https://github.com/DeterminateSystems/update-flake-lock) GitHub Action.\n\n            ```\n            {{ env.GIT_COMMIT_MESSAGE }}\n            ```\n\n          pr-labels: |\n            dependencies\n            automated\n          nix-options: --accept-flake-config\n      - name: Merge PR\n        run: |\n          gh pr merge --squash --delete-branch --auto \"$PR_NUMBER\"\n        env:\n          GH_TOKEN: ${{ secrets.GH_TOKEN_FOR_UPDATES }}\n          PR_NUMBER: ${{ steps.update.outputs.pull-request-number }}\n"
  },
  {
    "path": ".gitignore",
    "content": "/result\n.direnv/\n*.pdf\n"
  },
  {
    "path": ".markdownlint-cli2.jsonc",
    "content": "{\n  \"ignores\": [\"CHANGELOG.md\"],\n}\n"
  },
  {
    "path": ".markdownlint.json",
    "content": "{\n  \"no-inline-html\": false\n}\n"
  },
  {
    "path": ".prettierignore",
    "content": "docs/book\ndocs/theme\nflake.lock\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# [0.3.2] (June 27, 2025)\n\n### Added\n\n- `typstOpts` repeatable flags ([#59])\n\n[#59]: https://github.com/loqusion/typix/pull/59\n\n# [0.3.1] (April 02, 2025)\n\n### Added\n\n- Typst packages support (unstable) ([#51])\n- `with-typst-packages-unpublished` template ([#51])\n\n### Changed\n\n- Use `unstable_typstPackages` in `with-typst-packages` template ([#51])\n\n[#51]: https://github.com/loqusion/typix/pull/51\n\n# [0.3.0] (January 27, 2025)\n\n### Added\n\n- **BREAKING CHANGE:** Include an emoji font in all derivations by default ([#44])\n- Add `emojiFont` attribute in all derivations ([#44])\n\n[#44]: https://github.com/loqusion/typix/pull/44\n\n# [0.2.0] (January 3, 2025)\n\n### Fixed\n\n- **BREAKING CHANGE:** Unset `SOURCE_DATE_EPOCH` environment variable in all derivations\n  ([#40])\n\n[#40]: https://github.com/loqusion/typix/pull/40\n\n# [0.1.7] (December 29, 2024)\n\n### Changed\n\n- Improve build times ([#38])\n\n[#38]: https://github.com/loqusion/typix/pull/38\n\n# [0.1.6] (October 30, 2024)\n\n### Fixed\n\n- Include `metadata.toml` in `cleanTypstSource` ([#29])\n\n[#29]: https://github.com/loqusion/typix/pull/29\n\n# [0.1.5] (July 13, 2024)\n\n### Fixed\n\n- Include `typst.toml` in `cleanTypstSource` ([#20])\n\n[#20]: https://github.com/loqusion/typix/pull/20\n\n# [0.1.4] (May 2, 2024)\n\n### Fixed\n\n- Handle `src` attribute correctly in `virtualPaths` ([#12])\n\n[#12]: https://github.com/loqusion/typix/pull/12\n\n# [0.1.3] (March 26, 2024)\n\n### Fixed\n\n- Include missing dependencies in `buildTypstProjectLocal` and `watchTypstProject`\n\n# [0.1.2] (February 29, 2024)\n\n- Test release\n\n# [0.1.1] (February 29, 2024)\n\n- Add release script\n- Add `description` attribute to `flake.nix`\n\n# [0.1.0] (February 29, 2024)\n\n- First release\n\n[0.3.2]: https://github.com/loqusion/typix/compare/0.3.1...0.3.2\n[0.3.1]: https://github.com/loqusion/typix/compare/0.3.0...0.3.1\n[0.3.0]: https://github.com/loqusion/typix/compare/0.2.0...0.3.0\n[0.2.0]: https://github.com/loqusion/typix/compare/0.1.7...0.2.0\n[0.1.7]: https://github.com/loqusion/typix/compare/0.1.6...0.1.7\n[0.1.6]: https://github.com/loqusion/typix/compare/0.1.5...0.1.6\n[0.1.5]: https://github.com/loqusion/typix/compare/0.1.4...0.1.5\n[0.1.4]: https://github.com/loqusion/typix/compare/0.1.3...0.1.4\n[0.1.3]: https://github.com/loqusion/typix/compare/0.1.2...0.1.3\n[0.1.2]: https://github.com/loqusion/typix/compare/0.1.1...0.1.2\n[0.1.1]: https://github.com/loqusion/typix/compare/0.1.0...0.1.1\n[0.1.0]: https://github.com/loqusion/typix/commits/0.1.0-1/\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2023 loqusion\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<h1 align=\"center\">\n  <img\n    src=\"https://raw.githubusercontent.com/loqusion/typix/main/.github/assets/logo_1544x1544.png\"\n    alt=\"Typix Logo\"\n    width=\"150\"\n  /><br />\n  Typix\n</h1>\n\n<p align=\"center\">\n  <a href=\"https://flakehub.com/flake/loqusion/typix\">\n    <img\n      src=\"https://img.shields.io/endpoint?style=for-the-badge&color=95b6f9&labelColor=302D41&url=https://flakehub.com/f/loqusion/typix/badge\"\n      alt=\"FlakeHub version\"\n    ></a>\n</p>\n\nTypix aims to make it easier to use [Nix](https://nixos.org/) in\n[Typst](https://github.com/typst/typst) projects.\n\n- **Dependency management**: supports arbitrary dependencies including fonts,\n  images, and data\n- **Reproducible**: via a hermetically sealed build environment\n- **Extensible**: full support for [Typst packages](https://loqusion.github.io/typix/recipes/using-typst-packages.html)\n\n## Features\n\n- Automatically fetch dependencies and compile in a single command (`nix run\n.#build`)\n- Watch input files and recompile on changes (`nix run .#watch`)\n- Set up a shell environment with all dependencies made available via\n  environment variables and symlinks\n- Extensible via\n  [`mkTypstDerivation`](https://loqusion.github.io/typix/api/derivations/mk-typst-derivation.html)\n- Support for dependencies such as [fonts](https://typst.app/docs/reference/text/text/#parameters-font),\n  [images](https://typst.app/docs/reference/visualize/image/), and [data](https://typst.app/docs/reference/data-loading/)\n- [Typst packages](https://loqusion.github.io/typix/recipes/using-typst-packages.html)\n  fetched from the official Typst packages CDN\n\n## Getting Started\n\nAfter [installing Nix](https://github.com/DeterminateSystems/nix-installer) and\n[enabling\nflakes](https://nixos.wiki/wiki/Flakes#Enable_flakes_permanently_in_NixOS), you\ncan initialize a flake from the default template:\n\n```bash\nnix flake init --refresh -t github:loqusion/typix\n```\n\n> Alternatively, you can use a template demonstrating [Typst packages](https://loqusion.github.io/typix/recipes/using-typst-packages.html)\n> usage:\n>\n> ```bash\n> nix flake init --refresh -t 'github:loqusion/typix#with-typst-packages'\n> ```\n\nHere are some commands you can run from any template:\n\n- `nix run .#watch` — watch the input files and recompile on changes\n- `nix run .#build` — compile and copy the output to the current directory\n\n---\n\nFor more information, check out [the docs](https://loqusion.github.io/typix/).\n"
  },
  {
    "path": "checks/.gitignore",
    "content": "*.pdf\n"
  },
  {
    "path": "checks/build-local.nix",
    "content": "{\n  lib,\n  pkgs,\n  buildTypstProjectLocal,\n}: runCommandDrvAttr: args: let\n  build-local-drv = buildTypstProjectLocal ({\n      name = \"build-local-check\";\n    }\n    // args\n    // runCommandDrvAttr);\nin\n  pkgs.runCommand \"build-local\" (runCommandDrvAttr\n    // {\n      nativeBuildInputs =\n        (runCommandDrvAttr.nativeBuildInputs or [])\n        ++ [\n          build-local-drv\n        ];\n    }) ''\n    ${lib.getExe build-local-drv} \"$out\"\n  ''\n"
  },
  {
    "path": "checks/check-emojis.py",
    "content": "\"\"\"\nChecks if emoji characters in a PDF file are rendered with an appropriate font face.\n\nThis script is dumb, and only checks if the font face name for text with an\nemoji matches one of a set of patterns given on the command line. This\nassumption is naive, and may not hold if the font names change, or if a font\nname not supporting emoji happens to match any of the patterns.\n\"\"\"\n\nimport re\nimport sys\nfrom collections.abc import Iterator\nfrom dataclasses import dataclass\nfrom typing import Final\n\nimport emoji\nimport pdfplumber\n\n\n@dataclass\nclass TextElement:\n    text: str\n    font: str\n\n\nclass InvalidEmojiFontException(Exception):\n    def __init__(self, text_element: TextElement, font_patterns: list[re.Pattern]):\n        self.text_element = text_element\n        self.font_patterns = font_patterns\n        self.message = (\n            f'Detected invalid font for text containing emoji character: \"{text_element.text}\"\\n'\n            f'Font: \"{text_element.font}\"\\n'\n            f\"Font did not match any of the following patterns: {', '.join((f\"'{pat.pattern}'\" for pat in font_patterns))}\"\n        )\n        super().__init__(self.message)\n\n\nclass PDFChecker:\n    pdf_path: str\n\n    def __init__(self, pdf_path: str):\n        self.pdf_path = pdf_path\n\n    def check_emojis(self, font_patterns: list[re.Pattern]):\n        text_elements = self._extract_text_elements()\n\n        for text_element in text_elements:\n            if emoji.emoji_count(text_element.text) == 0:\n                continue\n\n            if not any(pat.search(text_element.font) for pat in font_patterns):\n                raise InvalidEmojiFontException(text_element, font_patterns)\n\n    def _extract_text_elements(self) -> Iterator[TextElement]:\n        with pdfplumber.open(self.pdf_path) as pdf:\n            for page in pdf.pages:\n                words = page.extract_words(\n                    keep_blank_chars=True,\n                    use_text_flow=True,\n                    extra_attrs=[\"fontname\"],\n                )\n\n                for word in words:\n                    yield TextElement(\n                        text=word[\"text\"],\n                        font=word[\"fontname\"],\n                    )\n\n\nclass InvalidArgumentException(Exception):\n    USAGE: Final = f\"usage: {sys.argv[0]} <pdf_path> <pattern> [<pattern>...]\"\n\n    def __init__(self, message: str):\n        self.message = message + \"\\n\" + InvalidArgumentException.USAGE\n        super().__init__(self.message)\n\n\ndef main():\n    pdf_path = sys.argv[1]\n    checker = PDFChecker(pdf_path)\n\n    font_patterns = list(map(lambda pat: re.compile(pat, re.IGNORECASE), sys.argv[2:]))\n    if len(font_patterns) == 0:\n        raise InvalidArgumentException(\n            \"expected one or more patterns given as arguments\"\n        )\n\n    checker.check_emojis(font_patterns)\n\n\nif __name__ == \"__main__\":\n    try:\n        main()\n    except InvalidEmojiFontException as err:\n        print(f\"test failed: {err}\", file=sys.stderr)\n        sys.exit(1)\n    except InvalidArgumentException as err:\n        print(f\"error: {err}\", file=sys.stderr)\n        sys.exit(2)\n    except Exception:\n        raise\n"
  },
  {
    "path": "checks/clean/bad.c",
    "content": "#include <stdio.h>\n\nint main(void) {\n    printf(\"Hello, World!\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "checks/clean/lib.typ",
    "content": "#bibliography(\"works.bib\")\n"
  },
  {
    "path": "checks/clean/metadata.toml",
    "content": "#:schema https://raw.githubusercontent.com/mintyfrankie/brilliant-CV/main/metadata.toml.schema.json\n\n# Set the output language\n# INFO: value must matches folder suffix; i.e \"zh\" -> \"./modules_zh\"\nlanguage = \"en\"\n\n[layout]\n# Optional values: skyblue, red, nephritis, concrete, darknight\n# You can also use a custom color by hex code i.e. \"#1E90FF\"\nawesome_color = \"skyblue\"\n\n# Skips are for controlling the spacing between sections and entries\nbefore_section_skip = \"1pt\"\nbefore_entry_skip = \"1pt\"\nbefore_entry_description_skip = \"1pt\"\n\n[layout.fonts]\nregular_fonts = [\"Source Sans Pro\", \"Source Sans 3\"]\nheader_font = \"Roboto\"\n\n[layout.header]\n# Optional values: left, center, right\nheader_align = \"left\"\n\n# Decide if you want to display profile photo or not\ndisplay_profile_photo = true\n\n[layout.entry]\n# Decide if you want to put your company in bold or your position in bold\ndisplay_entry_society_first = true\n\n# Decide if you want to display organisation logo or not\ndisplay_logo = true\n\n[inject]\n# Decide if you want to inject AI prompt or not\ninject_ai_prompt = false\n\n# Decide if you want to inject keywords or not\ninject_keywords = true\ninjected_keywords_list = [\"Data Analyst\", \"GCP\", \"Python\", \"SQL\", \"Tableau\"]\n\n[personal]\nfirst_name = \"John\"\nlast_name = \"Doe\"\n\n# The order of this section will affect how the entries are displayed\n# The custom value is for any additional information you want to add, name it as custom-1, custom-2, etc.\n[personal.info]\ngithub = \"mintyfrankie\"\nphone = \"+33 6 12 34 56 78\"\nemail = \"john.doe@me.org\"\nlinkedin = \"johndoe\"\n# gitlab = \"mintyfrankie\"\n# homepage = \"jd.me.org\"\n# orcid = \"0000-0000-0000-0000\"\n# researchgate = \"John-Doe\"\n# extraInfo = \"I am a cool kid\"\n[personal.info.custom-1]\n# image = \"\" # Example: image(\"./path/to/image.png\")\nawesomeIcon = \"graduation-cap\"   # Example: \"graduation-cap\" see https://typst.app/universe/package/fontawesome/\ntext = \"PhD\"\nlink = \"https://www.example.com\"\n\n# add a new section if you want to include the language of your choice\n# i.e. [[lang.ru]]\n# each section must contains the following fields\n[lang.en]\nheader_quote = \"Experienced Data Analyst looking for a full time job starting from now\"\ncv_footer = \"Curriculum vitae\"\nletter_footer = \"Cover letter\"\n\n[lang.fr]\nheader_quote = \"Analyste de données expérimenté à la recherche d'un emploi à temps plein disponible dès maintenant\"\ncv_footer = \"Résumé\"\nletter_footer = \"Lettre de motivation\"\n\n[lang.zh]\nheader_quote = \"具有丰富经验的数据分析师，随时可入职\"\ncv_footer = \"简历\"\nletter_footer = \"申请信\"\n\n# For languages that are not written in Latin script\n# Currently supported non-latin language codes: (\"zh\", \"ja\", \"ko\", \"ru\")\n[lang.non_latin]\nname = \"王道尔\"\nfont = \"Heiti SC\"\n"
  },
  {
    "path": "checks/clean/sub/bad.py",
    "content": "if __name__ == \"__main__\":\n    print(\"Hello, World!\")\n"
  },
  {
    "path": "checks/clean/sub/sub.typ",
    "content": ""
  },
  {
    "path": "checks/clean/sub/typst.toml",
    "content": "[package]\nname = \"sub\"\nversion = \"0.1.0\"\nentrypoint = \"sub.typ\"\n"
  },
  {
    "path": "checks/clean/typst.toml",
    "content": "[package]\nname = \"clean\"\nversion = \"0.1.0\"\nentrypoint = \"lib.typ\"\n"
  },
  {
    "path": "checks/clean/works.bib",
    "content": "\\begin{thebibliography}{9}\n\\bibitem{texbook}\nDonald E. Knuth (1986) \\emph{The \\TeX{} Book}, Addison-Wesley Professional.\n\n\\bibitem{lamport94}\nLeslie Lamport (1994) \\emph{\\LaTeX: a document preparation system}, Addison\nWesley, Massachusetts, 2nd ed.\n\\end{thebibliography}\n"
  },
  {
    "path": "checks/clean-expected/lib.typ",
    "content": "#bibliography(\"works.bib\")\n"
  },
  {
    "path": "checks/clean-expected/metadata.toml",
    "content": "#:schema https://raw.githubusercontent.com/mintyfrankie/brilliant-CV/main/metadata.toml.schema.json\n\n# Set the output language\n# INFO: value must matches folder suffix; i.e \"zh\" -> \"./modules_zh\"\nlanguage = \"en\"\n\n[layout]\n# Optional values: skyblue, red, nephritis, concrete, darknight\n# You can also use a custom color by hex code i.e. \"#1E90FF\"\nawesome_color = \"skyblue\"\n\n# Skips are for controlling the spacing between sections and entries\nbefore_section_skip = \"1pt\"\nbefore_entry_skip = \"1pt\"\nbefore_entry_description_skip = \"1pt\"\n\n[layout.fonts]\nregular_fonts = [\"Source Sans Pro\", \"Source Sans 3\"]\nheader_font = \"Roboto\"\n\n[layout.header]\n# Optional values: left, center, right\nheader_align = \"left\"\n\n# Decide if you want to display profile photo or not\ndisplay_profile_photo = true\n\n[layout.entry]\n# Decide if you want to put your company in bold or your position in bold\ndisplay_entry_society_first = true\n\n# Decide if you want to display organisation logo or not\ndisplay_logo = true\n\n[inject]\n# Decide if you want to inject AI prompt or not\ninject_ai_prompt = false\n\n# Decide if you want to inject keywords or not\ninject_keywords = true\ninjected_keywords_list = [\"Data Analyst\", \"GCP\", \"Python\", \"SQL\", \"Tableau\"]\n\n[personal]\nfirst_name = \"John\"\nlast_name = \"Doe\"\n\n# The order of this section will affect how the entries are displayed\n# The custom value is for any additional information you want to add, name it as custom-1, custom-2, etc.\n[personal.info]\ngithub = \"mintyfrankie\"\nphone = \"+33 6 12 34 56 78\"\nemail = \"john.doe@me.org\"\nlinkedin = \"johndoe\"\n# gitlab = \"mintyfrankie\"\n# homepage = \"jd.me.org\"\n# orcid = \"0000-0000-0000-0000\"\n# researchgate = \"John-Doe\"\n# extraInfo = \"I am a cool kid\"\n[personal.info.custom-1]\n# image = \"\" # Example: image(\"./path/to/image.png\")\nawesomeIcon = \"graduation-cap\"   # Example: \"graduation-cap\" see https://typst.app/universe/package/fontawesome/\ntext = \"PhD\"\nlink = \"https://www.example.com\"\n\n# add a new section if you want to include the language of your choice\n# i.e. [[lang.ru]]\n# each section must contains the following fields\n[lang.en]\nheader_quote = \"Experienced Data Analyst looking for a full time job starting from now\"\ncv_footer = \"Curriculum vitae\"\nletter_footer = \"Cover letter\"\n\n[lang.fr]\nheader_quote = \"Analyste de données expérimenté à la recherche d'un emploi à temps plein disponible dès maintenant\"\ncv_footer = \"Résumé\"\nletter_footer = \"Lettre de motivation\"\n\n[lang.zh]\nheader_quote = \"具有丰富经验的数据分析师，随时可入职\"\ncv_footer = \"简历\"\nletter_footer = \"申请信\"\n\n# For languages that are not written in Latin script\n# Currently supported non-latin language codes: (\"zh\", \"ja\", \"ko\", \"ru\")\n[lang.non_latin]\nname = \"王道尔\"\nfont = \"Heiti SC\"\n"
  },
  {
    "path": "checks/clean-expected/sub/sub.typ",
    "content": ""
  },
  {
    "path": "checks/clean-expected/sub/typst.toml",
    "content": "[package]\nname = \"sub\"\nversion = \"0.1.0\"\nentrypoint = \"sub.typ\"\n"
  },
  {
    "path": "checks/clean-expected/typst.toml",
    "content": "[package]\nname = \"clean\"\nversion = \"0.1.0\"\nentrypoint = \"lib.typ\"\n"
  },
  {
    "path": "checks/clean-expected/works.bib",
    "content": "\\begin{thebibliography}{9}\n\\bibitem{texbook}\nDonald E. Knuth (1986) \\emph{The \\TeX{} Book}, Addison-Wesley Professional.\n\n\\bibitem{lamport94}\nLeslie Lamport (1994) \\emph{\\LaTeX: a document preparation system}, Addison\nWesley, Massachusetts, 2nd ed.\n\\end{thebibliography}\n"
  },
  {
    "path": "checks/date/main.typ",
    "content": "#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",
    "content": "{\n  pkgs,\n  myLib,\n}: let\n  inherit (pkgs) lib;\n  inherit (lib.strings) escapeShellArg concatMapStringsSep;\n  onlyDrvs = lib.filterAttrs (_: lib.isDerivation);\nin\n  onlyDrvs (lib.makeScope myLib.newScope (self: let\n    callPackage = self.newScope {};\n    typstSource = \"main.typ\";\n    fontPaths = [\n      \"${pkgs.roboto}/share/fonts/truetype\"\n    ];\n    virtualPaths = [\n      {\n        src = ./fixtures/icons;\n        dest = \"icons\";\n      }\n    ];\n    unstable_typstPackages = [\n      {\n        name = \"example\";\n        version = \"0.1.0\";\n        hash = \"sha256-R18Xv3AoZsTtMycRasczTsje5yIfiURIxtDICQ4mvho=\";\n      }\n      {\n        name = \"cetz\";\n        version = \"0.3.4\";\n        hash = \"sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=\";\n      }\n      {\n        name = \"polylux\";\n        version = \"0.4.0\";\n        hash = \"sha256-4owP2KiyaaASS1YZ0Hs58k6UEVAqsRR3YdGF26ikosk=\";\n      }\n      # Required by cetz\n      {\n        name = \"oxifmt\";\n        version = \"0.2.1\";\n        hash = \"sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=\";\n      }\n    ];\n  in rec {\n    buildLocal = callPackage ./build-local.nix {};\n    buildLocalSimple = buildLocal {} {\n      inherit typstSource;\n      src = myLib.cleanTypstSource ./simple;\n    };\n    buildLocalSimpleWithFonts = buildLocal {} {\n      inherit fontPaths typstSource;\n      src = myLib.cleanTypstSource ./simple-with-fonts;\n    };\n    buildLocalSimpleWithVirtualPaths = buildLocal {} {\n      inherit virtualPaths typstSource;\n      src = myLib.cleanTypstSource ./simple-with-virtual-paths;\n    };\n    buildLocalWithMultipleParameters = buildLocal {} {\n      inherit typstSource;\n      src = myLib.cleanTypstSource ./simple-with-multiple-parameters;\n      typstOpts = {\n        input = [\"key1=value1\" \"key2=value2\" \"key3= --spaces-are-properly-escaped\" \"key4='quotes-are-properly-escaped\\\"\"];\n      };\n    };\n    buildLocalWithTypstPackages = buildLocal {} {\n      inherit typstSource;\n      src = myLib.cleanTypstSource ./typst-packages;\n      inherit unstable_typstPackages;\n    };\n\n    clean = myLib.mkTypstDerivation {\n      src = myLib.cleanTypstSource ./clean;\n      EXPECTED_SRC = ./clean-expected;\n      buildPhaseTypstCommand = ''\n        diff -r \"$src\" \"$EXPECTED_SRC\"\n        touch $out\n      '';\n    };\n\n    date = myLib.buildTypstProject {\n      inherit typstSource;\n      src = myLib.cleanTypstSource ./date;\n    };\n    dateWatch = watch {} {\n      inherit typstSource;\n      src = myLib.cleanTypstSource ./date;\n    };\n\n    devShell = myLib.devShell {\n      inherit virtualPaths;\n      checks = {\n        simple = myLib.buildTypstProject {\n          inherit virtualPaths typstSource;\n          src = myLib.cleanTypstSource ./simple;\n        };\n      };\n    };\n\n    checkEmojiScript = {\n      inputs =\n        (with pkgs; [\n          python312\n          python312Packages.emoji\n        ])\n        ++ (\n          with pkgs.python312Packages; [\n            # Referencing `emoji` doesn't work here because an attribute of that\n            # name already exists in a recursive attribute set (`rec {...}`)\n            pdfplumber\n          ]\n        );\n      script = patterns: ''\n        python3.12 ${./check-emojis.py} \"$out\" ${concatMapStringsSep \" \" escapeShellArg patterns}\n      '';\n    };\n\n    emoji = {\n      emojiFont,\n      fontPaths ? [],\n      patterns,\n    }: (myLib.buildTypstProject ({\n        inherit typstSource fontPaths;\n        src = myLib.cleanTypstSource ./emoji;\n        doCheck = true;\n        nativeCheckInputs = checkEmojiScript.inputs;\n        checkPhase = checkEmojiScript.script patterns;\n      }\n      // lib.optionalAttrs (emojiFont != \"__OMIT__\") {\n        inherit emojiFont;\n      }));\n    emojiOmit = emoji {\n      emojiFont = \"__OMIT__\";\n      patterns = [\"emoji\"];\n    };\n    emojiTwemoji = emoji {\n      emojiFont = \"twemoji\";\n      patterns = [\"emoji\"];\n    };\n    emojiTwemojiCbdt = emoji {\n      emojiFont = \"twemoji-cbdt\";\n      patterns = [\"emoji\"];\n    };\n    emojiNoto = emoji {\n      emojiFont = \"noto\";\n      patterns = [\"emoji\"];\n    };\n    emojiNotoMonochrome = emoji {\n      emojiFont = \"noto-monochrome\";\n      patterns = [\"emoji\"];\n    };\n    # FIXME: https://github.com/loqusion/typix/issues/79\n    # emojiEmojiOne = emoji {\n    #   emojiFont = \"emojione\";\n    #   patterns = [\"emoji\"];\n    # };\n    emojiFontOverride = emoji {\n      emojiFont = null;\n      fontPaths = [\"${pkgs.noto-fonts-color-emoji}/share/fonts/noto\"];\n      patterns = [\"emoji\"];\n    };\n\n    emojiWatch = {\n      emojiFont,\n      fontPaths ? [],\n      patterns,\n    }: (watch {\n        nativeBuildInputs = checkEmojiScript.inputs;\n        postBuild = checkEmojiScript.script patterns;\n      } ({\n          inherit typstSource fontPaths;\n          src = myLib.cleanTypstSource ./emoji;\n        }\n        // lib.optionalAttrs (emojiFont != \"__OMIT__\") {\n          inherit emojiFont;\n        }));\n    emojiWatchOmit = emojiWatch {\n      emojiFont = \"__OMIT__\";\n      patterns = [\"emoji\"];\n    };\n    emojiWatchTwemoji = emojiWatch {\n      emojiFont = \"twemoji\";\n      patterns = [\"emoji\"];\n    };\n    emojiWatchTwemojiCbdt = emojiWatch {\n      emojiFont = \"twemoji-cbdt\";\n      patterns = [\"emoji\"];\n    };\n    emojiWatchNoto = emojiWatch {\n      emojiFont = \"noto\";\n      patterns = [\"emoji\"];\n    };\n    emojiWatchNotoMonochrome = emojiWatch {\n      emojiFont = \"noto-monochrome\";\n      patterns = [\"emoji\"];\n    };\n    # FIXME: https://github.com/loqusion/typix/issues/79\n    # emojiWatchEmojiOne = emojiWatch {\n    #   emojiFont = \"emojione\";\n    #   patterns = [\"emoji\"];\n    # };\n    emojiWatchFontOverride = emojiWatch {\n      emojiFont = null;\n      fontPaths = [\"${pkgs.noto-fonts-color-emoji}/share/fonts/noto\"];\n      patterns = [\"emoji\"];\n    };\n\n    overlappingVirtualPaths = isInvariant: util: file:\n      util (let\n        op =\n          if isInvariant\n          then \"!=\"\n          else \"=\";\n        errorMsg =\n          if isInvariant\n          then ''$FILE_TO_CHECK was overwritten\\; it should stay the same when forceVirtualPaths is false''\n          else ''$FILE_TO_CHECK was not overwritten\\; it should be overwritten when forceVirtualPaths is true'';\n      in {\n        FILE_TO_CHECK = file;\n        preBuild = ''\n          if [ ! -e \"$FILE_TO_CHECK\" ]; then\n            echo \"$FILE_TO_CHECK does not exist; unable to run check\"\n            exit 1\n          fi\n          hash=$(sha256sum \"$FILE_TO_CHECK\" | awk '{ print $1 }')\n          if [ -z \"$hash\" ]; then\n            echo \"unable to obtain hash for $FILE_TO_CHECK\"\n            exit 1\n          fi\n        '';\n        postBuild = ''\n          hash=''${hash:?not defined}\n          new_hash=$(sha256sum \"$FILE_TO_CHECK\" | awk '{ print $1 }')\n          if [ -z \"$new_hash\" ]; then\n            echo \"unable to obtain hash for $FILE_TO_CHECK\"\n            exit 1\n          fi\n          if [ \"$hash\" ${op} \"$new_hash\" ]; then\n            echo ${errorMsg}\n            echo\n            echo \"old hash: $hash\"\n            echo \"new hash: $new_hash\"\n            exit 1\n          fi\n        '';\n      }) {\n        inherit virtualPaths typstSource;\n        src = ./overlapping-virtual-paths;\n        forceVirtualPaths = !isInvariant;\n      };\n    overlappingVirtualPathsInvariant = overlappingVirtualPaths true;\n    overlappingVirtualPathsForce = overlappingVirtualPaths false;\n\n    simple = myLib.buildTypstProject {\n      inherit typstSource;\n      src = myLib.cleanTypstSource ./simple;\n    };\n    simpleWithFonts = myLib.buildTypstProject {\n      inherit fontPaths typstSource;\n      src = myLib.cleanTypstSource ./simple-with-fonts;\n    };\n    simpleWithMultipleParameters = myLib.buildTypstProject {\n      inherit typstSource;\n      src = myLib.cleanTypstSource ./simple-with-multiple-parameters;\n      typstOpts = {\n        input = [\"key1=value1\" \"key2=value2\" \"key3= --spaces-are-properly-escaped\" \"key4='quotes-are-properly-escaped\\\"\"];\n      };\n    };\n    simpleWithVirtualPaths = myLib.buildTypstProject {\n      inherit virtualPaths typstSource;\n      src = myLib.cleanTypstSource ./simple-with-virtual-paths;\n    };\n\n    withTypstPackages = myLib.buildTypstProject {\n      inherit typstSource;\n      src = myLib.cleanTypstSource ./typst-packages;\n      inherit unstable_typstPackages;\n    };\n\n    virtualPathsChecks = callPackage ./virtual-paths.nix {};\n\n    watch = callPackage ./watch.nix {};\n    watchSimple = watch {} {\n      inherit typstSource;\n      src = myLib.cleanTypstSource ./simple;\n    };\n    watchSimpleWithFonts = watch {} {\n      inherit fontPaths typstSource;\n      src = myLib.cleanTypstSource ./simple-with-fonts;\n    };\n    watchWithMultipleParameters = watch {} {\n      inherit typstSource;\n      src = myLib.cleanTypstSource ./simple-with-multiple-parameters;\n      typstOpts = {\n        input = [\"key1=value1\" \"key2=value2\" \"key3= --spaces-are-properly-escaped\" \"key4='quotes-are-properly-escaped\\\"\"];\n      };\n    };\n    # TODO: see above\n    # watchSimpleWithTypstPackages = watch {} {\n    #   inherit typstSource;\n    #   src = myLib.cleanTypstSource ./simple-with-typst-packages;\n    # };\n    watchSimpleWithVirtualPaths = watch {} {\n      inherit virtualPaths typstSource;\n      src = myLib.cleanTypstSource ./simple-with-virtual-paths;\n    };\n\n    watchOverlappingVirtualPaths = overlappingVirtualPathsInvariant watch \"icons/link.svg\";\n    watchOverlappingVirtualPathsForce = overlappingVirtualPathsForce watch \"icons/link.svg\";\n  }))\n"
  },
  {
    "path": "checks/emoji/main.typ",
    "content": "#(emoji.tangerine)hell#(emoji.o) w#(emoji.o)rld#(emoji.face)\n"
  },
  {
    "path": "checks/overlapping-virtual-paths/main.typ",
    "content": "#lorem(100)\n\n#image(\"icons/link.svg\")\n"
  },
  {
    "path": "checks/simple/main.typ",
    "content": "#lorem(100)\n"
  },
  {
    "path": "checks/simple-with-fonts/main.typ",
    "content": "#set text(font: \"Roboto\")\n\n#lorem(100)\n"
  },
  {
    "path": "checks/simple-with-multiple-parameters/main.typ",
    "content": "#sys.inputs.key1\n#sys.inputs.key2\n"
  },
  {
    "path": "checks/simple-with-virtual-paths/main.typ",
    "content": "#lorem(100)\n\n#image(\"icons/link.svg\")\n#image(\"icons/paper-plane-tilt.svg\")\n"
  },
  {
    "path": "checks/typst-packages/main.typ",
    "content": "#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// example\n\n2 + 2 = #[add(2 + 2)]\n\n// cetz\n\n#cetz.canvas({\n  import cetz.draw: *\n\n  circle((0, 0))\n  line((0, 0), (2, 1))\n})\n\n// polylux\n\n// Make the paper dimensions fit for a presentation and the text larger\n#set page(paper: \"presentation-16-9\")\n#set text(size: 25pt)\n\n// Use #slide to create a slide and style it using your favourite Typst functions\n#slide[\n  #set align(horizon)\n  = Very minimalist slides\n\n  A lazy author\n\n  July 23, 2023\n]\n\n#slide[\n  == First slide\n\n  Some static text on this slide.\n]\n\n#slide[\n  == This slide changes!\n\n  You can always see this.\n  // Make use of features like #uncover, #only, and others to create dynamic content\n  #uncover(2)[But this appears later!]\n]\n"
  },
  {
    "path": "checks/virtual-paths.nix",
    "content": "{\n  cleanTypstSource,\n  copyVirtualPathsHook,\n  lib,\n  linkFarmFromDrvs,\n  linkVirtualPaths,\n  pkgs,\n}: let\n  inherit (lib.attrsets) filterAttrs mapAttrsToList;\n  inherit (lib.lists) all;\n  inherit (lib.strings) toShellVars;\n\n  cleanArgs = args:\n    builtins.removeAttrs args [\n      \"virtualPaths\"\n      \"assertionCommand\"\n      \"linkAssertionCommnad\"\n    ];\n\n  copyVirtualPathsHookAssertion = args @ {\n    virtualPaths,\n    assertionCommand,\n    ...\n  }:\n    pkgs.stdenvNoCC.mkDerivation ((cleanArgs args)\n      // {\n        src = cleanTypstSource ./simple;\n        nativeBuildInputs = [\n          (copyVirtualPathsHook virtualPaths)\n        ];\n        buildPhase = ''\n          runHook preBuild\n          runHook postBuild\n        '';\n        postBuild = ''\n          set -euo pipefail\n\n          assertionCommand() {\n            ${assertionCommand}\n          }\n\n          if ! assertionCommand; then\n            ${toShellVars {assertionText = assertionCommand;}}\n            echo \"assertion \\`$assertionText\\` failed\"\n            exit 1\n          fi\n\n          touch \"$out\"\n        '';\n      });\n\n  linkVirtualPathsAssertion = args @ {\n    virtualPaths,\n    assertionCommand,\n    linkAssertionCommand ? \"true\",\n    ...\n  }:\n    pkgs.stdenvNoCC.mkDerivation ((cleanArgs args)\n      // {\n        src = cleanTypstSource ./simple;\n        buildPhase = ''\n          ${linkVirtualPaths {inherit virtualPaths;}}\n          runHook postBuild\n        '';\n        postBuild = ''\n          set -euo pipefail\n\n          assertionCommand() {\n            ${assertionCommand}\n          }\n\n          linkAssertionCommand() {\n            ${linkAssertionCommand}\n          }\n\n          if ! assertionCommand; then\n            ${toShellVars {assertionText = assertionCommand;}}\n            echo \"assertion \\`$assertionText\\` failed\"\n            exit 1\n          fi\n          if ! linkAssertionCommand; then\n            ${toShellVars {assertionText = linkAssertionCommand;}}\n            echo \"assertion \\`$assertionText\\` failed\"\n            exit 1\n          fi\n\n          touch \"$out\"\n        '';\n      });\n\n  virtualPathsTestAttrs = {\n    fileSource = {\n      virtualPaths = [\"${./fixtures/icons}/link.svg\"];\n      assertionCommand = ''[ -f ./link.svg ]'';\n      linkAssertionCommand = ''[ -L ./link.svg ]'';\n    };\n\n    directorySource = {\n      virtualPaths = [./fixtures/icons];\n      assertionCommand = ''[ -f ./main.typ ] && [ -f ./link.svg ]'';\n      linkAssertionCommand = ''[ -L ./link.svg ]'';\n    };\n\n    fileSourceWithDest = {\n      virtualPaths = [\n        {\n          src = ./fixtures/icons/link.svg;\n          dest = \"link.svg\";\n        }\n      ];\n      assertionCommand = ''[ -f ./link.svg ]'';\n      linkAssertionCommand = ''[ -L ./link.svg ]'';\n    };\n\n    directorySourceWithDest = {\n      virtualPaths = [\n        {\n          src = ./fixtures/icons;\n          dest = \"icons\";\n        }\n      ];\n      assertionCommand = ''[ -d ./icons ] && [ -f ./icons/link.svg ]'';\n      linkAssertionCommand = ''[ ! -L ./icons ] && [ -L ./icons/link.svg ]'';\n    };\n\n    fileSourceWithDeepDest = {\n      virtualPaths = [\n        {\n          src = ./fixtures/icons/link.svg;\n          dest = \"assets/icons/link.svg\";\n        }\n      ];\n      assertionCommand = ''[ -d ./assets/icons ] && [ -f ./assets/icons/link.svg ]'';\n      linkAssertionCommand = ''[ ! -L ./assets ] && [ ! -L ./assets/icons ] && [ -L ./assets/icons/link.svg ]'';\n    };\n\n    directorySourceWithDeepDest = {\n      virtualPaths = [\n        {\n          src = ./fixtures/icons;\n          dest = \"assets/icons\";\n        }\n      ];\n      assertionCommand = ''[ -d ./assets/icons ] && [ -f ./assets/icons/link.svg ]'';\n      linkAssertionCommand = ''[ ! -L ./assets ] && [ ! -L ./assets/icons ] && [ -L ./assets/icons/link.svg ]'';\n    };\n\n    mergedSources = {\n      virtualPaths = [\n        {\n          src = ./fixtures/icons;\n          dest = \"icons\";\n        }\n        {\n          src = ./fixtures/more-icons;\n          dest = \"icons\";\n        }\n      ];\n      assertionCommand = ''[ -d ./icons ] && [ -f ./icons/link.svg ] && [ -f ./icons/another-link.svg ]'';\n      linkAssertionCommand = ''[ ! -L ./icons ] && [ -L ./icons/link.svg ] && [ -L ./icons/another-link.svg ]'';\n    };\n  };\n\n  skip = {\n    copyVirtualPathsHook = [];\n    linkVirtualPaths = [];\n  };\n  filterSkip = skipNames:\n    filterAttrs\n    (name: _: all (skipName: name != skipName) skipNames);\n\n  mapTestAttrs = f: skipAttrs: testGroupName:\n    mapAttrsToList\n    (name: attrs: f (attrs // {name = \"${testGroupName}-${name}\";}))\n    (filterSkip skipAttrs virtualPathsTestAttrs);\nin\n  linkFarmFromDrvs \"virtualPathsTests\"\n  (\n    (mapTestAttrs copyVirtualPathsHookAssertion skip.copyVirtualPathsHook \"copyVirtualPathsHook\")\n    ++ (mapTestAttrs linkVirtualPathsAssertion skip.linkVirtualPaths \"linkVirtualPaths\")\n  )\n"
  },
  {
    "path": "checks/watch.nix",
    "content": "{\n  lib,\n  pkgs,\n  watchTypstProject,\n}: runCommandDrvAttr: args: let\n  cleanedArgs = builtins.removeAttrs args [\n    \"src\"\n  ];\n  watch-drv = watchTypstProject ({\n      name = \"watch-check\";\n      # `typst watch` will never exit itself, but we can still check the exit status of `typst compile` for errors\n      typstWatchCommand = \"typst compile\";\n    }\n    // cleanedArgs);\nin\n  pkgs.runCommand \"watch\" (runCommandDrvAttr\n    // {\n      nativeBuildInputs =\n        (runCommandDrvAttr.nativeBuildInputs or [])\n        ++ [\n          watch-drv\n        ];\n    }) ''\n    # This is needed to imitate a user's project directory\n    cp -RLT --no-preserve=mode ${args.src} .\n\n    runHook preBuild\n    ${lib.getExe watch-drv} \"$out\"\n    runHook postBuild\n  ''\n"
  },
  {
    "path": "docs/.gitignore",
    "content": "book\n"
  },
  {
    "path": "docs/SUMMARY.md",
    "content": "<!-- markdownlint-disable MD025 -->\n\n# Summary\n\n- [Introduction](README.md)\n- [Getting Started](getting-started.md)\n\n# Recipes\n\n- [Adding dependencies](recipes/adding-dependencies.md)\n- [Specifying sources](recipes/specifying-sources.md)\n- [Declaring a shell environment](recipes/declaring-a-shell-environment.md)\n- [Using Typst packages](recipes/using-typst-packages.md)\n\n# API Reference\n\n- [Derivations](api/derivations.md)\n  - [buildTypstProject](api/derivations/build-typst-project.md)\n  - [buildTypstProjectLocal](api/derivations/build-typst-project-local.md)\n  - [devShell](api/derivations/dev-shell.md)\n  - [mkTypstDerivation](api/derivations/mk-typst-derivation.md)\n  - [watchTypstProject](api/derivations/watch-typst-project.md)\n- [Utilities](api/utilities.md)\n  - [cleanTypstSource](api/utilities/clean-typst-source.md)\n"
  },
  {
    "path": "docs/api/derivations/build-typst-project-local.md",
    "content": "# buildTypstProjectLocal\n\nReturns a derivation for compiling a Typst project and copying the output to the\ncurrent directory.\n\nThis is essentially a script which wraps\n[`buildTypstProject`](build-typst-project.md).\n\n<div class=\"warning\">\n\nUsing this derivation requires\n[`allow-import-from-derivation`](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-allow-import-from-derivation)\nto be `true` (which is the default at the time of writing).\n\nMore info: <https://nixos.org/manual/nix/stable/language/import-from-derivation>\n\n</div>\n\n<div class=\"warning\">\n\nInvoking the script produced by this derivation directly is currently\nunsupported. Instead, use `nix run`.\n\nSee [this issue](https://github.com/loqusion/typix/issues/2) for more\ninformation.\n\n</div>\n\n## Parameters\n\nAll parameters accepted by\n[`buildTypstProject`](build-typst-project.md#parameters) are also accepted by\n`buildTypstProjectLocal`. They are repeated below for convenience.\n\n### `src`\n\n{{#include common/src.md}}\n\n### `emojiFont` <sup><em>optional</em></sup> { #emojifont }\n\n{{#include common/emoji-font.md}}\n\n### `fontPaths` <sup><em>optional</em></sup> { #fontpaths }\n\n{{#include common/font-paths.md}}\n\n#### Example { #fontpaths-example }\n\n{{#include common/font-paths-example.md:buildtypstprojectlocal_example}}\n\n### `installPhaseCommand` <sup><em>optional</em></sup> { #installphasecommand }\n\n{{#include common/install-phase-command.md}}\n\n### `scriptName` <sup><em>optional</em></sup> { #scriptname }\n\n{{#include common/script-name.md}}\n\nDefault is `typst-build`.\n\n### `typstCompileCommand` <sup><em>optional</em></sup> { #typstcompilecommand }\n\n{{#include common/typst-compile-command.md}}\n\nDefault is `typst compile`.\n\n### `typstOpts` <sup><em>optional</em></sup> { #typstopts }\n\n{{#include common/typst-opts.md:head}}\n\n<!-- markdownlint-disable link-fragments -->\n\nThese are in addition to any options you manually pass in\n[`typstCompileCommand`](#typstcompilecommand).\n\n<!-- markdownlint-restore -->\n\n{{#include common/typst-opts.md:tail}}\n\n#### Example { #typstopts-example }\n\n{{#include common/typst-opts-example.md:buildtypstprojectlocal}}\n{{#include common/typst-opts-example.md:typstcompile}}\n\n### `typstOutput` <sup><em>optional</em></sup> { #typstoutput }\n\n{{#include common/typst-project-output.md:head}}\n{{#include common/typst-project-output.md:buildtypstprojectlocal}}\n\n### `typstSource` <sup><em>optional</em></sup> { #typstsource }\n\n{{#include common/typst-project-source.md}}\n\nDefault is `main.typ`.\n\n### `unstable_typstPackages` <sup><em>optional</em></sup> { #typstpackages }\n\n{{#include common/typst-packages.md:body}}\n\n#### Example { #typstpackages-example }\n\n{{#include common/typst-packages.md:example_buildtypstprojectlocal}}\n{{#include common/typst-packages.md:example_typst}}\n\n### `virtualPaths` <sup><em>optional</em></sup> { #virtualpaths }\n\n{{#include common/virtual-paths.md}}\n\n#### Example { #virtualpaths-example }\n\n{{#include common/virtual-paths-example.md:head}}\n{{#include common/virtual-paths-example.md:buildtypstprojectlocal_example}}\n{{#include common/virtual-paths-example.md:tail}}\n\n## Source\n\n- [`buildTypstProjectLocal`](https://github.com/loqusion/typix/blob/main/lib/buildTypstProjectLocal.nix)\n"
  },
  {
    "path": "docs/api/derivations/build-typst-project.md",
    "content": "# buildTypstProject\n\nReturns a derivation for compiling a Typst project.\n\nIf you want to build to the project directory, use\n[`buildTypstProjectLocal`](build-typst-project-local.md) instead.\n\n## Parameters\n\nAll parameters accepted by\n[`mkTypstDerivation`](mk-typst-derivation.md#parameters) are also accepted by\n`buildTypstProject`. They are repeated below for convenience.\n\n### `src`\n\n{{#include common/src.md}}\n\n### `emojiFont` <sup><em>optional</em></sup> { #emojifont }\n\n{{#include common/emoji-font.md}}\n\n### `fontPaths` <sup><em>optional</em></sup> { #fontpaths }\n\n{{#include common/font-paths.md}}\n\n#### Example { #fontpaths-example }\n\n{{#include common/font-paths-example.md:buildtypstproject_example}}\n\n### `installPhaseCommand` <sup><em>optional</em></sup> { #installphasecommand }\n\n{{#include common/install-phase-command.md}}\n\n### `typstCompileCommand` <sup><em>optional</em></sup> { #typstcompilecommand }\n\n{{#include common/typst-compile-command.md}}\n\nDefault is `typst compile`.\n\n### `typstOpts` <sup><em>optional</em></sup> { #typstopts }\n\n{{#include common/typst-opts.md:head}}\n\n<!-- markdownlint-disable link-fragments -->\n\nThese are in addition to any options you manually pass in\n[`typstCompileCommand`](#typstcompilecommand).\n\n<!-- markdownlint-restore -->\n\n{{#include common/typst-opts.md:tail}}\n\n#### Example { #typstopts-example }\n\n{{#include common/typst-opts-example.md:buildtypstproject}}\n{{#include common/typst-opts-example.md:typstcompile}}\n\n### `typstSource` <sup><em>optional</em></sup> { #typstsource }\n\n{{#include common/typst-project-source.md}}\n\nDefault is `main.typ`.\n\n### `unstable_typstPackages` <sup><em>optional</em></sup> { #typstpackages }\n\n{{#include common/typst-packages.md:body}}\n\n#### Example { #typstpackages-example }\n\n{{#include common/typst-packages.md:example_buildtypstproject}}\n{{#include common/typst-packages.md:example_typst}}\n\n### `virtualPaths` <sup><em>optional</em></sup> { #virtualpaths }\n\n{{#include common/virtual-paths.md}}\n\n#### Example { #virtualpaths-example }\n\n{{#include common/virtual-paths-example.md:head}}\n{{#include common/virtual-paths-example.md:buildtypstproject_example}}\n{{#include common/virtual-paths-example.md:tail}}\n\n## Source\n\n- [`buildTypstProject`](https://github.com/loqusion/typix/blob/main/lib/buildTypstProject.nix)\n"
  },
  {
    "path": "docs/api/derivations/common/emoji-font.md",
    "content": "Specify which emoji font to use. If `emojiFont` is `null`, no emoji font will\nbe included.\n\nMay be any of the following:\n\n- [`\"twemoji\"`](https://search.nixos.org/packages?channel=unstable&show=twemoji-color-font) (default)\n- [`\"twemoji-cbdt\"`](https://search.nixos.org/packages?channel=unstable&show=twitter-color-emoji)\n- [`\"noto\"`](https://search.nixos.org/packages?channel=unstable&show=noto-fonts-color-emoji)\n- [`\"noto-monochrome\"`](https://search.nixos.org/packages?channel=unstable&show=noto-fonts-monochrome-emoji)\n- [`\"emojione\"`](https://search.nixos.org/packages?channel=unstable&show=emojione)\n- `null` — Don't include any emoji font (e.g. so you can include your own)\n\n<details>\n<summary>Note about difference between <code>\"twemoji\"</code> and <code>\"twemoji-cbdt\"</code></summary>\n\nThe default Twemoji font displays color emojis using the SVG [font format],\nwhich may not be supported by some systems. If emojis aren't displaying\nproperly, using `\"twemoji-cbdt\"` may fix it.\n\n[font format]: https://www.colorfonts.wtf/\n\n</details>\n"
  },
  {
    "path": "docs/api/derivations/common/font-paths-example.md",
    "content": "<!-- markdownlint-disable-file first-line-h1 -->\n\n<!-- ANCHOR: buildtypstprojectlocal_example -->\n\n```nix\n{\n  outputs = { nixpkgs, typix }: let\n    system = \"x86_64-linux\";\n    pkgs = nixpkgs.legacyPackages.${system};\n    inherit (pkgs) lib;\n\n    build-script = typix.lib.${system}.buildTypstProjectLocal {\n      fontPaths = [\n        \"${pkgs.roboto}/share/fonts/truetype\"\n      ];\n    };\n  in {\n    apps.${system}.default = {\n      type = \"app\";\n      program = lib.getExe build-script;\n    };\n  };\n}\n```\n\n<!-- ANCHOR_END: buildtypstprojectlocal_example -->\n\n<!-- ANCHOR: buildtypstproject_example -->\n\n```nix\n{\n  outputs = { nixpkgs, typix }: let\n    system = \"x86_64-linux\";\n    pkgs = nixpkgs.legacyPackages.${system};\n  in {\n    packages.${system}.default = typix.lib.${system}.buildTypstProject {\n      fontPaths = [\n        \"${pkgs.roboto}/share/fonts/truetype\"\n      ];\n    };\n  };\n}\n```\n\n<!-- ANCHOR_END: buildtypstproject_example -->\n\n<!-- ANCHOR: devshell_example -->\n\n```nix\n{\n  outputs = { nixpkgs, typix }: let\n    system = \"x86_64-linux\";\n    pkgs = nixpkgs.legacyPackages.${system};\n  in {\n    devShells.${system}.default = typix.lib.${system}.devShell {\n      fontPaths = [\n        \"${pkgs.roboto}/share/fonts/truetype\"\n      ];\n    };\n  };\n}\n```\n\n<!-- ANCHOR_END: devshell_example -->\n\n<!-- ANCHOR: mktypstderivation_example -->\n\n```nix\n{\n  outputs = { nixpkgs, typix }: let\n    system = \"x86_64-linux\";\n    pkgs = nixpkgs.legacyPackages.${system};\n  in {\n    packages.${system}.default = typix.lib.${system}.mkTypstDerivation {\n      fontPaths = [\n        \"${pkgs.roboto}/share/fonts/truetype\"\n      ];\n    };\n  };\n}\n```\n\n<!-- ANCHOR_END: mktypstderivation_example -->\n\n<!-- ANCHOR: watchtypstproject_example -->\n\n```nix\n{\n  outputs = { nixpkgs, typix }: let\n    system = \"x86_64-linux\";\n    pkgs = nixpkgs.legacyPackages.${system};\n    inherit (pkgs) lib;\n\n    watch-script = typix.lib.${system}.watchTypstProject {\n      fontPaths = [\n        \"${pkgs.roboto}/share/fonts/truetype\"\n      ];\n    };\n  in {\n    apps.${system}.default = {\n      type = \"app\";\n      program = lib.getExe watch-script;\n    };\n  };\n}\n```\n\n<!-- ANCHOR_END: watchtypstproject_example -->\n"
  },
  {
    "path": "docs/api/derivations/common/font-paths.md",
    "content": "<!-- markdownlint-disable-file first-line-h1 -->\n\nList of sources specifying paths to font files that will be made available to\nyour Typst project. With this, you can compile Typst projects even when the\nfonts it uses are not available on your system.\n\nUsed for setting `TYPST_FONT_PATHS` (see [`text#font`][typst-ref-text--font]).\n\n[typst-ref-text--font]: https://typst.app/docs/reference/text/text/#parameters-font\n"
  },
  {
    "path": "docs/api/derivations/common/install-phase-command.md",
    "content": "<!-- markdownlint-disable first-line-h1 -->\n\nCommand (or commands) to run during\n[`installPhase`][nixpkgs-installphase].\n\n[nixpkgs-installphase]: https://nixos.org/manual/nixpkgs/stable/#ssec-install-phase\n"
  },
  {
    "path": "docs/api/derivations/common/script-name.md",
    "content": "<!-- markdownlint-disable-file first-line-h1 -->\n\nName of the script that will be added to the Nix store. You can use this name\nafter entering a development shell to invoke the script.\n"
  },
  {
    "path": "docs/api/derivations/common/src.md",
    "content": "<!-- markdownlint-disable-file first-line-h1 -->\n\n[Source](../../recipes/specifying-sources.md) containing all local files\nneeded in your Typst project.\n"
  },
  {
    "path": "docs/api/derivations/common/typst-compile-command.md",
    "content": "<!-- markdownlint-disable first-line-h1 -->\n\nBase Typst command to run to compile the project. Other arguments will be\nappended based on the parameters you supply.\n"
  },
  {
    "path": "docs/api/derivations/common/typst-opts-example.md",
    "content": "<!-- markdownlint-disable-file first-line-h1 -->\n\n<!-- ANCHOR: head -->\n\n```nix\n{\n  format = \"png\";\n  ppi = 300;\n  input = [\"key1=value1\" \"key2=value2\"];\n}\n```\n\n...will result in a command like:\n\n<!-- ANCHOR_END: head -->\n\n<!-- ANCHOR: buildtypstproject -->\n\n```nix\n{\n  outputs = { typix }: let\n    system = \"x86_64-linux\";\n  in {\n    packages.${system}.default = typix.lib.${system}.buildTypstProject {\n      typstOpts = {\n        format = \"png\";\n        ppi = 300;\n        input = [\"key1=value1\" \"key2=value2\"];\n      };\n    };\n  };\n}\n```\n\n...will result in a command like:\n\n<!-- ANCHOR_END: buildtypstproject -->\n\n<!-- ANCHOR: buildtypstprojectlocal -->\n\n```nix\n{\n  outputs = { typix }: let\n    system = \"x86_64-linux\";\n    inherit (nixpkgs) lib;\n\n    build-script = typix.lib.${system}.buildTypstProjectLocal {\n      typstOpts = {\n        format = \"png\";\n        ppi = 300;\n        input = [\"key1=value1\" \"key2=value2\"];\n      };\n    };\n  in {\n    apps.${system}.default = {\n      type = \"app\";\n      program = lib.getExe build-script;\n    };\n  };\n}\n```\n\n...will result in a command like:\n\n<!-- ANCHOR_END: buildtypstprojectlocal -->\n\n<!-- ANCHOR: watchtypstproject -->\n\n```nix\n{\n  outputs = { typix }: let\n    system = \"x86_64-linux\";\n    inherit (nixpkgs) lib;\n\n    watch-script = typix.lib.${system}.watchTypstProject {\n      typstOpts = {\n        format = \"png\";\n        ppi = 300;\n        input = [\"key1=value1\" \"key2=value2\"];\n      };\n    };\n  in {\n    apps.${system}.default = {\n      type = \"app\";\n      program = lib.getExe watch-script;\n    };\n  };\n}\n```\n\n...will result in a command like:\n\n<!-- ANCHOR_END: watchtypstproject -->\n\n<!-- ANCHOR: typstcompile -->\n\n```sh\ntypst compile --format png --ppi 300 --input key1=value1 --input key2=value2 <source> <output>\n```\n\n<!-- ANCHOR_END: typstcompile -->\n\n<!-- ANCHOR: typstwatch -->\n\n```sh\ntypst watch --format png --ppi 300 --input key1=value1 --input key2=value2 <source> <output>\n```\n\n<!-- ANCHOR_END: typstwatch -->\n"
  },
  {
    "path": "docs/api/derivations/common/typst-opts.md",
    "content": "<!-- markdownlint-disable-file first-line-h1 -->\n\n<!-- ANCHOR: head -->\n\nAttrset specifying command-line options to pass to the `typst` command.\n\n<!-- ANCHOR_END: head -->\n\n<!-- ANCHOR: tail -->\n\nDefault:\n\n```nix\n{\n  format = \"pdf\";\n}\n```\n\n<!-- ANCHOR_END: tail -->\n"
  },
  {
    "path": "docs/api/derivations/common/typst-packages.md",
    "content": "<!-- markdownlint-disable first-line-h1 -->\n\n<!-- ANCHOR: body -->\n\n<div class=\"warning\">\n\nThis is an **unstable** feature. Its API does not follow Semantic Versioning, and\nderivations relying on this feature may break at any time, even if you don't\nupdate Typst or Typix.\n\nWhen this feature reaches stability, it will be renamed to `typstPackages`.\n(The old name will be kept as an undocumented alias, to avoid unnecessary\nbreakage.)\n\n</div>\n\nList of [Typst packages] to use in your Typst project, fetched from the\nofficial Typst packages CDN at `https://packages.typst.org`.\n\nEach element of the list is an attribute set with the following keys:\n\n- `name`: the package's identifier in its namespace\n- `version`: the package's version as a full major-minor-patch triple\n- `namespace` _(optional)_: the package's namespace (defaults to `preview`)\n- `hash`: hash of the downloaded package tarball\n\n`hash` must be manually updated to match the hash of the package tarball downloaded\nfrom the registry, using the \"fake hash method\". See [Updating source hashes][fetchers-hash]\nfor how to do this.\n\nSometimes, you might encounter a Typst compilation error that looks like this:\n\n```text\n> help: error occurred while importing this module\n>   ┌─ @preview/cetz:0.3.4/src/canvas.typ:3:8\n>   │\n> 3 │ #import \"util.typ\"\n>   │         ^^^^^^^^^^\n> help: error occurred while importing this module\n>   ┌─ @preview/cetz:0.3.4/src/lib.typ:3:8\n>   │\n> 3 │ #import \"canvas.typ\": canvas\n>   │         ^^^^^^^^^^^^\n> help: error occurred while importing this module\n>   ┌─ main.typ:1:8\n>   │\n> 1 │ #import \"@preview/cetz:0.3.4\"\n>   │         ^^^^^^^^^^^^^^^^^^^^^\n>\nFor full logs, run 'nix log /nix/store/6jhjxbl7glmy4adpr5wzfgn9jvsyyipf-typst.drv'.\n```\n\nIn this example, Nix is hiding too much output for us to diagnose the issue.\nRun the command again with the [`-L` flag] (in our case, `nix run .#build -L`):\n\n[`-L` flag]: https://nix.dev/manual/nix/2.18/command-ref/new-cli/nix3-run#opt-print-build-logs\n\n```text\n> downloading @preview/oxifmt:0.2.1\n> error: failed to download package (Network Error: OpenSSL error)\n>   ┌─ @preview/cetz:0.3.4/src/deps.typ:1:8\n>   │\n> 1 │ #import \"@preview/oxifmt:0.2.1\"\n>   │         ^^^^^^^^^^^^^^^^^^^^^^^\n> help: error occurred while importing this module\n>   ┌─ @preview/cetz:0.3.4/src/util.typ:1:8\n>   │\n> 1 │ #import \"deps.typ\"\n>   │         ^^^^^^^^^^\n> help: error occurred while importing this module\n>   ┌─ @preview/cetz:0.3.4/src/canvas.typ:3:8\n>   │\n> 3 │ #import \"util.typ\"\n>   │         ^^^^^^^^^^\n> help: error occurred while importing this module\n>   ┌─ @preview/cetz:0.3.4/src/lib.typ:3:8\n>   │\n> 3 │ #import \"canvas.typ\": canvas\n>   │         ^^^^^^^^^^^^\n> help: error occurred while importing this module\n>   ┌─ main.typ:1:8\n>   │\n> 1 │ #import \"@preview/cetz:0.3.4\"\n>   │         ^^^^^^^^^^^^^^^^^^^^^\n```\n\nWe can see that `cetz` is trying to import `oxifmt` 0.2.1, but Typst can't\ndownload it because Nix derivations are (by design) run in an environment\nwhich does not support networking. To fix this, add `oxifmt` 0.2.1 to\n`unstable_typstPackages` alongside your direct dependencies.\n(Make sure to match the exact version shown in your error message!!)\n\nThere is currently no official support for [unpublished Typst packages].\nHowever, there is a [workaround].\n\n[Typst packages]: https://github.com/typst/packages\n[fetchers-hash]: https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-fetchers-updating-source-hashes\n[unpublished Typst packages]: https://github.com/typst/packages#local-packages\n[workaround]: ../../recipes/using-typst-packages.md#unpublished-typst-packages\n\n<!-- ANCHOR_END: body -->\n\n<!-- ANCHOR: example_buildtypstproject -->\n\n```nix\n{\n  outputs = { typix }: let\n    system = \"x86_64-linux\";\n  in {\n    packages.${system}.default = typix.lib.${system}.buildTypstProject {\n      unstable_typstPackages = [\n        {\n          name = \"cetz\";\n          version = \"0.3.4\";\n          hash = \"sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=\";\n        }\n        # Transitive dependencies must be manually specified\n        # `oxifmt` is required by `cetz`\n        {\n          name = \"oxifmt\";\n          version = \"0.2.1\";\n          hash = \"sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=\";\n        }\n      ];\n    };\n  };\n}\n```\n\n<!-- ANCHOR_END: example_buildtypstproject -->\n\n<!-- ANCHOR: example_buildtypstprojectlocal -->\n\n```nix\n{\n  outputs = { nixpkgs, typix }: let\n    inherit (nixpkgs) lib;\n    system = \"x86_64-linux\";\n\n    build-script = typix.lib.${system}.buildTypstProjectLocal {\n      unstable_typstPackages = [\n        {\n          name = \"cetz\";\n          version = \"0.3.4\";\n          hash = \"sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=\";\n        }\n        # Transitive dependencies must be manually specified\n        # `oxifmt` is required by `cetz`\n        {\n          name = \"oxifmt\";\n          version = \"0.2.1\";\n          hash = \"sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=\";\n        }\n      ];\n    };\n  in {\n    apps.${system}.default = {\n      type = \"app\";\n      program = lib.getExe build-script;\n    };\n  };\n}\n```\n\n<!-- ANCHOR_END: example_buildtypstprojectlocal -->\n\n<!-- ANCHOR: example_mktypstderivation -->\n\n```nix\n{\n  outputs = { typix }: let\n    system = \"x86_64-linux\";\n  in {\n    packages.${system}.default = typix.lib.${system}.mkTypstDerivation {\n      unstable_typstPackages = [\n        {\n          name = \"cetz\";\n          version = \"0.3.4\";\n          hash = \"sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=\";\n        }\n        # Transitive dependencies must be manually specified\n        # `oxifmt` is required by `cetz`\n        {\n          name = \"oxifmt\";\n          version = \"0.2.1\";\n          hash = \"sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=\";\n        }\n      ];\n    };\n  };\n}\n```\n\n<!-- ANCHOR_END: example_mktypstderivation -->\n\n<!-- ANCHOR: example_typst -->\n\nThen you can import and use the package in Typst:\n\n```typst\n#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```\n\n<!-- ANCHOR_END: example_typst -->\n"
  },
  {
    "path": "docs/api/derivations/common/typst-project-output.md",
    "content": "<!-- markdownlint-disable-file first-line-h1 -->\n\n<!-- ANCHOR: head -->\n\nDestination path for Typst output.\n\n<!-- ANCHOR_END: head -->\n\n<!-- ANCHOR: buildtypstprojectlocal -->\n\n<!-- markdownlint-disable link-fragments -->\n\nIf omitted, it will be inferred from\n[`typstSource`](#typstsource) — for example,\n`page.typ` will become `page.pdf` for PDF output.\n\n<!-- markdownlint-restore -->\n\n<!-- ANCHOR_END: buildtypstprojectlocal -->\n\n<!-- ANCHOR: watchtypstproject -->\n\n<!-- markdownlint-disable link-fragments -->\n\nIf omitted, it will be inferred from\n[`typstSource`](#typstsource) — for example,\n`page.typ` will become `page.pdf` for PDF output.\n\n<!-- markdownlint-restore -->\n\n<!-- ANCHOR_END: watchtypstproject -->\n"
  },
  {
    "path": "docs/api/derivations/common/typst-project-source.md",
    "content": "<!-- markdownlint-disable-file first-line-h1 -->\n\nTypst input file to compile.\n"
  },
  {
    "path": "docs/api/derivations/common/virtual-paths-example.md",
    "content": "<!-- markdownlint-disable-file first-line-h1 -->\n\n<!-- ANCHOR: head -->\n\nYou can specify dependencies in your flake input, and then use them in your\nproject with something like:\n\n<!-- ANCHOR_END: head -->\n\n<!-- ANCHOR: buildtypstprojectlocal_example -->\n\n```nix\n{\n  inputs = {\n    font-awesome = {\n      url = \"github:FortAwesome/Font-Awesome\";\n      flake = false;\n    };\n  };\n\n  outputs = { nixpkgs, typix, font-awesome }: let\n    system = \"x86_64-linux\";\n    inherit (nixpkgs) lib;\n\n    build-script = typix.lib.${system}.buildTypstProjectLocal {\n      virtualPaths = [\n        {\n          dest = \"icons\";\n          src = \"${font-awesome}/svgs/regular\";\n        }\n      ];\n    };\n  in {\n    apps.${system}.default = {\n      type = \"app\";\n      program = lib.getExe build-script;\n    };\n  };\n}\n```\n\n<!-- ANCHOR_END: buildtypstprojectlocal_example -->\n\n<!-- ANCHOR: buildtypstproject_example -->\n\n```nix\n{\n  inputs = {\n    font-awesome = {\n      url = \"github:FortAwesome/Font-Awesome\";\n      flake = false;\n    };\n  };\n\n  outputs = { typix, font-awesome }: let\n    system = \"x86_64-linux\";\n  in {\n    packages.${system}.default = typix.lib.${system}.buildTypstProject {\n      virtualPaths = [\n        {\n          dest = \"icons\";\n          src = \"${font-awesome}/svgs/regular\";\n        }\n      ];\n    };\n  };\n}\n```\n\n<!-- ANCHOR_END: buildtypstproject_example -->\n\n<!-- ANCHOR: devshell_example -->\n\n```nix\n{\n  inputs = {\n    font-awesome = {\n      url = \"github:FortAwesome/Font-Awesome\";\n      flake = false;\n    };\n  };\n\n  outputs = { typix, font-awesome }: let\n    system = \"x86_64-linux\";\n  in {\n    devShells.${system}.default = typix.lib.${system}.devShell {\n      virtualPaths = [\n        {\n          dest = \"icons\";\n          src = \"${font-awesome}/svgs/regular\";\n        }\n      ];\n    };\n  };\n}\n```\n\n<!-- ANCHOR_END: devshell_example -->\n\n<!-- ANCHOR: mktypstderivation_example -->\n\n```nix\n{\n  inputs = {\n    font-awesome = {\n      url = \"github:FortAwesome/Font-Awesome\";\n      flake = false;\n    };\n  };\n\n  outputs = { typix, font-awesome }: let\n    system = \"x86_64-linux\";\n  in {\n    packages.${system}.default = typix.lib.${system}.mkTypstDerivation {\n      virtualPaths = [\n        {\n          dest = \"icons\";\n          src = \"${font-awesome}/svgs/regular\";\n        }\n      ];\n    };\n  };\n}\n```\n\n<!-- ANCHOR_END: mktypstderivation_example -->\n\n<!-- ANCHOR: watchtypstproject_example -->\n\n```nix\n{\n  inputs = {\n    font-awesome = {\n      url = \"github:FortAwesome/Font-Awesome\";\n      flake = false;\n    };\n  };\n\n  outputs = { nixpkgs, typix, font-awesome }: let\n    system = \"x86_64-linux\";\n    inherit (nixpkgs) lib;\n\n    watch-script = typix.lib.${system}.watchTypstProject {\n      virtualPaths = [\n        {\n          dest = \"icons\";\n          src = \"${font-awesome}/svgs/regular\";\n        }\n      ];\n    };\n  in {\n    apps.${system}.default = {\n      type = \"app\";\n      program = lib.getExe watch-script;\n    };\n  };\n}\n```\n\n<!-- ANCHOR_END: watchtypstproject_example -->\n\n<!-- ANCHOR: typst_example -->\n\n```typst\n#image(\"icons/heart.svg\")\n```\n\n<!-- ANCHOR_END: typst_example -->\n\n<!-- ANCHOR: tail -->\n\nThen, reference the files in Typst:\n\n```typst\n#image(\"icons/heart.svg\")\n```\n\n<!-- ANCHOR_END: tail -->\n"
  },
  {
    "path": "docs/api/derivations/common/virtual-paths.md",
    "content": "<!-- markdownlint-disable-file first-line-h1 -->\n\nList of sources that will be made virtually available to your Typst project.\nUseful for projects which rely on remote resources, such as\n[images][typst-ref-image] or [data][typst-ref-data-loading].\n\nEach element of the list is an attribute set with the following keys:\n\n- `src`: path to source file or directory\n- `dest` _(optional)_: path where file(s) will be made available (defaults to `.`)\n  - If `src` is a directory, `dest` will be a directory containing the files in that directory.\n    - Specifying the same `dest` for multiple `src` directories will merge them.\n  - If `src` is a file, `dest` will be a copy of that file.\n\nInstead of an attrset, you may use a path which will be interpreted the same as\nif you had specified an attrset with just `src`.\n\n[typst-ref-data-loading]: https://typst.app/docs/reference/data-loading/\n[typst-ref-image]: https://typst.app/docs/reference/visualize/image/\n"
  },
  {
    "path": "docs/api/derivations/dev-shell.md",
    "content": "# devShell\n\nSets up a shell environment that activates with [`nix develop`][nix-ref-develop]\nor [`direnv`][direnv].\n\n## Parameters\n\n**Note:** All parameters for [`mkShell`][nixpkgs-mkshell] are also\nsupported.\n\n### `emojiFont` <sup><em>optional</em></sup> { #emojifont }\n\n{{#include common/emoji-font.md}}\n\n### extraShellHook <sup><em>optional</em></sup> { #extrashellhook }\n\nBash statements added to the [`shellHook`][nixpkgs-mkshell-attributes]\nattribute.\n\n### `fontPaths` <sup><em>optional</em></sup> { #fontpaths }\n\n{{#include common/font-paths.md}}\n\n#### Example { #fontpaths-example }\n\n{{#include common/font-paths-example.md:devshell_example}}\n\n### `forceVirtualPaths` <sup><em>optional</em></sup> { #forcevirtualpaths }\n\n<!-- markdownlint-disable link-fragments -->\n\nIf there are any conflicts between [`virtualPaths`](#virtualpaths) and files in your\nproject directory, they will not be overwritten unless `forceVirtualPaths` is\n`true`.\n\nDefault is `false`.\n\n<!-- markdownlint-restore -->\n\n### `virtualPaths` <sup><em>optional</em></sup> { #virtualpaths }\n\n{{#include common/virtual-paths.md}}\n\n<!-- markdownlint-disable link-fragments -->\n\n**NOTE:** Any paths specified here will not overwrite files in your project\ndirectory, unless you set [`forceVirtualPaths`](#forcevirtualpaths) to `true`.\n\n<!-- markdownlint-restore -->\n\n#### Example { #virtualpaths-example }\n\n{{#include common/virtual-paths-example.md:head}}\n{{#include common/virtual-paths-example.md:devshell_example}}\n{{#include common/virtual-paths-example.md:tail}}\n\n## Source\n\n- [`devShell`](https://github.com/loqusion/typix/blob/main/lib/devShell.nix)\n\n[direnv]: https://direnv.net/\n[nix-ref-develop]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-develop\n[nixpkgs-mkshell-attributes]: https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-mkShell-attributes\n[nixpkgs-mkshell]: https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-mkShell\n"
  },
  {
    "path": "docs/api/derivations/mk-typst-derivation.md",
    "content": "# mkTypstDerivation\n\nA generic derivation constructor for running Typst commands.\n\n## Parameters\n\n**Note:** All parameters for `stdenv.mkDerivation`[^stdenv] are also available.\n\n### `buildPhaseTypstCommand`\n\nCommand (or commands) to run during [`buildPhase`][nixpkgs-buildphase]. Any\noutput should typically be written to `$out`, e.g. `typst compile <source>\n\"$out\"`.\n\nSee also: [Typst CLI Usage][typst-cli-usage]\n\n### `src`\n\n{{#include common/src.md}}\n\n### `emojiFont` <sup><em>optional</em></sup> { #emojifont }\n\n{{#include common/emoji-font.md}}\n\n### `fontPaths` <sup><em>optional</em></sup> { #fontpaths }\n\n{{#include common/font-paths.md}}\n\n#### Example { #fontpaths-example }\n\n{{#include common/font-paths-example.md:mktypstderivation_example}}\n\n### `installPhaseCommand` <sup><em>optional</em></sup> { #installphasecommand }\n\n{{#include common/install-phase-command.md}}\n\n### `unstable_typstPackages` <sup><em>optional</em></sup> { #typstpackages }\n\n{{#include common/typst-packages.md:body}}\n\n#### Example { #typstpackages-example }\n\n{{#include common/typst-packages.md:example_mktypstderivation}}\n{{#include common/typst-packages.md:example_typst}}\n\n### `virtualPaths` <sup><em>optional</em></sup> { #virtualpaths }\n\n{{#include common/virtual-paths.md}}\n\n#### Example { #virtualpaths-example }\n\n{{#include common/virtual-paths-example.md:head}}\n{{#include common/virtual-paths-example.md:mktypstderivation_example}}\n{{#include common/virtual-paths-example.md:tail}}\n\n## Source\n\n- [`mkTypstDerivation`](https://github.com/loqusion/typix/blob/main/lib/mkTypstDerivation.nix)\n\n## Footnotes\n\n[^stdenv]: [`stdenv`][nixpkgs-stdenv] (not for the faint of heart)\n\n[nixpkgs-buildphase]: https://nixos.org/manual/nixpkgs/stable/#build-phase\n[nixpkgs-stdenv]: https://nixos.org/manual/nixpkgs/stable/#chap-stdenv\n[typst-cli-usage]: https://github.com/typst/typst#usage\n"
  },
  {
    "path": "docs/api/derivations/watch-typst-project.md",
    "content": "# watchTypstProject\n\nReturns a derivation for a script that watches an input file and recompiles on\nchanges.\n\n## Parameters\n\n**Note:** All parameters for\n[`writeShellApplication`][nixpkgs-writeshellapplication] are also supported\n(besides `text`).\n\n### `emojiFont` <sup><em>optional</em></sup> { #emojifont }\n\n{{#include common/emoji-font.md}}\n\n### `fontPaths` <sup><em>optional</em></sup> { #fontpaths }\n\n{{#include common/font-paths.md}}\n\n#### Example { #fontpaths-example }\n\n{{#include common/font-paths-example.md:watchtypstproject_example}}\n\n### `forceVirtualPaths` <sup><em>optional</em></sup> { #forcevirtualpaths }\n\n<!-- markdownlint-disable link-fragments -->\n\nIf there are any conflicts between [`virtualPaths`](#virtualpaths) and files in your\nproject directory, they will not be overwritten unless `forceVirtualPaths` is\n`true`.\n\nDefault is `false`.\n\n<!-- markdownlint-restore -->\n\n### `scriptName` <sup><em>optional</em></sup> { #scriptname }\n\n{{#include common/script-name.md}}\n\nDefault is `typst-watch`.\n\n### `typstOpts` <sup><em>optional</em></sup> { #typstopts }\n\n{{#include common/typst-opts.md:head}}\n\n<!-- markdownlint-disable link-fragments -->\n\nThese are in addition to any options you manually pass in\n[`typstWatchCommand`](#typstwatchcommand).\n\n<!-- markdownlint-restore -->\n\n{{#include common/typst-opts.md:tail}}\n\n#### Example { #typstopts-example }\n\n{{#include common/typst-opts-example.md:watchtypstproject}}\n{{#include common/typst-opts-example.md:typstwatch}}\n\n### `typstOutput` <sup><em>optional</em></sup> { #typstoutput }\n\n{{#include common/typst-project-output.md:head}}\n{{#include common/typst-project-output.md:watchtypstproject}}\n\n### `typstSource` <sup><em>optional</em></sup> { #typstsource }\n\n{{#include common/typst-project-source.md}}\n\nDefault is `main.typ`.\n\n### `typstWatchCommand` <sup><em>optional</em></sup> { #typstwatchcommand }\n\nBase Typst command to run to watch the project. Other arguments will be appended\nbased on the other parameters you supply.\n\nDefault is `typst watch`.\n\n### `virtualPaths` <sup><em>optional</em></sup> { #virtualpaths }\n\n{{#include common/virtual-paths.md}}\n\n<!-- markdownlint-disable link-fragments -->\n\n**NOTE:** Any paths specified here will not overwrite files in your project\ndirectory, unless you set [`forceVirtualPaths`](#forcevirtualpaths) to `true`.\n\n<!-- markdownlint-restore -->\n\n#### Example { #virtualpaths-example }\n\n{{#include common/virtual-paths-example.md:head}}\n{{#include common/virtual-paths-example.md:watchtypstproject_example}}\n{{#include common/virtual-paths-example.md:tail}}\n\n## Source\n\n- [`watchTypstProject`](https://github.com/loqusion/typix/blob/main/lib/watchTypstProject.nix)\n\n[nixpkgs-writeshellapplication]: https://nixos.org/manual/nixpkgs/stable/#trivial-builder-writeShellApplication\n"
  },
  {
    "path": "docs/api/derivations.md",
    "content": "# Derivations\n\nAs paraphrased from [the Nix Reference Manual][nix-ref-derivations]:\n\n> A derivation is a specification for running an executable on precisely defined\n> input files to repeatably produce output files at uniquely determined file\n> system paths.\n\nThe derivation constructors defined in Typix extend this behavior by running\n`typst compile`/`typst watch` in a context where all the dependencies of your\nTypst project (fonts, images, etc.) will be made available to the Typst\ncompiler, regardless of if they're already present on the system it runs on.\n\n- [`buildTypstProjectLocal`](derivations/build-typst-project-local.md) — Returns\n  a derivation for compiling a Typst project and copying the output to the\n  current directory.\n- [`buildTypstProject`](derivations/build-typst-project.md) — Returns a\n  derivation for compiling a Typst project.\n- [`devShell`](derivations/dev-shell.md) — Sets up a shell environment that\n  activates with [`nix develop`][nix-ref-develop] or [`direnv`][direnv].\n- [`mkTypstDerivation`](derivations/mk-typst-derivation.md) — A generic\n  derivation constructor for running Typst commands.\n- [`watchTypstDerivation`](derivations/watch-typst-project.md) — Returns a\n  derivation for a script that watches an input file and recompiles on changes.\n\n[direnv]: https://direnv.net/\n[nix-ref-derivations]: https://nixos.org/manual/nix/stable/language/derivations.html\n[nix-ref-develop]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-develop\n"
  },
  {
    "path": "docs/api/utilities/clean-typst-source.md",
    "content": "# cleanTypstSource\n\nFilters a source tree to only contain files that are usually pertinent to a\nTypst project.\n\n<!-- markdownlint-disable heading-increment -->\n\n#### Example\n\n<!-- markdownlint-restore -->\n\n```nix\n{\n  outputs = {\n    nixpkgs,\n    typix,\n  }: let\n    system = \"x86_64-linux\";\n    typixLib = typix.lib.${system};\n  in {\n    packages.${system}.default = typixLib.mkTypstDerivation {\n      src = typixLib.cleanTypstSource ./.;\n    };\n  };\n}\n```\n"
  },
  {
    "path": "docs/api/utilities.md",
    "content": "# Utilities\n\n- [`cleanTypstSource`](./utilities/clean-typst-source.md)\n"
  },
  {
    "path": "docs/book.toml",
    "content": "[book]\nauthors = [\"loqusion\"]\nlanguage = \"en\"\nsrc = \".\"\ntitle = \"Typix\"\n\n[output.html]\ndefault-theme = \"ayu\"\npreferred-dark-theme = \"ayu\"\ngit-repository-url = \"https://github.com/loqusion/typix\"\nedit-url-template = \"https://github.com/loqusion/typix/edit/main/docs/{path}\"\n"
  },
  {
    "path": "docs/getting-started.md",
    "content": "# Getting Started\n\nFirst, [install Nix][install-nix]:\n\n[install-nix]: https://github.com/DeterminateSystems/nix-installer\n\n<!-- markdownlint-disable MD013 -->\n\n```bash\ncurl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install\n```\n\n<!-- markdownlint-enable MD013 -->\n\nMake sure `nix-command` and `flakes` are enabled:\n\n`~/.config/nix/nix.conf`\n\n```ini\nexperimental-features = nix-command flakes\n```\n\nFinally, you can initialize a flake from the default template:\n\n```bash\nnix flake init --refresh -t github:loqusion/typix\n```\n\n> Alternatively, you can use a template demonstrating [Typst packages] usage:\n>\n> ```bash\n> nix flake init --refresh -t 'github:loqusion/typix#with-typst-packages'\n> ```\n>\n> [Typst packages]: ./recipes/using-typst-packages.md\n\n---\n\nHere are some commands you can run from any template:\n\n- `nix run .#watch` — watch the input files and recompile on changes\n- `nix run .#build` — compile and copy the output to the current directory\n\nFor more info, see [`nix run --help`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-run).\n"
  },
  {
    "path": "docs/recipes/adding-dependencies.md",
    "content": "# Adding dependencies\n\nYou can add dependencies to your [flake\ninputs][nix-ref-flake-inputs][^zero-to-nix-flakes] so that Typst compilation\ndoes not depend on the transient state of the local system: instead, any\ndependencies are automatically fetched and made available in a sandboxed\nenvironment.\n\nExamples of dependencies you might want to add:\n\n- [Font files][typst-ref-text--font] —\n  [`fontPaths`](../api/derivations/mk-typst-derivation.md#fontpaths)\n- [Image files][typst-ref-image] —\n  [`virtualPaths`](../api/derivations/mk-typst-derivation.md#virtualpaths)\n- [Data files][typst-ref-data-loading] (e.g. [JSON][typst-ref-data-json],\n  [TOML][typst-ref-data-toml], [XML][typst-ref-data-xml]) —\n  [`virtualPaths`](../api/derivations/mk-typst-derivation.md#virtualpaths)\n\nFor a more complete description of how to specify flake inputs, see the Nix\nReference Manual [section on flakerefs][nix-ref-flake-references].\n\n[^zero-to-nix-flakes]: See also: <https://zero-to-nix.com/concepts/flakes>\n\n## nixpkgs\n\nMany popular fonts are available as packages to [nixpkgs][nixpkgs], so if you're\nwanting to add a font it's good to try that before anything else.\n\nTo determine the path(s) to the files you wish to include, first run the\nfollowing command (which creates a symbolic link named `result` in the current\ndirectory):\n\n```bash\nnix-build '<nixpkgs>' --out-link result --attr PACKAGE_NAME\n```\n\nThen explore the `result` with whichever commands you like — for instance, using\n[`unix-tree`][unix-tree]:\n\n```bash\ntree ./result\n```\n\n```text\nresult\n└── share\n    └── fonts\n        └── truetype\n            ├── Roboto-BlackItalic.ttf\n            ├── Roboto-Black.ttf\n            ├── Roboto-BoldItalic.ttf\n            ├── Roboto-Bold.ttf\n            ├── RobotoCondensed-BoldItalic.ttf\n            ├── RobotoCondensed-Bold.ttf\n            ├── RobotoCondensed-Italic.ttf\n            ├── RobotoCondensed-LightItalic.ttf\n            ├── RobotoCondensed-Light.ttf\n            ├── RobotoCondensed-MediumItalic.ttf\n            ├── RobotoCondensed-Medium.ttf\n            ├── RobotoCondensed-Regular.ttf\n            ├── Roboto-Italic.ttf\n            ├── Roboto-LightItalic.ttf\n            ├── Roboto-Light.ttf\n            ├── Roboto-MediumItalic.ttf\n            ├── Roboto-Medium.ttf\n            ├── Roboto-Regular.ttf\n            ├── Roboto-ThinItalic.ttf\n            └── Roboto-Thin.ttf\n```\n\nHere, we can see that the relative path should be `share/fonts/truetype`, so in\n`flake.nix` we use that information like so:\n\n{{#include ../api/derivations/common/font-paths-example.md:mktypstderivation_example}}\n\n## GitHub\n\n[GitHub](https://github.com) hosts a great deal of fonts and icon libraries, and\nNix makes it easy to add GitHub repositories as flake inputs with [URL-like\nsyntax][nix-ref-flake-url].\n\nHere's an example of specifying a GitHub URL as a flake input and adding it to\n[`virtualPaths`](../api/derivations/mk-typst-derivation.md#virtualpaths), specifying\nthat we want the `svgs/regular` directory to be accessible from `icons`:\n\n{{#include ../api/derivations/common/virtual-paths-example.md:mktypstderivation_example}}\n\nWith this, we can use it in Typst as if it were any other local path:\n\n{{#include ../api/derivations/common/virtual-paths-example.md:typst_example}}\n\n## Using local files\n\nIf all else fails, you can always manually download what you need and move it to\nyour Typst project directory.\n\nHere's what you need to know:\n\n- The Typst compiler invoked by\n  [`buildTypstProject`](../api/derivations/build-typst-project.md),\n  [`buildTypstProjectLocal`](../api/derivations/build-typst-project-local.md),\n  etc. won't see the files you've added unless they're present in one of the\n  source tree parameters — in practice, these are\n  [`src`](../api/derivations/mk-typst-derivation.md#src),\n  [`fontPaths`](../api/derivations/mk-typst-derivation.md#fontpaths), and\n  [`virtualPaths`](../api/derivations/mk-typst-derivation.md#virtualpaths). (This\n  doesn't apply to\n  [`watchTypstProject`](../api/derivations/watch-typst-project.md).)\n- Paths to font files must still be passed in\n  [`fontPaths`](../api/derivations/mk-typst-derivation.md#fontpaths) or\n  otherwise made known to the Typst compiler (e.g. via\n  [`--font-path`][typst-man-compile--font-path]).\n\nSee [\"Specifying sources\"](./specifying-sources.md#expanding-a-source-tree) for\ninformation on how to expand a source tree to include the files you need.\n\n[nix-ref-flake-inputs]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake#flake-inputs\n[nix-ref-flake-references]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake#flake-references\n[nix-ref-flake-url]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake#url-like-syntax\n[nixpkgs]: https://search.nixos.org/packages\n[typst-man-compile--font-path]: https://man.archlinux.org/man/typst-compile.1.en#font\n[typst-ref-data-json]: https://typst.app/docs/reference/data-loading/json/\n[typst-ref-data-loading]: https://typst.app/docs/reference/data-loading/\n[typst-ref-data-toml]: https://typst.app/docs/reference/data-loading/toml/\n[typst-ref-data-xml]: https://typst.app/docs/reference/data-loading/xml/\n[typst-ref-image]: https://typst.app/docs/reference/visualize/image/\n[typst-ref-text--font]: https://typst.app/docs/reference/text/text/#parameters-font\n[unix-tree]: https://gitlab.com/OldManProgrammer/unix-tree\n"
  },
  {
    "path": "docs/recipes/declaring-a-shell-environment.md",
    "content": "# Declaring a shell environment\n\nYou can automatically pull your project's dependencies into your shell by\ndeclaring a [shell environment][nix-dev-declarative-shell] and then activating\nit with [`nix develop`][nix-ref-develop] or [`direnv`][direnv].\n\nHere's an example in a flake using Typix's\n[`devShell`](../api/derivations/dev-shell.md):\n\n```nix\n{\n  outputs = { typix }: let\n    system = \"x86_64-linux\";\n    typixLib = typix.lib.${system};\n\n    watch-script = typixLib.watchTypstProject {/* ... */};\n  in {\n    # packages, apps, etc. omitted\n\n    devShells.${system}.default = typixLib.devShell {\n      fontPaths = [/* ... */];\n      virtualPaths = [/* ... */];\n      packages = [\n        watch-script\n      ];\n    };\n  };\n}\n```\n\nWhat this example does:\n\n- Fonts added to [`fontPaths`](../api/derivations/dev-shell.md#fontpaths) will\n  be made available to `typst` commands via the `TYPST_FONT_PATHS` environment\n  variable.\n- Files in [`virtualPaths`](../api/derivations/dev-shell.md#virtualpaths) will be\n  recursively symlinked to the current directory (only overwriting existing\n  files when\n  [`forceVirtualPaths`](../api/derivations/dev-shell.md#forcevirtualpaths) is\n  `true`).\n- For convenience, the\n  [`typst-watch`](../api/derivations/watch-typst-project.md#scriptname) script\n  is added, which will run\n  [`watchTypstProject`](../api/derivations/watch-typst-project.md).\n\n[direnv]: https://direnv.net/\n[nix-dev-declarative-shell]: https://nix.dev/tutorials/first-steps/declarative-shell\n[nix-ref-develop]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-develop\n"
  },
  {
    "path": "docs/recipes/specifying-sources.md",
    "content": "# Specifying sources\n\nA number of derivations in Typix accept source trees as parameters, such as\n[`src`](../api/derivations/mk-typst-derivation.md#src),\n[`fontPaths`](../api/derivations/mk-typst-derivation.md#fontpaths), and\n[`virtualPaths`](../api/derivations/mk-typst-derivation.md#virtualpaths). Specifying\nthese is usually as simple as\n[`cleanTypstSource`](../api/utilities/clean-typst-source.md) in the case of\n`src` and string interpolation (via `${...}`) in the case of `fontPaths` and\n`virtualPaths`, but there are situations where more is required or desirable.\n\n## Expanding a source tree\n\n> TL;DR: you can use [`lib.sources.cleanSource`][nixpkgs-sources-cleansource],\n> but the problem with this approach is that every change to a file tracked by\n> git will invalidate the cache and trigger a rebuild.\n\nTo include more _local files_[^fileset-note] in a source tree, you can use a\ncombination of different functions in [`lib.fileset`][nixpkgs-fileset]\nsuch as [`lib.fileset.unions`][nixpkgs-fileset-unions],\n[`lib.fileset.fromSource`][nixpkgs-fileset-fromsource], and\n[`lib.fileset.toSource`][nixpkgs-fileset-tosource], like so:\n\n```nix\n{\n  outputs = { nixpkgs, typix }: let\n    system = \"x86_64-linux\";\n    pkgs = nixpkgs.legacyPackages.${system};\n    inherit (pkgs) lib;\n    typixLib = typix.lib.${system};\n    myTypstSource = typixLib.cleanTypstSource ./.;\n  in {\n    packages.${system}.default = typixLib.mkTypstDerivation {\n      src = lib.fileset.toSource {\n        root = ./.;\n        fileset = lib.fileset.unions [\n          (lib.fileset.fromSource myTypstSource)\n          ./path.svg\n          ./other/path.svg\n          ./another\n        ];\n      };\n    };\n  };\n}\n```\n\nThis will create a source tree that looks something like:\n\n```text\n/nix/store/...\n├── another\n│  ├── path1.svg\n│  ├── path2.svg\n│  └── path3.svg\n├── path.svg\n├── other\n│  └── path.svg\n└── ...\n```\n\n<!-- prettier-ignore-start -->\n[^fileset-note]: `lib.fileset` functions can only be used with local files, not\ne.g. flake inputs, which is what\n[`virtualPaths`](../api/derivations/mk-typst-derivation.md#virtualpaths) is for.\n<!-- prettier-ignore-end -->\n\n## Source filtering\n\nYou can do source filtering primarily using\n[`builtins.filterSource`][nix-ref-builtins-filtersource] and functions in\n[`lib.sources`][nixpkgs-sources] such as\n[`lib.sources.cleanSourceWith`][nixpkgs-sources-cleansourcewith].\n\nA more detailed explanation can be found in the Nix discussion: [\"Filtering\nSource Trees with Nix and Nixpkgs\"][nix-discussion-source-filtering].\n\nHere's an example which picks specific files by name:\n\n```nix\n{\n  outputs = { nixpkgs, typix, font-awesome }: let\n    system = \"x86_64-linux\";\n    pkgs = nixpkgs.legacyPackages.${system};\n\n    fontAwesomeSubset = let\n      icons = [\n        \"gem.svg\"\n        \"heart.svg\"\n        \"lightbulb.svg\"\n      ];\n    in lib.sources.cleanSourceWith {\n      src = \"${font-awesome}/svgs/regular\";\n      filter = path: type:\n        builtins.any (icon: builtins.baseNameOf path == icon) icons;\n    };\n  in {\n    packages.${system}.default = typix.lib.${system}.mkTypstDerivation {\n      virtualPaths = [\n        fontAwesomeSubset\n      ];\n    };\n  };\n}\n```\n\n[nix-discussion-source-filtering]: https://discourse.nixos.org/t/filtering-source-trees-with-nix-and-nixpkgs/19148\n[nix-ref-builtins-filtersource]: https://nixos.org/manual/nix/stable/language/builtins.html#builtins-filterSource\n[nixpkgs-fileset-fromsource]: https://nixos.org/manual/nixpkgs/stable/#function-library-lib.fileset.fromSource\n[nixpkgs-fileset-tosource]: https://nixos.org/manual/nixpkgs/stable/#function-library-lib.fileset.toSource\n[nixpkgs-fileset-unions]: https://nixos.org/manual/nixpkgs/stable/#function-library-lib.fileset.unions\n[nixpkgs-fileset]: https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-fileset\n[nixpkgs-sources-cleansource]: https://nixos.org/manual/nixpkgs/stable/#function-library-lib.sources.cleanSource\n[nixpkgs-sources-cleansourcewith]: https://nixos.org/manual/nixpkgs/stable/#function-library-lib.sources.cleanSourceWith\n[nixpkgs-sources]: https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-sources\n"
  },
  {
    "path": "docs/recipes/using-typst-packages.md",
    "content": "# Using Typst packages\n\n> TL;DR: Use [this example][published-example] as a template:\n>\n> ```bash\n> nix flake init --refresh -t 'github:loqusion/typix#with-typst-packages'\n> ```\n>\n> [published-example]: https://github.com/loqusion/typix/blob/main/examples/typst-packages/flake.nix\n\n<div class=\"warning\">\n\nTypst packages are considered experimental at the time of writing, and the\nmethods documented here may become outdated at any point if breaking changes are\nmade upstream.\n\nIf you experience any unexpected errors or bugs, and there are no [open issues]\nrelated to your problem, feel free to [open an issue].\n\n[open issues]: https://github.com/loqusion/typix/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22typst+packages%22\n[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+\n\n</div>\n\nThere are two types of [Typst packages][typst-packages]: _published_ and _unpublished_:\n\n- [_Published_ packages](#published-typst-packages) are those submitted to the\n  [Typst Packages repository][typst-packages] and can be browsed on [Typst Universe].\n- [_Unpublished_ packages](#unpublished-typst-packages) are packages that are\n  only available from unofficial sources.\n  They can be stored locally on your system, on a GitHub repository, or elsewhere.\n  (\"Unpublished\" can also refer to unpublished versions of a package which has\n  published versions.)\n\n[Typst Universe]: https://typst.app/universe/\n\n[Transitive dependencies] — that is, a _dependency's_ dependencies — must be\nadded explicitly, in addition to any direct dependencies you have. For\ninstance, `cetz` 0.3.4 depends on `oxifmt` 0.2.1, so if you use `cetz` 0.3.4 you\nmust also ensure `oxifmt` 0.2.1 is provided. This applies recursively: if you\ndepend on `A` which depends on `B` and `B` depends on `C`, you must explicitly\nspecify both `B` _and_ `C`, in addition to `A`. Also, the precise version is\nimportant: if different versions of the same package are imported, _both\nversions_ must be specified.\n\n[Transitive dependencies]: https://en.wikipedia.org/wiki/Transitive_dependency\n\nThe method to add Typst packages differs depending on whether they are published\nor unpublished.\n\n## Published Typst packages\n\nPublished Typst packages work out of the box for for [`watchTypstProject`] and\ncommands executed while [`devShell`] is active.\n\nFor [`buildTypstProject`], [`buildTypstProjectLocal`], and [`mkTypstDerivation`],\nthere are two methods:\n\n<!-- markdownlint-disable link-fragments -->\n\n- [`unstable_typstPackages`](#the-typstpackages-attribute) _(recommended)_\n- [`TYPST_PACKAGE_CACHE_PATH`](#the-typst_package_cache_path-environment-variable)\n\n<!-- markdownlint-enable link-fragments -->\n\nIt is recommended to use `unstable_typstPackages`, as it is faster and consumes\nless disk space.\n\n### The `unstable_typstPackages` attribute { #the-typstpackages-attribute }\n\nThe `unstable_typstPackages` attribute is used to fetch packages from the official\nTypst packages CDN at `https://packages.typst.org`.\n\nFor more information, see the respective documentation for the attribute on\n[`buildTypstProject`], [`buildTypstProjectLocal`], and [`mkTypstDerivation`].\n\n```nix\n{\n  outputs = {\n    nixpkgs,\n    typix,\n  }: let\n    inherit (nixpkgs) lib;\n    system = \"x86_64-linux\";\n\n    unstable_typstPackages = [\n      {\n        name = \"cetz\";\n        version = \"0.3.4\";\n        hash = \"sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=\";\n      }\n      # Transitive dependencies must be manually specified\n      # `oxifmt` is required by `cetz`\n      {\n        name = \"oxifmt\";\n        version = \"0.2.1\";\n        hash = \"sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=\";\n      }\n    ];\n\n    build-drv = typix.lib.${system}.buildTypstProject {\n      inherit unstable_typstPackages;\n      # ...\n    };\n\n    build-script = typix.lib.${system}.buildTypstProjectLocal {\n      inherit unstable_typstPackages;\n      # ...\n    };\n  in {\n    packages.${system}.default = build-drv;\n    apps.${system}.default = {\n      type = \"app\";\n      program = lib.getExe build-script;\n    };\n  };\n}\n```\n\n### The `TYPST_PACKAGE_CACHE_PATH` environment variable\n\nThis method downloads the _entire_ contents of the [Typst Packages repository][typst-packages],\nmaking all packages available in your Typst project.\n\nFirst, add the repository to flake inputs:\n\n```nix\n{\n  inputs.typst-packages = {\n    url = \"github:typst/packages\";\n    flake = false;\n  };\n}\n```\n\nThen, use it in flake outputs:\n\n```nix\n{\n  outputs = {\n    nixpkgs,\n    typix,\n    typst-packages,\n  }: let\n    inherit (nixpkgs) lib;\n    system = \"x86_64-linux\";\n\n    build-drv = typix.lib.${system}.buildTypstProject {\n      TYPST_PACKAGE_CACHE_PATH = \"${typst-packages}/packages\";\n      # ...\n    };\n\n    build-script = typix.lib.${system}.buildTypstProjectLocal {\n      TYPST_PACKAGE_CACHE_PATH = \"${typst-packages}/packages\";\n      # ...\n    };\n  in {\n    packages.${system}.default = build-drv;\n    apps.${system}.default = {\n      type = \"app\";\n      program = lib.getExe build-script;\n    };\n  };\n}\n```\n\n## Unpublished Typst packages\n\nIf the Typst package you want to use is stored locally — in the same repository\nas your flake — all you have to do is directly [import] the entrypoint module:\n\n[import]: https://typst.app/docs/reference/foundations/module/\n\n```typst\n#import \"my-typst-package/src/lib.typ\": my-item\n\n#my-item\n```\n\nYou may want to [expand the source tree] or [filter certain files].\n\n[expand the source tree]: ../recipes/specifying-sources.md#expanding-a-source-tree\n[filter certain files]: ../recipes/specifying-sources.md#source-filtering\n\nIf the imported module imports any packages, those packages must be specified\nusing one of the methods documented in this chapter.\n\nIf you need to fetch an unpublished Typst package from a GitHub repository instead,\nsee below.\n\n### Fetching from a GitHub repository\n\n> You can use [this example][unpublished-example] as a template:\n>\n> ```bash\n> nix flake init --refresh -t 'github:loqusion/typix#with-typst-packages-unpublished'\n> ```\n>\n> [unpublished-example]: https://github.com/loqusion/typix/blob/main/examples/typst-packages-unpublished/flake.nix\n\nAdd the GitHub repository containing the unpublished Typst package to [flake inputs]:\n\n[flake inputs]: https://nix.dev/manual/nix/2.24/command-ref/new-cli/nix3-flake#flake-references\n\n```nix\n{\n  inputs = {\n    my-typst-package = {\n      url = \"github:loqusion/my-typst-package\";\n      flake = false;\n    };\n  };\n}\n```\n\nThen, create a derivation containing the inputs and pass it to Typst with\nthe `TYPST_PACKAGE_PATH` environment variable:\n\n<!-- markdownlint-disable line-length -->\n\n```nix\n{\n  outputs = {\n    nixpkgs,\n    typix,\n    my-typst-package,\n  }: let\n    system = \"x86_64-linux\";\n    pkgs = nixpkgs.legacyPackages.${system};\n    inherit (pkgs) lib;\n    inherit (lib.strings) escapeShellArg;\n\n    mkTypstPackagesDrv = name: entries: let\n      linkFarmEntries =\n        lib.foldl (set: {\n          name,\n          version,\n          namespace,\n          input,\n        }:\n          set\n          // {\n            \"${namespace}/${name}/${version}\" = input;\n          })\n        {}\n        entries;\n    in\n      pkgs.linkFarm name linkFarmEntries;\n\n    unpublishedTypstPackages = mkTypstPackagesDrv \"unpublished-typst-packages\" [\n      # Unpublished packages can be added here\n      {\n        name = \"my-typst-package\";\n        version = \"0.1.0\";\n        namespace = \"local\";\n        input = my-typst-package;\n      }\n    ];\n\n    # Any transitive dependencies on published packages must be added here\n    unstable_typstPackages = [\n      {\n        name = \"oxifmt\";\n        version = \"0.2.1\";\n        hash = \"sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=\";\n      }\n    ];\n\n    build-drv = typix.lib.${system}.buildTypstProject {\n      inherit unstable_typstPackages;\n      TYPST_PACKAGE_PATH = unpublishedTypstPackages;\n      # ...\n    };\n\n    build-script = typix.lib.${system}.buildTypstProjectLocal {\n      inherit unstable_typstPackages;\n      TYPST_PACKAGE_PATH = unpublishedTypstPackages;\n      # ...\n    };\n\n    watch-script = typix.lib.${system}.watchTypstProject {\n      # `watchTypstProject` can already access published packages, so\n      # `unstable_typstPackages` is not needed here\n      typstWatchCommand = \"TYPST_PACKAGE_PATH=${escapeShellArg unpublishedTypstPackages} typst watch\";\n      # ...\n    };\n  in {\n    packages.${system}.default = build-drv;\n    apps.${system}.default = {\n      type = \"app\";\n      program = lib.getExe build-script;\n    };\n    apps.${system}.watch = {\n      type = \"app\";\n      program = lib.getExe watch-script;\n    };\n  };\n}\n```\n\nFinally, you can use the package in a Typst file:\n\n```typst\n#import \"@local/my-typst-package:0.1.0\": *\n\n#nothing\n```\n\n<!-- markdownlint-enable line-length -->\n\n[typst-packages]: https://github.com/typst/packages\n[`buildTypstProjectLocal`]: ../api/derivations/build-typst-project-local.md#typstpackages\n[`buildTypstProject`]: ../api/derivations/build-typst-project.md#typstpackages\n[`devShell`]: ../api/derivations/dev-shell.md\n[`mkTypstDerivation`]: ../api/derivations/mk-typst-derivation.md#typstpackages\n[`watchTypstProject`]: ../api/derivations/watch-typst-project.md\n"
  },
  {
    "path": "examples/.gitignore",
    "content": "/*/flake.lock\n/*/result\n"
  },
  {
    "path": "examples/quick-start/.gitignore",
    "content": "result*\n"
  },
  {
    "path": "examples/quick-start/flake.nix",
    "content": "{\n  description = \"A Typst project\";\n\n  inputs = {\n    nixpkgs.url = \"github:NixOS/nixpkgs/nixos-unstable\";\n\n    typix = {\n      url = \"github:loqusion/typix\";\n      inputs.nixpkgs.follows = \"nixpkgs\";\n    };\n\n    flake-utils.url = \"github:numtide/flake-utils\";\n\n    # Example of downloading icons from a non-flake source\n    # font-awesome = {\n    #   url = \"github:FortAwesome/Font-Awesome\";\n    #   flake = false;\n    # };\n  };\n\n  outputs = inputs @ {\n    nixpkgs,\n    typix,\n    flake-utils,\n    ...\n  }:\n    flake-utils.lib.eachDefaultSystem (system: let\n      pkgs = nixpkgs.legacyPackages.${system};\n      inherit (pkgs) lib;\n\n      typixLib = typix.lib.${system};\n\n      src = typixLib.cleanTypstSource ./.;\n      commonArgs = {\n        typstSource = \"main.typ\";\n\n        fontPaths = [\n          # Add paths to fonts here\n          # \"${pkgs.roboto}/share/fonts/truetype\"\n        ];\n\n        virtualPaths = [\n          # Add paths that must be locally accessible to typst here\n          # {\n          #   dest = \"icons\";\n          #   src = \"${inputs.font-awesome}/svgs/regular\";\n          # }\n        ];\n      };\n\n      # Compile a Typst project, *without* copying the result\n      # to the current directory\n      build-drv = typixLib.buildTypstProject (commonArgs\n        // {\n          inherit src;\n        });\n\n      # Compile a Typst project, and then copy the result\n      # to the current directory\n      build-script = typixLib.buildTypstProjectLocal (commonArgs\n        // {\n          inherit src;\n        });\n\n      # Watch a project and recompile on changes\n      watch-script = typixLib.watchTypstProject commonArgs;\n    in {\n      checks = {\n        inherit build-drv build-script watch-script;\n      };\n\n      packages.default = build-drv;\n\n      apps = rec {\n        default = watch;\n        build = flake-utils.lib.mkApp {\n          drv = build-script;\n        };\n        watch = flake-utils.lib.mkApp {\n          drv = watch-script;\n        };\n      };\n\n      devShells.default = typixLib.devShell {\n        inherit (commonArgs) fontPaths virtualPaths;\n        packages = [\n          # WARNING: Don't run `typst-build` directly, instead use `nix run .#build`\n          # See https://github.com/loqusion/typix/issues/2\n          # build-script\n          watch-script\n          # More packages can be added here, like typstfmt\n          # pkgs.typstfmt\n        ];\n      };\n    });\n}\n"
  },
  {
    "path": "examples/quick-start/main.typ",
    "content": "= Lorem ipsum\n#lorem(30)\n"
  },
  {
    "path": "examples/typst-packages/flake.nix",
    "content": "{\n  description = \"A Typst project that uses Typst packages\";\n\n  inputs = {\n    nixpkgs.url = \"github:NixOS/nixpkgs/nixos-unstable\";\n\n    typix = {\n      url = \"github:loqusion/typix\";\n      inputs.nixpkgs.follows = \"nixpkgs\";\n    };\n\n    flake-utils.url = \"github:numtide/flake-utils\";\n\n    # Example of downloading icons from a non-flake source\n    # font-awesome = {\n    #   url = \"github:FortAwesome/Font-Awesome\";\n    #   flake = false;\n    # };\n  };\n\n  outputs = inputs @ {\n    nixpkgs,\n    typix,\n    flake-utils,\n    ...\n  }:\n    flake-utils.lib.eachDefaultSystem (system: let\n      pkgs = nixpkgs.legacyPackages.${system};\n      inherit (pkgs) lib;\n\n      typixLib = typix.lib.${system};\n\n      src = typixLib.cleanTypstSource ./.;\n      commonArgs = {\n        typstSource = \"main.typ\";\n\n        fontPaths = [\n          # Add paths to fonts here\n          # \"${pkgs.roboto}/share/fonts/truetype\"\n        ];\n\n        virtualPaths = [\n          # Add paths that must be locally accessible to typst here\n          # {\n          #   dest = \"icons\";\n          #   src = \"${inputs.font-awesome}/svgs/regular\";\n          # }\n        ];\n      };\n\n      unstable_typstPackages = [\n        {\n          name = \"cetz\";\n          version = \"0.3.4\";\n          hash = \"sha256-5w3UYRUSdi4hCvAjrp9HslzrUw7BhgDdeCiDRHGvqd4=\";\n        }\n        # Required by cetz\n        {\n          name = \"oxifmt\";\n          version = \"0.2.1\";\n          hash = \"sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=\";\n        }\n      ];\n\n      # Compile a Typst project, *without* copying the result\n      # to the current directory\n      build-drv = typixLib.buildTypstProject (commonArgs\n        // {\n          inherit src unstable_typstPackages;\n        });\n\n      # Compile a Typst project, and then copy the result\n      # to the current directory\n      build-script = typixLib.buildTypstProjectLocal (commonArgs\n        // {\n          inherit src unstable_typstPackages;\n        });\n\n      # Watch a project and recompile on changes\n      watch-script = typixLib.watchTypstProject commonArgs;\n    in {\n      checks = {\n        inherit build-drv build-script watch-script;\n      };\n\n      packages.default = build-drv;\n\n      apps = rec {\n        default = watch;\n        build = flake-utils.lib.mkApp {\n          drv = build-script;\n        };\n        watch = flake-utils.lib.mkApp {\n          drv = watch-script;\n        };\n      };\n\n      devShells.default = typixLib.devShell {\n        inherit (commonArgs) fontPaths virtualPaths;\n        packages = [\n          # WARNING: Don't run `typst-build` directly, instead use `nix run .#build`\n          # See https://github.com/loqusion/typix/issues/2\n          # build-script\n          watch-script\n          # More packages can be added here, like typstfmt\n          # pkgs.typstfmt\n        ];\n      };\n    });\n}\n"
  },
  {
    "path": "examples/typst-packages/main.typ",
    "content": "#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",
    "content": "{\n  description = \"A Typst project that uses unpublished Typst packages\";\n\n  inputs = {\n    nixpkgs.url = \"github:NixOS/nixpkgs/nixos-unstable\";\n\n    typix = {\n      url = \"github:loqusion/typix\";\n      inputs.nixpkgs.follows = \"nixpkgs\";\n    };\n\n    flake-utils.url = \"github:numtide/flake-utils\";\n\n    # TODO: Change this and the list in `unpublishedTypstPackages`\n    my-typst-package = {\n      url = \"github:loqusion/my-typst-package\";\n      flake = false;\n    };\n\n    # Example of downloading icons from a non-flake source\n    # font-awesome = {\n    #   url = \"github:FortAwesome/Font-Awesome\";\n    #   flake = false;\n    # };\n  };\n\n  outputs = inputs @ {\n    nixpkgs,\n    typix,\n    flake-utils,\n    ...\n  }:\n    flake-utils.lib.eachDefaultSystem (system: let\n      pkgs = nixpkgs.legacyPackages.${system};\n      inherit (pkgs) lib;\n      inherit (lib.strings) escapeShellArg;\n\n      typixLib = typix.lib.${system};\n\n      src = typixLib.cleanTypstSource ./.;\n      commonArgs = {\n        typstSource = \"main.typ\";\n\n        fontPaths = [\n          # Add paths to fonts here\n          # \"${pkgs.roboto}/share/fonts/truetype\"\n        ];\n\n        virtualPaths = [\n          # Add paths that must be locally accessible to typst here\n          # {\n          #   dest = \"icons\";\n          #   src = \"${inputs.font-awesome}/svgs/regular\";\n          # }\n        ];\n      };\n\n      mkTypstPackagesDrv = name: entries: let\n        linkFarmEntries =\n          lib.foldl (set: {\n            name,\n            version,\n            namespace,\n            input,\n          }:\n            set\n            // {\n              \"${namespace}/${name}/${version}\" = input;\n            })\n          {}\n          entries;\n      in\n        pkgs.linkFarm name linkFarmEntries;\n\n      unpublishedTypstPackages = mkTypstPackagesDrv \"unpublished-typst-packages\" [\n        {\n          name = \"my-typst-package\";\n          version = \"0.1.0\";\n          namespace = \"local\";\n          input = inputs.my-typst-package;\n        }\n      ];\n\n      # Any transitive dependencies must be added here\n      # See https://loqusion.github.io/typix/recipes/using-typst-packages.html#the-typstpackages-attribute\n      unstable_typstPackages = [\n        {\n          name = \"oxifmt\";\n          version = \"0.2.1\";\n          hash = \"sha256-8PNPa9TGFybMZ1uuJwb5ET0WGIInmIgg8h24BmdfxlU=\";\n        }\n      ];\n\n      # Compile a Typst project, *without* copying the result\n      # to the current directory\n      build-drv = typixLib.buildTypstProject (commonArgs\n        // {\n          inherit src;\n          inherit unstable_typstPackages;\n          TYPST_PACKAGE_PATH = unpublishedTypstPackages;\n        });\n\n      # Compile a Typst project, and then copy the result\n      # to the current directory\n      build-script = typixLib.buildTypstProjectLocal (commonArgs\n        // {\n          inherit src;\n          inherit unstable_typstPackages;\n          TYPST_PACKAGE_PATH = unpublishedTypstPackages;\n        });\n\n      # Watch a project and recompile on changes\n      watch-script = typixLib.watchTypstProject (commonArgs\n        // {\n          typstWatchCommand = \"TYPST_PACKAGE_PATH=${escapeShellArg unpublishedTypstPackages} typst watch\";\n        });\n    in {\n      checks = {\n        inherit build-drv build-script watch-script;\n      };\n\n      packages.default = build-drv;\n\n      apps = rec {\n        default = watch;\n        build = flake-utils.lib.mkApp {\n          drv = build-script;\n        };\n        watch = flake-utils.lib.mkApp {\n          drv = watch-script;\n        };\n      };\n\n      devShells.default = typixLib.devShell {\n        inherit (commonArgs) fontPaths virtualPaths;\n        packages = [\n          # WARNING: Don't run `typst-build` directly, instead use `nix run .#build`\n          # See https://github.com/loqusion/typix/issues/2\n          # build-script\n          watch-script\n          # More packages can be added here, like typstfmt\n          # pkgs.typstfmt\n        ];\n      };\n    });\n}\n"
  },
  {
    "path": "examples/typst-packages-unpublished/main.typ",
    "content": "#import \"@local/my-typst-package:0.1.0\": *\n\n#nothing\n"
  },
  {
    "path": "flake.nix",
    "content": "{\n  description = \"Deterministic Typst compilation with Nix\";\n\n  nixConfig = {\n    extra-substituters = [\"https://typst-nix.cachix.org\"];\n    extra-trusted-public-keys = [\"typst-nix.cachix.org-1:OzDUMt0nd4wlI1AHucBPnchl4utWXeFTtUFt8XZ3DbA=\"];\n  };\n\n  inputs = {\n    nixpkgs.url = \"github:nixos/nixpkgs/nixos-unstable\";\n  };\n\n  outputs = {nixpkgs, ...}: let\n    inherit (nixpkgs) lib;\n\n    linux32BitSystems = [\"i686-linux\"];\n    linux64BitSystems = [\"x86_64-linux\" \"aarch64-linux\"];\n    linuxSystems = linux32BitSystems ++ linux64BitSystems;\n    darwinSystems = [\"x86_64-darwin\" \"aarch64-darwin\"];\n    systems = linuxSystems ++ darwinSystems;\n\n    forAllSystems = lib.genAttrs systems;\n\n    pkgsFor = lib.genAttrs systems (system: nixpkgs.legacyPackages.${system});\n\n    mkLib = pkgs:\n      import ./lib {\n        inherit (pkgs) lib newScope;\n      };\n\n    mkReleaseScript = pkgs:\n      import ./release.nix {\n        inherit pkgs;\n      };\n  in {\n    inherit mkLib;\n\n    overlays.default = _final: _prev: {};\n\n    templates = rec {\n      default = quick-start;\n      quick-start = {\n        description = \"A Typst project\";\n        path = ./examples/quick-start;\n      };\n      with-typst-packages = {\n        description = \"A Typst project (with packages)\";\n        path = ./examples/typst-packages;\n      };\n      with-typst-packages-unpublished = {\n        description = \"A Typst project (with unpublished packages)\";\n        path = ./examples/typst-packages-unpublished;\n      };\n    };\n\n    checks = forAllSystems (system: let\n      pkgs = pkgsFor.${system};\n    in (pkgs.callPackages ./checks {\n      inherit pkgs;\n      myLib = mkLib pkgs;\n    }));\n\n    lib = forAllSystems (system: mkLib pkgsFor.${system});\n\n    packages = forAllSystems (system: (\n      import ./pkgs.nix {pkgs = pkgsFor.${system};}\n    ));\n\n    apps = forAllSystems (system: {\n      release = {\n        type = \"app\";\n        program = lib.getExe (mkReleaseScript pkgsFor.${system});\n      };\n    });\n\n    formatter = forAllSystems (system: pkgsFor.${system}.alejandra);\n\n    devShells = forAllSystems (system: let\n      pkgs = pkgsFor.${system};\n    in {\n      default = pkgs.mkShellNoCC {\n        nativeBuildInputs = with pkgs; [\n          alejandra\n          markdownlint-cli\n          mdbook\n          nodePackages.prettier\n        ];\n      };\n    });\n  };\n}\n"
  },
  {
    "path": "lib/buildTypstProject.nix",
    "content": "{\n  lib,\n  mkTypstDerivation,\n  typstOptsFromArgs,\n}: args @ {\n  typstCompileCommand ? \"typst compile\",\n  typstSource ? \"main.typ\",\n  ...\n}: let\n  inherit (builtins) removeAttrs;\n  inherit (lib.strings) escapeShellArg;\n\n  typstOptsString = args.typstOptsString or (typstOptsFromArgs args);\n  cleanedArgs = removeAttrs args [\n    \"typstCompileCommand\"\n    \"typstOpts\"\n    \"typstOptsString\"\n    \"typstOutput\"\n    \"typstSource\"\n  ];\nin\n  mkTypstDerivation (cleanedArgs\n    // {\n      buildPhaseTypstCommand =\n        args.buildPhaseTypstCommand\n        or ''\n          ${typstCompileCommand} ${typstOptsString} ${escapeShellArg typstSource} \"$out\"\n        '';\n    })\n"
  },
  {
    "path": "lib/buildTypstProjectLocal.nix",
    "content": "{\n  buildTypstProject,\n  inferTypstProjectOutput,\n  lib,\n  pkgs,\n  typstOptsFromArgs,\n}: args @ {typstSource ? \"main.typ\", ...}: let\n  inherit (builtins) removeAttrs;\n  inherit (lib.strings) toShellVars;\n\n  typstOptsString = args.typstOptsString or (typstOptsFromArgs args);\n  typstOutput =\n    args.typstOutput\n    or (inferTypstProjectOutput (\n      {inherit typstSource;} // args\n    ));\n\n  buildTypstProjectDerivation = buildTypstProject (\n    cleanedArgs // {inherit typstOptsString typstSource;}\n  );\n  buildTypstProjectImport = builtins.path {path = buildTypstProjectDerivation;};\n\n  cleanedArgs = removeAttrs args [\n    \"scriptName\"\n  ];\nin\n  pkgs.writeShellApplication {\n    name = args.scriptName or \"typst-build\";\n\n    runtimeInputs = [\n      pkgs.coreutils\n    ];\n\n    text = ''\n      ${toShellVars {inherit typstOutput;}}\n      out=''${1:-''${typstOutput:?not defined}}\n      mkdir -p \"$(dirname \"$out\")\"\n      cp -LT --no-preserve=mode ${buildTypstProjectImport} \"$out\"\n    '';\n  }\n"
  },
  {
    "path": "lib/cleanTypstSource.nix",
    "content": "{lib}: src:\nlib.cleanSourceWith {\n  src = lib.cleanSource src;\n  filter = path: type: let\n    hasAcceptedSuffix = builtins.any (lib.flip lib.hasSuffix path) [\n      \".typ\" # Typst files\n      \".bib\" # BibLaTeX files\n    ];\n    isSpecialFile = builtins.elem (builtins.baseNameOf path) [\n      \"typst.toml\"\n      \"metadata.toml\"\n    ];\n  in\n    builtins.any lib.id [\n      (type == \"directory\")\n      hasAcceptedSuffix\n      isSpecialFile\n    ];\n}\n"
  },
  {
    "path": "lib/coerceVirtualPathAttr.nix",
    "content": "{lib}: let\n  inherit (builtins) isAttrs;\n  inherit (lib.strings) isStringLike;\nin\n  virtualPath:\n    if isStringLike virtualPath\n    then {\n      src = \"${virtualPath}\";\n      dest = \".\";\n    }\n    else if isAttrs virtualPath\n    then {\n      src = \"${virtualPath.src}\";\n      dest = virtualPath.dest or \".\";\n    }\n    else throw \"Invalid virtualPath: must be string or attrset\"\n"
  },
  {
    "path": "lib/default.nix",
    "content": "{\n  lib,\n  newScope,\n}:\nlib.makeScope newScope (self: let\n  inherit (self) callPackage;\nin {\n  buildTypstProjectLocal = callPackage ./buildTypstProjectLocal.nix {};\n  buildTypstProject = callPackage ./buildTypstProject.nix {};\n  cleanTypstSource = callPackage ./cleanTypstSource.nix {};\n  coerceVirtualPathAttr = callPackage ./coerceVirtualPathAttr.nix {};\n  copyVirtualPathsHook = callPackage ./setupHooks/copyVirtualPaths.nix {};\n  devShell = callPackage ./devShell.nix {};\n  emojiFontPathFromString = callPackage ./emojiFontPathFromString.nix {};\n  inferTypstProjectOutput = callPackage ./inferTypstProjectOutput.nix {};\n  linkVirtualPaths = callPackage ./linkVirtualPaths.nix {};\n  mkTypstDerivation = callPackage ./mkTypstDerivation.nix {};\n  typstOptsFromArgs = callPackage ./typstOptsFromArgs.nix {};\n  unsetSourceDateEpochHook = callPackage ./setupHooks/unsetSourceDateEpoch.nix {};\n  watchTypstProject = callPackage ./watchTypstProject.nix {};\n  fetchTypstPackages = callPackage ./fetchTypstPackages.nix {};\n})\n"
  },
  {
    "path": "lib/devShell.nix",
    "content": "{\n  emojiFontPathFromString,\n  lib,\n  linkVirtualPaths,\n  mkShellNoCC,\n  typst,\n}: args @ {\n  checks ? {},\n  emojiFont ? \"default\",\n  extraShellHook ? \"\",\n  fontPaths ? [],\n  forceVirtualPaths ? false,\n  inputsFrom ? [],\n  packages ? [],\n  virtualPaths ? [],\n  ...\n}: let\n  inherit (builtins) isNull removeAttrs;\n  inherit (lib) lists optionalAttrs optionalString;\n  inherit (lib.strings) concatStringsSep;\n\n  emojiFontPath = emojiFontPathFromString emojiFont;\n  allFontPaths = fontPaths ++ lists.optional (!isNull emojiFontPath) emojiFontPath;\n\n  unsetSourceDateEpochScript = builtins.readFile ./setupHooks/unsetSourceDateEpochScript.sh;\n\n  cleanedArgs = removeAttrs args [\n    \"checks\"\n    \"emojiFont\"\n    \"extraShellHook\"\n    \"fontPaths\"\n    \"forceVirtualPaths\"\n    \"inputsFrom\"\n    \"virtualPaths\"\n  ];\nin\n  mkShellNoCC (cleanedArgs\n    // optionalAttrs (allFontPaths != []) {\n      TYPST_FONT_PATHS = concatStringsSep \":\" allFontPaths;\n    }\n    // {\n      inputsFrom = builtins.attrValues checks ++ inputsFrom;\n\n      packages =\n        [\n          typst\n        ]\n        ++ packages;\n\n      shellHook =\n        args.shellHook\n        or (optionalString (virtualPaths != []) (linkVirtualPaths {\n          inherit virtualPaths forceVirtualPaths;\n        }))\n        + ''\n          ${unsetSourceDateEpochScript}\n        ''\n        + optionalString (extraShellHook != \"\") ''\n\n          ${extraShellHook}\n        '';\n    })\n"
  },
  {
    "path": "lib/emojiFontPathFromString.nix",
    "content": "{\n  lib,\n  pkgs,\n}: emojiFont: let\n  inherit (builtins) isNull isString typeOf;\nin\n  if isString emojiFont\n  then\n    (\n      if emojiFont == \"default\"\n      then \"${pkgs.twemoji-color-font}/share/fonts/truetype\"\n      else if emojiFont == \"twemoji\"\n      then \"${pkgs.twemoji-color-font}/share/fonts/truetype\"\n      else if emojiFont == \"twemoji-cbdt\"\n      then \"${pkgs.twitter-color-emoji}/share/fonts/truetype\"\n      else if emojiFont == \"noto\"\n      then \"${pkgs.noto-fonts-color-emoji}/share/fonts/noto\"\n      else if emojiFont == \"noto-monochrome\"\n      then \"${pkgs.noto-fonts-monochrome-emoji}/share/fonts/noto\"\n      else if emojiFont == \"emojione\"\n      then \"${pkgs.emojione}/share/fonts/truetype\"\n      else throw ''invalid value for `emojiFont`: \"${emojiFont}\". Must be one of: \"twemoji\", \"twemoji-cbdt\", \"noto\", \"noto-monochrome\", \"emojione\", null.''\n    )\n  else if isNull emojiFont\n  then null\n  else throw ''invalid type for `emojiFont`: ${typeOf emojiFont}. Must be string or null.''\n"
  },
  {
    "path": "lib/fetchTypstPackages.nix",
    "content": "{\n  fetchurl,\n  runCommand,\n  lib,\n  symlinkJoin,\n  stdenvNoCC,\n}: let\n  inherit (lib.lists) forEach;\n\n  typstPackageRegistry = \"https://packages.typst.org\";\n\n  # Downloads a tarball from the Typst package registry\n  fetchTypstTarball = {\n    namespace ? \"preview\",\n    name,\n    version,\n    hash,\n  } @ args:\n    fetchurl {\n      url = \"${typstPackageRegistry}/${namespace}/${name}-${version}.tar.gz\";\n      inherit hash;\n      downloadToTemp = true;\n\n      # The Typst package registry does not produce reproducible tarballs\n      # We modify the tarball *before* Nix computes the output hash,\n      # per instructions at https://reproducible-builds.org/docs/archives/\n      postFetch = ''\n        pushd $(mktemp -d)\n        mkdir extracted\n        tar -xzf $downloadedFile -C extracted\n        tar --owner=0 --group=0 --numeric-owner --format=gnu \\\n                --sort=name --mtime=\"@1\" \\\n                -czf extracted.tar.gz -C extracted .\n        mv ./extracted.tar.gz $out\n        popd\n      '';\n    };\n\n  # Downloads a Typst package from the package registry\n  # Places the downloaded package to $out/${namespace}/${name}/${version}\n  fetchTypstPackage = {\n    namespace ? \"preview\",\n    name,\n    version,\n    ...\n  } @ args: let\n    tarball = fetchTypstTarball args;\n    packageSubdir = \"${namespace}/${name}/${version}\";\n  in\n    runCommand \"fetch-typst-package-${namespace}-${name}-${version}\" {} ''\n      tarball=${tarball}\n      mkdir -p $out/${packageSubdir}\n      tar -xzf $tarball -C $out/${packageSubdir}\n    '';\nin\n  typstPackages:\n    symlinkJoin {\n      name = \"typst-packages\";\n      paths = forEach typstPackages fetchTypstPackage;\n    }\n"
  },
  {
    "path": "lib/inferTypstProjectOutput.nix",
    "content": "{lib}: args_: let\n  args =\n    if builtins.isString args_\n    then {typstSource = args_;}\n    else args_;\n  supportedFormats = [\"pdf\" \"svg\" \"png\" \"html\"];\n  format = ({format = \"pdf\";} // args.typstOpts or {}).format;\n  name = lib.strings.removeSuffix \".typ\" (builtins.baseNameOf args.typstSource);\n  extension =\n    if builtins.elem format supportedFormats\n    then format\n    else\n      lib.flip lib.trivial.warn \"\" ''\n        typix could not infer the typst output extension since ${format} is unsupported\n        to silence this warning consider one of the following:\n        - set the format option to one of: pdf, svg, png, html\n        - set `typstOutput` explicitly\n        - if ${format} is supported by typst but not by typix, please open a\n          PR at https://github.com/loqusion/typix\n      '';\nin\n  name + lib.optionalString (extension != \"\") \".${extension}\"\n"
  },
  {
    "path": "lib/linkVirtualPaths.nix",
    "content": "{\n  coerceVirtualPathAttr,\n  lib,\n  pkgs,\n}: let\n  inherit (builtins) toString;\n  inherit (pkgs) symlinkJoin;\n  inherit (lib) optionalString;\n  inherit (lib.filesystem) pathIsDirectory;\n  inherit (lib.strings) concatMapStringsSep toShellVars;\n\n  shellUtils = ''\n    _same_path() {\n      [ \"$(realpath \"$1\")\" = \"$(realpath \"$2\")\" ]\n    }\n\n    _ensure_parent_exists() {\n      mkdir -p \"$(dirname \"$1\")\"\n    }\n\n    _cleanup_parent() {\n      local parent\n      parent=$(dirname \"$1\")\n      if ! _same_path \".\" \"$1\" && ! _same_path \".\" \"$parent\"; then\n        rmdir -p --ignore-fail-on-non-empty \"$parent\"\n      fi\n    }\n  '';\nin\n  {\n    forceVirtualPaths ? false,\n    virtualPaths,\n  }:\n    shellUtils\n    + \"\\n\"\n    + (concatMapStringsSep\n      \"\\n\" (virtualPath_: let\n        virtualPath = coerceVirtualPathAttr virtualPath_;\n        source =\n          if !pathIsDirectory (toString virtualPath.src)\n          then virtualPath.src\n          else\n            (symlinkJoin {\n              name = \"symlink\" + optionalString (virtualPath ? dest) \"-${virtualPath.dest}\";\n              paths = [virtualPath.src];\n            });\n        lnAdditionalOpts = optionalString forceVirtualPaths \"--force\";\n        cpAdditionalOpts =\n          if forceVirtualPaths\n          then \"--force\"\n          else \"--no-clobber\";\n      in\n        # We don't want a refusal to overwrite existing files to cause nix to fail, so we add `|| true`\n        # to the commands this applies to\n        ''\n          ${toShellVars {\n            virtualPathSrc = source;\n            virtualPathDest = virtualPath.dest;\n          }}\n\n          _ensure_parent_exists \"$virtualPathDest\"\n\n          if [ -f \"$virtualPathSrc\" ]; then\n            echo \"typix: linking ${virtualPath.src} to $virtualPathDest\"\n            if _same_path \".\" \"$virtualPathDest\"; then\n              ln ${lnAdditionalOpts} -sv \"$virtualPathSrc\" \"$virtualPathDest\" ||\n                true\n            else\n              ln ${lnAdditionalOpts} -sTv \"$virtualPathSrc\" \"$virtualPathDest\" ||\n                true\n            fi\n          else\n            echo \"typix: linking ${virtualPath.src} to $virtualPathDest recursively\"\n            cp ${cpAdditionalOpts} -RTv --no-dereference --no-preserve=mode \"$virtualPathSrc\" \"$virtualPathDest\" ||\n              true\n          fi\n\n          _cleanup_parent \"$virtualPathDest\"\n        '')\n      virtualPaths)\n"
  },
  {
    "path": "lib/mkTypstDerivation.nix",
    "content": "{\n  copyVirtualPathsHook,\n  emojiFontPathFromString,\n  lib,\n  stdenvNoCC,\n  typst,\n  unsetSourceDateEpochHook,\n  fetchTypstPackages,\n}: args @ {\n  buildPhaseTypstCommand,\n  emojiFont ? \"default\",\n  fontPaths ? [],\n  installPhaseCommand ? \"\",\n  virtualPaths ? [],\n  unstable_typstPackages ? [],\n  ...\n}:\nassert lib.assertMsg (!(builtins.hasAttr \"unstableTypstPackages\" args)) ''\n  `unstableTypstPackages` has been renamed to `unstable_typstPackages`.\n''; let\n  inherit (builtins) baseNameOf getEnv isNull removeAttrs;\n  inherit (lib) lists optionalAttrs;\n  inherit (lib.strings) concatStringsSep;\n\n  emojiFontPath = emojiFontPathFromString emojiFont;\n  allFontPaths = fontPaths ++ lists.optional (!isNull emojiFontPath) emojiFontPath;\n\n  cleanedArgs = removeAttrs args [\n    \"buildPhaseTypstCommand\"\n    \"emojiFont\"\n    \"fontPaths\"\n    \"installPhaseCommand\"\n    \"virtualPaths\"\n    \"unstable_typstPackages\"\n  ];\n\n  name =\n    args.name\n    or (let\n      pwd = getEnv \"PWD\";\n    in\n      if pwd != \"\"\n      then baseNameOf pwd\n      else \"typst\");\n  nameArgs =\n    if args ? version\n    then {\n      pname = args.pname or name;\n      inherit (args) version;\n    }\n    else {inherit name;};\nin\n  stdenvNoCC.mkDerivation (cleanedArgs\n    // nameArgs\n    // optionalAttrs (allFontPaths != []) {\n      TYPST_FONT_PATHS = concatStringsSep \":\" allFontPaths;\n    }\n    // optionalAttrs (unstable_typstPackages != []) {\n      TYPST_PACKAGE_CACHE_PATH = fetchTypstPackages unstable_typstPackages;\n    }\n    // {\n      nativeBuildInputs =\n        (args.nativeBuildInputs or [])\n        ++ [\n          typst\n          (copyVirtualPathsHook virtualPaths)\n          unsetSourceDateEpochHook\n        ];\n\n      buildPhase =\n        args.buildPhase\n        or ''\n          runHook preBuild\n          ${buildPhaseTypstCommand}\n          runHook postBuild\n        '';\n\n      installPhase =\n        args.installPhase\n        or ''\n          runHook preInstall\n          ${installPhaseCommand}\n          runHook postInstall\n        '';\n    })\n"
  },
  {
    "path": "lib/setupHooks/copyVirtualPaths.nix",
    "content": "{\n  coerceVirtualPathAttr,\n  lib,\n  makeSetupHook,\n}: virtualPaths: let\n  inherit (lib.strings) concatMapStringsSep toShellVars;\n  copyAllVirtualPaths =\n    concatMapStringsSep\n    \"\\n\" (virtualPath_: let\n      virtualPath = coerceVirtualPathAttr virtualPath_;\n    in ''\n      ${toShellVars {\n        virtualPathSrc = virtualPath.src;\n        virtualPathDest = virtualPath.dest;\n      }}\n\n      echo \"Copying $virtualPathSrc to $virtualPathDest\"\n\n      _ensure_parent_exists \"$virtualPathDest\"\n\n      if [ -f \"$virtualPathSrc\" ] && _same_path \".\" \"$virtualPathDest\"; then\n        cp -Lv --reflink=auto --no-preserve=mode \"$virtualPathSrc\" \"$virtualPathDest\"\n      else\n        cp -LTRv --reflink=auto --no-preserve=mode \"$virtualPathSrc\" \"$virtualPathDest\"\n      fi\n\n      _cleanup_parent \"$virtualPathDest\"\n    '')\n    virtualPaths;\nin\n  makeSetupHook {\n    name = \"copyVirtualPaths\";\n    substitutions = {\n      inherit copyAllVirtualPaths;\n    };\n  }\n  ./copyVirtualPathsHook.sh\n"
  },
  {
    "path": "lib/setupHooks/copyVirtualPathsHook.sh",
    "content": "_same_path() {\n    [ \"$(realpath \"$1\")\" = \"$(realpath \"$2\")\" ]\n}\n\n_ensure_parent_exists() {\n    mkdir -p \"$(dirname \"$1\")\"\n}\n\n_cleanup_parent() {\n    local parent\n    parent=$(dirname \"$1\")\n    if ! _same_path \".\" \"$1\" && ! _same_path \".\" \"$parent\"; then\n        rmdir -p --ignore-fail-on-non-empty \"$parent\"\n    fi\n}\n\ncopyVirtualPaths() {\n\t:\n\t@copyAllVirtualPaths@\n}\n\npreBuildHooks+=(copyVirtualPaths)\n"
  },
  {
    "path": "lib/setupHooks/unsetSourceDateEpoch.nix",
    "content": "{makeSetupHook}: let\n  unsetSourceDateEpochScript = builtins.readFile ./unsetSourceDateEpochScript.sh;\nin\n  makeSetupHook {\n    name = \"unsetSourceDateEpoch\";\n    substitutions = {\n      inherit unsetSourceDateEpochScript;\n    };\n  }\n  ./unsetSourceDateEpochHook.sh\n"
  },
  {
    "path": "lib/setupHooks/unsetSourceDateEpochHook.sh",
    "content": "unsetSourceDateEpoch() {\n    @unsetSourceDateEpochScript@\n}\n\npreBuildHooks+=(unsetSourceDateEpoch)\n"
  },
  {
    "path": "lib/setupHooks/unsetSourceDateEpochScript.sh",
    "content": "unset SOURCE_DATE_EPOCH\n"
  },
  {
    "path": "lib/typstOptsFromArgs.nix",
    "content": "{lib}: origArgs: let\n  inherit (builtins) elem isBool isNull tail;\n  inherit (lib) optionalAttrs optionalString;\n  inherit (lib.attrsets) filterAttrs mapAttrsToList recursiveUpdate;\n  inherit (lib.lists) last;\n  inherit (lib.strings) concatMapStringsSep concatStringsSep escapeShellArg splitString;\n\n  pathExtension = path: let\n    splitPathTail = tail (splitString \".\" path);\n  in\n    if (splitPathTail != [])\n    then last splitPathTail\n    else null;\n\n  inferredFormatFromTypstProjectOutput =\n    if ((origArgs ? typstOpts.format) || (! origArgs ? typstOutput))\n    then null\n    else let\n      inherit (origArgs) typstOutput;\n      supportedExtensions = [\"pdf\" \"svg\" \"png\" \"html\"];\n      extension = pathExtension typstOutput;\n    in\n      if (elem extension supportedExtensions)\n      then extension\n      else null;\n\n  inferredTypstOpts = optionalAttrs (!isNull inferredFormatFromTypstProjectOutput) {\n    typstOpts.format = inferredFormatFromTypstProjectOutput;\n  };\n  defaultArgs = optionalAttrs (! origArgs ? typstOutput) {\n    typstOpts.format = \"pdf\";\n  };\n\n  args =\n    recursiveUpdate (\n      recursiveUpdate defaultArgs inferredTypstOpts\n    )\n    origArgs;\n\n  parametersFrom = opt: value:\n    \"--${opt}\"\n    + optionalString (!isBool value) \" ${escapeShellArg value}\";\nin\n  concatStringsSep \" \" (\n    mapAttrsToList\n    (\n      opt: value:\n        if builtins.isList value\n        then (concatMapStringsSep \" \" (parametersFrom opt) value)\n        else (parametersFrom opt value)\n    )\n    (filterAttrs (_: v: v != false && !isNull v) args.typstOpts)\n  )\n"
  },
  {
    "path": "lib/watchTypstProject.nix",
    "content": "{\n  emojiFontPathFromString,\n  inferTypstProjectOutput,\n  lib,\n  linkVirtualPaths,\n  pkgs,\n  typst,\n  typstOptsFromArgs,\n}: args @ {\n  emojiFont ? \"default\",\n  fontPaths ? [],\n  forceVirtualPaths ? false,\n  typstSource ? \"main.typ\",\n  typstWatchCommand ? \"typst watch\",\n  virtualPaths ? [],\n  ...\n}: let\n  inherit (builtins) isNull removeAttrs;\n  inherit (lib) lists optionalString;\n  inherit (lib.strings) concatStringsSep toShellVars;\n\n  emojiFontPath = emojiFontPathFromString emojiFont;\n  allFontPaths = fontPaths ++ lists.optional (!isNull emojiFontPath) emojiFontPath;\n  typstOptsString = args.typstOptsString or (typstOptsFromArgs args);\n  typstOutput =\n    args.typstOutput\n    or (inferTypstProjectOutput (\n      {inherit typstSource;} // args\n    ));\n\n  unsetSourceDateEpochScript = builtins.readFile ./setupHooks/unsetSourceDateEpochScript.sh;\n\n  cleanedArgs = removeAttrs args [\n    \"emojiFont\"\n    \"fontPaths\"\n    \"forceVirtualPaths\"\n    \"scriptName\"\n    \"text\"\n    \"typstOpts\"\n    \"typstOptsString\"\n    \"typstOutput\"\n    \"typstSource\"\n    \"typstWatchCommand\"\n    \"virtualPaths\"\n  ];\nin\n  pkgs.writeShellApplication (cleanedArgs\n    // {\n      name = args.scriptName or args.name or \"typst-watch\";\n\n      runtimeInputs =\n        (args.runtimeInputs or [])\n        ++ [\n          pkgs.coreutils\n          typst\n        ];\n\n      text =\n        optionalString (allFontPaths != []) ''\n          export TYPST_FONT_PATHS=${concatStringsSep \":\" allFontPaths}\n        ''\n        + optionalString (virtualPaths != []) (linkVirtualPaths {\n          inherit virtualPaths forceVirtualPaths;\n        })\n        + ''\n\n          ${toShellVars {inherit typstOutput typstSource;}}\n          out=''${1:-''${typstOutput:?not defined}}\n          mkdir -p \"$(dirname \"$out\")\"\n\n          ${unsetSourceDateEpochScript}\n\n          ${typstWatchCommand} ${typstOptsString} \"$typstSource\" \"$out\"\n        '';\n    })\n"
  },
  {
    "path": "pkgs.nix",
    "content": "{pkgs}: {\n  docs = let\n    inherit (pkgs) lib;\n    root = ./.;\n    rootPrefix = builtins.toString root;\n    src = lib.sources.cleanSourceWith {\n      src = root;\n      filter = path: _: let\n        relativePath = lib.strings.removePrefix rootPrefix path;\n      in\n        builtins.any ((lib.flip lib.strings.hasPrefix) relativePath) [\n          \"/docs\"\n          \"/README.md\"\n        ];\n    };\n  in\n    pkgs.stdenvNoCC.mkDerivation {\n      name = \"typix-mdbook\";\n\n      inherit src;\n\n      nativeBuildInputs = with pkgs; [mdbook];\n\n      buildPhase = ''\n        mdbook build docs --dest-dir \"$out\"\n      '';\n    };\n}\n"
  },
  {
    "path": "release.nix",
    "content": "{pkgs}:\npkgs.writeShellApplication {\n  name = \"github-release\";\n\n  runtimeInputs = with pkgs; [\n    gh\n    git\n    nodePackages.semver\n  ];\n\n  text = ''\n    VALID_INCREMENT_TYPES=\"major minor patch premajor preminor prepatch prerelease\"\n    increment=''${1:-patch}\n    # shellcheck disable=SC2076\n    if [[ ! \" $VALID_INCREMENT_TYPES \" =~ \" $increment \" ]]; then\n      echo \"Invalid increment type: $increment\" >&2\n      echo \"Expected one of: ''${VALID_INCREMENT_TYPES// /, }\" >&2\n      exit 1\n    fi\n\n    current_version=$(git describe --tags --abbrev=0)\n    next_version=$(semver --increment \"$increment\" \"$current_version\")\n\n    gh release create --generate-notes \"$next_version\"\n  '';\n}\n"
  }
]