diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml
new file mode 100644
index 0000000..6d9047e
--- /dev/null
+++ b/.github/workflows/npm-publish.yml
@@ -0,0 +1,20 @@
+name: npm publish
+on:
+ release:
+ types: published
+ workflow_dispatch:
+concurrency: ${{ github.workflow }}
+jobs:
+ npm-publish:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: lts
+ cache: npm
+ registry-url: https://registry.npmjs.org/
+ - run: npm ci
+ - run: npm publish
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
\ No newline at end of file
diff --git a/.github/workflows/npm-test.yml b/.github/workflows/npm-test.yml
new file mode 100644
index 0000000..89ca712
--- /dev/null
+++ b/.github/workflows/npm-test.yml
@@ -0,0 +1,39 @@
+name: npm test
+on:
+ push:
+ branches: "main"
+ paths-ignore:
+ - .gitignore
+ - LICENSE
+ - README.md
+ - .github/**
+ - "!.github/workflows/npm-test.yml"
+ pull_request:
+ branches: "main"
+ paths-ignore:
+ - .gitignore
+ - LICENSE
+ - README.md
+ - .github/**
+ - "!.github/workflows/npm-test.yml"
+concurrency:
+ group: ${{ github.workflow }}
+ cancel-in-progress: true
+jobs:
+ npm-test:
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - { os: ubuntu-latest, node-version: "20" }
+ - { os: windows-latest, node-version: "18" }
+ - { os: macos-latest, node-version: "20" }
+ runs-on: ${{ matrix.os }}
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: ${{ matrix.node-version }}
+ cache: npm
+ - run: npm ci
+ - run: npm test
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index c6bba59..3ba3b45 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,9 @@
+# Ignore Typst downloads when in dev
+typst-*.tar.xz
+typst-*.zip
+bin/typst
+
+#region https://github.com/github/gitignore/blob/main/Node.gitignore
# Logs
logs
*.log
@@ -128,3 +134,4 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
+#endregion
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index 07471cc..a7e77cb 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,21 +1,176 @@
-MIT License
-
-Copyright (c) 2023 Jacob Hummer
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
\ No newline at end of file
diff --git a/README.md b/README.md
index 0059de1..d801725 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,255 @@
-# typst.js
-A new markup-based typesetting system that is powerful and easy to learn.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Typst is a new markup-based typesetting system that is designed to be as powerful
+as LaTeX while being much easier to learn and use. Typst has:
+
+- Built-in markup for the most common formatting tasks
+- Flexible functions for everything else
+- A tightly integrated scripting system
+- Math typesetting, bibliography management, and more
+- Fast compile times thanks to incremental compilation
+- Friendly error messages in case something goes wrong
+
+This repository contains the Typst compiler and its CLI, which is everything you
+need to compile Typst documents locally. For the best writing experience,
+consider signing up to our [collaborative online editor][app] for free. It is
+currently in public beta.
+
+## Example
+A [gentle introduction][tutorial] to Typst is available in our documentation.
+However, if you want to see the power of Typst encapsulated in one image, here
+it is:
+
+
+
+
+
+Let's dissect what's going on:
+
+- We use _set rules_ to configure element properties like the size of pages or
+ the numbering of headings. By setting the page height to `auto`, it scales to
+ fit the content. Set rules accommodate the most common configurations. If you
+ need full control, you can also use [show rules][show] to completely redefine
+ the appearance of an element.
+
+- We insert a heading with the `= Heading` syntax. One equals sign creates a top
+ level heading, two create a subheading and so on. Typst has more lightweight
+ markup like this, see the [syntax] reference for a full list.
+
+- [Mathematical equations][math] are enclosed in dollar signs. By adding extra
+ spaces around the contents of a equation, we can put it into a separate block.
+ Multi-letter identifiers are interpreted as Typst definitions and functions
+ unless put into quotes. This way, we don't need backslashes for things like
+ `floor` and `sqrt`. And `phi.alt` applies the `alt` modifier to the `phi` to
+ select a particular symbol variant.
+
+- Now, we get to some [scripting]. To input code into a Typst document, we can
+ write a hash followed by an expression. We define two variables and a
+ recursive function to compute the n-th fibonacci number. Then, we display the
+ results in a center-aligned table. The table function takes its cells
+ row-by-row. Therefore, we first pass the formulas `$F_1$` to `$F_8$` and then
+ the computed fibonacci numbers. We apply the spreading operator (`..`) to both
+ because they are arrays and we want to pass the arrays' items as individual
+ arguments.
+
+
+ Text version of the code example.
+
+ ```typst
+ #set page(width: 10cm, height: auto)
+ #set heading(numbering: "1.")
+
+ = Fibonacci sequence
+ The Fibonacci sequence is defined through the
+ recurrence relation $F_n = F_(n-1) + F_(n-2)$.
+ It can also be expressed in _closed form:_
+
+ $ F_n = round(1 / sqrt(5) phi.alt^n), quad
+ phi.alt = (1 + sqrt(5)) / 2 $
+
+ #let count = 8
+ #let nums = range(1, count + 1)
+ #let fib(n) = (
+ if n <= 2 { 1 }
+ else { fib(n - 1) + fib(n - 2) }
+ )
+
+ The first #count numbers of the sequence are:
+
+ #align(center, table(
+ columns: count,
+ ..nums.map(n => $F_#n$),
+ ..nums.map(n => str(fib(n))),
+ ))
+ ```
+
+
+## Installation
+Typst's CLI is available from different sources:
+
+- You can get sources and pre-built binaries for the latest release of Typst
+ from the [releases page][releases]. Download the archive for your platform and
+ place it in a directory that is in your `PATH`. To stay up to date with future
+ releases, you can simply run `typst update`.
+
+- You can install Typst through different package managers. Note that the
+ versions in the package managers might lag behind the latest release.
+ - Linux: View [Typst on Repology][repology]
+ - macOS: `brew install typst`
+ - Windows: `winget install --id Typst.Typst`
+
+- If you have a [Rust][rust] toolchain installed, you can also install the
+ latest development version with
+ `cargo install --git https://github.com/typst/typst typst-cli`. Note that this
+ will be a "nightly" version that may be broken or not yet properly documented.
+
+- Nix users can use the `typst` package with `nix-shell -p typst` or build and
+ run the bleeding edge version with `nix run github:typst/typst -- --version`.
+
+- Docker users can run a prebuilt image with
+ `docker run -it ghcr.io/typst/typst:latest`.
+
+## Usage
+Once you have installed Typst, you can use it like this:
+```sh
+# Creates `file.pdf` in working directory.
+typst compile file.typ
+
+# Creates PDF file at the desired path.
+typst compile path/to/source.typ path/to/output.pdf
+```
+
+You can also watch source files and automatically recompile on changes. This is
+faster than compiling from scratch each time because Typst has incremental
+compilation.
+```sh
+# Watches source files and recompiles on changes.
+typst watch file.typ
+```
+
+Typst further allows you to add custom font paths for your project and list all
+of the fonts it discovered:
+```sh
+# Adds additional directories to search for fonts.
+typst compile --font-path path/to/fonts file.typ
+
+# Lists all of the discovered fonts in the system and the given directory.
+typst fonts --font-path path/to/fonts
+
+# Or via environment variable (Linux syntax).
+TYPST_FONT_PATHS=path/to/fonts typst fonts
+```
+
+For other CLI subcommands and options, see below:
+```sh
+# Prints available subcommands and options.
+typst help
+
+# Prints detailed usage of a subcommand.
+typst help watch
+```
+
+If you prefer an integrated IDE-like experience with autocompletion and instant
+preview, you can also check out the [Typst web app][app], which is currently in
+public beta.
+
+## Community
+The main place where the community gathers is our [Discord server][discord].
+Feel free to join there to ask questions, help out others, share cool things
+you created with Typst, or just to chat.
+
+Aside from that there are a few places where you can find things built by
+the community:
+
+- The official [package list](https://typst.app/docs/packages)
+- The [Awesome Typst](https://github.com/qjcg/awesome-typst) repository
+
+If you had a bad experience in our community, please [reach out to us][contact].
+
+## Contributing
+We would love to see contributions from the community. If you experience bugs,
+feel free to open an issue. If you would like to implement a new feature or bug
+fix, please follow the steps outlined in the [contribution guide][contributing].
+
+To build Typst yourself, first ensure that you have the
+[latest stable Rust][rust] installed. Then, clone this repository and build the
+CLI with the following commands:
+
+```sh
+git clone https://github.com/typst/typst
+cd typst
+cargo build --release
+```
+
+The optimized binary will be stored in `target/release/`.
+
+Another good way to contribute is by [sharing packages][packages] with the
+community.
+
+## Pronunciation and Spelling
+IPA: /taɪpst/. "Ty" like in **Ty**pesetting and "pst" like in Hi**pst**er. When
+writing about Typst, capitalize its name as a proper noun, with a capital "T".
+
+## Design Principles
+All of Typst has been designed with three key goals in mind: Power,
+simplicity, and performance. We think it's time for a system that matches the
+power of LaTeX, is easy to learn and use, all while being fast enough to realize
+instant preview. To achieve these goals, we follow three core design principles:
+
+- **Simplicity through Consistency:**
+ If you know how to do one thing in Typst, you should be able to transfer that
+ knowledge to other things. If there are multiple ways to do the same thing,
+ one of them should be at a different level of abstraction than the other. E.g.
+ it's okay that `= Introduction` and `#heading[Introduction]` do the same thing
+ because the former is just syntax sugar for the latter.
+
+- **Power through Composability:**
+ There are two ways to make something flexible: Have a knob for everything or
+ have a few knobs that you can combine in many ways. Typst is designed with the
+ second way in mind. We provide systems that you can compose in ways we've
+ never even thought of. TeX is also in the second category, but it's a bit
+ low-level and therefore people use LaTeX instead. But there, we don't really
+ have that much composability. Instead, there's a package for everything
+ (`\usepackage{knob}`).
+
+- **Performance through Incrementality:**
+ All Typst language features must accommodate for incremental compilation.
+ Luckily we have [`comemo`], a system for incremental compilation which does
+ most of the hard work in the background.
+
+[docs]: https://typst.app/docs/
+[app]: https://typst.app/
+[discord]: https://discord.gg/2uDybryKPe
+[tutorial]: https://typst.app/docs/tutorial/
+[show]: https://typst.app/docs/reference/styling/#show-rules
+[math]: https://typst.app/docs/reference/math/
+[syntax]: https://typst.app/docs/reference/syntax/
+[scripting]: https://typst.app/docs/reference/scripting/
+[rust]: https://rustup.rs/
+[releases]: https://github.com/typst/typst/releases/
+[repology]: https://repology.org/project/typst/versions
+[contact]: https://typst.app/contact
+[architecture]: https://github.com/typst/typst/blob/main/docs/dev/architecture.md
+[contributing]: https://github.com/typst/typst/blob/main/CONTRIBUTING.md
+[packages]: https://github.com/typst/packages/
+[`comemo`]: https://github.com/typst/comemo/
diff --git a/main.js b/main.js
new file mode 100644
index 0000000..8c1f1fc
--- /dev/null
+++ b/main.js
@@ -0,0 +1,26 @@
+#!/usr/bin/env node
+// @ts-check
+import { existsSync } from "node:fs";
+import { $ } from "execa";
+import { typstMetaInstall } from "./utils.js";
+import { fileURLToPath, pathToFileURL } from "node:url";
+import { readFile, writeFile } from "node:fs/promises";
+
+const package_ = JSON.parse(
+ await readFile(new URL("./package.json", import.meta.url), "utf8")
+);
+const tag = `v${package_.version.match(/^\d+\.\d+\.\d+/)[0]}`;
+
+const ext = process.platform === "win32" ? ".exe" : "";
+const typst = fileURLToPath(new URL(`./bin/typst${ext}`, import.meta.url));
+
+if (!existsSync(typst)) {
+ await typstMetaInstall(undefined, tag);
+}
+
+const { exitCode, signal } = await $({
+ stdio: "inherit",
+ reject: false,
+})`${typst} ${process.argv.slice(2)}`;
+if (signal) process.kill(process.pid, signal);
+process.exit(exitCode ?? 100);
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..33f46fe
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,208 @@
+{
+ "name": "typst",
+ "version": "0.10.0-3",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "typst",
+ "version": "0.10.0-3",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "execa": "^8.0.1"
+ },
+ "bin": {
+ "typst": "main.js"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/execa": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
+ "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
+ "dependencies": {
+ "cross-spawn": "^7.0.3",
+ "get-stream": "^8.0.1",
+ "human-signals": "^5.0.0",
+ "is-stream": "^3.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^5.1.0",
+ "onetime": "^6.0.0",
+ "signal-exit": "^4.1.0",
+ "strip-final-newline": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=16.17"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
+ "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/human-signals": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
+ "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
+ "engines": {
+ "node": ">=16.17.0"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
+ "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
+ },
+ "node_modules/mimic-fn": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
+ "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/npm-run-path": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz",
+ "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==",
+ "dependencies": {
+ "path-key": "^4.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/npm-run-path/node_modules/path-key": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+ "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
+ "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
+ "dependencies": {
+ "mimic-fn": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/strip-final-newline": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
+ "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..d415993
--- /dev/null
+++ b/package.json
@@ -0,0 +1,35 @@
+{
+ "name": "typst",
+ "version": "0.10.0-3",
+ "description": "A new markup-based typesetting system that is powerful and easy to learn.",
+ "keywords": [
+ "typesetting",
+ "markup",
+ "typesetter",
+ "typeset",
+ "typst",
+ "latex",
+ "markdown",
+ "pdf"
+ ],
+ "homepage": "https://typst.app/",
+ "bugs": "https://github.com/jcbhmr/typst.js/issues",
+ "repository": "github:jcbhmr/typst.js",
+ "license": "Apache-2.0",
+ "contributors": ["Jacob Hummer (https://jcbhmr.me/)"],
+ "type": "module",
+ "exports": null,
+ "bin": "main.js",
+ "files": [
+ "main.js",
+ "postinstall.js",
+ "utils.js"
+ ],
+ "scripts": {
+ "postinstall": "node postinstall.js || true",
+ "test": "node main.js --help"
+ },
+ "dependencies": {
+ "execa": "^8.0.1"
+ }
+}
\ No newline at end of file
diff --git a/postinstall.js b/postinstall.js
new file mode 100644
index 0000000..63d2b82
--- /dev/null
+++ b/postinstall.js
@@ -0,0 +1,18 @@
+#!/usr/bin/env node
+// @ts-check
+import { existsSync } from "node:fs";
+import { typstMetaInstall } from "./utils.js";
+import { fileURLToPath, pathToFileURL } from "node:url";
+import { readFile, writeFile } from "node:fs/promises";
+
+const package_ = JSON.parse(
+ await readFile(new URL("./package.json", import.meta.url), "utf8")
+);
+const tag = `v${package_.version.match(/^\d+\.\d+\.\d+/)[0]}`;
+
+const ext = process.platform === "win32" ? ".exe" : "";
+const typst = fileURLToPath(new URL(`./bin/typst${ext}`, import.meta.url));
+
+if (!existsSync(typst)) {
+ await typstMetaInstall(undefined, tag);
+}
\ No newline at end of file
diff --git a/utils.js b/utils.js
new file mode 100644
index 0000000..ebc371d
--- /dev/null
+++ b/utils.js
@@ -0,0 +1,105 @@
+// @ts-check
+import { fileURLToPath, pathToFileURL } from "node:url";
+import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
+import { Writable } from "node:stream";
+import { createWriteStream } from "node:fs";
+import { $ } from "execa";
+
+/**
+ *
+ * @param {import('node:fs').PathLike} destRaw
+ * @param {string} [tag]
+ * @param {string} [osRaw]
+ * @param {string} [archRaw]
+ */
+export async function typstMetaInstall(
+ destRaw = process.cwd(),
+ tag = undefined,
+ osRaw = process.platform,
+ archRaw = process.arch
+) {
+ const destPath =
+ destRaw instanceof URL ? fileURLToPath(destRaw) : `${destRaw}`;
+ const destFileURL =
+ destRaw instanceof URL ? destRaw : pathToFileURL(`${destRaw}`);
+ destFileURL.pathname.endsWith("/") || (destFileURL.pathname += "/");
+
+ if (tag === undefined) {
+ const response = await fetch(
+ `https://ungh.cc/repos/typst/typst/releases/latest`
+ );
+ const json = await response.json();
+ tag = json.release.tag;
+ }
+
+ const os = {
+ Windows: "win32",
+ Linux: "linux",
+ macOS: "darwin",
+ win32: "win32",
+ linux: "linux",
+ darwin: "darwin",
+ }[osRaw];
+ const arch = {
+ X64: "x64",
+ ARM64: "arm64",
+ ARM: "arm",
+ x64: "x64",
+ arm64: "arm64",
+ arm: "arm",
+ }[archRaw];
+
+ const archive = {
+ "darwin,arm64": "typst-aarch64-apple-darwin.tar.xz",
+ "linux,x64": "typst-x86_64-unknown-linux-musl.tar.xz",
+ "linux,arm": "typst-armv7-unknown-linux-musleabi.tar.xz",
+ "darwin,x64": "typst-x86_64-apple-darwin.tar.xz",
+ "win32,x64": "typst-x86_64-pc-windows-msvc.zip",
+ "linux,arm64": "typst-aarch64-unknown-linux-musl.tar.xz",
+ }[[os, arch].toString()];
+
+ const folder = {
+ "darwin,arm64": "typst-aarch64-apple-darwin",
+ "linux,x64": "typst-x86_64-unknown-linux-musl",
+ "linux,arm": "typst-armv7-unknown-linux-musleabi",
+ "darwin,x64": "typst-x86_64-apple-darwin",
+ "win32,x64": "typst-x86_64-pc-windows-msvc",
+ "linux,arm64": "typst-aarch64-unknown-linux-musl",
+ }[[os, arch].toString()];
+
+ const response = await fetch(
+ `https://github.com/typst/typst/releases/download/${tag}/${archive}`
+ );
+ await mkdir(destFileURL, { recursive: true });
+ const writable = Writable.toWeb(
+ createWriteStream(new URL(archive, destFileURL))
+ );
+ if (!response.body) throw new DOMException("No body", "NotSupportedError");
+ await response.body.pipeTo(writable);
+
+ if (archive.endsWith(".zip")) {
+ await $`powershell Expand-Archive -Path ${fileURLToPath(
+ new URL(archive, destFileURL)
+ )} -DestinationPath ${destPath} -Force`;
+ } else if (archive.endsWith(".tar.xz")) {
+ await $`tar -xJf ${fileURLToPath(
+ new URL(archive, destFileURL)
+ )} -C ${destPath}`;
+ } else {
+ throw new DOMException(
+ `Unsupported archive format: ${archive}`,
+ "NotSupportedError"
+ );
+ }
+
+ await rm(new URL(archive, destFileURL), { force: true });
+ await mkdir(new URL("./bin/", destFileURL), { recursive: true });
+ await rename(
+ new URL(`./${folder}/typst`, destFileURL),
+ new URL("./bin/typst", destFileURL)
+ );
+ await rm(new URL(`./${folder}`, destFileURL), {
+ recursive: true,
+ force: true,
+ });
+}
\ No newline at end of file