diff --git a/.coderabbit.yaml b/.coderabbit.yaml
index 79c0d2e..b4a2d9d 100644
--- a/.coderabbit.yaml
+++ b/.coderabbit.yaml
@@ -28,7 +28,7 @@ reviews:
instructions: >-
Cloudflare Worker and the ChannelRoom SQLite Durable Object, on the Workers Free plan only (no paid
products). Every promise is awaited or handed to ctx.waitUntil; a dropped one can be cancelled. Chat mod
- checks use ev.mod from MOD_BADGES in eventsub.js (a lead moderator has only the lead_moderator badge);
+ checks use ev.mod from MOD_BADGES in server/eventsub.ts (a lead moderator has only the lead_moderator badge);
flag any other badge read. Refusing the bot as a target stays the single BOT_TARGET_ACTIONS check.
Channels, logins and domains come from site.config.js only. Secrets, OAuth tokens and session values must
never reach logs, chat replies or error bodies.
@@ -40,7 +40,7 @@ reviews:
on the overlay but fighters, nameplates, bubbles and duel effects.
- path: "**/*.{ts,mts,cts,tsx}"
instructions: >-
- Strict TypeScript (tsconfig.strict.json lists each new or ported file) with .ts import paths and erasable syntax
+ Strict TypeScript (every file is in a tsconfig program that bun run typecheck checks) with .ts import paths and erasable syntax
only. A pull request from a port/ branch changes no runtime code; port-check proves it in CI. Flag every
any, as cast or ! assertion without a reason in a comment on that line or the line above.
- path: "tests/**"
@@ -63,7 +63,7 @@ reviews:
mode: warning
instructions: >-
If the pull request changes behavior in server/, src/ or public/ (not only formatting, comments or
- types), it must also change or add a test in tests/*.test.{mjs,ts} and update the matching doc in docs/
+ types), it must also change or add a test in tests/*.test.ts and update the matching doc in docs/
(CONTRACTS.md for routes, rules and config; STREAMER_SETUP.md or DUELS.md for what a streamer sees).
Pass if both are present or the change has no behavior effect.
- name: Config lives in site.config.js
diff --git a/AGENTS.md b/AGENTS.md
index eb98f13..8862c97 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -40,7 +40,7 @@ It is not wrangler: never `wrangler deploy` or `--env`.
refuses on its own.
- **Every behavior change gets a unit test** in `tests/*.test.ts` and a doc update: routes, rules and config in
`docs/CONTRACTS.md`; anything a streamer sees in `docs/STREAMER_SETUP.md` or `docs/DUELS.md`.
-- **Strict TypeScript.** New and ported code is `.ts` with `.ts` imports. A port PR changes no runtime code
+- **Strict TypeScript.** New code is `.ts` with `.ts` imports. A port PR changes no runtime code
(`bun run port-check`). Each `any`, `as` or `!` says why on that line or above (docs/DEVELOPMENT.md).
- **Browser tests run headed with GPU flags** through `chromeOptions()` in `tests/chrome.ts`. Don't set `HEADLESS=1`.
- **Design:** read `DESIGN.md` before changing any page or the overlay. It documents the system in
diff --git a/admin/index.html b/admin/index.html
index 8829e03..6425731 100644
--- a/admin/index.html
+++ b/admin/index.html
@@ -124,7 +124,7 @@
Rules: every save becomes a new version you can revert
Note for the history (optional)
-
+
Save new version Discard changes No unsaved changes. Edit any rule to save a new version.
@@ -157,7 +157,7 @@
Custom characters
-
Uploading characters isn't available yet.
diff --git a/docs/CONTRACTS.md b/docs/CONTRACTS.md
index 0be59d6..4f508f7 100644
--- a/docs/CONTRACTS.md
+++ b/docs/CONTRACTS.md
@@ -563,16 +563,15 @@ gitleaks git --config .gitleaks.toml --redact . # secret scan; CI scans the wh
bun run audit # bun audit --audit-level=high; CI fails on a high or critical advisory
bun run format # oxfmt (.oxfmtrc.json); format:check only reports
bun run lint # oxlint --deny-warnings, type-aware (.oxlintrc.json)
-bun run typecheck # tsc: tsconfig.worker/web/node.json (JS, loose), then four strict programs split by
- # globals: tsconfig.strict.json (Worker and Node types: server/, scripts/,
- # site.config.js, shared types, unit tests of Worker modules and tests/fakes.ts),
- # tsconfig.strict-web.json (DOM types: src/, types/dom.ts), tsconfig.strict-tests.json
- # (DOM and Node: unit tests of DOM modules) and tsconfig.strict-tests-shared.json
- # (Worker, DOM and Node: unit tests that import both); then port-check --strict-list.
- # It requires every TypeScript file in the program tsc reads from some strict config,
- # except cloudflare.config.ts (tsconfig.node.json) and types/browser.d.ts
- # (tsconfig.web.json). It fails a tsc error reading any of them, a strict option off
- # in any, a .d.ts, .d.mts or .d.cts
+bun run typecheck # tsc on five strict programs split by globals (strict options in tsconfig.base.json):
+ # tsconfig.worker.json (Workers types: server/), tsconfig.web.json (DOM types: src/,
+ # types/dom.ts), tsconfig.node.json (Workers and Node: scripts/, build configs, unit
+ # tests of Worker modules and tests/fakes.ts), tsconfig.node-dom.json (DOM and Node:
+ # unit tests of DOM modules, Playwright code, the character build) and
+ # tsconfig.node-all.json (Workers, DOM and Node: tests that import both); then
+ # port-check --strict-list. It requires every TypeScript file in the program tsc reads
+ # from some strict config. It fails a tsc error reading any of them, a strict option
+ # off in any, a .d.ts, .d.mts or .d.cts
# under skipLibCheck, and in any code file in those programs a comment with
# @ts-nocheck (any letter case) or eslint-disable / oxlint-disable (any form).
bun run port-check # node scripts/port-check.ts --base origin/main. Exits 1 on a difference or problem,
@@ -584,7 +583,7 @@ bun run port-check # node scripts/port-check.ts --base origin/main. Exit
# bunx cf build, offline, and compares every .cloudflare/output file (JS without
# comments, the rest byte for byte).
# - Leaves tsconfig*.json changes to that build diff, but fails a new root
- # tsconfig.json. For each strict config the merge base has (any of the four),
+ # tsconfig.json. For each strict config the merge base has (any of the five),
# the head's resolved compilerOptions for it
# (tsc --showConfig) must equal the base's; only its files list may change.
# - In tests/, scripts/, cloudflare.config.ts and vite.config.ts, passes a string
@@ -599,7 +598,7 @@ bun run port-check # node scripts/port-check.ts --base origin/main. Exit
node scripts/port-rename.ts # starts a port: renames to .ts, rewrites imports and doc paths;
# refuses files under public/ and never rewrites one: it lists each
# line there that names a renamed file as file:line
-bun run test:unit # node --import ./tests/register.ts --test "tests/*.test.{mjs,ts}"
+bun run test:unit # node --import ./tests/register.ts --test "tests/*.test.ts"
bun run test:port # node --test tests/port/port-check.test.ts: port-check and port-rename against fixture
# repos in one new OS temp folder per run (the build tests run bunx cf build); not in
# check, for speed; CI runs it next to bun run check
diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md
index e51434e..bbd4d5b 100644
--- a/docs/DEVELOPMENT.md
+++ b/docs/DEVELOPMENT.md
@@ -43,14 +43,11 @@ bun run dev
- `bun run lint` runs [oxlint](https://oxc.rs/docs/guide/usage/linter) with type-aware rules
(`.oxlintrc.json`). Warnings fail it. In `server/` every promise must be awaited or handed to
`waitUntil`, because the Worker can cancel one that is dropped.
-- `bun run typecheck` runs `tsc` seven times. `tsconfig.worker.json` (server/, all TypeScript, with Workers types only),
- `tsconfig.web.json` (src/ with the served modules in src/served/, DOM types plus `types/browser.d.ts`) and `tsconfig.node.json`
- (the build configs) check loosely; `tsconfig.strict.json` (Worker and Node types),
- `tsconfig.strict-web.json` (DOM types), `tsconfig.strict-tests.json` (DOM and Node types) and
- `tsconfig.strict-tests-shared.json` (Worker, DOM and Node types) check every TypeScript file, the unit
- tests, browser tests, scripts and `vite.config.ts` included, with `strict`, `noUncheckedIndexedAccess` and
- `exactOptionalPropertyTypes`. In a `.js` file, add JSDoc where inference falls short
- (`/** @param {{ … }} opts */`) rather than casting the problem away.
+- `bun run typecheck` runs `tsc` on five strict programs (below), then `node scripts/port-check.ts --strict-list`.
+ `tsconfig.base.json` sets `strict`, `noUncheckedIndexedAccess` and `exactOptionalPropertyTypes` for all of
+ them, so every TypeScript file is checked the same way: the Worker, the pages, the unit tests, browser tests,
+ scripts and build configs. The one JavaScript file in a program is `site.config.js`, which has tsc check it
+ through its own `// @ts-check`.
- `bun run audit` checks every installed package against the advisory database and fails on a high or
critical one. When the fix sits behind a dependency that pins the old version, add an exact version to
`overrides` in `package.json` (as for `sharp`) once that release is 7 days old. Before bumping a package,
@@ -60,31 +57,36 @@ bun run dev
## TypeScript port
-The code moves from JSDoc-typed JavaScript to strict TypeScript one file at a time. Node 22.18+ runs
-`.ts` scripts with no flags, and Vite and `cf build` strip the types from the pages and the Worker.
+The code moved from JSDoc-typed JavaScript to strict TypeScript one file at a time. Every file outside
+`public/`, except `site.config.js`, is now `.ts`. Node 22.18+ runs `.ts` scripts with no flags, and Vite
+and `cf build` strip the types from the pages and the Worker.
- New and ported files are `.ts`, import local files with the `.ts` extension and use only syntax
that strips to JavaScript (no `enum`, `namespace` or parameter properties; `erasableSyntaxOnly`).
Type-only imports say `import type` (`verbatimModuleSyntax`).
-- Every TypeScript file (`.ts`, `.mts`, `.cts`, `.tsx`) is listed in `files` in one of the four
- strict programs, split by runtime so each sees only its own globals:
- - `tsconfig.strict.json`: the Worker (`server/`), the scripts that use no DOM or Buffer methods (`scripts/`),
- `vite.config.ts`, `site.config.js`, the shared types, the Node-only test runners (`tests/chrome.ts`,
- `tests/seed-local.ts`, `tests/build-versions.ts`, `tests/upload-workerd.ts`), and the unit tests that import only Worker and shared modules (with their
- helpers: `tests/fakes.ts`, `tests/register.ts` and the others). Worker and Node types, no DOM, so
- server code can't use `document` or `window`, and Web Crypto and streams keep the Workers types.
- - `tsconfig.strict-web.json`: browser code (`src/`, and `types/dom.ts`). DOM types and
- `vite/client`, no Worker or Node types. A browser file that imports a server module pulls it
- into this program too, so such a module (today `server/upgrades.ts`, and through type imports
- in `src/dashboard.ts` and `src/parse.ts`, `server/cosmetics.ts` and `server/model.ts`) must
- type-check with DOM types as well.
- - `tsconfig.strict-tests.json`: unit tests that import a DOM module but no Worker module
+- Every TypeScript file (`.ts`, `.mts`, `.cts`, `.tsx`) is in one of five strict programs, split by
+ runtime so each sees only its own globals. The Worker types, the DOM and Node clash (the Worker types declare
+ `Buffer` as `any`; they and the DOM type streams, Web Crypto and canvas contexts differently), so one program
+ can't hold them all:
+ - `tsconfig.worker.json`: the Worker, every file in `server/`. Workers types only, so server code can't
+ use Node, `document` or `window`, and Web Crypto and streams keep the Workers types.
+ - `tsconfig.web.json`: browser code, every file in `src/` (the served modules in `src/served/` included),
+ and `types/dom.ts`. DOM types and `vite/client`, no Worker or Node types. A browser file that imports a
+ server module pulls it into this program too, so such a module (today `server/upgrades.ts`, and through
+ type imports in `src/dashboard.ts` and `src/parse.ts`, `server/cosmetics.ts` and `server/model.ts`)
+ must type-check with DOM types as well.
+ - `tsconfig.node.json`: the scripts that use no DOM or Buffer methods (`scripts/`), `vite.config.ts` and
+ `cloudflare.config.ts`, the Node-only test runners (`tests/chrome.ts`, `tests/seed-local.ts`,
+ `tests/build-versions.ts`, `tests/upload-workerd.ts`), and the unit tests that import only Worker and
+ shared modules (with their helpers: `tests/fakes.ts`, `tests/register.ts` and the others). Worker and
+ Node types, no DOM.
+ - `tsconfig.node-dom.json`: unit tests that import a DOM module but no Worker module
(`tests/browser-parse.test.ts`, `tests/overlay.test.ts`, `tests/served.test.ts`), and Playwright code that imports none
(`tests/dev-ui.ts`, `scripts/og-image.ts`, `scripts/live-chat-e2e.ts`), whose page callbacks
run in the browser. DOM and Node types. The character build (`scripts/build-characters.ts`,
`scripts/lib/png-io.ts`, `scripts/lib/zip-read.ts`) is here too: the Worker types declare `Buffer`
- as `any`, which hides its methods in `tsconfig.strict.json`.
- - `tsconfig.strict-tests-shared.json`: unit tests that import both a Worker module and a DOM
+ as `any`, which hides its methods in `tsconfig.node.json`.
+ - `tsconfig.node-all.json`: unit tests that import both a Worker module and a DOM
module (`tests/arena-client.test.ts`, `tests/atlas.test.ts`, `tests/cosmetics.test.ts`,
`tests/spritify.test.ts`), and the browser tests that import a Worker module (`tests/smoke.ts`,
`tests/ui.ts`, `tests/arena-browser.ts`, `tests/e2e-local.ts`). Worker, DOM and Node types. Keep a test file on one side where
@@ -96,24 +98,24 @@ The code moves from JSDoc-typed JavaScript to strict TypeScript one file at a ti
value the test expects to find, and `Loose` (`any`) for JSON bodies and rows a test asserts on.
Each of their casts carries its reason there once.
- `types/lib-guards.ts`, `types/site.ts` and `site.config.js` are on every list. A `.d.ts` file on
- any fails (below), so new types go in `.ts` files. Two TypeScript files are checked by
- another program instead: `cloudflare.config.ts` by `tsconfig.node.json` and
- `types/browser.d.ts` by `tsconfig.web.json`. `bun run typecheck` (so `bun run check`) enforces
+ `tsconfig.worker.json` and `tsconfig.web.json` take a folder (`include`), so a new file in `server/`
+ or `src/` is checked as soon as it exists; the three Node programs list each file in `files`. `types/lib-guards.ts`, `types/site.ts` and
+ `site.config.js` are in every program. A `.d.ts` file in any fails (below), so new types go in `.ts`
+ files. `bun run typecheck` (so `bun run check`) enforces
this by ending with `node scripts/port-check.ts --strict-list`, which reads every tracked and
untracked file that git doesn't ignore and prints
- `tsconfig.strict.json, tsconfig.strict-web.json, tsconfig.strict-tests.json and tsconfig.strict-tests-shared.json cover every TypeScript file`,
+ `tsconfig.worker.json, tsconfig.web.json, tsconfig.node.json, tsconfig.node-dom.json and tsconfig.node-all.json cover every TypeScript file`,
or one line per file it misses, as
- ` is not in tsconfig.strict.json, tsconfig.strict-web.json, tsconfig.strict-tests.json or tsconfig.strict-tests-shared.json`.
- The lines name `tsconfig.strict.json` and each of the other three the repo has (two read
- `a and b` / `a or b`), so a repo with only `tsconfig.strict.json` names it alone. It asks tsc for
+ ` is not in tsconfig.worker.json, tsconfig.web.json, tsconfig.node.json, tsconfig.node-dom.json or tsconfig.node-all.json`.
+ The lines name `tsconfig.worker.json` and each of the other four the repo has (two read
+ `a and b` / `a or b`), so a repo with only `tsconfig.worker.json` names it alone. It asks tsc for
each program (`tsc -p --listFilesOnly`), so `files`, `include` and `exclude` count as
tsc reads them, and each error tsc prints reading a config fails it too, as
`tsc -p : error TS…`.
- The strict list also fails when any strict config checks less, as tsc reads it after
`extends` (`tsc --showConfig`; the rules take about 0.25 s). Each line names the config; the
- problems print in the order `tsconfig.strict.json`, `tsconfig.strict-web.json`,
- `tsconfig.strict-tests.json`, `tsconfig.strict-tests-shared.json`:
+ problems print in the order `tsconfig.worker.json`, `tsconfig.web.json`, `tsconfig.node.json`,
+ `tsconfig.node-dom.json`, `tsconfig.node-all.json`:
- `strict`, `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, `verbatimModuleSyntax` and
`erasableSyntaxOnly` must be true:
` must set to true (it is )`.
@@ -157,10 +159,10 @@ A port pull request changes types only, from a `port/` branch:
oxc-stripped JavaScript of its `.js` or `.ts` source at `/.js` (docs/CONTRACTS.md §9). oxc
keeps comments, so a port that adds only types serves the same code under the same `?v=` hash,
while a changed comment changes the hash and open overlays reload once.
-2. Add types until `bun run typecheck` passes, and add the file to `tsconfig.strict.json` (Worker,
- scripts, unit tests of Worker modules), `tsconfig.strict-web.json` (browser code in `src/`),
- `tsconfig.strict-tests.json` (unit tests of DOM modules, Playwright code) or
- `tsconfig.strict-tests-shared.json` (tests that import both).
+2. Add types until `bun run typecheck` passes. A file in `server/` or `src/` is already in its program;
+ add any other to `files` in `tsconfig.node.json` (scripts, unit tests of Worker modules),
+ `tsconfig.node-dom.json` (unit tests of DOM modules, Playwright code) or `tsconfig.node-all.json`
+ (tests that import both).
3. `bun run port-check` (`node scripts/port-check.ts --base origin/main`) checks every file that
differs between the working tree and where the branch left `main`. Code files are `.js`, `.mjs`,
`.cjs`, `.jsx`, `.ts`, `.mts`, `.cts` and `.tsx`. Run without `--base [` or `--strict-list`,
diff --git a/package.json b/package.json
index e4ebf58..07c0c15 100644
--- a/package.json
+++ b/package.json
@@ -12,12 +12,12 @@
"format": "oxfmt",
"format:check": "oxfmt --check",
"lint": "oxlint --deny-warnings",
- "typecheck": "tsc -p tsconfig.worker.json && tsc -p tsconfig.web.json && tsc -p tsconfig.node.json && tsc -p tsconfig.strict.json && tsc -p tsconfig.strict-web.json && tsc -p tsconfig.strict-tests.json && tsc -p tsconfig.strict-tests-shared.json && node scripts/port-check.ts --strict-list",
+ "typecheck": "tsc -p tsconfig.worker.json && tsc -p tsconfig.web.json && tsc -p tsconfig.node.json && tsc -p tsconfig.node-dom.json && tsc -p tsconfig.node-all.json && node scripts/port-check.ts --strict-list",
"port-check": "node scripts/port-check.ts --base origin/main",
"audit": "bun audit --audit-level=high",
"check": "bun run format:check && bun run lint && bun run typecheck && bun run test:unit",
"test": "node tests/smoke.ts",
- "test:unit": "node --import ./tests/register.ts --test \"tests/*.test.{mjs,ts}\"",
+ "test:unit": "node --import ./tests/register.ts --test \"tests/*.test.ts\"",
"test:port": "node --test tests/port/port-check.test.ts",
"test:ui": "node tests/ui.ts && node tests/arena-browser.ts",
"test:dev-ui": "node tests/dev-ui.ts",
diff --git a/public/_headers b/public/_headers
index bda280f..db9f515 100644
--- a/public/_headers
+++ b/public/_headers
@@ -1,17 +1,17 @@
-# Static responses only; /api/* and /auth/* set their own headers in server/worker.js.
-# The Content-Security-Policy lines repeat server/security.js (PAGE_CSP, OVERLAY_CSP); tests/security.test.mjs checks they match.
+# Static responses only; /api/* and /auth/* set their own headers in server/worker.ts.
+# The Content-Security-Policy lines repeat server/security.ts (PAGE_CSP, OVERLAY_CSP); tests/security.test.ts checks they match.
/*
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Strict-Transport-Security: max-age=31536000; includeSubDomains
-# Vite's bundles have a content hash in the name (vite.config.js assetsDir), so a new build gets new URLs.
+# Vite's bundles have a content hash in the name (vite.config.ts assetsDir), so a new build gets new URLs.
/assets/build/*
Cache-Control: public, max-age=31536000, immutable
# Pages with sign-in and mod actions can't be framed by other sites (clickjacking). The overlay stays frameable for OBS
# and for the demo on /start. The pages in runWorkerFirst now pass through the Worker, which sets these itself
-# (server/worker.js page()); these rules cover them if assets ever answer directly. The home page (/) serves the intro.
+# (server/worker.ts page()); these rules cover them if assets ever answer directly. The home page (/) serves the intro.
/
Content-Security-Policy: default-src 'self'; script-src 'self' https://static.cloudflareinsights.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; media-src 'self' data: blob:; object-src 'none'; base-uri 'self'; connect-src 'self' https://cloudflareinsights.com; frame-ancestors 'none'
X-Frame-Options: DENY
@@ -27,7 +27,7 @@
# no-transform keeps Cloudflare from adding its Web Analytics beacon, which OVERLAY_CSP blocks (a console error in OBS
# and in the /start demo on every load). max-age=0 and must-revalidate are the assets default, so a new build still loads.
-# The OBS overlay stays out of search results. The test site's pages and robots.txt say noindex from the Worker (server/worker.js).
+# The OBS overlay stays out of search results. The test site's pages and robots.txt say noindex from the Worker (server/worker.ts).
/overlay*
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; media-src 'self' data: blob:; object-src 'none'; base-uri 'self'; connect-src 'self' wss://irc-ws.chat.twitch.tv
X-Robots-Tag: noindex, nofollow
diff --git a/public/dashboard.css b/public/dashboard.css
index fd895bf..8aa28b8 100644
--- a/public/dashboard.css
+++ b/public/dashboard.css
@@ -1385,7 +1385,7 @@ html:has(.config-bar.dirty) {
@media (max-width: 900px) {
/* narrow screens: the preview card sticks to the top of the screen as a compact bar while you pick in the tabs
- below it, so the fighter and Save are always in view (dashboard.js keeps scroll-padding-top clear of it) */
+ below it, so the fighter and Save are always in view (dashboard.ts keeps scroll-padding-top clear of it) */
/* :has() matches the wide /start rule's specificity, so the sign-in card also stacks */
.hero-grid,
.hero-grid:has(.signup-card) {
@@ -2850,7 +2850,7 @@ body:has(#gate:not([hidden])) .gate {
}
}
-/* round 7: voxel thumbnails on the picker tiles (src/voxthumb.js); the flat sprite shows until one is drawn */
+/* round 7: voxel thumbnails on the picker tiles (src/voxthumb.ts); the flat sprite shows until one is drawn */
.thumb {
display: grid;
place-items: center;
@@ -3282,7 +3282,7 @@ body:has(#gate:not([hidden])) .gate {
}
/* ---------- round 10 ---------- */
-/* phones: once you scroll into the picker the stuck preview becomes a short strip (dashboard.js compactPreview) */
+/* phones: once you scroll into the picker the stuck preview becomes a short strip (dashboard.ts compactPreview) */
@media (max-width: 900px) {
html.compact .hero-card.has-3d .showcase {
height: 148px;
@@ -3412,7 +3412,7 @@ body:has(#gate:not([hidden])) .gate {
/* ---------- round 11 ---------- */
@media (max-width: 900px) {
- /* the Save bar steps aside while scrolling down and on Ranks and Rules (dashboard.js tuckSaveBar) */
+ /* the Save bar steps aside while scrolling down and on Ranks and Rules (dashboard.ts tuckSaveBar) */
html.bar-away .hero-card.has-3d .toolbar {
transform: translateY(110%);
}
@@ -4390,7 +4390,7 @@ main.page:has(> .ready:last-child) {
}
@media (max-width: 900px) {
/* phones: the flat on-stream view rides over the 3D stage instead of taking a row. Only its "Preview a win" chip shows;
- the on-stream strip slides up along the stage's bottom while the win plays (dashboard.js sets .is-playing) */
+ the on-stream strip slides up along the stage's bottom while the win plays (dashboard.ts sets .is-playing) */
.hero-card.has-3d .preview {
grid-area: show;
align-self: stretch;
@@ -4887,7 +4887,7 @@ body:has(.hero-card.has-3d) .site-foot {
margin-top: 0;
}
-/* ---------- round 28: the intro's camera moves on every page, as baked stills scrubbed by scroll (src/scrub.js) ---------- */
+/* ---------- round 28: the intro's camera moves on every page, as baked stills scrubbed by scroll (src/scrub.ts) ---------- */
/* the backdrop: the camera pulls back from the floating islets as the page scrolls; the old still stays until it loads */
.scene-sky {
position: fixed;
diff --git a/scripts/port-check.ts b/scripts/port-check.ts
index fceae3f..0cd50a4 100644
--- a/scripts/port-check.ts
+++ b/scripts/port-check.ts
@@ -1,7 +1,7 @@
// Proves a TypeScript port changes no runtime code, and that the strict programs check every TypeScript file:
-// tsconfig.strict.json (the Worker, scripts, shared files and most unit tests), tsconfig.strict-web.json (browser code),
-// tsconfig.strict-tests.json (unit tests of DOM modules) and tsconfig.strict-tests-shared.json (unit tests that import
-// both a Worker module and a DOM module).
+// tsconfig.worker.json (the Worker), tsconfig.web.json (browser code), tsconfig.node.json (scripts, build configs and
+// unit tests of Worker modules), tsconfig.node-dom.json (unit tests of DOM modules, Playwright code) and
+// tsconfig.node-all.json (tests that import both a Worker module and a DOM module).
//
// `--base ][` pairs every file at the merge base with `][` against the working tree. Code files are stripped to
// JavaScript with oxc and compared. A file pairs with the same path; a code file gone at head pairs with a new code file
@@ -37,27 +37,24 @@ import {
type Specifier,
} from "./lib/port.ts";
-const STRICT_CONFIG = "tsconfig.strict.json";
-
-/** The strict program for browser code: DOM types, and none of the Worker's or Node's. */
-const STRICT_WEB_CONFIG = "tsconfig.strict-web.json";
-
-/** The strict program for unit tests that import a DOM module: DOM and Node types, no Worker types. */
-const STRICT_TESTS_CONFIG = "tsconfig.strict-tests.json";
-
-/** The strict program for unit tests that import both a Worker module and a DOM module: all three type sets. */
-const STRICT_TESTS_SHARED_CONFIG = "tsconfig.strict-tests-shared.json";
-
-/** The strict programs, in the order their problems print. A file passes the strict list in any of them; a config the
- * working tree lacks is skipped. */
-const STRICT_CONFIGS = [STRICT_CONFIG, STRICT_WEB_CONFIG, STRICT_TESTS_CONFIG, STRICT_TESTS_SHARED_CONFIG];
-
-/** The strict configs a message names: tsconfig.strict.json always, then each other one `root` has, as "a", "a or b",
- * or "a, b or c" (with `and` for "and"). */
+/** The strict programs, one per set of globals, in the order their problems print: the Worker (Workers types), the
+ * browser (DOM), and Node code with Workers types, with DOM types, or with both. A file passes the strict list in any
+ * of them; a config the working tree lacks is skipped. */
+const STRICT_CONFIGS = [
+ "tsconfig.worker.json",
+ "tsconfig.web.json",
+ "tsconfig.node.json",
+ "tsconfig.node-dom.json",
+ "tsconfig.node-all.json",
+] as const; // a tuple, so STRICT_CONFIGS[0] is a string, not string | undefined
+
+/** The strict configs a message names: the first always, then each other one `root` has, as "a", "a or b", or
+ * "a, b or c" (with `and` for "and"). */
function strictNames(root: string, and = false): { names: string; count: number } {
- const present = STRICT_CONFIGS.filter((config) => config === STRICT_CONFIG || existsSync(path.join(root, config)));
- const last = present.at(-1) ?? STRICT_CONFIG;
- const names = present.length > 1 ? `${present.slice(0, -1).join(", ")} ${and ? "and" : "or"} ${last}` : STRICT_CONFIG;
+ const [first] = STRICT_CONFIGS;
+ const present = STRICT_CONFIGS.filter((config) => config === first || existsSync(path.join(root, config)));
+ const last = present.at(-1) ?? first;
+ const names = present.length > 1 ? `${present.slice(0, -1).join(", ")} ${and ? "and" : "or"} ${last}` : first;
return { names, count: present.length };
}
@@ -86,12 +83,6 @@ const STRIPPED: Record] = {
".tsx": ".jsx",
};
-/** TypeScript files that the strict programs leave out, each with the program that checks it instead. */
-const STRICT_EXCLUSIONS: Record = {
- "cloudflare.config.ts": "tsconfig.node.json",
- "types/browser.d.ts": "tsconfig.web.json",
-};
-
/** Changed files that don't ship to the Worker or the pages, each with the reason printed when one is allowed. */
const UNSHIPPED: [RegExp, string][] = [
[/^(?!public\/).*\.md$/, "documentation"],
@@ -376,13 +367,6 @@ async function strictListProblems(
bases: ReadonlyMap> = new Map(),
): Promise {
const typescript = files.filter((file) => /\.(?:ts|mts|cts|tsx)$/.test(file)).sort();
- const programs = new Map>();
- for (const file of typescript) {
- const program = STRICT_EXCLUSIONS[file];
- if (program !== undefined && !programs.has(program) && existsSync(path.join(root, program))) {
- programs.set(program, programFiles(root, program));
- }
- }
const runs = STRICT_CONFIGS.map((config) => {
const has = existsSync(path.join(root, config));
const program = has ? programFiles(root, config) : Promise.resolve({ files: new Set(), errors: [] });
@@ -400,15 +384,7 @@ async function strictListProblems(
for (const file of listed) checked.add(file);
}
const lists = strictNames(root).names;
- for (const file of typescript) {
- if (checked.has(file)) continue;
- const program = STRICT_EXCLUSIONS[file];
- const other = program === undefined ? undefined : programs.get(program);
- if (program === undefined) problems.push(`${file} is not in ${lists}`);
- else if (other === undefined || !(await other).files.has(file)) {
- problems.push(`${file} is left out of ${STRICT_CONFIG} for ${program}, which does not list it`);
- }
- }
+ for (const file of typescript) if (!checked.has(file)) problems.push(`${file} is not in ${lists}`);
return problems;
}
diff --git a/scripts/port-rename.ts b/scripts/port-rename.ts
index a063371..b561313 100644
--- a/scripts/port-rename.ts
+++ b/scripts/port-rename.ts
@@ -132,7 +132,7 @@ function main(): number {
console.log(`updated ${file}${imports > 0 ? ` (${imports} import${imports === 1 ? "" : "s"})` : ""}`);
}
console.log(
- `Next: annotate the .ts files, add them to "files" in tsconfig.strict.json (Worker, Node) or tsconfig.strict-web.json (browser), run node scripts/port-check.ts --base origin/main`,
+ `Next: annotate the .ts files, add any outside server/ and src/ to "files" in tsconfig.node.json, tsconfig.node-dom.json or tsconfig.node-all.json, run node scripts/port-check.ts --base origin/main`,
);
return 0;
}
diff --git a/tests/atlas.test.ts b/tests/atlas.test.ts
index ec2516c..2fbc051 100644
--- a/tests/atlas.test.ts
+++ b/tests/atlas.test.ts
@@ -1,6 +1,6 @@
// Lane D: the browser atlas packer (src/served/atlas.ts) against the server's upload limits and validation
// (server/uploads.ts). Its own file because it imports both a Worker module and a DOM module
-// (tsconfig.strict-tests-shared.json).
+// (tsconfig.node-all.json).
// Run with: node --import ./tests/register.ts --test tests/atlas.test.ts
import test from "node:test";
import assert from "node:assert/strict";
diff --git a/tests/cosmetics.test.ts b/tests/cosmetics.test.ts
index 2c02b0c..7466e65 100644
--- a/tests/cosmetics.test.ts
+++ b/tests/cosmetics.test.ts
@@ -1,5 +1,5 @@
// Cosmetic ids shared by the Worker (server/cosmetics.ts) and the overlay drawings (src/served/cosmetics.ts). Its own
-// file because it imports both a Worker module and a DOM module (tsconfig.strict-tests-shared.json).
+// file because it imports both a Worker module and a DOM module (tsconfig.node-all.json).
import test from "node:test";
import assert from "node:assert/strict";
diff --git a/tests/dev-ui.ts b/tests/dev-ui.ts
index 9cab340..12f0d28 100644
--- a/tests/dev-ui.ts
+++ b/tests/dev-ui.ts
@@ -366,7 +366,7 @@ for (const size of sizes) {
await page.waitForFunction(() => document.querySelector("#editor")!.value.includes("overlay"));
await page.click("#save-file");
await page.waitForFunction(() =>
- // !: the element is on the page, so its textContent is a string
+ // !: #code-status is on the page, and an element's textContent is a string, never null
/Saved to live-fix\/overlay-text/.test(document.querySelector("#code-status")!.textContent!),
);
await page.click("#deploy-test");
diff --git a/tests/port/port-check.test.ts b/tests/port/port-check.test.ts
index 116419c..a8ef07a 100644
--- a/tests/port/port-check.test.ts
+++ b/tests/port/port-check.test.ts
@@ -107,7 +107,7 @@ async function repo(files: Fixture, dir?: string): Promise {
return dir;
}
-/** The options port-check requires tsconfig.strict.json to set (STRICT_ON in scripts/port-check.ts). */
+/** The options port-check requires every strict config to set (STRICT_ON in scripts/port-check.ts). */
const STRICT_OPTIONS = {
strict: true,
noUncheckedIndexedAccess: true,
@@ -116,7 +116,7 @@ const STRICT_OPTIONS = {
erasableSyntaxOnly: true,
};
-/** A tsconfig.strict.json with the required options plus `options`, any other top-level keys in `more`, then `files`
+/** A strict config with the required options plus `options`, any other top-level keys in `more`, then `files`
* (left out when null), as JSONC with a comment and a trailing comma. */
function strictConfig({
files = [],
@@ -164,8 +164,8 @@ async function buildRepo(files: Record, head
"vite.config.js": `import { cloudflare } from "${PLUGIN}";\nexport default { plugins: [cloudflare()] };\n`,
"cloudflare.config.ts": cloudflareConfig(),
".gitignore": "node_modules/\n.cloudflare/\n.wrangler/\n.port-check/\n",
- "tsconfig.strict.json": strictList(),
- "tsconfig.node.json": '{ "include": ["vite.config.js", "cloudflare.config.ts"] }\n',
+ "tsconfig.worker.json": strictList(),
+ "tsconfig.node.json": strictList("cloudflare.config.ts"),
"index.html": PAGE,
"src/main.js": 'console.log("page");\n',
"server/worker.js": 'export default { fetch() { return new Response("ok"); } };\n',
@@ -298,7 +298,7 @@ describe("port-check", { concurrency: true }, () => {
});
test("annotations, comments and type-only code strip to the same JavaScript", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("pair.ts", "sum.ts"),
+ "tsconfig.worker.json": strictList("pair.ts", "sum.ts"),
"pair.ts": "export type Pair = [number, number];\n",
"sum.ts": "// Adds two numbers.\nconst ZERO = 0;\nexport function sum(a, b) {\n return a + b + ZERO;\n}\n",
});
@@ -320,7 +320,7 @@ describe("port-check", { concurrency: true }, () => {
test("a script with a hashbang ported from .mjs to .ts is identical: oxc parses the hashbang apart only in .ts", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("tool.ts"),
+ "tsconfig.worker.json": strictList("tool.ts"),
"tool.mjs":
'#!/usr/bin/env node\n// Prints its arguments.\nimport { argv } from "node:process";\nconsole.log(argv);\n',
});
@@ -334,7 +334,7 @@ describe("port-check", { concurrency: true }, () => {
test("an added typeof check is a runtime difference, reported at its source lines", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("num.ts"),
+ "tsconfig.worker.json": strictList("num.ts"),
"num.js": "/**\n * @param {unknown} v\n */\nexport const toInt = (v) => (Number.isInteger(v) ? v : 0);\n",
});
renameSync(path.join(dir, "num.js"), path.join(dir, "num.ts"));
@@ -357,7 +357,7 @@ describe("port-check", { concurrency: true }, () => {
test("a renamed file whose importers switch from .js to .ts specifiers is identical", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("lib/util.ts", "main.ts"),
+ "tsconfig.worker.json": strictList("lib/util.ts", "main.ts"),
"lib/util.js": "export function double(n) {\n return n * 2;\n}\n",
"main.js": 'import { double } from "./lib/util.js";\nexport const four = double(2);\n',
});
@@ -373,7 +373,7 @@ describe("port-check", { concurrency: true }, () => {
test("files moved to another folder pair by name, with their importers' paths followed", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("src/served/overlay.ts"),
+ "tsconfig.worker.json": strictList("src/served/overlay.ts"),
"web/chat.js": "export const say = (text) => text.trim();\n",
"web/overlay.js":
'import { say } from "./chat.js";\nimport { clamp } from "../server/game.js";\nexport const hello = say(" hi ") + clamp(1);\n',
@@ -394,7 +394,7 @@ describe("port-check", { concurrency: true }, () => {
test("a moved file that git sees as a deletion plus an addition is still compared", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("lib/rank.ts"),
+ "tsconfig.worker.json": strictList("lib/rank.ts"),
"server/rank.js": "export const START = 1000;\nexport const next = (elo) => elo + 16;\n",
});
moveOut(dir, "server/rank.js");
@@ -422,7 +422,7 @@ describe("port-check", { concurrency: true }, () => {
test("a code file gone at head with nothing to pair fails, naming it", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList(),
+ "tsconfig.worker.json": strictList(),
"gone.js": "export const gone = true;\n",
"kept.js": "export const kept = true;\n",
});
@@ -436,7 +436,7 @@ describe("port-check", { concurrency: true }, () => {
});
test("a new file passes only when it strips to no runtime code", async () => {
- const dir = await repo({ "tsconfig.strict.json": strictList("server/model.ts", "server/extra.ts") });
+ const dir = await repo({ "tsconfig.worker.json": strictList("server/model.ts", "server/extra.ts") });
write(dir, {
"server/model.ts": "export type Fighter = { id: string; elo: number };\n",
"server/extra.ts": "export type Id = string;\nexport const id = (value: string): Id => value;\n",
@@ -450,7 +450,7 @@ describe("port-check", { concurrency: true }, () => {
test("two files that could pair by the same name fail instead of guessing", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("c/x.ts"),
+ "tsconfig.worker.json": strictList("c/x.ts"),
"a/x.js": "export const x = 1;\n",
"b/x.js": "export const x = 2;\n",
});
@@ -467,7 +467,7 @@ describe("port-check", { concurrency: true }, () => {
test("edited .js, .mjs and .cjs files are compared", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList(),
+ "tsconfig.worker.json": strictList(),
"app.js": 'import { LIMIT } from "./config.js";\nexport const cap = LIMIT * 2;\n',
"config.js": "export const LIMIT = 10;\n",
"legacy.cjs": "module.exports = { retries: 3 };\n",
@@ -499,7 +499,7 @@ describe("port-check", { concurrency: true }, () => {
test(".mts, .cts and .tsx ports are compared and must be in the strict list", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("util.mts", "old.cts"),
+ "tsconfig.worker.json": strictList("util.mts", "old.cts"),
"util.mjs": "export const half = (n) => n / 2;\n",
"old.cjs": "const x = 1;\nmodule.exports = { x };\n",
"view.jsx": "export const View = () => hi ;\n",
@@ -514,14 +514,14 @@ describe("port-check", { concurrency: true }, () => {
});
assert.deepEqual(await portCheck(dir), {
status: 1,
- stdout: "view.tsx is not in tsconfig.strict.json\n3 files compared, 0 different, 1 other problems\n",
+ stdout: "view.tsx is not in tsconfig.worker.json\n3 files compared, 0 different, 1 other problems\n",
stderr: "",
});
});
test("an import switched from .mjs to a different .js module is a difference", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("main.ts"),
+ "tsconfig.worker.json": strictList("main.ts"),
"b.mjs": "export const b = 1;\n",
"b.js": "export const b = 2;\n",
"main.js": 'import { b } from "./b.mjs";\nexport const value = b;\n',
@@ -543,7 +543,7 @@ describe("port-check", { concurrency: true }, () => {
test("bundler annotation comments are compared, not stripped", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("pure.ts", "lazy.ts"),
+ "tsconfig.worker.json": strictList("pure.ts", "lazy.ts"),
"pure.js": "export const store = /*#__PURE__*/ makeStore();\n",
"lazy.js": "export const mod = (url) => import(/* @vite-ignore */ url);\n",
});
@@ -571,7 +571,7 @@ describe("port-check", { concurrency: true }, () => {
test("a relative import of a file that is not at head fails, naming the importer, line and path", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("u.ts", "n.ts"),
+ "tsconfig.worker.json": strictList("u.ts", "n.ts"),
"u.js": "export const half = (n) => n / 2;\n",
"m.js":
'import { half } from "./u.js";\nexport const one = half(2);\nexport const lazy = () => import(`./u.js`);\n',
@@ -600,7 +600,7 @@ describe("port-check", { concurrency: true }, () => {
test("changed, new and gone files that ship fail, naming each", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList(),
+ "tsconfig.worker.json": strictList(),
"index.html": '\n\n\n',
"src/main.js": "export const main = 1;\n",
"data.json": '{ "cap": 50 }\n',
@@ -633,7 +633,7 @@ describe("port-check", { concurrency: true }, () => {
test("files that don't ship are allowed, and shipped text whose only change is a renamed path passes", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("src/main.ts", "web/overlay.ts"),
+ "tsconfig.worker.json": strictList("src/main.ts", "web/overlay.ts"),
"src/main.js": "export const main = 1;\n",
"web/overlay.js": "export const overlay = 1;\n",
"index.html": '\n\n\n',
@@ -650,7 +650,7 @@ describe("port-check", { concurrency: true }, () => {
"package.json": '{ "scripts": { "main": "node src/main.ts" } }\n',
"docs/notes.md": "Start in src/main.ts, the entry point.\n",
".coderabbit.yaml": "reviews: { profile: chill }\n",
- "tsconfig.strict.json": strictList("src/main.ts", "web/overlay.ts", "types/extra.d.ts"),
+ "tsconfig.worker.json": strictList("src/main.ts", "web/overlay.ts", "types/extra.d.ts"),
"types/extra.d.ts": "export type Extra = string;\n",
});
assert.deepEqual(await portCheck(dir), {
@@ -660,7 +660,7 @@ describe("port-check", { concurrency: true }, () => {
"allowed: docs/notes.md (documentation, does not ship)",
"allowed: index.html (only renamed paths changed)",
"allowed: package.json (only renamed paths changed)",
- "allowed: tsconfig.strict.json (no build config reads it)",
+ "allowed: tsconfig.worker.json (no build config reads it)",
"allowed: web/overlay.html (only renamed paths changed)",
"6 files compared, 0 different",
"",
@@ -671,7 +671,7 @@ describe("port-check", { concurrency: true }, () => {
test("a re-export of inline types only fails, and oxlint fails the import form", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("x.ts", "m.ts"),
+ "tsconfig.worker.json": strictList("x.ts", "m.ts"),
"x.js": "export const X = 1;\n",
"m.js": "export const m = 1;\n",
});
@@ -702,7 +702,7 @@ describe("port-check", { concurrency: true }, () => {
});
test("a port left with types only says the head has no runtime code", async () => {
- const dir = await repo({ "tsconfig.strict.json": strictList("k.ts"), "k.js": "export const K = 1;\n" });
+ const dir = await repo({ "tsconfig.worker.json": strictList("k.ts"), "k.js": "export const K = 1;\n" });
await git(dir, "mv", "k.js", "k.ts");
write(dir, { "k.ts": "export type K = number;\n" });
assert.deepEqual(await portCheck(dir), {
@@ -721,16 +721,16 @@ describe("port-check", { concurrency: true }, () => {
test("without a build config, a tsconfig change is allowed but for the strict options, and a tsconfig under public/ compares byte for byte", async () => {
const dir = await repo({
"tsconfig.base.json": `${JSON.stringify({ compilerOptions: { target: "esnext", ...STRICT_OPTIONS } })}\n`,
- "tsconfig.strict.json":
+ "tsconfig.worker.json":
'// Strict.\n{ "extends": "./tsconfig.base.json", "compilerOptions": { "strict": true }, "files": [] }\n',
- "tsconfig.web.json": '{ "extends": "./tsconfig.base.json", "include": ["src/**/*.js"] }\n',
+ "tsconfig.app.json": '{ "extends": "./tsconfig.base.json", "include": ["src/**/*.js"] }\n',
"public/tsconfig.json": '{ "compilerOptions": {} }\n',
});
write(dir, {
- "tsconfig.json": '{ "files": [], "references": [{ "path": "./tsconfig.web.json" }] }\n',
- "tsconfig.strict.json":
+ "tsconfig.json": '{ "files": [], "references": [{ "path": "./tsconfig.app.json" }] }\n',
+ "tsconfig.worker.json":
'{\n "extends": "./tsconfig.base.json",\n "compilerOptions": { "strict": true, "useDefineForClassFields": false },\n "files": [],\n}\n',
- "tsconfig.web.json":
+ "tsconfig.app.json":
'// Browser code.\n{ "extends": "./tsconfig.base.json", "include": ["src/**/*.js", "public/*.js"], "exclude": ["dist"] }\n',
"public/tsconfig.json": '{ "compilerOptions": { "strict": true } }\n',
});
@@ -740,10 +740,10 @@ describe("port-check", { concurrency: true }, () => {
"public/tsconfig.json differs (line 1; public/ is served as written)",
' base: { "compilerOptions": {} }',
' head: { "compilerOptions": { "strict": true } }',
+ "allowed: tsconfig.app.json (no build config reads it)",
"allowed: tsconfig.json (no build config reads it)",
- "allowed: tsconfig.strict.json (no build config reads it)",
- "allowed: tsconfig.web.json (no build config reads it)",
- "tsconfig.strict.json changes useDefineForClassFields from the base (base not set, head false); a port changes only its files list",
+ "allowed: tsconfig.worker.json (no build config reads it)",
+ "tsconfig.worker.json changes useDefineForClassFields from the base (base not set, head false); a port changes only its files list",
"1 files compared, 1 different, 1 other problems",
"",
].join("\n"),
@@ -752,16 +752,16 @@ describe("port-check", { concurrency: true }, () => {
});
test("with a build config, a changed tsconfig is left to the build diff, and a new root tsconfig.json fails", async () => {
- const dir = await buildRepo({ "tsconfig.web.json": '{ "include": ["src/**/*.js"] }\n' });
+ const dir = await buildRepo({ "tsconfig.app.json": '{ "include": ["src/**/*.js"] }\n' });
write(dir, {
- "tsconfig.json": '{ "files": [], "references": [{ "path": "./tsconfig.web.json" }] }\n',
- "tsconfig.web.json": '// Browser code.\n{ "include": ["src/**/*.js"] }\n',
+ "tsconfig.json": '{ "files": [], "references": [{ "path": "./tsconfig.app.json" }] }\n',
+ "tsconfig.app.json": '// Browser code.\n{ "include": ["src/**/*.js"] }\n',
});
assert.deepEqual(await portCheck(dir), {
status: 1,
stdout: [
+ "allowed: tsconfig.app.json (the build diff compares what the build makes with it)",
"tsconfig.json is new at the repo root, where the base build would read it too, so the build diff cannot see what it changes; add it in a change of its own",
- "allowed: tsconfig.web.json (the build diff compares what the build makes with it)",
"1 files compared, 1 different; 8 build output files compared, 0 different",
"",
].join("\n"),
@@ -807,13 +807,13 @@ describe("port-check", { concurrency: true }, () => {
"server/worker.js":
'import { Thing } from "./thing.ts";\nexport default { fetch() { return new Response(String(new Thing(1).size)); } };\n',
"server/tsconfig.json": '{ "include": ["*.ts"] }\n',
- "tsconfig.strict.json": strictList("server/thing.ts"),
+ "tsconfig.worker.json": strictList("server/thing.ts"),
});
assert.deepEqual(await portCheck(dir), {
status: 1,
stdout: [
"allowed: server/tsconfig.json (the build diff compares what the build makes with it)",
- "allowed: tsconfig.strict.json (the build diff compares what the build makes with it)",
+ "allowed: tsconfig.worker.json (the build diff compares what the build makes with it)",
".cloudflare/output/v0/workers/default/bundle/index.js differs (line 2)",
" base: globalThis.sideLoaded = true;",
" head: var Thing = class {",
@@ -830,12 +830,12 @@ describe("port-check", { concurrency: true }, () => {
write(dir, {
"server/worker.ts": 'export default { fetch(): Response { return new Response("ok"); } };\n',
"cloudflare.config.ts": cloudflareConfig("./server/worker.ts"),
- "tsconfig.strict.json": strictList("server/worker.ts"),
+ "tsconfig.worker.json": strictList("server/worker.ts"),
});
assert.deepEqual(await portCheck(dir), {
status: 0,
stdout: [
- "allowed: tsconfig.strict.json (the build diff compares what the build makes with it)",
+ "allowed: tsconfig.worker.json (the build diff compares what the build makes with it)",
"2 files compared, 0 different; 8 build output files compared, 0 different",
"",
].join("\n"),
@@ -849,7 +849,7 @@ describe("port-check", { concurrency: true }, () => {
write(dir, {
"server/worker.ts": 'export default { fetch(): Response { return new Response("ok"); } };\n',
"server/tsconfig.json": '{ "extends": "./missing.json" }\n',
- "tsconfig.strict.json": strictList("server/worker.ts"),
+ "tsconfig.worker.json": strictList("server/worker.ts"),
});
const { status, stdout, stderr } = await portCheck(dir);
const lines = stdout.split("\n");
@@ -861,7 +861,7 @@ describe("port-check", { concurrency: true }, () => {
stderr: "",
first: [
"allowed: server/tsconfig.json (the build diff compares what the build makes with it)",
- "allowed: tsconfig.strict.json (the build diff compares what the build makes with it)",
+ "allowed: tsconfig.worker.json (the build diff compares what the build makes with it)",
"the head build failed (bunx cf build):",
],
last: ["1 files compared, 0 different; the build failed, 1 other problems", ""],
@@ -900,7 +900,7 @@ describe("port-check", { concurrency: true }, () => {
"server/worker.ts": 'export default { fetch(): Response { return new Response("ok"); } };\n',
"server/tsconfig.json": '{ "extends": "./missing.json" }\n',
"cloudflare.config.ts": cloudflareConfig("./server/worker.ts"),
- "tsconfig.strict.json": strictList("server/worker.ts"),
+ "tsconfig.worker.json": strictList("server/worker.ts"),
});
write(dir, { "server/tsconfig.json": "{}\n" });
const sha = (await git(dir, "rev-parse", "main")).trim();
@@ -922,7 +922,7 @@ describe("port-check", { concurrency: true }, () => {
});
test("a committed .port-check/ fails, since no check compares what is in it", async () => {
- const dir = await repo({ "tsconfig.strict.json": strictList() });
+ const dir = await repo({ "tsconfig.worker.json": strictList() });
write(dir, {
".port-check/0123abc/server/worker.js": "export default {};\n",
".port-check/0123abc/index.html": PAGE,
@@ -941,7 +941,7 @@ describe("port-check", { concurrency: true }, () => {
});
test("a file committed at exactly .port-check fails", async () => {
- const dir = await repo({ "tsconfig.strict.json": strictList() });
+ const dir = await repo({ "tsconfig.worker.json": strictList() });
write(dir, { ".port-check": "not a folder\n" });
await git(dir, "add", "-f", "--", ".port-check");
await git(dir, "commit", "-q", "-m", "cache file");
@@ -957,7 +957,7 @@ describe("port-check", { concurrency: true }, () => {
});
test("a symlink committed at exactly .port-check fails", async () => {
- const dir = await repo({ "tsconfig.strict.json": strictList() });
+ const dir = await repo({ "tsconfig.worker.json": strictList() });
// A symlink entry needs no symlink support on disk: the index takes it as is. Its target is a blob, written from a
// file next to the repo so the working tree stays clean.
writeFileSync(`${dir}-link`, "elsewhere");
@@ -976,7 +976,7 @@ describe("port-check", { concurrency: true }, () => {
});
test("a folder named .port-check with a Kelvin sign for its k is checked like any other: only ASCII letters fold", async () => {
- const dir = await repo({ "tsconfig.strict.json": strictList() });
+ const dir = await repo({ "tsconfig.worker.json": strictList() });
const file = `.port-chec${String.fromCodePoint(0x212a)}/evil.js`;
write(dir, { [file]: 'globalThis.evil = "ships";\n' });
await git(dir, "add", "-A");
@@ -1118,7 +1118,7 @@ describe("port-check", { concurrency: true }, () => {
test("text whose bytes change but decode the same fails instead of passing as a renamed path, and so does a BOM", async () => {
const latin1 = (text: string) => Buffer.from(text, "latin1");
const dir = await repo({
- "tsconfig.strict.json": strictList("src/main.ts"),
+ "tsconfig.worker.json": strictList("src/main.ts"),
"src/main.js": "export const main = 1;\n",
"index.html": latin1('\ncaf\xe9
\n'),
"notes.txt": latin1("caf\xe9\n"),
@@ -1148,7 +1148,7 @@ describe("port-check", { concurrency: true }, () => {
test("a Markdown file under public/ ships, so a change to it fails", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList(),
+ "tsconfig.worker.json": strictList(),
"public/notes.md": "Duel rules.\n",
"docs/notes.md": "Docs.\n",
});
@@ -1220,7 +1220,7 @@ describe("port-check", { concurrency: true }, () => {
test("a renamed path next to invalid UTF-8 at head, where the base was valid, fails", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("src/main.ts"),
+ "tsconfig.worker.json": strictList("src/main.ts"),
"src/main.js": "export const main = 1;\n",
"index.html": pageWith("/src/main.js", REPLACEMENT),
});
@@ -1235,7 +1235,7 @@ describe("port-check", { concurrency: true }, () => {
test("a renamed path next to valid UTF-8 at head, where the base was invalid, fails", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("src/main.ts"),
+ "tsconfig.worker.json": strictList("src/main.ts"),
"src/main.js": "export const main = 1;\n",
"index.html": pageWith("/src/main.js", INVALID),
});
@@ -1297,7 +1297,7 @@ describe("port-check", { concurrency: true }, () => {
test("a file under public/ compares byte for byte: a comment edit, a new comment-only module and a renamed path fail", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList(),
+ "tsconfig.worker.json": strictList(),
"src/main.js": "export const main = 1;\n",
"public/overlay.js": "// The overlay.\nexport const overlay = 1;\n",
"public/_headers": "# Mirrors src/main.js.\n/*\n X-Frame-Options: DENY\n",
@@ -1308,7 +1308,7 @@ describe("port-check", { concurrency: true }, () => {
"public/overlay.js": "// The OBS overlay.\nexport const overlay = 1;\n",
"public/x.js": "// Reserved for the next duel effect.\n",
"public/_headers": "# Mirrors src/main.ts.\n/*\n X-Frame-Options: DENY\n",
- "tsconfig.strict.json": strictList("src/main.ts"),
+ "tsconfig.worker.json": strictList("src/main.ts"),
});
assert.deepEqual(await portCheck(dir), {
status: 1,
@@ -1320,7 +1320,7 @@ describe("port-check", { concurrency: true }, () => {
" base: // The overlay.",
" head: // The OBS overlay.",
"public/x.js is new and ships",
- "allowed: tsconfig.strict.json (no build config reads it)",
+ "allowed: tsconfig.worker.json (no build config reads it)",
"4 files compared, 3 different",
"",
].join("\n"),
@@ -1330,7 +1330,7 @@ describe("port-check", { concurrency: true }, () => {
test("a test or script may update a string naming a ported file, and any other string change fails", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList(),
+ "tsconfig.worker.json": strictList(),
"src/ui.js": "export const ui = 1;\n",
"src/files.js": 'export const FILES = ["src/ui.js"];\n',
"tests/ui.test.mjs":
@@ -1341,11 +1341,11 @@ describe("port-check", { concurrency: true }, () => {
"src/ui.ts": "export const ui: number = 1;\n",
"tests/ui.test.mjs":
'import { readFileSync } from "node:fs";\nconst text = readFileSync("src/ui.ts", "utf8");\nif (!text.includes("ui")) throw new Error("ui");\n',
- "tsconfig.strict.json": strictList("src/ui.ts"),
+ "tsconfig.worker.json": strictList("src/ui.ts"),
});
assert.deepEqual(await portCheck(dir), {
status: 0,
- stdout: "allowed: tsconfig.strict.json (no build config reads it)\n2 files compared, 0 different\n",
+ stdout: "allowed: tsconfig.worker.json (no build config reads it)\n2 files compared, 0 different\n",
stderr: "",
});
write(dir, {
@@ -1362,7 +1362,7 @@ describe("port-check", { concurrency: true }, () => {
"tests/ui.test.mjs differs (base line 2, head line 2)",
' base: const text = readFileSync("src/ui.js", "utf8");',
' head: const text = readFileSync("src/ui.js", "latin1");',
- "allowed: tsconfig.strict.json (no build config reads it)",
+ "allowed: tsconfig.worker.json (no build config reads it)",
"3 files compared, 2 different",
"",
].join("\n"),
@@ -1372,7 +1372,7 @@ describe("port-check", { concurrency: true }, () => {
test("a test string that named the .ts path before the port passes unchanged", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList(),
+ "tsconfig.worker.json": strictList(),
"src/ui.js": "export const ui = 1;\n",
"tests/paths.test.mjs":
'import { ui } from "../src/ui.js";\nconst SOURCES = ["src/ui.ts", "src/ui.js"];\nif (SOURCES.length !== ui + 1) throw new Error("paths");\n',
@@ -1382,11 +1382,11 @@ describe("port-check", { concurrency: true }, () => {
"src/ui.ts": "export const ui: number = 1;\n",
"tests/paths.test.mjs":
'import { ui } from "../src/ui.ts";\nconst SOURCES = ["src/ui.ts", "src/ui.ts"];\nif (SOURCES.length !== ui + 1) throw new Error("paths");\n',
- "tsconfig.strict.json": strictList("src/ui.ts"),
+ "tsconfig.worker.json": strictList("src/ui.ts"),
});
assert.deepEqual(await portCheck(dir), {
status: 0,
- stdout: "allowed: tsconfig.strict.json (no build config reads it)\n2 files compared, 0 different\n",
+ stdout: "allowed: tsconfig.worker.json (no build config reads it)\n2 files compared, 0 different\n",
stderr: "",
});
write(dir, {
@@ -1399,7 +1399,7 @@ describe("port-check", { concurrency: true }, () => {
"tests/paths.test.mjs differs (base line 2, head line 2)",
' base: const SOURCES = ["src/ui.js", "src/ui.js"];',
' head: const SOURCES = ["src/ui.js", "src/ui.mjs"];',
- "allowed: tsconfig.strict.json (no build config reads it)",
+ "allowed: tsconfig.worker.json (no build config reads it)",
"2 files compared, 1 different",
"",
].join("\n"),
@@ -1409,7 +1409,7 @@ describe("port-check", { concurrency: true }, () => {
test("a code file under public/ fails when renamed, moved in or out, or turned into TypeScript", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList(),
+ "tsconfig.worker.json": strictList(),
"public/hats.js": "export const HATS = [];\n",
"public/fx.js": "export const fx = 1;\n",
"public/overlay.js":
@@ -1424,7 +1424,7 @@ describe("port-check", { concurrency: true }, () => {
"public/hats.ts": "export const HATS: string[] = [];\n",
"public/overlay.js":
'import { HATS } from "./hats.ts";\nimport { fx } from "../src/served/fx.js";\nexport const n = HATS.length + fx;\n',
- "tsconfig.strict.json": strictList("public/hats.ts"),
+ "tsconfig.worker.json": strictList("public/hats.ts"),
});
assert.deepEqual(await portCheck(dir), {
status: 1,
@@ -1435,7 +1435,7 @@ describe("port-check", { concurrency: true }, () => {
' base: import { HATS } from "./hats.js";',
' head: import { HATS } from "./hats.ts";',
"public/fx.js -> src/served/fx.js changes a path under public/, which serves code as written",
- "allowed: tsconfig.strict.json (no build config reads it)",
+ "allowed: tsconfig.worker.json (no build config reads it)",
"public/hats.ts is TypeScript under public/, which serves code as written",
"1 files compared, 1 different, 4 other problems",
"",
@@ -1445,7 +1445,7 @@ describe("port-check", { concurrency: true }, () => {
});
test("a --base that names no commit is bad usage, reported in one line", async () => {
- const dir = await repo({ "tsconfig.strict.json": strictList() });
+ const dir = await repo({ "tsconfig.worker.json": strictList() });
assert.deepEqual(await node(dir, SCRIPT, "--base", "no-such-ref"), {
status: 2,
stdout: "",
@@ -1463,7 +1463,7 @@ describe("port-check", { concurrency: true }, () => {
const csp = (src: string) =>
` Content-Security-Policy: default-src 'self'; ${"img-src 'self' data: https://static-cdn.jtvnw.net; ".repeat(3)}connect-src 'self' ${src}\n`;
const dir = await repo({
- "tsconfig.strict.json": strictList(),
+ "tsconfig.worker.json": strictList(),
"public/_headers": `/*\n${csp("wss://a.example")}`,
});
write(dir, { "public/_headers": `/*\n${csp("wss://b.example")}` });
@@ -1482,8 +1482,7 @@ describe("port-check", { concurrency: true }, () => {
test("--strict-list fails each TypeScript file no program checks", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("a.ts"),
- "tsconfig.node.json": '{ "include": ["vite.config.js"] }\n',
+ "tsconfig.worker.json": strictList("a.ts"),
"a.ts": "export const a = 1;\n",
"cloudflare.config.ts": "export default {};\n",
"lib/x.mts": "export const x = 1;\n",
@@ -1492,9 +1491,9 @@ describe("port-check", { concurrency: true }, () => {
assert.deepEqual(await node(dir, SCRIPT, "--strict-list"), {
status: 1,
stdout: [
- "cloudflare.config.ts is left out of tsconfig.strict.json for tsconfig.node.json, which does not list it",
- "lib/x.mts is not in tsconfig.strict.json",
- "server/foo.ts is not in tsconfig.strict.json",
+ "cloudflare.config.ts is not in tsconfig.worker.json",
+ "lib/x.mts is not in tsconfig.worker.json",
+ "server/foo.ts is not in tsconfig.worker.json",
"",
].join("\n"),
stderr: "",
@@ -1503,80 +1502,82 @@ describe("port-check", { concurrency: true }, () => {
test("--strict-list reads the program from tsc, so exclude takes a file out and a glob include puts one in", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictConfig({ files: null, include: ["**/*.ts"], exclude: ["server/rank.ts"] }),
+ "tsconfig.worker.json": strictConfig({ files: null, include: ["**/*.ts"], exclude: ["server/rank.ts"] }),
"a.ts": "export const a = 1;\n",
"server/rank.ts": "export const rank = 1;\n",
});
assert.deepEqual(await node(dir, SCRIPT, "--strict-list"), {
status: 1,
- stdout: "server/rank.ts is not in tsconfig.strict.json\n",
+ stdout: "server/rank.ts is not in tsconfig.worker.json\n",
stderr: "",
});
- write(dir, { "tsconfig.strict.json": strictConfig({ files: null, include: ["**/*.ts"] }) });
+ write(dir, { "tsconfig.worker.json": strictConfig({ files: null, include: ["**/*.ts"] }) });
assert.deepEqual(await node(dir, SCRIPT, "--strict-list"), {
status: 0,
- stdout: "tsconfig.strict.json covers every TypeScript file\n",
+ stdout: "tsconfig.worker.json covers every TypeScript file\n",
stderr: "",
});
});
- test("--strict-list passes a TypeScript file listed only in tsconfig.strict-web.json, and names both lists for one in neither", async () => {
+ test("--strict-list passes a TypeScript file listed only in tsconfig.web.json, and names both lists for one in neither", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("a.ts"),
- "tsconfig.strict-web.json": strictList("src/view.ts"),
+ "tsconfig.worker.json": strictList("a.ts"),
+ "tsconfig.web.json": strictList("src/view.ts"),
"a.ts": "export const a = 1;\n",
"src/view.ts": "export const view = 1;\n",
});
assert.deepEqual(await node(dir, SCRIPT, "--strict-list"), {
status: 0,
- stdout: "tsconfig.strict.json and tsconfig.strict-web.json cover every TypeScript file\n",
+ stdout: "tsconfig.worker.json and tsconfig.web.json cover every TypeScript file\n",
stderr: "",
});
write(dir, { "src/other.ts": "export const other = 1;\n" });
assert.deepEqual(await node(dir, SCRIPT, "--strict-list"), {
status: 1,
- stdout: "src/other.ts is not in tsconfig.strict.json or tsconfig.strict-web.json\n",
+ stdout: "src/other.ts is not in tsconfig.worker.json or tsconfig.web.json\n",
stderr: "",
});
});
- test("--strict-list passes a test file listed only in tsconfig.strict-tests.json, and names every list for one in none", async () => {
+ test("--strict-list passes a test file listed only in tsconfig.node-dom.json, and names every list for one in none", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("a.ts"),
- "tsconfig.strict-tests.json": strictList("tests/view.test.ts"),
+ "tsconfig.worker.json": strictList("a.ts"),
+ "tsconfig.node-dom.json": strictList("tests/view.test.ts"),
"a.ts": "export const a = 1;\n",
"tests/view.test.ts": "export const view = 1;\n",
});
assert.deepEqual(await node(dir, SCRIPT, "--strict-list"), {
status: 0,
- stdout: "tsconfig.strict.json and tsconfig.strict-tests.json cover every TypeScript file\n",
+ stdout: "tsconfig.worker.json and tsconfig.node-dom.json cover every TypeScript file\n",
stderr: "",
});
write(dir, {
- "tsconfig.strict-web.json": strictList("src/view.ts"),
- "tsconfig.strict-tests-shared.json": strictList("tests/both.test.ts"),
+ "tsconfig.web.json": strictList("src/view.ts"),
+ "tsconfig.node.json": strictList("scripts/tool.ts"),
+ "tsconfig.node-all.json": strictList("tests/both.test.ts"),
"src/view.ts": "export const view = 1;\n",
+ "scripts/tool.ts": "export const tool = 1;\n",
"tests/both.test.ts": "export const both = 1;\n",
});
assert.deepEqual(await node(dir, SCRIPT, "--strict-list"), {
status: 0,
stdout:
- "tsconfig.strict.json, tsconfig.strict-web.json, tsconfig.strict-tests.json and tsconfig.strict-tests-shared.json cover every TypeScript file\n",
+ "tsconfig.worker.json, tsconfig.web.json, tsconfig.node.json, tsconfig.node-dom.json and tsconfig.node-all.json cover every TypeScript file\n",
stderr: "",
});
write(dir, { "tests/other.test.ts": "export const other = 1;\n" });
assert.deepEqual(await node(dir, SCRIPT, "--strict-list"), {
status: 1,
stdout:
- "tests/other.test.ts is not in tsconfig.strict.json, tsconfig.strict-web.json, tsconfig.strict-tests.json or tsconfig.strict-tests-shared.json\n",
+ "tests/other.test.ts is not in tsconfig.worker.json, tsconfig.web.json, tsconfig.node.json, tsconfig.node-dom.json or tsconfig.node-all.json\n",
stderr: "",
});
});
- test("--strict-list holds tsconfig.strict-web.json to the strict options and reads its files' comments once", async () => {
+ test("--strict-list holds tsconfig.web.json to the strict options and reads its files' comments once", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("a.ts", "shared.ts"),
- "tsconfig.strict-web.json": strictConfig({
+ "tsconfig.worker.json": strictList("a.ts", "shared.ts"),
+ "tsconfig.web.json": strictConfig({
files: ["shared.ts", "src/view.ts"],
options: { exactOptionalPropertyTypes: false },
}),
@@ -1587,36 +1588,32 @@ describe("port-check", { concurrency: true }, () => {
assert.deepEqual(await node(dir, SCRIPT, "--strict-list"), {
status: 1,
stdout: [
- "shared.ts:1 has @ts-nocheck, which turns type checking off; files on tsconfig.strict.json are checked whole",
- "tsconfig.strict-web.json must set exactOptionalPropertyTypes to true (it is false)",
- "src/view.ts:1 has @ts-nocheck, which turns type checking off; files on tsconfig.strict-web.json are checked whole",
+ "shared.ts:1 has @ts-nocheck, which turns type checking off; files on tsconfig.worker.json are checked whole",
+ "tsconfig.web.json must set exactOptionalPropertyTypes to true (it is false)",
+ "src/view.ts:1 has @ts-nocheck, which turns type checking off; files on tsconfig.web.json are checked whole",
"",
].join("\n"),
stderr: "",
});
});
- test("a port changes only tsconfig.strict-web.json's files list, and keeps the file once the base has it", async () => {
+ test("a port changes only tsconfig.web.json's files list, and keeps the file once the base has it", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList(),
- "tsconfig.strict-web.json": strictList("src/a.ts"),
+ "tsconfig.worker.json": strictList(),
+ "tsconfig.web.json": strictList("src/a.ts"),
"src/a.ts": "export const a = 1;\n",
});
write(dir, {
- "tsconfig.strict-web.json": strictList("src/a.ts", "src/b.ts"),
+ "tsconfig.web.json": strictList("src/a.ts", "src/b.ts"),
"src/b.ts": "export type B = string;\n",
});
assert.deepEqual(await portCheck(dir), {
status: 0,
- stdout: [
- "allowed: tsconfig.strict-web.json (no build config reads it)",
- "1 files compared, 0 different",
- "",
- ].join("\n"),
+ stdout: ["allowed: tsconfig.web.json (no build config reads it)", "1 files compared, 0 different", ""].join("\n"),
stderr: "",
});
write(dir, {
- "tsconfig.strict-web.json": strictConfig({
+ "tsconfig.web.json": strictConfig({
files: ["src/a.ts", "src/b.ts"],
options: { useDefineForClassFields: false },
}),
@@ -1624,21 +1621,21 @@ describe("port-check", { concurrency: true }, () => {
assert.deepEqual(await portCheck(dir), {
status: 1,
stdout: [
- "allowed: tsconfig.strict-web.json (no build config reads it)",
- "tsconfig.strict-web.json changes useDefineForClassFields from the base (base not set, head false); a port changes only its files list",
+ "allowed: tsconfig.web.json (no build config reads it)",
+ "tsconfig.web.json changes useDefineForClassFields from the base (base not set, head false); a port changes only its files list",
"1 files compared, 0 different, 1 other problems",
"",
].join("\n"),
stderr: "",
});
- moveOut(dir, "tsconfig.strict-web.json");
+ moveOut(dir, "tsconfig.web.json");
assert.deepEqual(await portCheck(dir), {
status: 1,
stdout: [
- "allowed: tsconfig.strict-web.json (no build config reads it)",
- "tsconfig.strict-web.json is gone at head; the base has it, so a port keeps it",
- "src/a.ts is not in tsconfig.strict.json",
- "src/b.ts is not in tsconfig.strict.json",
+ "allowed: tsconfig.web.json (no build config reads it)",
+ "tsconfig.web.json is gone at head; the base has it, so a port keeps it",
+ "src/a.ts is not in tsconfig.worker.json",
+ "src/b.ts is not in tsconfig.worker.json",
"1 files compared, 0 different, 3 other problems",
"",
].join("\n"),
@@ -1661,14 +1658,14 @@ describe("port-check", { concurrency: true }, () => {
},
];
for (const { options, line } of loose) {
- test(`--strict-list fails a tsconfig.strict.json that ${line.replace(/ \(.*|, which.*/, "")}`, async () => {
+ test(`--strict-list fails a tsconfig.worker.json that ${line.replace(/ \(.*|, which.*/, "")}`, async () => {
const dir = await repo({
- "tsconfig.strict.json": strictConfig({ files: ["a.ts"], options }),
+ "tsconfig.worker.json": strictConfig({ files: ["a.ts"], options }),
"a.ts": "export const a = 1;\n",
});
assert.deepEqual(await node(dir, SCRIPT, "--strict-list"), {
status: 1,
- stdout: `tsconfig.strict.json ${line}\n`,
+ stdout: `tsconfig.worker.json ${line}\n`,
stderr: "",
});
});
@@ -1677,15 +1674,15 @@ describe("port-check", { concurrency: true }, () => {
test("--strict-list reads options through extends, and fails a declaration file skipLibCheck would skip", async () => {
const dir = await repo({
"tsconfig.base.json": '{ "compilerOptions": { "strictBindCallApply": false, "skipLibCheck": true } }\n',
- "tsconfig.strict.json": strictConfig({ extends: "./tsconfig.base.json", files: ["a.ts", "types/x.d.ts"] }),
+ "tsconfig.worker.json": strictConfig({ extends: "./tsconfig.base.json", files: ["a.ts", "types/x.d.ts"] }),
"a.ts": "export const a = 1;\n",
"types/x.d.ts": "export type X = string;\n",
});
assert.deepEqual(await node(dir, SCRIPT, "--strict-list"), {
status: 1,
stdout: [
- "tsconfig.strict.json sets strictBindCallApply to false, which checks less",
- "types/x.d.ts is a declaration file, which skipLibCheck leaves unchecked in tsconfig.strict.json; name it .ts",
+ "tsconfig.worker.json sets strictBindCallApply to false, which checks less",
+ "types/x.d.ts is a declaration file, which skipLibCheck leaves unchecked in tsconfig.worker.json; name it .ts",
"",
].join("\n"),
stderr: "",
@@ -1694,12 +1691,12 @@ describe("port-check", { concurrency: true }, () => {
test("--strict-list fails on each error tsc prints reading the strict list", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictConfig({ files: ["a.ts", "gone.ts"] }),
+ "tsconfig.worker.json": strictConfig({ files: ["a.ts", "gone.ts"] }),
"a.ts": "export const a = 1;\n",
});
const { status, stdout, stderr } = await node(dir, SCRIPT, "--strict-list");
assert.deepEqual({ status, stderr }, { status: 1, stderr: "" });
- assert.match(stdout, /^tsc -p tsconfig\.strict\.json: error TS6053: File '[^']*\/gone\.ts' not found\.\n$/);
+ assert.match(stdout, /^tsc -p tsconfig.worker.json: error TS6053: File '[^']*\/gone\.ts' not found\.\n$/);
});
// Every option port-check requires on (STRICT_ON) and every `no*` option that turns checking off (NO_TURNS_OFF),
@@ -1719,19 +1716,19 @@ describe("port-check", { concurrency: true }, () => {
...Object.keys(STRICT_OPTIONS).map((name) => ({
name,
value: false,
- lines: [`tsconfig.strict.json must set ${name} to true (it is false)`],
+ lines: [`tsconfig.worker.json must set ${name} to true (it is false)`],
})),
...NO_TURNS_OFF.map((name) => ({
name,
value: true,
// tsc 7 dropped noStrictGenericChecks: it reads the option as unknown, and that error refuses the list instead.
- lines: [`tsconfig.strict.json sets ${name} to true, which checks less`, `Unknown compiler option '${name}'.`],
+ lines: [`tsconfig.worker.json sets ${name} to true, which checks less`, `Unknown compiler option '${name}'.`],
})),
];
for (const { name, value, lines } of turnedOff) {
- test(`--strict-list fails a tsconfig.strict.json with ${name} set to ${value}`, async () => {
+ test(`--strict-list fails a tsconfig.worker.json with ${name} set to ${value}`, async () => {
const dir = await repo({
- "tsconfig.strict.json": strictConfig({ files: ["a.ts"], options: { [name]: value } }),
+ "tsconfig.worker.json": strictConfig({ files: ["a.ts"], options: { [name]: value } }),
"a.ts": "export const a = 1;\n",
});
const { status, stdout, stderr } = await node(dir, SCRIPT, "--strict-list");
@@ -1746,7 +1743,7 @@ describe("port-check", { concurrency: true }, () => {
test("--strict-list fails .d.mts and .d.cts files, which skipLibCheck would skip as it does .d.ts", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictConfig({
+ "tsconfig.worker.json": strictConfig({
files: ["a.ts", "types/x.d.mts", "types/y.d.cts"],
options: { skipLibCheck: true },
}),
@@ -1757,17 +1754,17 @@ describe("port-check", { concurrency: true }, () => {
assert.deepEqual(await node(dir, SCRIPT, "--strict-list"), {
status: 1,
stdout: [
- "types/x.d.mts is a declaration file, which skipLibCheck leaves unchecked in tsconfig.strict.json; name it .ts",
- "types/y.d.cts is a declaration file, which skipLibCheck leaves unchecked in tsconfig.strict.json; name it .ts",
+ "types/x.d.mts is a declaration file, which skipLibCheck leaves unchecked in tsconfig.worker.json; name it .ts",
+ "types/y.d.cts is a declaration file, which skipLibCheck leaves unchecked in tsconfig.worker.json; name it .ts",
"",
].join("\n"),
stderr: "",
});
});
- const nocheckWhy = "which turns type checking off; files on tsconfig.strict.json are checked whole";
+ const nocheckWhy = "which turns type checking off; files on tsconfig.worker.json are checked whole";
const lintWhy =
- "which can turn off any lint rule, ban-ts-comment included; files on tsconfig.strict.json take no lint directives";
+ "which can turn off any lint rule, ban-ts-comment included; files on tsconfig.worker.json take no lint directives";
const offSwitches = [
{ text: "/// @ts-nocheck\nexport const a = 1;\n", lines: [`a.ts:1 has @ts-nocheck, ${nocheckWhy}`] },
{ text: "// @TS-NOCHECK\nexport const a = 1;\n", lines: [`a.ts:1 has @TS-NOCHECK, ${nocheckWhy}`] },
@@ -1798,7 +1795,7 @@ describe("port-check", { concurrency: true }, () => {
];
for (const { text, lines } of offSwitches) {
test(`--strict-list fails a strict-list file with ${JSON.stringify(text.split("\n")[0])}`, async () => {
- const dir = await repo({ "tsconfig.strict.json": strictList("a.ts"), "a.ts": text });
+ const dir = await repo({ "tsconfig.worker.json": strictList("a.ts"), "a.ts": text });
assert.deepEqual(await node(dir, SCRIPT, "--strict-list"), {
status: 1,
stdout: [...lines, ""].join("\n"),
@@ -1809,7 +1806,7 @@ describe("port-check", { concurrency: true }, () => {
test("--strict-list reads comments in every file on the list, JavaScript too, and only comments", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictConfig({
+ "tsconfig.worker.json": strictConfig({
files: ["a.ts", "site.config.js"],
options: { allowJs: true, noEmit: true },
}),
@@ -1824,27 +1821,27 @@ describe("port-check", { concurrency: true }, () => {
write(dir, { "site.config.js": "// The site config.\nexport default {};\n" });
assert.deepEqual(await node(dir, SCRIPT, "--strict-list"), {
status: 0,
- stdout: "tsconfig.strict.json covers every TypeScript file\n",
+ stdout: "tsconfig.worker.json covers every TypeScript file\n",
stderr: "",
});
});
const changedOption = (name: string, base: string, head: string) =>
- `tsconfig.strict.json changes ${name} from the base (base ${base}, head ${head}); a port changes only its files list`;
+ `tsconfig.worker.json changes ${name} from the base (base ${base}, head ${head}); a port changes only its files list`;
/** The strict list below, extending tsconfig.base.json, with `options` added. */
const strictOn = (options: Record = {}, files: string[] = ["a.ts"]) =>
strictConfig({ extends: "./tsconfig.base.json", files, options });
const optionChanges = [
{
what: "adds paths",
- head: { "tsconfig.strict.json": strictOn({ paths: { "#x/*": ["./x/*"] } }) },
- allowed: ["tsconfig.strict.json"],
+ head: { "tsconfig.worker.json": strictOn({ paths: { "#x/*": ["./x/*"] } }) },
+ allowed: ["tsconfig.worker.json"],
line: changedOption("paths", "not set", '{"#x/*":["./x/*"]}'),
},
{
what: "adds types",
- head: { "tsconfig.strict.json": strictOn({ types: [] }) },
- allowed: ["tsconfig.strict.json"],
+ head: { "tsconfig.worker.json": strictOn({ types: [] }) },
+ allowed: ["tsconfig.worker.json"],
line: changedOption("types", "not set", "[]"),
},
{
@@ -1855,10 +1852,10 @@ describe("port-check", { concurrency: true }, () => {
},
];
for (const { what, head, allowed, line } of optionChanges) {
- test(`once the base has tsconfig.strict.json, a head that ${what} fails`, async () => {
+ test(`once the base has tsconfig.worker.json, a head that ${what} fails`, async () => {
const dir = await repo({
"tsconfig.base.json": '{ "compilerOptions": { "lib": ["esnext"] } }\n',
- "tsconfig.strict.json": strictOn(),
+ "tsconfig.worker.json": strictOn(),
"a.ts": "export const a = 1;\n",
});
write(dir, head);
@@ -1875,16 +1872,16 @@ describe("port-check", { concurrency: true }, () => {
});
}
- test("once the base has tsconfig.strict.json, a head that only adds a file to it passes", async () => {
+ test("once the base has tsconfig.worker.json, a head that only adds a file to it passes", async () => {
const dir = await repo({
"tsconfig.base.json": '{ "compilerOptions": { "lib": ["esnext"] } }\n',
- "tsconfig.strict.json": strictOn(),
+ "tsconfig.worker.json": strictOn(),
"a.ts": "export const a = 1;\n",
});
- write(dir, { "tsconfig.strict.json": strictOn({}, ["a.ts", "b.ts"]), "b.ts": "export type B = string;\n" });
+ write(dir, { "tsconfig.worker.json": strictOn({}, ["a.ts", "b.ts"]), "b.ts": "export type B = string;\n" });
assert.deepEqual(await portCheck(dir), {
status: 0,
- stdout: "allowed: tsconfig.strict.json (no build config reads it)\n1 files compared, 0 different\n",
+ stdout: "allowed: tsconfig.worker.json (no build config reads it)\n1 files compared, 0 different\n",
stderr: "",
});
});
@@ -1999,7 +1996,7 @@ describe("port-rename", () => {
"server/rank.js -> server/rank.ts",
"updated docs/notes.md",
"updated server/main.js (1 import)",
- 'Next: annotate the .ts files, add them to "files" in tsconfig.strict.json (Worker, Node) or tsconfig.strict-web.json (browser), run node scripts/port-check.ts --base origin/main',
+ 'Next: annotate the .ts files, add any outside server/ and src/ to "files" in tsconfig.node.json, tsconfig.node-dom.json or tsconfig.node-all.json, run node scripts/port-check.ts --base origin/main',
"",
].join("\n"),
stderr: "",
@@ -2026,7 +2023,7 @@ describe("port-rename", () => {
"updated server/d.tsx (1 import)",
"updated server/e.cts (1 import)",
"updated types/rank.d.ts (1 import)",
- 'Next: annotate the .ts files, add them to "files" in tsconfig.strict.json (Worker, Node) or tsconfig.strict-web.json (browser), run node scripts/port-check.ts --base origin/main',
+ 'Next: annotate the .ts files, add any outside server/ and src/ to "files" in tsconfig.node.json, tsconfig.node-dom.json or tsconfig.node-all.json, run node scripts/port-check.ts --base origin/main',
"",
].join("\n"),
stderr: "",
@@ -2035,7 +2032,7 @@ describe("port-rename", () => {
test("follows template-literal and query-string imports, and port-check reads them back as the base paths", async () => {
const dir = await repo({
- "tsconfig.strict.json": strictList("u.ts"),
+ "tsconfig.worker.json": strictList("u.ts"),
"u.js": "export const u = 1;\n",
"m.js":
'export const a = () => import(`./u.js`);\nexport const b = () => import("./u.js?v=1#top");\nexport const c = (x) => import(`./${x}.js`);\n',
@@ -2045,7 +2042,7 @@ describe("port-rename", () => {
stdout: [
"u.js -> u.ts",
"updated m.js (2 imports)",
- 'Next: annotate the .ts files, add them to "files" in tsconfig.strict.json (Worker, Node) or tsconfig.strict-web.json (browser), run node scripts/port-check.ts --base origin/main',
+ 'Next: annotate the .ts files, add any outside server/ and src/ to "files" in tsconfig.node.json, tsconfig.node-dom.json or tsconfig.node-all.json, run node scripts/port-check.ts --base origin/main',
"",
].join("\n"),
stderr: "",
@@ -2084,7 +2081,7 @@ describe("port-rename", () => {
"note: public/overlay.html:1 names a renamed file; left as is, since public/ is served as written",
"note: public/overlay.js:1 names a renamed file; left as is, since public/ is served as written",
"note: public/overlay.js:2 names a renamed file; left as is, since public/ is served as written",
- 'Next: annotate the .ts files, add them to "files" in tsconfig.strict.json (Worker, Node) or tsconfig.strict-web.json (browser), run node scripts/port-check.ts --base origin/main',
+ 'Next: annotate the .ts files, add any outside server/ and src/ to "files" in tsconfig.node.json, tsconfig.node-dom.json or tsconfig.node-all.json, run node scripts/port-check.ts --base origin/main',
"",
].join("\n"),
stderr: "",
diff --git a/tsconfig.base.json b/tsconfig.base.json
index b64ce7d..14001e0 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -1,9 +1,11 @@
{
"compilerOptions": {
+ // site.config.js is the one JavaScript file in any program; its own `// @ts-check` has tsc check it.
"allowJs": true,
- "checkJs": true,
"noEmit": true,
- "strict": false,
+ "strict": true,
+ "noUncheckedIndexedAccess": true,
+ "exactOptionalPropertyTypes": true,
"target": "esnext",
"module": "esnext",
"moduleDetection": "force",
diff --git a/tsconfig.json b/tsconfig.json
index 79bd0dd..314bbca 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,18 +1,14 @@
-// Type checking (`bun run typecheck`): one loose project per runtime for the JavaScript, because the Worker, the
-// browser and Node each have their own globals, and four strict ones for the TypeScript files, split by the globals
-// their files need: tsconfig.strict.json (Worker, scripts, shared, the build config, and the unit tests of Worker and
-// shared modules), tsconfig.strict-web.json (browser, DOM types), tsconfig.strict-tests.json (unit tests of DOM modules
-// and Playwright scripts: DOM and Node) and tsconfig.strict-tests-shared.json (tests that import both: Worker, DOM and
-// Node). Nothing is emitted.
+// Type checking (`bun run typecheck`): five strict programs, split by the globals their files run with, because the
+// Worker, the browser and Node each have their own and some of them clash (the Workers types declare `Buffer` as
+// `any`, and they and the DOM type streams, crypto and canvas contexts differently). Nothing is emitted.
+// scripts/port-check.ts --strict-list fails a TypeScript file that none of them checks.
{
"files": [],
"references": [
{ "path": "./tsconfig.worker.json" },
{ "path": "./tsconfig.web.json" },
{ "path": "./tsconfig.node.json" },
- { "path": "./tsconfig.strict.json" },
- { "path": "./tsconfig.strict-web.json" },
- { "path": "./tsconfig.strict-tests.json" },
- { "path": "./tsconfig.strict-tests-shared.json" }
+ { "path": "./tsconfig.node-dom.json" },
+ { "path": "./tsconfig.node-all.json" }
]
}
diff --git a/tsconfig.node-all.json b/tsconfig.node-all.json
new file mode 100644
index 0000000..7c02281
--- /dev/null
+++ b/tsconfig.node-all.json
@@ -0,0 +1,21 @@
+// Tests that need Workers and DOM types at once: unit tests that import a Worker module and a DOM module, and browser
+// tests that import a Worker module. Workers, DOM and Node types. One entry per file; keep a test on one side where
+// you can, since neither side's globals are kept out here.
+{
+ "extends": "./tsconfig.base.json",
+ "compilerOptions": { "lib": ["esnext", "dom", "dom.iterable"], "types": ["@cloudflare/workers-types", "node"] },
+ "files": [
+ "types/lib-guards.ts",
+ "types/site.ts",
+ "site.config.js",
+ "types/dom.ts",
+ "tests/arena-client.test.ts",
+ "tests/atlas.test.ts",
+ "tests/cosmetics.test.ts",
+ "tests/spritify.test.ts",
+ "tests/e2e-local.ts",
+ "tests/smoke.ts",
+ "tests/ui.ts",
+ "tests/arena-browser.ts"
+ ]
+}
diff --git a/tsconfig.node-dom.json b/tsconfig.node-dom.json
new file mode 100644
index 0000000..af33234
--- /dev/null
+++ b/tsconfig.node-dom.json
@@ -0,0 +1,22 @@
+// Node code that needs DOM types but imports no Worker module: unit tests of DOM modules, and Playwright tests and
+// scripts whose page callbacks run in the browser. The character build lives here too: the Workers types declare
+// `Buffer` as `any`, which hides its methods. DOM and Node types. One entry per file.
+{
+ "extends": "./tsconfig.base.json",
+ "compilerOptions": { "lib": ["esnext", "dom", "dom.iterable"], "types": ["node"] },
+ "files": [
+ "types/lib-guards.ts",
+ "types/site.ts",
+ "site.config.js",
+ "types/dom.ts",
+ "tests/browser-parse.test.ts",
+ "tests/overlay.test.ts",
+ "tests/served.test.ts",
+ "tests/dev-ui.ts",
+ "scripts/og-image.ts",
+ "scripts/lib/zip-read.ts",
+ "scripts/lib/png-io.ts",
+ "scripts/build-characters.ts",
+ "scripts/live-chat-e2e.ts"
+ ]
+}
diff --git a/tsconfig.node.json b/tsconfig.node.json
index 8d3cc9d..94416bf 100644
--- a/tsconfig.node.json
+++ b/tsconfig.node.json
@@ -1,7 +1,48 @@
-// Node build configs, checked with Node types. They, the scripts and all tests are TypeScript in the strict configs
-// too (tsconfig.strict.json, tsconfig.strict-tests.json and tsconfig.strict-tests-shared.json).
+// Node code that runs Worker code or uses only Node and Workers globals: the scripts that need no DOM or Buffer
+// methods, the build configs, the Node-only test runners, and the unit tests that import only Worker and shared modules
+// (with their helpers). Workers and Node types, no DOM. One entry per file.
{
"extends": "./tsconfig.base.json",
- "compilerOptions": { "lib": ["esnext"], "types": ["node"] },
- "include": ["vite.config.ts", "cloudflare.config.ts", "types/lib-guards.ts"]
+ "compilerOptions": { "lib": ["esnext"], "types": ["@cloudflare/workers-types", "node"] },
+ "files": [
+ "types/lib-guards.ts",
+ "types/site.ts",
+ "site.config.js",
+ "scripts/lib/port.ts",
+ "scripts/port-check.ts",
+ "scripts/port-rename.ts",
+ "scripts/lib/served.ts",
+ "tests/fakes.ts",
+ "tests/register.ts",
+ "tests/cloudflare-test-loader.ts",
+ "tests/csp-helper.ts",
+ "tests/upload-helpers.ts",
+ "tests/auth.test.ts",
+ "tests/channel-param.test.ts",
+ "tests/channel.test.ts",
+ "tests/content.test.ts",
+ "tests/dedupe.test.ts",
+ "tests/dev-api.test.ts",
+ "tests/dev-release.test.ts",
+ "tests/game.test.ts",
+ "tests/hardening.test.ts",
+ "tests/hosts.test.ts",
+ "tests/registry.test.ts",
+ "tests/security.test.ts",
+ "tests/site-config.test.ts",
+ "tests/upload.test.ts",
+ "tests/worker.test.ts",
+ "tests/parse.test.ts",
+ "vite.config.ts",
+ "scripts/install-hooks.ts",
+ "scripts/release.ts",
+ "scripts/devtools.ts",
+ "scripts/test-all.ts",
+ "tests/chrome.ts",
+ "tests/seed-local.ts",
+ "tests/build-versions.ts",
+ "tests/upload-workerd.ts",
+ "tests/port/port-check.test.ts",
+ "cloudflare.config.ts"
+ ]
}
diff --git a/tsconfig.strict-tests-shared.json b/tsconfig.strict-tests-shared.json
deleted file mode 100644
index cd20951..0000000
--- a/tsconfig.strict-tests-shared.json
+++ /dev/null
@@ -1,27 +0,0 @@
-// Strict TypeScript for tests that need both Worker and DOM types: unit tests that import a Worker module and a DOM
-// module, and browser tests that import a Worker module (server/security.ts, server/game.ts, upload helpers).
-{
- "extends": "./tsconfig.base.json",
- "compilerOptions": {
- "lib": ["esnext", "dom", "dom.iterable"],
- "types": ["@cloudflare/workers-types", "node"],
- "checkJs": false,
- "strict": true,
- "noUncheckedIndexedAccess": true,
- "exactOptionalPropertyTypes": true
- },
- "files": [
- "types/lib-guards.ts",
- "types/site.ts",
- "site.config.js",
- "types/dom.ts",
- "tests/arena-client.test.ts",
- "tests/atlas.test.ts",
- "tests/cosmetics.test.ts",
- "tests/spritify.test.ts",
- "tests/e2e-local.ts",
- "tests/smoke.ts",
- "tests/ui.ts",
- "tests/arena-browser.ts"
- ]
-}
diff --git a/tsconfig.strict-tests.json b/tsconfig.strict-tests.json
deleted file mode 100644
index 0c61168..0000000
--- a/tsconfig.strict-tests.json
+++ /dev/null
@@ -1,29 +0,0 @@
-// Strict TypeScript for Node code that needs DOM types but imports no Worker module: unit tests of a DOM module
-// (src/served/overlay.ts), and Playwright tests and scripts whose page callbacks run in the browser. Node-only scripts
-// that use Buffer's methods (the character build) live here too: the Worker types in tsconfig.strict.json hide them.
-{
- "extends": "./tsconfig.base.json",
- "compilerOptions": {
- "lib": ["esnext", "dom", "dom.iterable"],
- "types": ["node"],
- "checkJs": false,
- "strict": true,
- "noUncheckedIndexedAccess": true,
- "exactOptionalPropertyTypes": true
- },
- "files": [
- "types/lib-guards.ts",
- "types/site.ts",
- "site.config.js",
- "types/dom.ts",
- "tests/browser-parse.test.ts",
- "tests/overlay.test.ts",
- "tests/served.test.ts",
- "tests/dev-ui.ts",
- "scripts/og-image.ts",
- "scripts/lib/zip-read.ts",
- "scripts/lib/png-io.ts",
- "scripts/build-characters.ts",
- "scripts/live-chat-e2e.ts"
- ]
-}
diff --git a/tsconfig.strict-web.json b/tsconfig.strict-web.json
deleted file mode 100644
index bd59f3b..0000000
--- a/tsconfig.strict-web.json
+++ /dev/null
@@ -1,49 +0,0 @@
-// Strict TypeScript for browser code (src/ and types/dom.ts): DOM types, no Worker or Node types.
-// Every ported browser .ts file is listed here, one entry per file; Worker, script and shared files go in
-// tsconfig.strict.json. scripts/port-check.ts fails a branch that changes a .ts file missing from both lists.
-{
- "extends": "./tsconfig.base.json",
- "compilerOptions": {
- "lib": ["esnext", "dom", "dom.iterable"],
- "types": ["vite/client"],
- "checkJs": false,
- "strict": true,
- "noUncheckedIndexedAccess": true,
- "exactOptionalPropertyTypes": true
- },
- "files": [
- "types/lib-guards.ts",
- "types/site.ts",
- "site.config.js",
- "types/dom.ts",
- "src/channel-param.ts",
- "src/character-groups.ts",
- "src/setup.ts",
- "src/scrub.ts",
- "src/intro/back.ts",
- "src/intro/sound.ts",
- "src/ui.ts",
- "src/parse.ts",
- "src/start.ts",
- "src/sprite-maker.ts",
- "src/spritify.ts",
- "src/intro/bevel.ts",
- "src/intro/voxels.ts",
- "src/intro/world.ts",
- "src/fighter3d.ts",
- "src/voxthumb.ts",
- "src/intro/main.ts",
- "src/served/hats.ts",
- "src/served/atlas.ts",
- "src/served/parse.ts",
- "src/served/chat.ts",
- "src/served/arena-client.ts",
- "src/served/pets.ts",
- "src/served/cosmetics.ts",
- "src/served/upload.ts",
- "src/served/overlay.ts",
- "src/dashboard.ts",
- "src/admin.ts",
- "src/dev.ts"
- ]
-}
diff --git a/tsconfig.strict.json b/tsconfig.strict.json
deleted file mode 100644
index 0c3095d..0000000
--- a/tsconfig.strict.json
+++ /dev/null
@@ -1,77 +0,0 @@
-// Strict TypeScript. Every new or ported .ts file is listed here, one entry per file; scripts/port-check.ts fails a
-// branch that changes a .ts file missing from this list.
-{
- "extends": "./tsconfig.base.json",
- "compilerOptions": {
- "lib": ["esnext"],
- "types": ["@cloudflare/workers-types", "node"],
- "checkJs": false,
- "strict": true,
- "noUncheckedIndexedAccess": true,
- "exactOptionalPropertyTypes": true
- },
- "files": [
- "types/lib-guards.ts",
- "types/site.ts",
- "site.config.js",
- "scripts/lib/port.ts",
- "scripts/port-check.ts",
- "scripts/port-rename.ts",
- "scripts/lib/served.ts",
- "server/env.ts",
- "server/model.ts",
- "server/upgrades.ts",
- "server/uploads.ts",
- "server/cosmetics.ts",
- "server/parse.ts",
- "server/botcommands.ts",
- "server/dedupe.ts",
- "server/hosts.ts",
- "server/ranklog.ts",
- "server/ratelimit.ts",
- "server/security.ts",
- "server/pets.ts",
- "server/sprites.ts",
- "server/game.ts",
- "server/streamelements.ts",
- "server/auth.ts",
- "server/channels.ts",
- "server/eventsub.ts",
- "server/backups.ts",
- "server/accounts.ts",
- "server/developer.ts",
- "server/channel.ts",
- "server/worker.ts",
- "tests/fakes.ts",
- "tests/register.ts",
- "tests/cloudflare-test-loader.ts",
- "tests/csp-helper.ts",
- "tests/upload-helpers.ts",
- "tests/auth.test.ts",
- "tests/channel-param.test.ts",
- "tests/channel.test.ts",
- "tests/content.test.ts",
- "tests/dedupe.test.ts",
- "tests/dev-api.test.ts",
- "tests/dev-release.test.ts",
- "tests/game.test.ts",
- "tests/hardening.test.ts",
- "tests/hosts.test.ts",
- "tests/registry.test.ts",
- "tests/security.test.ts",
- "tests/site-config.test.ts",
- "tests/upload.test.ts",
- "tests/worker.test.ts",
- "tests/parse.test.ts",
- "vite.config.ts",
- "scripts/install-hooks.ts",
- "scripts/release.ts",
- "scripts/devtools.ts",
- "scripts/test-all.ts",
- "tests/chrome.ts",
- "tests/seed-local.ts",
- "tests/build-versions.ts",
- "tests/upload-workerd.ts",
- "tests/port/port-check.test.ts"
- ]
-}
diff --git a/tsconfig.web.json b/tsconfig.web.json
index 85253a1..8b4ca50 100644
--- a/tsconfig.web.json
+++ b/tsconfig.web.json
@@ -1,6 +1,8 @@
-// Browser code: the pages (src/) and the overlay and other modules served at fixed URLs (src/served/).
+// Browser code: the pages (src/) and the overlay and other modules served at fixed URLs (src/served/). DOM types and
+// vite/client, no Worker or Node types. A server module a page imports is checked here too, so it must type-check with
+// DOM types as well.
{
"extends": "./tsconfig.base.json",
"compilerOptions": { "lib": ["esnext", "dom", "dom.iterable"], "types": ["vite/client"] },
- "include": ["src/**/*.js", "types/browser.d.ts", "types/lib-guards.ts"]
+ "include": ["src/**/*.ts", "types/lib-guards.ts", "types/site.ts", "types/dom.ts", "site.config.js"]
}
diff --git a/tsconfig.worker.json b/tsconfig.worker.json
index 52b2169..f627054 100644
--- a/tsconfig.worker.json
+++ b/tsconfig.worker.json
@@ -1,6 +1,7 @@
-// The Cloudflare Worker and its Durable Objects (server/).
+// The Cloudflare Worker and its Durable Objects (server/): Workers types only, so server code can't use Node or DOM
+// globals.
{
"extends": "./tsconfig.base.json",
"compilerOptions": { "lib": ["esnext"], "types": ["@cloudflare/workers-types"] },
- "include": ["server/**/*.ts", "site.config.js", "types/lib-guards.ts"]
+ "include": ["server/**/*.ts", "types/lib-guards.ts", "types/site.ts", "site.config.js"]
}
diff --git a/types/browser.d.ts b/types/browser.d.ts
deleted file mode 100644
index aecc2a3..0000000
--- a/types/browser.d.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-// Type checking only (tsconfig.web.json): what lib.dom leaves out or types more narrowly than the pages use it.
-export {};
-
-declare global {
- interface ParentNode {
- // The pages look elements up by selector and use them as the element they know it is (an input's value, a
- // canvas's context), so selector lookups are untyped instead of plain Element.
- querySelector(selectors: string): any;
- querySelectorAll(selectors: string): NodeListOf;
- }
- interface Window {
- __arenaMove?: (userId: string, x: number) => void; // overlay ?debug=1 hooks (src/served/overlay.ts)
- __arenaDebug?: () => unknown;
- __intro?: any; // home page test hooks (src/intro/main.ts)
- webkitAudioContext?: typeof AudioContext; // older Safari
- }
- interface Navigator {
- connection?: { saveData?: boolean; effectiveType?: string }; // Network Information API, Chromium only
- }
-}
diff --git a/types/dom.ts b/types/dom.ts
index 76e231d..0773fe9 100644
--- a/types/dom.ts
+++ b/types/dom.ts
@@ -1,6 +1,5 @@
-// Browser globals for the strict browser program (tsconfig.strict-web.json) that lib.dom leaves out. The loose web
-// program (tsconfig.web.json) reads types/browser.d.ts instead, which also makes selector lookups untyped; strict
-// files cast each lookup to the element the page holds.
+// Browser globals that lib.dom leaves out, for the browser program (tsconfig.web.json) and the Node programs with DOM
+// types. Selector lookups stay typed as lib.dom has them, so each one is cast to the element the page holds.
export {};
declare global {