Skip to content

Modernize toolchain: bun, bun build, node:test, TS 7, Biome + rumdl + lefthook - #402

Merged
dalisoft merged 15 commits into
masterfrom
chore/modernize-toolchain
Oct 1, 2026
Merged

dalisoft merged 15 commits into
masterfrom
chore/modernize-toolchain

Conversation

@dalisoft

@dalisoft dalisoft commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

Migrates to bun + native tooling.

Changes

  • bun as package manager (baseline npm ci broken: smartlint@6.0.4 unpublished)
  • rollup + rollup-plugin-typescript2 -> bun build (3ms) + tsc --emitDeclarationOnly; jest -> node --test (1:1 port; 2 assertions adapted from jest's babel-transformed fn.toString to native)
  • ESLint + Prettier + husky + lint-staged + smartlint removed; Biome 2.5 + rumdl 0.2 + lefthook 2.1 (commitlint kept)
  • TypeScript 5.0 -> 7.0.2 (node10/bundler, lib es2017, rootDir); TS7-strict fixes (IBlock|void -> undefined, typed reduce)
  • commitlint 21: extends @commitlint/config-conventional directly (legacy 'airlight' alias unresolved)

Verification: 9/9 tests pass in 0.31s (build+test); lint clean.

Metrics

op before after delta
install npm ci fails (404) bun 2.7s restored
dependencies 929 packages 90 packages -90%
build rollup bun build 3ms no bundler dep
test jest (unrunnable) node:test 0.3s fixed

Follow-up: CI security & correctness

  • PR lint/build moved from pull_request_target to the unprivileged pull_request event (PR code no longer executes with repo secrets); the dependabot auto-merge job keeps pull_request_target and never checks out PR code; bun pinned to 1.4.2
  • Both workflows were still on npm ci, which fails after the bun migration (no package-lock.json) — migrated to bun 1.4.2 against bun.lock
  • Audit finding for the release pipeline: the published 2.4.4 release tarball accidentally ships semantic-release@^19 as its runtime dependency (this branch's package.json is clean — semantic-release is not a dependency at all). Releasing 2.4.5 from the merged branch removes that whole npm@8/tar@6 chain from every downstream consumer (including ultimate, whose audit is green except for exactly this)

Toolchain updates (follow-up directives)

  • ls-lint kept (.ls-lint.yml restored) and oxlint added — lint pipeline: ls-lint && biome check . && oxlint . && rumdl check .
  • semantic-release → dalisoft/release-me (release-me-sh, signed tags); .releaserc.json removed

@dalisoft
dalisoft force-pushed the chore/modernize-toolchain branch from afeabef to 251d110 Compare September 30, 2026 20:12

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

github-actions[bot]
github-actions Bot previously approved these changes Oct 1, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

github-actions[bot]
github-actions Bot previously approved these changes Oct 1, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

github-actions[bot]
github-actions Bot previously approved these changes Oct 1, 2026
dalisoft and others added 15 commits October 1, 2026 20:46
- replace package-lock.json with bun.lock
- npm ci was broken: smartlint@6.0.4 no longer exists on the registry
…+rumdl+lefthook

- biome.json matches the old airlight prettier style (single quotes, 80 cols, no trailing commas)
- rumdl.toml mirrors the old .markdownlint.json (MD013/MD033/MD041/MD059 off)
- lefthook.yml: pre-commit (biome+rumdl), commit-msg (commitlint), pre-push (lint+test)
- code fixes surfaced by Biome/TS7 strict: explicit types, IBlock|undefined returns, typed reduce callback
…deps to latest

- bun build bundles esm/analyze.js (15 modules, 3ms); tsc --emitDeclarationOnly for typings
- drop rollup, @rollup/plugin-node-resolve, rollup-plugin-typescript2, jest, coveralls (929 -> 90 packages)
- jest spec ported 1:1 to node:test + node:assert/strict (assertions adapted to native fn.toString output — the old expectations depended on jest's babel transform)
- tsconfig: TS7 removals (moduleResolution node10, esModuleInterop=false), explicit rootDir, lib es2017, emitDeclarationOnly
- typings entry moved to typings/src/analyze.d.ts (rootDir now repo root)
commitlint 21 cannot resolve the legacy 'airlight' extends alias; the airlight
package was only a re-export of @commitlint/config-conventional anyway
Per review: minimize diff churn — noUnusedVariables/noUnusedFunctionParameters
are warnings in Biome config, and the cosmetic underscore renames they caused
are reverted to the original parameter names. Import reordering stays off.
lint/test jobs now run on the unprivileged pull_request event so PR code
never executes with repo secrets; the dependabot auto-merge job keeps
pull_request_target and never checks out PR code. both workflows were
also still on npm ci, which fails after the bun migration (no
package-lock.json); they now use bun 1.4.2 (pinned) against bun.lock
node --test treated trailing-slash directory arguments as module files
on node 22; the test script now passes a plain path. macos-12 runners
are retired and replaced with macos-14
actions/checkout v7, actions/cache v6, actions/setup-node v7. caching
~/.bun/install/cache instead of node_modules amortizes the uWS
GitHub-tag fetch (~13.5s cold of a 16s install) and hardlinks much
faster than a node_modules tarball restore
- ls-lint: restores the .ls-lint.yml ruleset (pointcase rule no longer
  exists in @ls-lint/ls-lint 2.3) and runs first in the lint pipeline
- oxlint: added as the eslint-slot linter after biome
- release: semantic-release and its .releaserc.json replaced by
  release-me-sh (same flow as nanoexpress: npm, npm-post, git and
  github-release plugins with signed tags)
- every workflow that executes PR code runs on the unprivileged
  pull_request event with contents: read workflow permissions; the
  dependabot auto-merge job moved to its own automerge.yml (the only
  pull_request_target workflow, filtered to dependabot, with no
  repository checkout at all)
- all actions pinned to commit SHAs with version comments
  (checkout v7.0.1, cache v6.1.0, setup-node v7.0.0, setup-bun v2.2.0,
  action-dependabot-auto-merge v2.6.6)
- review-approve workflows drop the checkout (gh CLI is API-only) and
  request only pull-requests: write
exact versions (checkout v7.0.1, cache v6.1.0, setup-node v7.0.0,
setup-bun v2.2.0, action-dependabot-auto-merge v2.6.6) instead of SHA
pins — same reproducibility guarantee, easier to read and bump
approves dalisoft's PRs with a LGTM comment using only the workflow
token on the unprivileged pull_request event (no secrets, no
pull_request_target); fork PRs and dependabot PRs are excluded —
dependabot approvals happen in automerge.yml. replaces the legacy
review-approve workflow where it existed
bare directory arguments are treated as module files on node 22 and 24
(only 26 accepts them); explicit globs work identically on 22, 24 and 26
…>= 22

BREAKING CHANGE: the next release is 3.0.0: Node.js >= 22 is required,
the build pipeline is bun-based, and the published package no longer
ships semantic-release as a runtime dependency
@dalisoft
dalisoft force-pushed the chore/modernize-toolchain branch from 56c54cd to a5196c7 Compare October 1, 2026 15:49

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@dalisoft
dalisoft merged commit a5196c7 into master Oct 1, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant