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