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:
1 parent
babc35b72a
commit
64a7f48efa
5 files changed
+193
-3
No files matched your search
@@ -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"
|
||||
]
|
||||
}
|
||||
Generated
+16
-1
@@ -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
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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 {};
|
||||
Reference in new issue
Block a user