@lycoristech/azurdata 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +25 -0
- package/README.md +123 -0
- package/data/.gitkeep +0 -0
- package/data/id-map.json +3530 -0
- package/data/ship-list.json +4478 -0
- package/data/ships.json +143282 -0
- package/data/version.json +5 -0
- package/dist/cjs/client/AzurData.js +69 -0
- package/dist/cjs/client/fetcher.js +121 -0
- package/dist/cjs/client/index.js +7 -0
- package/dist/cjs/client/ships.js +80 -0
- package/dist/cjs/config.js +14 -0
- package/dist/cjs/index.js +6 -0
- package/dist/cjs/ingest/files.js +134 -0
- package/dist/cjs/ingest/index.js +18 -0
- package/dist/cjs/ingest/upstream.js +12 -0
- package/dist/cjs/normalize/construction.js +186 -0
- package/dist/cjs/normalize/identity.js +131 -0
- package/dist/cjs/normalize/index.js +25 -0
- package/dist/cjs/normalize/misc.js +31 -0
- package/dist/cjs/normalize/retrofit.js +21 -0
- package/dist/cjs/normalize/ship.js +406 -0
- package/dist/cjs/normalize/skills.js +194 -0
- package/dist/cjs/normalize/skins.js +141 -0
- package/dist/cjs/normalize/slots.js +35 -0
- package/dist/cjs/normalize/stats.js +182 -0
- package/dist/cjs/output/index.js +20 -0
- package/dist/cjs/output/writeIdMap.js +52 -0
- package/dist/cjs/output/writeShipList.js +31 -0
- package/dist/cjs/output/writeShips.js +33 -0
- package/dist/cjs/output/writeVersion.js +23 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/schema/output/index.js +17 -0
- package/dist/cjs/schema/output/ship.js +169 -0
- package/dist/cjs/schema/raw/attributeInfoByType.js +11 -0
- package/dist/cjs/schema/raw/equipDataByType.js +12 -0
- package/dist/cjs/schema/raw/fleetTechGroup.js +10 -0
- package/dist/cjs/schema/raw/fleetTechShipClass.js +15 -0
- package/dist/cjs/schema/raw/fleetTechShipTemplate.js +20 -0
- package/dist/cjs/schema/raw/index.js +38 -0
- package/dist/cjs/schema/raw/shipDataBlueprint.js +11 -0
- package/dist/cjs/schema/raw/shipDataBreakout.js +17 -0
- package/dist/cjs/schema/raw/shipDataByStar.js +10 -0
- package/dist/cjs/schema/raw/shipDataByType.js +13 -0
- package/dist/cjs/schema/raw/shipDataCreateExchange.js +10 -0
- package/dist/cjs/schema/raw/shipDataGroup.js +22 -0
- package/dist/cjs/schema/raw/shipDataStatistics.js +24 -0
- package/dist/cjs/schema/raw/shipDataStrengthen.js +12 -0
- package/dist/cjs/schema/raw/shipDataTemplate.js +26 -0
- package/dist/cjs/schema/raw/shipDataTrans.js +13 -0
- package/dist/cjs/schema/raw/shipSkinTemplate.js +23 -0
- package/dist/cjs/schema/raw/shipSkinWords.js +11 -0
- package/dist/cjs/schema/raw/shopTemplate.js +14 -0
- package/dist/cjs/schema/raw/skillDataDisplay.js +11 -0
- package/dist/cjs/schema/raw/skillDataTemplate.js +17 -0
- package/dist/cjs/schema/raw/transformDataTemplate.js +18 -0
- package/dist/cjs/schema/raw/voiceActorCn.js +11 -0
- package/dist/cjs/translate/enums.js +131 -0
- package/dist/cjs/translate/index.js +19 -0
- package/dist/cjs/translate/lookups.js +63 -0
- package/dist/cjs/translate/strings.js +98 -0
- package/dist/client/AzurData.d.ts +25 -0
- package/dist/client/AzurData.d.ts.map +1 -0
- package/dist/client/AzurData.js +63 -0
- package/dist/client/AzurData.js.map +1 -0
- package/dist/client/fetcher.d.ts +25 -0
- package/dist/client/fetcher.d.ts.map +1 -0
- package/dist/client/fetcher.js +116 -0
- package/dist/client/fetcher.js.map +1 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +3 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/ships.d.ts +20 -0
- package/dist/client/ships.d.ts.map +1 -0
- package/dist/client/ships.js +74 -0
- package/dist/client/ships.js.map +1 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +12 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest/files.d.ts +25 -0
- package/dist/ingest/files.d.ts.map +1 -0
- package/dist/ingest/files.js +108 -0
- package/dist/ingest/files.js.map +1 -0
- package/dist/ingest/index.d.ts +3 -0
- package/dist/ingest/index.d.ts.map +1 -0
- package/dist/ingest/index.js +3 -0
- package/dist/ingest/index.js.map +1 -0
- package/dist/ingest/upstream.d.ts +4 -0
- package/dist/ingest/upstream.d.ts.map +1 -0
- package/dist/ingest/upstream.js +6 -0
- package/dist/ingest/upstream.js.map +1 -0
- package/dist/normalize/construction.d.ts +30 -0
- package/dist/normalize/construction.d.ts.map +1 -0
- package/dist/normalize/construction.js +184 -0
- package/dist/normalize/construction.js.map +1 -0
- package/dist/normalize/identity.d.ts +47 -0
- package/dist/normalize/identity.d.ts.map +1 -0
- package/dist/normalize/identity.js +129 -0
- package/dist/normalize/identity.js.map +1 -0
- package/dist/normalize/index.d.ts +10 -0
- package/dist/normalize/index.d.ts.map +1 -0
- package/dist/normalize/index.js +10 -0
- package/dist/normalize/index.js.map +1 -0
- package/dist/normalize/misc.d.ts +15 -0
- package/dist/normalize/misc.d.ts.map +1 -0
- package/dist/normalize/misc.js +29 -0
- package/dist/normalize/misc.js.map +1 -0
- package/dist/normalize/retrofit.d.ts +14 -0
- package/dist/normalize/retrofit.d.ts.map +1 -0
- package/dist/normalize/retrofit.js +19 -0
- package/dist/normalize/retrofit.js.map +1 -0
- package/dist/normalize/ship.d.ts +67 -0
- package/dist/normalize/ship.d.ts.map +1 -0
- package/dist/normalize/ship.js +369 -0
- package/dist/normalize/ship.js.map +1 -0
- package/dist/normalize/skills.d.ts +20 -0
- package/dist/normalize/skills.d.ts.map +1 -0
- package/dist/normalize/skills.js +192 -0
- package/dist/normalize/skills.js.map +1 -0
- package/dist/normalize/skins.d.ts +14 -0
- package/dist/normalize/skins.d.ts.map +1 -0
- package/dist/normalize/skins.js +139 -0
- package/dist/normalize/skins.js.map +1 -0
- package/dist/normalize/slots.d.ts +14 -0
- package/dist/normalize/slots.d.ts.map +1 -0
- package/dist/normalize/slots.js +33 -0
- package/dist/normalize/slots.js.map +1 -0
- package/dist/normalize/stats.d.ts +19 -0
- package/dist/normalize/stats.d.ts.map +1 -0
- package/dist/normalize/stats.js +180 -0
- package/dist/normalize/stats.js.map +1 -0
- package/dist/output/index.d.ts +5 -0
- package/dist/output/index.d.ts.map +1 -0
- package/dist/output/index.js +5 -0
- package/dist/output/index.js.map +1 -0
- package/dist/output/writeIdMap.d.ts +16 -0
- package/dist/output/writeIdMap.d.ts.map +1 -0
- package/dist/output/writeIdMap.js +47 -0
- package/dist/output/writeIdMap.js.map +1 -0
- package/dist/output/writeShipList.d.ts +9 -0
- package/dist/output/writeShipList.d.ts.map +1 -0
- package/dist/output/writeShipList.js +26 -0
- package/dist/output/writeShipList.js.map +1 -0
- package/dist/output/writeShips.d.ts +15 -0
- package/dist/output/writeShips.d.ts.map +1 -0
- package/dist/output/writeShips.js +28 -0
- package/dist/output/writeShips.js.map +1 -0
- package/dist/output/writeVersion.d.ts +11 -0
- package/dist/output/writeVersion.d.ts.map +1 -0
- package/dist/output/writeVersion.js +18 -0
- package/dist/output/writeVersion.js.map +1 -0
- package/dist/schema/output/index.d.ts +2 -0
- package/dist/schema/output/index.d.ts.map +1 -0
- package/dist/schema/output/index.js +2 -0
- package/dist/schema/output/index.js.map +1 -0
- package/dist/schema/output/ship.d.ts +977 -0
- package/dist/schema/output/ship.d.ts.map +1 -0
- package/dist/schema/output/ship.js +167 -0
- package/dist/schema/output/ship.js.map +1 -0
- package/dist/schema/raw/attributeInfoByType.d.ts +25 -0
- package/dist/schema/raw/attributeInfoByType.d.ts.map +1 -0
- package/dist/schema/raw/attributeInfoByType.js +9 -0
- package/dist/schema/raw/attributeInfoByType.js.map +1 -0
- package/dist/schema/raw/equipDataByType.d.ts +31 -0
- package/dist/schema/raw/equipDataByType.d.ts.map +1 -0
- package/dist/schema/raw/equipDataByType.js +10 -0
- package/dist/schema/raw/equipDataByType.js.map +1 -0
- package/dist/schema/raw/fleetTechGroup.d.ts +19 -0
- package/dist/schema/raw/fleetTechGroup.d.ts.map +1 -0
- package/dist/schema/raw/fleetTechGroup.js +8 -0
- package/dist/schema/raw/fleetTechGroup.js.map +1 -0
- package/dist/schema/raw/fleetTechShipClass.d.ts +49 -0
- package/dist/schema/raw/fleetTechShipClass.d.ts.map +1 -0
- package/dist/schema/raw/fleetTechShipClass.js +13 -0
- package/dist/schema/raw/fleetTechShipClass.js.map +1 -0
- package/dist/schema/raw/fleetTechShipTemplate.d.ts +79 -0
- package/dist/schema/raw/fleetTechShipTemplate.d.ts.map +1 -0
- package/dist/schema/raw/fleetTechShipTemplate.js +18 -0
- package/dist/schema/raw/fleetTechShipTemplate.js.map +1 -0
- package/dist/schema/raw/index.d.ts +23 -0
- package/dist/schema/raw/index.d.ts.map +1 -0
- package/dist/schema/raw/index.js +23 -0
- package/dist/schema/raw/index.js.map +1 -0
- package/dist/schema/raw/shipDataBlueprint.d.ts +25 -0
- package/dist/schema/raw/shipDataBlueprint.d.ts.map +1 -0
- package/dist/schema/raw/shipDataBlueprint.js +9 -0
- package/dist/schema/raw/shipDataBlueprint.js.map +1 -0
- package/dist/schema/raw/shipDataBreakout.d.ts +61 -0
- package/dist/schema/raw/shipDataBreakout.d.ts.map +1 -0
- package/dist/schema/raw/shipDataBreakout.js +15 -0
- package/dist/schema/raw/shipDataBreakout.js.map +1 -0
- package/dist/schema/raw/shipDataByStar.d.ts +19 -0
- package/dist/schema/raw/shipDataByStar.d.ts.map +1 -0
- package/dist/schema/raw/shipDataByStar.js +8 -0
- package/dist/schema/raw/shipDataByStar.js.map +1 -0
- package/dist/schema/raw/shipDataByType.d.ts +37 -0
- package/dist/schema/raw/shipDataByType.d.ts.map +1 -0
- package/dist/schema/raw/shipDataByType.js +11 -0
- package/dist/schema/raw/shipDataByType.js.map +1 -0
- package/dist/schema/raw/shipDataCreateExchange.d.ts +19 -0
- package/dist/schema/raw/shipDataCreateExchange.d.ts.map +1 -0
- package/dist/schema/raw/shipDataCreateExchange.js +8 -0
- package/dist/schema/raw/shipDataCreateExchange.js.map +1 -0
- package/dist/schema/raw/shipDataGroup.d.ts +79 -0
- package/dist/schema/raw/shipDataGroup.d.ts.map +1 -0
- package/dist/schema/raw/shipDataGroup.js +20 -0
- package/dist/schema/raw/shipDataGroup.js.map +1 -0
- package/dist/schema/raw/shipDataStatistics.d.ts +103 -0
- package/dist/schema/raw/shipDataStatistics.d.ts.map +1 -0
- package/dist/schema/raw/shipDataStatistics.js +22 -0
- package/dist/schema/raw/shipDataStatistics.js.map +1 -0
- package/dist/schema/raw/shipDataStrengthen.d.ts +31 -0
- package/dist/schema/raw/shipDataStrengthen.d.ts.map +1 -0
- package/dist/schema/raw/shipDataStrengthen.js +10 -0
- package/dist/schema/raw/shipDataStrengthen.js.map +1 -0
- package/dist/schema/raw/shipDataTemplate.d.ts +115 -0
- package/dist/schema/raw/shipDataTemplate.d.ts.map +1 -0
- package/dist/schema/raw/shipDataTemplate.js +24 -0
- package/dist/schema/raw/shipDataTemplate.js.map +1 -0
- package/dist/schema/raw/shipDataTrans.d.ts +37 -0
- package/dist/schema/raw/shipDataTrans.d.ts.map +1 -0
- package/dist/schema/raw/shipDataTrans.js +11 -0
- package/dist/schema/raw/shipDataTrans.js.map +1 -0
- package/dist/schema/raw/shipSkinTemplate.d.ts +97 -0
- package/dist/schema/raw/shipSkinTemplate.d.ts.map +1 -0
- package/dist/schema/raw/shipSkinTemplate.js +21 -0
- package/dist/schema/raw/shipSkinTemplate.js.map +1 -0
- package/dist/schema/raw/shipSkinWords.d.ts +25 -0
- package/dist/schema/raw/shipSkinWords.d.ts.map +1 -0
- package/dist/schema/raw/shipSkinWords.js +9 -0
- package/dist/schema/raw/shipSkinWords.js.map +1 -0
- package/dist/schema/raw/shopTemplate.d.ts +43 -0
- package/dist/schema/raw/shopTemplate.d.ts.map +1 -0
- package/dist/schema/raw/shopTemplate.js +12 -0
- package/dist/schema/raw/shopTemplate.js.map +1 -0
- package/dist/schema/raw/skillDataDisplay.d.ts +25 -0
- package/dist/schema/raw/skillDataDisplay.d.ts.map +1 -0
- package/dist/schema/raw/skillDataDisplay.js +9 -0
- package/dist/schema/raw/skillDataDisplay.js.map +1 -0
- package/dist/schema/raw/skillDataTemplate.d.ts +61 -0
- package/dist/schema/raw/skillDataTemplate.d.ts.map +1 -0
- package/dist/schema/raw/skillDataTemplate.js +15 -0
- package/dist/schema/raw/skillDataTemplate.js.map +1 -0
- package/dist/schema/raw/transformDataTemplate.d.ts +67 -0
- package/dist/schema/raw/transformDataTemplate.d.ts.map +1 -0
- package/dist/schema/raw/transformDataTemplate.js +16 -0
- package/dist/schema/raw/transformDataTemplate.js.map +1 -0
- package/dist/schema/raw/voiceActorCn.d.ts +25 -0
- package/dist/schema/raw/voiceActorCn.d.ts.map +1 -0
- package/dist/schema/raw/voiceActorCn.js +9 -0
- package/dist/schema/raw/voiceActorCn.js.map +1 -0
- package/dist/translate/enums.d.ts +34 -0
- package/dist/translate/enums.d.ts.map +1 -0
- package/dist/translate/enums.js +126 -0
- package/dist/translate/enums.js.map +1 -0
- package/dist/translate/index.d.ts +4 -0
- package/dist/translate/index.d.ts.map +1 -0
- package/dist/translate/index.js +4 -0
- package/dist/translate/index.js.map +1 -0
- package/dist/translate/lookups.d.ts +37 -0
- package/dist/translate/lookups.d.ts.map +1 -0
- package/dist/translate/lookups.js +61 -0
- package/dist/translate/lookups.js.map +1 -0
- package/dist/translate/strings.d.ts +40 -0
- package/dist/translate/strings.d.ts.map +1 -0
- package/dist/translate/strings.js +92 -0
- package/dist/translate/strings.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AzurData = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const ships_js_1 = require("./ships.js");
|
|
10
|
+
const fetcher_js_1 = require("./fetcher.js");
|
|
11
|
+
function resolveThisDir() {
|
|
12
|
+
// CJS: __dirname is injected by Node
|
|
13
|
+
// ESM under tsx/ts-node: __dirname is polyfilled
|
|
14
|
+
// Pure ESM: falls back to cwd
|
|
15
|
+
try {
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
17
|
+
// @ts-ignore __dirname exists in CJS but not in ESM type defs
|
|
18
|
+
if (typeof __dirname === "string")
|
|
19
|
+
return __dirname; // eslint-disable-line no-undef
|
|
20
|
+
}
|
|
21
|
+
catch { /* not CJS */ }
|
|
22
|
+
return process.cwd();
|
|
23
|
+
}
|
|
24
|
+
class AzurData {
|
|
25
|
+
ships;
|
|
26
|
+
/** Sync constructor — loads baked data from disk. No network. */
|
|
27
|
+
constructor(options = {}) {
|
|
28
|
+
const dataDir = options.dataPath ?? AzurData.resolveDefaultDataPath();
|
|
29
|
+
const shipsJson = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(dataDir, "ships.json"), "utf8"));
|
|
30
|
+
const idMapJson = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(dataDir, "id-map.json"), "utf8"));
|
|
31
|
+
this.ships = new ships_js_1.Ships({ data: shipsJson, idMap: idMapJson });
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Async factory — fetches latest data from GitHub, caches locally,
|
|
35
|
+
* falls back to baked data if offline.
|
|
36
|
+
*
|
|
37
|
+
* ```ts
|
|
38
|
+
* const azur = await AzurData.init({ fetchLatest: true });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
static async init(options = {}) {
|
|
42
|
+
const { fetchLatest = true, ...fetchOpts } = options;
|
|
43
|
+
if (fetchLatest) {
|
|
44
|
+
const fetched = await (0, fetcher_js_1.fetchLatestData)(fetchOpts);
|
|
45
|
+
if (fetched) {
|
|
46
|
+
const instance = Object.create(AzurData.prototype);
|
|
47
|
+
instance.ships = new ships_js_1.Ships({
|
|
48
|
+
data: fetched.ships,
|
|
49
|
+
idMap: fetched.idMap,
|
|
50
|
+
});
|
|
51
|
+
return instance;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Fallback to baked data
|
|
55
|
+
return new AzurData();
|
|
56
|
+
}
|
|
57
|
+
static resolveDefaultDataPath() {
|
|
58
|
+
const thisDir = resolveThisDir();
|
|
59
|
+
let candidate = thisDir;
|
|
60
|
+
for (let i = 0; i < 5; i++) {
|
|
61
|
+
const dataPath = node_path_1.default.resolve(candidate, "data");
|
|
62
|
+
if (node_fs_1.default.existsSync(node_path_1.default.join(dataPath, "ships.json")))
|
|
63
|
+
return dataPath;
|
|
64
|
+
candidate = node_path_1.default.resolve(candidate, "..");
|
|
65
|
+
}
|
|
66
|
+
return node_path_1.default.resolve(process.cwd(), "data");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.AzurData = AzurData;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.fetchLatestData = fetchLatestData;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
10
|
+
const config_js_1 = require("../config.js");
|
|
11
|
+
const DEFAULT_CACHE_DIR = node_path_1.default.join(node_os_1.default.homedir(), ".azurdata");
|
|
12
|
+
const DEFAULT_MAX_AGE = 6 * 60 * 60 * 1000; // 6 hours
|
|
13
|
+
/**
|
|
14
|
+
* Fetch latest data from GitHub, with local cache and baked-data fallback.
|
|
15
|
+
*
|
|
16
|
+
* Flow:
|
|
17
|
+
* 1. If cache exists and is fresh (< maxAge) → load from cache
|
|
18
|
+
* 2. Else fetch version.json from remote → compare with cache
|
|
19
|
+
* 3. If remote is newer → fetch ships.json + id-map.json, write to cache
|
|
20
|
+
* 4. If any fetch fails → fall back to cache, then to null (caller uses baked data)
|
|
21
|
+
*/
|
|
22
|
+
async function fetchLatestData(options = {}) {
|
|
23
|
+
const cacheDir = options.cacheDir ?? DEFAULT_CACHE_DIR;
|
|
24
|
+
const maxAge = options.maxAge ?? DEFAULT_MAX_AGE;
|
|
25
|
+
const baseUrl = options.dataUrl ?? config_js_1.DATA_BASE_URL;
|
|
26
|
+
// Check cache freshness
|
|
27
|
+
const cachedShipsPath = node_path_1.default.join(cacheDir, "ships.json");
|
|
28
|
+
const cachedIdMapPath = node_path_1.default.join(cacheDir, "id-map.json");
|
|
29
|
+
const cachedVersionPath = node_path_1.default.join(cacheDir, "version.json");
|
|
30
|
+
if (isCacheFresh(cachedVersionPath, maxAge)) {
|
|
31
|
+
return loadFromCache(cachedShipsPath, cachedIdMapPath);
|
|
32
|
+
}
|
|
33
|
+
// Fetch remote version
|
|
34
|
+
let remoteVersion = null;
|
|
35
|
+
try {
|
|
36
|
+
remoteVersion = await fetchJson(`${baseUrl}/version.json`);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Network error — try cache regardless of age
|
|
40
|
+
return loadFromCache(cachedShipsPath, cachedIdMapPath);
|
|
41
|
+
}
|
|
42
|
+
// Compare with cached version
|
|
43
|
+
if (remoteVersion && isCacheUpToDate(cachedVersionPath, remoteVersion)) {
|
|
44
|
+
// Touch the cache file to reset maxAge timer
|
|
45
|
+
touchFile(cachedVersionPath);
|
|
46
|
+
return loadFromCache(cachedShipsPath, cachedIdMapPath);
|
|
47
|
+
}
|
|
48
|
+
// Fetch fresh data
|
|
49
|
+
try {
|
|
50
|
+
const [ships, idMap] = await Promise.all([
|
|
51
|
+
fetchJson(`${baseUrl}/ships.json`),
|
|
52
|
+
fetchJson(`${baseUrl}/id-map.json`),
|
|
53
|
+
]);
|
|
54
|
+
if (!ships || !idMap) {
|
|
55
|
+
return loadFromCache(cachedShipsPath, cachedIdMapPath);
|
|
56
|
+
}
|
|
57
|
+
// Write to cache atomically
|
|
58
|
+
writeCache(cacheDir, {
|
|
59
|
+
"ships.json": ships,
|
|
60
|
+
"id-map.json": idMap,
|
|
61
|
+
"version.json": remoteVersion,
|
|
62
|
+
});
|
|
63
|
+
return { ships, idMap };
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return loadFromCache(cachedShipsPath, cachedIdMapPath);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
70
|
+
async function fetchJson(url) {
|
|
71
|
+
const res = await fetch(url);
|
|
72
|
+
if (!res.ok)
|
|
73
|
+
return null;
|
|
74
|
+
return (await res.json());
|
|
75
|
+
}
|
|
76
|
+
function isCacheFresh(versionPath, maxAge) {
|
|
77
|
+
try {
|
|
78
|
+
const stat = node_fs_1.default.statSync(versionPath);
|
|
79
|
+
return Date.now() - stat.mtimeMs < maxAge;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function isCacheUpToDate(versionPath, remote) {
|
|
86
|
+
try {
|
|
87
|
+
const cached = JSON.parse(node_fs_1.default.readFileSync(versionPath, "utf8"));
|
|
88
|
+
return cached.generatedAt === remote.generatedAt;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function touchFile(filePath) {
|
|
95
|
+
try {
|
|
96
|
+
const now = new Date();
|
|
97
|
+
node_fs_1.default.utimesSync(filePath, now, now);
|
|
98
|
+
}
|
|
99
|
+
catch { /* ignore */ }
|
|
100
|
+
}
|
|
101
|
+
function loadFromCache(shipsPath, idMapPath) {
|
|
102
|
+
try {
|
|
103
|
+
if (!node_fs_1.default.existsSync(shipsPath) || !node_fs_1.default.existsSync(idMapPath))
|
|
104
|
+
return null;
|
|
105
|
+
const ships = JSON.parse(node_fs_1.default.readFileSync(shipsPath, "utf8"));
|
|
106
|
+
const idMap = JSON.parse(node_fs_1.default.readFileSync(idMapPath, "utf8"));
|
|
107
|
+
return { ships, idMap };
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function writeCache(cacheDir, files) {
|
|
114
|
+
node_fs_1.default.mkdirSync(cacheDir, { recursive: true });
|
|
115
|
+
for (const [name, data] of Object.entries(files)) {
|
|
116
|
+
const target = node_path_1.default.join(cacheDir, name);
|
|
117
|
+
const tmp = target + ".tmp";
|
|
118
|
+
node_fs_1.default.writeFileSync(tmp, JSON.stringify(data), "utf8");
|
|
119
|
+
node_fs_1.default.renameSync(tmp, target); // atomic on most filesystems
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Ships = exports.AzurData = void 0;
|
|
4
|
+
var AzurData_js_1 = require("./AzurData.js");
|
|
5
|
+
Object.defineProperty(exports, "AzurData", { enumerable: true, get: function () { return AzurData_js_1.AzurData; } });
|
|
6
|
+
var ships_js_1 = require("./ships.js");
|
|
7
|
+
Object.defineProperty(exports, "Ships", { enumerable: true, get: function () { return ships_js_1.Ships; } });
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Ships = void 0;
|
|
7
|
+
const fuse_js_1 = __importDefault(require("fuse.js"));
|
|
8
|
+
class Ships {
|
|
9
|
+
data;
|
|
10
|
+
idMap;
|
|
11
|
+
fuse;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.data = options.data;
|
|
14
|
+
this.idMap = options.idMap;
|
|
15
|
+
this.fuse = new fuse_js_1.default(Object.values(options.data), {
|
|
16
|
+
keys: [
|
|
17
|
+
{ name: "names.en", weight: 3 },
|
|
18
|
+
{ name: "names.code", weight: 2 },
|
|
19
|
+
{ name: "names.jp", weight: 1 },
|
|
20
|
+
{ name: "names.cn", weight: 1 },
|
|
21
|
+
],
|
|
22
|
+
threshold: options.fuseThreshold ?? 0.4,
|
|
23
|
+
includeScore: true,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
// Primary getter. Accepts:
|
|
27
|
+
// - canonical group_type: "20212"
|
|
28
|
+
// - legacy 3-digit code: "115" (via idMap)
|
|
29
|
+
// - any name in idMap (case-insensitive)
|
|
30
|
+
// - fuzzy match via fuse.js
|
|
31
|
+
get(nameOrId) {
|
|
32
|
+
if (typeof nameOrId !== "string" || nameOrId.length === 0)
|
|
33
|
+
return undefined;
|
|
34
|
+
// 1. Direct id hit
|
|
35
|
+
if (this.data[nameOrId])
|
|
36
|
+
return this.data[nameOrId];
|
|
37
|
+
// 2. Exact id-map hit (case sensitive first)
|
|
38
|
+
const directId = this.idMap[nameOrId];
|
|
39
|
+
if (directId && this.data[directId])
|
|
40
|
+
return this.data[directId];
|
|
41
|
+
// 3. Case-insensitive id-map hit
|
|
42
|
+
// Build a lowercased copy lazily
|
|
43
|
+
const lower = nameOrId.toLowerCase();
|
|
44
|
+
const ciIdMap = this.getCiIdMap();
|
|
45
|
+
const ciId = ciIdMap[lower];
|
|
46
|
+
if (ciId && this.data[ciId])
|
|
47
|
+
return this.data[ciId];
|
|
48
|
+
// 4. Fuse.js fuzzy
|
|
49
|
+
const results = this.fuse.search(nameOrId, { limit: 1 });
|
|
50
|
+
if (results.length > 0 && results[0].score !== undefined && results[0].score < 0.5) {
|
|
51
|
+
return results[0].item;
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
_ciIdMap;
|
|
56
|
+
getCiIdMap() {
|
|
57
|
+
if (!this._ciIdMap) {
|
|
58
|
+
this._ciIdMap = {};
|
|
59
|
+
for (const [k, v] of Object.entries(this.idMap)) {
|
|
60
|
+
this._ciIdMap[k.toLowerCase()] = v;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return this._ciIdMap;
|
|
64
|
+
}
|
|
65
|
+
getAll() {
|
|
66
|
+
return Object.values(this.data);
|
|
67
|
+
}
|
|
68
|
+
getById(id) {
|
|
69
|
+
return this.data[id];
|
|
70
|
+
}
|
|
71
|
+
count() {
|
|
72
|
+
return Object.keys(this.data).length;
|
|
73
|
+
}
|
|
74
|
+
// Search multiple matches
|
|
75
|
+
search(query, limit = 10) {
|
|
76
|
+
const results = this.fuse.search(query, { limit });
|
|
77
|
+
return results.map(r => r.item);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.Ships = Ships;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DATA_BASE_URL = exports.THUMBNAILS_URL = exports.PAINTINGS_URL = exports.IMAGE_BASE_URL = void 0;
|
|
4
|
+
// Central config for GitHub URLs.
|
|
5
|
+
const GITHUB_USER = "iujab";
|
|
6
|
+
const GITHUB_BRANCH = "main";
|
|
7
|
+
// Image URLs (azurlane-images repo)
|
|
8
|
+
const IMAGES_REPO = "azurlane-images";
|
|
9
|
+
exports.IMAGE_BASE_URL = `https://raw.githubusercontent.com/${GITHUB_USER}/${IMAGES_REPO}/${GITHUB_BRANCH}`;
|
|
10
|
+
exports.PAINTINGS_URL = `${exports.IMAGE_BASE_URL}/paintings`;
|
|
11
|
+
exports.THUMBNAILS_URL = `${exports.IMAGE_BASE_URL}/thumbnails`;
|
|
12
|
+
// Data URLs (azurdata repo — for runtime fetch)
|
|
13
|
+
const DATA_REPO = "AzurAPI";
|
|
14
|
+
exports.DATA_BASE_URL = `https://raw.githubusercontent.com/${GITHUB_USER}/${DATA_REPO}/${GITHUB_BRANCH}/data`;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Ships = exports.AzurData = void 0;
|
|
4
|
+
var index_js_1 = require("./client/index.js");
|
|
5
|
+
Object.defineProperty(exports, "AzurData", { enumerable: true, get: function () { return index_js_1.AzurData; } });
|
|
6
|
+
Object.defineProperty(exports, "Ships", { enumerable: true, get: function () { return index_js_1.Ships; } });
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.loadShipDataTemplate = loadShipDataTemplate;
|
|
7
|
+
exports.loadShipDataStatistics = loadShipDataStatistics;
|
|
8
|
+
exports.loadShipDataBreakout = loadShipDataBreakout;
|
|
9
|
+
exports.loadShipSkinWords = loadShipSkinWords;
|
|
10
|
+
exports.loadShopTemplate = loadShopTemplate;
|
|
11
|
+
exports.loadShipDataStrengthen = loadShipDataStrengthen;
|
|
12
|
+
exports.loadShipDataBlueprint = loadShipDataBlueprint;
|
|
13
|
+
exports.loadShipDataTrans = loadShipDataTrans;
|
|
14
|
+
exports.loadShipDataGroup = loadShipDataGroup;
|
|
15
|
+
exports.loadShipSkinTemplate = loadShipSkinTemplate;
|
|
16
|
+
exports.loadTransformDataTemplate = loadTransformDataTemplate;
|
|
17
|
+
exports.loadFleetTechShipTemplate = loadFleetTechShipTemplate;
|
|
18
|
+
exports.loadFleetTechShipClass = loadFleetTechShipClass;
|
|
19
|
+
exports.loadFleetTechGroup = loadFleetTechGroup;
|
|
20
|
+
exports.loadShipDataByType = loadShipDataByType;
|
|
21
|
+
exports.loadShipDataByStar = loadShipDataByStar;
|
|
22
|
+
exports.loadSkillDataTemplate = loadSkillDataTemplate;
|
|
23
|
+
exports.loadSkillDataDisplay = loadSkillDataDisplay;
|
|
24
|
+
exports.loadVoiceActorCn = loadVoiceActorCn;
|
|
25
|
+
exports.loadEquipDataByType = loadEquipDataByType;
|
|
26
|
+
exports.loadShipDataCreateExchange = loadShipDataCreateExchange;
|
|
27
|
+
exports.loadAttributeInfoByType = loadAttributeInfoByType;
|
|
28
|
+
const fs_1 = __importDefault(require("fs"));
|
|
29
|
+
const index_js_1 = require("../schema/raw/index.js");
|
|
30
|
+
const upstream_js_1 = require("./upstream.js");
|
|
31
|
+
function readJsonFile(filePath) {
|
|
32
|
+
try {
|
|
33
|
+
const raw = fs_1.default.readFileSync(filePath, "utf-8");
|
|
34
|
+
const parsed = JSON.parse(raw);
|
|
35
|
+
// Many upstream files have an "all" key containing an array of IDs
|
|
36
|
+
// (an index listing all record keys). Strip it before validation.
|
|
37
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
38
|
+
const obj = parsed;
|
|
39
|
+
if ("all" in obj && Array.isArray(obj["all"])) {
|
|
40
|
+
const { all: _all, ...rest } = obj;
|
|
41
|
+
return rest;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return parsed;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// File missing or unreadable — treat as empty
|
|
48
|
+
return {};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function loadFile(schema, filePath) {
|
|
52
|
+
const data = readJsonFile(filePath);
|
|
53
|
+
// Empty object stub — return as-is (valid empty record)
|
|
54
|
+
if (data !== null && typeof data === "object" && !Array.isArray(data) && Object.keys(data).length === 0) {
|
|
55
|
+
return {};
|
|
56
|
+
}
|
|
57
|
+
const result = schema.safeParse(data);
|
|
58
|
+
if (!result.success) {
|
|
59
|
+
throw new Error(`Zod parse failed for file: ${filePath}\n${result.error.message}`);
|
|
60
|
+
}
|
|
61
|
+
return result.data;
|
|
62
|
+
}
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// sharecfgdata/ files
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
function loadShipDataTemplate(region = "EN") {
|
|
67
|
+
return loadFile(index_js_1.ShipDataTemplateSchema, (0, upstream_js_1.regionPath)(region, "sharecfgdata", "ship_data_template.json"));
|
|
68
|
+
}
|
|
69
|
+
function loadShipDataStatistics(region = "EN") {
|
|
70
|
+
return loadFile(index_js_1.ShipDataStatisticsSchema, (0, upstream_js_1.regionPath)(region, "sharecfgdata", "ship_data_statistics.json"));
|
|
71
|
+
}
|
|
72
|
+
function loadShipDataBreakout(region = "EN") {
|
|
73
|
+
return loadFile(index_js_1.ShipDataBreakoutSchema, (0, upstream_js_1.regionPath)(region, "sharecfgdata", "ship_data_breakout.json"));
|
|
74
|
+
}
|
|
75
|
+
function loadShipSkinWords(region = "EN") {
|
|
76
|
+
return loadFile(index_js_1.ShipSkinWordsSchema, (0, upstream_js_1.regionPath)(region, "sharecfgdata", "ship_skin_words.json"));
|
|
77
|
+
}
|
|
78
|
+
function loadShopTemplate(region = "EN") {
|
|
79
|
+
return loadFile(index_js_1.ShopTemplateSchema, (0, upstream_js_1.regionPath)(region, "sharecfgdata", "shop_template.json"));
|
|
80
|
+
}
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// ShareCfg/ files
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
function loadShipDataStrengthen(region = "EN") {
|
|
85
|
+
return loadFile(index_js_1.ShipDataStrengthenSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "ship_data_strengthen.json"));
|
|
86
|
+
}
|
|
87
|
+
function loadShipDataBlueprint(region = "EN") {
|
|
88
|
+
return loadFile(index_js_1.ShipDataBlueprintSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "ship_data_blueprint.json"));
|
|
89
|
+
}
|
|
90
|
+
function loadShipDataTrans(region = "EN") {
|
|
91
|
+
return loadFile(index_js_1.ShipDataTransSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "ship_data_trans.json"));
|
|
92
|
+
}
|
|
93
|
+
function loadShipDataGroup(region = "EN") {
|
|
94
|
+
return loadFile(index_js_1.ShipDataGroupSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "ship_data_group.json"));
|
|
95
|
+
}
|
|
96
|
+
function loadShipSkinTemplate(region = "EN") {
|
|
97
|
+
return loadFile(index_js_1.ShipSkinTemplateSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "ship_skin_template.json"));
|
|
98
|
+
}
|
|
99
|
+
function loadTransformDataTemplate(region = "EN") {
|
|
100
|
+
return loadFile(index_js_1.TransformDataTemplateSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "transform_data_template.json"));
|
|
101
|
+
}
|
|
102
|
+
function loadFleetTechShipTemplate(region = "EN") {
|
|
103
|
+
return loadFile(index_js_1.FleetTechShipTemplateSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "fleet_tech_ship_template.json"));
|
|
104
|
+
}
|
|
105
|
+
function loadFleetTechShipClass(region = "EN") {
|
|
106
|
+
return loadFile(index_js_1.FleetTechShipClassSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "fleet_tech_ship_class.json"));
|
|
107
|
+
}
|
|
108
|
+
function loadFleetTechGroup(region = "EN") {
|
|
109
|
+
return loadFile(index_js_1.FleetTechGroupSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "fleet_tech_group.json"));
|
|
110
|
+
}
|
|
111
|
+
function loadShipDataByType(region = "EN") {
|
|
112
|
+
return loadFile(index_js_1.ShipDataByTypeSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "ship_data_by_type.json"));
|
|
113
|
+
}
|
|
114
|
+
function loadShipDataByStar(region = "EN") {
|
|
115
|
+
return loadFile(index_js_1.ShipDataByStarSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "ship_data_by_star.json"));
|
|
116
|
+
}
|
|
117
|
+
function loadSkillDataTemplate(region = "EN") {
|
|
118
|
+
return loadFile(index_js_1.SkillDataTemplateSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "skill_data_template.json"));
|
|
119
|
+
}
|
|
120
|
+
function loadSkillDataDisplay(region = "EN") {
|
|
121
|
+
return loadFile(index_js_1.SkillDataDisplaySchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "skill_data_display.json"));
|
|
122
|
+
}
|
|
123
|
+
function loadVoiceActorCn(region = "EN") {
|
|
124
|
+
return loadFile(index_js_1.VoiceActorCnSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "voice_actor_CN.json"));
|
|
125
|
+
}
|
|
126
|
+
function loadEquipDataByType(region = "EN") {
|
|
127
|
+
return loadFile(index_js_1.EquipDataByTypeSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "equip_data_by_type.json"));
|
|
128
|
+
}
|
|
129
|
+
function loadShipDataCreateExchange(region = "EN") {
|
|
130
|
+
return loadFile(index_js_1.ShipDataCreateExchangeSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "ship_data_create_exchange.json"));
|
|
131
|
+
}
|
|
132
|
+
function loadAttributeInfoByType(region = "EN") {
|
|
133
|
+
return loadFile(index_js_1.AttributeInfoByTypeSchema, (0, upstream_js_1.regionPath)(region, "ShareCfg", "attribute_info_by_type.json"));
|
|
134
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./upstream.js"), exports);
|
|
18
|
+
__exportStar(require("./files.js"), exports);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.UPSTREAM_ROOT = void 0;
|
|
7
|
+
exports.regionPath = regionPath;
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
exports.UPSTREAM_ROOT = path_1.default.resolve(process.cwd(), "upstream/azurlane-data");
|
|
10
|
+
function regionPath(region, ...segments) {
|
|
11
|
+
return path_1.default.join(exports.UPSTREAM_ROOT, region, ...segments);
|
|
12
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeConstruction = normalizeConstruction;
|
|
4
|
+
const enums_js_1 = require("../translate/enums.js");
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Internal helpers
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
/**
|
|
9
|
+
* Flatten all string tokens from a description entry tuple.
|
|
10
|
+
* description entries are [string, unknown, number?] tuples.
|
|
11
|
+
*/
|
|
12
|
+
function descEntryText(entry) {
|
|
13
|
+
return entry[0];
|
|
14
|
+
}
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Main
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
function normalizeConstruction(inputs) {
|
|
19
|
+
const { groupType, groupRow, lb3RowId, shipType, initialStar, fleetTechShipTemplate, shipDataCreateExchange, shipDataByType, shipDataByStar, lookups, constructionTimeOverride, } = inputs;
|
|
20
|
+
const result = {};
|
|
21
|
+
// -------------------------------------------------------------------------
|
|
22
|
+
// 1. construction.availableIn
|
|
23
|
+
// -------------------------------------------------------------------------
|
|
24
|
+
const descriptions = groupRow.description ?? [];
|
|
25
|
+
let lightFlag = false;
|
|
26
|
+
let heavyFlag = false;
|
|
27
|
+
let aviationFlag = false;
|
|
28
|
+
let limitedFlag = false;
|
|
29
|
+
for (const entry of descriptions) {
|
|
30
|
+
const text = descEntryText(entry);
|
|
31
|
+
const lower = text.toLowerCase();
|
|
32
|
+
if (lower.includes("light construction") ||
|
|
33
|
+
(lower.includes("light") && lower.includes("construction"))) {
|
|
34
|
+
lightFlag = true;
|
|
35
|
+
}
|
|
36
|
+
if (lower.includes("heavy construction") ||
|
|
37
|
+
(lower.includes("heavy") && lower.includes("construction"))) {
|
|
38
|
+
heavyFlag = true;
|
|
39
|
+
}
|
|
40
|
+
if (lower.includes("special construction") ||
|
|
41
|
+
(lower.includes("aviation") && lower.includes("construction"))) {
|
|
42
|
+
aviationFlag = true;
|
|
43
|
+
}
|
|
44
|
+
if (lower.startsWith("event:") ||
|
|
45
|
+
lower === "limited build") {
|
|
46
|
+
limitedFlag = true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// exchange: true if lb3RowId appears as a value in any exchange_ship_id array
|
|
50
|
+
let exchangeFlag = false;
|
|
51
|
+
const lb3RowIdNum = Number(lb3RowId);
|
|
52
|
+
for (const exchangeRow of Object.values(shipDataCreateExchange)) {
|
|
53
|
+
if (exchangeRow === undefined)
|
|
54
|
+
continue;
|
|
55
|
+
const ids = exchangeRow.exchange_ship_id ?? [];
|
|
56
|
+
if (ids.includes(lb3RowIdNum)) {
|
|
57
|
+
exchangeFlag = true;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const anyAvailableIn = lightFlag || heavyFlag || aviationFlag || limitedFlag || exchangeFlag;
|
|
62
|
+
const hasConstructionTime = constructionTimeOverride !== undefined;
|
|
63
|
+
if (anyAvailableIn || hasConstructionTime) {
|
|
64
|
+
const availableIn = anyAvailableIn
|
|
65
|
+
? {
|
|
66
|
+
light: lightFlag,
|
|
67
|
+
heavy: heavyFlag,
|
|
68
|
+
aviation: aviationFlag,
|
|
69
|
+
limited: limitedFlag,
|
|
70
|
+
exchange: exchangeFlag,
|
|
71
|
+
}
|
|
72
|
+
: undefined;
|
|
73
|
+
result.construction = {
|
|
74
|
+
...(hasConstructionTime ? { constructionTime: constructionTimeOverride } : {}),
|
|
75
|
+
...(availableIn !== undefined ? { availableIn } : {}),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// -------------------------------------------------------------------------
|
|
79
|
+
// 2. scrapValue
|
|
80
|
+
// -------------------------------------------------------------------------
|
|
81
|
+
const typeRow = shipDataByType[String(shipType)];
|
|
82
|
+
const goldRatio = typeRow?.distory_resource_gold_ratio ?? 0;
|
|
83
|
+
const fixGold = typeRow?.fix_resource_gold ?? 0;
|
|
84
|
+
const coin = Math.floor(goldRatio * 120 + fixGold);
|
|
85
|
+
// medal: from ship_data_by_star[initialStar].destory_item — find item_id === 15001
|
|
86
|
+
const starRow = shipDataByStar[String(initialStar)];
|
|
87
|
+
const destroyItems = starRow?.destory_item ?? [];
|
|
88
|
+
let medal = 0;
|
|
89
|
+
for (const [, itemId, qty] of destroyItems) {
|
|
90
|
+
if (itemId === 15001) {
|
|
91
|
+
medal = qty;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (coin > 0 || medal > 0) {
|
|
96
|
+
result.scrapValue = { coin, oil: 0, medal };
|
|
97
|
+
}
|
|
98
|
+
// -------------------------------------------------------------------------
|
|
99
|
+
// 3. fleetTech
|
|
100
|
+
// -------------------------------------------------------------------------
|
|
101
|
+
const techRow = fleetTechShipTemplate[groupType];
|
|
102
|
+
if (techRow !== undefined) {
|
|
103
|
+
const collection = techRow.pt_get;
|
|
104
|
+
const maxLimitBreak = techRow.pt_upgrage;
|
|
105
|
+
const maxLevel = techRow.pt_level;
|
|
106
|
+
const total = collection + maxLimitBreak + maxLevel;
|
|
107
|
+
const techPoints = {
|
|
108
|
+
collection,
|
|
109
|
+
maxLimitBreak,
|
|
110
|
+
maxLevel,
|
|
111
|
+
total,
|
|
112
|
+
};
|
|
113
|
+
// collection bonus
|
|
114
|
+
let collectionBonus;
|
|
115
|
+
if (techRow.add_get_attr !== 0 && techRow.add_get_value !== 0) {
|
|
116
|
+
collectionBonus = {
|
|
117
|
+
stat: enums_js_1.FLEET_TECH_STAT_MAP[techRow.add_get_attr] ?? "unknown",
|
|
118
|
+
bonus: techRow.add_get_value,
|
|
119
|
+
applicable: techRow.add_get_shiptype.map((id) => lookups.hullTypeName(id)),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
// maxLevel bonus
|
|
123
|
+
let maxLevelBonus;
|
|
124
|
+
if (techRow.add_level_attr !== 0 && techRow.add_level_value !== 0) {
|
|
125
|
+
maxLevelBonus = {
|
|
126
|
+
stat: enums_js_1.FLEET_TECH_STAT_MAP[techRow.add_level_attr] ?? "unknown",
|
|
127
|
+
bonus: techRow.add_level_value,
|
|
128
|
+
applicable: techRow.add_level_shiptype.map((id) => lookups.hullTypeName(id)),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
result.fleetTech = {
|
|
132
|
+
techPoints,
|
|
133
|
+
statsBonus: {
|
|
134
|
+
...(collectionBonus !== undefined ? { collection: collectionBonus } : {}),
|
|
135
|
+
...(maxLevelBonus !== undefined ? { maxLevel: maxLevelBonus } : {}),
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
// -------------------------------------------------------------------------
|
|
140
|
+
// 4. obtainedFrom
|
|
141
|
+
// -------------------------------------------------------------------------
|
|
142
|
+
const mapPrefixes = ["explore chapter", "exploring stage"];
|
|
143
|
+
const fromMaps = [];
|
|
144
|
+
let firstNonMapText;
|
|
145
|
+
for (const entry of descriptions) {
|
|
146
|
+
const text = descEntryText(entry);
|
|
147
|
+
const lower = text.toLowerCase();
|
|
148
|
+
const isMap = mapPrefixes.some((prefix) => lower.startsWith(prefix));
|
|
149
|
+
if (isMap) {
|
|
150
|
+
// Extract the stage code using a regex: match Chapter/Stage followed by digits/dashes
|
|
151
|
+
const match = /\b(?:Chapter|Stage)\s+([0-9\-SEX\s]+)/i.exec(text);
|
|
152
|
+
if (match !== null && match[1] !== undefined) {
|
|
153
|
+
fromMaps.push(`Chapter ${match[1].trim()}`);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
// Fallback: take last whitespace-separated token
|
|
157
|
+
const tokens = text.trim().split(/\s+/);
|
|
158
|
+
const last = tokens[tokens.length - 1];
|
|
159
|
+
if (last !== undefined) {
|
|
160
|
+
fromMaps.push(last);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else if (firstNonMapText === undefined) {
|
|
165
|
+
firstNonMapText = text;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
let obtainedFromStr;
|
|
169
|
+
if (firstNonMapText !== undefined) {
|
|
170
|
+
obtainedFromStr = firstNonMapText;
|
|
171
|
+
}
|
|
172
|
+
else if (fromMaps.length > 0) {
|
|
173
|
+
obtainedFromStr = "Map Drop";
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
obtainedFromStr = "Unknown";
|
|
177
|
+
}
|
|
178
|
+
const shouldEmitObtainedFrom = fromMaps.length > 0 || obtainedFromStr !== "Unknown";
|
|
179
|
+
if (shouldEmitObtainedFrom) {
|
|
180
|
+
result.obtainedFrom = {
|
|
181
|
+
...(fromMaps.length > 0 ? { fromMaps } : {}),
|
|
182
|
+
obtainedFrom: obtainedFromStr,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
return result;
|
|
186
|
+
}
|