• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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