feedback5 WE2: remove the kits/tier1-6.js re-export shims and shared/standIn.js diyRecord (#5)

Nothing but tests imported them: kits_t3 / kits_alt_t3 / kits_t4 / kits_t5 read
kits/index.js TIER_KITS, playtest5_elements / playtest6-combat / facing the real modules,
simServe checks /sim/content/kits/index.js; test/backups.test.js composes the prototypes
through shared/diy.js diyRecordOf at their locked selection. check:imports passes.
Docs: kits/README.md, DATA.md. Golden: no scenario moved.
This commit is contained in:
sganggs committed 2026-10-06 16:07:49 +08:00
1 parent 19691d0b06
commit 92a179e71e
18 files changed
+33 -81

No files matched your search

+1 -1
View File
@@ -675,7 +675,7 @@ one slot, the picks of a tier differ, no module of another game mode — `isDiyM
"在【沉沦者的黑流树海】中") and the 生息演算 module RA-A (森蚺) are never a player's choice [ASSUMED], the owner's decision of
2026-10-05 for ISW-A and the same reason for SO / RA, while the record and the sim still compose them for the kits' tests). **In battle** a PlayerBattleInput entry of a DIY slot carries `diy` (the pick) and
is fielded as `getChess(slotId, { diy })` (docs/SIM.md §12); its kit is `KITS[charId]` (kits/README.md "How to add an
operator (自选)"). (`shared/standIn.js diyRecord(slot, charId, backups, sel)` is the older prototype-only form.)
operator (自选)").
`diy`:
-1
View File
@@ -16,7 +16,6 @@ operators, the self-select 6★ operators, contributions from GitHub issue #136
| `shared/tier1.js` | the general kit helpers (blackboard readers, unit predicates, hit hooks, area queries, buffs, zones, free tiles, skill records) and the notes of the tier-1 kits |
| `shared/tier2.js` … `tier6.js` | helpers two or more kits of that tier use, and that tier's notes (conventions, simplifications, fx kinds) |
| `shared/summoner.js` | the 召唤师 summon deck the 自选 kits of 麦哲伦 / 令 / 电弧 share (`summonDeck`: the holding, a placed piece's return, recalls, the summons leaving with their owner; `holdBuff`, `tokenStat`) |
| `tier1.js` … `tier6.js` | re-export shims for the old import paths; removed after the 0.2.0 refactor |
`content/index.js` takes `KITS` from `index.js`: a unit's kit is `KITS[def.baseId]` (also the exact or the suffix-less
id), else the generic kit built from the skill blackboard (`content/generic.js`, docs/SIM.md §7.4). A 补位 stand-in's
-8
View File
@@ -1,8 +0,0 @@
// server/sim/content/kits/tier1.js — re-export shim (0.2.0 refactor, R4): the tier-1 kits live one per file in ops/,
// registered by index.js; their shared helpers and notes are in shared/tier1.js (README.md). This module keeps the
// old imports working until the shims are removed after the 0.2.0 refactor wave.
import { TIER_KITS } from './index.js';
export * from './shared/tier1.js';
export { tinmanKit } from './ops/chess_char_1_16-tinman.js';
export default TIER_KITS[0];
-6
View File
@@ -1,6 +0,0 @@
// server/sim/content/kits/tier2.js — re-export shim (0.2.0 refactor, R4): the tier-2 kits live one per file in ops/,
// registered by index.js; their shared helpers and notes are in shared/tier2.js (README.md). This module keeps the
// old imports working until the shims are removed after the 0.2.0 refactor wave.
import { TIER_KITS } from './index.js';
export default TIER_KITS[1];
-6
View File
@@ -1,6 +0,0 @@
// server/sim/content/kits/tier3.js — re-export shim (0.2.0 refactor, R4): the tier-3 kits live one per file in ops/,
// registered by index.js; their shared helpers and notes are in shared/tier3.js (README.md). This module keeps the
// old imports working until the shims are removed after the 0.2.0 refactor wave.
import { TIER_KITS } from './index.js';
export default TIER_KITS[2];
-6
View File
@@ -1,6 +0,0 @@
// server/sim/content/kits/tier4.js — re-export shim (0.2.0 refactor, R4): the tier-4 kits live one per file in ops/,
// registered by index.js; their shared helpers and notes are in shared/tier4.js (README.md). This module keeps the
// old imports working until the shims are removed after the 0.2.0 refactor wave.
import { TIER_KITS } from './index.js';
export default Object.freeze({ ...TIER_KITS[3] });
-6
View File
@@ -1,6 +0,0 @@
// server/sim/content/kits/tier5.js — re-export shim (0.2.0 refactor, R4): the tier-5 kits live one per file in ops/,
// registered by index.js; their shared helpers and notes are in shared/tier5.js (README.md). This module keeps the
// old imports working until the shims are removed after the 0.2.0 refactor wave.
import { TIER_KITS } from './index.js';
export default TIER_KITS[4];
-7
View File
@@ -1,7 +0,0 @@
// server/sim/content/kits/tier6.js — re-export shim (0.2.0 refactor, R4): the tier-6 kits live one per file in ops/,
// registered by index.js; their shared helpers and notes are in shared/tier6.js (README.md). This module keeps the
// old imports working until the shims are removed after the 0.2.0 refactor wave.
import { TIER_KITS } from './index.js';
export { PITHST_ELEMENTS } from './ops/chess_char_1_15-pithst.js';
export default TIER_KITS[5];
+2 -19
View File
@@ -1,5 +1,6 @@
// shared/standIn.js — a chess fielded with another character's body: the 补位 stand-in (原型干员) of a NORMAL chess
// whose operator the player does not own, and a 自选 (DIY) slot filled with a prototype. Pure ESM shared by the build
// whose operator the player does not own, and the composition a 自选 (DIY) slot uses (shared/diy.js diyRecordOf calls
// composeUnitRecord with the pick). Pure ESM shared by the build
// (tools/build-data.mjs proves composeUnitRecord rebuilds every PRESET chess from its own unit form), the simulation and
// the client. Data: data/backups.json (docs/DATA.md §18).
//
@@ -130,21 +131,3 @@ export function standInRecord(chess, backups) {
return composeUnitRecord(chess, unit, unitForm(backups, b.charId, chess.status),
{ skillIndex: b.skillIndex, moduleId: b.uniEquipId ?? null, standInFor: chess.charId });
}
/**
* A 自选 slot (DIY chess record, normal or elite) filled with a prototype `charId` (backups.diy.prototypes[tier]):
* the slot's identity (tier, price, no 特质) with the pick's derived bonds (backups.diy.operators[charId].bonds). The
* skill and module are the caller's — which skill a prototype carries in a slot is not in the data (DESIGN 0.2.0
* draft, open question). Null when the pick is not a legal prototype of the slot's tier or the data lacks it.
* @param {object} slot a DIY chess record (data/chess.json, `isDiy`)
* @param {string} charId the picked prototype
* @param {object} backups data/backups.json
* @param {{ skillIndex?: number, moduleId?: string|null }} [opts]
* @returns {object|null}
*/
export function diyRecord(slot, charId, backups, { skillIndex, moduleId = null } = {}) {
if (!slot?.isDiy || !(backups?.diy?.prototypes?.[slot.tier] || []).includes(charId)) return null;
const unit = backups.units?.[charId] ?? null;
return composeUnitRecord(slot, unit, unitForm(backups, charId, slot.status),
{ skillIndex, moduleId, bonds: backups.diy.operators?.[charId]?.bonds ?? null });
}
+14 -13
View File
@@ -12,7 +12,8 @@ import assert from 'node:assert/strict';
import { readFileSync, existsSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { standInRecord, diyRecord, composeUnitRecord, unitForm, statusKey, IDENTITY_FIELDS } from '../shared/standIn.js';
import { standInRecord, composeUnitRecord, unitForm, statusKey, IDENTITY_FIELDS } from '../shared/standIn.js';
import { diyRecordOf, lockedSelection } from '../shared/diy.js';
import { composeStats, composeTalents, resolveLoadout, loadoutRecord, normalizeChess } from '../server/sim/simdata.js';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
@@ -212,26 +213,26 @@ test('DIY: prototype picks — the 9 elites at tiers 5 and 6, six 4★ reserves
assert.deepEqual(prototypes['6'], ELITES);
assert.deepEqual(prototypes['5'], [...RESERVES.filter((id) => !['char_600_cpione', 'char_607_cspec'].includes(id)), ...ELITES]);
assert.equal(prototypes['5'].length, 15);
// every pick composes in every slot form, with any of its skills (which skill a prototype carries in a slot is an open
// question — the data supports any answer), with the derived bonds (协防干员: no prototype has a faction) and no 特质
// every pick composes in every slot form — at its locked selection (diy.locked: "技能携带规则与系统补位时一致"; shared/diy.js
// diyRecordOf, which replaced standIn.js's prototype-only diyRecord in 0.2.0) — with the derived bonds (协防干员: no
// prototype has a faction) and no 特质
const data = { chess, backups };
for (const [id, s] of Object.entries(backups.diy.slots)) {
for (const slot of [chess[id], chess[s.goldenId]]) {
for (const p of prototypes[s.tier]) {
const form = unitForm(backups, p, slot.status);
assert.ok(form, `${slot.chessId} ${p}: form`);
for (const sk of form.skills) {
const mod = slot.status.equipLevel > 0 ? form.modules[0]?.uniEquipId ?? null : null;
const r = diyRecord(slot, p, backups, { skillIndex: sk.index, moduleId: mod });
assert.ok(r && r.skill.index === sk.index && r.charId === p, `${slot.chessId} ${p} S${sk.index + 1}`);
assert.deepEqual([r.bonds, r.garrisonIds, r.price, r.tier], [['emptyShip'], [], 4, s.tier]);
if (mod) assert.equal(r.module.active, true, `${slot.chessId} ${p}: module`);
}
const lk = lockedSelection(data, s.tier, p);
const r = diyRecordOf(slot, { charId: p }, data);
assert.ok(r && r.skill.index === lk.skillIndex && r.charId === p, `${slot.chessId} ${p}`);
assert.deepEqual([r.bonds, r.garrisonIds, r.price, r.tier], [['emptyShip'], [], 4, s.tier]);
if (slot.status.equipLevel > 0 && lk.uniEquipId) assert.equal(r.module.active, true, `${slot.chessId} ${p}: module`);
}
}
}
assert.equal(diyRecord(chess.chess_char_6_diy1_a, 'char_601_cguard', backups, { skillIndex: 2 }), null, 'a reserve is not a tier-6 pick');
assert.equal(diyRecord(chess.chess_char_5_diy1_a, 'char_600_cpione', backups, { skillIndex: 2 }), null, '预备干员-先锋 is not a pick');
assert.equal(diyRecord(chess.chess_char_5_01_a, 'char_608_acpion', backups, { skillIndex: 2 }), null, 'not a DIY slot');
assert.equal(diyRecordOf(chess.chess_char_6_diy1_a, { charId: 'char_601_cguard' }, data), null, 'a reserve is not a tier-6 pick');
assert.equal(diyRecordOf(chess.chess_char_5_diy1_a, { charId: 'char_600_cpione' }, data), null, '预备干员-先锋 is not a pick');
assert.equal(diyRecordOf(chess.chess_char_5_01_a, { charId: 'char_608_acpion' }, data), null, 'not a DIY slot');
});
test('DIY: the 71 owned 6★ picks — a form at every slot status with all three skills, every module at stage 1 and 3, their summons', () => {
+3 -1
View File
@@ -9,7 +9,9 @@ import { skillSpecSource } from '../../server/sim/content/index.js';
import { effectiveProfile } from '../../server/sim/ai.js';
import { kitCoverage } from '../../tools/kit-coverage.mjs';
import { wolfShadows, wolfTacticalPoint } from '../../server/sim/content/tokens.js';
import KITS from '../../server/sim/content/kits/tier3.js';
import { TIER_KITS } from '../../server/sim/content/kits/index.js';
const KITS = TIER_KITS[2];
const ds = getDefaultSource();
/** Skill index of `skillId` on chess `id`. */
+3 -1
View File
@@ -5,9 +5,11 @@ import assert from 'node:assert/strict';
import { makeBattle, enemyRec, checkInvariants } from '../helpers/battleHarness.js';
import { getDefaultSource } from '../../server/sim/simdata.js';
import { effectiveProfile } from '../../server/sim/ai.js';
import KITS from '../../server/sim/content/kits/tier3.js';
import { TIER_KITS } from '../../server/sim/content/kits/index.js';
import { COLS } from '../../server/sim/constants.js';
const KITS = TIER_KITS[2];
const ds = getDefaultSource();
const D = (id) => ds.getChess(id);
const BB = (id) => D(id).skill.bb;
+3 -1
View File
@@ -4,9 +4,11 @@ import { test } from 'node:test';
import assert from 'node:assert/strict';
import { makeBattle, enemyRec, checkInvariants } from '../helpers/battleHarness.js';
import { getDefaultSource } from '../../server/sim/simdata.js';
import kits from '../../server/sim/content/kits/tier4.js';
import { TIER_KITS } from '../../server/sim/content/kits/index.js';
import { absoluteRangeKeys } from '../../server/sim/targeting.js';
const kits = TIER_KITS[3];
const ds = getDefaultSource();
const D = (id) => ds.getChess(id);
const approx = (a, b, eps = 1e-6, msg = '') => assert.ok(Math.abs(a - b) <= eps * Math.max(1, Math.abs(b)), `${msg} ${a} ≈ ${b}`);
+3 -1
View File
@@ -3,7 +3,9 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { makeBattle, enemyRec, chessRec, checkInvariants } from '../helpers/battleHarness.js';
import KITS from '../../server/sim/content/kits/tier5.js';
import { TIER_KITS } from '../../server/sim/content/kits/index.js';
const KITS = TIER_KITS[4];
const approx = (a, b, eps = 1e-6, msg = '') => assert.ok(Math.abs(a - b) <= eps * Math.max(1, Math.abs(b)), `${msg} ${a} ≉ ${b}`);
const dummy = (key = 'enemy_dummy', o = {}) => enemyRec({ key, hp: 1e7, speed: 0, ...o });
+1 -1
View File
@@ -14,7 +14,7 @@ import { test } from 'node:test';
import assert from 'node:assert/strict';
import { makeBattle, enemyRec, chessRec, checkInvariants } from '../helpers/battleHarness.js';
import { getDefaultSource } from '../../server/sim/simdata.js';
import { PITHST_ELEMENTS } from '../../server/sim/content/kits/tier6.js';
import { PITHST_ELEMENTS } from '../../server/sim/content/kits/ops/chess_char_1_15-pithst.js';
import { spawnYanyou } from '../../server/sim/content/tokens.js';
import { COLS } from '../../server/sim/constants.js';
+1 -1
View File
@@ -12,7 +12,7 @@ after(async () => { if (srv) await srv.close(); });
test('/sim/ serves the simulation modules read-only; nothing else of server/ is reachable', async () => {
srv = await startServer({ port: 0, host: '127.0.0.1', quiet: true });
const get = (p, headers = {}) => fetch(srv.url + p, { redirect: 'manual', headers });
for (const p of ['/sim/spec.js', '/sim/Battle.js', '/sim/simdata.js', '/sim/constants.js', '/sim/content/index.js', '/sim/content/kits/tier1.js', '/sim/content/support/index.js']) {
for (const p of ['/sim/spec.js', '/sim/Battle.js', '/sim/simdata.js', '/sim/constants.js', '/sim/content/index.js', '/sim/content/kits/index.js', '/sim/content/support/index.js']) {
const r = await get(p);
assert.equal(r.status, 200, p);
assert.match(r.headers.get('content-type'), /^text\/javascript/, p);
+1 -1
View File
@@ -12,7 +12,7 @@ import { COLS } from '../../server/sim/constants.js';
import { makeBattle, chessRec, enemyRec, checkInvariants } from '../helpers/battleHarness.js';
import { findSummonTile } from '../../server/sim/content/tokens.js';
import { frontTile, sideTiles, alliesAround, N4 } from '../../server/sim/content/support/index.js';
import { freeTileAround } from '../../server/sim/content/kits/tier1.js';
import { freeTileAround } from '../../server/sim/content/kits/shared/tier1.js';
import { DIRS as PROTOCOL_DIRS } from '../../shared/protocol.js';
const K = (r, c) => r * COLS + c;
+1 -1
View File
@@ -22,7 +22,7 @@ import { makeBattle, chessRec, enemyRec, checkInvariants } from '../helpers/batt
import { getDefaultSource, hasGeneratedData } from '../../server/sim/simdata.js';
import { effectiveProfile } from '../../server/sim/ai.js';
import { PUSH_TILES, PUSH_TILES_EFFECT, PULL_STOP_RADIUS, ASPD_MIN, COLS } from '../../server/sim/constants.js';
import { alliesInGridOf } from '../../server/sim/content/kits/tier1.js';
import { alliesInGridOf } from '../../server/sim/content/kits/shared/tier1.js';
import { Unit } from '../../server/sim/units.js';
import { spawnYanyou, TOKEN_IDS } from '../../server/sim/content/tokens.js';