• 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  /**
129   * 获取包名
130   * @returns {string}
131   */
132  getPackageName() {
133    return this.packageName;
134  }
135
136  /**
137   * 类型名称,如 class, enum, interface, namespace 名字
138   *
139   * @param {string} className
140   * @returns {Object}
141   */
142  setClassName(className) {
143    this.className = className;
144    return this;
145  }
146
147  /**
148   * 获取classs Name
149   * @returns {string|string|any|string}
150   */
151  getClassName() {
152    if (this.className) {
153      return this.className;
154    }
155    let parentInfo = this.parent;
156    while (parentInfo) {
157      if (!parentInfo.className) {
158        parentInfo = parentInfo.parent;
159      } else {
160        return parentInfo.className;
161      }
162    }
163    return '';
164  }
165
166  /**
167   * API的类型,如方法,属性,枚举等
168   *
169   * @param {ApiType} apiType
170   * @returns {Object}
171   */
172  setApiType(apiType) {
173    this.apiType = apiType;
174    return this;
175  }
176
177  getApiType() {
178    return this.apiType;
179  }
180
181  /**
182   * API原始的文本
183   *
184   * @param {string} rawText
185   * @returns {Object}
186   */
187  setRawText(rawText) {
188    this.rawText = rawText;
189    return this;
190  }
191
192  /**
193   * 获取原始文本
194   * @returns {string}
195   */
196  getRawText() {
197    return this.rawText;
198  }
199
200  /**
201   * API所属的d.ts文件路径
202   *
203   * @param {string} path
204   * @returns {Object}
205   */
206  setPath(path) {
207    this.path = path;
208    return this;
209  }
210
211  /**
212   * 获取路径
213   * @returns {string}
214   */
215  getPath() {
216    return this.path;
217  }
218
219
220
221  /**
222   * API AST节点对象
223   *
224   * @param {ts.Node} node
225   * @returns {Object}
226   */
227  setAstNode(node) {
228    this.node = node;
229    return this;
230  }
231
232  /**
233   * 获取node
234   * @returns {collaborationEditObject.Node}
235   */
236  getAstNode() {
237    return this.node;
238  }
239
240  /**
241   * API的JSDoc信息
242   *
243   * @param {Object} jsdoc
244   * @returns {Object}
245   */
246  setJSdoc(jsdoc) {
247    this.jsdoc = jsdoc;
248    return this;
249  }
250
251  /**
252   * 设置tagItem
253   * @param jsdocTagItem
254   */
255  setJSDocTagItem(jsdocTagItem) {
256    this.jsdocTagItem = jsdocTagItem;
257  }
258
259  /**
260   * 获取tagItem
261   * @returns {*}
262   */
263  getJSDocTagItem() {
264    return this.jsdocTagItem;
265  }
266
267  /**
268   * AST节点的签名信息,可以确保在一个模块中的唯一性
269   *
270   * @param {ts.Node} astNode
271   * @param {string} packageName
272   * @param {string} className
273   * @returns {Object}
274   */
275  setApiSignature(astNode, packageName, className) {
276    this.signature = getNodeSignature(astNode, packageName, className);
277    return this;
278  }
279
280  /**
281   * 获取api签名
282   * @returns {string}
283   */
284  getApiSignature() {
285    return this.signature;
286  }
287
288  /**
289   * 设置API Name
290   * @param apiName
291   * @returns {ApiDigestInfo}
292   */
293  setApiName(apiName) {
294    this.apiName = apiName;
295    return this;
296  }
297
298  /**
299   * 获取API Name
300   * @returns {*}
301   */
302  getApiName() {
303    return this.apiName;
304  }
305
306  /**
307   * API 父节点摘要信息,可以确认某个节点的空间位置。
308   *
309   * @param {Object} digestInfo
310   * @returns {Object}
311   */
312  setParent(digestInfo) {
313    this.parent = digestInfo;
314    return this;
315  }
316
317  getParent() {
318    return this.parent;
319  }
320
321  /**
322   * 设置 syscap
323   * @param syscap
324   * @returns {ApiDigestInfo}
325   */
326  setSyscap(syscap) {
327    this.syscap = syscap;
328    return this;
329  }
330}
331
332const ApiType = {
333  EnumType: { name: '枚举', code: 0 },
334  EnumMember: { name: '枚举成员', code: 1 },
335  ClassType: { name: '类', code: 2 },
336  ClassProperty: { name: '类属性', code: 3 },
337  ClassMethod: { name: '类方法', code: 4 },
338  InterfaceType: { name: '接口', code: 5 },
339  InterfaceMethod: { name: '接口方法', code: 6 },
340  InterfaceProperty: { name: '接口属性', code: 7 },
341  ExportType: { name: '类型导出', code: 8 },
342  FunctionType: { name: '方法', code: 9 },
343  NamespaceType: { name: '命名空间', code: 10 },
344  TypeAliasDeclaration: { name: '类型成员', code: 11 },
345  Constructor: { name: '构造器', code: 12 },
346  CallSignature: { name: '类方法', code: 13 },
347  SourceFile: { name: 'sourfile', code: 14 }
348};
349
350exports.ApiDigestInfo = ApiDigestInfo;
351exports.ApiType = ApiType;
352exports.apiDataHelper = {
353  addApiInfo: addApiInfo,
354  addApiDigestInfo: addApiDigestInfo,
355  getNodeSignature: getNodeSignature,
356};