@xivdyetools/core 4.0.1 → 4.2.0
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/dist/blending/conversions.d.ts +24 -0
- package/dist/blending/conversions.d.ts.map +1 -1
- package/dist/blending/conversions.js +36 -3
- package/dist/blending/conversions.js.map +1 -1
- package/dist/constants/index.d.ts +24 -0
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/constants/index.js +38 -0
- package/dist/constants/index.js.map +1 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/services/APIService.d.ts.map +1 -1
- package/dist/services/APIService.js +23 -9
- package/dist/services/APIService.js.map +1 -1
- package/dist/services/CharacterColorService.d.ts +4 -0
- package/dist/services/CharacterColorService.d.ts.map +1 -1
- package/dist/services/CharacterColorService.js +17 -2
- package/dist/services/CharacterColorService.js.map +1 -1
- package/dist/services/LocalizationService.d.ts +8 -0
- package/dist/services/LocalizationService.d.ts.map +1 -1
- package/dist/services/LocalizationService.js +9 -1
- package/dist/services/LocalizationService.js.map +1 -1
- package/dist/services/PaletteService.d.ts +6 -1
- package/dist/services/PaletteService.d.ts.map +1 -1
- package/dist/services/PaletteService.js +7 -2
- package/dist/services/PaletteService.js.map +1 -1
- package/dist/services/chara/chara-parser.d.ts +7 -1
- package/dist/services/chara/chara-parser.d.ts.map +1 -1
- package/dist/services/chara/chara-parser.js.map +1 -1
- package/dist/services/dye/HarmonyGenerator.d.ts +3 -1
- package/dist/services/dye/HarmonyGenerator.d.ts.map +1 -1
- package/dist/services/dye/HarmonyGenerator.js +41 -8
- package/dist/services/dye/HarmonyGenerator.js.map +1 -1
- package/dist/services/dye/HarmonySelector.d.ts +107 -0
- package/dist/services/dye/HarmonySelector.d.ts.map +1 -0
- package/dist/services/dye/HarmonySelector.js +176 -0
- package/dist/services/dye/HarmonySelector.js.map +1 -0
- package/dist/services/localization/TranslationProvider.d.ts +11 -6
- package/dist/services/localization/TranslationProvider.d.ts.map +1 -1
- package/dist/services/localization/TranslationProvider.js +33 -28
- package/dist/services/localization/TranslationProvider.js.map +1 -1
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +14 -1
- package/dist/types/index.js.map +1 -1
- package/package.json +8 -8
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Harmony slot selection — the one implementation every surface uses.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this exists
|
|
5
|
+
*
|
|
6
|
+
* The web app and the Discord bot used to answer "which dyes make a triadic
|
|
7
|
+
* harmony with this one?" through completely different code, and they
|
|
8
|
+
* disagreed for **89–100 % of base dyes on every harmony type** (measured
|
|
9
|
+
* 2026-09-03 over all 125 dyes):
|
|
10
|
+
*
|
|
11
|
+
* - the page walked `HARMONY_OFFSETS`, built each target by carrying the base
|
|
12
|
+
* dye's SATURATION AND VALUE onto the rotated hue, and ranked candidates by
|
|
13
|
+
* the user's configured ΔE method;
|
|
14
|
+
* - the bot called a named `DyeService.find*Dyes()` per type, which rotates hue
|
|
15
|
+
* without preserving S/V — and `findComplementaryPair` did not rotate at all,
|
|
16
|
+
* it took an RGB `invert()`.
|
|
17
|
+
*
|
|
18
|
+
* For a desaturated base the difference is not subtle: `/harmony analogous` on
|
|
19
|
+
* Snow White returned Neon Green and Kobold Brown, where the page shows Pure
|
|
20
|
+
* White and Pearl White.
|
|
21
|
+
*
|
|
22
|
+
* This module is the page's algorithm, lifted verbatim so the page's output is
|
|
23
|
+
* unchanged and every other surface now matches it. `HARMONY_OFFSETS` supplies
|
|
24
|
+
* the geometry, so a harmony type is a row in a table rather than a method —
|
|
25
|
+
* which is why `compound` and `shades` work here without any new code.
|
|
26
|
+
*
|
|
27
|
+
* @module services/dye/HarmonySelector
|
|
28
|
+
*/
|
|
29
|
+
import { HARMONY_OFFSETS } from '../../constants/index.js';
|
|
30
|
+
import { ColorService } from '../ColorService.js';
|
|
31
|
+
/**
|
|
32
|
+
* The single definition of "how far is this dye from the slot's target".
|
|
33
|
+
*
|
|
34
|
+
* BUG-064: everything that scores a harmony row goes through here, so a panel
|
|
35
|
+
* can never mix ΔE units with degrees of hue — which is exactly what it used to
|
|
36
|
+
* do when a filtered-out companion's replacement was scored differently from
|
|
37
|
+
* its neighbours.
|
|
38
|
+
*/
|
|
39
|
+
function devianceFor(dye, targetHue, targetHex, config) {
|
|
40
|
+
if (config.usePerceptualMatching) {
|
|
41
|
+
return ColorService.getDistanceForMethod(targetHex, dye.hex, config.matchingMethod);
|
|
42
|
+
}
|
|
43
|
+
const dyeHue = ColorService.hexToHsv(dye.hex).h;
|
|
44
|
+
const hueDiff = Math.abs(dyeHue - targetHue);
|
|
45
|
+
return Math.min(hueDiff, 360 - hueDiff);
|
|
46
|
+
}
|
|
47
|
+
/** Every candidate scored against one slot's ideal, nearest first. */
|
|
48
|
+
function rankCandidates(candidates, targetHue, targetHex, config) {
|
|
49
|
+
const scored = [];
|
|
50
|
+
for (const dye of candidates) {
|
|
51
|
+
// Facewear carries generic names ("Red", "Blue") and is not a dye since
|
|
52
|
+
// schema v2; it must never surface as a harmony match.
|
|
53
|
+
if (dye.category === 'Facewear')
|
|
54
|
+
continue;
|
|
55
|
+
scored.push({ dye, deviance: devianceFor(dye, targetHue, targetHex, config) });
|
|
56
|
+
}
|
|
57
|
+
scored.sort((a, b) => a.deviance - b.deviance);
|
|
58
|
+
return scored;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Whether `harmonyType` is one this module can build.
|
|
62
|
+
*
|
|
63
|
+
* Every key of `HARMONY_OFFSETS` works, which is the point: a type is a row in
|
|
64
|
+
* that table, not a bespoke method, so the ten the page offers are the ten
|
|
65
|
+
* every surface can offer.
|
|
66
|
+
*/
|
|
67
|
+
export function isKnownHarmonyType(harmonyType) {
|
|
68
|
+
return Object.hasOwn(HARMONY_OFFSETS, harmonyType);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Choose a dye for every slot of a harmony.
|
|
72
|
+
*
|
|
73
|
+
* Callers filter `candidates` themselves — this function does not know about
|
|
74
|
+
* anyone's dye-filter shape, and pre-filtering is what makes "the nearest
|
|
75
|
+
* ALLOWED dye to the ideal" the answer, rather than "the nearest allowed dye to
|
|
76
|
+
* a dye that was thrown away".
|
|
77
|
+
*
|
|
78
|
+
* @param baseHex the colour the harmony is built around; supplies H, S and V
|
|
79
|
+
* @param harmonyType a key of `HARMONY_OFFSETS`
|
|
80
|
+
* @param candidates the pool to choose from, already filtered
|
|
81
|
+
* @param config ranking and de-duplication behaviour
|
|
82
|
+
* @param options dyes to exclude, and any slots the caller has pinned
|
|
83
|
+
* @returns one slot per offset; `dye` is `null` for a slot with no candidate
|
|
84
|
+
*/
|
|
85
|
+
export function generateHarmonySlots(baseHex, harmonyType, candidates, config, options) {
|
|
86
|
+
// Own-property check, not a truthiness one: `HARMONY_OFFSETS['toString']`
|
|
87
|
+
// returns Object.prototype.toString, which is TRUTHY, so a `!offsets` guard
|
|
88
|
+
// sails past it and the `.forEach` below throws. The web app reads this type
|
|
89
|
+
// straight out of a share URL (`?harmony=`), so the key really can be
|
|
90
|
+
// arbitrary.
|
|
91
|
+
if (!isKnownHarmonyType(harmonyType))
|
|
92
|
+
return [];
|
|
93
|
+
const offsets = HARMONY_OFFSETS[harmonyType];
|
|
94
|
+
const baseHsv = ColorService.hexToHsv(baseHex);
|
|
95
|
+
const companionCount = config.companionCount ?? 0;
|
|
96
|
+
const preventDuplicates = config.preventDuplicates ?? false;
|
|
97
|
+
// Two different questions, and they were one set until 2026-09-03.
|
|
98
|
+
//
|
|
99
|
+
// `excluded` is "must never be chosen" — normally the base dye itself, which
|
|
100
|
+
// is never a member of its own harmony. A custom colour has no dye to
|
|
101
|
+
// exclude, which is why this is a list rather than a required base dye:
|
|
102
|
+
// `/harmony color:#FF0000` has a hex and nothing else.
|
|
103
|
+
//
|
|
104
|
+
// `used` is "already on screen", and only matters when the caller asked for
|
|
105
|
+
// no repeats.
|
|
106
|
+
//
|
|
107
|
+
// Seeding `used` with the exclusions conflated them, and `used` is read only
|
|
108
|
+
// on the `preventDuplicates` branch — so with duplicates allowed the
|
|
109
|
+
// exclusions did nothing at all, against this function's own documented
|
|
110
|
+
// contract. bot-logic defaults `preventDuplicates` to false, so `/harmony
|
|
111
|
+
// monochromatic` (a single `[0]` offset, whose ideal IS the base colour)
|
|
112
|
+
// answered the base dye as its own harmony at deltaE 0, and `/harmony
|
|
113
|
+
// analogous` on a near-grey answered the base twice.
|
|
114
|
+
const excluded = new Set(options?.excludeItemIDs ?? []);
|
|
115
|
+
const used = new Set();
|
|
116
|
+
const slots = [];
|
|
117
|
+
offsets.forEach((offset, index) => {
|
|
118
|
+
const normalisedOffset = ((offset % 360) + 360) % 360;
|
|
119
|
+
const targetHue = (baseHsv.h + normalisedOffset) % 360;
|
|
120
|
+
// The ideal carries the BASE's saturation and value onto the rotated hue.
|
|
121
|
+
// That is the whole reason a desaturated base finds desaturated dyes, and
|
|
122
|
+
// the single biggest difference from the per-type find*Dyes() methods.
|
|
123
|
+
const targetHex = ColorService.hsvToHex(targetHue, baseHsv.s, baseHsv.v);
|
|
124
|
+
const ranked = rankCandidates(candidates, targetHue, targetHex, config);
|
|
125
|
+
const pin = options?.pinned?.get(index);
|
|
126
|
+
// Every branch below assigns, so no initialiser: an unread `= null` here
|
|
127
|
+
// would be one more place for a future edit to leave a slot silently empty.
|
|
128
|
+
let chosen;
|
|
129
|
+
if (pin) {
|
|
130
|
+
// An explicit hand-swap wins its slot outright, exclusions included: the
|
|
131
|
+
// user naming a dye outranks our guess about which dyes are eligible.
|
|
132
|
+
chosen = { dye: pin, deviance: devianceFor(pin, targetHue, targetHex, config) };
|
|
133
|
+
}
|
|
134
|
+
else if (preventDuplicates) {
|
|
135
|
+
// First eligible-and-unused, else the nearest eligible even if already
|
|
136
|
+
// shown: a slot with a dye repeated beats a slot left blank. An excluded
|
|
137
|
+
// dye is not a fallback in either case.
|
|
138
|
+
chosen =
|
|
139
|
+
ranked.find((c) => !excluded.has(c.dye.itemID) && !used.has(c.dye.itemID)) ??
|
|
140
|
+
ranked.find((c) => !excluded.has(c.dye.itemID)) ??
|
|
141
|
+
null;
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
chosen = ranked.find((c) => !excluded.has(c.dye.itemID)) ?? null;
|
|
145
|
+
}
|
|
146
|
+
if (chosen)
|
|
147
|
+
used.add(chosen.dye.itemID);
|
|
148
|
+
const companions = [];
|
|
149
|
+
if (companionCount > 0) {
|
|
150
|
+
for (const candidate of ranked) {
|
|
151
|
+
if (companions.length >= companionCount)
|
|
152
|
+
break;
|
|
153
|
+
if (excluded.has(candidate.dye.itemID))
|
|
154
|
+
continue;
|
|
155
|
+
if (chosen && candidate.dye.itemID === chosen.dye.itemID)
|
|
156
|
+
continue;
|
|
157
|
+
if (preventDuplicates && used.has(candidate.dye.itemID))
|
|
158
|
+
continue;
|
|
159
|
+
companions.push(candidate.dye);
|
|
160
|
+
if (preventDuplicates)
|
|
161
|
+
used.add(candidate.dye.itemID);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
slots.push({
|
|
165
|
+
index,
|
|
166
|
+
offset: normalisedOffset,
|
|
167
|
+
targetHue,
|
|
168
|
+
targetHex,
|
|
169
|
+
dye: chosen?.dye ?? null,
|
|
170
|
+
deviance: chosen?.deviance ?? 0,
|
|
171
|
+
companions,
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
return slots;
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=HarmonySelector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HarmonySelector.js","sourceRoot":"","sources":["../../../src/services/dye/HarmonySelector.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,12 +13,17 @@ import type { LocaleRegistry } from './LocaleRegistry.js';
|
|
|
13
13
|
*
|
|
14
14
|
* Fallback chain: requested locale → English → formatted key / original value
|
|
15
15
|
*
|
|
16
|
-
* BUG-007:
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
16
|
+
* BUG-007: every lookup keeps a truthiness check, which treats an empty string
|
|
17
|
+
* ("") as a missing translation and falls back to English. That is intentional —
|
|
18
|
+
* an empty string in a locale file means "not translated yet", and the Korean
|
|
19
|
+
* and Chinese locales are manually sourced with incomplete coverage. For
|
|
20
|
+
* detecting incomplete locale files at build time, see `build-locales.ts`.
|
|
21
|
+
*
|
|
22
|
+
* BUG-105: every lookup is ALSO guarded with `Object.hasOwn`, because a bare
|
|
23
|
+
* truthiness check on a plain object resolves through `Object.prototype` — a
|
|
24
|
+
* key of `'constructor'` or `'toString'` is truthy and returns a FUNCTION where
|
|
25
|
+
* a localized string is expected. FINDING-027 added that guard to `getLabel`
|
|
26
|
+
* alone; its ten siblings went without one until this pass.
|
|
22
27
|
*/
|
|
23
28
|
export declare class TranslationProvider {
|
|
24
29
|
private registry;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TranslationProvider.d.ts","sourceRoot":"","sources":["../../../src/services/localization/TranslationProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EACd,cAAc,EACd,UAAU,EACV,OAAO,EACP,QAAQ,EACR,OAAO,EACP,OAAO,EACR,MAAM,oBAAoB,CAAC;AAM5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D
|
|
1
|
+
{"version":3,"file":"TranslationProvider.d.ts","sourceRoot":"","sources":["../../../src/services/localization/TranslationProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EACd,cAAc,EACd,UAAU,EACV,OAAO,EACP,QAAQ,EACR,OAAO,EACP,OAAO,EACR,MAAM,oBAAoB,CAAC;AAM5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,mBAAmB;IAClB,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,cAAc;IAE5C;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAqBzD;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI;IA+B7D;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoBzD;;;;;;;;;;;;OAYG;IACH,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoB/D;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoBzD;;;;;;;;;;;;OAYG;IACH,cAAc,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoB/D;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoB1D;;;;;;;;;;;;;;;;OAgBG;IACH,cAAc,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAiB3D;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAiBrD;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAiBvD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoBjD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoBjD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,SAAS;CAMlB"}
|
|
@@ -12,12 +12,17 @@ import { CONSOLIDATED_DYES, CONSOLIDATED_IDS, } from '../../config/consolidated-
|
|
|
12
12
|
*
|
|
13
13
|
* Fallback chain: requested locale → English → formatted key / original value
|
|
14
14
|
*
|
|
15
|
-
* BUG-007:
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
15
|
+
* BUG-007: every lookup keeps a truthiness check, which treats an empty string
|
|
16
|
+
* ("") as a missing translation and falls back to English. That is intentional —
|
|
17
|
+
* an empty string in a locale file means "not translated yet", and the Korean
|
|
18
|
+
* and Chinese locales are manually sourced with incomplete coverage. For
|
|
19
|
+
* detecting incomplete locale files at build time, see `build-locales.ts`.
|
|
20
|
+
*
|
|
21
|
+
* BUG-105: every lookup is ALSO guarded with `Object.hasOwn`, because a bare
|
|
22
|
+
* truthiness check on a plain object resolves through `Object.prototype` — a
|
|
23
|
+
* key of `'constructor'` or `'toString'` is truthy and returns a FUNCTION where
|
|
24
|
+
* a localized string is expected. FINDING-027 added that guard to `getLabel`
|
|
25
|
+
* alone; its ten siblings went without one until this pass.
|
|
21
26
|
*/
|
|
22
27
|
export class TranslationProvider {
|
|
23
28
|
registry;
|
|
@@ -71,13 +76,13 @@ export class TranslationProvider {
|
|
|
71
76
|
const localeData = this.registry.getLocale(locale);
|
|
72
77
|
const idStr = String(itemID);
|
|
73
78
|
// Try requested locale
|
|
74
|
-
if (localeData?.dyeNames[idStr]) {
|
|
79
|
+
if (localeData?.dyeNames && Object.hasOwn(localeData.dyeNames, idStr) && localeData?.dyeNames[idStr]) {
|
|
75
80
|
return localeData.dyeNames[idStr];
|
|
76
81
|
}
|
|
77
82
|
// Fallback to English
|
|
78
83
|
if (locale !== 'en') {
|
|
79
84
|
const englishData = this.registry.getLocale('en');
|
|
80
|
-
if (englishData?.dyeNames[idStr]) {
|
|
85
|
+
if (englishData?.dyeNames && Object.hasOwn(englishData.dyeNames, idStr) && englishData?.dyeNames[idStr]) {
|
|
81
86
|
return englishData.dyeNames[idStr];
|
|
82
87
|
}
|
|
83
88
|
}
|
|
@@ -109,13 +114,13 @@ export class TranslationProvider {
|
|
|
109
114
|
getCategory(category, locale) {
|
|
110
115
|
const localeData = this.registry.getLocale(locale);
|
|
111
116
|
// Try requested locale
|
|
112
|
-
if (localeData?.categories[category]) {
|
|
117
|
+
if (localeData?.categories && Object.hasOwn(localeData.categories, category) && localeData?.categories[category]) {
|
|
113
118
|
return localeData.categories[category];
|
|
114
119
|
}
|
|
115
120
|
// Fallback to English
|
|
116
121
|
if (locale !== 'en') {
|
|
117
122
|
const englishData = this.registry.getLocale('en');
|
|
118
|
-
if (englishData?.categories[category]) {
|
|
123
|
+
if (englishData?.categories && Object.hasOwn(englishData.categories, category) && englishData?.categories[category]) {
|
|
119
124
|
return englishData.categories[category];
|
|
120
125
|
}
|
|
121
126
|
}
|
|
@@ -138,13 +143,13 @@ export class TranslationProvider {
|
|
|
138
143
|
getAcquisition(acquisition, locale) {
|
|
139
144
|
const localeData = this.registry.getLocale(locale);
|
|
140
145
|
// Try requested locale
|
|
141
|
-
if (localeData?.acquisitions[acquisition]) {
|
|
146
|
+
if (localeData?.acquisitions && Object.hasOwn(localeData.acquisitions, acquisition) && localeData?.acquisitions[acquisition]) {
|
|
142
147
|
return localeData.acquisitions[acquisition];
|
|
143
148
|
}
|
|
144
149
|
// Fallback to English
|
|
145
150
|
if (locale !== 'en') {
|
|
146
151
|
const englishData = this.registry.getLocale('en');
|
|
147
|
-
if (englishData?.acquisitions[acquisition]) {
|
|
152
|
+
if (englishData?.acquisitions && Object.hasOwn(englishData.acquisitions, acquisition) && englishData?.acquisitions[acquisition]) {
|
|
148
153
|
return englishData.acquisitions[acquisition];
|
|
149
154
|
}
|
|
150
155
|
}
|
|
@@ -167,13 +172,13 @@ export class TranslationProvider {
|
|
|
167
172
|
getCurrency(currency, locale) {
|
|
168
173
|
const localeData = this.registry.getLocale(locale);
|
|
169
174
|
// Try requested locale
|
|
170
|
-
if (localeData?.currencies
|
|
175
|
+
if (localeData?.currencies && Object.hasOwn(localeData.currencies, currency) && localeData.currencies[currency]) {
|
|
171
176
|
return localeData.currencies[currency];
|
|
172
177
|
}
|
|
173
178
|
// Fallback to English
|
|
174
179
|
if (locale !== 'en') {
|
|
175
180
|
const englishData = this.registry.getLocale('en');
|
|
176
|
-
if (englishData?.currencies
|
|
181
|
+
if (englishData?.currencies && Object.hasOwn(englishData.currencies, currency) && englishData.currencies[currency]) {
|
|
177
182
|
return englishData.currencies[currency];
|
|
178
183
|
}
|
|
179
184
|
}
|
|
@@ -196,13 +201,13 @@ export class TranslationProvider {
|
|
|
196
201
|
getHarmonyType(key, locale) {
|
|
197
202
|
const localeData = this.registry.getLocale(locale);
|
|
198
203
|
// Try requested locale
|
|
199
|
-
if (localeData?.harmonyTypes[key]) {
|
|
204
|
+
if (localeData?.harmonyTypes && Object.hasOwn(localeData.harmonyTypes, key) && localeData?.harmonyTypes[key]) {
|
|
200
205
|
return localeData.harmonyTypes[key];
|
|
201
206
|
}
|
|
202
207
|
// Fallback to English
|
|
203
208
|
if (locale !== 'en') {
|
|
204
209
|
const englishData = this.registry.getLocale('en');
|
|
205
|
-
if (englishData?.harmonyTypes[key]) {
|
|
210
|
+
if (englishData?.harmonyTypes && Object.hasOwn(englishData.harmonyTypes, key) && englishData?.harmonyTypes[key]) {
|
|
206
211
|
return englishData.harmonyTypes[key];
|
|
207
212
|
}
|
|
208
213
|
}
|
|
@@ -225,13 +230,13 @@ export class TranslationProvider {
|
|
|
225
230
|
getVisionType(key, locale) {
|
|
226
231
|
const localeData = this.registry.getLocale(locale);
|
|
227
232
|
// Try requested locale
|
|
228
|
-
if (localeData?.visionTypes[key]) {
|
|
233
|
+
if (localeData?.visionTypes && Object.hasOwn(localeData.visionTypes, key) && localeData?.visionTypes[key]) {
|
|
229
234
|
return localeData.visionTypes[key];
|
|
230
235
|
}
|
|
231
236
|
// Fallback to English
|
|
232
237
|
if (locale !== 'en') {
|
|
233
238
|
const englishData = this.registry.getLocale('en');
|
|
234
|
-
if (englishData?.visionTypes[key]) {
|
|
239
|
+
if (englishData?.visionTypes && Object.hasOwn(englishData.visionTypes, key) && englishData?.visionTypes[key]) {
|
|
235
240
|
return englishData.visionTypes[key];
|
|
236
241
|
}
|
|
237
242
|
}
|
|
@@ -257,12 +262,12 @@ export class TranslationProvider {
|
|
|
257
262
|
*/
|
|
258
263
|
getVisionShort(key, locale) {
|
|
259
264
|
const localeData = this.registry.getLocale(locale);
|
|
260
|
-
if (localeData?.visions
|
|
265
|
+
if (localeData?.visions && Object.hasOwn(localeData.visions, key) && localeData.visions[key]) {
|
|
261
266
|
return localeData.visions[key];
|
|
262
267
|
}
|
|
263
268
|
if (locale !== 'en') {
|
|
264
269
|
const englishData = this.registry.getLocale('en');
|
|
265
|
-
if (englishData?.visions
|
|
270
|
+
if (englishData?.visions && Object.hasOwn(englishData.visions, key) && englishData.visions[key]) {
|
|
266
271
|
return englishData.visions[key];
|
|
267
272
|
}
|
|
268
273
|
}
|
|
@@ -286,12 +291,12 @@ export class TranslationProvider {
|
|
|
286
291
|
*/
|
|
287
292
|
getToolName(key, locale) {
|
|
288
293
|
const localeData = this.registry.getLocale(locale);
|
|
289
|
-
if (localeData?.tools
|
|
294
|
+
if (localeData?.tools && Object.hasOwn(localeData.tools, key) && localeData.tools[key]) {
|
|
290
295
|
return localeData.tools[key];
|
|
291
296
|
}
|
|
292
297
|
if (locale !== 'en') {
|
|
293
298
|
const englishData = this.registry.getLocale('en');
|
|
294
|
-
if (englishData?.tools
|
|
299
|
+
if (englishData?.tools && Object.hasOwn(englishData.tools, key) && englishData.tools[key]) {
|
|
295
300
|
return englishData.tools[key];
|
|
296
301
|
}
|
|
297
302
|
}
|
|
@@ -315,12 +320,12 @@ export class TranslationProvider {
|
|
|
315
320
|
*/
|
|
316
321
|
getSheetName(key, locale) {
|
|
317
322
|
const localeData = this.registry.getLocale(locale);
|
|
318
|
-
if (localeData?.sheets
|
|
323
|
+
if (localeData?.sheets && Object.hasOwn(localeData.sheets, key) && localeData.sheets[key]) {
|
|
319
324
|
return localeData.sheets[key];
|
|
320
325
|
}
|
|
321
326
|
if (locale !== 'en') {
|
|
322
327
|
const englishData = this.registry.getLocale('en');
|
|
323
|
-
if (englishData?.sheets
|
|
328
|
+
if (englishData?.sheets && Object.hasOwn(englishData.sheets, key) && englishData.sheets[key]) {
|
|
324
329
|
return englishData.sheets[key];
|
|
325
330
|
}
|
|
326
331
|
}
|
|
@@ -342,13 +347,13 @@ export class TranslationProvider {
|
|
|
342
347
|
getRace(key, locale) {
|
|
343
348
|
const localeData = this.registry.getLocale(locale);
|
|
344
349
|
// Try requested locale
|
|
345
|
-
if (localeData?.races
|
|
350
|
+
if (localeData?.races && Object.hasOwn(localeData.races, key) && localeData.races[key]) {
|
|
346
351
|
return localeData.races[key];
|
|
347
352
|
}
|
|
348
353
|
// Fallback to English
|
|
349
354
|
if (locale !== 'en') {
|
|
350
355
|
const englishData = this.registry.getLocale('en');
|
|
351
|
-
if (englishData?.races
|
|
356
|
+
if (englishData?.races && Object.hasOwn(englishData.races, key) && englishData.races[key]) {
|
|
352
357
|
return englishData.races[key];
|
|
353
358
|
}
|
|
354
359
|
}
|
|
@@ -371,13 +376,13 @@ export class TranslationProvider {
|
|
|
371
376
|
getClan(key, locale) {
|
|
372
377
|
const localeData = this.registry.getLocale(locale);
|
|
373
378
|
// Try requested locale
|
|
374
|
-
if (localeData?.clans
|
|
379
|
+
if (localeData?.clans && Object.hasOwn(localeData.clans, key) && localeData.clans[key]) {
|
|
375
380
|
return localeData.clans[key];
|
|
376
381
|
}
|
|
377
382
|
// Fallback to English
|
|
378
383
|
if (locale !== 'en') {
|
|
379
384
|
const englishData = this.registry.getLocale('en');
|
|
380
|
-
if (englishData?.clans
|
|
385
|
+
if (englishData?.clans && Object.hasOwn(englishData.clans, key) && englishData.clans[key]) {
|
|
381
386
|
return englishData.clans[key];
|
|
382
387
|
}
|
|
383
388
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TranslationProvider.js","sourceRoot":"","sources":["../../../src/services/localization/TranslationProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAYH,OAAO,EACL,iBAAiB,EACjB,gBAAgB,GAEjB,MAAM,kCAAkC,CAAC;AAG1C
|
|
1
|
+
{"version":3,"file":"TranslationProvider.js","sourceRoot":"","sources":["../../../src/services/localization/TranslationProvider.ts"],"names":[],"mappings":"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"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -53,5 +53,18 @@ export declare function isMatchingMethod(value: unknown): value is MatchingMetho
|
|
|
53
53
|
* URL `algo` param, API body) into the 5.0 vocabulary: current values pass
|
|
54
54
|
* through, retired values map, anything else falls back to the default.
|
|
55
55
|
*/
|
|
56
|
+
/**
|
|
57
|
+
* BUG-011: `value in OBJ` and `OBJ[value]` both walk `Object.prototype`, so
|
|
58
|
+
* `'constructor'`, `'toString'` and `'__proto__'` looked like legacy method
|
|
59
|
+
* names and returned a FUNCTION typed as a `MatchingMethod`. This normalizer is
|
|
60
|
+
* applied at every ingress — KV preference, localStorage, the URL `algo` param,
|
|
61
|
+
* API bodies — and its whole contract is "anything else falls back to the
|
|
62
|
+
* default", so a crafted value propagated a function into the matching method
|
|
63
|
+
* and `getDistanceForMethod`'s exhaustive switch then returned `undefined`.
|
|
64
|
+
*
|
|
65
|
+
* `Object.hasOwn` is the fix rather than a `Map` because
|
|
66
|
+
* `LEGACY_MATCHING_METHOD_MAP` is a published export; changing its type would
|
|
67
|
+
* be a breaking change for a defect that needs a guard, not a new shape.
|
|
68
|
+
*/
|
|
56
69
|
export declare function normalizeMatchingMethod(value: unknown): MatchingMethod;
|
|
57
70
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,KAAK,GAAG,aAAa,CAAC;AAEjG,qFAAqF;AACrF,eAAO,MAAM,gBAAgB,EAAE,SAAS,cAAc,EAOrD,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,uBAAuB,EAAE,cAA4B,CAAC;AAEnE;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,cAAc,GAAG,OAAO,EAAE,MAAM,CAQzE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAKrE,CAAC;AAEF,yCAAyC;AACzC,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAExE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAMtE"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,KAAK,GAAG,aAAa,CAAC;AAEjG,qFAAqF;AACrF,eAAO,MAAM,gBAAgB,EAAE,SAAS,cAAc,EAOrD,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,uBAAuB,EAAE,cAA4B,CAAC;AAEnE;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,cAAc,GAAG,OAAO,EAAE,MAAM,CAQzE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAKrE,CAAC;AAEF,yCAAyC;AACzC,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAExE;AAED;;;;GAIG;AACH;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAMtE"}
|
package/dist/types/index.js
CHANGED
|
@@ -51,10 +51,23 @@ export function isMatchingMethod(value) {
|
|
|
51
51
|
* URL `algo` param, API body) into the 5.0 vocabulary: current values pass
|
|
52
52
|
* through, retired values map, anything else falls back to the default.
|
|
53
53
|
*/
|
|
54
|
+
/**
|
|
55
|
+
* BUG-011: `value in OBJ` and `OBJ[value]` both walk `Object.prototype`, so
|
|
56
|
+
* `'constructor'`, `'toString'` and `'__proto__'` looked like legacy method
|
|
57
|
+
* names and returned a FUNCTION typed as a `MatchingMethod`. This normalizer is
|
|
58
|
+
* applied at every ingress — KV preference, localStorage, the URL `algo` param,
|
|
59
|
+
* API bodies — and its whole contract is "anything else falls back to the
|
|
60
|
+
* default", so a crafted value propagated a function into the matching method
|
|
61
|
+
* and `getDistanceForMethod`'s exhaustive switch then returned `undefined`.
|
|
62
|
+
*
|
|
63
|
+
* `Object.hasOwn` is the fix rather than a `Map` because
|
|
64
|
+
* `LEGACY_MATCHING_METHOD_MAP` is a published export; changing its type would
|
|
65
|
+
* be a breaking change for a defect that needs a guard, not a new shape.
|
|
66
|
+
*/
|
|
54
67
|
export function normalizeMatchingMethod(value) {
|
|
55
68
|
if (isMatchingMethod(value))
|
|
56
69
|
return value;
|
|
57
|
-
if (typeof value === 'string' && value
|
|
70
|
+
if (typeof value === 'string' && Object.hasOwn(LEGACY_MATCHING_METHOD_MAP, value)) {
|
|
58
71
|
return LEGACY_MATCHING_METHOD_MAP[value];
|
|
59
72
|
}
|
|
60
73
|
return DEFAULT_MATCHING_METHOD;
|
package/dist/types/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA+BH,qFAAqF;AACrF,MAAM,CAAC,MAAM,gBAAgB,GAA8B;IACzD,WAAW;IACX,OAAO;IACP,OAAO;IACP,SAAS;IACT,KAAK;IACL,aAAa;CACd,CAAC;AAEF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,uBAAuB,GAAmB,WAAW,CAAC;AAEnE;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA6C;IAC5E,SAAS,EAAE,QAAQ;IACnB,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,MAAM;IACb,OAAO,EAAE,SAAS;IAClB,GAAG,EAAE,UAAU;IACf,WAAW,EAAE,eAAe;IAC5B,KAAK,EAAE,OAAO;CACf,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAmC;IACxE,IAAI,EAAE,WAAW;IACjB,gBAAgB,EAAE,WAAW;IAC7B,kEAAkE;IAClE,SAAS,EAAE,KAAK;CACjB,CAAC;AAEF,yCAAyC;AACzC,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,gBAAsC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC9F,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,IAAI,gBAAgB,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA+BH,qFAAqF;AACrF,MAAM,CAAC,MAAM,gBAAgB,GAA8B;IACzD,WAAW;IACX,OAAO;IACP,OAAO;IACP,SAAS;IACT,KAAK;IACL,aAAa;CACd,CAAC;AAEF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,uBAAuB,GAAmB,WAAW,CAAC;AAEnE;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA6C;IAC5E,SAAS,EAAE,QAAQ;IACnB,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,MAAM;IACb,OAAO,EAAE,SAAS;IAClB,GAAG,EAAE,UAAU;IACf,WAAW,EAAE,eAAe;IAC5B,KAAK,EAAE,OAAO;CACf,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAmC;IACxE,IAAI,EAAE,WAAW;IACjB,gBAAgB,EAAE,WAAW;IAC7B,kEAAkE;IAClE,SAAS,EAAE,KAAK;CACjB,CAAC;AAEF,yCAAyC;AACzC,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,gBAAsC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC9F,CAAC;AAED;;;;GAIG;AACH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,IAAI,gBAAgB,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,0BAA0B,EAAE,KAAK,CAAC,EAAE,CAAC;QAClF,OAAO,0BAA0B,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,uBAAuB,CAAC;AACjC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xivdyetools/core",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "Core color algorithms and dye database for XIV Dye Tools",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -46,15 +46,15 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"spectral.js": "^3.0.0",
|
|
49
|
-
"@xivdyetools/
|
|
50
|
-
"@xivdyetools/
|
|
49
|
+
"@xivdyetools/logger": "2.2.0",
|
|
50
|
+
"@xivdyetools/types": "3.0.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@types/node": "^26.
|
|
54
|
-
"@vitest/coverage-v8": "^4.1.
|
|
55
|
-
"csv-parse": "^7.0.
|
|
56
|
-
"tsx": "^4.23.
|
|
57
|
-
"vitest": "^4.1.
|
|
53
|
+
"@types/node": "^26.4.0",
|
|
54
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
55
|
+
"csv-parse": "^7.0.2",
|
|
56
|
+
"tsx": "^4.23.12",
|
|
57
|
+
"vitest": "^4.1.11",
|
|
58
58
|
"yaml": "^2.9.0"
|
|
59
59
|
},
|
|
60
60
|
"engines": {
|