feedback5 R6: add a small checkJs slice and core typedefs

tsc checks shared (except protocol.js and bandBonds.js), the sim rng/dir/constants helpers, and types/core.js. strict stays off. types/README.md says how to widen the slice.
This commit is contained in:
sganggs committed 2026-10-05 16:18:28 +08:00
1 parent babc35b72a
commit 64a7f48efa
5 files changed
+193 -3

No files matched your search

+29
View File
@@ -0,0 +1,29 @@
{
// First typecheck slice (npm run typecheck). strict stays off until a folder is clean.
// tsc does not load this file unless invoked with -p jsconfig.json.
// Widen one path at a time: see types/README.md.
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"checkJs": true,
"allowJs": true,
"noEmit": true,
"strict": false,
"skipLibCheck": true,
"types": [],
"lib": ["ES2022"],
"maxNodeModuleJsDepth": 0
},
"include": [
"shared/**/*.js",
"server/sim/rng.js",
"server/sim/dir.js",
"server/sim/constants.js",
"types/**/*.js"
],
"exclude": [
"shared/protocol.js",
"shared/bandBonds.js"
]
}
+16 -1
View File
@@ -21,7 +21,8 @@
"@eslint/js": "^10.0.1",
"eslint": "^10.12.0",
"globals": "^17.13.0",
"puppeteer-core": "^25.12.0"
"puppeteer-core": "^25.12.0",
"typescript": "^5.9.2"
},
"engines": {
"node": ">=22"
@@ -2334,6 +2335,20 @@
"engines": {
"node": ">= 18"
}
},
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
}
}
}
+4 -2
View File
@@ -35,7 +35,8 @@
"setup": "node tools/setup.mjs",
"doctor": "node tools/doctor.mjs",
"launch": "node scripts/launch.mjs",
"lint": "eslint ."
"lint": "eslint .",
"typecheck": "tsc --noEmit --checkJs -p jsconfig.json"
},
"engines": {
"node": ">=22"
@@ -52,6 +53,7 @@
"@eslint/js": "^10.0.1",
"eslint": "^10.12.0",
"globals": "^17.13.0",
"puppeteer-core": "^25.12.0"
"puppeteer-core": "^25.12.0",
"typescript": "^5.9.2"
}
}
+25
View File
@@ -0,0 +1,25 @@
# Typecheck
`npm run typecheck` runs `tsc --noEmit --checkJs -p jsconfig.json`.
The first slice is the closed set that already typechecks:
- `shared/` except `shared/protocol.js` and `shared/bandBonds.js` (their JSDoc does not match the code yet; see below)
- `server/sim/rng.js`, `server/sim/dir.js`, `server/sim/constants.js` (the last imports `GEO` from shared)
- `types/` — JSDoc for `Unit`, `DamageInfo`, the snapshot tuples, and the protocol message envelope
`strict` is off. `tsc` does not read `jsconfig.json` on its own; the script passes `-p`.
## Widen it
Add one file or one folder to `jsconfig.json` `include`, then run `npm run typecheck`. Fix JSDoc that disagrees with the code in that folder. Leave `strict` off until the folder reports nothing. Do not add `@ts-nocheck`.
Suggested order once the sim split settles: `server/sim/grid.js`, `server/sim/body.js`, `server/sim/buffs.js`, then `server/sim/damage.js` against the typedefs in `types/core.js`. The sim does not import `types/`. The typedefs are a reference, not a runtime dependency.
`types/core.js` follows docs/DESIGN.md §5.2, §5.4, §8 and docs/SIM.md §4, §9. Where those two disagree on `DamageInfo.type`, the typedef uses the union `makeDamageInfo` actually builds (`'elemental'` as well as `'element'`).
## Not in the first slice
`shared/protocol.js` — the catalogue JSDoc is ahead of a few object literals (`$optional` sits on a `Record` of checkers; `unitStatsEntry` does not list `side` or `silenced`, and the code reads `side`). Fix the comments, then remove it from `exclude`.
`shared/bandBonds.js` — the data-shape JSDoc rejects an empty fallback object and a tuple callback. Same treatment.
+119
View File
@@ -0,0 +1,119 @@
/**
* Core shapes for the sim and the wire protocol.
*
* Taken from docs/DESIGN.md §5.2 (Unit), §5.4 (DamageInfo), §8 (envelope, b.snap)
* and docs/SIM.md §4 (DamageInfo as makeDamageInfo builds it) and §9 (snapshot tuples).
* The sim does not import this file. It is here so the shapes have one JSDoc home
* while server/sim is still being split.
*/
/**
* A unit inside one battle. Minimum fields from DESIGN §5.2.
* Stats (`maxHp`, `atk`, …) are recomputed by the sim and are not all listed here.
*
* @typedef {Object} Unit
* @property {number} id unique per battle
* @property {'ally'|'enemy'} side
* @property {'op'|'token'|'enemy'|'device'} kind
* @property {string} defId
* @property {string|number} ownerId player id; enemies use the field owner or the source player
* @property {number} x
* @property {number} y
* @property {number} [tileR] operators
* @property {number} [tileC] operators
* @property {'UP'|'RIGHT'|'DOWN'|'LEFT'} [dir] allies: deploy direction. Enemies are not meaningful here.
* @property {number} facing horizontal sign, +1 or −1 (LEFT is −1)
* @property {number} hp
* @property {boolean} alive
* @property {number} sp
* @property {Object[]} [buffs]
* @property {number} [statusFlags]
* @property {number[]} [blocking] operators: ids of enemies they block
* @property {number|null} [blockedBy] enemies: blocker id
* @property {number[][]} [liveRangeGrid] the attack range the detail card shows
* @property {string} [form] model form (enemy mode, or a doll's `'doll'`)
*/
/**
* One damage instance, after `makeDamageInfo` (server/sim/damage.js).
* DESIGN §5.4 lists `type` as `'phys'|'arts'|'true'|'element'`.
* SIM §4 and the normaliser also use `'elemental'` (HP damage from an element burst)
* and keep `'element'` for gauge fill, which removes no HP.
*
* @typedef {Object} DamageInfo
* @property {number} amount pre-mitigation
* @property {'phys'|'arts'|'true'|'elemental'|'element'} type
* @property {'burn'|'necrosis'|'neural'|'apoptosis'|string|null} [element]
* @property {number} [atkScale]
* @property {number} [defIgnoreFlat]
* @property {number} [defIgnorePct]
* @property {number} [resIgnoreFlat]
* @property {number} [resIgnorePct]
* @property {number} [mul]
* @property {boolean} [canDodge]
* @property {boolean} [isSkill]
* @property {boolean} [isSplash]
* @property {boolean} [isAttack]
* @property {boolean} [isProjectile]
* @property {string[]} [tags]
* @property {boolean} [cancel] set by a `hit` hook to drop the instance
* @property {boolean} [noSp]
* @property {boolean} [ignoreSleep]
* @property {boolean} [ignoreSelect] reaches an airborne ally; the hit selected nobody
* @property {boolean} [sourceless] 无来源: source stats add nothing
* @property {number} [attackId] shared by every instance of one normal attack; 0 otherwise
* @property {Unit|null} [traitAlly]
*/
/**
* One living unit in a snapshot.
* `[id, x, y, hp, maxHp, sp, spMax, flags, anim]` (SIM §9, DESIGN §8.2).
* `flags` is the UF bitmask. `anim` is the ANIM code.
*
* @typedef {[number, number, number, number, number, number, number, number, number]} UnitSnap
*/
/**
* A knocked-out operator waiting to redeploy.
* `[id, respawnAt, respawnTime, state, row, col]`.
* `state`: 0 counting, 1 timer done and DP short, 2 timer done and the tile is taken.
*
* @typedef {[number, number, number, number, number, number]} DownSnap
*/
/**
* Element gauge or burst cooldown on one unit.
* `[id, element, fill, cooldownEnd, cooldown]`.
*
* @typedef {[number, string, number, number, number]} ElemSnap
*/
/**
* `snapshot()` (SIM §9). On the wire this object is the payload of `b.snap`,
* and `t` is sent as `gt` because the frame's `t` is the message type (DESIGN §8.2).
* `dp` is one number. `down` and `elem` are omitted when empty.
*
* @typedef {Object} FieldSnapshot
* @property {string} fieldId
* @property {number} t game seconds
* @property {UnitSnap[]} units
* @property {number} dp
* @property {number} killed
* @property {number} total
* @property {Object<string, number>} [dps]
* @property {Object} [boss]
* @property {DownSnap[]} [down]
* @property {ElemSnap[]} [elem]
*/
/**
* One WebSocket JSON frame (DESIGN §8). Client requests may carry `rid`.
* The server's `ok` or `error` echoes it. Server pushes omit it.
* Other own fields are the payload. Inbound frames are capped at 64 KB.
*
* @typedef {Object} ProtocolMessage
* @property {string} t message type
* @property {number} [rid] request id
*/
export {};