• 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
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