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};