1/* 2 * Copyright (c) 2023 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 { ErrorTagFormat, ErrorMessage, PermissionData } from '../../../typedef/checker/result_type'; 17import { Comment } from '../../../typedef/parser/Comment'; 18import { CommonFunctions, throwsTagDescriptionArr } from '../../../utils/checkUtils'; 19import { ApiInfo, ApiType, ClassInfo, GenericInfo, TypeAliasInfo, TypeAliasType, TypeParamInfo } from '../../../typedef/parser/ApiInfoDefination'; 20import { MethodInfo, PropertyInfo, ParamInfo } from '../../../typedef/parser/ApiInfoDefination'; 21import { PunctuationMark } from '../../../utils/Constant'; 22import { SystemCapability } from '../config/syscapConfigFile.json'; 23import { module } from '../config/permissionConfigFile.json'; 24import { toNumber } from 'lodash'; 25import { ApiMaxVersion } from '../config/api_check_version.json'; 26 27export class TagValueCheck { 28 /** 29 * all jsdoc tag value check 30 * @param { ApiInfo } singleApi 31 * @param { Comment.JsDocInfo } apiJsdoc 32 * @returns { ErrorTagFormat[] } 33 */ 34 static tagValueCheck(singleApi: ApiInfo, apiJsdoc: Comment.JsDocInfo): ErrorTagFormat[] { 35 const tagValueError: ErrorTagFormat[] = []; 36 const tagsName: Comment.CommentTag[] | undefined = apiJsdoc.tags; 37 let throwsIndex: number = 0; 38 let paramIndex: number = -1; 39 if (tagsName === undefined) { 40 return tagValueError; 41 } 42 const tagsTag: string[] = []; 43 tagsName.forEach((tagName: Comment.CommentTag) => { tagsTag.push(tagName.tag); }); 44 const isDeprecated: boolean = tagsTag.includes('deprecated'); 45 tagsName.forEach((tag) => { 46 let errorTagInfo: ErrorTagFormat = { 47 state: true, 48 errorInfo: '', 49 }; 50 switch (tag.tag) { 51 case 'since': 52 errorTagInfo = TagValueCheck.sinceTagValueCheck(singleApi, tag); 53 break; 54 case 'extends': 55 case 'implements': 56 errorTagInfo = !isDeprecated ? TagValueCheck.extendsTagValueCheck(singleApi, tag) : errorTagInfo; 57 break; 58 case 'enum': 59 errorTagInfo = !isDeprecated ? TagValueCheck.enumTagValueCheck(tag) : errorTagInfo; 60 break; 61 case 'returns': 62 errorTagInfo = !isDeprecated ? TagValueCheck.returnsTagValueCheck(singleApi, tag) : errorTagInfo; 63 break; 64 case 'namespace': 65 case 'typedef': 66 case 'struct': 67 errorTagInfo = !isDeprecated ? TagValueCheck.outerTagValueCheck(singleApi as ClassInfo, tag) : errorTagInfo; 68 break; 69 case 'type': 70 errorTagInfo = !isDeprecated ? TagValueCheck.typeTagValueCheck(singleApi, tag) : errorTagInfo; 71 break; 72 case 'syscap': 73 errorTagInfo = TagValueCheck.syscapTagValueCheck(tag); 74 break; 75 case 'default': 76 errorTagInfo = !isDeprecated ? TagValueCheck.defaultTagValueCheck(tag) : errorTagInfo; 77 break; 78 case 'deprecated': 79 errorTagInfo = TagValueCheck.deprecatedTagValueCheck(tag); 80 break; 81 case 'permission': 82 errorTagInfo = !isDeprecated ? TagValueCheck.permissionTagValueCheck(tag) : errorTagInfo; 83 break; 84 case 'throws': 85 if (singleApi.getLastJsDocInfo()?.deprecatedVersion === '-1') { 86 throwsIndex += 1; 87 errorTagInfo = !isDeprecated ? TagValueCheck.throwsTagValueCheck(tag, throwsIndex, tagsName) : errorTagInfo; 88 } 89 break; 90 case 'param': 91 paramIndex += 1; 92 errorTagInfo = !isDeprecated ? TagValueCheck.paramTagValueCheck(singleApi, tag, paramIndex) : errorTagInfo; 93 break; 94 case 'useinstead': 95 errorTagInfo = TagValueCheck.useinsteadTagValueCheck(tag); 96 break; 97 default: 98 break; 99 } 100 if (!errorTagInfo.state) { 101 tagValueError.push(errorTagInfo); 102 } 103 }); 104 return tagValueError; 105 } 106 107 /** 108 * since tag value check 109 * @param { Comment.CommentTag } tag 110 * @returns { ErrorTagFormat } 111 */ 112 static sinceTagValueCheck(singleApi: ApiInfo, tag: Comment.CommentTag): ErrorTagFormat { 113 const sinceValueCheckResult: ErrorTagFormat = { 114 state: true, 115 errorInfo: '', 116 }; 117 const sinceValue: string = CommonFunctions.getSinceVersion(tag.name); 118 const sinceValueIsNumber: boolean = /^\d+$/.test(sinceValue); 119 const allSinceValue: string[] = []; 120 singleApi.getJsDocInfos().forEach((tagInfo: Comment.JsDocInfo) => { 121 allSinceValue.push(tagInfo.since); 122 }); 123 const newSinceValueArr = Array.from(new Set(allSinceValue)); 124 if (!sinceValueIsNumber) { 125 sinceValueCheckResult.state = false; 126 sinceValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_SINCE; 127 } else if (toNumber(sinceValue) > toNumber(ApiMaxVersion)) { 128 sinceValueCheckResult.state = false; 129 sinceValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_SINCE_NUMBER; 130 } 131 if (allSinceValue.length !== newSinceValueArr.length) { 132 sinceValueCheckResult.state = false; 133 sinceValueCheckResult.errorInfo = sinceValueCheckResult.errorInfo + ErrorMessage.ERROR_INFO_VALUE_SINCE_JSDOC; 134 } 135 return sinceValueCheckResult; 136 } 137 138 /** 139 * extends tag value check 140 * @param { ApiInfo } singleApi 141 * @param { Comment.CommentTag } tag 142 * @returns { ErrorTagFormat } 143 */ 144 static extendsTagValueCheck(singleApi: ApiInfo, tag: Comment.CommentTag): ErrorTagFormat { 145 const extendsValueCheckResult: ErrorTagFormat = { 146 state: true, 147 errorInfo: '', 148 }; 149 let extendsTagValue: string = tag.name + tag.description; 150 if (singleApi.getApiType() === ApiType.CLASS || singleApi.getApiType() === ApiType.INTERFACE) { 151 const extendsApiValue: string = CommonFunctions.getExtendsApiValue(singleApi); 152 const ImplementsApiValue: string = CommonFunctions.getImplementsApiValue(singleApi); 153 if (tag.tag === 'extends' && extendsTagValue.replace(/\s/g, '') !== extendsApiValue) { 154 extendsValueCheckResult.state = false; 155 extendsValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_EXTENDS; 156 } 157 if (tag.tag === 'implements' && extendsTagValue !== ImplementsApiValue) { 158 extendsValueCheckResult.state = false; 159 extendsValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_IMPLEMENTS; 160 } 161 } 162 return extendsValueCheckResult; 163 } 164 165 /** 166 * enum tag value check 167 * @param { Comment.CommentTag } tag 168 * @returns { ErrorTagFormat } 169 */ 170 static enumTagValueCheck(tag: Comment.CommentTag): ErrorTagFormat { 171 const enumValueCheckResult: ErrorTagFormat = { 172 state: true, 173 errorInfo: '', 174 }; 175 const enumValues = ['string', 'number']; 176 if (enumValues.indexOf(tag.type) === -1) { 177 enumValueCheckResult.state = false; 178 enumValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_ENUM; 179 } 180 return enumValueCheckResult; 181 } 182 183 /** 184 * retuens tag value check 185 * @param { ApiInfo } singleApi 186 * @param { Comment.CommentTag } tag 187 * @returns { ErrorTagFormat } 188 */ 189 static returnsTagValueCheck(singleApi: ApiInfo, tag: Comment.CommentTag): ErrorTagFormat { 190 const returnsValueCheckResult: ErrorTagFormat = { 191 state: true, 192 errorInfo: '', 193 }; 194 const returnsTagValue: string = tag.type.replace(/\s/g, ''); 195 let returnsApiValue: string[] = []; 196 const legalApiArr: string[] = [ApiType.METHOD, ApiType.TYPE_ALIAS]; 197 if (!legalApiArr.includes(singleApi.getApiType())) { 198 return returnsValueCheckResult; 199 } 200 const spacealCase: string[] = CommonFunctions.judgeSpecialCase((singleApi as MethodInfo).returnValueType); 201 if (singleApi.getApiType() === ApiType.TYPE_ALIAS) { 202 returnsApiValue.push((singleApi as TypeAliasInfo).getReturnType().join()); 203 } else { 204 returnsApiValue = spacealCase.length > 0 ? spacealCase : (singleApi as MethodInfo).getReturnValue(); 205 } 206 207 if (returnsApiValue.length === 0) { 208 returnsValueCheckResult.state = false; 209 returnsValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_RETURNS; 210 } else if (returnsTagValue !== returnsApiValue.join('|').replace(/\s/g, '')) { 211 returnsValueCheckResult.state = false; 212 returnsValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_RETURNS; 213 } 214 return returnsValueCheckResult; 215 } 216 217 /** 218 * namespace tag value check 219 * @param { ClassInfo } singleApi 220 * @param { Comment.CommentTag } tag 221 * @returns { ErrorTagFormat } 222 */ 223 static outerTagValueCheck(singleApi: ClassInfo, tag: Comment.CommentTag): ErrorTagFormat { 224 const outerValueCheckResult: ErrorTagFormat = { 225 state: true, 226 errorInfo: '', 227 }; 228 let tagValue: string = tag.name; 229 let tagType: string = tag.type; 230 let apiValue: string = singleApi.getApiName(); 231 const definedText: string = singleApi.getDefinedText(); 232 if (tag.tag === 'namespace' && tagValue !== apiValue) { 233 outerValueCheckResult.state = false; 234 outerValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_NAMESPACE; 235 } 236 if (tag.tag === 'typedef') { 237 if (singleApi.getApiType() === ApiType.TYPE_ALIAS) { 238 const ordinaryTagValue: string = (singleApi as ApiInfo as TypeAliasInfo).getType().join('|').replace(/\s/g, ''); 239 const typeIsFuction: boolean = (singleApi as ApiInfo as TypeAliasInfo).getTypeIsFunction(); 240 const typeIsObject: boolean = (singleApi as ApiInfo as TypeAliasInfo).getTypeName() === TypeAliasType.OBJECT_TYPE; 241 apiValue = typeIsFuction ? 'function' : typeIsObject ? 'object' : ordinaryTagValue; 242 } else { 243 const genericArr: GenericInfo[] = singleApi.getGenericInfo(); 244 if (genericArr.length > 0) { 245 let genericInfo = genericArr.map((generic) => { 246 return generic.getGenericContent(); 247 }).join(','); 248 apiValue = apiValue + '<' + genericInfo + '>'; 249 } 250 } 251 if (singleApi.getApiType() === 'Interface' && tagValue !== apiValue) { 252 outerValueCheckResult.state = false; 253 outerValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_TYPEDEF; 254 } else if (singleApi.getApiType() === ApiType.TYPE_ALIAS && !singleApi.getIsExport() && 255 tagType.replace(/\s/g, '') !== apiValue) { 256 outerValueCheckResult.state = false; 257 outerValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_TYPEDEF; 258 } 259 } 260 if (tag.tag === 'struct' && tagType !== apiValue) { 261 outerValueCheckResult.state = false; 262 outerValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_STRUCT; 263 } 264 return outerValueCheckResult; 265 } 266 267 /** 268 * type tag value check 269 * @param { ApiInfo } singleApi 270 * @param { Comment.CommentTag } tag 271 * @returns { ErrorTagFormat } 272 */ 273 static typeTagValueCheck(singleApi: ApiInfo, tag: Comment.CommentTag): ErrorTagFormat { 274 const typeValueCheckResult: ErrorTagFormat = { 275 state: true, 276 errorInfo: '', 277 }; 278 if (singleApi.getApiType() !== ApiType.PROPERTY) { 279 return typeValueCheckResult; 280 } 281 let typeTagValue: string = tag.type.replace(/\s/g, ''); 282 let typeApiValue: string[] = []; 283 const spacealCase: string[] = CommonFunctions.judgeSpecialCase((singleApi as PropertyInfo).typeKind); 284 if (spacealCase.length > 0) { 285 typeApiValue = spacealCase; 286 } else { 287 typeApiValue = (singleApi as PropertyInfo).type; 288 } 289 290 let typeApiUnionValue: string = typeApiValue.join('|').replace(/\s/g, ''); 291 const isOptional: boolean = !(singleApi as PropertyInfo).getIsRequired(); 292 if (isOptional && typeApiValue.length === 1) { 293 typeApiUnionValue = '?' + typeApiUnionValue; 294 } else if (isOptional && typeApiValue.length > 1) { 295 typeApiUnionValue = '?(' + typeApiUnionValue + ')'; 296 } 297 if (typeTagValue.replace(/\s/g, '') !== typeApiUnionValue.replace(/\s/g, '')) { 298 typeValueCheckResult.state = false; 299 typeValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_TYPE; 300 } 301 return typeValueCheckResult; 302 } 303 /** 304 * syacap tag value check 305 * @param { Comment.CommentTag } tag 306 * @returns { ErrorTagFormat } 307 */ 308 static syscapTagValueCheck(tag: Comment.CommentTag): ErrorTagFormat { 309 const syscapValueCheckResult: ErrorTagFormat = { 310 state: true, 311 errorInfo: '', 312 }; 313 const syscapRule: string[] = SystemCapability; 314 const syscapTagValue: string = tag.name; 315 if (!syscapRule.includes(syscapTagValue)) { 316 syscapValueCheckResult.state = false; 317 syscapValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_SYSCAP; 318 } 319 return syscapValueCheckResult; 320 } 321 /** 322 * default tag value check 323 * @param { Comment.CommentTag } tag 324 * @returns { ErrorTagFormat } 325 */ 326 static defaultTagValueCheck(tag: Comment.CommentTag): ErrorTagFormat { 327 const defaultValueCheckResult: ErrorTagFormat = { 328 state: true, 329 errorInfo: '', 330 }; 331 const defaultTagValue: string = tag.name + tag.type; 332 if (defaultTagValue.length === 0) { 333 defaultValueCheckResult.state = false; 334 defaultValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_DEFAULT; 335 } 336 return defaultValueCheckResult; 337 } 338 339 /** 340 * deprecated tag value check 341 * @param { Comment.CommentTag } tag 342 * @returns { ErrorTagFormat } 343 */ 344 static deprecatedTagValueCheck(tag: Comment.CommentTag): ErrorTagFormat { 345 const deprecatedValueCheckResult: ErrorTagFormat = { 346 state: true, 347 errorInfo: '', 348 }; 349 const deprecatedFixedField: string = tag.name; 350 351 const deprecatedVersion: string = CommonFunctions.getSinceVersion(tag.description); 352 const isNumber: boolean = /^\d+$/.test(deprecatedVersion); 353 if (deprecatedFixedField !== 'since' || !isNumber) { 354 deprecatedValueCheckResult.state = false; 355 deprecatedValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_DEPRECATED; 356 } 357 return deprecatedValueCheckResult; 358 } 359 /** 360 * permission tag value check 361 * @param { Comment.CommentTag } tag 362 * @returns { ErrorTagFormat } 363 */ 364 static permissionTagValueCheck(tag: Comment.CommentTag): ErrorTagFormat { 365 const permissionValueCheckResult: ErrorTagFormat = { 366 state: true, 367 errorInfo: '', 368 }; 369 370 const permissionRuleDatas: PermissionData[] = module.definePermissions as PermissionData[]; 371 const permissionRule: string[] = []; 372 permissionRuleDatas.forEach((permissionRuleData: PermissionData) => { 373 permissionRule.push(permissionRuleData.name); 374 }); 375 const permissionTagValue: string = tag.name + tag.description; 376 const permissionArr = permissionTagValue 377 .replace(/(\s|\(|\))/g, '') 378 .replace(/(or|and)/g, '$') 379 .split('$'); 380 permissionArr.forEach((permissionItem) => { 381 if (!permissionRule.includes(permissionItem)) { 382 permissionValueCheckResult.state = false; 383 permissionValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_PERMISSION; 384 } 385 }); 386 return permissionValueCheckResult; 387 } 388 389 /** 390 * throws tag value check 391 * @param { Comment.CommentTag } tag 392 * @param { number } throwsIndex 393 * @returns { ErrorTagFormat } 394 */ 395 static throwsTagValueCheck(tag: Comment.CommentTag, throwsIndex: number, tagsName: Comment.CommentTag[] | undefined): ErrorTagFormat { 396 const throwsValueCheckResult: ErrorTagFormat = { 397 state: true, 398 errorInfo: '', 399 }; 400 const throwsTagType: string = tag.type; 401 const throwsTagName: string = tag.name; 402 const isNumber: boolean = /^\d+$/.test(throwsTagName); 403 if (throwsTagType !== 'BusinessError') { 404 throwsValueCheckResult.state = false; 405 throwsValueCheckResult.errorInfo = CommonFunctions.createErrorInfo(ErrorMessage.ERROR_INFO_VALUE1_THROWS, [ 406 JSON.stringify(throwsIndex), 407 ]); 408 } 409 if (!isNumber) { 410 throwsValueCheckResult.state = false; 411 throwsValueCheckResult.errorInfo = CommonFunctions.createErrorInfo(ErrorMessage.ERROR_INFO_VALUE2_THROWS, [ 412 JSON.stringify(throwsIndex), 413 ]); 414 } else if (throwsTagName === '401') { 415 const specialThrowsDescription: string = tag.description; 416 const throws401DescriptionStartIndexof: number = specialThrowsDescription.indexOf(throwsTagDescriptionArr[0]); 417 const throws401DescriptionOneIndexof: number = specialThrowsDescription.indexOf(throwsTagDescriptionArr[1]); 418 const throws401DescriptionTwoIndexof: number = specialThrowsDescription.indexOf(throwsTagDescriptionArr[2]); 419 const throws401DescriptionThreeIndexof: number = specialThrowsDescription.indexOf(throwsTagDescriptionArr[3]); 420 const hasDescriptionContent: boolean = throws401DescriptionOneIndexof !== -1 || 421 throws401DescriptionTwoIndexof !== -1 || throws401DescriptionThreeIndexof !== -1; 422 const descriptionReg = new RegExp(`${throwsTagDescriptionArr[0]}|${throwsTagDescriptionArr[1]}|${throwsTagDescriptionArr[2]}|${throwsTagDescriptionArr[3]}|<br>`, 'g'); 423 const hasElseString: boolean = /[A-Za-z]+/.test(specialThrowsDescription.replace(descriptionReg, '')); 424 if (throws401DescriptionStartIndexof === -1 || throws401DescriptionStartIndexof > 1 || !hasDescriptionContent || 425 hasElseString) { 426 throwsValueCheckResult.state = false; 427 throwsValueCheckResult.errorInfo = throwsValueCheckResult.errorInfo + ErrorMessage.ERROR_INFO_VALUE3_THROWS; 428 } 429 } 430 const allTagName: string[] = []; 431 tagsName?.forEach((tag: Comment.CommentTag) => { 432 allTagName.push(tag.tag); 433 }); 434 return throwsValueCheckResult; 435 } 436 437 /** 438 * param tag value check 439 * @param { ApiInfo } singleApi 440 * @param { Comment.CommentTag } tag 441 * @param { number } paramIndex 442 * @returns { ErrorTagFormat } 443 */ 444 static paramTagValueCheck(singleApi: ApiInfo, tag: Comment.CommentTag, paramIndex: number): ErrorTagFormat { 445 const paramValueCheckResult: ErrorTagFormat = { 446 state: true, 447 errorInfo: '', 448 }; 449 const legalApiArr: string[] = [ApiType.METHOD, ApiType.TYPE_ALIAS]; 450 if (!legalApiArr.includes(singleApi.getApiType())) { 451 return paramValueCheckResult; 452 } 453 const paramTagType: string = tag.type.replace(/\s/g, ''); 454 const paramTagName: string = tag.name; 455 456 457 let paramApiName: string = ''; 458 let paramApiType: string[] = []; 459 460 if (singleApi.getApiType() === ApiType.TYPE_ALIAS) { 461 const typeParams: ParamInfo[] = (singleApi as TypeAliasInfo).getParamInfos(); 462 paramApiName = typeParams.length > paramIndex ? typeParams[paramIndex].getApiName() : ''; 463 paramApiType = typeParams.length > paramIndex ? typeParams[paramIndex].getType() : ['']; 464 } else { 465 const paramApiInfos: ParamInfo[] = (singleApi as MethodInfo).getParams(); 466 paramApiName = paramApiInfos[paramIndex]?.getApiName(); 467 const spacealCase: string[] = paramApiInfos[paramIndex] ? 468 CommonFunctions.judgeSpecialCase(paramApiInfos[paramIndex].paramType) : []; 469 paramApiType = spacealCase.length > 0 ? spacealCase : paramApiInfos[paramIndex]?.getType(); 470 } 471 472 if (paramTagName !== paramApiName) { 473 paramValueCheckResult.state = false; 474 paramValueCheckResult.errorInfo = CommonFunctions.createErrorInfo(ErrorMessage.ERROR_INFO_VALUE_PARAM, [ 475 JSON.stringify(paramIndex + 1), 476 JSON.stringify(paramIndex + 1), 477 ]); 478 } 479 if (paramApiType === undefined || paramTagType !== paramApiType.join('|').replace(/\s/g, '')) { 480 paramValueCheckResult.state = false; 481 paramValueCheckResult.errorInfo = 482 paramValueCheckResult.errorInfo + 483 CommonFunctions.createErrorInfo(ErrorMessage.ERROR_INFO_TYPE_PARAM, [ 484 JSON.stringify(paramIndex + 1), 485 JSON.stringify(paramIndex + 1), 486 ]); 487 } 488 489 return paramValueCheckResult; 490 } 491 492 /** 493 * 494 * 1.引用不同文件的api接口 495 * xxx.xxx#xxx 496 * 497 * 2.引用不同文件的模块接口 498 * xxx.xxx 499 * 500 * 3.引用不同文件的api事件接口 501 * xxx.xxx#event:xxx 502 */ 503 /** 504 * useinstead format check 505 * @param { string } moduleValue 506 * @returns { boolean } 507 */ 508 static checkModule(moduleValue: string): boolean { 509 return ( 510 /^[A-Za-z0-9_]+\b(\.[A-Za-z0-9_]+\b)*$/.test(moduleValue) || 511 /^[A-Za-z0-9_]+\b(\.[A-Za-z0-9_]+\b)*\#[A-Za-z0-9_]+\b$/.test(moduleValue) || 512 /^[A-Za-z0-9_]+\b(\.[A-Za-z0-9_]+\b)*\#event:[A-Za-z0-9_]+\b$/.test(moduleValue) 513 ); 514 } 515 /** 516 * Split useinstead value to determine if the file belongs to arkui. 517 * @param { string } useinsteadTagValue 518 * @param { ErrorTagFormat } useinsteadValueCheckResult 519 */ 520 static splitUseinsteadValue(useinsteadTagValue: string, useinsteadValueCheckResult: ErrorTagFormat): void { 521 if (!useinsteadTagValue || useinsteadTagValue === '') { 522 useinsteadValueCheckResult.state = false; 523 useinsteadValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_USEINSTEAD; 524 } 525 // 拆分字符串 526 const splitArray: string[] = useinsteadTagValue.split(/\//g); 527 const MODEL_COUNT: number = 1; 528 const MODEL_COUNTS: number = 2; 529 const FILENAME_MODEL_COUNT: number = 1; 530 if (splitArray.length === MODEL_COUNT) { 531 // 同一文件 532 useinsteadValueCheckResult.state = 533 splitArray[0].indexOf(PunctuationMark.LEFT_BRACKET) === -1 && 534 splitArray[0].indexOf(PunctuationMark.RIGHT_BRACKET) === -1 && 535 TagValueCheck.checkModule(splitArray[0]); 536 } else if (splitArray.length === MODEL_COUNTS) { 537 // 不同文件 538 const fileNameArray: string[] = splitArray[0].split('.'); 539 if (fileNameArray.length === FILENAME_MODEL_COUNT) { 540 // arkui 541 useinsteadValueCheckResult.state = 542 useinsteadValueCheckResult.state && 543 /^[A-Za-z0-9_]+\b$/.test(fileNameArray[0]) && 544 TagValueCheck.checkModule(splitArray[1]); 545 } else { 546 // 非arkui 547 let checkFileName: boolean = true; 548 for (let i = 0; i < fileNameArray.length; i++) { 549 checkFileName = 550 checkFileName && 551 fileNameArray[0] === 'ohos' && 552 /^[A-Za-z0-9_]+\b$/.test(fileNameArray[i]); 553 } 554 if ( 555 !checkFileName || 556 (!TagValueCheck.checkModule(splitArray[1]) && 557 splitArray[1].indexOf(PunctuationMark.LEFT_BRACKET) === -1 && 558 splitArray[1].indexOf(PunctuationMark.RIGHT_BRACKET) === -1) 559 ) { 560 useinsteadValueCheckResult.state = false; 561 } 562 } 563 } else { 564 // 格式错误 565 useinsteadValueCheckResult.state = false; 566 } 567 if (!useinsteadValueCheckResult.state) { 568 useinsteadValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_USEINSTEAD; 569 } 570 } 571 /** 572 * useinstead tag value check 573 * @param { Comment.CommentTag } tag 574 * @returns { ErrorTagFormat } 575 */ 576 static useinsteadTagValueCheck(tag: Comment.CommentTag): ErrorTagFormat { 577 let useinsteadValueCheckResult: ErrorTagFormat = { 578 state: true, 579 errorInfo: '', 580 }; 581 const useinsteadTagValue: string = tag.name; 582 if (useinsteadTagValue === '') { 583 useinsteadValueCheckResult.state = false; 584 useinsteadValueCheckResult.errorInfo = ErrorMessage.ERROR_INFO_VALUE_USEINSTEAD; 585 } else { 586 TagValueCheck.splitUseinsteadValue(useinsteadTagValue, useinsteadValueCheckResult); 587 } 588 return useinsteadValueCheckResult; 589 } 590} 591