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 18/** 19 * 流程处理结果, code值参考 constant/Code 20 */ 21export interface ProcessResult { 22 code: number, 23 content: string; 24} 25 26export interface ISourceCodeProcessor { 27 28 /** 29 * 处理源码的方法,输入原始代码,输出处理后的源码。 30 * 31 * @param content 32 */ 33 process(context: Context, content: string): Promise<ProcessResult>; 34} 35 36/** 37 * 全局的配置选项。 38 */ 39export class Options { 40 scriptTarget: ts.ScriptTarget = ts.ScriptTarget.ES2017; 41 42 /** 43 * prettier插件配置项 44 */ 45 formaterOption = { 46 47 /** 48 * 解析器 49 */ 50 parser: 'typescript', 51 52 /** 53 * 单引号 54 */ 55 singleQuote: true, 56 57 /** 58 * 代码行最大宽度 59 */ 60 printWidth: 120, 61 62 /** 63 * 缩进的空格数 64 */ 65 tabWidth: 2, 66 67 /** 68 * 末尾逗号 'es5'|'none'|'all' 69 * es5 默认值,对象,数组末尾有. TS 中的类型参数末尾没有 70 * none 没有末尾逗号 71 * all 合法的位置都会出现 72 */ 73 trailingComma: 'none', 74 75 /** 76 * {foo: bar} - false 77 * { foo: bar } - true 78 */ 79 bracketSpacing: true, 80 81 /** 82 * 表达式后的分号 83 */ 84 semi: true, 85 86 /** 87 * 对象属性的引号 88 * 'as-needed': 需要时添加 89 * 'consistent': 有一个属性需要添加时,所有都添加 90 * 'preserve': 保留原始 91 */ 92 quoteProps: 'as-needed' 93 }; 94 95 printerOptions = { 96 omitTrailingSemicolon: false, 97 removeComments: false, 98 preserveSourceNewlines: true 99 }; 100 101 commentOptions = { 102 emptyLineUnderDescrition: true 103 }; 104 splitUnionTypeApi: boolean = false; 105 workingBranch: string = 'master'; 106 isTest: boolean = false; 107} 108 109 110/** 111 * 112 * 上下文对象 113 * 114 */ 115export interface Context { 116 117 /** 118 * 设置原始文件节点信息对象,仅供预处理时调用 119 * 120 * @param rawInfo 121 */ 122 setRawSourceInfo(rawInfo: rawInfo.RawSourceCodeInfo): void; 123 124 /** 125 * 获取原始文件节点信息,用于查询原始文本位置 126 */ 127 getRawSourceCodeInfo(): rawInfo.RawSourceCodeInfo; 128 129 /** 130 * 获取日志管理器 131 */ 132 getLogReporter(): LogReporter; 133 134 /** 135 * 设置日志管理器 136 */ 137 setLogReporter(logReporter: LogReporter): void; 138 139 /** 140 * 获取整改后的d.ts文件路径 141 */ 142 getOutputFile(): string; 143 144 /** 145 * 获取待整改的d.ts文件路径 146 */ 147 getInputFile(): string; 148 149 /** 150 * 获取d.ts AST 解析器 151 * 152 * @param code 153 */ 154 getSourceParser(code: string): sourceParser.SourceCodeParser; 155 156 /** 157 * 获取全局配置对象 158 */ 159 getOptions(): Options; 160} 161 162export namespace rawInfo { 163 164 /** 165 * 原始文件信息,包含带注释的所有AST节点信息 166 */ 167 export abstract class RawSourceCodeInfo { 168 rawCode: string; 169 170 constructor(code: string) { 171 this.rawCode = code; 172 } 173 174 abstract findRawNodeInfo(node: ts.Node): RawNodeInfo | undefined; 175 } 176 177 178 /** 179 * 原始文件AST节点信息 180 * 181 */ 182 export interface RawNodeInfo { 183 184 /** 185 * 行号 186 */ 187 line: number; 188 189 /** 190 * 所在行的第几个字符 191 */ 192 character: number; 193 194 /** 195 * Ast节点对象 196 */ 197 astNode: ts.Node; 198 } 199 200} 201 202 203/** 204 * 注释相关的命名空间 205 */ 206export namespace comment { 207 208 /** 209 * 描述注释及关联的Ast节点 210 */ 211 export interface CommentNode { 212 commentInfos?: CommentInfo[]; 213 214 astNode?: ts.Node; 215 216 parentNode?: CommentNode; 217 } 218 219 220 /** 221 * 注释信息 222 */ 223 export interface CommentInfo { 224 225 /** 226 * 原始注释文本 227 */ 228 text: string; 229 230 /** 231 * 是否为多行注释 232 */ 233 isMultiLine: boolean; 234 235 /** 236 * true为头注释,false为未注释 237 */ 238 isLeading: boolean; 239 240 /** 241 * 注释描述 242 */ 243 description: string; 244 245 /** 246 * 注释标签列表 247 */ 248 commentTags: Array<CommentTag>; 249 250 /** 251 * 结构化的注释对象 252 */ 253 parsedComment: comment.ParsedComment | undefined; 254 255 /** 256 * 注释起始位置 257 */ 258 pos: number; 259 260 /** 261 * 注释结束位置 262 */ 263 end: number; 264 265 /** 266 * 是否忽略此注释 267 */ 268 ignore: boolean; 269 270 /** 271 * 是否是api注释 272 */ 273 isApiComment: boolean, 274 275 /** 276 * 是否为特殊日志。例如,为了增加空行而添加的特殊单行日志。 277 */ 278 isInstruct: boolean; 279 } 280 281 /** 282 * 注释被拆分为以下部分: 283 * |start|delimiter|postDelimiter|tag|postTag|name|postName|type|postType|description|end\ 284 */ 285 export interface CommentToken { 286 287 /** 288 * 注释每行起始字符 289 */ 290 start: string; 291 292 /** 293 * 注释行开始定界符 294 */ 295 delimiter: string; 296 297 /** 298 * 定界符之后的字符 299 */ 300 postDelimiter: string; 301 302 /** 303 * 标签 304 */ 305 tag: string; 306 307 /** 308 * 标签之后的字符 309 */ 310 postTag: string; 311 312 /** 313 * 标签名称 314 */ 315 name: string; 316 317 /** 318 * 标签后的字符 319 */ 320 postName: string; 321 322 /** 323 * 类型 324 */ 325 type: string; 326 327 /** 328 * 类型后的字符 329 */ 330 postType: string; 331 332 /** 333 * 描述 334 */ 335 description: string; 336 337 /** 338 * 结束字符 339 */ 340 end: string; 341 342 /** 343 * 行结束字符 344 */ 345 lineEnd: string; 346 } 347 348 export interface CommentSource { 349 350 /** 351 * 行号 352 */ 353 number: number; 354 355 /** 356 * 原始注释行 357 */ 358 source: string; 359 360 /** 361 * 注释被拆分后的对象 362 */ 363 tokens: CommentToken; 364 } 365 366 367 export interface CommentTag { 368 369 /** 370 * 注释标签,例如 @param 371 */ 372 tag: string; 373 374 /** 375 * 标签名称, 例如 @param name 376 */ 377 name: string; 378 379 /** 380 * 类型, 例如 @param { type } name 381 */ 382 type: string; 383 384 /** 385 * 是否可选 386 */ 387 optional: boolean; 388 389 /** 390 * 描述 391 */ 392 description: string; 393 394 /** 395 * 默认值 396 */ 397 defaultValue?: string; 398 399 /** 400 * 原始注释内容 401 */ 402 source: string; 403 404 /** 405 * 行号 406 */ 407 lineNumber: number; 408 409 /** 410 * tag 的描述可能有多行, 首行包含tag信息,其余包含tag的描述信息。 411 */ 412 tokenSource: Array<comment.CommentSource>; 413 } 414 415 /** 416 * 未整改的d.ts文件中的注释信息。 417 */ 418 export interface RawCommentInfo { 419 start: number; 420 end: number; 421 comment: string; 422 astNode: ts.Node 423 } 424 425 export enum CommentLocationKind { 426 427 /** 428 * 头注释 429 */ 430 LEADING = 0, 431 432 /** 433 * 尾注释 434 */ 435 TRAILING = 1 436 } 437} 438 439/** 440 * comment-parser 解析后的数据结构 441 */ 442export namespace comment { 443 444 /** 445 * 原始注释信息 446 */ 447 export interface Source { 448 449 /** 行号 */ 450 number: number; 451 452 /** 原始文本内容 */ 453 source: string; 454 455 /** 注释拆分 */ 456 tokens: Token; 457 } 458 459 /** 460 * 注释标签 461 */ 462 export interface Tag { 463 464 /** 465 * 标签名如 @since tag = since 466 */ 467 tag: string; 468 469 /** 470 * 标签名,如 @since 9, name = 9 471 */ 472 name: string; 473 474 /** 475 * 类型, 例如 @throws { BusinessErro }, type = BusinessError 476 */ 477 type: string; 478 479 /** 480 * 是否可选,例如 @param [encoding = 'utf-8'], optional = true 481 */ 482 optional: boolean; 483 484 /** 485 * 标签的描述,例如 @throws { BusinessError } 401 - if the input parameters are invalid 486 * description = - if the input parameters are invalid 487 */ 488 description: string; 489 490 /** 491 * 标签对应的原始注释信息。 492 */ 493 source: Source[]; 494 } 495 496 /** 497 * 注释的每行被拆分成Token的每个字段。 498 */ 499 export interface Token { 500 501 /** 502 * 起始字符,例如本行注释的起始符号为' ',5个空格 503 */ 504 start: string; 505 506 /** 507 * 定界符,例如本行注释的定界符为'*' 508 */ 509 delimiter: string; 510 511 /** 512 * 紧跟定界符之后的字符,一般为一个空格 513 */ 514 postDelimiter: string; 515 516 /** 517 * 标签,例如 @since 518 */ 519 tag: string; 520 521 /** 522 * 紧跟标签之后的符号, 一般是空格 523 */ 524 postTag: string; 525 526 /** 527 * 标签名称例如 @since 9, name = 9 528 * @throws { BusinessError } 401, name = 401 529 */ 530 name: string; 531 532 /** 533 * 紧跟 name 的字符,一般为空格 534 */ 535 postName: string; 536 537 /** 538 * 类型例如@param { string }, type = { string } 539 */ 540 type: string; 541 542 /** 543 * 紧跟类型的字符,一般为空格 544 */ 545 postType: string; 546 547 /** 548 * 描述信息,例如 @throws { BusinessError } 401 - if the input parameters are invalid. 549 * description = - if the input parameters are invalid. 550 */ 551 description: string; 552 553 /** 554 * 注释的结束符 555 */ 556 end: string; 557 558 /** 559 * 行的结束符 560 */ 561 lineEnd: string; 562 } 563 564 /** 565 * comment-parser 解析后最顶层的数据结构 566 */ 567 export interface ParsedComment { 568 569 /** 570 * 注释块中的描述信息 571 */ 572 description: string; 573 574 /** 575 * 注释块中的标签集合 576 */ 577 tags: Tag[]; 578 579 /** 580 * 注释块的所有原始信息集合。 581 */ 582 source: Source[]; 583 } 584} 585 586 587/** 588 * 日志处理器 589 */ 590export interface LogReporter { 591 592 /** 593 * 添加校验结果 594 * 595 * @param checkResult 校验结果对象 596 */ 597 addCheckResult(checkResult: CheckLogResult): void 598 599 /** 600 * 添加整改结果 601 * 602 * @param modifyResult 整改结果对象 603 */ 604 addModifyResult(modifyResult: ModifyLogResult): void 605 606 /** 607 * 获取校验结果映射表 608 */ 609 getCheckResultMap(): Map<string, string>; 610 611 /** 612 * 获取整改结果映射表 613 */ 614 getModifyResultMap(): Map<string, string>; 615 616 /** 617 * 将校验结果报告落盘 618 * @param path 报告落盘路径 619 */ 620 writeCheckResults(path: string): Promise<void>; 621 622 /** 623 * 将整改结果报告落盘 624 * @param path 报告落盘路径 625 */ 626 writeModifyResults(path: string): Promise<void>; 627 628 /** 629 * 将结果报告落盘 630 * @param path 报告落盘路径 631 */ 632 writeAllResults(path: string): Promise<void>; 633 634 /** 635 * 传入writer对象 636 * 637 * @param writer writer对象 638 */ 639 setWriter(writer: LogWriter): void; 640} 641 642/** 643 * 校验结果对象定义 644 * 645 * TODO 646 */ 647export interface CheckLogResult { 648 // 文件地址(行号,列号) 649 filePath?: string; 650 // 接口名称 651 apiName: string; 652 // 接口内容 653 apiContent?: string; 654 // 异常类型 655 errorType: string; 656 // 告警信息 657 errorInfo: string; 658 // 版本号 659 version: string; 660 // 模块名称 661 moduleName: string; 662} 663 664/** 665 * 整改结果对象定义 666 * 667 * TODO 668 */ 669export interface ModifyLogResult { 670 // 文件地址(行号,列号) 671 filePath?: string; 672 // 接口名称 673 apiName?: string; 674 // 接口内容 675 apiContent?: string; 676 // 整改类型 677 modifyType: string; 678 // 版本号 679 version: string; 680 // 描述 681 description: string; 682 // 模块名称 683 moduleName?: string; 684} 685 686/** 687 * 结果日志输出接口 688 */ 689export interface LogWriter { 690 691 /** 692 * 693 * @param checkResults 校验结果集 694 * @param modifyResults 整改结果集 695 * @param path 报告落盘路径 696 */ 697 writeResults(checkResults: Array<CheckLogResult> | undefined, modifyResults: Array<ModifyLogResult> | undefined, path: string): Promise<void>; 698} 699 700/** 701 * JSDoc整改类型枚举类 702 */ 703export enum JSDocModifyType { 704 EVENT_SUBSCRIPTION_SPLITTION = '事件订阅api拆分', 705 AYYNCHRONOUS_FUNCTION_JSDOC_COPY = '同名异步函数共用JSDoc拆分', 706 MISSING_TAG_COMPLETION = '缺失标签补全', 707 TAG_ORDER_AJUSTMENT = '标签顺序调整' 708} 709 710/** 711 * JSDoc校验异常类型枚举类 712 */ 713export enum JSDocCheckErrorType { 714 INCOMPLETE_TAG = '无法补全的标签', 715 API_FORMAT_ERROR = 'api格式错误', 716 TAG_VALUE_ERROR = '标签使用错误', 717 PARAM_DESCRIPTION_WARNING = '缺失param标签描述信息' 718} 719 720export namespace sourceParser { 721 722 /** 723 * 源码解析器 724 */ 725 export abstract class SourceCodeParser { 726 content: string; 727 constructor(sourceCode: string) { 728 this.content = sourceCode; 729 } 730 731 /** 732 * 节点树修改方法,新节点通过 {@code ITransformCallback#onTransformNode} 返回 733 * 734 * @param callback 735 */ 736 abstract transform(callback: ITransformCallback): ts.SourceFile | undefined; 737 738 /** 739 * 遍历所有待注释的节点,解析对应注释并调用 INodeVisitorCallback#onVisitNode 740 * 用于校验、注释整改。 741 * 742 * @param callback 743 */ 744 abstract visitEachNodeComment(callback: INodeVisitorCallback, onlyVisitHasComment?: boolean): ts.SourceFile | undefined; 745 746 /** 747 * 打印源代码 748 * 749 * @param sourceFile 750 */ 751 abstract printSourceFile(sourceFile: ts.SourceFile): string; 752 753 /** 754 * 创建ts.SourceFile对象。对于非TS代码文件也可以被解析成改对象。 755 * 756 * @param content 文件内容 757 * @param name 文件名 758 */ 759 abstract createSourceFile(content: string, name?: string): ts.SourceFile | undefined; 760 } 761 762 /** 763 * AST 节点修改回调接口 764 */ 765 export interface ITransformCallback { 766 767 /** 768 * 入参为原始AST节点,自定义业务功能,并返回新的AST节点。 769 * 770 * @param node 新的节点对象,若不创建新节点则返回undefined 771 */ 772 onTransformNode(node: comment.CommentNode): ts.Node | undefined; 773 } 774 775 776 /** 777 * 节点遍历回调接口 778 */ 779 export interface INodeVisitorCallback { 780 onVisitNode(node: comment.CommentNode): void; 781 } 782} 783 784/** 785 * 整改工具的API 786 */ 787export interface IJSDocModifier { 788 start(): Promise<void>; 789} 790 791interface OrderResultInfo { 792 checkResult: boolean; 793 errorInfo: string; 794} 795 796export interface IllegalTagsInfo { 797 checkResult: boolean; 798 errorInfo: string; 799 index: number; 800} 801 802/** 803 * 单个节点检查返回格式 804 */ 805export interface JsDocCheckResult { 806 orderResult: OrderResultInfo; 807 illegalTags: IllegalTagsInfo[]; 808 missingTags: string[]; 809} 810 811export interface JsDocModificationInterface { 812 (node: comment.CommentNode, commentInfo: comment.CommentInfo, tagName: string, context: Context | undefined): boolean; 813} 814 815/** 816 * 错误告警 817 */ 818export enum ErrorInfo { 819 PARAM_FORAMT_ERROR = '@param标签无法补全, 请自行确认当前api第[$$]个参数是否为基础类型或定义类型.', 820 PARAM_FORAMT_DESCRIPTION_ERROR = '请自行添加第[$$]个参数的描述信息.', 821 COMPLETE_TAG_INFORMATION = '补全第[$$]段JSDoc的@$$标签.', 822 COMPLETE_INHERIT_TAG_INFORMATION = '第[$$]段JSDoc从父类继承@$$标签.', 823 COMPLETE_INHERIT_PERMISSION_TAG_ERROR = '第[$$]段JSDoc父类存在@$$标签, 请自行确认并补全相同标签.', 824 COMPLETE_TAG_ERROR = '第[$$]段JSDoc缺少@$$标签, 请自行确认并修改.', 825 COMPLETE_INTERFACE_TAG_ERROR = '第[$$]段JSDoc缺少@interface或@typedef标签, 请自行确认并补全@interface或@typedef标签.', 826 MODIFY_TAG_ORDER_INFORMATION = '第[$$]段JSDoc标签顺序调整.', 827 JSDOC_FORMAT_ERROR = 'JSDoc格式错误, 请检查.', 828 JSDOC_ILLEGAL_ERROR = '第[$$]段JSDoc校验失败: \n', 829 EVENT_SUBSCRIPTION_SPLITTION = '对事件订阅函数[$$]进行了拆分.', 830 AYYNCHRONOUS_FUNCTION_JSDOC_COPY = '对异步函数[$$]进行了JSDoc复制.' 831} 832 833/** 834 * 方法或函数节点联合类型定义 835 */ 836export type MethodNodeType = ts.FunctionDeclaration | ts.MethodDeclaration | ts.MethodSignature; 837 838export interface ApiSplitProcessorInterface { 839 (node: ts.Node, context: Context | undefined): ts.Node | undefined; 840} 841 842/** 843 * 注释信息 844 */ 845export interface CommentData { 846 tag: string, 847 name: string, 848 type: string, 849 optional: boolean, 850 description: string, 851 source: Array<comment.CommentSource>, 852 default: string 853}