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