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