build: modernize the toolchain, adopt TypeScript 7, and pick up the republished upstreams - #350
Merged
Merged
Conversation
…nd turbo Swaps the whole build/lint/test toolchain in one pass rather than upgrading tools the swap deletes: - tsdown replaces the three `tsc -p` build passes and the `ncp package.cjs.json` step. `esm/index.js`, `cjs/index.js` and the declarations beside them keep their paths; the CJS target moves ES5 -> ES2015 (rolldown's floor). The `tslib` output is dropped: it was built on every release and never appeared in the tarball. - vitest replaces jest, ts-jest and the four jest-watch-* plugins. `globals: true` keeps every spec file byte-identical. Coverage is now a gate, not a report: thresholds are set to the level the repo already meets. - biome (via @repobuddy/biome) replaces eslint 8, its plugins and prettier. The reformat lands here. `perf_hooks` deliberately keeps its bare specifier — package.json's `browser` field maps that name, and the mapping does not apply to `node:perf_hooks`. - turbo runs the verify graph; knip replaces depcheck and found two genuinely dead pieces (`ts/assert-order/internalInterfaces.ts` and three unused test helpers). - tsdown does not typecheck, so `typecheck` is an explicit script in `verify`. Proven by appending a deliberate type error and confirming a non-zero exit. TypeScript moves to 7.0.2. The old blockers went with jest and eslint (`ts-jest`'s `<6` peer, `ts-api-utils` via eslint), tsdown accepts a `^7` peer, and this package publishes no typedoc docs — the one remaining TS7 blocker — so the full verify runs green on it. TS7 stops auto-including `@types/*`, so `types` is now named explicitly. Runtime dependency minimums are raised to the versions this is built and tested against: iso-error@6.0.5, path-equal@1.2.7, satisfier@5.4.4, tersify@4.0.6, type-plus@7.6.2. type-plus stays on the 7.x line deliberately; its 8.x is still a changesets prerelease. Supply-chain soak: the 24h window moves from `.npmrc` (where npm warned it was not a valid key) into pnpm-workspace.yaml, and gains `minimumReleaseAgeStrict: true`. pnpm 11's default mode is loose — on meeting a too-young package it silently appends it to `minimumReleaseAgeExclude` and continues, so the soak enforces nothing. Strict mode fails the install instead, and every exclusion below it is a deliberate exact-version pin. The list was empty before this change and contains only reviewed entries after it; the transitive `unpartial@1.0.7` is pinned too, because the soak evaluates per resolved version and pinning the direct deps alone was not enough. `.husky/commit-msg` was committed 100644, so git had been skipping it — commitlint had never actually run. Now 100755 and verified to reject a non-conventional message.
Nothing here was merging bot PRs, through three independent faults at once: - `.github/mergify.yml` was `extends: .github`, and `cyberuni/.github` carries no Mergify config at all — so it resolved to nothing. - `dependabot-automerge.yml` armed `gh pr merge --auto --squash`, and this repo disallows squash merges. It also had no `.github/dependabot.yml` to feed it. - The two-line Renovate preset carries no automerge policy. Renovate is now the single updater and the single merge mechanism, with `platformAutomerge` so it enqueues natively through the merge queue rather than merging around it. Majors stay manual. `minimumReleaseAge` mirrors the pnpm-side soak.
🦋 Changeset detectedLatest commit: af3732f The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #350 +/- ##
==========================================
- Coverage 96.35% 95.18% -1.18%
==========================================
Files 24 21 -3
Lines 357 187 -170
Branches 60 47 -13
==========================================
- Hits 344 178 -166
+ Misses 13 8 -5
- Partials 0 1 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This was referenced Sep 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings
assertrononto the current stack in one pass: toolchain swap, the five republished runtime upstreams, TypeScript 7, a repaired supply-chain soak, and one updater feeding one merge mechanism.Toolchain
tsc -ppasses +ncp@repobuddy/biomenpm-run-allchainEleven devDependencies were deleted rather than upgraded, which is why five open Renovate majors (jest 30, eslint 10,
@typescript-eslint8, size-limit 12) are closed by this rather than merged.Published paths are preserved.
esm/index.js,cjs/index.js,cjs/package.jsonand the declarations beside each keep their names;LICENSEandREADME.mdstill ship; no spec file ships. The emitted output does change — the CJS target moves ES5 → ES2015 (rolldown's floor), a small_virtual/helper set appears next to the entry, and per-module.d.tsfiles unreachable through theexportsmap are no longer emitted — so this carries a patch changeset, not afeat.tsdown does not typecheck.
typecheckis now an explicit script insideverify; proven real by appending a deliberate type error and confirming a non-zero exit.Coverage is a gate, not a report. Thresholds are set to the level the repo already meets (95%).
TypeScript 7 — adopted
The sweep-wide "TS7 is blocked" note does not apply here. Both old blockers (
ts-jest's<6peer,ts-api-utilsvia eslint) leave with jest and eslint;tsdown@0.22accepts a^7peer; and the one real remaining blocker —typedoc@0.28.20crashing at import under TS7 — is not present, because this package publishes no typedoc docs. The fullverifyruns green on 7.0.2.TS7 stops auto-including
@types/*, sotypesis now named explicitly (["node", "vitest/globals"]).Runtime upstreams
Minimums raised to the versions this is built and tested against, all republished by the same sweep and all carrying npm provenance:
iso-errorpath-equalsatisfiertersifytype-plustype-plusdeliberately stays on 7.x — its 8.x line is still a changesets prerelease on thebetatag.Supply-chain soak — a control repaired, not loosened
The 24h window moves out of
.npmrc(where npm warnedminimumreleaseagewas not a valid key) intopnpm-workspace.yaml, and gainsminimumReleaseAgeStrict: true.This matters because pnpm 11's default mode is loose and self-weakening: on meeting a package younger than the window it does not fail — it silently appends that package to
minimumReleaseAgeExcludeand carries on. Under the default, the soak enforces nothing and the exclusion list grows by itself.Under strict mode the install fails with
ERR_PNPM_NO_MATURE_MATCHING_VERSIONinstead, so every exclusion has to be deliberate. Seven versions tripped it here, and each exclusion below is an exact-version pin, never a weakened policy:unpartial@1.0.7is the point worth noting: the soak is evaluated per resolved version including transitives, so pinning the five direct dependencies was not enough —tersify@4.0.6pulls it.knipwas held at~6.33.0rather than excluded, because a range constraint is cheaper than a pin.Audit:
minimumReleaseAgeExcludewas empty before this change and, after a fullpnpm nuke+pnpm install --frozen-lockfile, contains only the five reviewed entries above. Nothing was auto-appended.Pre-existing bugs surfaced, not regressions introduced
.husky/commit-msgwas committed100644, so git had been skipping it — commitlint had never once run on this repo. Now100755, and verified to reject a non-conventional message.knipfoundts/assert-order/internalInterfaces.tsand three test helpers that nothing referenced. Removed.perf_hookskeeps its bare specifier deliberately (with a scoped biome ignore):package.json'sbrowserfield maps that name for bundlers, and the mapping does not apply to thenode:prefixed form.Dependency automation
Nothing was merging bot PRs here, through three independent faults at once:
.github/mergify.ymlwasextends: .github, andcyberuni/.githubcarries no Mergify config at all — it resolved to nothing.dependabot-automerge.ymlarmedgh pr merge --auto --squash, and this repo disallows squash merges (and there is no.github/dependabot.ymlto feed it).Both dead mechanisms are removed. Renovate with
platformAutomergeis now the single updater and the single merge mechanism, and it enqueues natively through the merge queue rather than merging around it. Majors stay manual.Proof
pnpm nuke && pnpm install --frozen-lockfile && pnpm verifygreen from a cold tree,--force(no turbo cache).pnpm packtarball diffed against the publishedassertron@11.5.3:LICENSE,README.md,cjs/index.{js,d.ts},cjs/package.json,esm/index.{js,d.ts}all present; zero spec files.importand CJSrequireboth exercised (truthy,falsy→AssertionError,satisfies,AssertOrder), andtsc --module nodenext --strictresolves the types from both an ESM and a CJS consumer.Settings applied outside this PR
Merge queue rule added to the
mainruleset (withstrict_required_status_checks_policy: false); Actions default workflow permissions tightenedwrite→read(every workflow that needs more declares its ownpermissions:); Dependabot security updates disabled in favour of Renovate; and the four stale secrets —NPM_TOKEN,CI_GITHUB_TOKEN,CODACY_PROJECT_TOKEN,CODECOV_TOKEN— deleted. Releases have run on OIDC trusted publishing since 11.5.3, which carries provenance.