wuira 0.2.3 → 0.2.5
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/CHANGELOG.md +38 -0
- package/README.md +62 -792
- package/data/icons/forever.json +90051 -0
- package/docs/icons.md +28 -0
- package/docs/source-converters.md +34 -0
- package/lib/datasources/DataSource.d.ts +8 -0
- package/lib/datasources/DataSource.lua +7 -0
- package/lib/datasources/GroupMembers.d.ts +6 -0
- package/lib/datasources/GroupMembers.lua +332 -0
- package/lib/datasources/GroupRoster.d.ts +28 -0
- package/lib/datasources/GroupRoster.lua +611 -0
- package/lib/datasources/MathConverter.d.ts +6 -0
- package/lib/datasources/MathConverter.lua +61 -0
- package/lib/datasources/MathExpression.d.ts +16 -0
- package/lib/datasources/MathExpression.lua +281 -0
- package/lib/datasources/Resources.d.ts +3 -2
- package/lib/datasources/Resources.lua +57 -48
- package/lib/datasources/SourceConverter.d.ts +39 -0
- package/lib/datasources/SourceConverter.lua +568 -0
- package/lib/datasources/UnitInfo.d.ts +6 -0
- package/lib/datasources/UnitInfo.lua +347 -15
- package/lib/datasources/UnitSource.d.ts +8 -3
- package/lib/datasources/UnitSource.lua +318 -5
- package/lib/datasources/index.d.ts +7 -1
- package/lib/datasources/index.lua +15 -0
- package/lib/icons/index.d.ts +45634 -0
- package/lib/icons/index.lua +3 -0
- package/lib/index.d.ts +1 -0
- package/lib/store/index.lua +20 -18
- package/lib/ui/Cell.d.ts +2 -0
- package/lib/ui/ForEach.d.ts +18 -4
- package/lib/ui/ForEach.lua +763 -13
- package/lib/ui/index.d.ts +1 -1
- package/package.json +20 -4
- package/tools/build-library.mjs +1 -1
- package/tools/generate-icons.mjs +10 -0
- package/tools/icon-data.mjs +59 -0
- package/tools/update-icons.mjs +36 -0
package/lib/ui/index.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export { Window } from "./Window";
|
|
|
18
18
|
export { TextInput } from "./TextInput";
|
|
19
19
|
export { ScrollHost } from "./ScrollHost";
|
|
20
20
|
export type { WindowOptions } from "./Window";
|
|
21
|
-
export type { ForEachProps } from "./ForEach";
|
|
21
|
+
export type { ForEachProps, ForEachSource } from "./ForEach";
|
|
22
22
|
export { GridLayout } from "./GridLayout";
|
|
23
23
|
export { ProgressBar } from "./ProgressBar";
|
|
24
24
|
export { Background } from "./decorations/Background";
|
package/package.json
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wuira",
|
|
3
|
-
"
|
|
3
|
+
"repository": {
|
|
4
|
+
"type": "git",
|
|
5
|
+
"url": "git+https://github.com/KerimCETINBAS/wuira.git"
|
|
6
|
+
},
|
|
7
|
+
"version": "0.2.5",
|
|
4
8
|
"author": {
|
|
5
9
|
"name": "Kerim Cetinbas",
|
|
6
10
|
"email": "a.cetinbas@icloud.com"
|
|
@@ -42,7 +46,11 @@
|
|
|
42
46
|
},
|
|
43
47
|
"./config/tsconfig.json": "./config/tsconfig.json",
|
|
44
48
|
"./tools/wow-modules.mjs": "./tools/wow-modules.mjs",
|
|
45
|
-
"./package.json": "./package.json"
|
|
49
|
+
"./package.json": "./package.json",
|
|
50
|
+
"./icons": {
|
|
51
|
+
"types": "./lib/icons/index.d.ts",
|
|
52
|
+
"default": "./lib/icons/index.lua"
|
|
53
|
+
}
|
|
46
54
|
},
|
|
47
55
|
"typesVersions": {
|
|
48
56
|
"*": {
|
|
@@ -66,6 +74,9 @@
|
|
|
66
74
|
],
|
|
67
75
|
"console-polyfill": [
|
|
68
76
|
"lib/console-polyfill.d.ts"
|
|
77
|
+
],
|
|
78
|
+
"icons": [
|
|
79
|
+
"lib/icons/index.d.ts"
|
|
69
80
|
]
|
|
70
81
|
}
|
|
71
82
|
},
|
|
@@ -81,7 +92,10 @@
|
|
|
81
92
|
"tsconfig.lib.json",
|
|
82
93
|
"README.md",
|
|
83
94
|
"CHANGELOG.md",
|
|
84
|
-
"LICENSE"
|
|
95
|
+
"LICENSE",
|
|
96
|
+
"data/icons/forever.json",
|
|
97
|
+
"docs/icons.md",
|
|
98
|
+
"docs/source-converters.md"
|
|
85
99
|
],
|
|
86
100
|
"engines": {
|
|
87
101
|
"node": ">=22.13"
|
|
@@ -97,7 +111,9 @@
|
|
|
97
111
|
"check": "tsc -p tsconfig.json --noEmit",
|
|
98
112
|
"spells:update": "node tools/update-spells.mjs",
|
|
99
113
|
"spells:generate": "node tools/generate-spells.mjs",
|
|
100
|
-
"test": "node --test tests/*.test.cjs"
|
|
114
|
+
"test": "node --test tests/*.test.cjs",
|
|
115
|
+
"icons:update": "node tools/update-icons.mjs",
|
|
116
|
+
"icons:generate": "node tools/generate-icons.mjs"
|
|
101
117
|
},
|
|
102
118
|
"devDependencies": {
|
|
103
119
|
"fengari-node-cli": "0.1.0"
|
package/tools/build-library.mjs
CHANGED
|
@@ -12,7 +12,7 @@ const result = spawnSync(process.execPath, [require.resolve("typescript-to-lua/d
|
|
|
12
12
|
if (result.status !== 0) process.exit(result.status || 1);
|
|
13
13
|
fs.mkdirSync(path.join(root, "lib/platform"), { recursive: true });
|
|
14
14
|
fs.copyFileSync(path.join(root, "src/platform/forever.d.ts"), path.join(root, "lib/platform/forever.d.ts"));
|
|
15
|
-
for (const file of ["index.d.ts", "ui/index.d.ts", "datasources/index.d.ts", "store/index.d.ts", "skins/index.d.ts", "spells/index.d.ts"]) {
|
|
15
|
+
for (const file of ["index.d.ts", "ui/index.d.ts", "datasources/index.d.ts", "store/index.d.ts", "skins/index.d.ts", "spells/index.d.ts", "icons/index.d.ts"]) {
|
|
16
16
|
const target = path.join(root, "lib", file);
|
|
17
17
|
const reference = file === "index.d.ts" ? "./platform/forever.d.ts" : "../platform/forever.d.ts";
|
|
18
18
|
fs.writeFileSync(target, `/// <reference path="${reference}" />\n` + fs.readFileSync(target, "utf8"));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { iconEnumSource } from "./icon-data.mjs";
|
|
4
|
+
const root = path.resolve(import.meta.dirname, "..");
|
|
5
|
+
const catalog = JSON.parse(fs.readFileSync(path.join(root,"data/icons/forever.json"),"utf8"));
|
|
6
|
+
const spells = JSON.parse(fs.readFileSync(path.join(root, "data/spells/forever.json"), "utf8"));
|
|
7
|
+
if (catalog.build !== spells.build || catalog.product !== spells.product) throw new Error("Icon and spell builds must match");
|
|
8
|
+
const output=path.join(root,"src/icons");fs.mkdirSync(output,{recursive:true});
|
|
9
|
+
fs.writeFileSync(path.join(output, "index.ts"), iconEnumSource(catalog));
|
|
10
|
+
console.log("Generated " + catalog.icons.length + " native icon IDs");
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** Build-time catalog data. Nothing in this module runs inside the game. */
|
|
2
|
+
export function collectIcons(spells, tables) {
|
|
3
|
+
const spellNames = new Map(spells.spells.map(row => [row[0], row]));
|
|
4
|
+
const itemNames = new Map(tables.ItemSparse.map(row => [Number(row.ID), row.Display_lang]));
|
|
5
|
+
if (!tables.SpellMisc.length || !tables.SpellMisc.every(row => "SpellIconFileDataID" in row && "ActiveIconFileDataID" in row && "SpellID" in row)
|
|
6
|
+
|| !tables.Item.length || !tables.Item.every(row => "IconFileDataID" in row)
|
|
7
|
+
|| !tables.ItemSparse.length || !tables.ItemSparse.every(row => "Display_lang" in row)) throw new Error("Unexpected client icon schema");
|
|
8
|
+
const icons = new Map();
|
|
9
|
+
const add = (value, name, kind, priority) => {
|
|
10
|
+
const id = Number(value);
|
|
11
|
+
if (!Number.isSafeInteger(id) || id < 0) throw new Error("Invalid icon FileDataID");
|
|
12
|
+
if (id === 0) return;
|
|
13
|
+
const icon = icons.get(id) ?? { id, names: new Map(), kinds: new Set() };
|
|
14
|
+
const label = name.trim();
|
|
15
|
+
icon.names.set(label, Math.min(icon.names.get(label) ?? Infinity, priority));
|
|
16
|
+
icon.kinds.add(kind); icons.set(id, icon);
|
|
17
|
+
};
|
|
18
|
+
for (const row of tables.SpellMisc) {
|
|
19
|
+
const spell = spellNames.get(Number(row.SpellID));
|
|
20
|
+
const name = spell?.[1]?.trim() || "Spell " + row.SpellID;
|
|
21
|
+
const priority = spell?.[4] ? 0 : spell ? 2 : 4;
|
|
22
|
+
add(row.SpellIconFileDataID, name, "spell", priority);
|
|
23
|
+
add(row.ActiveIconFileDataID, name + " (active)", "spell", priority + 1);
|
|
24
|
+
}
|
|
25
|
+
for (const row of tables.Item) {
|
|
26
|
+
const name = itemNames.get(Number(row.ID))?.trim();
|
|
27
|
+
add(row.IconFileDataID, name || "Item " + row.ID, "item", name ? 1 : 4);
|
|
28
|
+
}
|
|
29
|
+
return [...icons.values()].sort((a, b) => a.id - b.id).map(icon => {
|
|
30
|
+
const names = [...icon.names].sort(([a, pa], [b, pb]) => pa - pb || (a < b ? -1 : a > b ? 1 : 0)).map(([name]) => name);
|
|
31
|
+
return [icon.id, names[0], names, [...icon.kinds].sort()];
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function iconEnumSource(catalog) {
|
|
36
|
+
if (catalog.version !== 1 || catalog.product !== "wow_classic_beta" || !/^1\.60\./.test(catalog.build)) throw new Error("Unsupported icon catalog");
|
|
37
|
+
const identifier = name => {
|
|
38
|
+
const value = name.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").replace(/['’]/g, "")
|
|
39
|
+
.split(/[^A-Za-z0-9]+/).filter(Boolean).map(word => word[0].toUpperCase() + word.slice(1)).join("");
|
|
40
|
+
return /^[A-Za-z]/.test(value) ? value : "Icon" + value;
|
|
41
|
+
};
|
|
42
|
+
const ids = new Set(), aliases = new Map(), occupied = new Set(), lines = [];
|
|
43
|
+
for (const [id, name, names] of catalog.icons) {
|
|
44
|
+
if (!Number.isSafeInteger(id) || id < 1 || ids.has(id) || !name || !Array.isArray(names) || !names.includes(name)) throw new Error("Invalid icon record: " + id);
|
|
45
|
+
ids.add(id);
|
|
46
|
+
const key = identifier(name) + "_" + id;
|
|
47
|
+
occupied.add(key); lines.push(" " + key + " = " + id + ",");
|
|
48
|
+
for (const alias of names) {
|
|
49
|
+
const key = identifier(alias);
|
|
50
|
+
if (!aliases.has(key)) aliases.set(key, new Set());
|
|
51
|
+
aliases.get(key).add(id);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
for (const [name, values] of [...aliases].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) if (values.size === 1 && !occupied.has(name)) {
|
|
55
|
+
occupied.add(name); lines.push(" " + name + " = " + [...values][0] + ",");
|
|
56
|
+
}
|
|
57
|
+
return "// Auto generated. Do not edit.\n// Source: Forever " + catalog.build + "; run npm run icons:generate.\n"
|
|
58
|
+
+ "/** Native texture FileDataIDs, independent of spell and action IDs. */\nexport const enum Icons {\n" + lines.join("\n") + "\n}\n";
|
|
59
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { parseCSV } from "./spell-data.mjs";
|
|
5
|
+
import { collectIcons } from "./icon-data.mjs";
|
|
6
|
+
const root = path.resolve(import.meta.dirname, "..");
|
|
7
|
+
const argument = name => process.argv[process.argv.indexOf(name) + 1];
|
|
8
|
+
const build = process.argv.includes("--build") ? argument("--build") : undefined;
|
|
9
|
+
const spells = JSON.parse(fs.readFileSync(path.join(root, "data/spells/forever.json"), "utf8"));
|
|
10
|
+
if (!build || !build.startsWith("1.60.") || build !== spells.build || spells.product !== "wow_classic_beta") throw new Error("Use the same verified Forever build as the spell catalog");
|
|
11
|
+
const cached = process.argv.includes("--cached"), directory = path.join(root, "data/icons/.cache", build);
|
|
12
|
+
fs.mkdirSync(directory, { recursive: true });
|
|
13
|
+
const hash = value => createHash("sha256").update(value).digest("hex"), sources = [];
|
|
14
|
+
async function table(name) {
|
|
15
|
+
const url = "https://wago.tools/db2/" + name + "/csv?build=" + build, file = path.join(directory, name + ".csv");
|
|
16
|
+
let text;
|
|
17
|
+
if (cached) text = fs.readFileSync(file, "utf8");
|
|
18
|
+
else {
|
|
19
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(60000) });
|
|
20
|
+
if (!response.ok || !response.headers.get("content-type")?.includes("text/csv")) throw new Error("Icon data download failed: " + name + " (" + response.status + ")");
|
|
21
|
+
text = await response.text(); fs.writeFileSync(file, text);
|
|
22
|
+
}
|
|
23
|
+
const rows = parseCSV(text); sources.push({ table: name, url, sha256: hash(text), rows: rows.length }); return [name, rows];
|
|
24
|
+
}
|
|
25
|
+
const results = await Promise.allSettled(["SpellMisc", "Item", "ItemSparse"].map(table));
|
|
26
|
+
const failures = results.filter(result => result.status === "rejected");
|
|
27
|
+
if (failures.length) throw new AggregateError(failures.map(result => result.reason), "Icon data download failed");
|
|
28
|
+
const tables = Object.fromEntries(results.map(result => result.value));
|
|
29
|
+
const rows = collectIcons(spells, tables);
|
|
30
|
+
if (rows.length < 500) throw new Error("Icon catalog is unexpectedly small");
|
|
31
|
+
const catalog = { version: 1, product: spells.product, build, locale: spells.locale,
|
|
32
|
+
sources: sources.sort((a,b) => a.table.localeCompare(b.table)), spellCatalogSHA256: hash(JSON.stringify(spells)),
|
|
33
|
+
columns: ["fileDataId","name","aliases","kinds"], icons: rows };
|
|
34
|
+
fs.mkdirSync(path.join(root,"data/icons"),{recursive:true});
|
|
35
|
+
fs.writeFileSync(path.join(root,"data/icons/forever.json"),JSON.stringify(catalog,null,2)+"\n");
|
|
36
|
+
console.log("Saved "+rows.length+" spell/item icons for Forever "+build);
|