1/* 2 * Copyright (c) 2024 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 ts from 'typescript'; 17 18enum PermissionVaildTokenState { 19 Init, 20 LeftParenthesis, 21 RightParenthesis, 22 PermissionChar, 23 And, 24 Or, 25} 26 27interface PermissionVaildCalcInfo { 28 valid: boolean; 29 currentToken: PermissionVaildTokenState; 30 finish: boolean; 31 currentPermissionMatch: boolean; 32} 33 34interface PermissionVaildCalcGroup { 35 subQueue: string[]; 36 includeParenthesis: boolean; 37} 38 39export interface PermissionModule { 40 modulePath: string; 41 testPermissions: string[]; 42 permissions: string[]; 43} 44 45export class JsDocCheckService { 46 /** 47 * STER1. Parse the permission information configured on the API 48 * STEP2. Recursive queue to obtain whether the current permission configuration supports it 49 */ 50 static validPermission(comment: string, permissionsArray: string[]): boolean { 51 const permissionsItem: string[] = JsDocCheckService.getSplitsArrayWithDesignatedCharAndStr(comment ?? '', ' ') 52 .filter((item) => { 53 return item !== ''; 54 }); 55 const permissionsQueue: string[] = []; 56 permissionsItem.forEach((item: string) => { 57 //STEP1.1 Parse'(' 58 const leftParenthesisItem: string[] = JsDocCheckService.getSplitsArrayWithDesignatedCharAndArrayStr([item], '('); 59 //STEP1.2 Parse')' 60 const rightParenthesisItem: string[] = JsDocCheckService.getSplitsArrayWithDesignatedCharAndArrayStr(leftParenthesisItem, ')'); 61 permissionsQueue.push(...rightParenthesisItem); 62 }); 63 //STEP2 64 const calcValidResult: PermissionVaildCalcInfo = { 65 valid: false, 66 currentToken: PermissionVaildTokenState.Init, 67 finish: false, 68 currentPermissionMatch: true, 69 }; 70 JsDocCheckService.validPermissionRecursion(permissionsQueue, permissionsArray, calcValidResult); 71 return calcValidResult.valid; 72 } 73 74 private static validPermissionRecursion(permissionsQueue: string[], permissions: string[], calcValidResult: PermissionVaildCalcInfo): void { 75 if (permissionsQueue.some(item => ['(', ')'].includes(item))) { 76 const groups: PermissionVaildCalcGroup[] = JsDocCheckService.groupWithParenthesis(permissionsQueue); 77 const groupJoin: string[] = JsDocCheckService.getGroupItemPermission(groups, calcValidResult, permissions); 78 JsDocCheckService.getPermissionVaildAtoms(groupJoin, calcValidResult, permissions ?? []); 79 } else { 80 JsDocCheckService.getPermissionVaildAtoms(permissionsQueue, calcValidResult, permissions ?? []); 81 } 82 } 83 84 private static getSplitsArrayWithDesignatedCharAndStr(permission: string, designatedChar: string): string[] { 85 return permission.split(designatedChar).map(item => item.trim()); 86 } 87 88 private static getGroupItemPermission( 89 groups: PermissionVaildCalcGroup[], 90 calcValidResult: PermissionVaildCalcInfo, 91 permissions: string[]): string[] { 92 const groupJoin: string[] = []; 93 groups.forEach((groupItem: PermissionVaildCalcGroup) => { 94 if (groupItem.includeParenthesis) { 95 const calcValidResultItem: PermissionVaildCalcInfo = { 96 ...calcValidResult, 97 }; 98 const subStack: string[] = groupItem.subQueue.slice(1, groupItem.subQueue.length - 1); 99 JsDocCheckService.validPermissionRecursion(subStack, permissions, calcValidResultItem); 100 if (calcValidResultItem.valid) { 101 groupJoin.push(''); 102 } else { 103 groupJoin.push('NA'); 104 } 105 } else { 106 groupJoin.push(...groupItem.subQueue); 107 } 108 }); 109 return groupJoin; 110 } 111 112 private static groupWithParenthesis(stack: string[]): PermissionVaildCalcGroup[] { 113 let currentLeftParenthesisCount: number = 0; 114 const groups: PermissionVaildCalcGroup[] = []; 115 let currentGroupItem: PermissionVaildCalcGroup = { 116 subQueue: [], 117 includeParenthesis: false, 118 }; 119 stack.forEach((item: string, index: number) => { 120 if (item === '(') { 121 if (currentLeftParenthesisCount === 0) { 122 groups.push(currentGroupItem); 123 currentGroupItem = { 124 subQueue: [item], 125 includeParenthesis: true 126 }; 127 } else { 128 currentGroupItem.subQueue.push(item); 129 } 130 currentLeftParenthesisCount++; 131 } else if (item === ')') { 132 currentLeftParenthesisCount--; 133 currentGroupItem.subQueue.push(item); 134 if (currentLeftParenthesisCount === 0) { 135 groups.push(currentGroupItem); 136 currentGroupItem = { 137 subQueue: [], 138 includeParenthesis: false, 139 }; 140 } 141 } else { 142 currentGroupItem.subQueue.push(item); 143 if (index === stack.length - 1) { 144 groups.push(currentGroupItem); 145 } 146 } 147 }); 148 return groups; 149 } 150 151 private static getPermissionVaildAtoms(atomStacks: string[], calcValidResult: PermissionVaildCalcInfo, configPermissions: string[]): void { 152 if (calcValidResult.finish) { 153 return; 154 } 155 if (atomStacks[0] === 'and') { 156 calcValidResult.currentToken = PermissionVaildTokenState.And; 157 } else if (atomStacks[0] === 'or') { 158 calcValidResult.currentToken = PermissionVaildTokenState.Or; 159 } else { 160 if (calcValidResult.currentToken === PermissionVaildTokenState.Or) { 161 if (JsDocCheckService.inValidOrExpression( 162 atomStacks, 163 calcValidResult, 164 configPermissions 165 )) { 166 calcValidResult.currentPermissionMatch = false; 167 } 168 } else if (calcValidResult.currentToken === PermissionVaildTokenState.And) { 169 if (JsDocCheckService.inValidAndExpression( 170 atomStacks, 171 calcValidResult, 172 configPermissions 173 )) { 174 calcValidResult.currentPermissionMatch = false; 175 } 176 } else { 177 calcValidResult.currentPermissionMatch = 178 JsDocCheckService.validPermissionItem(atomStacks[0], configPermissions); 179 } 180 } 181 if (atomStacks.length > 1) { 182 JsDocCheckService.getPermissionVaildAtoms( 183 atomStacks.slice(1), 184 calcValidResult, 185 configPermissions 186 ); 187 } else { 188 calcValidResult.valid = calcValidResult.currentPermissionMatch; 189 calcValidResult.finish = true; 190 } 191 } 192 193 private static inValidOrExpression( 194 atomStacks: string[], 195 calcValidResult: PermissionVaildCalcInfo, 196 configPermissions: string[]): boolean { 197 if ( 198 !calcValidResult.currentPermissionMatch && 199 !JsDocCheckService.validPermissionItem(atomStacks[0], configPermissions) 200 ) { 201 calcValidResult.valid = false; 202 return true; 203 } 204 calcValidResult.currentPermissionMatch = true; 205 return false; 206 } 207 private static inValidAndExpression( 208 atomStacks: string[], 209 calcValidResult: PermissionVaildCalcInfo, 210 configPermissions: string[]): boolean { 211 if ( 212 !calcValidResult.currentPermissionMatch || 213 !JsDocCheckService.validPermissionItem(atomStacks[0], configPermissions) 214 ) { 215 calcValidResult.valid = false; 216 return true; 217 } 218 calcValidResult.currentPermissionMatch = 219 JsDocCheckService.validPermissionItem(atomStacks[0], configPermissions); 220 return false; 221 } 222 private static validPermissionItem(atomStackItem: string, configPermissions: string[]): boolean { 223 return atomStackItem === '' || configPermissions.includes(atomStackItem); 224 } 225 226 private static getSplitsArrayWithDesignatedCharAndArrayStr( 227 leftParenthesisItems: string[], 228 designatedChar: string 229 ): string[] { 230 const rightParenthesisItems: string[] = []; 231 leftParenthesisItems.forEach((leftParenthesisItem: string) => { 232 if (leftParenthesisItem.includes(designatedChar)) { 233 const rightParenthesis: string[] = 234 JsDocCheckService.getSplitsArrayWithDesignatedCharAndStr( 235 leftParenthesisItem, 236 designatedChar 237 ); 238 rightParenthesis.forEach((item: string) => { 239 if (item === '') { 240 rightParenthesisItems.push(designatedChar); 241 } else { 242 rightParenthesisItems.push(item); 243 } 244 }); 245 } else { 246 rightParenthesisItems.push(leftParenthesisItem); 247 } 248 }); 249 return rightParenthesisItems; 250 } 251} 252