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}