• 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
16const ts = require('typescript');
17
18/**
19 * 添加API信息到 apiMap
20 *
21 * @param {Map} apiMap
22 * @param {ApiDigestInfo} apiDigestInfo
23 */
24function addApiDigestInfo(apiMap, apiDigestInfo) {
25  addApiInfo(apiMap, apiDigestInfo.getPackageName(),
26    apiDigestInfo.getClassName(), apiDigestInfo.getApiName(),
27    apiDigestInfo.getApiSignature(), apiDigestInfo);
28}
29
30/**
31 * 将API摘要信息如以下数据格式保存
32 * @example
33 * { packageName : Map }
34 *                  |
35 *      { className : { type: ApiDigestInfo, children: Map } }
36 *                                                      |
37 *                                             { apiName : Map }
38 *                                                          |
39 *                                                { signature : ApiDigestInfo[] }
40 *
41 * @param {Map} apiMap API 摘要集合
42 * @param {string} packageName 包名
43 * @param {string} className 类型名
44 * @param {string} apiSignature api节点签名
45 * @param {ApiDigestInfo} api api摘要信息
46 */
47function addApiInfo(apiMap, packageName, className, apiName, apiSignature, api) {
48  let dtsMap = apiMap.get(packageName);
49  // 集合中没有该文件数据
50  if (!dtsMap) {
51    dtsMap = new Map();
52    apiMap.set(packageName, dtsMap);
53  }
54  // 类数据
55  let classApi = dtsMap.get(className);
56  if (!classApi) {
57    classApi = {
58      children: new Map(),
59    };
60    dtsMap.set(className, classApi);
61  }
62
63  if (isTypeDeclaration(api) && !classApi.type) {
64    classApi.type = api;
65    return;
66  }
67
68  // api 映射表
69  let apiNameMap = classApi.children.get(apiName);
70  if (!apiNameMap) {
71    apiNameMap = new Map();
72    classApi.children.set(apiName, apiNameMap);
73  }
74
75  let apiArray = apiNameMap.get(apiSignature);
76  if (!apiArray) {
77    apiArray = [];
78    apiNameMap.set(apiSignature, apiArray);
79  }
80  apiArray.push(api);
81}
82
83function isTypeDeclaration(api) {
84  const types = [ApiType.ClassType.code, ApiType.InterfaceType.code, ApiType.EnumType.code, ApiType.NamespaceType.code, ApiType.SourceFile.code];
85  return types.includes(api.getApiType().code);
86}
87
88/**
89 * 获取AST节点的签名信息, 它由所有子节点非空字符串拼接而成,具有唯一性。
90 * 类型的签名由 包名+类型名来确认唯一性。
91 *
92 * @param {ts.Node} astNode
93 * @param {string} packageName
94 * @param {string} className
95 * @returns {string}
96 */
97function getNodeSignature(astNode, packageName, className) {
98  if (ts.isInterfaceDeclaration(astNode) || ts.isClassDeclaration(astNode) ||
99    ts.isModuleDeclaration(astNode) || ts.isEnumDeclaration(astNode) || ts.isSourceFile(astNode)) {
100    return `${packageName}#${className}`;
101  }
102  let signature = '';
103  if (astNode.getChildCount() > 0) {
104    astNode.forEachChild((childNode) => {
105      signature += `#${getNodeSignature(childNode)}`;
106    });
107  } else {
108    signature = ts.isIdentifier(astNode) ? astNode.text.replace(/\'|\"/g, '') : astNode.getText().replace(/\'|\"/g, '');
109  }
110  return signature;
111}
112
113class ApiDigestInfo {
114  constructor() {
115  }
116
117  /**
118   * 设置包名,包名为d.ts文件与SDK根目录的相对路径
119   *
120   * @param {string} packageName
121   * @returns {Object}
122   */
123  setPackageName(packageName) {
124    this.packageName = packageName;
125    return this;
126  }
127
128  getPackageName() {
129    return this.packageName;
130  }
131
132  /**
133   * 类型名称,如 class, enum, interface, namespace 名字
134   *
135   * @param {string} className
136   * @returns {Object}
137   */
138  setClassName(className) {
139    this.className = className;
140    return this;
141  }
142
143  getClassName() {
144    if (this.className) {
145      return this.className;
146    }
147    let parentInfo = this.parent;
148    while (parentInfo) {
149      if (!parentInfo.className) {
150        parentInfo = parentInfo.parent;
151      } else {
152        return parentInfo.className;
153      }
154    }
155    return '';
156  }
157
158  /**
159   * API的类型,如方法,属性,枚举等
160   *
161   * @param {ApiType} apiType
162   * @returns {Object}
163   */
164  setApiType(apiType) {
165    this.apiType = apiType;
166    return this;
167  }
168
169  getApiType() {
170    return this.apiType;
171  }
172
173  /**
174   * API原始的文本
175   *
176   * @param {string} rawText
177   * @returns {Object}
178   */
179  setRawText(rawText) {
180    this.rawText = rawText;
181    return this;
182  }
183
184  getRawText() {
185    return this.rawText;
186  }
187
188  /**
189   * API所属的d.ts文件路径
190   *
191   * @param {string} path
192   * @returns {Object}
193   */
194  setPath(path) {
195    this.path = path;
196    return this;
197  }
198
199  getPath() {
200    return this.path;
201  }
202
203
204
205  /**
206   * API AST节点对象
207   *
208   * @param {ts.Node} node
209   * @returns {Object}
210   */
211  setAstNode(node) {
212    this.node = node;
213    return this;
214  }
215
216  getAstNode() {
217    return this.node;
218  }
219
220  /**
221   * API的JSDoc信息
222   *
223   * @param {Object} jsdoc
224   * @returns {Object}
225   */
226  setJSdoc(jsdoc) {
227    this.jsdoc = jsdoc;
228    return this;
229  }
230
231  setJSDocTagItem(jsdocTagItem) {
232    this.jsdocTagItem = jsdocTagItem;
233  }
234
235  getJSDocTagItem() {
236    return this.jsdocTagItem;
237  }
238
239  /**
240   * AST节点的签名信息,可以确保在一个模块中的唯一性
241   *
242   * @param {ts.Node} astNode
243   * @param {string} packageName
244   * @param {string} className
245   * @returns {Object}
246   */
247  setApiSignature(astNode, packageName, className) {
248    this.signature = getNodeSignature(astNode, packageName, className);
249    return this;
250  }
251
252  getApiSignature() {
253    return this.signature;
254  }
255
256  setApiName(apiName) {
257    this.apiName = apiName;
258    return this;
259  }
260
261  getApiName() {
262    return this.apiName;
263  }
264
265  /**
266   * API 父节点摘要信息,可以确认某个节点的空间位置。
267   *
268   * @param {Object} digestInfo
269   * @returns {Object}
270   */
271  setParent(digestInfo) {
272    this.parent = digestInfo;
273    return this;
274  }
275
276  getParent() {
277    return this.parent;
278  }
279
280  setSyscap(syscap) {
281    this.syscap = syscap;
282    return this;
283  }
284}
285
286const ApiType = {
287  EnumType: { name: '枚举', code: 0 },
288  EnumMember: { name: '枚举成员', code: 1 },
289  ClassType: { name: '类', code: 2 },
290  ClassProperty: { name: '类属性', code: 3 },
291  ClassMethod: { name: '类方法', code: 4 },
292  InterfaceType: { name: '接口', code: 5 },
293  InterfaceMethod: { name: '接口方法', code: 6 },
294  InterfaceProperty: { name: '接口属性', code: 7 },
295  ExportType: { name: '类型导出', code: 8 },
296  FunctionType: { name: '方法', code: 9 },
297  NamespaceType: { name: '命名空间', code: 10 },
298  TypeAliasDeclaration: { name: '类型成员', code: 11 },
299  Constructor: { name: '构造器', code: 12 },
300  CallSignature: { name: '类方法', code: 13 },
301  SourceFile: { name: 'sourfile', code: 14 }
302};
303
304exports.ApiDigestInfo = ApiDigestInfo;
305exports.ApiType = ApiType;
306exports.apiDataHelper = {
307  addApiInfo: addApiInfo,
308  addApiDigestInfo: addApiDigestInfo,
309  getNodeSignature: getNodeSignature,
310};