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 ts from 'typescript'; 17 18import { Comment } from './Comment'; 19import { DecoratorInfo } from './Decorator'; 20import { JsDocProcessorHelper } from '../../coreImpl/parser/JsDocProcessor'; 21 22export enum ApiType { 23 SOURCE_FILE = 'SourceFile', 24 REFERENCE_FILE = 'Reference', 25 PROPERTY = 'Property', 26 CLASS = 'Class', 27 INTERFACE = 'Interface', 28 NAMESPACE = 'Namespace', 29 METHOD = 'Method', 30 MODULE = 'Module', 31 EXPORT = 'Export', 32 EXPORT_DEFAULT = 'ExportDefault', 33 CONSTANT = 'Constant', 34 IMPORT = 'Import', 35 DECLARE_CONST = 'DeclareConst', 36 ENUM_VALUE = 'EnumValue', 37 TYPE_ALIAS = 'TypeAlias', 38 PARAM = 'Param', 39 ENUM = 'Enum', 40 STRUCT = 'Struct', 41} 42 43export enum TypeAliasType { 44 UNION_TYPE = 'UnionType', 45 OBJECT_TYPE = 'ObjectType', 46 TUPLE_TYPE = 'TupleType', 47 REFERENCE_TYPE = 'ReferenceType', 48} 49 50export class BasicApiInfo { 51 private node: ts.Node | undefined = undefined; //astnode节点 52 filePath: string = ''; // api所在文件的路径 53 apiType: ApiType = '' as ApiType; // api的类型 54 // api的定义语句,如果为namespace、class、interface、enum等节点的话,则仅为定义的那行 55 definedText: string = ''; 56 pos: ts.LineAndCharacter = { line: -1, character: -1 }; // api所在的位置信息 57 parentApi: BasicApiInfo | undefined = undefined; // 定义api节点的父节点的api信息 58 isExport: boolean = false; // api节点是否有export关键字进行导出 59 apiName: string = ''; // api的名称 60 hierarchicalRelations: string[] = []; // api所属的层级关系 61 decorators: DecoratorInfo[] | undefined = undefined; //decorators修饰器集合 62 isStruct: boolean = false; //是否为structDeclaration内部api 63 syscap: string = ''; 64 currentVersion = '-1'; 65 jsDocText: string = ''; 66 67 constructor(apiType: string = '', node: ts.Node, parentApi: BasicApiInfo | undefined) { 68 this.node = node; 69 this.setParentApi(parentApi); 70 if (parentApi) { 71 this.setFilePath(parentApi.getFilePath()); 72 this.setIsStruct(parentApi.getIsStruct()); 73 } 74 this.setApiType(apiType); 75 const sourceFile: ts.SourceFile = node.getSourceFile(); 76 const start: number = node.getStart(); 77 const pos: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(start); 78 pos.character++; 79 pos.line++; 80 this.setPos(pos); 81 if (node.decorators) { 82 node.decorators.forEach((decorator: ts.Decorator) => { 83 this.addDecorators([new DecoratorInfo(decorator)]); 84 }); 85 } 86 } 87 88 getNode(): ts.Node | undefined { 89 return this.node; 90 } 91 92 removeNode() { 93 this.node = undefined; 94 } 95 96 setFilePath(fileFilePath: string): void { 97 this.filePath = fileFilePath; 98 } 99 100 getFilePath(): string { 101 return this.filePath; 102 } 103 104 setApiType(apiType: string): void { 105 this.apiType = apiType as ApiType; 106 } 107 108 getApiType(): string { 109 return this.apiType; 110 } 111 112 setDefinedText(definedText: string): void { 113 this.definedText = definedText; 114 } 115 116 getDefinedText(): string { 117 return this.definedText; 118 } 119 120 setPos(pos: ts.LineAndCharacter): void { 121 this.pos = pos; 122 } 123 124 getPos(): ts.LineAndCharacter { 125 return this.pos; 126 } 127 128 setParentApi(parentApi: BasicApiInfo | undefined): void { 129 this.parentApi = parentApi; 130 } 131 132 getParentApi(): BasicApiInfo | undefined { 133 return this.parentApi; 134 } 135 136 setIsExport(isExport: boolean): void { 137 this.isExport = isExport; 138 } 139 140 getIsExport(): boolean { 141 return this.isExport; 142 } 143 144 setApiName(apiName: string): void { 145 this.apiName = apiName; 146 if (this.parentApi) { 147 this.setHierarchicalRelations(this.parentApi.getHierarchicalRelations()); 148 } 149 this.addHierarchicalRelation([apiName]); 150 } 151 152 getApiName(): string { 153 return this.apiName; 154 } 155 156 setHierarchicalRelations(hierarchicalRelations: string[]): void { 157 this.hierarchicalRelations = [...hierarchicalRelations]; 158 } 159 160 getHierarchicalRelations(): string[] { 161 return this.hierarchicalRelations; 162 } 163 164 addHierarchicalRelation(hierarchicalRelation: string[]): void { 165 this.hierarchicalRelations.push(...hierarchicalRelation); 166 } 167 168 setDecorators(decorators: DecoratorInfo[]): void { 169 this.decorators = decorators; 170 } 171 172 addDecorators(decorators: DecoratorInfo[]): void { 173 if (!this.decorators) { 174 this.decorators = []; 175 } 176 this.decorators.push(...decorators); 177 } 178 179 getDecorators(): DecoratorInfo[] | undefined { 180 return this.decorators; 181 } 182 183 setIsStruct(isStruct: boolean): void { 184 this.isStruct = isStruct; 185 } 186 187 getIsStruct(): boolean { 188 return this.isStruct; 189 } 190 191 setSyscap(syscap: string): void { 192 this.syscap = syscap; 193 } 194 195 getSyscap(): string { 196 return this.syscap; 197 } 198 199 setCurrentVersion(version: string): void { 200 this.currentVersion = version; 201 } 202 203 getCurrentVersion(): string { 204 return this.currentVersion; 205 } 206 207 setJsDocText(jsDocText: string): void { 208 this.jsDocText = jsDocText; 209 } 210 211 getJsDocText(): string { 212 return this.jsDocText; 213 } 214} 215 216export class ExportDefaultInfo extends BasicApiInfo { } 217 218export class ReferenceInfo extends BasicApiInfo { 219 pathName: string = ''; 220 221 setPathName(pathName: string): ReferenceInfo { 222 this.pathName = pathName; 223 return this; 224 } 225 226 getPathName(): string { 227 return this.pathName; 228 } 229} 230 231export class ExportDeclareInfo extends BasicApiInfo { 232 exportValues: Array<ExportImportValue> = []; 233 234 addExportValues(name: string, type: string): void { 235 this.exportValues.push({ key: name, value: type || name }); 236 } 237 238 getExportValues(): Array<ExportImportValue> { 239 return this.exportValues; 240 } 241} 242 243/** 244 * import导入的信息,包含导入的值和路径信息 245 */ 246export class ImportInfo extends BasicApiInfo { 247 importValues: Array<ExportImportValue> = []; 248 importPath: string = ''; 249 250 addImportValue(name: string, type: string): void { 251 this.importValues.push({ key: name, value: type || name }); 252 } 253 254 getImportValues(): Array<ExportImportValue> { 255 return this.importValues; 256 } 257 258 setImportPath(importPath: string): void { 259 this.importPath = importPath; 260 } 261 262 getImportPath(): string { 263 return this.importPath; 264 } 265} 266 267export class ApiInfo extends BasicApiInfo { 268 jsDocInfos: Comment.JsDocInfo[] = []; // 所有的JsDoc信息 269 270 constructor(apiType: string = '', node: ts.Node, parentApi: BasicApiInfo) { 271 super(apiType, node, parentApi); 272 const jsDocInfos: Comment.JsDocInfo[] = JsDocProcessorHelper.processJsDocInfos(node); 273 this.setJsDocText(node.getFullText().replace(node.getText(), '')); 274 this.addJsDocInfos(jsDocInfos); 275 } 276 277 getJsDocInfos(): Comment.JsDocInfo[] { 278 return this.jsDocInfos; 279 } 280 281 getLastJsDocInfo(): Comment.JsDocInfo | undefined { 282 const length: number = this.jsDocInfos.length; 283 if (length === 0) { 284 return undefined; 285 } 286 return this.jsDocInfos[length - 1]; 287 } 288 289 addJsDocInfos(jsDocInfos: Comment.JsDocInfo[]): void { 290 if (jsDocInfos.length > 0) { 291 this.setCurrentVersion(jsDocInfos[jsDocInfos.length - 1]?.getSince()); 292 } 293 this.jsDocInfos.push(...jsDocInfos); 294 } 295 296 addJsDocInfo(jsDocInfo: Comment.JsDocInfo): void { 297 this.setCurrentVersion(jsDocInfo.getSince()); 298 this.jsDocInfos.push(jsDocInfo); 299 } 300} 301 302export class ClassInfo extends ApiInfo { 303 parentClasses: string[] = []; // 继承的父类 304 childApis: BasicApiInfo[] = []; // 子节点的信息 305 306 setParentClasses(parentClasses: string[]): void { 307 this.parentClasses.push(...parentClasses); 308 } 309 310 getParentClasses(): string[] { 311 return this.parentClasses; 312 } 313 314 addChildApis(childApis: BasicApiInfo[]): void { 315 this.childApis.push(...childApis); 316 } 317 318 addChildApi(childApi: BasicApiInfo): void { 319 this.childApis.push(childApi); 320 } 321 322 getChildApis(): BasicApiInfo[] { 323 return this.childApis; 324 } 325} 326 327export class InterfaceInfo extends ApiInfo { 328 parentClasses: string[] = []; // 继承的父类 329 childApis: BasicApiInfo[] = []; // 子节点的信息 330 331 setParentClasses(parentClasses: string[]): void { 332 this.parentClasses.push(...parentClasses); 333 } 334 335 getParentClasses(): string[] { 336 return this.parentClasses; 337 } 338 339 addChildApis(childApis: BasicApiInfo[]): void { 340 this.childApis.push(...childApis); 341 } 342 343 addChildApi(childApi: BasicApiInfo): void { 344 this.childApis.push(childApi); 345 } 346 347 getChildApis(): BasicApiInfo[] { 348 return this.childApis; 349 } 350} 351 352export class NamespaceInfo extends ApiInfo { 353 childApis: BasicApiInfo[] = []; 354 355 addChildApis(childApis: BasicApiInfo[]): void { 356 this.childApis.push(...childApis); 357 } 358 359 addChildApi(childApi: BasicApiInfo): void { 360 this.childApis.push(childApi); 361 } 362 363 getChildApis(): BasicApiInfo[] { 364 return this.childApis; 365 } 366} 367 368export class StructInfo extends ApiInfo { 369 childApis: BasicApiInfo[] = []; 370 371 addChildApis(childApis: BasicApiInfo[]): void { 372 this.childApis.push(...childApis); 373 } 374 375 addChildApi(childApi: BasicApiInfo): void { 376 this.childApis.push(childApi); 377 } 378 379 getChildApis(): BasicApiInfo[] { 380 return this.childApis; 381 } 382} 383 384export class ModuleInfo extends ApiInfo { 385 childApis: BasicApiInfo[] = []; 386 387 addChildApis(childApis: BasicApiInfo[]): void { 388 this.childApis.push(...childApis); 389 } 390 391 addChildApi(childApi: BasicApiInfo): void { 392 this.childApis.push(childApi); 393 } 394 395 getChildApis(): BasicApiInfo[] { 396 return this.childApis; 397 } 398} 399 400export class EnumInfo extends ApiInfo { 401 childApis: BasicApiInfo[] = []; 402 403 addChildApis(childApis: BasicApiInfo[]): void { 404 this.childApis.push(...childApis); 405 } 406 407 addChildApi(childApi: BasicApiInfo): void { 408 this.childApis.push(childApi); 409 } 410 411 getChildApis(): BasicApiInfo[] { 412 return this.childApis; 413 } 414} 415 416/** 417 * 属性会包含declare const定义的节点 418 */ 419export class PropertyInfo extends ApiInfo { 420 type: string[] = []; // 属性的类型,数组是由于可能为联合类型 421 isReadOnly: boolean = false; // 属性是否为只读 422 isRequired: boolean = false; // 属性是否为必选 423 isStatic: boolean = false; // 属性是否为静态 424 typeKind: ts.SyntaxKind = -1; //type类型的kind值 425 426 addType(type: string[]): void { 427 this.type.push(...type); 428 } 429 430 getType(): string[] { 431 return this.type; 432 } 433 434 setIsReadOnly(isReadOnly: boolean): void { 435 this.isReadOnly = isReadOnly; 436 } 437 438 getIsReadOnly(): boolean { 439 return this.isReadOnly; 440 } 441 442 setIsRequired(isRequired: boolean): void { 443 this.isRequired = isRequired; 444 } 445 446 getIsRequired(): boolean { 447 return this.isRequired; 448 } 449 450 setIsStatic(isStatic: boolean): void { 451 this.isStatic = isStatic; 452 } 453 454 getIsStatic(): boolean { 455 return this.isStatic; 456 } 457 458 setTypeKind(typeKind: ts.SyntaxKind): void { 459 this.typeKind = typeKind; 460 } 461 462 getTypeKind(): ts.SyntaxKind { 463 return this.typeKind; 464 } 465} 466 467export class ConstantInfo extends ApiInfo { 468 value: string = ''; // 常量的取值 469 470 setValue(value: string): void { 471 this.value = value; 472 } 473 474 getValue(): string { 475 return this.value; 476 } 477} 478 479/** 480 * 使用type关键字定义的节点,归为自定义类型的范畴 481 */ 482export class TypeAliasInfo extends ApiInfo { 483 type: string[] = []; // type定义的类型 484 typeName: TypeAliasType = '' as TypeAliasType; //type的类型 485 486 addType(type: string[]): void { 487 this.type.push(...type); 488 } 489 490 getType(): string[] { 491 return this.type; 492 } 493 494 setTypeName(typeName: string): TypeAliasInfo { 495 this.typeName = typeName as TypeAliasType; 496 return this; 497 } 498 499 getTypeName(): string { 500 return this.typeName; 501 } 502} 503 504export class EnumValueInfo extends ApiInfo { 505 value: string = ''; // 枚举值 506 507 setValue(value: string): void { 508 this.value = value; 509 } 510 511 getValue(): string { 512 return this.value; 513 } 514} 515 516export class MethodInfo extends ApiInfo { 517 callForm: string = ''; // 方法的调用形式 518 params: ParamInfo[] = []; // 方法的参数列表 519 returnValue: string[] = []; // 方法的返回值类型 520 isStatic: boolean = false; // 方法是否是静态 521 sync: string = ''; //同步函数标志 522 returnValueType: ts.SyntaxKind = -1; 523 524 setCallForm(callForm: string): void { 525 this.callForm = callForm; 526 } 527 528 getCallForm(): string { 529 return this.callForm; 530 } 531 532 addParam(paramInfo: ParamInfo): void { 533 this.params.push(paramInfo); 534 } 535 536 getParams(): ParamInfo[] { 537 return this.params; 538 } 539 540 setReturnValue(returnValue: string[]): void { 541 this.returnValue.push(...returnValue); 542 } 543 544 getReturnValue(): string[] { 545 return this.returnValue; 546 } 547 548 setReturnValueType(returnValueType: ts.SyntaxKind): void { 549 this.returnValueType = returnValueType; 550 } 551 552 getReturnValueType(): ts.SyntaxKind { 553 return this.returnValueType; 554 } 555 556 setIsStatic(isStatic: boolean): void { 557 this.isStatic = isStatic; 558 } 559 560 getIsStatic(): boolean { 561 return this.isStatic; 562 } 563 564 setSync(sync: string): void { 565 this.sync = sync; 566 } 567 568 getSync(): string { 569 return this.sync; 570 } 571} 572 573export class ParamInfo { 574 apiType: string = ''; // api的类型为方法参数 575 apiName: string = ''; // 参数名 576 paramType: ts.SyntaxKind = -1; // 参数类型的kind 577 type: string[] = []; // 参数的类型 578 isRequired: boolean = false; // 参数是否必选 579 definedText: string = ''; 580 581 constructor(apiType: string) { 582 this.apiType = apiType; 583 } 584 585 getApiType(): string { 586 return this.apiType; 587 } 588 589 setApiName(apiName: string) { 590 this.apiName = apiName; 591 } 592 593 getApiName(): string { 594 return this.apiName; 595 } 596 597 setType(type: string[]): void { 598 this.type.push(...type); 599 } 600 601 getParamType(): ts.SyntaxKind { 602 return this.paramType; 603 } 604 605 setParamType(paramType: ts.SyntaxKind): void { 606 this.paramType = paramType; 607 } 608 609 getType(): string[] { 610 return this.type; 611 } 612 613 setIsRequired(isRequired: boolean): void { 614 this.isRequired = isRequired; 615 } 616 617 getIsRequired(): boolean { 618 return this.isRequired; 619 } 620 621 setDefinedText(definedText: string): void { 622 this.definedText = definedText; 623 } 624 625 getDefinedText(): string { 626 return this.definedText; 627 } 628} 629 630export type ExportImportValue = { key: string; value: string }; 631export interface NodeProcessorInterface { 632 (node: ts.Node, parentApiInfo: BasicApiInfo): BasicApiInfo; 633} 634 635export type PropertyNode = ts.PropertyDeclaration | ts.PropertySignature; 636 637export interface ModifierProcessorInterface { 638 (propertyInfo: BasicApiInfo): void; 639} 640 641/** 642 * ts中所有方法节点 643 */ 644export type MethodType = 645 | ts.MethodDeclaration 646 | ts.MethodSignature 647 | ts.FunctionDeclaration 648 | ts.CallSignatureDeclaration 649 | ts.ConstructorDeclaration 650 | ts.ConstructSignatureDeclaration; 651 652/** 653 * 拥有子节点的class,处理数据时需要addChildApi,获取数据时可以getChildApis 654 */ 655export type ContainerApiInfo = NamespaceInfo | ClassInfo | InterfaceInfo | EnumInfo | ModuleInfo | StructInfo; 656 657/** 658 * 将节点强制转换为ContainerApiInfo节点时需要根据ApiType来判断哪些apiInfo节点有childApi 659 */ 660export const containerApiTypes: Set<string> = new Set([ 661 ApiType.NAMESPACE, 662 ApiType.CLASS, 663 ApiType.INTERFACE, 664 ApiType.ENUM, 665 ApiType.MODULE, 666 ApiType.STRUCT, 667]); 668 669/** 670 * 不存在jsdoc信息的节点 671 */ 672export const notJsDocApiTypes: Set<string> = new Set([ 673 ApiType.SOURCE_FILE, 674 ApiType.IMPORT, 675 ApiType.EXPORT, 676 ApiType.EXPORT_DEFAULT, 677 ApiType.MODULE, 678 ApiType.REFERENCE_FILE, 679]); 680