diff --git a/index.js b/index.js index 31cb4a95e4..e2514a32e4 100644 --- a/index.js +++ b/index.js @@ -160,10 +160,26 @@ module.exports = class Items extends Array { */ filter(fn) { const A = []; + const filteredNames = this.i18n ? new Set() : null; for (const el of this) { - if (fn(el)) A.push(el); + if (fn(el)) { + A.push(el); + if (filteredNames) filteredNames.add(el.uniqueName); + } + } + + if (filteredNames) { + const filteredI18n = {}; + for (const uniqueName of filteredNames) { + if (Object.prototype.hasOwnProperty.call(this.i18n, uniqueName)) { + filteredI18n[uniqueName] = this.i18n[uniqueName]; + } + } + A.i18n = filteredI18n; } + + A.versions = this.versions; return A; } diff --git a/index.mjs b/index.mjs index 817d4d073a..d57041f7da 100644 --- a/index.mjs +++ b/index.mjs @@ -159,15 +159,31 @@ export default class Items extends Array { */ filter(fn) { const A = []; + const filteredNames = this.i18n ? new Set() : null; for (const el of this) { - if (fn(el)) A.push(el); + if (fn(el)) { + A.push(el); + if (filteredNames) filteredNames.add(el.uniqueName); + } } + + if (filteredNames) { + const filteredI18n = {}; + for (const uniqueName of filteredNames) { + if (Object.prototype.hasOwnProperty.call(this.i18n, uniqueName)) { + filteredI18n[uniqueName] = this.i18n[uniqueName]; + } + } + A.i18n = filteredI18n; + } + + A.versions = this.versions; return A; } /** - * @Override Array.prototype.filter + * @Override Array.prototype.map * * See filter override */ diff --git a/test/index.spec.mjs b/test/index.spec.mjs index 74d00507a0..8957ed7e70 100755 --- a/test/index.spec.mjs +++ b/test/index.spec.mjs @@ -322,6 +322,30 @@ const test = (base) => { const realLength = items.length; assert(realLength === items.map((x) => x).length); }); + it('should preserve i18n and versions after filter', async () => { + const items = await wrapConstr({ category: ['Pets'], i18n: ['es'] }); + const filtered = items.filter(() => true); + assert.deepStrictEqual(filtered.i18n, items.i18n, 'filter should preserve i18n'); + assert.deepStrictEqual(filtered.versions, items.versions, 'filter should preserve versions'); + }); + it('should filter i18n entries to only matched items', async () => { + const items = await wrapConstr({ category: ['Pets'], i18n: ['es'] }); + const targetUniqueName = items[0]?.uniqueName; + const filtered = items.filter((i) => i.uniqueName === targetUniqueName); + assert.strictEqual(filtered.length, 1, 'should have exactly one result'); + assert.ok(filtered.i18n, 'filtered result should have i18n'); + assert.ok(filtered.i18n[targetUniqueName], 'i18n should contain the matched item'); + assert.strictEqual(Object.keys(filtered.i18n).length, 1, 'i18n should only contain the matched item'); + }); + it('edge case: should ignore i18n entry when is missing from original', async () => { + const items = await wrapConstr({ category: ['Pets'], i18n: ['es'] }); + const targetUniqueName = items[0]?.uniqueName; + items.i18n = {}; // simulate missing i18n entries + const filtered = items.filter((i) => i.uniqueName === targetUniqueName); + assert.strictEqual(filtered.length, 1, 'should have exactly one result'); + assert.ok(filtered.i18n, 'filtered result should have i18n'); + assert.strictEqual(Object.keys(filtered.i18n).length, 0, 'i18n should be empty when original is empty'); + }); describe('helminth', async () => { it('should only have drops', async () => { const items = await wrapConstr({ category: ['Warframes'] });