forked from angular/angular
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcoalesce.js
More file actions
86 lines (76 loc) · 2.44 KB
/
coalesce.js
File metadata and controls
86 lines (76 loc) · 2.44 KB
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
import {isPresent} from 'angular2/src/facade/lang';
import {List, ListWrapper, Map, MapWrapper} from 'angular2/src/facade/collection';
import {RECORD_TYPE_SELF, ProtoRecord} from './proto_record';
/**
* Removes "duplicate" records. It assuming that record evaluation does not
* have side-effects.
*
* Records that are not last in bindings are removed and all the indices
* of the records that depend on them are updated.
*
* Records that are last in bindings CANNOT be removed, and instead are
* replaced with very cheap SELF records.
*/
export function coalesce(records:List<ProtoRecord>):List<ProtoRecord> {
var res = ListWrapper.create();
var indexMap = MapWrapper.create();
for (var i = 0; i < records.length; ++i) {
var r = records[i];
var record = _replaceIndices(r, res.length + 1, indexMap);
var matchingRecord = _findMatching(record, res);
if (isPresent(matchingRecord) && record.lastInBinding) {
ListWrapper.push(res, _selfRecord(record, matchingRecord.selfIndex, res.length + 1));
MapWrapper.set(indexMap, r.selfIndex, matchingRecord.selfIndex);
} else if (isPresent(matchingRecord) && !record.lastInBinding) {
MapWrapper.set(indexMap, r.selfIndex, matchingRecord.selfIndex);
} else {
ListWrapper.push(res, record);
MapWrapper.set(indexMap, r.selfIndex, record.selfIndex);
}
}
return res;
}
function _selfRecord(r:ProtoRecord, contextIndex:number, selfIndex:number):ProtoRecord {
return new ProtoRecord(
RECORD_TYPE_SELF,
"self",
null,
[],
r.fixedArgs,
contextIndex,
selfIndex,
r.bindingRecord,
r.expressionAsString,
r.lastInBinding,
r.lastInDirective
);
}
function _findMatching(r:ProtoRecord, rs:List<ProtoRecord>){
return ListWrapper.find(rs, (rr) =>
rr.mode === r.mode &&
rr.funcOrValue === r.funcOrValue &&
rr.contextIndex === r.contextIndex &&
ListWrapper.equals(rr.args, r.args)
);
}
function _replaceIndices(r:ProtoRecord, selfIndex:number, indexMap:Map) {
var args = ListWrapper.map(r.args, (a) => _map(indexMap, a));
var contextIndex = _map(indexMap, r.contextIndex);
return new ProtoRecord(
r.mode,
r.name,
r.funcOrValue,
args,
r.fixedArgs,
contextIndex,
selfIndex,
r.bindingRecord,
r.expressionAsString,
r.lastInBinding,
r.lastInDirective
);
}
function _map(indexMap:Map, value:number) {
var r = MapWrapper.get(indexMap, value)
return isPresent(r) ? r : value;
}