Skip to content

Commit 9190d17

Browse files
refactor recorder and recordsSet
1 parent a2bb99f commit 9190d17

File tree

2 files changed

+57
-34
lines changed

2 files changed

+57
-34
lines changed

src/Recorder.ts

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,55 @@
11
import { inspect, InspectOptions } from 'util'
2-
import { SubstituteNodeBase } from './SubstituteNodeBase'
2+
3+
import { FilterFunction } from './Types'
34
import { RecordsSet } from './RecordsSet'
45

5-
export class Recorder {
6-
private _records: RecordsSet<SubstituteNodeBase>
7-
private _indexedRecords: Map<PropertyKey, RecordsSet<SubstituteNodeBase>>
6+
export class Recorder<TRecord> {
7+
private _identity: PropertyKey
8+
private _records: RecordsSet<TRecord>
9+
private _indexedRecords: Map<PropertyKey, RecordsSet<TRecord>>
810

9-
constructor() {
11+
private constructor(identity: PropertyKey) {
12+
this._identity = identity
1013
this._records = new RecordsSet()
1114
this._indexedRecords = new Map()
1215
}
1316

14-
public get records(): RecordsSet<SubstituteNodeBase> {
17+
public static withIdentityProperty<TRecord>(identity: keyof TRecord): Recorder<TRecord> {
18+
return new this(identity)
19+
}
20+
21+
public get records(): RecordsSet<TRecord> {
1522
return this._records
1623
}
1724

18-
public get indexedRecords(): Map<PropertyKey, RecordsSet<SubstituteNodeBase>> {
25+
public get indexedRecords(): Map<PropertyKey, RecordsSet<TRecord>> {
1926
return this._indexedRecords
2027
}
2128

22-
public addIndexedRecord(node: SubstituteNodeBase): void {
23-
this.addRecord(node)
24-
const existingNodes = this.indexedRecords.get(node.key)
25-
if (typeof existingNodes === 'undefined') this.indexedRecords.set(node.key, new RecordsSet([node]))
26-
else existingNodes.add(node)
29+
public addIndexedRecord(record: TRecord): void {
30+
const id = this.getIdentity(record)
31+
this.addRecord(record)
32+
const existingNodes = this.indexedRecords.get(id)
33+
if (typeof existingNodes === 'undefined') this.indexedRecords.set(id, new RecordsSet([record]))
34+
else existingNodes.add(record)
2735
}
2836

29-
public addRecord(node: SubstituteNodeBase): void {
30-
this._records.add(node)
37+
public addRecord(record: TRecord): void {
38+
this._records.add(record)
3139
}
3240

33-
public getSiblingsOf(node: SubstituteNodeBase): RecordsSet<SubstituteNodeBase> {
34-
const siblingNodes = this.indexedRecords.get(node.key) ?? new RecordsSet()
35-
return siblingNodes.filter(siblingNode => siblingNode !== node)
41+
public getSiblingsOf(record: TRecord): RecordsSet<TRecord> {
42+
const siblings = this.indexedRecords.get(this.getIdentity(record)) ?? new RecordsSet()
43+
return siblings.filter(sibling => sibling !== record)
3644
}
3745

38-
public clearRecords(filterFunction: (node: SubstituteNodeBase) => boolean) {
46+
public clearRecords(filterFunction: FilterFunction<TRecord>) {
3947
const recordsToRemove = this.records.filter(filterFunction)
4048
for (const record of recordsToRemove) {
41-
const indexedRecord = this.indexedRecords.get(record.key)
49+
const id = this.getIdentity(record)
50+
const indexedRecord = this.indexedRecords.get(id)
4251
indexedRecord.delete(record)
43-
if (indexedRecord.size === 0) this.indexedRecords.delete(record.key)
52+
if (indexedRecord.size === 0) this.indexedRecords.delete(id)
4453
this.records.delete(record)
4554
}
4655
}
@@ -51,4 +60,8 @@ export class Recorder {
5160
([key, value]) => `\n ${key.toString()}: {\n${[...value.map(v => ` ${inspect(v, options)}`)].join(',\n')}\n }`
5261
).join()
5362
}
54-
}
63+
64+
private getIdentity(record: TRecord): PropertyKey {
65+
return record[this._identity as keyof TRecord] as PropertyKey
66+
}
67+
}

src/RecordsSet.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
type FilterFunction<T> = (item: T) => boolean
1+
import { FilterFunction } from './Types'
2+
23
type MapperFunction<T, R> = (item: T) => R
3-
type Transformer<T, R> = { type: 'filter', fnc: FilterFunction<T> } | { type: 'mapper', fnc: MapperFunction<T, R> }
4+
type Transformer<T, R> = { type: 'filter', predicate: FilterFunction<T> } | { type: 'mapper', predicate: MapperFunction<T, R> }
45

56
export class RecordsSet<T> extends Set<T> {
67
private _transformer: Transformer<any, any>
78
private readonly _prevIter?: RecordsSet<T>
89

910
constructor(value?: Iterable<T> | readonly T[]) {
10-
super(value instanceof RecordsSet ? undefined : value)
11-
if (value instanceof RecordsSet) this._prevIter = value
11+
const isRecordSet = value instanceof RecordsSet
12+
super(isRecordSet ? undefined : value)
13+
if (isRecordSet) this._prevIter = value
1214
}
1315

1416
get size(): number {
@@ -17,15 +19,15 @@ export class RecordsSet<T> extends Set<T> {
1719
return currentSize
1820
}
1921

20-
filter(predicate: (item: T) => boolean): RecordsSet<T> {
21-
const newInstance = new RecordsSet<T>(this)
22-
newInstance._transformer = { type: 'filter', fnc: predicate }
22+
filter(predicate: FilterFunction<T>): RecordsSet<T> {
23+
const newInstance = new RecordsSet<T>(this as RecordsSet<T>)
24+
newInstance._transformer = { type: 'filter', predicate }
2325
return newInstance
2426
}
2527

26-
map<R>(predicate: (item: T) => R): RecordsSet<R> {
28+
map<R>(predicate: MapperFunction<T, R>): RecordsSet<R> {
2729
const newInstance = new RecordsSet<R | T>(this)
28-
newInstance._transformer = { type: 'mapper', fnc: predicate }
30+
newInstance._transformer = { type: 'mapper', predicate }
2931
return newInstance as RecordsSet<R>
3032
}
3133

@@ -41,7 +43,10 @@ export class RecordsSet<T> extends Set<T> {
4143
}
4244

4345
clear() {
44-
Object.defineProperty(this, '_prevIter', { value: undefined })
46+
if (this._prevIter instanceof RecordsSet) {
47+
this._prevIter.clear()
48+
Object.defineProperty(this, '_prevIter', { value: undefined })
49+
}
4550
super.clear()
4651
}
4752

@@ -54,12 +59,17 @@ export class RecordsSet<T> extends Set<T> {
5459
yield* this.applyTransform(super.values())
5560
}
5661

57-
private *applyTransform(itarable: Iterable<T>): IterableIterator<T> {
62+
private * applyTransform(itarable: Iterable<T>): IterableIterator<T> {
5863
const transform = this._transformer
5964
if (typeof transform === 'undefined') return yield* itarable
6065
for (const value of itarable) {
61-
if (transform.type === 'mapper') yield transform.fnc(value)
62-
if (transform.type === 'filter' && transform.fnc(value)) yield value
66+
switch (transform.type) {
67+
case 'filter':
68+
if (transform.predicate(value)) yield value
69+
break
70+
case 'mapper': yield transform.predicate(value)
71+
break
72+
}
6373
}
6474
}
6575
}

0 commit comments

Comments
 (0)