Skip to content
This repository was archived by the owner on May 5, 2021. It is now read-only.

Commit dd7dc62

Browse files
committed
[IMP] Core: add contains() on Modifiers
1 parent 20ce823 commit dd7dc62

File tree

2 files changed

+87
-12
lines changed

2 files changed

+87
-12
lines changed

packages/core/src/Modifiers.ts

+32-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Constructor, isConstructor } from '../../utils/src/utils';
33
import { EventMixin } from '../../utils/src/EventMixin';
44
import { VersionableArray } from './Memory/VersionableArray';
55

6-
export class Modifiers extends EventMixin {
6+
export class Modifiers extends EventMixin implements Iterable<Modifier> {
77
private _contents: Modifier[];
88
constructor(...modifiers: Array<Modifier | Constructor<Modifier>>) {
99
super();
@@ -247,6 +247,22 @@ export class Modifiers extends EventMixin {
247247
toggle(modifier: Modifier | Constructor<Modifier>): void {
248248
this.remove(modifier) || this.append(modifier);
249249
}
250+
/**
251+
* Check that all `otherModifiers` ar contained within this ones.
252+
*
253+
* @param otherModifiers
254+
*/
255+
contains(otherModifiers: Modifiers): boolean {
256+
for (const otherModifier of otherModifiers) {
257+
const foundModifier = this.find(m => m.isSameAs(otherModifier));
258+
// Modifier.isSameAs(undefined) could return true. See
259+
// `Attribute.isSameAs`.
260+
if (!foundModifier && !otherModifier.isSameAs(undefined)) {
261+
return false;
262+
}
263+
}
264+
return true;
265+
}
250266
/**
251267
* Return true if the modifiers in this array are the same as the modifiers
252268
* in the given array (as defined by the `isSameAs` methods of the
@@ -255,17 +271,7 @@ export class Modifiers extends EventMixin {
255271
* @param otherModifiers
256272
*/
257273
areSameAs(otherModifiers: Modifiers): boolean {
258-
const modifiersMap = new Map(
259-
this._contents?.map(a => [a, otherModifiers.find(b => a.isSameAs(b))]) || [],
260-
);
261-
const aModifiers = Array.from(modifiersMap.keys());
262-
const bModifiers = Array.from(modifiersMap.values());
263-
264-
const allAinB = aModifiers.every(a => a.isSameAs(modifiersMap.get(a)));
265-
const allBinA = otherModifiers.every(
266-
b => bModifiers.includes(b) || b.isSameAs(this.find(b)),
267-
);
268-
return allAinB && allBinA;
274+
return this.contains(otherModifiers) && otherModifiers.contains(this);
269275
}
270276
/**
271277
* Remove all modifiers.
@@ -306,6 +312,20 @@ export class Modifiers extends EventMixin {
306312
map<T>(callbackfn: (value: Modifier, index: number, array: Modifier[]) => T): T[] {
307313
return this._contents?.map(callbackfn) || [];
308314
}
315+
/**
316+
* Iterate through all modifiers.
317+
*/
318+
[Symbol.iterator](): Iterator<Modifier> {
319+
let index = -1;
320+
const data = this._contents || [];
321+
322+
return {
323+
next: (): IteratorResult<Modifier> => ({
324+
value: data[++index],
325+
done: !(index in data),
326+
}),
327+
};
328+
}
309329
/**
310330
* @override
311331
*/

packages/core/test/Modifiers.test.ts

+55
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ class ExtendedModifier extends Modifier {
1818
return otherModifier instanceof ExtendedModifier && this.value === otherModifier.value;
1919
}
2020
}
21+
class SameUndefinedModifier extends Modifier {
22+
isSameAs(otherModifier: Modifier): boolean {
23+
return otherModifier instanceof Modifier || typeof otherModifier === 'undefined';
24+
}
25+
}
2126
describe('core', () => {
2227
describe('Modifiers', () => {
2328
describe('constructor()', () => {
@@ -505,6 +510,56 @@ describe('core', () => {
505510
expect(modifiersMap[1] instanceof ExtendedModifier).to.be.true;
506511
});
507512
});
513+
describe('contains()', () => {
514+
it('should contain itself favorably', () => {
515+
const m1 = new Modifier();
516+
const m2 = new Modifier();
517+
const modifiers1 = new Modifiers(m1, m2);
518+
expect(modifiers1.contains(modifiers1)).to.be.true;
519+
});
520+
it('should contain a modifier that has the same favorably', () => {
521+
const m1 = new ExtendedModifier(1);
522+
const m2 = new ExtendedModifier(2);
523+
const modifiers1 = new Modifiers(m1, m2);
524+
const m1bis = new ExtendedModifier(1);
525+
const m2bis = new ExtendedModifier(2);
526+
const modifiers2 = new Modifiers(m1bis);
527+
const modifiers3 = new Modifiers(m2bis);
528+
const modifiers4 = new Modifiers(m1bis, m2bis);
529+
expect(modifiers1.contains(modifiers2)).to.be.true;
530+
expect(modifiers1.contains(modifiers3)).to.be.true;
531+
expect(modifiers1.contains(modifiers4)).to.be.true;
532+
});
533+
it('should contain a modifier that has the same favorably even if their order is different', () => {
534+
const m1 = new ExtendedModifier(1);
535+
const m2 = new ExtendedModifier(2);
536+
const modifiers1 = new Modifiers(m1, m2);
537+
const modifiers2 = new Modifiers(m2, m1);
538+
expect(modifiers1.contains(modifiers2)).to.be.true;
539+
});
540+
it('should contain a modifier that has the same favorably even if their order and instances are different', () => {
541+
const m1 = new ExtendedModifier(1);
542+
const m2 = new ExtendedModifier(2);
543+
const modifiers1 = new Modifiers(m1, m2);
544+
const m1bis = new ExtendedModifier(1);
545+
const m2bis = new ExtendedModifier(2);
546+
const modifiers2 = new Modifiers(m2bis, m1bis);
547+
expect(modifiers1.contains(modifiers2)).to.be.true;
548+
});
549+
it('should match with modifiers that are the same with undefined', () => {
550+
const m1 = new SameUndefinedModifier();
551+
const modifiers1 = new Modifiers();
552+
const modifiers2 = new Modifiers(m1);
553+
expect(modifiers1.contains(modifiers2)).to.be.true;
554+
});
555+
it('should not contain the other modifiers', () => {
556+
const m1 = new ExtendedModifier(1);
557+
const modifiers1 = new Modifiers(m1);
558+
const m2 = new ExtendedModifier(0);
559+
const modifiers2 = new Modifiers(m2);
560+
expect(modifiers1.contains(modifiers2)).to.be.false;
561+
});
562+
});
508563
describe('areSameAs()', () => {
509564
it('should know that an instance of Modifiers is the same as itself', () => {
510565
const m1 = new Modifier();

0 commit comments

Comments
 (0)