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 ts = require('typescript'); 16const fs = require('fs'); 17const re = require("./tools/re"); 18const { getLicense, checkOutBody } = require("./tools/tool"); 19const { analyzeNamespace } = require("./analyze/namespace"); 20 21// 读取和解析.d.ts文件 22const filePath = '@ohos.test.d.ts'; 23// const sourceCode = fs.readFileSync(filePath, 'utf-8'); 24// const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true); 25// let statements = sourceFile.statements 26 27// 打印语法树 28function stringifyWithoutCircular(obj) { 29 const cache = new Set(); 30 return JSON.stringify(obj, (key, value) => { 31 if (typeof value === 'object' && value !== null) { 32 if (cache.has(value)) { 33 return; // Skip circular references 34 } 35 cache.add(value); 36 } 37 return value; 38 }); 39 } 40 41 42function analyzeFileRaw(fn) { 43 const sourceCode = fs.readFileSync(filePath, 'utf-8'); 44 const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true); 45 let statements = sourceFile.statements 46 47 // console.log(stringifyWithoutCircular(sourceFile)); 48 49 let result = { 50 exportDefault: [], 51 exports: [], 52 imports:[], 53 declareType: [], 54 declareFunction: [], 55 declareNamespace: [], 56 declareInterface: [], 57 declareLicense: [], 58 } 59 60 if (statements.length === 0 ) { 61 return null; 62 } 63 64 let imports = statements[0].getText(); 65 if (imports != null) { 66 result.imports.push(imports); 67 } 68 69 let data = statements[0].getFullText(); 70 let licenseData = getLicense(data); 71 if (null != licenseData) { 72 result.declareLicense.push(licenseData) 73 } 74 75 let impordts = statements[1].getText(); 76 77 let ff = statements[1].getChildren(); 78 let ffa = statements[1].getChildAt(1); 79 let ffb = statements[1].getChildCount(); 80 let ffc = statements[1].getLastToken(); 81 let xx = statements[1].getEnd(); 82 83 // let exportsInfo = statements[2].getText(); 84 85 // let ff = statements[2].end 86 // let gg = statements[2]. 87 // let exportName = statements[2].expression.escapedText 88 89 // result.exportDefault.push(exportName); 90 91 return analyzeRaw(statements, result) 92} 93 94function analyzeRaw(statements, result) { 95 while (true) { 96 let exportsInfo = statements[2].getText(); 97 let matchs = re.match("export default ([a-zA-Z0-9_]+);", exportsInfo); 98 if (matchs != null) { 99 let exportName = re.getReg(exportsInfo, matchs.regs[1]) 100 // data = re.removeReg(data, matchs.regs[0]); 101 result.exportDefault.push(exportName) 102 } 103 104 // data = re.replaceAll(data, "\n{", "{"); 105 // let matchType = analyzeMatchType(matchs, data, result) 106 // if (matchType != null) { 107 // data = matchType[0] 108 // if (matchType[1] != null) { 109 // result = matchType[1] 110 // } 111 // } 112 let data = statements[1].getText(); 113 let namespace = analyzeMatchNamespace(matchs, data, result) 114 if (namespace != null) { 115 data = namespace[0] 116 result = namespace[1] 117 } 118 let interface = analyzeMatchInterface(matchs, data, result) 119 if (interface != null) { 120 data = interface[0] 121 result = interface[1] 122 } 123 return result; 124 // let functionMatch = analyzeMatchFunction(matchs, data, result) 125 // if (functionMatch != null) { 126 // data = functionMatch[0] 127 // result = functionMatch[1] 128 // } 129 // if (oldData == data) { 130 // NapiLog.logError("\nvvv 解析文件失败 vvv"); 131 // NapiLog.logError("[", data.substring(0, data.length > 64 ? 64 : data.length), "]"); 132 // break; 133 // } 134 } 135 return result 136} 137 138function analyzeMatchNamespace(matchs, data, result) { 139 matchs = re.match("declare namespace ([a-zA-Z_0-9]+) *({)", data); 140 // 解析declare 141 if (matchs != null) { 142 let namespaceName = re.getReg(data, matchs.regs[1]) 143 let namespaceData = checkOutBody(data, matchs.regs[2][0], null, true) 144 data = data.substring(matchs.regs[2][1] + namespaceData.length + 1, data.length) 145 result.declareNamespace.push({ 146 name: namespaceName, 147 body: analyzeNamespace(namespaceData) 148 }) 149 } 150 return [data, result] 151} 152 153function analyzeMatchInterface(matchs, data, result) { 154 matchs = re.match("(export )*(declare )*interface ([A-Za-z_0-9<>= ]+) (extends [a-zA-Z]+ )*({)", data) 155 if (matchs) { 156 let interfaceName = re.getReg(data, matchs.regs[3]) 157 let interfaceData = checkOutBody(data, matchs.regs[5][0], null, true) 158 data = data.substring(matchs.regs[5][1] + interfaceData.length + 1, data.length) 159 result.declareInterface.push({ 160 name: interfaceName, 161 body: {} 162 }) 163 } 164 return [data, result] 165} 166 167function analyzeMatchFunction(matchs, data, result) { 168 matchs = re.match("declare function ([A-Za-z0-9_]+)\\(([\n a-zA-Z:;=,_0-9?<>{}|]*)\\) *:" 169 + "*([A-Za-z0-9_<>{}:, .]+);*", data) 170 if (matchs) { 171 let functionName = re.getReg(data, matchs.regs[1]) 172 let functionBody = re.getReg(data, matchs.regs[2]) 173 data = re.removeReg(data, matchs.regs[0]) 174 result.declareFunction.push({ 175 name: functionName, 176 body: functionBody 177 }) 178 } 179 return [data, result] 180} 181 182function analyzeMatchType(matchs, data, result) { 183 matchs = re.match("(export )*type ([a-zA-Z]+) *= *([()a-zA-Z :=>,\"| ]+);", data) 184 if (matchs) { 185 let exportName = re.getReg(data, matchs.regs[2]) 186 let exportBody = re.getReg(data, matchs.regs[3]) 187 data = re.removeReg(data, matchs.regs[0]); 188 result.declareType.push({ 189 name: exportName, 190 body: exportBody 191 }) 192 if (matchs.regs[1][0] != -1) { 193 result.exports.push(exportName) 194 } 195 } 196 197 matchs = re.match("(export )*type ([a-zA-Z]+) *= *(\n{)", data) 198 if (matchs) { 199 let exportName = re.getReg(data, matchs.regs[2]) 200 let exportBody = checkOutBody(data, matchs.regs[3][0], null, true) 201 data = data.substring(matchs.regs[3][1] + exportBody.length + 2, data.length) 202 result.declareType.push({ 203 name: exportName, 204 body: exportBody 205 }) 206 if (matchs.regs[1][0] != -1) { 207 result.exports.push(exportName) 208 } 209 } 210 return [data, result] 211} 212 213module.exports = { 214 analyzeFileRaw 215}