@ttsc/lint 0.7.1 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -24
- package/lib/index.js.map +1 -1
- package/package.json +3 -3
- package/plugin/ast_helpers.go +158 -158
- package/plugin/compile.go +303 -303
- package/plugin/config.go +322 -322
- package/plugin/engine.go +152 -153
- package/plugin/host.go +128 -128
- package/plugin/main.go +21 -21
- package/plugin/rules_arrays.go +51 -51
- package/plugin/rules_console.go +22 -23
- package/plugin/rules_debugger.go +4 -4
- package/plugin/rules_dupes.go +134 -134
- package/plugin/rules_empty.go +68 -68
- package/plugin/rules_eval.go +28 -28
- package/plugin/rules_finally.go +91 -91
- package/plugin/rules_gap.go +188 -188
- package/plugin/rules_logic.go +268 -268
- package/plugin/rules_loops.go +89 -89
- package/plugin/rules_misc.go +43 -43
- package/plugin/rules_problems.go +396 -396
- package/plugin/rules_protos.go +17 -17
- package/plugin/rules_self.go +56 -56
- package/plugin/rules_strings.go +65 -65
- package/plugin/rules_suggestions.go +863 -863
- package/plugin/rules_throw.go +16 -16
- package/plugin/rules_ts.go +161 -161
- package/plugin/rules_ts_extra.go +467 -467
- package/plugin/rules_var.go +86 -86
- package/src/index.ts +1 -4
package/README.md
CHANGED
|
@@ -9,7 +9,48 @@
|
|
|
9
9
|
[](https://github.com/samchon/ttsc/tree/master/docs)
|
|
10
10
|
[](https://discord.gg/E94XhzrUCZ)
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Lint as compile errors.
|
|
13
|
+
|
|
14
|
+
Rules run inside `ttsc`'s `typescript-go` type-check pass — one compile, both checks.
|
|
15
|
+
|
|
16
|
+
## Demonstration
|
|
17
|
+
|
|
18
|
+
Given this file:
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// src/lint.ts
|
|
22
|
+
var x: number = 3;
|
|
23
|
+
let y: number = 4;
|
|
24
|
+
const z: string = 5;
|
|
25
|
+
|
|
26
|
+
console.log(x + y + z);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Run `ttsc` with `@ttsc/lint` enabled (see [Setup](#setup)):
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
$ pnpm ttsc
|
|
33
|
+
src/lint.ts:3:7 - error TS2322: Type 'number' is not assignable to type 'string'.
|
|
34
|
+
|
|
35
|
+
3 const z: string = 5;
|
|
36
|
+
~
|
|
37
|
+
|
|
38
|
+
src/lint.ts:2:5 - error TS17397: [prefer-const] Use const instead of let.
|
|
39
|
+
|
|
40
|
+
2 let y: number = 4;
|
|
41
|
+
~~~~~~~~~~~~~
|
|
42
|
+
|
|
43
|
+
src/lint.ts:1:1 - error TS11966: [no-var] Unexpected var, use let or const instead.
|
|
44
|
+
|
|
45
|
+
1 var x: number = 3;
|
|
46
|
+
~~~~~~~~~~~~~~~~~~
|
|
47
|
+
|
|
48
|
+
Found 3 errors in the same file, starting at: src/lint.ts:3
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Type errors (`TS2322`) and lint violations (`TS17397`, `TS11966`) come out together, in the same `error TSxxxxx` shape.
|
|
52
|
+
|
|
53
|
+
CI that already runs `ttsc` blocks on lint with no extra wiring.
|
|
13
54
|
|
|
14
55
|
## Setup
|
|
15
56
|
|
|
@@ -19,7 +60,9 @@ Install `ttsc`, TypeScript-Go, and the lint plugin:
|
|
|
19
60
|
npm install -D ttsc @typescript/native-preview @ttsc/lint
|
|
20
61
|
```
|
|
21
62
|
|
|
22
|
-
|
|
63
|
+
Add the plugin under `compilerOptions.plugins` in your `tsconfig.json`.
|
|
64
|
+
|
|
65
|
+
Keep `@ttsc/lint` as the first plugin entry — see [Plugin order](#plugin-order).
|
|
23
66
|
|
|
24
67
|
```jsonc
|
|
25
68
|
{
|
|
@@ -39,16 +82,20 @@ Open your project's `tsconfig.json`, then add this entry under `compilerOptions.
|
|
|
39
82
|
}
|
|
40
83
|
```
|
|
41
84
|
|
|
42
|
-
|
|
85
|
+
Then run your normal `ttsc` or `ttsx`:
|
|
43
86
|
|
|
44
87
|
```bash
|
|
45
88
|
npx ttsc
|
|
46
89
|
npx ttsx src/index.ts
|
|
47
90
|
```
|
|
48
91
|
|
|
49
|
-
Lint errors fail the command.
|
|
92
|
+
- Lint errors fail the command.
|
|
93
|
+
- Under `ttsx`, lint errors stop the program before your entrypoint runs.
|
|
94
|
+
- Lint warnings are printed without changing the exit code.
|
|
95
|
+
|
|
96
|
+
### External config file
|
|
50
97
|
|
|
51
|
-
You can also keep the
|
|
98
|
+
You can also keep the rules in a standalone file and reference it from `tsconfig.json`:
|
|
52
99
|
|
|
53
100
|
```jsonc
|
|
54
101
|
{
|
|
@@ -73,28 +120,17 @@ export default {
|
|
|
73
120
|
};
|
|
74
121
|
```
|
|
75
122
|
|
|
76
|
-
`config` accepts
|
|
123
|
+
The `config` field accepts:
|
|
77
124
|
|
|
78
|
-
|
|
125
|
+
- An inline object (shown earlier), **or** a path to a file ending in `.json`, `.js`, `.cjs`, `.mjs`, `.ts`, `.cts`, or `.mts`.
|
|
126
|
+
- For JS/TS configs: a `default` export, a named `config` export, a direct module export, or a function that returns the object.
|
|
127
|
+
- Relative paths resolve from the directory of the owning `tsconfig.json`.
|
|
79
128
|
|
|
80
|
-
|
|
81
|
-
{
|
|
82
|
-
"compilerOptions": {
|
|
83
|
-
"plugins": [
|
|
84
|
-
{
|
|
85
|
-
"transform": "@ttsc/lint",
|
|
86
|
-
"config": {
|
|
87
|
-
"no-var": "error"
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
]
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
```
|
|
129
|
+
## Plugin order
|
|
94
130
|
|
|
95
|
-
|
|
131
|
+
`@ttsc/lint` must be the first plugin in `compilerOptions.plugins`.
|
|
96
132
|
|
|
97
|
-
|
|
133
|
+
It inspects the source you wrote, so output plugins (`@ttsc/banner`, `@ttsc/paths`, `@ttsc/strip`) have to come after it.
|
|
98
134
|
|
|
99
135
|
```jsonc
|
|
100
136
|
{
|
|
@@ -112,7 +148,9 @@ Inline `config` is also accepted:
|
|
|
112
148
|
}
|
|
113
149
|
```
|
|
114
150
|
|
|
115
|
-
|
|
151
|
+
## Scope
|
|
152
|
+
|
|
153
|
+
Diagnostic-only today: no autofix, no recommended preset, no custom rule loading, and no cross-file lint rules.
|
|
116
154
|
|
|
117
155
|
## Rules
|
|
118
156
|
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,0DAA6B;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,0DAA6B;AAK7B,qDAAmC;AAEnC,0BACE,QAA0D;IAE1D,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,mBAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC;QAC/C,KAAK,EAAE,OAAO;KACf,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttsc/lint",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "Reference ttsc plugin: ESLint-style lint rules hosted in the same Program/Checker as the type-check pass.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"plugin"
|
|
28
28
|
],
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
30
|
+
"@typescript/native-preview": "7.0.0-dev.20260501.1",
|
|
31
31
|
"@types/node": "^25.3.0",
|
|
32
32
|
"rimraf": "^6.1.2",
|
|
33
|
-
"ttsc": "0.7.
|
|
33
|
+
"ttsc": "0.7.3"
|
|
34
34
|
},
|
|
35
35
|
"repository": {
|
|
36
36
|
"type": "git",
|
package/plugin/ast_helpers.go
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
package main
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
-
|
|
4
|
+
"strings"
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
7
|
+
shimscanner "github.com/microsoft/typescript-go/shim/scanner"
|
|
8
8
|
)
|
|
9
9
|
|
|
10
10
|
// nodeText returns the source text under a node with all leading
|
|
@@ -14,213 +14,213 @@ import (
|
|
|
14
14
|
// would include any preceding comment because tsgo's Pos points at
|
|
15
15
|
// the start of leading trivia, not the actual token.
|
|
16
16
|
func nodeText(file *shimast.SourceFile, node *shimast.Node) string {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
if file == nil || node == nil {
|
|
18
|
+
return ""
|
|
19
|
+
}
|
|
20
|
+
src := file.Text()
|
|
21
|
+
end := node.End()
|
|
22
|
+
pos := shimscanner.SkipTrivia(src, node.Pos())
|
|
23
|
+
if pos < 0 || end > len(src) || pos >= end {
|
|
24
|
+
return ""
|
|
25
|
+
}
|
|
26
|
+
return strings.TrimRight(src[pos:end], " \t\r\n")
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
// identifierText returns the lexical name of an Identifier node, or "" if
|
|
30
30
|
// the node isn't an Identifier.
|
|
31
31
|
func identifierText(node *shimast.Node) string {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
if node == nil || node.Kind != shimast.KindIdentifier {
|
|
33
|
+
return ""
|
|
34
|
+
}
|
|
35
|
+
id := node.AsIdentifier()
|
|
36
|
+
if id == nil {
|
|
37
|
+
return ""
|
|
38
|
+
}
|
|
39
|
+
return id.Text
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// stripParens descends through ParenthesizedExpression nodes and returns
|
|
43
43
|
// the first non-parenthesized child. ESLint rules typically operate on
|
|
44
44
|
// the canonical form.
|
|
45
45
|
func stripParens(node *shimast.Node) *shimast.Node {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
46
|
+
for node != nil && node.Kind == shimast.KindParenthesizedExpression {
|
|
47
|
+
next := node.AsParenthesizedExpression()
|
|
48
|
+
if next == nil || next.Expression == nil {
|
|
49
|
+
return node
|
|
50
|
+
}
|
|
51
|
+
node = next.Expression
|
|
52
|
+
}
|
|
53
|
+
return node
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
// isMatchingPropertyAccess reports whether `node` reads the chain
|
|
57
57
|
// `head.tail[0].tail[1]…`. Useful for detecting `obj.__proto__` or
|
|
58
58
|
// `console.log` shapes regardless of nesting.
|
|
59
59
|
func isMatchingPropertyAccess(node *shimast.Node, head string, tail ...string) bool {
|
|
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
|
-
|
|
60
|
+
if node == nil || node.Kind != shimast.KindPropertyAccessExpression {
|
|
61
|
+
return false
|
|
62
|
+
}
|
|
63
|
+
chain := []*shimast.Node{}
|
|
64
|
+
cur := node
|
|
65
|
+
for cur != nil && cur.Kind == shimast.KindPropertyAccessExpression {
|
|
66
|
+
access := cur.AsPropertyAccessExpression()
|
|
67
|
+
if access == nil {
|
|
68
|
+
return false
|
|
69
|
+
}
|
|
70
|
+
chain = append([]*shimast.Node{access.Name()}, chain...)
|
|
71
|
+
cur = access.Expression
|
|
72
|
+
}
|
|
73
|
+
if cur == nil || identifierText(cur) != head {
|
|
74
|
+
return false
|
|
75
|
+
}
|
|
76
|
+
if len(chain) != len(tail) {
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
for i, want := range tail {
|
|
80
|
+
if identifierText(chain[i]) != want {
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return true
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
// isLiteralBoolean returns the boolean value (and ok=true) for a
|
|
88
88
|
// `KindTrueKeyword` / `KindFalseKeyword` literal. Other nodes return
|
|
89
89
|
// (false, false).
|
|
90
90
|
func isLiteralBoolean(node *shimast.Node) (bool, bool) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
91
|
+
if node == nil {
|
|
92
|
+
return false, false
|
|
93
|
+
}
|
|
94
|
+
switch node.Kind {
|
|
95
|
+
case shimast.KindTrueKeyword:
|
|
96
|
+
return true, true
|
|
97
|
+
case shimast.KindFalseKeyword:
|
|
98
|
+
return false, true
|
|
99
|
+
}
|
|
100
|
+
return false, false
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
// isLiteralExpression returns true for nodes whose value is intrinsically
|
|
104
104
|
// truthy / falsy at parse time — these flag `no-constant-condition` etc.
|
|
105
105
|
func isLiteralExpression(node *shimast.Node) bool {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
106
|
+
if node == nil {
|
|
107
|
+
return false
|
|
108
|
+
}
|
|
109
|
+
switch node.Kind {
|
|
110
|
+
case
|
|
111
|
+
shimast.KindStringLiteral,
|
|
112
|
+
shimast.KindNumericLiteral,
|
|
113
|
+
shimast.KindBigIntLiteral,
|
|
114
|
+
shimast.KindNoSubstitutionTemplateLiteral,
|
|
115
|
+
shimast.KindRegularExpressionLiteral,
|
|
116
|
+
shimast.KindTrueKeyword,
|
|
117
|
+
shimast.KindFalseKeyword,
|
|
118
|
+
shimast.KindNullKeyword:
|
|
119
|
+
return true
|
|
120
|
+
}
|
|
121
|
+
return false
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
// callCalleeName returns the simple-identifier callee of a CallExpression
|
|
125
125
|
// (e.g. `eval` from `eval("...")`). Returns "" when the callee is more
|
|
126
126
|
// complex than a bare identifier.
|
|
127
127
|
func callCalleeName(call *shimast.CallExpression) string {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
if call == nil || call.Expression == nil {
|
|
129
|
+
return ""
|
|
130
|
+
}
|
|
131
|
+
return identifierText(call.Expression)
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
// numericLiteralText returns the literal text of a numeric / bigint
|
|
135
135
|
// literal, normalized for the comparisons rules need (`-0`, `0xFF`).
|
|
136
136
|
func numericLiteralText(node *shimast.Node) string {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
137
|
+
if node == nil {
|
|
138
|
+
return ""
|
|
139
|
+
}
|
|
140
|
+
switch node.Kind {
|
|
141
|
+
case shimast.KindNumericLiteral:
|
|
142
|
+
if lit := node.AsNumericLiteral(); lit != nil {
|
|
143
|
+
return lit.Text
|
|
144
|
+
}
|
|
145
|
+
case shimast.KindBigIntLiteral:
|
|
146
|
+
if lit := node.AsBigIntLiteral(); lit != nil {
|
|
147
|
+
return lit.Text
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return ""
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
// stringLiteralText returns the value of a string-shaped literal:
|
|
154
154
|
// StringLiteral or NoSubstitutionTemplateLiteral.
|
|
155
155
|
func stringLiteralText(node *shimast.Node) string {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
156
|
+
if node == nil {
|
|
157
|
+
return ""
|
|
158
|
+
}
|
|
159
|
+
switch node.Kind {
|
|
160
|
+
case shimast.KindStringLiteral:
|
|
161
|
+
if lit := node.AsStringLiteral(); lit != nil {
|
|
162
|
+
return lit.Text
|
|
163
|
+
}
|
|
164
|
+
case shimast.KindNoSubstitutionTemplateLiteral:
|
|
165
|
+
if lit := node.AsNoSubstitutionTemplateLiteral(); lit != nil {
|
|
166
|
+
return lit.Text
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return ""
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
// walkDescendants visits node and every child below it, depth-first.
|
|
173
173
|
func walkDescendants(node *shimast.Node, visit func(*shimast.Node)) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
174
|
+
if node == nil {
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
visit(node)
|
|
178
|
+
node.ForEachChild(func(child *shimast.Node) bool {
|
|
179
|
+
walkDescendants(child, visit)
|
|
180
|
+
return false
|
|
181
|
+
})
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
func bindingIdentifierNames(node *shimast.Node) []string {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
185
|
+
if node == nil {
|
|
186
|
+
return nil
|
|
187
|
+
}
|
|
188
|
+
if name := identifierText(node); name != "" {
|
|
189
|
+
return []string{name}
|
|
190
|
+
}
|
|
191
|
+
if node.Kind != shimast.KindObjectBindingPattern && node.Kind != shimast.KindArrayBindingPattern {
|
|
192
|
+
return nil
|
|
193
|
+
}
|
|
194
|
+
var names []string
|
|
195
|
+
walkDescendants(node, func(child *shimast.Node) {
|
|
196
|
+
if child == node {
|
|
197
|
+
return
|
|
198
|
+
}
|
|
199
|
+
if name := identifierText(child); name != "" {
|
|
200
|
+
names = append(names, name)
|
|
201
|
+
}
|
|
202
|
+
})
|
|
203
|
+
return names
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
func isLiteralLike(node *shimast.Node) bool {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
207
|
+
node = stripParens(node)
|
|
208
|
+
if node == nil {
|
|
209
|
+
return false
|
|
210
|
+
}
|
|
211
|
+
if isLiteralExpression(node) {
|
|
212
|
+
return true
|
|
213
|
+
}
|
|
214
|
+
if node.Kind == shimast.KindPrefixUnaryExpression {
|
|
215
|
+
prefix := node.AsPrefixUnaryExpression()
|
|
216
|
+
if prefix == nil {
|
|
217
|
+
return false
|
|
218
|
+
}
|
|
219
|
+
switch prefix.Operator {
|
|
220
|
+
case shimast.KindPlusToken, shimast.KindMinusToken:
|
|
221
|
+
return prefix.Operand != nil &&
|
|
222
|
+
(prefix.Operand.Kind == shimast.KindNumericLiteral || prefix.Operand.Kind == shimast.KindBigIntLiteral)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return false
|
|
226
226
|
}
|