/
Reference.ts
129 lines (114 loc) · 2.89 KB
/
Reference.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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import { TSESTree } from '@typescript-eslint/typescript-estree';
import { createIdGenerator } from '../ID';
import { Scope } from '../scope';
import { Variable } from '../Variable';
enum ReferenceFlag {
READ = 0x1,
WRITE = 0x2,
RW = 0x3,
}
interface ReferenceImplicitGlobal {
node: TSESTree.Node;
pattern: TSESTree.BindingName;
ref?: Reference;
}
const generator = createIdGenerator();
/**
* A Reference represents a single occurrence of an identifier in code.
*/
class Reference {
/**
* A unique ID for this instance - primarily used to help debugging and testing
*/
public readonly $id: number = generator();
/**
* The read-write mode of the reference.
*/
readonly #flag: ReferenceFlag;
/**
* Reference to the enclosing Scope.
* @public
*/
public readonly from: Scope;
/**
* Identifier syntax node.
* @public
*/
public readonly identifier: TSESTree.Identifier;
/**
* `true` if this writing reference is a variable initializer or a default value.
* @public
*/
public readonly init?: boolean;
/**
* The {@link Variable} object that this reference refers to. If such variable was not defined, this is `null`.
* @public
*/
public resolved: Variable | null;
/**
* If reference is writeable, this is the node being written to it.
* @public
*/
public readonly writeExpr?: TSESTree.Node | null;
public readonly maybeImplicitGlobal?: ReferenceImplicitGlobal | null;
/**
* True if this reference was created from a type context, false otherwise
*/
public readonly isTypeReference: boolean;
constructor(
identifier: TSESTree.Identifier,
scope: Scope,
flag: ReferenceFlag,
writeExpr?: TSESTree.Node | null,
maybeImplicitGlobal?: ReferenceImplicitGlobal | null,
init?: boolean,
isTypeReference = false,
) {
this.identifier = identifier;
this.from = scope;
this.resolved = null;
this.#flag = flag;
if (this.isWrite()) {
this.writeExpr = writeExpr;
this.init = init;
}
this.maybeImplicitGlobal = maybeImplicitGlobal;
this.isTypeReference = isTypeReference;
}
/**
* Whether the reference is writeable.
* @public
*/
public isWrite(): boolean {
return !!(this.#flag & ReferenceFlag.WRITE);
}
/**
* Whether the reference is readable.
* @public
*/
public isRead(): boolean {
return !!(this.#flag & ReferenceFlag.READ);
}
/**
* Whether the reference is read-only.
* @public
*/
public isReadOnly(): boolean {
return this.#flag === ReferenceFlag.READ;
}
/**
* Whether the reference is write-only.
* @public
*/
public isWriteOnly(): boolean {
return this.#flag === ReferenceFlag.WRITE;
}
/**
* Whether the reference is read-write.
* @public
*/
public isReadWrite(): boolean {
return this.#flag === ReferenceFlag.RW;
}
}
export { Reference, ReferenceFlag, ReferenceImplicitGlobal };