1/* 2* Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development 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*/ 15const re = require("../tools/re"); 16const { removeEmptyLine, checkOutBody, addUniqFunc2List } = require("../tools/tool"); 17const { analyzeFunction } = require("./function"); 18const { analyzeInterface, parseNotes } = require("./interface"); 19const { analyzeEnum } = require("./enum"); 20const { NapiLog } = require("../tools/NapiLog"); 21const { analyzeType, analyzeType2, analyzeType2Result } = require("./type"); 22const { NumberIncrease, EnumValueType, getLogErrInfo } = require("../tools/common"); 23 24function preProcessData(data) { 25 data = data.indexOf("//") < 0 ? data : parseNotes(data); 26 data = re.replaceAll(data, "\n{", "{"); 27 return data; 28} 29 30function getDataByResult(result) { 31 let data = null 32 if (result !== null) { 33 data = result 34 } 35 return data 36} 37 38/**namespace解析 */ 39function analyzeNamespace(data) { 40 let result = { 41 exports: [], 42 enum: [], 43 const: [], 44 type: [], 45 function: [], 46 interface: [], 47 class: [], 48 namespace: [], 49 callFunction: [], 50 } 51 while (data !== '\n') { 52 let oldData = data 53 data = removeEmptyLine(data) 54 let matchs = re.match(" *\n*", data) 55 data = preProcessData(data); 56 // 只剩下空格和回车时,解析完成 57 if (matchs && matchs.regs[0][1] === data.length) break 58 let parseEnumResult = parseEnum(matchs, data, result) 59 data = getDataByResult(parseEnumResult) 60 61 result = parseEnumType(result); 62 63 let parseInterResult = parseInterface(matchs, data, result) 64 data = getDataByResult(parseInterResult) 65 66 let parseFunctionResult = parseFunction(matchs, data, result) 67 data = getDataByResult(parseFunctionResult) 68 69 let parseTypeResult = parseType(matchs, data, result) 70 data = getDataByResult(parseTypeResult) 71 72 let parseClassResult = parseClass(matchs, data, result) 73 data = getDataByResult(parseClassResult) 74 75 let parseNamespaceResult = parseNamespace(matchs, data, result) 76 data = getDataByResult(parseNamespaceResult) 77 78 data = removeReg(matchs, data, result) 79 if (oldData === data) { 80 NapiLog.logError("解析Namespace失败"); 81 NapiLog.logError("[", data.substring(0, data.length > 128 ? 128 : data.length), "]"); 82 break; 83 } 84 } 85 return result 86} 87 88function parseEnumType(result) { 89 if (null === result) { 90 return null; 91 } 92 93 for (let i in result.enum) { 94 let enumm = result.enum[i] 95 96 // interface 匹配 97 for (let i in result.interface) { 98 let interf = result.interface[i] 99 if(!isValidValue(interf)) { 100 NapiLog.logError("parseEnumType interf is null!"); 101 return null; 102 } 103 104 // function 匹配 105 for (let j in interf.body.function) { 106 let func = interf.body.function[j]; 107 if(!isValidValue(func)) { 108 NapiLog.logError("parseEnumType func is null!"); 109 return null; 110 } 111 112 // 参数匹配 113 for (let k in func.value) { 114 let v = func.value[k]; 115 if(!isValidValue(v)) { 116 NapiLog.logError("parseEnumType func.value is null!"); 117 return null; 118 } 119 120 if (v.type === enumm.name) { 121 if (enumm.body.enumValueType === EnumValueType.ENUM_VALUE_TYPE_NUMBER) { 122 v.type = "NUMBER_TYPE_" + NumberIncrease.getAndIncrease(); 123 } else if (enumm.body.enumValueType === EnumValueType.ENUM_VALUE_TYPE_STRING) { 124 v.type = "string"; 125 } else { 126 NapiLog.logError("parseEnumType for interface function value is not support this type %s." 127 .format(enumm.body.enumValueType), getLogErrInfo()); 128 return null; 129 } 130 result.interface[i].body.function[j].value[k].type = v.type; 131 } 132 } 133 } 134 } 135 } 136 return result 137} 138 139function parseNamespace(matchs, data, result) { 140 matchs = re.match("(export )*namespace ([a-zA-Z0-9]+) ({)", data) 141 if (matchs) { 142 let namespaceName = re.getReg(data, matchs.regs[2]) 143 let namespaceBody = checkOutBody(data, matchs.regs[3][0], null, true) 144 result.namespace.push({ 145 name: namespaceName, 146 body: analyzeNamespace(namespaceBody) 147 }) 148 data = data.substring(matchs.regs[3][0] + namespaceBody.length + 2, data.length) 149 if (matchs.regs[1][0] !== -1) { 150 result.exports.push(namespaceName) 151 } 152 } 153 return data 154} 155 156function parseClass(matchs, data, result) { 157 matchs = re.match( 158 "(export )*class ([A-Za-z_0-9]+)(<T>)* *(extends [a-zA-Z_0-9, ]+)* *(implements [a-zA-Z_0-9, ]+)* *({)" 159 , data) 160 if (matchs) { 161 // class类型也解析成interface结构,该结构在后面生成C++代码时会按napi_define_class处理成C++的class 162 return createInterfaceData(matchs, data, result) 163 } 164 return data 165} 166 167function parseEnum(matchs, data, result) { 168 matchs = re.match("(export )*enum *([A-Za-z_0-9]+) *({)", data) 169 if (matchs !== null) { 170 let enumName = re.getReg(data, matchs.regs[2]); 171 let enumBody = checkOutBody(data, matchs.regs[3][0], null, null) 172 result.enum.push({ 173 name: enumName, 174 body: analyzeEnum(enumBody.substring(1, enumBody.length - 1)) 175 }) 176 data = data.substring(matchs.regs[3][0] + enumBody.length) 177 if (matchs.regs[1][0] !== -1) { 178 result.exports.push(enumName) 179 } 180 } 181 matchs = re.match("(export )*const ([A-Za-z_0-9]+) *[:=]{1} ([A-Za-z_0-9]+);", data) 182 if (matchs) { 183 let constName = re.getReg(data, matchs.regs[1]) 184 result.const.push({ 185 name: constName, 186 body: re.getReg(data, matchs.regs[2]) 187 }) 188 data = re.removeReg(data, matchs.regs[0]) 189 if (matchs.regs[1][0] !== -1) { 190 result.exports.push(constName) 191 } 192 } 193 return data 194} 195 196function isValidValue(value) { 197 if (value === null || value === undefined) { 198 return false; 199 } 200 return true; 201} 202 203function getTypeInfo(result, typeName, typeType, isEnum) { 204 if (!isValidValue(result) || !isValidValue(result.type)) { 205 NapiLog.logError("getTypeInfo: result or result.type is invalid!"); 206 } 207 result.type.push({ 208 name: typeName, 209 body: typeType, 210 isEnum: isEnum 211 }) 212} 213 214function parseType(matchs, data, result) { 215 matchs = re.match("(export )*type ([a-zA-Z]+) *= *([\\(\\):=a-zA-Z<> |]+);", data) 216 if (matchs) { 217 let typeName = re.getReg(data, matchs.regs[2]); 218 let typeType = re.getReg(data, matchs.regs[3]); 219 let index = typeType.indexOf("number") 220 if (index !== -1) { 221 typeType = typeType.replace("number", "NUMBER_TYPE_" + NumberIncrease.getAndIncrease()) 222 } 223 getTypeInfo(result, typeName, typeType, false); 224 data = re.removeReg(data, matchs.regs[0]) 225 if (matchs.regs[1][0] !== -1) { 226 result.exports.push(typeName) 227 } 228 } 229 230 matchs = re.match("(export )*type ([a-zA-Z]+) *= *([\\(\\):=a-zA-Z<> |\n']+);", data) 231 if (matchs) { 232 let typeName = re.getReg(data, matchs.regs[2]); 233 let typeBody = re.getReg(data, matchs.regs[3]); 234 235 getTypeInfo(result, typeName, analyzeType2(typeBody.substring(1, typeBody.length - 1)), true); 236 data = re.removeReg(data, matchs.regs[0]) 237 if (matchs.regs[1][0] !== -1) { 238 result.exports.push(typeName) 239 } 240 } 241 242 matchs = re.match("(export )*type ([a-zA-Z]+) *= *({)", data) 243 if (matchs) { 244 let typeName = re.getReg(data, matchs.regs[2]); 245 let typeBody = checkOutBody(data, matchs.regs[3][0], null, true) 246 if (typeBody === null) { 247 NapiLog.logError("ParseType typeBody is null!"); 248 } 249 let bodyObj = analyzeType(typeBody.substring(1, typeBody.length - 1), result.type) 250 getTypeInfo(result, typeName, bodyObj, false); 251 data = data.substring(matchs.regs[3][0] + typeBody.length + 2, data.length) 252 if (matchs.regs[1][0] !== -1) { 253 result.exports.push(typeName) 254 } 255 } 256 return data 257} 258 259function parseFunction(matchs, data, result) { 260 matchs = re.match("(export )*function (\\$*[A-Za-z0-9_]+) *(\\()", data) 261 if (null == matchs) { 262 matchs = re.match("(export )*function (static )*(\\$*[A-Za-z0-9_]+) *(\\()", data) 263 } 264 if (null == matchs) { 265 matchs = re.match("(export )*function (static )*(register\\$*[A-Za-z0-9_]+) *(\\()", data) 266 } 267 if (matchs) { 268 let funcName = re.getReg(data, 269 matchs.regs.length === 5 ? [matchs.regs[2][0], matchs.regs[3][1]] : matchs.regs[2]) 270 let funcValue = checkOutBody(data, 271 matchs.regs.length === 5 ? matchs.regs[4][0] : matchs.regs[3][0], ["(", ")"], null) 272 let funcRet = checkOutBody(data.substring(matchs.regs.length === 5 ? 273 matchs.regs[4][0] : matchs.regs[3][0] + funcValue.length), 0, ["", "\n"], null) 274 data = data.substring(matchs.regs.length === 5 ? 275 matchs.regs[4][0] : matchs.regs[3][0] + funcValue.length + funcRet.length) 276 let matchFunc = re.match(" *: *([A-Za-z0-9_<>{}\\[\\]:;, .=]+);*", funcRet) 277 let matchFuncArray = re.match(" *: *([A-Za-z0-9]+)(\\[]);*", funcRet) 278 if (matchFuncArray) { 279 funcRet = re.getReg(funcRet, [matchFuncArray.regs[1][0], matchFuncArray.regs[2][1]]) 280 } 281 else if (matchFunc) { 282 funcRet = re.getReg(funcRet, matchFunc.regs[1]) 283 } 284 else { 285 funcRet = "void" 286 } 287 funcRet = re.replaceAll(re.replaceAll(funcRet, " ", ""), "\n", "") 288 289 if(funcRet[funcRet.length-1] === ";"){ 290 funcRet = funcRet.substring(0, funcRet.length-1) 291 } 292 let funcDetail = analyzeFunction( 293 result, false, funcName, funcValue.substring(1, funcValue.length - 1), funcRet, result) 294 if (funcDetail !== null) { 295 // 完全一样的方法不重复添加 (如同名同参的AsyncCallback和Promise方法) 296 addUniqFunc2List(funcDetail, result.function) 297 } 298 if (matchs.regs[1][0] !== -1) { 299 result.exports.push(funcName) 300 } 301 } 302 return data 303} 304 305/** 306 * 提取当前类继承或实现的父类名称列表 307 * @param firstKey 继承/实现关键字 (extends或implements) 308 * @param secondKey 继承/实现关键字 (extends或implements) 309 * @param parentStr 正则匹配到的继承语句 (如 extends xx1, xx2 implements yy1, yy2) 310 * @returns 继承的名称列表 ([xx1, xx2, yy1, yy2]) 311 */ 312function getParentNameList(firstKey, secondKey, parentStr) { 313 if (parentStr === '') { 314 return [] 315 } 316 317 let firstParents = '' 318 let secondParents = '' 319 if (parentStr.indexOf(secondKey) > 0) { 320 // 同时出现extends和implements关键字的情况 (如 extends xx1, xx2 implements yy1, yy2) 321 firstParents = parentStr.split(secondKey)[0].split(firstKey)[1] 322 secondParents = parentStr.split(secondKey)[1].trim() 323 } else { 324 // 只有extends或implements一种关键字的情况 (如 extends xx1, xx2 或者 implements yy1, yy2) 325 firstParents = parentStr.split(firstKey)[1] 326 } 327 328 let nameList = firstParents.split(",") 329 if (secondParents !== '') { 330 let secondList = secondParents.split(",") 331 nameList.push(...secondList) 332 } 333 334 return nameList 335} 336 337/** 338 * 创建interface数据结构 339 * @param matchs 正则匹配对象 340 * @param data 原始ts文件内容 341 * @param result 解析后的ts数据结构 342 * @returns data 原始ts文件内容中剩余未解析的部分 343 */ 344function createInterfaceData (matchs, data, result) { 345 let interfaceName = re.getReg(data, matchs.regs[2]) 346 let interfaceBody = checkOutBody(data, matchs.regs[6][0], null, null) 347 let bodyObj = analyzeInterface(interfaceBody.substring(1, interfaceBody.length - 1), result.interface, 348 result, interfaceName) 349 let extendsParent = re.getReg(data, matchs.regs[4]) 350 let implementParent = re.getReg(data, matchs.regs[5]) 351 bodyObj.parentNameList = [] 352 if(extendsParent !== '') { 353 bodyObj.parentNameList = getParentNameList("extends", "implements", extendsParent) 354 } 355 if(implementParent !== '') { 356 bodyObj.parentNameList = getParentNameList("implements", "extends", implementParent) 357 } 358 for (let i in bodyObj.parentNameList) { 359 bodyObj.parentNameList[i] = bodyObj.parentNameList[i].trim() 360 if (bodyObj.parentNameList[i] === interfaceName) { 361 // 接口不能自己继承自己 362 NapiLog.logError("The interface [%s] can not extends with itself.".format(interfaceName)) 363 return data 364 } 365 } 366 367 bodyObj.parentList = [] // 该接口继承的父类型列表 368 bodyObj.childList = [] // 继承自该接口的子类型列表 369 370 result.interface.push({ 371 name: interfaceName, 372 body: bodyObj 373 }) 374 let rr = matchs.regs[6][0] 375 rr = matchs.regs[6][0] + interfaceBody.length 376 let tmp = data[rr] 377 data = data.substring(matchs.regs[6][0] + interfaceBody.length, data.length) 378 if (matchs.regs[1][0] !== -1) { 379 result.exports.push(interfaceName) 380 } 381 return data 382} 383 384function parseInterface(matchs, data, result) { 385 matchs = re.match( 386 "(export )*interface ([A-Za-z_0-9]+)(<T>)* *(extends [a-zA-Z_0-9, ]+)* *(implements [a-zA-Z_0-9, ]+)* *({)" 387 , data) 388 if (matchs) { 389 return createInterfaceData (matchs, data, result) 390 } 391 return data 392} 393 394function removeReg(matchs, data, result) { 395 matchs = re.match("export { ([a-zA-Z]+) };", data) 396 if (matchs) { 397 let exportName = re.getReg(data, matchs.regs[1]) 398 result.exports.push(exportName) 399 data = re.removeReg(data, matchs.regs[0]) 400 } 401 matchs = re.match("export import [a-zA-Z]+ = [a-zA-Z\\.]+;", data) 402 if (matchs) { 403 data = re.removeReg(data, matchs.regs[0]) 404 } 405 matchs = re.match("readonly [a-zA-Z]+: [a-z\\[\\]]+;*", data) 406 if (matchs) { 407 data = re.removeReg(data, matchs.regs[0]) 408 } 409 return data 410} 411module.exports = { 412 analyzeNamespace, 413 parseNamespace, 414 parseEnum, 415 parseFunction, 416 parseInterface, 417 parseClass, 418 parseType 419}