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/js": "^10.0.1",
|
||||||
"eslint": "^10.12.0",
|
"eslint": "^10.12.0",
|
||||||
"globals": "^17.13.0",
|
"globals": "^17.13.0",
|
||||||
"puppeteer-core": "^25.12.0"
|
"puppeteer-core": "^25.12.0",
|
||||||
|
"typescript": "^5.9.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
@@ -2334,6 +2335,20 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 18"
|
"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",
|
"setup": "node tools/setup.mjs",
|
||||||
"doctor": "node tools/doctor.mjs",
|
"doctor": "node tools/doctor.mjs",
|
||||||
"launch": "node scripts/launch.mjs",
|
"launch": "node scripts/launch.mjs",
|
||||||
"lint": "eslint ."
|
"lint": "eslint .",
|
||||||
|
"typecheck": "tsc --noEmit --checkJs -p jsconfig.json"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
@@ -52,6 +53,7 @@
|
|||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"eslint": "^10.12.0",
|
"eslint": "^10.12.0",
|
||||||
"globals": "^17.13.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