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