• 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, 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}