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