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 { 17 ApiInfo, 18 ApiType, 19 BasicApiInfo, 20 ConstantInfo, 21 EnumValueInfo, 22 MethodInfo, 23 ParamInfo, 24 EnumInfo, 25 PropertyInfo, 26 TypeAliasInfo, 27 ClassInfo, 28 TypeParamInfo, 29} from '../../typedef/parser/ApiInfoDefination'; 30import { Comment } from '../../typedef/parser/Comment'; 31import { 32 ApiDiffType, 33 ApiStatusCode, 34 ApiNodeDiffProcessor, 35 ApiSceneDiffProcessor, 36 ApiScenesDiffProcessor, 37 BasicDiffInfo, 38 DiffTypeInfo, 39 diffMap, 40 incompatibleApiDiffTypes, 41 JsDocDiffProcessor, 42 parentApiTypeSet 43} from '../../typedef/diff/ApiInfoDiff'; 44import { StringUtils } from '../../utils/StringUtils'; 45import { CharMapType, CompareReturnObjType, PermissionsProcessorHelper, RangeChange } from './PermissionsProcessor'; 46import { DecoratorInfo } from '../../typedef/parser/Decorator'; 47import { CommonFunctions } from '../../utils/checkUtils'; 48import { NumberConstant } from '../../utils/Constant'; 49 50export namespace DiffProcessorHelper { 51 /** 52 * 权限编码进行逻辑运算的转义规则 53 */ 54 export const permissionsCharMap: CharMapType = new Map([ 55 ['and', { splitchar: 'and', transferchar: '&' }], 56 ['or', { splitchar: 'or', transferchar: '|' }], 57 ]); 58 59 /** 60 * type进行逻辑运算的转义规则 61 */ 62 export const typeCharMap: CharMapType = new Map([ 63 ['and', { splitchar: '&', transferchar: '&' }], 64 ['or', { splitchar: '|', transferchar: '|' }], 65 ]); 66 67 /** 68 * 处理api节点jsdoc中的diff信息工具 69 * 70 */ 71 export class JsDocDiffHelper { 72 static diffJsDocInfo( 73 oldApiInfo: ApiInfo, 74 newApiInfo: ApiInfo, 75 diffInfos: BasicDiffInfo[], 76 isAllDeprecated?: boolean, 77 isAllSheet?: boolean 78 ): void { 79 const oldJsDocInfo: Comment.JsDocInfo | undefined = oldApiInfo.getLastJsDocInfo(); 80 const newJsDocInfo: Comment.JsDocInfo | undefined = newApiInfo.getLastJsDocInfo(); 81 JsDocDiffHelper.diffSinceVersion(oldApiInfo, newApiInfo, diffInfos); 82 const allDiffTypeInfo: DiffTypeInfo[] | undefined = JsDocDiffHelper.diffErrorCodes(oldJsDocInfo, newJsDocInfo); 83 allDiffTypeInfo?.forEach((diffType: DiffTypeInfo) => { 84 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo(oldApiInfo, newApiInfo, diffType); 85 diffInfos.push(diffInfo); 86 }); 87 for (let i = 0; i < jsDocDiffProcessors.length; i++) { 88 const jsDocDiffProcessor: JsDocDiffProcessor | undefined = jsDocDiffProcessors[i]; 89 const diffType: DiffTypeInfo | undefined = jsDocDiffProcessor( 90 oldJsDocInfo, 91 newJsDocInfo, 92 isAllDeprecated, 93 isAllSheet 94 ); 95 if (!diffType) { 96 continue; 97 } 98 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo(oldApiInfo, newApiInfo, diffType); 99 diffInfos.push(diffInfo); 100 } 101 } 102 103 static getFirstSinceVersion(jsDocInfos: Comment.JsDocInfo[]): string { 104 let sinceVersion: string = ''; 105 for (let i = 0; i < jsDocInfos.length; i++) { 106 const jsDocInfo: Comment.JsDocInfo = jsDocInfos[i]; 107 if (jsDocInfo.getSince() !== '-1') { 108 sinceVersion = jsDocInfo.getSince(); 109 return sinceVersion; 110 } 111 } 112 return sinceVersion; 113 } 114 115 static diffSinceVersion(oldApiInfo: ApiInfo, newApiInfo: ApiInfo, diffInfos: BasicDiffInfo[]): void { 116 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 117 const oldFirstJsDocInfo: Comment.JsDocInfo | undefined = oldApiInfo.getJsDocInfos()[0]; 118 const newFirstJsDocInfo: Comment.JsDocInfo | undefined = newApiInfo.getJsDocInfos()[0]; 119 const sinceVersionOfOld: string = oldFirstJsDocInfo ? oldFirstJsDocInfo.getSince() : '-1'; 120 const sinceVersionOfNew: string = newFirstJsDocInfo ? newFirstJsDocInfo.getSince() : '-1'; 121 diffTypeInfo 122 .setStatusCode(ApiStatusCode.VERSION_CHNAGES) 123 .setOldMessage(sinceVersionOfOld) 124 .setNewMessage(sinceVersionOfNew); 125 if (sinceVersionOfOld === sinceVersionOfNew) { 126 return; 127 } 128 if (sinceVersionOfOld === '-1') { 129 diffTypeInfo.setDiffType(ApiDiffType.SINCE_VERSION_NA_TO_HAVE); 130 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo(oldApiInfo, newApiInfo, diffTypeInfo); 131 diffInfos.push(diffInfo); 132 return; 133 } 134 if (sinceVersionOfNew === '-1') { 135 diffTypeInfo.setDiffType(ApiDiffType.SINCE_VERSION_HAVE_TO_NA); 136 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo(oldApiInfo, newApiInfo, diffTypeInfo); 137 diffInfos.push(diffInfo); 138 return; 139 } 140 diffTypeInfo.setDiffType(ApiDiffType.SINCE_VERSION_A_TO_B); 141 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo(oldApiInfo, newApiInfo, diffTypeInfo); 142 diffInfos.push(diffInfo); 143 } 144 145 static diffIsSystemApi( 146 oldJsDocInfo: Comment.JsDocInfo | undefined, 147 newJsDocInfo: Comment.JsDocInfo | undefined 148 ): DiffTypeInfo | undefined { 149 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 150 const isSystemApiOfOld: boolean = oldJsDocInfo ? oldJsDocInfo.getIsSystemApi() : false; 151 const isSystemApiOfNew: boolean = newJsDocInfo ? newJsDocInfo.getIsSystemApi() : false; 152 diffTypeInfo 153 .setStatusCode(ApiStatusCode.SYSTEM_API_CHNAGES) 154 .setOldMessage(StringUtils.transformBooleanToTag(isSystemApiOfOld, Comment.JsDocTag.SYSTEM_API)) 155 .setNewMessage(StringUtils.transformBooleanToTag(isSystemApiOfNew, Comment.JsDocTag.SYSTEM_API)); 156 if (isSystemApiOfNew === isSystemApiOfOld) { 157 return undefined; 158 } 159 if (isSystemApiOfNew) { 160 return diffTypeInfo.setDiffType(ApiDiffType.PUBLIC_TO_SYSTEM); 161 } 162 return diffTypeInfo.setDiffType(ApiDiffType.SYSTEM_TO_PUBLIC); 163 } 164 165 static diffModelLimitation( 166 oldJsDocInfo: Comment.JsDocInfo | undefined, 167 newJsDocInfo: Comment.JsDocInfo | undefined 168 ): DiffTypeInfo | undefined { 169 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 170 const modelLimitationDiffMap: Map<string, ApiDiffType> = new Map([ 171 ['_stagemodelonly', ApiDiffType.NA_TO_STAGE], 172 ['stagemodelonly_', ApiDiffType.STAGE_TO_NA], 173 ['_famodelonly', ApiDiffType.NA_TO_FA], 174 ['famodelonly_', ApiDiffType.FA_TO_NA], 175 ['famodelonly_stagemodelonly', ApiDiffType.FA_TO_STAGE], 176 ['stagemodelonly_famodelonly', ApiDiffType.STAGE_TO_FA], 177 ]); 178 const modelLimitationOfOld: string = oldJsDocInfo ? oldJsDocInfo.getModelLimitation().toLowerCase() : ''; 179 const modelLimitationOfNew: string = newJsDocInfo ? newJsDocInfo.getModelLimitation().toLowerCase() : ''; 180 if (modelLimitationOfNew === modelLimitationOfOld) { 181 return undefined; 182 } 183 const diffMsg: string = `${modelLimitationOfOld.toLowerCase()}_${modelLimitationOfNew.toLowerCase()}`; 184 const diffType: ApiDiffType = modelLimitationDiffMap.get(diffMsg) as ApiDiffType; 185 diffTypeInfo 186 .setStatusCode(ApiStatusCode.MODEL_CHNAGES) 187 .setDiffType(diffType) 188 .setOldMessage(modelLimitationOfOld) 189 .setNewMessage(modelLimitationOfNew); 190 return diffTypeInfo; 191 } 192 193 static diffIsForm( 194 oldJsDocInfo: Comment.JsDocInfo | undefined, 195 newJsDocInfo: Comment.JsDocInfo | undefined 196 ): DiffTypeInfo | undefined { 197 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 198 const isCardOfOld: boolean = oldJsDocInfo ? oldJsDocInfo.getIsForm() : false; 199 const isCardOfNew: boolean = newJsDocInfo ? newJsDocInfo.getIsForm() : false; 200 diffTypeInfo 201 .setStatusCode(ApiStatusCode.FORM_CHANGED) 202 .setOldMessage(StringUtils.transformBooleanToTag(isCardOfOld, Comment.JsDocTag.FORM)) 203 .setNewMessage(StringUtils.transformBooleanToTag(isCardOfNew, Comment.JsDocTag.FORM)); 204 if (isCardOfNew === isCardOfOld) { 205 return undefined; 206 } 207 if (isCardOfNew) { 208 return diffTypeInfo.setDiffType(ApiDiffType.NA_TO_CARD); 209 } 210 return diffTypeInfo.setDiffType(ApiDiffType.CARD_TO_NA); 211 } 212 213 static diffIsCrossPlatForm( 214 oldJsDocInfo: Comment.JsDocInfo | undefined, 215 newJsDocInfo: Comment.JsDocInfo | undefined 216 ): DiffTypeInfo | undefined { 217 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 218 const isCrossPlatFormOfOld: boolean = oldJsDocInfo ? oldJsDocInfo.getIsCrossPlatForm() : false; 219 const isCrossPlatFormOfNew: boolean = newJsDocInfo ? newJsDocInfo.getIsCrossPlatForm() : false; 220 diffTypeInfo 221 .setStatusCode(ApiStatusCode.CROSSPLATFORM_CHANGED) 222 .setOldMessage(StringUtils.transformBooleanToTag(isCrossPlatFormOfOld, Comment.JsDocTag.CROSS_PLAT_FORM)) 223 .setNewMessage(StringUtils.transformBooleanToTag(isCrossPlatFormOfNew, Comment.JsDocTag.CROSS_PLAT_FORM)); 224 if (isCrossPlatFormOfNew === isCrossPlatFormOfOld) { 225 return undefined; 226 } 227 if (isCrossPlatFormOfNew) { 228 return diffTypeInfo.setDiffType(ApiDiffType.NA_TO_CROSS_PLATFORM); 229 } 230 return diffTypeInfo.setDiffType(ApiDiffType.CROSS_PLATFORM_TO_NA); 231 } 232 233 static diffAtomicService( 234 oldJsDocInfo: Comment.JsDocInfo | undefined, 235 newJsDocInfo: Comment.JsDocInfo | undefined 236 ): DiffTypeInfo | undefined { 237 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 238 const isAtomicServiceOfOld: boolean | undefined = oldJsDocInfo ? oldJsDocInfo.getIsAtomicService() : false; 239 const isAtomicServiceOfNew: boolean | undefined = newJsDocInfo ? newJsDocInfo.getIsAtomicService() : false; 240 diffTypeInfo 241 .setStatusCode(ApiStatusCode.ATOMICSERVICE_CHANGE) 242 .setOldMessage(StringUtils.transformBooleanToTag(isAtomicServiceOfOld, Comment.JsDocTag.ATOMIC_SERVICE)) 243 .setNewMessage(StringUtils.transformBooleanToTag(isAtomicServiceOfNew, Comment.JsDocTag.ATOMIC_SERVICE)); 244 if (isAtomicServiceOfOld === isAtomicServiceOfNew) { 245 return undefined; 246 } 247 if (isAtomicServiceOfNew) { 248 return diffTypeInfo.setDiffType(ApiDiffType.ATOMIC_SERVICE_NA_TO_HAVE); 249 } 250 return diffTypeInfo.setDiffType(ApiDiffType.ATOMIC_SERVICE_HAVE_TO_NA); 251 } 252 253 static diffPermissions( 254 oldJsDocInfo: Comment.JsDocInfo | undefined, 255 newJsDocInfo: Comment.JsDocInfo | undefined 256 ): DiffTypeInfo | undefined { 257 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 258 const permissionsOfOld: string = oldJsDocInfo ? oldJsDocInfo.getPermission() : ''; 259 const permissionsOfNew: string = newJsDocInfo ? newJsDocInfo.getPermission() : ''; 260 diffTypeInfo 261 .setStatusCode(ApiStatusCode.PERMISSION_CHANGES) 262 .setOldMessage(permissionsOfOld) 263 .setNewMessage(permissionsOfNew); 264 if (permissionsOfOld === permissionsOfNew) { 265 return undefined; 266 } 267 if (permissionsOfOld === '') { 268 return diffTypeInfo.setStatusCode(ApiStatusCode.PERMISSION_NEW).setDiffType(ApiDiffType.PERMISSION_NA_TO_HAVE); 269 } 270 if (permissionsOfNew === '') { 271 return diffTypeInfo 272 .setStatusCode(ApiStatusCode.PERMISSION_DELETE) 273 .setDiffType(ApiDiffType.PERMISSION_HAVE_TO_NA); 274 } 275 const permiss: PermissionsProcessorHelper = new PermissionsProcessorHelper(permissionsCharMap); 276 const compareVal: CompareReturnObjType = permiss.comparePermissions(permissionsOfOld, permissionsOfNew); 277 if (compareVal.range === RangeChange.DOWN) { 278 return diffTypeInfo.setDiffType(ApiDiffType.PERMISSION_RANGE_SMALLER); 279 } 280 if (compareVal.range === RangeChange.UP) { 281 return diffTypeInfo.setDiffType(ApiDiffType.PERMISSION_RANGE_BIGGER); 282 } 283 return diffTypeInfo.setDiffType(ApiDiffType.PERMISSION_RANGE_CHANGE); 284 } 285 286 static diffErrorCodes( 287 oldJsDocInfo: Comment.JsDocInfo | undefined, 288 newJsDocInfo: Comment.JsDocInfo | undefined 289 ): DiffTypeInfo[] | undefined { 290 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 291 const errorCodesOfOld: number[] = oldJsDocInfo ? oldJsDocInfo.getErrorCode().sort() : []; 292 const errorCodesOfNew: number[] = newJsDocInfo ? newJsDocInfo.getErrorCode().sort() : []; 293 const errorCodeSetOfOld: Set<number> = new Set(errorCodesOfOld); 294 const errorCodeSetOfNew: Set<number> = new Set(errorCodesOfNew); 295 const allErrorCodes: Set<number> = new Set(errorCodesOfNew.concat(errorCodesOfOld)); 296 const errorCodesStringOfOld: string = errorCodesOfOld.toString(); 297 const errorCodesStringOfNew: string = errorCodesOfNew.toString(); 298 const allDiffTypeInfo: DiffTypeInfo[] = []; 299 diffTypeInfo 300 .setStatusCode(ApiStatusCode.ERRORCODE_CHANGES) 301 .setOldMessage(errorCodesStringOfOld) 302 .setNewMessage(errorCodesStringOfNew); 303 if (errorCodesStringOfNew === errorCodesStringOfOld) { 304 return undefined; 305 } 306 if (errorCodesOfOld.length === 0 && errorCodesOfNew.length !== 0) { 307 allDiffTypeInfo.push( 308 diffTypeInfo.setStatusCode(ApiStatusCode.NEW_ERRORCODE).setDiffType(ApiDiffType.ERROR_CODE_NA_TO_HAVE) 309 ); 310 return allDiffTypeInfo; 311 } 312 const oldChangeErrorCodes: number[] = []; 313 const newChangeErrorCodes: number[] = []; 314 allErrorCodes.forEach((errorCode: number) => { 315 if (!errorCodeSetOfOld.has(errorCode)) { 316 oldChangeErrorCodes.push(errorCode); 317 } 318 if (!errorCodeSetOfNew.has(errorCode)) { 319 newChangeErrorCodes.push(errorCode); 320 } 321 }); 322 if (oldChangeErrorCodes.length !== 0) { 323 const oldDiffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 324 oldDiffTypeInfo 325 .setOldMessage('NA') 326 .setNewMessage(oldChangeErrorCodes.join()) 327 .setStatusCode(ApiStatusCode.NEW_ERRORCODE) 328 .setDiffType(ApiDiffType.ERROR_CODE_ADD); 329 allDiffTypeInfo.push(oldDiffTypeInfo); 330 } 331 if (newChangeErrorCodes.length !== 0) { 332 const newDiffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 333 newDiffTypeInfo 334 .setOldMessage(newChangeErrorCodes.join()) 335 .setNewMessage('NA') 336 .setStatusCode(ApiStatusCode.ERRORCODE_DELETE) 337 .setDiffType(ApiDiffType.ERROR_CODE_REDUCE); 338 allDiffTypeInfo.push(newDiffTypeInfo); 339 } 340 return allDiffTypeInfo; 341 } 342 343 static diffSyscap( 344 oldJsDocInfo: Comment.JsDocInfo | undefined, 345 newJsDocInfo: Comment.JsDocInfo | undefined 346 ): DiffTypeInfo | undefined { 347 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 348 const syscapOfOld: string = oldJsDocInfo ? oldJsDocInfo.getSyscap() : ''; 349 const syscapOfNew: string = newJsDocInfo ? newJsDocInfo.getSyscap() : ''; 350 diffTypeInfo.setStatusCode(ApiStatusCode.SYSCAP_CHANGES).setOldMessage(syscapOfOld).setNewMessage(syscapOfNew); 351 if (syscapOfNew === syscapOfOld) { 352 return undefined; 353 } 354 if (syscapOfOld === '') { 355 return diffTypeInfo.setDiffType(ApiDiffType.SYSCAP_NA_TO_HAVE); 356 } 357 if (syscapOfNew === '') { 358 return diffTypeInfo.setDiffType(ApiDiffType.SYSCAP_HAVE_TO_NA); 359 } 360 return diffTypeInfo.setDiffType(ApiDiffType.SYSCAP_A_TO_B); 361 } 362 363 static diffDeprecated( 364 oldJsDocInfo: Comment.JsDocInfo | undefined, 365 newJsDocInfo: Comment.JsDocInfo | undefined, 366 isAllDeprecated?: boolean, 367 isAllSheet?: boolean 368 ): DiffTypeInfo | undefined { 369 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 370 const deprecatedVersionOfOld: string = oldJsDocInfo ? oldJsDocInfo.getDeprecatedVersion() : '-1'; 371 const deprecatedVersionOfNew: string = newJsDocInfo ? newJsDocInfo.getDeprecatedVersion() : '-1'; 372 diffTypeInfo 373 .setStatusCode(ApiStatusCode.DEPRECATED_CHNAGES) 374 .setOldMessage(deprecatedVersionOfOld.toString()) 375 .setNewMessage(deprecatedVersionOfNew.toString()); 376 if (deprecatedVersionOfNew === deprecatedVersionOfOld) { 377 return undefined; 378 } 379 if (isAllSheet) { 380 if (deprecatedVersionOfOld === '-1' && !isAllDeprecated) { 381 return diffTypeInfo.setDiffType(ApiDiffType.DEPRECATED_NOT_All); 382 } 383 if (deprecatedVersionOfOld === '-1' && isAllDeprecated) { 384 return diffTypeInfo.setDiffType(ApiDiffType.DEPRECATED_NA_TO_HAVE); 385 } 386 } else { 387 if (deprecatedVersionOfOld === '-1') { 388 return diffTypeInfo.setDiffType(ApiDiffType.DEPRECATED_NA_TO_HAVE); 389 } 390 if (deprecatedVersionOfNew === '-1') { 391 return diffTypeInfo.setDiffType(ApiDiffType.DEPRECATED_HAVE_TO_NA); 392 } 393 } 394 395 if (deprecatedVersionOfNew === '-1') { 396 return diffTypeInfo.setDiffType(ApiDiffType.DEPRECATED_HAVE_TO_NA); 397 } 398 399 return diffTypeInfo.setDiffType(ApiDiffType.DEPRECATED_A_TO_B); 400 } 401 } 402 403 /** 404 * 比较API的装饰器信息 405 */ 406 export class ApiDecoratorsDiffHelper { 407 /** 408 * 新旧版本API一致的情况下,比较装饰器 409 * 410 * @param {ApiInfo} oldApiInfo 411 * @param {ApiInfo} newApiInfo 412 * @param {BasicDiffInfo[]} diffInfos 413 * @returns 414 */ 415 static diffDecorator(oldApiInfo: ApiInfo, newApiInfo: ApiInfo, diffInfos: BasicDiffInfo[]): void { 416 const oldDecoratorsMap: Map<string, string[] | undefined> = ApiDecoratorsDiffHelper.setDecoratorsMap( 417 oldApiInfo.getDecorators() 418 ); 419 const newDecoratorsMap: Map<string, string[] | undefined> = ApiDecoratorsDiffHelper.setDecoratorsMap( 420 newApiInfo.getDecorators() 421 ); 422 if (newDecoratorsMap.size === 0) { 423 for (const key of oldDecoratorsMap.keys()) { 424 ApiDecoratorsDiffHelper.addDeleteDecoratorsInfo(key, oldApiInfo, newApiInfo, diffInfos); 425 } 426 return; 427 } 428 429 if (oldDecoratorsMap.size === 0) { 430 for (const key of newDecoratorsMap.keys()) { 431 ApiDecoratorsDiffHelper.addNewDecoratorsInfo(key, oldApiInfo, newApiInfo, diffInfos); 432 newDecoratorsMap.delete(key); 433 } 434 return; 435 } 436 ApiDecoratorsDiffHelper.diffDecoratorInfo(oldDecoratorsMap, newDecoratorsMap, oldApiInfo, newApiInfo, diffInfos); 437 } 438 439 static diffDecoratorInfo( 440 oldDecoratorsMap: Map<string, string[] | undefined>, 441 newDecoratorsMap: Map<string, string[] | undefined>, 442 oldApiInfo: ApiInfo, 443 newApiInfo: ApiInfo, 444 diffInfos: BasicDiffInfo[] 445 ): void { 446 const sameDecoratorSet: Set<string> = new Set(); 447 for (const key of oldDecoratorsMap.keys()) { 448 const newDecoratorArguments: string[] | undefined = newDecoratorsMap.get(key); 449 const oldDecoratorArguments: string[] | undefined = oldDecoratorsMap.get(key); 450 //新版本没有这个装饰器 451 if (!newDecoratorArguments) { 452 ApiDecoratorsDiffHelper.addDeleteDecoratorsInfo(key, oldApiInfo, newApiInfo, diffInfos); 453 sameDecoratorSet.add(key); 454 continue; 455 } 456 457 // 新旧版本装饰器参数一样 458 if (oldDecoratorArguments && newDecoratorArguments.join() === oldDecoratorArguments.join()) { 459 newDecoratorsMap.delete(key); 460 sameDecoratorSet.add(key); 461 continue; 462 } 463 } 464 // 新版中剩下的装饰器为新增 465 for (const key of newDecoratorsMap.keys()) { 466 ApiDecoratorsDiffHelper.addNewDecoratorsInfo(key, oldApiInfo, newApiInfo, diffInfos); 467 } 468 469 for (const key of oldDecoratorsMap.keys()) { 470 if (sameDecoratorSet.has(key)) { 471 continue; 472 } 473 ApiDecoratorsDiffHelper.addDeleteDecoratorsInfo(key, oldApiInfo, newApiInfo, diffInfos); 474 } 475 } 476 477 static setDecoratorsMap(decorators: DecoratorInfo[] | undefined): Map<string, string[] | undefined> { 478 const decoratorsMap: Map<string, string[]> = new Map(); 479 if (!decorators) { 480 return decoratorsMap; 481 } 482 483 decorators.forEach((decoratorInfo: DecoratorInfo) => { 484 const expressionArguments: string[] | undefined = decoratorInfo.getExpressionArguments(); 485 decoratorsMap.set(decoratorInfo.getExpression(), expressionArguments === undefined ? [] : expressionArguments); 486 }); 487 return decoratorsMap; 488 } 489 490 static addDeleteDecoratorsInfo( 491 decoratorName: string, 492 oldApiInfo: ApiInfo, 493 newApiInfo: ApiInfo, 494 diffInfos: BasicDiffInfo[] 495 ): void { 496 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 497 diffTypeInfo 498 .setStatusCode(ApiStatusCode.DELETE_DECORATOR) 499 .setDiffType(ApiDiffType.DELETE_DECORATOR) 500 .setOldMessage(decoratorName) 501 .setNewMessage(''); 502 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo(oldApiInfo, newApiInfo, diffTypeInfo); 503 diffInfos.push(diffInfo); 504 } 505 506 static addNewDecoratorsInfo( 507 decoratorName: string, 508 oldApiInfo: ApiInfo, 509 newApiInfo: ApiInfo, 510 diffInfos: BasicDiffInfo[] 511 ): void { 512 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 513 diffTypeInfo 514 .setStatusCode(ApiStatusCode.NEW_DECORATOR) 515 .setDiffType(ApiDiffType.NEW_DECORATOR) 516 .setOldMessage('') 517 .setNewMessage(decoratorName); 518 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo(oldApiInfo, newApiInfo, diffTypeInfo); 519 diffInfos.push(diffInfo); 520 } 521 } 522 523 export class ApiCheckHelper { 524 /** 525 * 比较两个API的历史版本jsdoc 526 * 527 * @param {ApiInfo} oldApiInfo 528 * @param {ApiInfo} newApiInfo 529 * @param {BasicDiffInfo[]} diffInfos 530 */ 531 static diffHistoricalJsDoc(oldApiInfo: ApiInfo, newApiInfo: ApiInfo, diffInfos: BasicDiffInfo[]): void { 532 const currentVersion: string = CommonFunctions.getCheckApiVersion().toString(); 533 const oldJsDocTextArr: Array<string> = oldApiInfo.getJsDocText().split('*/'); 534 const newJsDocTextArr: Array<string> = newApiInfo.getJsDocText().split('*/'); 535 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 536 537 if (oldApiInfo.getCurrentVersion() === currentVersion) { 538 oldJsDocTextArr.splice(NumberConstant.DELETE_CURRENT_JS_DOC); 539 } else { 540 oldJsDocTextArr.splice(-1); 541 } 542 543 if (newApiInfo.getCurrentVersion() === currentVersion) { 544 newJsDocTextArr.splice(NumberConstant.DELETE_CURRENT_JS_DOC); 545 } else { 546 newJsDocTextArr.splice(-1); 547 } 548 549 if (oldJsDocTextArr.length !== newJsDocTextArr.length) { 550 diffTypeInfo.setDiffType(ApiDiffType.HISTORICAL_JSDOC_CHANGE); 551 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo(oldApiInfo, newApiInfo, diffTypeInfo); 552 diffInfos.push(diffInfo); 553 return; 554 } 555 for (let i = 0; i < oldJsDocTextArr.length; i++) { 556 if (oldJsDocTextArr[i].replace(/\r\n|\n|\s+/g, '') !== newJsDocTextArr[i].replace(/\r\n|\n|\s+/g, '')) { 557 diffTypeInfo.setDiffType(ApiDiffType.HISTORICAL_JSDOC_CHANGE); 558 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo(oldApiInfo, newApiInfo, diffTypeInfo); 559 diffInfos.push(diffInfo); 560 } 561 } 562 } 563 564 static diffHistoricalAPI(oldApiInfo: ApiInfo, newApiInfo: ApiInfo, diffInfos: BasicDiffInfo[]): void { 565 const currentVersion: string = CommonFunctions.getCheckApiVersion().toString(); 566 const oldApiDefinedText: string = oldApiInfo.getDefinedText(); 567 const newApiDefinedText: string = newApiInfo.getDefinedText(); 568 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 569 if (oldApiDefinedText !== newApiDefinedText && newApiInfo.getCurrentVersion() !== currentVersion) { 570 diffTypeInfo.setDiffType(ApiDiffType.HISTORICAL_API_CHANGE); 571 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo(oldApiInfo, newApiInfo, diffTypeInfo); 572 diffInfos.push(diffInfo); 573 } 574 } 575 } 576 577 /** 578 * 处理api节点的diff信息工具 579 * 580 */ 581 export class ApiNodeDiffHelper { 582 /** 583 * 根据节点类型处理节点的diff信息,处理的主流程 584 * 585 * @param {ApiInfo} oldApiInfo 旧版本的节点信息 586 * @param {ApiInfo} newApiInfo 新版本的节点信息 587 * @param {BasicDiffInfo[]} diffInfos 各个节点diff信息集合 588 * @return {void} 589 */ 590 static diffNodeInfo(oldApiInfo: ApiInfo, newApiInfo: ApiInfo, diffInfos: BasicDiffInfo[], isCheck?: boolean): void { 591 if (isCheck) { 592 ApiCheckHelper.diffHistoricalJsDoc(oldApiInfo, newApiInfo, diffInfos); 593 ApiCheckHelper.diffHistoricalAPI(oldApiInfo, newApiInfo, diffInfos); 594 } 595 const apiType: string = newApiInfo.getApiType(); 596 if (oldApiInfo.getApiType() !== apiType) { 597 return; 598 } 599 const apiNodeDiff: ApiNodeDiffProcessor | undefined = apiNodeDiffMethod.get(apiType); 600 if (!apiNodeDiff) { 601 return; 602 } 603 apiNodeDiff(oldApiInfo, newApiInfo, diffInfos); 604 } 605 606 /** 607 * 处理type类型 608 * 609 * @static 610 * @param {string} oldType 旧版本的type字符串 611 * @param {string} newType 新版本的type字符串 612 * @return { ApiDiffType | undefined} type范围的变化情况 613 * @memberof ApiNodeDiffHelper 614 */ 615 static diffBaseType(oldType: string, newType: string): DiffTypeInfo | undefined { 616 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 617 if (oldType === newType) { 618 return undefined; 619 } 620 diffTypeInfo.setStatusCode(ApiStatusCode.TYPE_CHNAGES).setOldMessage(oldType).setNewMessage(newType); 621 if (oldType === '') { 622 return diffTypeInfo.setDiffType(ApiDiffType.TYPE_RANGE_CHANGE); 623 } 624 if (newType === '') { 625 return diffTypeInfo.setDiffType(ApiDiffType.TYPE_RANGE_CHANGE); 626 } 627 const permiss: PermissionsProcessorHelper = new PermissionsProcessorHelper(typeCharMap); 628 const compareVal: CompareReturnObjType = permiss.comparePermissions(oldType, newType); 629 if (compareVal.range === RangeChange.DOWN) { 630 return diffTypeInfo.setDiffType(ApiDiffType.TYPE_RANGE_SMALLER); 631 } 632 if (compareVal.range === RangeChange.UP) { 633 return diffTypeInfo.setDiffType(ApiDiffType.TYPE_RANGE_BIGGER); 634 } 635 return diffTypeInfo.setDiffType(ApiDiffType.TYPE_RANGE_CHANGE); 636 } 637 638 /** 639 * 处理方法节点,获取对应diff信息 640 * 641 * @param {ApiInfo} oldApiInfo 旧版本的方法节点信息 642 * @param {ApiInfo} newApiInfo 新版本的方法节点信息 643 * @param {BasicDiffInfo[]} diffInfos 各个节点diff信息集合 644 */ 645 static diffMethod(oldApiInfo: ApiInfo, newApiInfo: ApiInfo, diffInfos: BasicDiffInfo[]): void { 646 methodDiffProcessors.forEach((methodDiffProcessor: ApiScenesDiffProcessor) => { 647 const diffTypeInfo: DiffTypeInfo[] | DiffTypeInfo | undefined = methodDiffProcessor( 648 oldApiInfo as MethodInfo, 649 newApiInfo as MethodInfo 650 ); 651 if (!diffTypeInfo) { 652 return; 653 } 654 if (diffTypeInfo instanceof Array) { 655 diffTypeInfo.forEach((info: DiffTypeInfo) => { 656 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo( 657 oldApiInfo, 658 newApiInfo, 659 info.setStatusCode(ApiStatusCode.FUNCTION_CHANGES) 660 ); 661 diffInfos.push(diffInfo); 662 }); 663 } else { 664 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo( 665 oldApiInfo, 666 newApiInfo, 667 diffTypeInfo.setStatusCode(ApiStatusCode.FUNCTION_CHANGES) 668 ); 669 diffInfos.push(diffInfo); 670 } 671 }); 672 } 673 static diffTypeAliasReturnType(oldApiInfo: TypeAliasInfo, newApiInfo: TypeAliasInfo): DiffTypeInfo | undefined { 674 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 675 const oldReturnType: string[] = oldApiInfo.getReturnType()?.split('|'); 676 const newReturnType: string[] = newApiInfo.getReturnType()?.split('|'); 677 const olaMethodTypeStr = oldReturnType.toString().replace(/\r|\n|\s+|'|"/g, ''); 678 const newMethodTypeStr = newReturnType.toString().replace(/\r|\n|\s+|'|"/g, ''); 679 if (olaMethodTypeStr === newMethodTypeStr) { 680 return undefined; 681 } 682 diffTypeInfo.setOldMessage(olaMethodTypeStr).setNewMessage(newMethodTypeStr); 683 if (checkParentContainChild(newReturnType, oldReturnType)) { 684 return diffTypeInfo.setDiffType(ApiDiffType.TYPE_ALIAS_FUNCTION_RETURN_TYPE_ADD); 685 } 686 if (checkParentContainChild(oldReturnType, newReturnType)) { 687 return diffTypeInfo.setDiffType(ApiDiffType.TYPE_ALIAS_FUNCTION_RETURN_TYPE_REDUCE); 688 } 689 // 旧版本不包含新版本,新版本也不含旧版本,就定义为返回值变更 690 return diffTypeInfo.setDiffType(ApiDiffType.TYPE_ALIAS_FUNCTION_RETURN_TYPE_CHANGE); 691 } 692 /** 693 * 处理方法节点的返回值 694 * 695 * @param {MethodInfo} oldApiInfo 旧版本的方法节点信息 696 * @param {MethodInfo} newApiInfo 新版本的方法节点信息 697 * @return {*} {(ApiDiffType | undefined)} 方法节点的返回值的变化情况 698 */ 699 static diffMethodReturnType(oldApiInfo: MethodInfo, newApiInfo: MethodInfo): DiffTypeInfo | undefined { 700 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 701 const oldReturnType: string[] = oldApiInfo.getReturnValue(); 702 const newReturnType: string[] = newApiInfo.getReturnValue(); 703 const oldMethodTypeStr = oldReturnType.toString().replace(/\r|\n|\s+|'|"|>/g, ''); 704 const newMethodTypeStr = newReturnType.toString().replace(/\r|\n|\s+|'|"|>/g, ''); 705 if (oldMethodTypeStr === newMethodTypeStr) { 706 return undefined; 707 } 708 diffTypeInfo.setOldMessage(oldReturnType.toString()).setNewMessage(newReturnType.toString()); 709 if (checkParentContainChild(newReturnType, oldReturnType)) { 710 return diffTypeInfo.setDiffType(ApiDiffType.FUNCTION_RETURN_TYPE_ADD); 711 } 712 if (StringUtils.hasSubstring(newMethodTypeStr, oldMethodTypeStr)) { 713 return diffTypeInfo.setDiffType(ApiDiffType.FUNCTION_RETURN_TYPE_ADD); 714 } 715 if (checkParentContainChild(oldReturnType, newReturnType)) { 716 return diffTypeInfo.setDiffType(ApiDiffType.FUNCTION_RETURN_TYPE_REDUCE); 717 } 718 if (StringUtils.hasSubstring(oldMethodTypeStr, newMethodTypeStr)) { 719 return diffTypeInfo.setDiffType(ApiDiffType.FUNCTION_RETURN_TYPE_REDUCE); 720 } 721 // 旧版本不包含新版本,新版本也不含旧版本,就定义为返回值变更 722 return diffTypeInfo.setDiffType(ApiDiffType.FUNCTION_RETURN_TYPE_CHANGE); 723 } 724 725 /** 726 * 727 * @param isTypeAlias 是否为自定义节点类型 728 * @returns {*} {DiffMethodType} 当前节点类型对应的修改类型 729 */ 730 static getDiffMethodTypes(isTypeAlias: boolean): DiffMethodType & DiffTypeChangeType { 731 if (isTypeAlias) { 732 return { 733 POS_CHANGE: ApiDiffType.TYPE_ALIAS_FUNCTION_PARAM_POS_CHAHGE, 734 ADD_OPTIONAL_PARAM: ApiDiffType.TYPE_ALIAS_FUNCTION_PARAM_UNREQUIRED_ADD, 735 ADD_REQUIRED_PARAM: ApiDiffType.TYPE_ALIAS_FUNCTION_PARAM_REQUIRED_ADD, 736 REDUCE_PARAM: ApiDiffType.TYPE_ALIAS_FUNCTION_PARAM_REDUCE, 737 PARAM_TYPE_CHANGE: ApiDiffType.TYPE_ALIAS_FUNCTION_PARAM_TYPE_CHANGE, 738 PARAM_TYPE_ADD: ApiDiffType.TYPE_ALIAS_FUNCTION_PARAM_TYPE_ADD, 739 PARAM_TYPE_REDUCE: ApiDiffType.TYPE_ALIAS_FUNCTION_PARAM_TYPE_REDUCE, 740 PARAM_TO_UNREQUIRED: ApiDiffType.TYPE_ALIAS_FUNCTION_PARAM_TO_UNREQUIRED, 741 PARAM_TO_REQUIRED: ApiDiffType.TYPE_ALIAS_FUNCTION_PARAM_TO_REQUIRED, 742 PARAM_CHANGE: ApiDiffType.TYPE_ALIAS_FUNCTION_PARAM_CHANGE, 743 }; 744 } else { 745 return { 746 POS_CHANGE: ApiDiffType.FUNCTION_PARAM_POS_CHANGE, 747 ADD_OPTIONAL_PARAM: ApiDiffType.FUNCTION_PARAM_UNREQUIRED_ADD, 748 ADD_REQUIRED_PARAM: ApiDiffType.FUNCTION_PARAM_REQUIRED_ADD, 749 REDUCE_PARAM: ApiDiffType.FUNCTION_PARAM_REDUCE, 750 PARAM_TYPE_CHANGE: ApiDiffType.FUNCTION_PARAM_TYPE_CHANGE, 751 PARAM_TYPE_ADD: ApiDiffType.FUNCTION_PARAM_TYPE_ADD, 752 PARAM_TYPE_REDUCE: ApiDiffType.FUNCTION_PARAM_TYPE_REDUCE, 753 PARAM_TO_UNREQUIRED: ApiDiffType.FUNCTION_PARAM_TO_UNREQUIRED, 754 PARAM_TO_REQUIRED: ApiDiffType.FUNCTION_PARAM_TO_REQUIRED, 755 PARAM_CHANGE: ApiDiffType.FUNCTION_PARAM_CHANGE, 756 }; 757 } 758 } 759 /** 760 * 处理方法节点的参数,获取对应diff信息 761 * 762 * @param {MethodInfo} oldApiInfo 旧版本的方法节点信息 763 * @param {MethodInfo} newApiInfo 新版本的方法节点信息 764 * @return {*} {ApiDiffType[]} 返回各个参数的变化情况 765 */ 766 static diffMethodParams( 767 oldApiInfo: MethodInfo | TypeAliasInfo, 768 newApiInfo: MethodInfo | TypeAliasInfo 769 ): DiffTypeInfo[] { 770 const diffTypeInfos: DiffTypeInfo[] = []; 771 const isTypeAlias: boolean = oldApiInfo.getApiType() === 'TypeAlias'; 772 const oldMethodParams: ParamInfo[] = isTypeAlias 773 ? (oldApiInfo as TypeAliasInfo).getParamInfos() 774 : (oldApiInfo as MethodInfo).getParams(); 775 const newMethodParams: ParamInfo[] = isTypeAlias 776 ? (newApiInfo as TypeAliasInfo).getParamInfos() 777 : (newApiInfo as MethodInfo).getParams(); 778 const diffMethodType: DiffMethodType & DiffTypeChangeType = ApiNodeDiffHelper.getDiffMethodTypes(isTypeAlias); 779 780 ApiNodeDiffHelper.diffParamsPosition(oldMethodParams, newMethodParams, diffTypeInfos, diffMethodType); 781 ApiNodeDiffHelper.diffNewOptionalParam(oldMethodParams, newMethodParams, diffTypeInfos, diffMethodType); 782 ApiNodeDiffHelper.diffNewRequiredParam(oldMethodParams, newMethodParams, diffTypeInfos, diffMethodType); 783 ApiNodeDiffHelper.diffReducedParam(oldMethodParams, newMethodParams, diffTypeInfos, diffMethodType); 784 ApiNodeDiffHelper.diffParamTypeChange(oldMethodParams, newMethodParams, diffTypeInfos, diffMethodType); 785 ApiNodeDiffHelper.diffParamChange(oldMethodParams, newMethodParams, diffTypeInfos, diffMethodType); 786 ApiNodeDiffHelper.diffMethodParamChange(oldMethodParams, newMethodParams, diffTypeInfos, diffMethodType); 787 return diffTypeInfos; 788 } 789 /** 790 * 方法参数名变化,且不属于新增、减少的情况,归纳为方法参数变化, 791 * 792 * @param {ParamInfo[]} oldMethodParams 函数旧参数节点信息 793 * @param {ParamInfo[]} newMethodParams 函数新参数节点信息 794 * @param diffTypeInfos 处理好的结果信息 795 */ 796 static diffMethodParamChange( 797 oldMethodParams: ParamInfo[], 798 newMethodParams: ParamInfo[], 799 diffTypeInfos: DiffTypeInfo[], 800 diffMethodType: DiffMethodType 801 ): void { 802 const oldParamLen: number = oldMethodParams.length; 803 const newParamLen: number = newMethodParams.length; 804 // 1.新旧版本参数一个不存在即不符合,直接返回 805 if (!oldParamLen || !newParamLen) { 806 return; 807 } 808 // 2. 判断新旧版本参数名称相同的参数的个数和新旧版本的参数是否相同,相同即为新增或者减少参数 809 // 2.1 循环得到所有的参数名称 810 const oldParamNames: string[] = []; 811 const newParamNames: string[] = []; 812 for (let i: number = 0; i < Math.max(oldParamLen, newParamLen); i++) { 813 const newCur: ParamInfo = newMethodParams[i]; 814 const oldCur: ParamInfo = oldMethodParams[i]; 815 newCur && newParamNames.push(newCur.getApiName()); 816 oldCur && oldParamNames.push(oldCur.getApiName()); 817 } 818 // 2.2 找出旧版本不同的参数名称 819 const oldDiffParams: ParamInfo[] = oldMethodParams.filter( 820 (oldParam: ParamInfo) => !newParamNames.includes(oldParam.getApiName()) 821 ); 822 // 2.3 得到参数相同的个数 823 const sameParamsLength: number = oldParamLen - oldDiffParams.length; 824 // 2.4 判断新旧版本参数名称相同的参数的个数和新旧版本的参数是否相同,相同即为新增或者减少参数 825 if (sameParamsLength === oldParamLen || sameParamsLength === newParamLen) { 826 return; 827 } 828 829 let oldDiffInfos: ParamInfo[] = oldMethodParams; 830 let newDiffInfos: ParamInfo[] = newMethodParams; 831 // 3.将新旧版本参数信息中前面检查出来的信息去掉 832 diffTypeInfos.forEach((diffInfo: DiffTypeInfo) => { 833 // 循环已经得到的结果信息,找到新旧版本里不在已经得到的结果信息里面的参数信息 834 oldDiffInfos = oldDiffInfos.filter( 835 (oldDiffInfo: ParamInfo) => diffInfo.getOldMessage() !== oldDiffInfo.getDefinedText() 836 ); 837 newDiffInfos = newDiffInfos.filter( 838 (newDiffInfo: ParamInfo) => diffInfo.getNewMessage() !== newDiffInfo.getDefinedText() 839 ); 840 }); 841 // 4.剩下的部分就是发生变化的部分,生成返回信息 842 const oldNamesStr: string = stitchMethodParameters(oldDiffInfos); 843 const newNamesStr: string = stitchMethodParameters(newDiffInfos); 844 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 845 diffTypeInfo.setDiffType(diffMethodType.PARAM_CHANGE).setOldMessage(oldNamesStr).setNewMessage(newNamesStr); 846 diffTypeInfos.push(diffTypeInfo); 847 } 848 /** 849 * 比较函数位置发生变化 850 * 851 * @param {ParamInfo[]} oldMethodParams 函数旧参数节点信息 852 * @param {ParamInfo[]} newMethodParams 函数新参数节点信息 853 * @param diffTypeInfos 854 */ 855 static diffParamsPosition( 856 oldMethodParams: ParamInfo[], 857 newMethodParams: ParamInfo[], 858 diffTypeInfos: DiffTypeInfo[], 859 diffMethodType: DiffMethodType 860 ): void { 861 const oldParamLen: number = oldMethodParams.length; 862 const newParamLen: number = newMethodParams.length; 863 // 1.如果旧版本的参数长度不大于1,或者两者长度不一致,直接返回 864 if (oldParamLen <= 1 || oldParamLen !== newParamLen) { 865 return; 866 } 867 // 2.判断两个版本的相同位置的参数名称是否一致,相同直接返回 868 const isSamePosition: boolean = checkIsSameOfSamePosition(newMethodParams, oldMethodParams); 869 if (isSamePosition) { 870 return; 871 } 872 // 3.如果旧版本的参数不完全包含新版本的参数或者两个版本的参数是否完全一致,一个不符合直接返回 873 const isContain: boolean = checkIsContain(oldMethodParams, newMethodParams); 874 if (!isContain) { 875 return; 876 } 877 // 4.上述情况都不符合,处理返回信息 878 const oldNamesStr: string = stitchMethodParameters(oldMethodParams); 879 const newNamesStr: string = stitchMethodParameters(newMethodParams); 880 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 881 diffTypeInfo.setDiffType(diffMethodType.POS_CHANGE).setOldMessage(oldNamesStr).setNewMessage(newNamesStr); 882 diffTypeInfos.push(diffTypeInfo); 883 } 884 885 /** 886 * 函数新增可选参数 887 * 888 * @param oldMethodParams 889 * @param newMethodParams 890 * @param diffTypeInfos 891 */ 892 static diffNewOptionalParam( 893 oldMethodParams: ParamInfo[], 894 newMethodParams: ParamInfo[], 895 diffTypeInfos: DiffTypeInfo[], 896 diffMethodType: DiffMethodType 897 ): void { 898 const oldParamLen: number = oldMethodParams.length; 899 const newParamLen: number = newMethodParams.length; 900 // 1.如果新版本参数为空或者旧版本参数长度大于或者等于新版本参数长度,直接返回 901 if (newParamLen === 0 || oldParamLen >= newParamLen) { 902 return; 903 } 904 // 2.新版本参数需要完全包含旧版本,如果不包含,直接返回 905 const isContain: boolean = checkIsContain(newMethodParams, oldMethodParams); 906 if (!isContain) { 907 return; 908 } 909 // 3.是否存在新增的可选参数 910 const oldParamNames: string[] = oldMethodParams.map((oldParam: ParamInfo) => oldParam.getApiName()); 911 const addParams: ParamInfo[] = newMethodParams.filter((newParam: ParamInfo) => { 912 const curParamName: string = newParam.getApiName(); 913 return !oldParamNames.includes(curParamName) && !newParam.getIsRequired(); 914 }); 915 // 4.新版本新增的参数是否存在参数是可选类型,不存在直接返回 916 if (!addParams.length) { 917 return; 918 } 919 // 5.存在新增的参数是可选参数,处理返回信息 920 const addParamNamesStr: string = stitchMethodParameters(addParams); 921 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 922 diffTypeInfo.setOldMessage('').setDiffType(diffMethodType.ADD_OPTIONAL_PARAM).setNewMessage(addParamNamesStr); 923 diffTypeInfos.push(diffTypeInfo); 924 } 925 926 /** 927 * 函数新增必选参数 928 * 929 * @param oldMethodParams 930 * @param newMethodParams 931 * @param diffTypeInfos 932 */ 933 static diffNewRequiredParam( 934 oldMethodParams: ParamInfo[], 935 newMethodParams: ParamInfo[], 936 diffTypeInfos: DiffTypeInfo[], 937 diffMethodType: DiffMethodType 938 ): void { 939 const oldParamLen: number = oldMethodParams.length; 940 const newParamLen: number = newMethodParams.length; 941 // 1.如果新版本参数为空或者旧版本参数长度大于或者等于新版本参数长度,直接返回 942 if (newParamLen === 0 || oldParamLen >= newParamLen) { 943 return; 944 } 945 // 2.新版本参数需要完全包含旧版本,如果不包含,直接返回 946 const isContain: boolean = checkIsContain(newMethodParams, oldMethodParams); 947 if (!isContain) { 948 return; 949 } 950 // 3.是否存在新增的必选参数 951 const oldParamNames: string[] = oldMethodParams.map((oldParam: ParamInfo) => oldParam.getApiName()); 952 const addParams: ParamInfo[] = newMethodParams.filter((newParam: ParamInfo) => { 953 const curParamName: string = newParam.getApiName(); 954 return !oldParamNames.includes(curParamName) && newParam.getIsRequired(); 955 }); 956 // 4.新版本新增的参数是否存在参数是必选类型,不存在直接返回 957 if (!addParams.length) { 958 return; 959 } 960 // 5.存在新增的参数是可选参数,处理返回信息 961 const addParamNamesStr: string = stitchMethodParameters(addParams); 962 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 963 diffTypeInfo.setDiffType(diffMethodType.ADD_REQUIRED_PARAM).setOldMessage('').setNewMessage(addParamNamesStr); 964 diffTypeInfos.push(diffTypeInfo); 965 } 966 967 /** 968 * 函数删除参数 969 * 970 * @param oldMethodParams 971 * @param newMethodParams 972 * @param diffTypeInfos 973 */ 974 static diffReducedParam( 975 oldMethodParams: ParamInfo[], 976 newMethodParams: ParamInfo[], 977 diffTypeInfos: DiffTypeInfo[], 978 diffMethodType: DiffMethodType 979 ): void { 980 const oldParamLen: number = oldMethodParams.length; 981 const newParamLen: number = newMethodParams.length; 982 // 1.旧版本参数为空或者新版本参数长度大于或者等于旧版本参数长度,直接返回 983 if (oldParamLen === 0 || newParamLen >= oldParamLen) { 984 return; 985 } 986 // 2.如果旧版本的参数不包含新版本的参数,直接返回 987 const isContain: boolean = checkIsContain(oldMethodParams, newMethodParams); 988 if (newParamLen > 0 && !isContain) { 989 return; 990 } 991 // 3.参数减少,处理返回信息 992 const newParamNames: string[] = newMethodParams.map((newParam: ParamInfo) => newParam.getApiName()); 993 const reduceParams: ParamInfo[] = oldMethodParams.filter( 994 (oldParam: ParamInfo) => !newParamNames.includes(oldParam.getApiName()) 995 ); 996 const reduceNamesStr: string = stitchMethodParameters(reduceParams); 997 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 998 diffTypeInfo.setDiffType(diffMethodType.REDUCE_PARAM).setOldMessage(reduceNamesStr).setNewMessage(''); 999 diffTypeInfos.push(diffTypeInfo); 1000 } 1001 /** 1002 * 比较参数必选/可选的变更,(可选->必选,必选->可选) 1003 * 1004 * @param oldMethodParams 1005 * @param newMethodParams 1006 * @param diffTypeInfos 1007 */ 1008 static diffParamChange( 1009 oldMethodParams: ParamInfo[], 1010 newMethodParams: ParamInfo[], 1011 diffTypeInfos: DiffTypeInfo[], 1012 diffMethodType: DiffMethodType 1013 ): void { 1014 // 1.新旧版本的参数长度应大于0 1015 const oldParamLen: number = oldMethodParams.length; 1016 const newParamLen: number = newMethodParams.length; 1017 if (!oldParamLen || !newParamLen) { 1018 return; 1019 } 1020 // 2.找到参数名称一致和参数类型一致的参数进行比较,不存在直接返回 1021 const sameParamInfos: ParamInfo[] = oldMethodParams.filter((oldParam: ParamInfo) => { 1022 const oldParamName: string = oldParam.getApiName(); 1023 return newMethodParams.find((newParam: ParamInfo) => newParam.getApiName() === oldParamName); 1024 }); 1025 if (!sameParamInfos.length) { 1026 return; 1027 } 1028 // 3.比较参数名和类型一致是否发生了可选/必选的变化,参数类型不需要计较 1029 sameParamInfos.forEach((sameInfo: ParamInfo, idx: number) => { 1030 const curOldParamName: string = sameInfo.getApiName(); 1031 const curNewParam: ParamInfo = newMethodParams.find( 1032 (newParam: ParamInfo) => newParam.getApiName() === curOldParamName 1033 )!; 1034 if (curNewParam.getIsRequired() !== sameInfo.getIsRequired()) { 1035 // 参数发生了可选/必选的变化,处理返回信息 1036 const oldMessage = sameInfo.getDefinedText(); 1037 const newMessage = curNewParam.getDefinedText(); 1038 const changeType: number = sameInfo.getIsRequired() 1039 ? diffMethodType.PARAM_TO_UNREQUIRED 1040 : diffMethodType.PARAM_TO_REQUIRED; 1041 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 1042 diffTypeInfo.setDiffType(changeType).setOldMessage(oldMessage).setNewMessage(newMessage); 1043 diffTypeInfos.push(diffTypeInfo); 1044 } 1045 }); 1046 } 1047 1048 /** 1049 * 比较参数类型的变更,(参数类型范围扩大/参数类型范围缩小/参数类型变更) 1050 * 1051 * @param oldMethodParams 1052 * @param newMethodParams 1053 * @param diffTypeInfos 1054 */ 1055 static diffParamTypeChange( 1056 oldMethodParams: ParamInfo[], 1057 newMethodParams: ParamInfo[], 1058 diffTypeInfos: DiffTypeInfo[], 1059 diffMethodType: DiffMethodType & DiffTypeChangeType 1060 ): void { 1061 //1.判断新旧版本参数长度大于0 1062 const oldParamLen: number = oldMethodParams.length; 1063 const newParamLen: number = newMethodParams.length; 1064 if (!oldParamLen || !newParamLen) { 1065 return; 1066 } 1067 const newParamName: string[] = newMethodParams.map((newParam: ParamInfo) => newParam.getApiName()); 1068 // 2.需要新旧版本存在参数名称一致的,不存在直接返回 1069 const sameParamInfo: ParamInfo[] = oldMethodParams.filter((oldParam: ParamInfo) => 1070 newParamName.includes(oldParam.getApiName()) 1071 ); 1072 if (!sameParamInfo.length) { 1073 return; 1074 } 1075 // 3.寻找参数名称相同的情况下的参数类型变化的 1076 sameParamInfo.forEach((curSame: ParamInfo, idx: number) => { 1077 const oldParamTypes: string[] = curSame.getType(); 1078 const curNewParam: ParamInfo = newMethodParams.find( 1079 (newParam: ParamInfo) => newParam.getApiName() === curSame.getApiName() 1080 )!; 1081 const newParamTypes: string[] = curNewParam.getType(); 1082 // 处理参数类型不一样的,生成返回信息 1083 if (oldParamTypes.toString().replace(/\r|\n|\s+|'|"/g, '') !== newParamTypes.toString().replace(/\r|\n|\s+|'|"/g, '')) { 1084 // 根据参数的差异来获取对应的statusCode 1085 const diffType: number = diffChangeType(oldParamTypes, newParamTypes, diffMethodType); 1086 const oldMessage: string = curSame.getDefinedText(); 1087 const newMessage: string = curNewParam.getDefinedText(); 1088 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 1089 diffTypeInfo.setDiffType(diffType).setOldMessage(oldMessage).setNewMessage(newMessage); 1090 diffTypeInfos.push(diffTypeInfo); 1091 } 1092 }); 1093 } 1094 1095 /** 1096 * 处理方法节点的参数名称 1097 * 1098 * @param {ParamInfo} oldApiInfo 旧版本的参数节点信息 1099 * @param {ParamInfo} newApiInfo 新版本的参数节点信息 1100 * @return {*} {(ApiDiffType | undefined)} 方法节点的参数名称的变化情况 1101 */ 1102 static diffMethodParamName(oldApiInfo: ParamInfo, newApiInfo: ParamInfo): ApiDiffType | undefined { 1103 const oldParamName: string = oldApiInfo.getApiName(); 1104 const newParamName: string = newApiInfo.getApiName(); 1105 if (oldParamName === newParamName) { 1106 return undefined; 1107 } 1108 return ApiDiffType.FUNCTION_PARAM_NAME_CHANGE; 1109 } 1110 1111 /** 1112 * 处理方法节点的参数类型 1113 * 1114 * @param {ParamInfo} oldApiInfo 旧版本的参数节点信息 1115 * @param {ParamInfo} newApiInfo 新版本的参数节点信息 1116 * @return {*} {(ApiDiffType | undefined)} 方法节点的参数类型的变化情况 1117 */ 1118 static diffMethodParamType(oldApiInfo: ParamInfo, newApiInfo: ParamInfo): ApiDiffType | undefined { 1119 const oldParamType: string[] = oldApiInfo.getType(); 1120 const newParamType: string[] = newApiInfo.getType(); 1121 const oldParamTypeStr: string = oldParamType 1122 .toString() 1123 .replace(/\r|\n|\s+|'|"/g, '') 1124 .replace(/\|/g, '\\|'); 1125 const newParamTypeStr: string = newParamType 1126 .toString() 1127 .replace(/\r|\n|\s+|'|"/g, '') 1128 .replace(/\|/g, `\\|`); 1129 if (oldParamTypeStr === newParamTypeStr) { 1130 return undefined; 1131 } 1132 if (StringUtils.hasSubstring(newParamTypeStr, oldParamTypeStr)) { 1133 return ApiDiffType.FUNCTION_PARAM_TYPE_ADD; 1134 } 1135 if (StringUtils.hasSubstring(oldParamTypeStr, newParamTypeStr)) { 1136 return ApiDiffType.FUNCTION_PARAM_TYPE_REDUCE; 1137 } 1138 return ApiDiffType.FUNCTION_PARAM_TYPE_CHANGE; 1139 } 1140 1141 /** 1142 * 处理方法节点的参数必选 1143 * 1144 * @param {ParamInfo} oldApiInfo 旧版本的参数节点信息 1145 * @param {ParamInfo} newApiInfo 新版本的参数节点信息 1146 * @return {*} {(ApiDiffType | undefined)} 方法节点的必选参数的变化情况 1147 */ 1148 static diffMethodParamRequired(oldApiInfo: ParamInfo, newApiInfo: ParamInfo): ApiDiffType | undefined { 1149 const oldParamISRequired: boolean = oldApiInfo.getIsRequired(); 1150 const newParamISRequired: boolean = newApiInfo.getIsRequired(); 1151 if (oldParamISRequired === newParamISRequired) { 1152 return undefined; 1153 } 1154 return newParamISRequired ? ApiDiffType.FUNCTION_PARAM_TO_REQUIRED : ApiDiffType.FUNCTION_PARAM_TO_UNREQUIRED; 1155 } 1156 1157 /** 1158 * 处理class节点,获取对应diff信息 1159 * 1160 * @param {ApiInfo} oldApiInfo 旧版本的class节点信息 1161 * @param {ApiInfo} newApiInfo 新版本的class节点信息 1162 * @param {BasicDiffInfo[]} diffInfos 各个节点diff信息集合 1163 * @return {*} {void} 1164 */ 1165 static diffClass(oldApiInfo: ApiInfo, newApiInfo: ApiInfo, diffInfos: BasicDiffInfo[]): void { 1166 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 1167 const olaClassName: string = oldApiInfo.getApiName(); 1168 const newClassName: string = newApiInfo.getApiName(); 1169 if (olaClassName === newClassName) { 1170 return; 1171 } 1172 diffTypeInfo 1173 .setStatusCode(ApiStatusCode.CLASS_CHANGES) 1174 .setDiffType(ApiDiffType.API_NAME_CHANGE) 1175 .setOldMessage(olaClassName) 1176 .setNewMessage(newClassName); 1177 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo(oldApiInfo, newApiInfo, diffTypeInfo); 1178 diffInfos.push(diffInfo); 1179 } 1180 1181 /** 1182 * 处理interface节点,获取对应diff信息 1183 * 1184 * @param {ApiInfo} oldApiInfo 旧版本的interface节点信息 1185 * @param {ApiInfo} newApiInfo 新版本的interface节点信息 1186 * @param {BasicDiffInfo[]} diffInfos 各个节点diff信息集合 1187 * @return {*} {void} 1188 */ 1189 static diffInterface(oldApiInfo: ApiInfo, newApiInfo: ApiInfo, diffInfos: BasicDiffInfo[]): void { 1190 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 1191 const olaClassName: string = oldApiInfo.getApiName(); 1192 const newClassName: string = newApiInfo.getApiName(); 1193 if (olaClassName === newClassName) { 1194 return; 1195 } 1196 diffTypeInfo 1197 .setStatusCode(ApiStatusCode.CLASS_CHANGES) 1198 .setDiffType(ApiDiffType.API_NAME_CHANGE) 1199 .setOldMessage(olaClassName) 1200 .setNewMessage(newClassName); 1201 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo(oldApiInfo, newApiInfo, diffTypeInfo); 1202 diffInfos.push(diffInfo); 1203 } 1204 1205 /** 1206 * 处理namespace节点,获取对应diff信息 1207 * 1208 * @param {ApiInfo} oldApiInfo 旧版本的namespace节点信息 1209 * @param {ApiInfo} newApiInfo 新版本的namespace节点信息 1210 * @param {BasicDiffInfo[]} diffInfos 各个节点diff信息集合 1211 * @return {*} {void} 1212 */ 1213 static diffNamespace(oldApiInfo: ApiInfo, newApiInfo: ApiInfo, diffInfos: BasicDiffInfo[]): void { 1214 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 1215 const olaClassName: string = oldApiInfo.getApiName(); 1216 const newClassName: string = newApiInfo.getApiName(); 1217 if (olaClassName === newClassName) { 1218 return; 1219 } 1220 diffTypeInfo 1221 .setStatusCode(ApiStatusCode.CLASS_CHANGES) 1222 .setDiffType(ApiDiffType.API_NAME_CHANGE) 1223 .setOldMessage(olaClassName) 1224 .setNewMessage(newClassName); 1225 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo(oldApiInfo, newApiInfo, diffTypeInfo); 1226 diffInfos.push(diffInfo); 1227 } 1228 1229 /** 1230 * 处理属性节点,获取对应diff信息 1231 * 1232 * @param {ApiInfo} oldApiInfo 旧版本的属性节点信息 1233 * @param {ApiInfo} newApiInfo 新版本的属性节点信息 1234 * @param {BasicDiffInfo[]} diffInfos 各个节点diff信息集合 1235 * @return {*} {void} 1236 */ 1237 static diffProperty(oldApiInfo: ApiInfo, newApiInfo: ApiInfo, diffInfos: BasicDiffInfo[]): void { 1238 propertyDiffProcessors.forEach((propertyDiffProcessor: ApiSceneDiffProcessor) => { 1239 const diffType: DiffTypeInfo | undefined = propertyDiffProcessor(oldApiInfo, newApiInfo); 1240 if (!diffType) { 1241 return; 1242 } 1243 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo( 1244 oldApiInfo, 1245 newApiInfo, 1246 diffType.setStatusCode(ApiStatusCode.FUNCTION_CHANGES) 1247 ); 1248 diffInfos.push(diffInfo); 1249 }); 1250 } 1251 1252 /** 1253 * 处理属性节点的类型 1254 * 1255 * @param {ApiInfo} oldApiInfo 旧版本的属性节点信息 1256 * @param {ApiInfo} newApiInfo 新版本的属性节点信息 1257 * @return {*} {(ApiDiffType | undefined)} 属性节点的类型的变化情况 1258 */ 1259 static diffPropertyType(oldApiInfo: PropertyInfo, newApiInfo: PropertyInfo): DiffTypeInfo | undefined { 1260 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 1261 const olaPropertyType: string[] = oldApiInfo.getType(); 1262 const newPropertyType: string[] = newApiInfo.getType(); 1263 const oldPropertyIsReadOnly: boolean = oldApiInfo.getIsReadOnly(); 1264 const newPropertyIsReadOnly: boolean = newApiInfo.getIsReadOnly(); 1265 const olaPropertyTypeStr = olaPropertyType.toString().replace(/\r|\n|\s+/g, ''); 1266 const newPropertyTypeStr = newPropertyType.toString().replace(/\r|\n|\s+/g, ''); 1267 if (olaPropertyTypeStr === newPropertyTypeStr) { 1268 return undefined; 1269 } 1270 diffTypeInfo.setOldMessage(olaPropertyType.toString()).setNewMessage(newPropertyType.toString()); 1271 if (olaPropertyTypeStr.replace(/\,|\;/g, '') === newPropertyTypeStr.replace(/\,|\;/g, '')) { 1272 return diffTypeInfo.setDiffType(ApiDiffType.PROPERTY_TYPE_SIGN_CHANGE); 1273 } 1274 if (StringUtils.hasSubstring(newPropertyTypeStr, olaPropertyTypeStr)) { 1275 return diffTypeInfo.setDiffType( 1276 newPropertyIsReadOnly ? ApiDiffType.PROPERTY_READONLY_ADD : ApiDiffType.PROPERTY_WRITABLE_ADD 1277 ); 1278 } 1279 if (StringUtils.hasSubstring(olaPropertyTypeStr, newPropertyTypeStr)) { 1280 return diffTypeInfo.setDiffType( 1281 oldPropertyIsReadOnly ? ApiDiffType.PROPERTY_READONLY_REDUCE : ApiDiffType.PROPERTY_WRITABLE_REDUCE 1282 ); 1283 } 1284 return diffTypeInfo.setDiffType(ApiDiffType.PROPERTY_TYPE_CHANGE); 1285 } 1286 1287 /** 1288 * 处理属性节点的必选属性 1289 * 1290 * @param {ApiInfo} oldApiInfo 旧版本的属性节点信息 1291 * @param {ApiInfo} newApiInfo 新版本的属性节点信息 1292 * @return {*} {(ApiDiffType | undefined)} 属性节点的必选属性的变化情况 1293 */ 1294 static diffPropertyRequired(oldApiInfo: PropertyInfo, newApiInfo: PropertyInfo): DiffTypeInfo | undefined { 1295 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 1296 const oldPropertyName: string = oldApiInfo.getApiName(); 1297 const newPropertyName: string = newApiInfo.getApiName(); 1298 const oldPropertyIsReadOnly: boolean = oldApiInfo.getIsReadOnly(); 1299 //???只读属性是否会变为可写属性 1300 const propertyRequiredDiffMap: Map<string, ApiDiffType> = new Map([ 1301 //old是否必选_new是否必选_old是否只读 1302 ['_true_false_true', ApiDiffType.PROPERTY_READONLY_TO_UNREQUIRED], 1303 ['_false_true_true', ApiDiffType.PROPERTY_READONLY_TO_REQUIRED], 1304 ['_true_false_false', ApiDiffType.PROPERTY_WRITABLE_TO_UNREQUIRED], 1305 ['_false_true_false', ApiDiffType.PROPERTY_WRITABLE_TO_REQUIRED], 1306 ]); 1307 const oldPropertyISRequired: boolean = oldApiInfo.getIsRequired(); 1308 const newPropertyISRequired: boolean = newApiInfo.getIsRequired(); 1309 1310 if (oldPropertyName === newPropertyName && oldPropertyISRequired === newPropertyISRequired) { 1311 return undefined; 1312 } 1313 diffTypeInfo.setOldMessage(oldApiInfo.getDefinedText()).setNewMessage(newApiInfo.getDefinedText()); 1314 const paramRequiredStr: string = `_${!!oldPropertyISRequired}_${!!newPropertyISRequired}_${!!oldPropertyIsReadOnly}`; 1315 const paramRequiredType: ApiDiffType = propertyRequiredDiffMap.get(paramRequiredStr) as ApiDiffType; 1316 return diffTypeInfo.setDiffType(paramRequiredType); 1317 } 1318 1319 /** 1320 * 处理常量节点,获取对应diff信息 1321 * 1322 * @param {ApiInfo} oldApiInfo 旧版本的常量节点信息 1323 * @param {ApiInfo} newApiInfo 新版本的常量节点信息 1324 * @param {BasicDiffInfo[]} diffInfos 各个节点diff信息集合 1325 */ 1326 static diffConstant(oldApiInfo: ApiInfo, newApiInfo: ApiInfo, diffInfos: BasicDiffInfo[]): void { 1327 constantDiffProcessors.forEach((constantDiffProcessor: ApiSceneDiffProcessor) => { 1328 const diffTypeInfo: DiffTypeInfo | undefined = constantDiffProcessor(oldApiInfo, newApiInfo); 1329 if (!diffTypeInfo) { 1330 return; 1331 } 1332 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo( 1333 oldApiInfo, 1334 newApiInfo, 1335 diffTypeInfo.setStatusCode(ApiStatusCode.FUNCTION_CHANGES) 1336 ); 1337 diffInfos.push(diffInfo); 1338 }); 1339 } 1340 1341 /** 1342 * 处理常量节点的值 1343 * 1344 * @param {ConstantInfo} oldApiInfo 旧版本的常量节点信息 1345 * @param {ConstantInfo} newApiInfo 新版本的常量节点信息 1346 * @return {*} {(ApiDiffType | undefined)} 常量节点的值的变化情况 1347 */ 1348 static diffConstantValue(oldApiInfo: ConstantInfo, newApiInfo: ConstantInfo): DiffTypeInfo | undefined { 1349 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 1350 const olaConstantValue: string = oldApiInfo.getValue(); 1351 const newConstantValue: string = newApiInfo.getValue(); 1352 if (olaConstantValue === newConstantValue) { 1353 return undefined; 1354 } 1355 diffTypeInfo.setOldMessage(olaConstantValue).setNewMessage(newConstantValue); 1356 return diffTypeInfo.setDiffType(ApiDiffType.CONSTANT_VALUE_CHANGE); 1357 } 1358 1359 /** 1360 * 处理自定义类型节点,过去对应diff信息 1361 * 1362 * @param {ApiInfo} oldApiInfo 旧版本的自定义类型节点信息 1363 * @param {ApiInfo} newApiInfo 新版本的自定义类型节点信息 1364 * @param {BasicDiffInfo[]} diffInfos 各个节点diff信息集合 1365 */ 1366 static diffTypeAlias(oldApiInfo: ApiInfo, newApiInfo: ApiInfo, diffInfos: BasicDiffInfo[]): void { 1367 typeAliasDiffProcessors.forEach((typeAliasDiffProcessor: ApiSceneDiffProcessor) => { 1368 const diffTypeInfo: DiffTypeInfo | undefined = typeAliasDiffProcessor(oldApiInfo, newApiInfo); 1369 if (!diffTypeInfo) { 1370 return; 1371 } 1372 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo(oldApiInfo, newApiInfo, diffTypeInfo); 1373 diffInfos.push(diffInfo); 1374 }); 1375 // 自定义类型为方法 1376 if ((oldApiInfo as TypeAliasInfo).getTypeIsFunction()) { 1377 const diffTypeInfos: DiffTypeInfo[] = ApiNodeDiffHelper.diffMethodParams( 1378 oldApiInfo as TypeAliasInfo, 1379 newApiInfo as TypeAliasInfo 1380 ); 1381 const diffTypeReturnInfo: DiffTypeInfo | undefined = ApiNodeDiffHelper.diffTypeAliasReturnType( 1382 oldApiInfo as TypeAliasInfo, 1383 newApiInfo as TypeAliasInfo 1384 ); 1385 diffTypeReturnInfo && diffTypeInfos.push(diffTypeReturnInfo); 1386 diffTypeInfos.forEach((info: DiffTypeInfo) => { 1387 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo( 1388 oldApiInfo, 1389 newApiInfo, 1390 info.setStatusCode(ApiStatusCode.TYPE_CHNAGES) 1391 ); 1392 diffInfos.push(diffInfo); 1393 }); 1394 } 1395 } 1396 1397 /** 1398 * 处理自定义类型节点的类型(类型值范围扩大/类型值范围缩小/类型值改变) 1399 * 1400 * @param {TypeAliasInfo} oldApiInfo 旧版本的自定义类型节点信息 1401 * @param {TypeAliasInfo} newApiInfo 新版本的自定义类型节点信息 1402 * @return {*} {(ApiDiffType | undefined)} 自定义类型节点的类型的变化情况 1403 */ 1404 static diffTypeAliasType(oldApiInfo: TypeAliasInfo, newApiInfo: TypeAliasInfo): DiffTypeInfo | undefined { 1405 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 1406 const olaTypeAliasType: string[] = oldApiInfo.getType(); 1407 const newTypeAliasType: string[] = newApiInfo.getType(); 1408 const olaTypeAliasTypeStr: string = olaTypeAliasType.toString(); 1409 const newTypeAliasTypeStr: string = newTypeAliasType.toString(); 1410 // 1.两者定义相同,没有变化 1411 if (olaTypeAliasTypeStr.replace(/\r|\n|\s+|'|"/g, '') === newTypeAliasTypeStr.replace(/\r|\n|\s+|'|"/g, '')) { 1412 return undefined; 1413 } 1414 // 自定义函数类型 1415 if (oldApiInfo.getTypeIsFunction()) { 1416 return undefined; 1417 } 1418 // 2.两者定义不同 1419 const diffMethodType: DiffTypeChangeType = { 1420 PARAM_TYPE_CHANGE: ApiDiffType.TYPE_ALIAS_CHANGE, 1421 PARAM_TYPE_ADD: ApiDiffType.TYPE_ALIAS_ADD, 1422 PARAM_TYPE_REDUCE: ApiDiffType.TYPE_ALIAS_REDUCE, 1423 }; 1424 const diffType: number = diffChangeType(olaTypeAliasType, newTypeAliasType, diffMethodType); 1425 diffTypeInfo 1426 .setOldMessage(olaTypeAliasType.join(' | ')) 1427 .setNewMessage(newTypeAliasType.join(' | ')) 1428 .setStatusCode(ApiStatusCode.TYPE_CHNAGES) 1429 .setDiffType(diffType); 1430 return diffTypeInfo; 1431 } 1432 /** 1433 * 处理枚举值节点,获取对应diff信息 1434 * 1435 * @param {ApiInfo} oldApiInfo 旧版本的枚举值节点信息 1436 * @param {ApiInfo} newApiInfo 新版本的枚举值节点信息 1437 * @param {BasicDiffInfo[]} diffInfos 各个节点diff信息集合 1438 */ 1439 static diffEnum(oldApiInfo: ApiInfo, newApiInfo: ApiInfo, diffInfos: BasicDiffInfo[]): void { 1440 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 1441 const oldEnumName: string = oldApiInfo.getApiName(); 1442 const newEnumName: string = newApiInfo.getApiName(); 1443 if (oldEnumName === newEnumName) { 1444 return; 1445 } 1446 diffTypeInfo.setDiffType(ApiDiffType.API_NAME_CHANGE).setOldMessage(oldEnumName).setNewMessage(newEnumName); 1447 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo( 1448 oldApiInfo, 1449 newApiInfo, 1450 diffTypeInfo.setStatusCode(ApiStatusCode.FUNCTION_CHANGES) 1451 ); 1452 diffInfos.push(diffInfo); 1453 } 1454 1455 /** 1456 * 处理枚举值节点的每个元素,获取对应diff信息 1457 * 1458 * @param {EnumValueInfo} oldApiInfo 旧版本的枚举值节点元素信息 1459 * @param {EnumValueInfo} newApiInfo 新版本的枚举值节点元素信息 1460 * @param {BasicDiffInfo[]} diffInfos 各个节点diff信息集合 1461 */ 1462 static diffEnumMember(oldApiInfo: EnumValueInfo, newApiInfo: EnumValueInfo, diffInfos: BasicDiffInfo[]): void { 1463 enumDiffProcessors.forEach((enumDiffProcessor: ApiSceneDiffProcessor) => { 1464 const diffTypeInfo: DiffTypeInfo | undefined = enumDiffProcessor(oldApiInfo, newApiInfo); 1465 if (!diffTypeInfo) { 1466 return; 1467 } 1468 const diffInfo: BasicDiffInfo = DiffProcessorHelper.wrapDiffInfo( 1469 oldApiInfo, 1470 newApiInfo, 1471 diffTypeInfo.setStatusCode(ApiStatusCode.FUNCTION_CHANGES) 1472 ); 1473 diffInfos.push(diffInfo); 1474 }); 1475 } 1476 1477 /** 1478 * 处理枚举值节点的每个元素的值 1479 * 1480 * @param {EnumValueInfo} oldApiInfo 旧版本的枚举值节点元素信息 1481 * @param {EnumValueInfo} newApiInfo 新版本的枚举值节点元素信息 1482 * @return {*} {(ApiDiffType | undefined)} 枚举值节点的每个元素的值的变化情况 1483 */ 1484 static diffEnumMemberValue(oldApiInfo: EnumValueInfo, newApiInfo: EnumValueInfo): DiffTypeInfo | undefined { 1485 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 1486 const olaEnumMemberValue: string = oldApiInfo.getValue(); 1487 const newEnumMemberValue: string = newApiInfo.getValue(); 1488 if (olaEnumMemberValue === newEnumMemberValue) { 1489 return undefined; 1490 } 1491 diffTypeInfo.setOldMessage(olaEnumMemberValue).setNewMessage(newEnumMemberValue); 1492 return diffTypeInfo.setDiffType(ApiDiffType.ENUM_MEMBER_VALUE_CHANGE); 1493 } 1494 1495 /** 1496 * 处理通用类型节点的apiName 1497 * 1498 * @param {ApiInfo} oldApiInfo 旧版本的节点信息 1499 * @param {ApiInfo} newApiInfo 新版本的节点信息 1500 * @return {*} {(ApiDiffType | undefined)} apiName的变化情况 1501 */ 1502 static diffApiName(oldApiInfo: ApiInfo, newApiInfo: ApiInfo): DiffTypeInfo | undefined { 1503 const diffTypeInfo: DiffTypeInfo = new DiffTypeInfo(); 1504 const olaConstantName: string = oldApiInfo.getApiName(); 1505 const newConstantName: string = newApiInfo.getApiName(); 1506 if (olaConstantName === newConstantName) { 1507 return undefined; 1508 } 1509 diffTypeInfo.setOldMessage(olaConstantName).setNewMessage(newConstantName); 1510 return diffTypeInfo.setDiffType(ApiDiffType.API_NAME_CHANGE); 1511 } 1512 1513 /** 1514 * 新旧版本参数个数没变化时,判断参数类型范围扩大/缩小/更改 1515 * 1516 * @param oldTypes 旧版本参数类型 1517 * @param newTypes 新版本参数类型 1518 * @param diffTypes 1519 * @returns 1520 */ 1521 static diffSingleParamType(oldTypes: string[], newTypes: string[], diffTypes: DiffTypeChangeType): number { 1522 const oldParamTypeStr: string = oldTypes 1523 .toString() 1524 .replace(/\r|\n|\s+|'|"|>/g, '') 1525 .replace(/\|/g, '\\|'); 1526 const newParamTypeStr: string = newTypes 1527 .toString() 1528 .replace(/\r|\n|\s+|'|"|>/g, '') 1529 .replace(/\|/g, '\\|'); 1530 if (StringUtils.hasSubstring(newParamTypeStr, oldParamTypeStr)) { 1531 return diffTypes.PARAM_TYPE_ADD; 1532 } 1533 if (StringUtils.hasSubstring(oldParamTypeStr, newParamTypeStr)) { 1534 return diffTypes.PARAM_TYPE_REDUCE; 1535 } 1536 return diffTypes.PARAM_TYPE_CHANGE; 1537 } 1538 } 1539 1540 /** 1541 * 检查父集是否完全包含子集 1542 * 1543 * @param {ParamInfo[]} parentInfos 父集节点信息 1544 * @param {ParamInfo[]} childInfos 子集节点信息 1545 * @returns {*} {boolean} 完全包含为true, 否则为false 1546 */ 1547 function checkIsContain(parentInfos: ParamInfo[], childInfos: ParamInfo[]): boolean { 1548 return childInfos.every((child: ParamInfo) => { 1549 const curChildName = child.getApiName(); 1550 // 父节点里面是否存在子节点的参数名称 1551 const curParentNode = parentInfos.find((item: ParamInfo) => item.getApiName() === curChildName); 1552 // 相同参数的类型是否一样 1553 return curParentNode && curParentNode.getApiType() === child.getApiType(); 1554 }); 1555 } 1556 1557 function checkParentContainChild(parentStrArr: string[], childStrArr: string[]): boolean { 1558 return childStrArr.every((child: string) => parentStrArr.includes(child)); 1559 } 1560 1561 interface DiffTypeChangeType { 1562 PARAM_TYPE_CHANGE: ApiDiffType; 1563 PARAM_TYPE_ADD: ApiDiffType; 1564 PARAM_TYPE_REDUCE: ApiDiffType; 1565 } 1566 // statusCode对应的几种变化类型 1567 interface DiffMethodType { 1568 POS_CHANGE: ApiDiffType; 1569 ADD_OPTIONAL_PARAM: ApiDiffType; 1570 ADD_REQUIRED_PARAM: ApiDiffType; 1571 REDUCE_PARAM: ApiDiffType; 1572 PARAM_TO_UNREQUIRED: ApiDiffType; 1573 PARAM_TO_REQUIRED: ApiDiffType; 1574 PARAM_CHANGE: ApiDiffType; 1575 } 1576 /** 1577 * 根据参数的差异来获取对应的statusCode 1578 * 1579 * @param {string[]} oldTypes 旧参数数组 1580 * @param {string[]} newTypes 新参数数组 1581 * @returns {*} {ApiDiffType} statusCode 1582 */ 1583 function diffChangeType(oldTypes: string[], newTypes: string[], diffTypes: DiffTypeChangeType): ApiDiffType { 1584 const oldLen: number = oldTypes.length; 1585 const newLen: number = newTypes.length; 1586 switch (oldLen - newLen) { 1587 case 0: 1588 return DiffProcessorHelper.ApiNodeDiffHelper.diffSingleParamType(oldTypes, newTypes, diffTypes); 1589 case -newLen: 1590 return diffTypes.PARAM_TYPE_ADD; 1591 case oldLen: 1592 return diffTypes.PARAM_TYPE_REDUCE; 1593 default: 1594 if (oldLen > newLen) { 1595 return newTypes.every((type: string) => oldTypes.includes(type)) 1596 ? diffTypes.PARAM_TYPE_REDUCE 1597 : diffTypes.PARAM_TYPE_CHANGE; 1598 } else { 1599 return oldTypes.every((type: string) => newTypes.includes(type)) 1600 ? diffTypes.PARAM_TYPE_ADD 1601 : diffTypes.PARAM_TYPE_CHANGE; 1602 } 1603 } 1604 } 1605 1606 /** 1607 * 检查两个版本的相同位置的参数的参数名是否相同 1608 * 1609 * @param {ParamInfo[]} parentInfos 父节点信息 1610 * @param {ParamInfo[]} childInfos 子集节点信息 1611 * @returns {*} {boolean} 完全相同为true, 否则为false 1612 */ 1613 function checkIsSameOfSamePosition(parentInfos: ParamInfo[], childInfos: ParamInfo[]): boolean { 1614 return parentInfos.every((curParentItem: ParamInfo, idx: number) => { 1615 const curChildItem: ParamInfo = childInfos[idx]; 1616 return curParentItem.getApiName() === curChildItem.getApiName(); 1617 }); 1618 } 1619 1620 /** 1621 * 根据当前节点信息来拼接返回的新旧信息 1622 * 1623 * @param {ParamInfo} methodParams 函数参数的节点信息 1624 * @returns {*} {string} 字符串拼接后的节点信息 1625 */ 1626 function stitchMethodParameters(methodParams: ParamInfo[]): string { 1627 if (methodParams.length <= 1) { 1628 return methodParams[0].getDefinedText(); 1629 } 1630 return methodParams.reduce((preStr: string, curItem: ParamInfo, idx: number) => { 1631 let curStr: string = curItem.getDefinedText(); 1632 if (idx !== methodParams.length - 1) { 1633 curStr += ', '; 1634 } 1635 return (preStr += curStr); 1636 }, ''); 1637 } 1638 1639 /** 1640 * 根据节点信息和type生成需要的diff对象 1641 * 1642 * @param {(BasicApiInfo | undefined)} [oldApiInfo=undefined] 旧版本节点信息,默认undefined 1643 * @param {(BasicApiInfo | undefined)} [newApiInfo=undefined] 新版本节点信息,默认undefined 1644 * @param {ApiDiffType} diffType diff的节点类型 1645 * @return {*} {BasicDiffInfo} 生成的diff对象 1646 */ 1647 export function wrapDiffInfo( 1648 oldApiInfo: BasicApiInfo | undefined = undefined, 1649 newApiInfo: BasicApiInfo | undefined = undefined, 1650 diffTypeInfo: DiffTypeInfo, 1651 isNewFile?: boolean 1652 ): BasicDiffInfo { 1653 const newPropertyInfo = newApiInfo as PropertyInfo; 1654 const newMethodInfo = newApiInfo as MethodInfo; 1655 const parentApiType: string = (newApiInfo && newApiInfo.getParentApiType()) ? newApiInfo.getParentApiType() : ''; 1656 let isCompatible = true; 1657 if ( 1658 !isNewFile && parentApiTypeSet.has(parentApiType) && 1659 diffTypeInfo.getDiffType() === ApiDiffType.ADD && 1660 ((newApiInfo?.getApiType() === ApiType.METHOD && newMethodInfo.getIsRequired()) || 1661 (newApiInfo?.getApiType() === ApiType.PROPERTY && newPropertyInfo.getIsRequired())) 1662 ) { 1663 isCompatible = false; 1664 } 1665 const diffInfo: BasicDiffInfo = new BasicDiffInfo(); 1666 const diffType: ApiDiffType = diffTypeInfo.getDiffType(); 1667 const clonedOldApiInfo = oldApiInfo as ApiInfo; 1668 const clonedNewApiInfo = newApiInfo as ApiInfo; 1669 const oldApiLevel: boolean | undefined = clonedOldApiInfo?.getLastJsDocInfo()?.getIsSystemApi(); 1670 const newApiLevel: boolean | undefined = clonedNewApiInfo?.getLastJsDocInfo()?.getIsSystemApi(); 1671 let apiIsSameName: boolean | undefined = clonedNewApiInfo?.getIsSameNameFunction(); 1672 if (!newApiInfo) { 1673 apiIsSameName = clonedOldApiInfo?.getIsSameNameFunction(); 1674 } 1675 1676 if (oldApiInfo) { 1677 processOldApiDiff(oldApiInfo, diffInfo); 1678 } 1679 if (newApiInfo) { 1680 processNewApiDiff(newApiInfo, diffInfo); 1681 } 1682 diffInfo 1683 .setDiffType(diffType) 1684 .setDiffMessage(diffMap.get(diffType) as string) 1685 .setStatusCode(diffTypeInfo.getStatusCode()) 1686 .setIsCompatible(!isCompatible ? false : !incompatibleApiDiffTypes.has(diffType)) 1687 .setOldDescription(diffTypeInfo.getOldMessage()) 1688 .setNewDescription(diffTypeInfo.getNewMessage()) 1689 .setIsSystemapi(newApiLevel ? newApiLevel : oldApiLevel) 1690 .setIsSameNameFunction(apiIsSameName); 1691 return diffInfo; 1692 } 1693 1694 /** 1695 * 添加旧版本的基础信息 1696 * 1697 * @param {BasicApiInfo} oldApiInfo 旧版本的节点信息 1698 * @param {BasicDiffInfo} diffInfo 需要填充的diff对象 1699 */ 1700 function processOldApiDiff(oldApiInfo: BasicApiInfo, diffInfo: BasicDiffInfo): void { 1701 const clonedOldApiInfo: ApiInfo = oldApiInfo as ApiInfo; 1702 const kitInfo: string | undefined = clonedOldApiInfo.getLastJsDocInfo()?.getKit(); 1703 if (kitInfo) { 1704 diffInfo.setOldKitInfo(kitInfo); 1705 } 1706 1707 diffInfo 1708 .setOldApiDefinedText(oldApiInfo.getDefinedText()) 1709 .setApiType(oldApiInfo.getApiType()) 1710 .setOldApiName(oldApiInfo.getApiName()) 1711 .setOldDtsName(oldApiInfo.getFilePath()) 1712 .setOldHierarchicalRelations(oldApiInfo.getHierarchicalRelations()) 1713 .setOldPos(oldApiInfo.getPos()) 1714 .setOldSyscapField(oldApiInfo.getSyscap()); 1715 } 1716 1717 /** 1718 * 添加新版本的基础信息 1719 * 1720 * @param {BasicApiInfo} newApiInfo 新版本的节点信息 1721 * @param {BasicDiffInfo} diffInfo 需要填充的diff对象 1722 */ 1723 function processNewApiDiff(newApiInfo: BasicApiInfo, diffInfo: BasicDiffInfo): void { 1724 const clonedOldApiInfo: ApiInfo = newApiInfo as ApiInfo; 1725 const kitInfo: string | undefined = clonedOldApiInfo.getLastJsDocInfo()?.getKit(); 1726 if (kitInfo) { 1727 diffInfo.setNewKitInfo(kitInfo); 1728 } 1729 diffInfo 1730 .setNewApiDefinedText(newApiInfo.getDefinedText()) 1731 .setApiType(newApiInfo.getApiType()) 1732 .setNewApiName(newApiInfo.getApiName()) 1733 .setNewDtsName(newApiInfo.getFilePath()) 1734 .setNewHierarchicalRelations(newApiInfo.getHierarchicalRelations()) 1735 .setNewPos(newApiInfo.getPos()) 1736 .setNewSyscapField(newApiInfo.getSyscap()); 1737 } 1738 /** 1739 * api节点类型对应的处理方法,获取diff信息 1740 */ 1741 export const apiNodeDiffMethod: Map<string, ApiNodeDiffProcessor> = new Map([ 1742 [ApiType.PROPERTY, ApiNodeDiffHelper.diffProperty], 1743 [ApiType.CLASS, ApiNodeDiffHelper.diffClass], 1744 [ApiType.INTERFACE, ApiNodeDiffHelper.diffInterface], 1745 [ApiType.NAMESPACE, ApiNodeDiffHelper.diffNamespace], 1746 [ApiType.METHOD, ApiNodeDiffHelper.diffMethod], 1747 [ApiType.CONSTANT, ApiNodeDiffHelper.diffConstant], 1748 [ApiType.ENUM, ApiNodeDiffHelper.diffEnum], 1749 [ApiType.ENUM_VALUE, ApiNodeDiffHelper.diffEnumMember], 1750 [ApiType.TYPE_ALIAS, DiffProcessorHelper.ApiNodeDiffHelper.diffTypeAlias], 1751 ]); 1752 1753 /** 1754 * api节点jsdoc需要处理的数据,获取diff信息 1755 */ 1756 export const jsDocDiffProcessors: JsDocDiffProcessor[] = [ 1757 JsDocDiffHelper.diffSyscap, 1758 JsDocDiffHelper.diffDeprecated, 1759 JsDocDiffHelper.diffPermissions, 1760 JsDocDiffHelper.diffIsForm, 1761 JsDocDiffHelper.diffIsCrossPlatForm, 1762 JsDocDiffHelper.diffModelLimitation, 1763 JsDocDiffHelper.diffIsSystemApi, 1764 JsDocDiffHelper.diffAtomicService, 1765 ]; 1766 1767 /** 1768 * 枚举值节点需要处理的数据 1769 */ 1770 export const enumDiffProcessors: ApiSceneDiffProcessor[] = [ 1771 ApiNodeDiffHelper.diffApiName, 1772 ApiNodeDiffHelper.diffEnumMemberValue, 1773 ]; 1774 1775 /** 1776 * 自定义类型节点需要处理的数据 1777 */ 1778 export const typeAliasDiffProcessors: ApiSceneDiffProcessor[] = [ 1779 ApiNodeDiffHelper.diffApiName, 1780 ApiNodeDiffHelper.diffTypeAliasType, 1781 ]; 1782 1783 /** 1784 * 常量节点需要处理的数据 1785 */ 1786 export const constantDiffProcessors: ApiSceneDiffProcessor[] = [ 1787 ApiNodeDiffHelper.diffApiName, 1788 ApiNodeDiffHelper.diffConstantValue, 1789 ]; 1790 1791 /** 1792 * 属性节点需要处理的数据 1793 */ 1794 export const propertyDiffProcessors: ApiSceneDiffProcessor[] = [ 1795 ApiNodeDiffHelper.diffApiName, 1796 ApiNodeDiffHelper.diffPropertyType, 1797 ApiNodeDiffHelper.diffPropertyRequired, 1798 ]; 1799 1800 /** 1801 * 属性节点需要处理的数据 1802 */ 1803 export const methodDiffProcessors: ApiScenesDiffProcessor[] = [ 1804 ApiNodeDiffHelper.diffApiName, 1805 ApiNodeDiffHelper.diffMethodReturnType, 1806 ApiNodeDiffHelper.diffMethodParams, 1807 ]; 1808} 1809