-
-
Notifications
You must be signed in to change notification settings - Fork 208
/
Copy pathrabin-karp.ts
106 lines (91 loc) · 3.02 KB
/
rabin-karp.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import {IClone, ICloneValidator, IMapFrame, IOptions, IStore, IValidationResult} from './interfaces';
import {runCloneValidators} from './validators';
import {ITokensMap} from '.';
import EventEmitter = require('eventemitter3');
export class RabinKarp {
constructor(
private readonly options: IOptions,
private readonly eventEmitter: EventEmitter,
private readonly cloneValidators: ICloneValidator[],
) {
}
public async run(tokenMap: ITokensMap, store: IStore<IMapFrame>): Promise<IClone[]> {
return new Promise((resolve => {
let mapFrameInStore;
let clone: IClone | null = null;
const clones: IClone[] = [];
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
const loop = () => {
const iteration = tokenMap.next();
store
.get(iteration.value.id)
.then(
(mapFrameFromStore: IMapFrame) => {
mapFrameInStore = mapFrameFromStore;
if (!clone) {
clone = RabinKarp.createClone(tokenMap.getFormat(), iteration.value, mapFrameInStore);
}
},
() => {
if (clone && this.validate(clone)) {
clones.push(clone);
}
clone = null;
if (iteration.value.id) {
return store.set(iteration.value.id, iteration.value);
}
},
)
.finally(() => {
if (!iteration.done) {
if (clone) {
clone = RabinKarp.enlargeClone(clone, iteration.value, mapFrameInStore);
}
loop();
} else {
resolve(clones);
}
});
}
loop();
}));
}
private validate(clone: IClone): boolean {
const validation: IValidationResult = runCloneValidators(clone, this.options, this.cloneValidators);
let status = validation.status
if (this.options.customValidate) {
status = status && this.options.customValidate(clone)
}
if (status) {
this.eventEmitter.emit('CLONE_FOUND', {clone})
} else {
this.eventEmitter.emit('CLONE_SKIPPED', {clone, validation})
}
return status;
}
private static createClone(format: string, mapFrameA: IMapFrame, mapFrameB: IMapFrame): IClone {
return {
format,
foundDate: new Date().getTime(),
duplicationA: {
sourceId: mapFrameA.sourceId,
start: mapFrameA.start.loc.start,
end: mapFrameA.end.loc.end,
range: [mapFrameA.start.range[0], mapFrameA.end.range[1]],
},
duplicationB: {
sourceId: mapFrameB.sourceId,
start: mapFrameB.start.loc.start,
end: mapFrameB.end.loc.end,
range: [mapFrameB.start.range[0], mapFrameB.end.range[1]],
},
}
}
private static enlargeClone(clone: IClone, mapFrameA: IMapFrame, mapFrameB: IMapFrame): IClone {
clone.duplicationA.range[1] = mapFrameA.end.range[1];
clone.duplicationA.end = mapFrameA.end.loc.end;
clone.duplicationB.range[1] = mapFrameB.end.range[1];
clone.duplicationB.end = mapFrameB.end.loc.end;
return clone;
}
}