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