1/* 2 * Copyright (c) 2021-2022 Huawei Device 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 */ 15 16const ts = require('typescript') 17const path = require('path') 18const fs = require('fs') 19 20const addTSInterfaceSet = ['ForEach', 'LazyForEach', 'TapGesture', 'LongPressGesture', 'LongPressGesture', 21 'PanGesture', 'SwipeGesture', 'PinchGesture', 'RotationGesture', 'GestureGroup','PageTransitionEnter', 22 'PageTransitionExit']; 23const addTSAttributeSet = ['AlphabetIndexer', 'Animator', 'Badge', 'Blank', 'Button', 'Calendar', 'Canvas', 24 'Checkbox', 'CheckboxGroup', 'Circle', 'Column', 'ColumnSplit', 'Counter', 'DataPanel', 'DatePicker', 25 'Divider', 'Ellipse', 'Flex', 'FormComponent', 'Gauge', 'Grid', 'GridItem', 'GridContainer', 'Image', 26 'ImageAnimator', 'Line', 'List', 'ListItem', 'ListItemGroup', 'LoadingProgress', 'Marquee', 'Navigation', 'Navigator', 27 'Panel', 'Path', 'PatternLock', 'Piece', 'PluginComponent', 'Polygon', 'Polyline', 'Progress', 28 'QRCode', 'Radio', 'Rating', 'Rect', 'Refresh', 'Row', 'RowSplit', 'Scroll', 'ScrollBar', 'Search', 29 'Select', 'Shape', 'Sheet', 'Slider', 'Span', 'Stack', 'Stepper', 'StepperItem', 'Swiper', 30 'TabContent', 'Tabs', 'Text', 'TextArea', 'TextClock', 'TextInput', 'TextPicker', 'TextTimer', 31 'Toggle', 'Video', 'Web', 'XComponent', 'RichText', 'RemoteWindow', 'WaterFlow', 'FlowItem']; 32 33generateTargetFile(process.argv[2], process.argv[3]); 34function generateTargetFile(filePath, output) { 35 const files = []; 36 const globalTsFile = path.resolve(filePath, '../../ets/global.d.ts'); 37 const featureAbilityPath = path.resolve(filePath, '../../../common/full/featureability.d.ts'); 38 const middleTsFile = path.resolve(filePath, 'middle_class.d.ts'); 39 if (fs.existsSync(globalTsFile)) { 40 files.push(globalTsFile); 41 } 42 if (fs.existsSync(featureAbilityPath)) { 43 files.push(featureAbilityPath); 44 } 45 readFile(filePath, files); 46 if (!fs.existsSync(output)) { 47 mkDir(output); 48 } 49 const license = `/* 50 * Copyright (c) 2021 Huawei Device Co., Ltd. 51 * Licensed under the Apache License, Version 2.0 (the "License"); 52 * you may not use this file except in compliance with the License. 53 * You may obtain a copy of the License at 54 * 55 * http://www.apache.org/licenses/LICENSE-2.0 56 * 57 * Unless required by applicable law or agreed to in writing, software 58 * distributed under the License is distributed on an "AS IS" BASIS, 59 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 60 * See the License for the specific language governing permissions and 61 * limitations under the License. 62 */`; 63 files.forEach((item) => { 64 let content = fs.readFileSync(item, 'utf8'); 65 const fileName = path.resolve(output, path.basename(item)); 66 if (item === featureAbilityPath) { 67 content = processsFile(content, fileName, true); 68 } else if (item === globalTsFile) { 69 content = license + '\n\n' + processsFile(content, fileName, true); 70 } else { 71 content = processImportType(content); 72 } 73 fs.writeFile(fileName, content, err => { 74 if (err) { 75 console.error(err); 76 return; 77 } 78 }); 79 }); 80} 81 82function processImportType(content) { 83 return content.replace(/(import\s*\(("|'))(\.\.\/api\/[^("|')]*("|')\)\.)/g, (item, item1, item2, item3) => { 84 return item1 + '../../' + item3; 85 }) 86} 87 88function readFile(dir, fileDir) { 89 const files = fs.readdirSync(dir); 90 files.forEach((element) => { 91 const filePath = path.join(dir, element); 92 const status = fs.statSync(filePath); 93 if (status.isDirectory()) { 94 readFile(filePath, fileDir); 95 } else { 96 fileDir.push(filePath); 97 } 98 }); 99} 100 101function mkDir(filePath) { 102 const parent = path.join(filePath, '..'); 103 if (!(fs.existsSync(parent) && !fs.statSync(parent).isFile())) { 104 mkDir(parent); 105 } 106 fs.mkdirSync(filePath); 107} 108 109function processsFile(content, fileName, isGlobal) { 110 let sourceFile = ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS); 111 const newStatements = []; 112 if (sourceFile.statements && sourceFile.statements.length) { 113 if (isGlobal) { 114 sourceFile.statements.forEach((node) => { 115 if (!ts.isImportDeclaration(node)) { 116 if (node.modifiers && node.modifiers.length && node.modifiers[0].kind === ts.SyntaxKind.ExportKeyword) { 117 node.modifiers.splice(0, 1); 118 } 119 if (isVariable(node)) { 120 const name = node.declarationList.declarations[0].name.getText(); 121 const type = node.declarationList.declarations[0].type.getText(); 122 if (name.indexOf(type) !== -1) { 123 const declarationNode = ts.factory.updateVariableDeclaration(node.declarationList.declarations[0], 124 ts.factory.createIdentifier(type), node.declarationList.declarations[0].exclamationToken, 125 node.declarationList.declarations[0].type, node.declarationList.declarations[0].initializer); 126 node.declarationList = ts.factory.updateVariableDeclarationList(node.declarationList, [declarationNode]); 127 } 128 } 129 newStatements.push(node); 130 } 131 }); 132 } else { 133 sourceFile.statements.forEach((node) => { 134 processComponent(node, newStatements); 135 }); 136 } 137 } 138 sourceFile = ts.factory.updateSourceFile(sourceFile, newStatements); 139 const printer = ts.createPrinter({ removeComments: false, newLine: ts.NewLineKind.LineFeed }); 140 const result = printer.printNode(ts.EmitHint.Unspecified, sourceFile, sourceFile); 141 return result; 142} 143 144function processComponent(node, newStatements) { 145 let extendNode = null; 146 if (isInterface(node)) { 147 const componentName = node.name.getText().replace(/Interface$/, ''); 148 const result = validateComponentMembers(node, componentName); 149 if (result.isComponentName) { 150 const heritageClause = ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, 151 [ts.factory.createExpressionWithTypeArguments(result.extendNode, undefined)]); 152 extendNode = null; 153 node = ts.factory.updateInterfaceDeclaration(node, node.decorators, node.modifiers, 154 node.name, node.typeParameters, [heritageClause], node.members); 155 } 156 if (addTSInterfaceSet.includes(componentName)) { 157 node = ts.factory.updateInterfaceDeclaration(node, node.decorators, node.modifiers, node.name, 158 node.typeParameters, [ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, 159 [ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier('TS' + componentName + 'Interface'), 160 undefined)])], node.members); 161 } 162 } 163 if (isClass(node) && addTSAttributeSet.includes(node.name.getText().replace(/Attribute$/, ''))) { 164 node = ts.factory.updateClassDeclaration(node, node.decorators, node.modifiers, node.name, 165 node.typeParameters, [ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, 166 [ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier('TS' + node.name.getText()), 167 undefined)])], node.members); 168 } 169 newStatements.push(node); 170} 171 172function validateComponentMembers(node, componentName) { 173 let extendNode = null; 174 let isComponentName = false; 175 if (node.members) { 176 for (let i = 0; i < node.members.length; i++) { 177 const callSignNode = node.members[i]; 178 if (isSignNode(callSignNode)) { 179 const callSignName = callSignNode.type.typeName.getText().replace(/Attribute$/, ''); 180 if (componentName === callSignName) { 181 extendNode = callSignNode.type.typeName; 182 isComponentName = true; 183 break; 184 } 185 } 186 } 187 } 188 return { isComponentName, extendNode } 189} 190 191function isVariable(node) { 192 if (ts.isVariableStatement(node) && node.declarationList && node.declarationList.declarations && 193 node.declarationList.declarations.length && ts.isVariableDeclaration(node.declarationList.declarations[0]) && 194 node.declarationList.declarations[0].name && node.declarationList.declarations[0].type) { 195 return true; 196 } 197 return false; 198} 199 200function isInterface(node) { 201 return ts.isInterfaceDeclaration(node) && node.name && ts.isIdentifier(node.name) && 202 /Interface$/.test(node.name.getText()); 203} 204 205function isClass(node) { 206 return ts.isClassDeclaration(node) && node.name && ts.isIdentifier(node.name) && 207 /Attribute$/.test(node.name.getText()); 208} 209 210function isSignNode(node) { 211 return (ts.isCallSignatureDeclaration(node) || ts.isConstructSignatureDeclaration(node)) && 212 node.type && ts.isTypeReferenceNode(node.type) && node.type.typeName && ts.isIdentifier(node.type.typeName) && 213 /Attribute$/.test(node.type.typeName.getText()); 214} 215 216generateComponentConfig(process.argv[4]); 217function generateComponentConfig(dir) { 218 const configFile = path.resolve(dir, 'component_map.js'); 219 if (fs.existsSync(configFile)) { 220 const { COMPONENT_MAP, FORM_MAP } = require(configFile); 221 try { 222 fs.writeFileSync(path.resolve(dir, '../component_config.json'), JSON.stringify(COMPONENT_MAP)); 223 fs.writeFileSync(path.resolve(dir, '../form_config.json'), JSON.stringify(FORM_MAP)); 224 } catch (error) { 225 console.error(error); 226 } 227 } 228} 229