Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ jobs:
with:
node-version: 24

- name: Setup Bun
uses: oven-sh/setup-bun@v2

- name: Cache dependencies
uses: actions/cache@v5
with:
Expand All @@ -46,6 +49,11 @@ jobs:

- run: npm install

# --no-install because a bare `bunx quartz` falls back to an unrelated
# package on npm instead of failing
- name: Ensure bunx resolves the local CLI
run: bunx --no-install quartz --help

- name: Install Quartz plugins
run: npx quartz plugin install

Expand Down
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"test": "tsx --test",
"profile": "0x -D prof ./quartz/bootstrap-cli.mjs build --concurrency=1",
"install-plugins": "npx tsx ./quartz/plugins/loader/install-plugins.ts",
"prebuild": "npm run install-plugins"
"prebuild": "npm run install-plugins",
"postinstall": "node quartz/bootstrap-postinstall.mjs"
},
"engines": {
"npm": ">=10.9.2",
Expand Down
77 changes: 77 additions & 0 deletions quartz/bootstrap-postinstall.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env node
import {
chmodSync,
existsSync,
mkdirSync,
readlinkSync,
symlinkSync,
unlinkSync,
writeFileSync,
} from "fs"
import path from "path"

// npm links the `bin` entry into node_modules/.bin on install, bun does not
try {
const root = path.resolve(import.meta.dirname, "..")
const target = path.join(root, "quartz", "bootstrap-cli.mjs")
const binDir = path.join(root, "node_modules", ".bin")
const linkPath = path.join(binDir, "quartz")
const relativeTarget = path.relative(binDir, target)

// as a dependency, npm links the bin itself, running here would only litter a node_modules into the package
if (!existsSync(path.join(root, "node_modules"))) {
process.exit(0)
}

mkdirSync(binDir, { recursive: true })

if (process.platform === "win32") {
// windows ignores the shebang, so it needs the same shims npm writes
const posixTarget = relativeTarget.split(path.sep).join("/")

// a symlink left by a wsl run would be followed and the shim written straight into the cli source file
try {
unlinkSync(linkPath)
} catch {}

writeFileSync(
linkPath,
`#!/bin/sh\nexec node --no-deprecation "$(dirname "$0")/${posixTarget}" "$@"\n`,
)
writeFileSync(
`${linkPath}.cmd`,
`@ECHO off\r\nnode --no-deprecation "%~dp0${relativeTarget}" %*\r\n`,
)
writeFileSync(
`${linkPath}.ps1`,
`#!/usr/bin/env pwsh\nnode --no-deprecation "$PSScriptRoot/${posixTarget}" $args\nexit $LASTEXITCODE\n`,
)
} else {
try {
// checked in as 755, but bunx won't run the cli if a setup drops the mode
chmodSync(target, 0o755)
} catch (err) {
console.warn(`[quartz] could not make ${target} executable: ${err.message}`)
}

try {
symlinkSync(relativeTarget, linkPath)
} catch (err) {
if (err.code !== "EEXIST") {
throw err
}
// not necessarily a symlink, a windows checkout leaves a plain file here
let current = null
try {
current = readlinkSync(linkPath)
} catch {}

if (current !== relativeTarget) {
unlinkSync(linkPath)
symlinkSync(relativeTarget, linkPath)
}
}
}
} catch (err) {
console.warn(`[quartz] could not link node_modules/.bin/quartz: ${err.message}`)
}
Loading