• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import * as ts from "typescript";
17import * as jshelpers from "./jshelpers";
18
19export function isOctalNumber(num: string): boolean {
20    if (!num || num.length < 2) {
21        return false;
22    }
23
24    let reg = /^0[0-7]+$/;
25    if (!reg.test(num)) {
26        return false;
27    }
28
29    return true;
30}
31
32export function isNewOrCallExpression(node: ts.Node): boolean {
33    return node.kind === ts.SyntaxKind.NewExpression || node.kind === ts.SyntaxKind.CallExpression;
34}
35
36export function stringLiteralIsInRegExp(node: ts.Node) {
37    let parent = node.parent;
38    if (parent && isNewOrCallExpression(parent)) {
39        let expression = (<ts.NewExpression | ts.CallExpression>parent).expression;
40        if (ts.isIdentifier(expression)) {
41            if (expression.escapedText === "RegExp") {
42                return true;
43            }
44        }
45    }
46
47    return false;
48}
49
50export function isIncludeOctalEscapeSequence(text: string): boolean {
51    let reg = /\\(?:[1-7][0-7]{0,2}|[0-7]{2,3})/g;
52    if (!text.match(reg)) {
53        return false;
54    }
55
56    // Like \\1, should not be treated as an octal escape sequence
57    let index = 0;
58    while (index < text.length) {
59        if (text[index] == '\\' && index != text.length - 1) {
60            if (text[index + 1] == "\\") {
61                index++;
62            } else if (text[index + 1] >= '0' && text[index + 1] <= '7') {
63                return true;
64            }
65        }
66        index++;
67    }
68
69    return false;
70}
71
72export function isEvalOrArgumentsIdentifier(node: ts.Node): boolean {
73    return ts.isIdentifier(node) && (node.escapedText === "eval" || node.escapedText === "arguments");
74}
75
76export function isLeftHandSideExpressionKind(kind: ts.SyntaxKind) {
77    switch (kind) {
78        case ts.SyntaxKind.NumericLiteral:
79        case ts.SyntaxKind.BigIntLiteral:
80        case ts.SyntaxKind.StringLiteral:
81        case ts.SyntaxKind.RegularExpressionLiteral:
82        case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
83        case ts.SyntaxKind.Identifier:
84        case ts.SyntaxKind.FalseKeyword:
85        case ts.SyntaxKind.ImportKeyword:
86        case ts.SyntaxKind.NullKeyword:
87        case ts.SyntaxKind.SuperKeyword:
88        case ts.SyntaxKind.ThisKeyword:
89        case ts.SyntaxKind.TrueKeyword:
90        case ts.SyntaxKind.ArrayLiteralExpression:
91        case ts.SyntaxKind.ObjectLiteralExpression:
92        case ts.SyntaxKind.PropertyAccessExpression:
93        case ts.SyntaxKind.ElementAccessExpression:
94        case ts.SyntaxKind.CallExpression:
95        case ts.SyntaxKind.NewExpression:
96        case ts.SyntaxKind.TaggedTemplateExpression:
97        case ts.SyntaxKind.ParenthesizedExpression:
98        case ts.SyntaxKind.FunctionExpression:
99        case ts.SyntaxKind.TemplateExpression:
100        case ts.SyntaxKind.ClassExpression:
101        case ts.SyntaxKind.NonNullExpression:
102        case ts.SyntaxKind.MetaProperty:
103        case ts.SyntaxKind.JsxElement:
104        case ts.SyntaxKind.JsxSelfClosingElement:
105        case ts.SyntaxKind.JsxFragment:
106            return true;
107        default:
108            return false;
109    }
110}
111
112export function isLeftHandSideExpression(node: ts.Node) {
113    return isLeftHandSideExpressionKind(ts.skipPartiallyEmittedExpressions(node).kind);
114}
115
116export function isAssignmentOperator(token: ts.SyntaxKind) {
117    return token >= ts.SyntaxKind.FirstAssignment && token <= ts.SyntaxKind.LastAssignment;
118}
119
120export function isOriginalKeyword(node: ts.Identifier): boolean {
121    if (node.originalKeywordKind! >= ts.SyntaxKind.FirstFutureReservedWord &&
122        node.originalKeywordKind! <= ts.SyntaxKind.LastFutureReservedWord) {
123        return true;
124    }
125
126    return false;
127}
128
129export function isFunctionLikeDeclaration(node: ts.Node): node is ts.FunctionLikeDeclaration {
130    if (!node) {
131        return false;
132    }
133
134    switch (node.kind) {
135        case ts.SyntaxKind.ArrowFunction:
136        case ts.SyntaxKind.Constructor:
137        case ts.SyntaxKind.FunctionExpression:
138        case ts.SyntaxKind.FunctionDeclaration:
139        case ts.SyntaxKind.GetAccessor:
140        case ts.SyntaxKind.MethodDeclaration:
141        case ts.SyntaxKind.SetAccessor:
142            return true;
143        default:
144            return false;
145    }
146}
147
148export function allowLetAndConstDeclarations(node: ts.Node): boolean {
149    if (!node) {
150        return false;
151    }
152
153    switch (node.kind) {
154        case ts.SyntaxKind.DoStatement:
155        case ts.SyntaxKind.IfStatement:
156        case ts.SyntaxKind.ForStatement:
157        case ts.SyntaxKind.ForInStatement:
158        case ts.SyntaxKind.ForOfStatement:
159        case ts.SyntaxKind.WhileStatement:
160        case ts.SyntaxKind.WithStatement:
161            return false;
162        case ts.SyntaxKind.LabeledStatement:
163            return allowLetAndConstDeclarations(node.parent);
164        default:
165            break;
166    }
167    return true;
168}
169
170export function isGlobalIdentifier(name: string) {
171    switch (name) {
172        case "NaN":
173        case "undefined":
174        case "Infinity":
175            return true;
176        default:
177            return false;
178    }
179}
180
181export function isBindingPattern(node: ts.Node | undefined): boolean {
182    if (!node) {
183        return false;
184    }
185
186    switch (node.kind) {
187        case ts.SyntaxKind.ArrayBindingPattern:
188        case ts.SyntaxKind.ObjectBindingPattern:
189            return true;
190        default:
191            return false;
192    }
193}
194
195export function visibilityToString(flag: ts.ModifierFlags): string | undefined {
196    switch (flag) {
197        case ts.ModifierFlags.Private:
198            return "private";
199        case ts.ModifierFlags.Protected:
200            return "protected";
201        default:
202            return "public";
203    }
204}
205
206export function isDeclInGlobal(id: ts.Identifier): boolean {
207    let parent = id.parent;
208    while ((parent) && (parent.kind != ts.SyntaxKind.Block)) {
209        parent = parent.parent;
210    }
211
212    if (!parent) {
213        return true;
214    }
215
216    return false;
217}
218
219export function isInBlockScope(node: ts.Node): boolean {
220    switch (node.kind) {
221        case ts.SyntaxKind.SourceFile:
222        case ts.SyntaxKind.CaseBlock:
223        case ts.SyntaxKind.DefaultClause:
224        case ts.SyntaxKind.CaseClause:
225        case ts.SyntaxKind.Block:
226        case ts.SyntaxKind.Constructor:
227        case ts.SyntaxKind.MethodDeclaration:
228            return true;
229        default:
230            break;
231    }
232
233    return false;
234}
235
236export function isIncludeBackslash8Or9InString(text: string): boolean {
237
238    // \8 and \9 are not allowed in strict mode
239    let index = 0;
240    while (index < text.length) {
241        if (text[index] == '\\' && index != text.length - 1) {
242            if (text[index + 1] == "\\") {
243                index++;
244            } else if (text[index + 1] == '8' || text[index + 1] == '9') {
245                return true;
246            }
247        }
248        index++;
249    }
250
251    return false;
252}
253
254export function isOptionalParameter(node: ts.ParameterDeclaration): boolean {
255    if (jshelpers.hasQuestionToken(node)) {
256        return true;
257    }
258
259    if (!node.parent || !node.parent.parent) {
260        return false;
261    }
262
263    let iife = jshelpers.getImmediatelyInvokedFunctionExpression(node.parent);
264    if (iife) {
265        return !node.type && !node.dotDotDotToken && node.parent.parameters.indexOf(node) >= iife.arguments.length;
266    }
267
268    return false;
269}
270
271export function isStatement(kind: ts.SyntaxKind) {
272    if (kind >= ts.SyntaxKind.FirstStatement && kind <= ts.SyntaxKind.LastStatement) {
273        return true;
274    }
275
276    return false;
277}