1# SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
2#
3# SPDX-License-Identifier: CC0-1.0
4
5[tools]
6bun = "1.3"
7
8[tasks.fmt]
9description = "Format all files with Biome"
10run = "bun run fmt"
11
12[tasks.lint]
13description = "Lint all files with Biome"
14run = "bun run lint"
15
16[tasks.typecheck]
17description = "Type-check all packages with TypeScript"
18run = "bun run typecheck"
19
20[tasks.check]
21description = "Format, lint, and type-check"
22depends = ["fmt", "lint", "typecheck"]
23
24[tasks."release:bump"]
25description = "Bump one or more package versions"
26usage = '''
27arg "<version>" help="SemVer increment or exact version"
28arg "<packages>" help="Package selectors" var=#true var_min=1
29flag "--preid <preid>" help="Prerelease identifier for pre* increments"
30'''
31shell = "bash -c"
32run = '''
33set -euo pipefail
34
35version=${usage_version:?}
36preid=${usage_preid:-}
37eval "packages=(${usage_packages:?})"
38
39exact_version_re='^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$'
40is_exact_version=false
41if [[ "$version" =~ $exact_version_re ]]; then
42 is_exact_version=true
43fi
44
45case "$version" in
46 patch|minor|major|prepatch|preminor|premajor|prerelease) ;;
47 *)
48 if [[ "$is_exact_version" != true ]]; then
49 echo "Error: unsupported version '$version'" >&2
50 echo "Use patch, minor, major, prepatch, preminor, premajor, prerelease, or an exact SemVer." >&2
51 exit 1
52 fi
53 ;;
54esac
55
56if [[ -n "$preid" ]]; then
57 case "$version" in
58 prepatch|preminor|premajor|prerelease) ;;
59 *)
60 echo "Error: --preid only applies to prepatch, preminor, premajor, or prerelease" >&2
61 exit 1
62 ;;
63 esac
64fi
65
66resolved_dirs=$(bash scripts/resolve-release-packages.bash "${packages[@]}")
67mapfile -t dirs <<< "$resolved_dirs"
68
69if [[ "$is_exact_version" == true && -n "${dirs[1]:-}" ]]; then
70 echo "Error: exact versions may only be applied to one package at a time" >&2
71 exit 1
72fi
73
74for dir in "${dirs[@]}"; do
75 args=(pm version "$version" --no-git-tag-version)
76 if [[ -n "$preid" ]]; then
77 args+=(--preid "$preid")
78 fi
79 echo "Bumping $dir"
80 (
81 cd "$dir"
82 bun "${args[@]}"
83 )
84done
85'''
86
87[tasks."release:pack"]
88description = "Check and dry-run npm package packing"
89usage = '''
90arg "<packages>" help="Package selectors" var=#true var_min=1
91'''
92shell = "bash -c"
93run = '''
94set -euo pipefail
95
96eval "packages=(${usage_packages:?})"
97resolved_dirs=$(bash scripts/resolve-release-packages.bash "${packages[@]}")
98mapfile -t dirs <<< "$resolved_dirs"
99
100mise run check
101
102for dir in "${dirs[@]}"; do
103 echo "Packing $dir (dry run)"
104 bunx npm pack --dry-run "./$dir"
105done
106'''
107
108[tasks."release:publish"]
109description = "Check, dry-run, and publish npm packages"
110usage = '''
111arg "<packages>" help="Package selectors" var=#true var_min=1
112flag "--tag <tag>" help="npm dist-tag" default="latest"
113flag "--otp <otp>" help="One-time password for npm two-factor auth"
114'''
115shell = "bash -c"
116run = '''
117set -euo pipefail
118
119package_version() {
120 bun -e 'const fs = require("node:fs"); const path = require("node:path"); const pkg = JSON.parse(fs.readFileSync(path.join(process.argv[1], "package.json"), "utf8")); console.log(pkg.version);' "$1"
121}
122
123eval "packages=(${usage_packages:?})"
124tag=${usage_tag:?}
125otp=${usage_otp:-}
126resolved_dirs=$(bash scripts/resolve-release-packages.bash "${packages[@]}")
127mapfile -t dirs <<< "$resolved_dirs"
128
129if [[ -n "$otp" && -n "${dirs[1]:-}" ]]; then
130 echo "Error: --otp may only be used with one package at a time" >&2
131 echo "Use an npm automation token for multi-package publishing, or publish each package separately with a fresh OTP." >&2
132 exit 1
133fi
134
135for dir in "${dirs[@]}"; do
136 version=$(package_version "$dir")
137 if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+- && "$tag" == latest ]]; then
138 echo "Error: refusing to publish prerelease $dir@$version with tag latest" >&2
139 echo "Use --tag beta or another prerelease dist-tag." >&2
140 exit 1
141 fi
142done
143
144mise run check
145
146publish_args=(--access public --tag "$tag")
147if [[ -n "$otp" ]]; then
148 publish_args+=(--otp "$otp")
149fi
150
151for dir in "${dirs[@]}"; do
152 echo "Publishing $dir (dry run)"
153 bunx npm publish --dry-run "${publish_args[@]}" "./$dir"
154done
155
156for dir in "${dirs[@]}"; do
157 echo "Publishing $dir"
158 bunx npm publish "${publish_args[@]}" "./$dir"
159done
160'''