13af6ab5fSopenharmony_ci/* 23af6ab5fSopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License. 53af6ab5fSopenharmony_ci * You may obtain a copy of the License at 63af6ab5fSopenharmony_ci * 73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83af6ab5fSopenharmony_ci * 93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and 133af6ab5fSopenharmony_ci * limitations under the License. 143af6ab5fSopenharmony_ci */ 153af6ab5fSopenharmony_ci 163af6ab5fSopenharmony_ciimport type { 173af6ab5fSopenharmony_ci ElementAccessExpression, 183af6ab5fSopenharmony_ci EnumDeclaration, 193af6ab5fSopenharmony_ci ExportDeclaration, 203af6ab5fSopenharmony_ci ModifiersArray, 213af6ab5fSopenharmony_ci ModuleDeclaration, 223af6ab5fSopenharmony_ci Node, 233af6ab5fSopenharmony_ci ParameterDeclaration, 243af6ab5fSopenharmony_ci PropertyAccessExpression, 253af6ab5fSopenharmony_ci SourceFile 263af6ab5fSopenharmony_ci} from 'typescript'; 273af6ab5fSopenharmony_ci 283af6ab5fSopenharmony_ciimport { 293af6ab5fSopenharmony_ci createSourceFile, 303af6ab5fSopenharmony_ci forEachChild, 313af6ab5fSopenharmony_ci isBinaryExpression, 323af6ab5fSopenharmony_ci isClassDeclaration, 333af6ab5fSopenharmony_ci isClassExpression, 343af6ab5fSopenharmony_ci isStructDeclaration, 353af6ab5fSopenharmony_ci isExpressionStatement, 363af6ab5fSopenharmony_ci isEnumDeclaration, 373af6ab5fSopenharmony_ci isExportAssignment, 383af6ab5fSopenharmony_ci isExportDeclaration, 393af6ab5fSopenharmony_ci isExportSpecifier, 403af6ab5fSopenharmony_ci isIdentifier, 413af6ab5fSopenharmony_ci isInterfaceDeclaration, 423af6ab5fSopenharmony_ci isObjectLiteralExpression, 433af6ab5fSopenharmony_ci isTypeAliasDeclaration, 443af6ab5fSopenharmony_ci isVariableDeclaration, 453af6ab5fSopenharmony_ci isVariableStatement, 463af6ab5fSopenharmony_ci isElementAccessExpression, 473af6ab5fSopenharmony_ci isPropertyAccessExpression, 483af6ab5fSopenharmony_ci isStringLiteral, 493af6ab5fSopenharmony_ci ScriptTarget, 503af6ab5fSopenharmony_ci SyntaxKind, 513af6ab5fSopenharmony_ci sys, 523af6ab5fSopenharmony_ci isConstructorDeclaration, 533af6ab5fSopenharmony_ci getModifiers, 543af6ab5fSopenharmony_ci isNamedExports, 553af6ab5fSopenharmony_ci isNamespaceExport, 563af6ab5fSopenharmony_ci isPropertyDeclaration, 573af6ab5fSopenharmony_ci isPropertySignature, 583af6ab5fSopenharmony_ci isMethodDeclaration, 593af6ab5fSopenharmony_ci isMethodSignature, 603af6ab5fSopenharmony_ci isObjectLiteralElementLike, 613af6ab5fSopenharmony_ci isModuleDeclaration, 623af6ab5fSopenharmony_ci isPropertyAssignment, 633af6ab5fSopenharmony_ci isModuleBlock, 643af6ab5fSopenharmony_ci isFunctionDeclaration, 653af6ab5fSopenharmony_ci isEnumMember 663af6ab5fSopenharmony_ci} from 'typescript'; 673af6ab5fSopenharmony_ci 683af6ab5fSopenharmony_ciimport fs from 'fs'; 693af6ab5fSopenharmony_ciimport path from 'path'; 703af6ab5fSopenharmony_ciimport json5 from 'json5'; 713af6ab5fSopenharmony_ci 723af6ab5fSopenharmony_ciimport { 733af6ab5fSopenharmony_ci exportOriginalNameSet, 743af6ab5fSopenharmony_ci getClassProperties, 753af6ab5fSopenharmony_ci getElementAccessExpressionProperties, 763af6ab5fSopenharmony_ci getEnumProperties, getInterfaceProperties, 773af6ab5fSopenharmony_ci getObjectExportNames, 783af6ab5fSopenharmony_ci getObjectProperties, 793af6ab5fSopenharmony_ci getTypeAliasProperties, 803af6ab5fSopenharmony_ci isParameterPropertyModifier, 813af6ab5fSopenharmony_ci} from '../utils/OhsUtil'; 823af6ab5fSopenharmony_ciimport { scanProjectConfig } from './ApiReader'; 833af6ab5fSopenharmony_ciimport { stringPropsSet, enumPropsSet } from '../utils/OhsUtil'; 843af6ab5fSopenharmony_ciimport type { IOptions } from '../configs/IOptions'; 853af6ab5fSopenharmony_ciimport { FileUtils } from '../utils/FileUtils'; 863af6ab5fSopenharmony_ciimport { supportedParsingExtension } from './type'; 873af6ab5fSopenharmony_ci 883af6ab5fSopenharmony_ciexport namespace ApiExtractor { 893af6ab5fSopenharmony_ci interface KeywordInfo { 903af6ab5fSopenharmony_ci hasExport: boolean, 913af6ab5fSopenharmony_ci hasDeclare: boolean 923af6ab5fSopenharmony_ci } 933af6ab5fSopenharmony_ci 943af6ab5fSopenharmony_ci export enum ApiType { 953af6ab5fSopenharmony_ci API = 1, 963af6ab5fSopenharmony_ci COMPONENT = 2, 973af6ab5fSopenharmony_ci PROJECT_DEPENDS = 3, 983af6ab5fSopenharmony_ci PROJECT = 4, 993af6ab5fSopenharmony_ci CONSTRUCTOR_PROPERTY = 5 1003af6ab5fSopenharmony_ci } 1013af6ab5fSopenharmony_ci 1023af6ab5fSopenharmony_ci let mCurrentExportedPropertySet: Set<string> = new Set<string>(); 1033af6ab5fSopenharmony_ci let mCurrentExportNameSet: Set<string> = new Set<string>(); 1043af6ab5fSopenharmony_ci export let mPropertySet: Set<string> = new Set<string>(); 1053af6ab5fSopenharmony_ci export let mExportNames: Set<string> = new Set<string>(); 1063af6ab5fSopenharmony_ci export let mConstructorPropertySet: Set<string> = undefined; 1073af6ab5fSopenharmony_ci export let mSystemExportSet: Set<string> = new Set<string>(); 1083af6ab5fSopenharmony_ci /** 1093af6ab5fSopenharmony_ci * filter classes or interfaces with export, default, etc 1103af6ab5fSopenharmony_ci */ 1113af6ab5fSopenharmony_ci const getKeyword = function (modifiers: ModifiersArray): KeywordInfo { 1123af6ab5fSopenharmony_ci if (modifiers === undefined) { 1133af6ab5fSopenharmony_ci return {hasExport: false, hasDeclare: false}; 1143af6ab5fSopenharmony_ci } 1153af6ab5fSopenharmony_ci 1163af6ab5fSopenharmony_ci let hasExport: boolean = false; 1173af6ab5fSopenharmony_ci let hasDeclare: boolean = false; 1183af6ab5fSopenharmony_ci 1193af6ab5fSopenharmony_ci for (const modifier of modifiers) { 1203af6ab5fSopenharmony_ci if (modifier.kind === SyntaxKind.ExportKeyword) { 1213af6ab5fSopenharmony_ci hasExport = true; 1223af6ab5fSopenharmony_ci } 1233af6ab5fSopenharmony_ci 1243af6ab5fSopenharmony_ci if (modifier.kind === SyntaxKind.DeclareKeyword) { 1253af6ab5fSopenharmony_ci hasDeclare = true; 1263af6ab5fSopenharmony_ci } 1273af6ab5fSopenharmony_ci } 1283af6ab5fSopenharmony_ci 1293af6ab5fSopenharmony_ci return {hasExport: hasExport, hasDeclare: hasDeclare}; 1303af6ab5fSopenharmony_ci }; 1313af6ab5fSopenharmony_ci 1323af6ab5fSopenharmony_ci /** 1333af6ab5fSopenharmony_ci * get export name list 1343af6ab5fSopenharmony_ci * @param astNode 1353af6ab5fSopenharmony_ci */ 1363af6ab5fSopenharmony_ci const visitExport = function (astNode, isSystemApi: boolean): void { 1373af6ab5fSopenharmony_ci /** 1383af6ab5fSopenharmony_ci * export = exportClass //collect exportClass 1393af6ab5fSopenharmony_ci * 1403af6ab5fSopenharmony_ci * function foo() 1413af6ab5fSopenharmony_ci * export default foo //collect foo 1423af6ab5fSopenharmony_ci */ 1433af6ab5fSopenharmony_ci if (isExportAssignment(astNode)) { 1443af6ab5fSopenharmony_ci let nodeName = astNode.expression.getText(); 1453af6ab5fSopenharmony_ci if (!mCurrentExportNameSet.has(nodeName)) { 1463af6ab5fSopenharmony_ci collectNodeName(nodeName); 1473af6ab5fSopenharmony_ci } 1483af6ab5fSopenharmony_ci return; 1493af6ab5fSopenharmony_ci } 1503af6ab5fSopenharmony_ci 1513af6ab5fSopenharmony_ci if (isExportDeclaration(astNode) && astNode.exportClause) { 1523af6ab5fSopenharmony_ci /** 1533af6ab5fSopenharmony_ci * export {name1, name2} //collect name1, name2 1543af6ab5fSopenharmony_ci * export {name1 as n1, name2} //collect n1, name2 1553af6ab5fSopenharmony_ci * export {name1 as default, name2, name3} //collect default, name2, name3 1563af6ab5fSopenharmony_ci */ 1573af6ab5fSopenharmony_ci if (isNamedExports(astNode.exportClause)) { 1583af6ab5fSopenharmony_ci for (const element of astNode.exportClause.elements) { 1593af6ab5fSopenharmony_ci const exportElementName = element.name.getText(); 1603af6ab5fSopenharmony_ci if (!mCurrentExportNameSet.has(exportElementName)) { 1613af6ab5fSopenharmony_ci collectNodeName(exportElementName); 1623af6ab5fSopenharmony_ci } 1633af6ab5fSopenharmony_ci } 1643af6ab5fSopenharmony_ci } 1653af6ab5fSopenharmony_ci 1663af6ab5fSopenharmony_ci /** 1673af6ab5fSopenharmony_ci * export * as name1 from 'file.ts' //collect name1 1683af6ab5fSopenharmony_ci */ 1693af6ab5fSopenharmony_ci if (isNamespaceExport(astNode.exportClause)) { 1703af6ab5fSopenharmony_ci const exportElementName = astNode.exportClause.name.getText(); 1713af6ab5fSopenharmony_ci if (!mCurrentExportNameSet.has(exportElementName)) { 1723af6ab5fSopenharmony_ci collectNodeName(exportElementName); 1733af6ab5fSopenharmony_ci } 1743af6ab5fSopenharmony_ci } 1753af6ab5fSopenharmony_ci 1763af6ab5fSopenharmony_ci /** 1773af6ab5fSopenharmony_ci * Other export syntax, which does not contain a name. such as: 1783af6ab5fSopenharmony_ci * export * from 'file.ts' 1793af6ab5fSopenharmony_ci */ 1803af6ab5fSopenharmony_ci return; 1813af6ab5fSopenharmony_ci } 1823af6ab5fSopenharmony_ci 1833af6ab5fSopenharmony_ci let {hasExport, hasDeclare} = getKeyword(astNode.modifiers); 1843af6ab5fSopenharmony_ci if (!hasExport) { 1853af6ab5fSopenharmony_ci addCommonJsExports(astNode, isSystemApi); 1863af6ab5fSopenharmony_ci return; 1873af6ab5fSopenharmony_ci } 1883af6ab5fSopenharmony_ci 1893af6ab5fSopenharmony_ci if (astNode.name) { 1903af6ab5fSopenharmony_ci let nodeName = astNode.name.getText(); 1913af6ab5fSopenharmony_ci if (!mCurrentExportNameSet.has(nodeName)) { 1923af6ab5fSopenharmony_ci collectNodeName(nodeName); 1933af6ab5fSopenharmony_ci } 1943af6ab5fSopenharmony_ci 1953af6ab5fSopenharmony_ci return; 1963af6ab5fSopenharmony_ci } 1973af6ab5fSopenharmony_ci 1983af6ab5fSopenharmony_ci if (hasDeclare && astNode.declarationList) { 1993af6ab5fSopenharmony_ci astNode.declarationList.declarations.forEach((declaration) => { 2003af6ab5fSopenharmony_ci const declarationName = declaration.name.getText(); 2013af6ab5fSopenharmony_ci if (!mCurrentExportNameSet.has(declarationName)) { 2023af6ab5fSopenharmony_ci collectNodeName(declarationName); 2033af6ab5fSopenharmony_ci } 2043af6ab5fSopenharmony_ci }); 2053af6ab5fSopenharmony_ci } 2063af6ab5fSopenharmony_ci }; 2073af6ab5fSopenharmony_ci 2083af6ab5fSopenharmony_ci const isCollectedToplevelElements = function (astNode): boolean { 2093af6ab5fSopenharmony_ci if (astNode.name && !mCurrentExportNameSet.has(astNode.name.getText())) { 2103af6ab5fSopenharmony_ci return false; 2113af6ab5fSopenharmony_ci } 2123af6ab5fSopenharmony_ci 2133af6ab5fSopenharmony_ci if (astNode.name === undefined) { 2143af6ab5fSopenharmony_ci let {hasDeclare} = getKeyword(astNode.modifiers); 2153af6ab5fSopenharmony_ci if (hasDeclare && astNode.declarationList && 2163af6ab5fSopenharmony_ci !mCurrentExportNameSet.has(astNode.declarationList.declarations[0].name.getText())) { 2173af6ab5fSopenharmony_ci return false; 2183af6ab5fSopenharmony_ci } 2193af6ab5fSopenharmony_ci } 2203af6ab5fSopenharmony_ci 2213af6ab5fSopenharmony_ci return true; 2223af6ab5fSopenharmony_ci }; 2233af6ab5fSopenharmony_ci 2243af6ab5fSopenharmony_ci /** 2253af6ab5fSopenharmony_ci * used only in oh sdk api extract or api of xxx.d.ts declaration file 2263af6ab5fSopenharmony_ci * @param astNode 2273af6ab5fSopenharmony_ci */ 2283af6ab5fSopenharmony_ci const visitChildNode = function (astNode): void { 2293af6ab5fSopenharmony_ci if (!astNode) { 2303af6ab5fSopenharmony_ci return; 2313af6ab5fSopenharmony_ci } 2323af6ab5fSopenharmony_ci 2333af6ab5fSopenharmony_ci if (astNode.name !== undefined && !mCurrentExportedPropertySet.has(astNode.name.getText())) { 2343af6ab5fSopenharmony_ci if (isStringLiteral(astNode.name)) { 2353af6ab5fSopenharmony_ci mCurrentExportedPropertySet.add(astNode.name.text); 2363af6ab5fSopenharmony_ci } else { 2373af6ab5fSopenharmony_ci mCurrentExportedPropertySet.add(astNode.name.getText()); 2383af6ab5fSopenharmony_ci } 2393af6ab5fSopenharmony_ci } 2403af6ab5fSopenharmony_ci 2413af6ab5fSopenharmony_ci astNode.forEachChild((childNode) => { 2423af6ab5fSopenharmony_ci visitChildNode(childNode); 2433af6ab5fSopenharmony_ci }); 2443af6ab5fSopenharmony_ci }; 2453af6ab5fSopenharmony_ci 2463af6ab5fSopenharmony_ci // Collect constructor properties from all files. 2473af6ab5fSopenharmony_ci const visitNodeForConstructorProperty = function (astNode): void { 2483af6ab5fSopenharmony_ci if (!astNode) { 2493af6ab5fSopenharmony_ci return; 2503af6ab5fSopenharmony_ci } 2513af6ab5fSopenharmony_ci 2523af6ab5fSopenharmony_ci if (isConstructorDeclaration) { 2533af6ab5fSopenharmony_ci const visitParam = (param: ParameterDeclaration): void => { 2543af6ab5fSopenharmony_ci const modifiers = getModifiers(param); 2553af6ab5fSopenharmony_ci if (!modifiers || modifiers.length <= 0) { 2563af6ab5fSopenharmony_ci return; 2573af6ab5fSopenharmony_ci } 2583af6ab5fSopenharmony_ci 2593af6ab5fSopenharmony_ci const findRet = modifiers.find(modifier => isParameterPropertyModifier(modifier)); 2603af6ab5fSopenharmony_ci if (!isIdentifier(param.name) || findRet === undefined) { 2613af6ab5fSopenharmony_ci return; 2623af6ab5fSopenharmony_ci } 2633af6ab5fSopenharmony_ci mConstructorPropertySet?.add(param.name.getText()); 2643af6ab5fSopenharmony_ci }; 2653af6ab5fSopenharmony_ci 2663af6ab5fSopenharmony_ci astNode?.parameters?.forEach((param) => { 2673af6ab5fSopenharmony_ci visitParam(param); 2683af6ab5fSopenharmony_ci }); 2693af6ab5fSopenharmony_ci } 2703af6ab5fSopenharmony_ci 2713af6ab5fSopenharmony_ci astNode.forEachChild((childNode) => { 2723af6ab5fSopenharmony_ci visitNodeForConstructorProperty(childNode); 2733af6ab5fSopenharmony_ci }); 2743af6ab5fSopenharmony_ci }; 2753af6ab5fSopenharmony_ci /** 2763af6ab5fSopenharmony_ci * visit ast of a file and collect api list 2773af6ab5fSopenharmony_ci * used only in oh sdk api extract 2783af6ab5fSopenharmony_ci * @param astNode node of ast 2793af6ab5fSopenharmony_ci */ 2803af6ab5fSopenharmony_ci const visitPropertyAndName = function (astNode): void { 2813af6ab5fSopenharmony_ci if (!isCollectedToplevelElements(astNode)) { 2823af6ab5fSopenharmony_ci /** 2833af6ab5fSopenharmony_ci * Collects property names of elements within top-level elements that haven't been collected yet. 2843af6ab5fSopenharmony_ci * @param astNode toplevel elements of sourcefile 2853af6ab5fSopenharmony_ci */ 2863af6ab5fSopenharmony_ci collectPropertyNames(astNode); 2873af6ab5fSopenharmony_ci return; 2883af6ab5fSopenharmony_ci } 2893af6ab5fSopenharmony_ci 2903af6ab5fSopenharmony_ci visitChildNode(astNode); 2913af6ab5fSopenharmony_ci }; 2923af6ab5fSopenharmony_ci 2933af6ab5fSopenharmony_ci /** 2943af6ab5fSopenharmony_ci * commonjs exports extract 2953af6ab5fSopenharmony_ci * examples: 2963af6ab5fSopenharmony_ci * - exports.A = 1; 2973af6ab5fSopenharmony_ci * - exports.B = hello; // hello can be variable or class ... 2983af6ab5fSopenharmony_ci * - exports.C = {}; 2993af6ab5fSopenharmony_ci * - exports.D = class {}; 3003af6ab5fSopenharmony_ci * - exports.E = function () {} 3013af6ab5fSopenharmony_ci * - class F {} 3023af6ab5fSopenharmony_ci * - exports.F = F; 3033af6ab5fSopenharmony_ci * - module.exports = {G: {}}; 3043af6ab5fSopenharmony_ci */ 3053af6ab5fSopenharmony_ci const addCommonJsExports = function (astNode: Node, isRemoteHarOrSystemApi: boolean = false): void { 3063af6ab5fSopenharmony_ci if (!isExpressionStatement(astNode) || !astNode.expression) { 3073af6ab5fSopenharmony_ci return; 3083af6ab5fSopenharmony_ci } 3093af6ab5fSopenharmony_ci 3103af6ab5fSopenharmony_ci const expression = astNode.expression; 3113af6ab5fSopenharmony_ci if (!isBinaryExpression(expression)) { 3123af6ab5fSopenharmony_ci return; 3133af6ab5fSopenharmony_ci } 3143af6ab5fSopenharmony_ci 3153af6ab5fSopenharmony_ci const left = expression.left; 3163af6ab5fSopenharmony_ci if (!isElementAccessExpression(left) && !isPropertyAccessExpression(left)) { 3173af6ab5fSopenharmony_ci return; 3183af6ab5fSopenharmony_ci } 3193af6ab5fSopenharmony_ci 3203af6ab5fSopenharmony_ci if (!isModuleExports(left) || expression.operatorToken.kind !== SyntaxKind.EqualsToken) { 3213af6ab5fSopenharmony_ci return; 3223af6ab5fSopenharmony_ci } 3233af6ab5fSopenharmony_ci 3243af6ab5fSopenharmony_ci if (isElementAccessExpression(left)) { 3253af6ab5fSopenharmony_ci if (isStringLiteral(left.argumentExpression)) { 3263af6ab5fSopenharmony_ci /** 3273af6ab5fSopenharmony_ci * - module.exports['A'] = class {}; 3283af6ab5fSopenharmony_ci * - module.exports['a'] = {}; 3293af6ab5fSopenharmony_ci * - module.exports['a'] = A; 3303af6ab5fSopenharmony_ci */ 3313af6ab5fSopenharmony_ci mCurrentExportedPropertySet.add(left.argumentExpression.text); 3323af6ab5fSopenharmony_ci mCurrentExportNameSet.add(left.argumentExpression.text); 3333af6ab5fSopenharmony_ci } 3343af6ab5fSopenharmony_ci } 3353af6ab5fSopenharmony_ci 3363af6ab5fSopenharmony_ci if (isPropertyAccessExpression(left)) { 3373af6ab5fSopenharmony_ci if (isIdentifier(left.name)) { 3383af6ab5fSopenharmony_ci /** 3393af6ab5fSopenharmony_ci * - module.exports.A = a; 3403af6ab5fSopenharmony_ci * - module.exports.A = {}; 3413af6ab5fSopenharmony_ci * - module.exports.A = class {}; 3423af6ab5fSopenharmony_ci */ 3433af6ab5fSopenharmony_ci mCurrentExportedPropertySet.add(left.name.getText()); 3443af6ab5fSopenharmony_ci mCurrentExportNameSet.add(left.name.getText()); 3453af6ab5fSopenharmony_ci } 3463af6ab5fSopenharmony_ci } 3473af6ab5fSopenharmony_ci 3483af6ab5fSopenharmony_ci if (isIdentifier(expression.right)) { 3493af6ab5fSopenharmony_ci /** 3503af6ab5fSopenharmony_ci * module.exports.A = a; 3513af6ab5fSopenharmony_ci * exports.A = a; 3523af6ab5fSopenharmony_ci * module.exports = a; 3533af6ab5fSopenharmony_ci */ 3543af6ab5fSopenharmony_ci let originalName = expression.right.getText(); 3553af6ab5fSopenharmony_ci if (isRemoteHarOrSystemApi) { 3563af6ab5fSopenharmony_ci // To achieve compatibility changes, originalName is still collected into mCurrentExportNameSet 3573af6ab5fSopenharmony_ci // for both remoteHar and system API files. 3583af6ab5fSopenharmony_ci 3593af6ab5fSopenharmony_ci // NOTE: This logic will be optimized later to avoid collecting originalName into mCurrentExportNameSet under any circumstances. 3603af6ab5fSopenharmony_ci mCurrentExportNameSet.add(originalName); 3613af6ab5fSopenharmony_ci } else { 3623af6ab5fSopenharmony_ci exportOriginalNameSet.add(originalName); 3633af6ab5fSopenharmony_ci } 3643af6ab5fSopenharmony_ci return; 3653af6ab5fSopenharmony_ci } 3663af6ab5fSopenharmony_ci 3673af6ab5fSopenharmony_ci if (isClassDeclaration(expression.right) || isClassExpression(expression.right)) { 3683af6ab5fSopenharmony_ci /** 3693af6ab5fSopenharmony_ci * module.exports.A = class testClass {} 3703af6ab5fSopenharmony_ci * module.exports = class testClass {} 3713af6ab5fSopenharmony_ci * exports.A = class testClass {} 3723af6ab5fSopenharmony_ci * module.exports.A = class {} 3733af6ab5fSopenharmony_ci */ 3743af6ab5fSopenharmony_ci getClassProperties(expression.right, mCurrentExportedPropertySet); 3753af6ab5fSopenharmony_ci return; 3763af6ab5fSopenharmony_ci } 3773af6ab5fSopenharmony_ci 3783af6ab5fSopenharmony_ci if (isObjectLiteralExpression(expression.right)) { 3793af6ab5fSopenharmony_ci /** 3803af6ab5fSopenharmony_ci * module.exports = {a, b, c}; 3813af6ab5fSopenharmony_ci * module.exports.A = {a, b, c}; 3823af6ab5fSopenharmony_ci * exports.A = {a, b, c} 3833af6ab5fSopenharmony_ci */ 3843af6ab5fSopenharmony_ci getObjectProperties(expression.right, mCurrentExportedPropertySet); 3853af6ab5fSopenharmony_ci // module.exports = {a, b, c}, {a, b, c} as the export content of the module 3863af6ab5fSopenharmony_ci let defaultExport = left.expression.getText() === 'module'; 3873af6ab5fSopenharmony_ci if (defaultExport) { 3883af6ab5fSopenharmony_ci getObjectExportNames(expression.right, mCurrentExportNameSet); 3893af6ab5fSopenharmony_ci } 3903af6ab5fSopenharmony_ci return; 3913af6ab5fSopenharmony_ci } 3923af6ab5fSopenharmony_ci 3933af6ab5fSopenharmony_ci return; 3943af6ab5fSopenharmony_ci }; 3953af6ab5fSopenharmony_ci 3963af6ab5fSopenharmony_ci function isModuleExports(leftExpression: ElementAccessExpression | PropertyAccessExpression): boolean { 3973af6ab5fSopenharmony_ci let leftExpressionText = leftExpression.expression.getText(); 3983af6ab5fSopenharmony_ci if (isPropertyAccessExpression(leftExpression.expression)) { 3993af6ab5fSopenharmony_ci /** 4003af6ab5fSopenharmony_ci * For example: 4013af6ab5fSopenharmony_ci * module.exports.a = A; 4023af6ab5fSopenharmony_ci * module.exports['a'] = A; 4033af6ab5fSopenharmony_ci */ 4043af6ab5fSopenharmony_ci return leftExpressionText === 'module.exports'; 4053af6ab5fSopenharmony_ci } 4063af6ab5fSopenharmony_ci if (isIdentifier(leftExpression.expression)) { 4073af6ab5fSopenharmony_ci if (leftExpressionText === 'module') { 4083af6ab5fSopenharmony_ci // module.exports = {A}, A as the export content of the module 4093af6ab5fSopenharmony_ci if (isPropertyAccessExpression(leftExpression) && leftExpression.name.getText() === 'exports') { 4103af6ab5fSopenharmony_ci return true; 4113af6ab5fSopenharmony_ci } 4123af6ab5fSopenharmony_ci } 4133af6ab5fSopenharmony_ci 4143af6ab5fSopenharmony_ci /** 4153af6ab5fSopenharmony_ci * For example: 4163af6ab5fSopenharmony_ci * exports.a = A; 4173af6ab5fSopenharmony_ci */ 4183af6ab5fSopenharmony_ci return leftExpressionText === 'exports'; 4193af6ab5fSopenharmony_ci } 4203af6ab5fSopenharmony_ci return false; 4213af6ab5fSopenharmony_ci }; 4223af6ab5fSopenharmony_ci 4233af6ab5fSopenharmony_ci /** 4243af6ab5fSopenharmony_ci * extract project export name 4253af6ab5fSopenharmony_ci * - export {xxx, xxx}; 4263af6ab5fSopenharmony_ci * - export {xxx as xx, xxx as xx}; 4273af6ab5fSopenharmony_ci * - export default function/class/...{}; 4283af6ab5fSopenharmony_ci * - export class xxx{} 4293af6ab5fSopenharmony_ci * - ... 4303af6ab5fSopenharmony_ci * @param astNode 4313af6ab5fSopenharmony_ci */ 4323af6ab5fSopenharmony_ci const visitProjectExport = function (astNode, isRemoteHarFile: boolean): void { 4333af6ab5fSopenharmony_ci if (isExportAssignment(astNode)) { 4343af6ab5fSopenharmony_ci handleExportAssignment(astNode); 4353af6ab5fSopenharmony_ci return; 4363af6ab5fSopenharmony_ci } 4373af6ab5fSopenharmony_ci 4383af6ab5fSopenharmony_ci if (isExportDeclaration(astNode)) { 4393af6ab5fSopenharmony_ci handleExportDeclaration(astNode, isRemoteHarFile); 4403af6ab5fSopenharmony_ci return; 4413af6ab5fSopenharmony_ci } 4423af6ab5fSopenharmony_ci 4433af6ab5fSopenharmony_ci let {hasExport} = getKeyword(astNode.modifiers); 4443af6ab5fSopenharmony_ci if (!hasExport) { 4453af6ab5fSopenharmony_ci addCommonJsExports(astNode, isRemoteHarFile); 4463af6ab5fSopenharmony_ci forEachChild(astNode, node => visitProjectExport(node, isRemoteHarFile)); 4473af6ab5fSopenharmony_ci return; 4483af6ab5fSopenharmony_ci } 4493af6ab5fSopenharmony_ci 4503af6ab5fSopenharmony_ci if (astNode.name) { 4513af6ab5fSopenharmony_ci if (!mCurrentExportNameSet.has(astNode.name.getText())) { 4523af6ab5fSopenharmony_ci mCurrentExportNameSet.add(astNode.name.getText()); 4533af6ab5fSopenharmony_ci mCurrentExportedPropertySet.add(astNode.name.getText()); 4543af6ab5fSopenharmony_ci } 4553af6ab5fSopenharmony_ci 4563af6ab5fSopenharmony_ci forEachChild(astNode, node => visitProjectExport(node, isRemoteHarFile)); 4573af6ab5fSopenharmony_ci return; 4583af6ab5fSopenharmony_ci } 4593af6ab5fSopenharmony_ci 4603af6ab5fSopenharmony_ci if (isClassDeclaration(astNode)) { 4613af6ab5fSopenharmony_ci getClassProperties(astNode, mCurrentExportedPropertySet); 4623af6ab5fSopenharmony_ci return; 4633af6ab5fSopenharmony_ci } 4643af6ab5fSopenharmony_ci 4653af6ab5fSopenharmony_ci if (isVariableStatement(astNode)) { 4663af6ab5fSopenharmony_ci astNode.declarationList.forEachChild((child) => { 4673af6ab5fSopenharmony_ci if (isVariableDeclaration(child) && !mCurrentExportNameSet.has(child.name.getText())) { 4683af6ab5fSopenharmony_ci mCurrentExportNameSet.add(child.name.getText()); 4693af6ab5fSopenharmony_ci mCurrentExportedPropertySet.add(child.name.getText()); 4703af6ab5fSopenharmony_ci } 4713af6ab5fSopenharmony_ci }); 4723af6ab5fSopenharmony_ci 4733af6ab5fSopenharmony_ci return; 4743af6ab5fSopenharmony_ci } 4753af6ab5fSopenharmony_ci 4763af6ab5fSopenharmony_ci forEachChild(astNode, node => visitProjectExport(node, isRemoteHarFile)); 4773af6ab5fSopenharmony_ci }; 4783af6ab5fSopenharmony_ci 4793af6ab5fSopenharmony_ci function handleExportAssignment(astNode): void { 4803af6ab5fSopenharmony_ci // let xxx; export default xxx = a; 4813af6ab5fSopenharmony_ci if (isBinaryExpression(astNode.expression)) { 4823af6ab5fSopenharmony_ci if (isObjectLiteralExpression(astNode.expression.right)) { 4833af6ab5fSopenharmony_ci getObjectProperties(astNode.expression.right, mCurrentExportedPropertySet); 4843af6ab5fSopenharmony_ci return; 4853af6ab5fSopenharmony_ci } 4863af6ab5fSopenharmony_ci 4873af6ab5fSopenharmony_ci if (isClassExpression(astNode.expression.right)) { 4883af6ab5fSopenharmony_ci getClassProperties(astNode.expression.right, mCurrentExportedPropertySet); 4893af6ab5fSopenharmony_ci } 4903af6ab5fSopenharmony_ci 4913af6ab5fSopenharmony_ci return; 4923af6ab5fSopenharmony_ci } 4933af6ab5fSopenharmony_ci 4943af6ab5fSopenharmony_ci // export = xxx; The xxx here can't be obfuscated 4953af6ab5fSopenharmony_ci // export default yyy; The yyy here can be obfuscated 4963af6ab5fSopenharmony_ci if (isIdentifier(astNode.expression)) { 4973af6ab5fSopenharmony_ci if (!mCurrentExportNameSet.has(astNode.expression.getText())) { 4983af6ab5fSopenharmony_ci mCurrentExportNameSet.add(astNode.expression.getText()); 4993af6ab5fSopenharmony_ci mCurrentExportedPropertySet.add(astNode.expression.getText()); 5003af6ab5fSopenharmony_ci } 5013af6ab5fSopenharmony_ci return; 5023af6ab5fSopenharmony_ci } 5033af6ab5fSopenharmony_ci 5043af6ab5fSopenharmony_ci if (isObjectLiteralExpression(astNode.expression)) { 5053af6ab5fSopenharmony_ci getObjectProperties(astNode.expression, mCurrentExportedPropertySet); 5063af6ab5fSopenharmony_ci } 5073af6ab5fSopenharmony_ci } 5083af6ab5fSopenharmony_ci 5093af6ab5fSopenharmony_ci function handleExportDeclaration(astNode: ExportDeclaration, isRemoteHarFile: boolean): void { 5103af6ab5fSopenharmony_ci if (astNode.exportClause) { 5113af6ab5fSopenharmony_ci if (astNode.exportClause.kind === SyntaxKind.NamedExports) { 5123af6ab5fSopenharmony_ci astNode.exportClause.forEachChild((child) => { 5133af6ab5fSopenharmony_ci if (!isExportSpecifier(child)) { 5143af6ab5fSopenharmony_ci return; 5153af6ab5fSopenharmony_ci } 5163af6ab5fSopenharmony_ci 5173af6ab5fSopenharmony_ci if (child.propertyName) { 5183af6ab5fSopenharmony_ci let originalName = child.propertyName.getText(); 5193af6ab5fSopenharmony_ci if (isRemoteHarFile || astNode.moduleSpecifier) { 5203af6ab5fSopenharmony_ci // For the first condition, this ensures that for remoteHar files, 5213af6ab5fSopenharmony_ci // originalName is still collected into mCurrentExportNameSet to maintain compatibility. 5223af6ab5fSopenharmony_ci // NOTE: This specification needs to be revised to determine whether to add originalName 5233af6ab5fSopenharmony_ci // to mCurrentExportNameSet should be independent of whether it is in a remoteHar file. 5243af6ab5fSopenharmony_ci 5253af6ab5fSopenharmony_ci // The second condition indicates that for `export {A as B} from './filePath'` statements, 5263af6ab5fSopenharmony_ci // the original name (A) needs to be added to the export whitelist. 5273af6ab5fSopenharmony_ci mCurrentExportNameSet.add(originalName); 5283af6ab5fSopenharmony_ci } else { 5293af6ab5fSopenharmony_ci /** 5303af6ab5fSopenharmony_ci * In project source code: 5313af6ab5fSopenharmony_ci * class A { 5323af6ab5fSopenharmony_ci * prop1 = 1; 5333af6ab5fSopenharmony_ci * prop2 = 2; 5343af6ab5fSopenharmony_ci * } 5353af6ab5fSopenharmony_ci * export {A as B}; // collect A to ensure we can collect prop1 and prop2 5363af6ab5fSopenharmony_ci */ 5373af6ab5fSopenharmony_ci exportOriginalNameSet.add(originalName); 5383af6ab5fSopenharmony_ci } 5393af6ab5fSopenharmony_ci } 5403af6ab5fSopenharmony_ci 5413af6ab5fSopenharmony_ci let exportName = child.name.getText(); 5423af6ab5fSopenharmony_ci mCurrentExportedPropertySet.add(exportName); 5433af6ab5fSopenharmony_ci mCurrentExportNameSet.add(exportName); 5443af6ab5fSopenharmony_ci }); 5453af6ab5fSopenharmony_ci } 5463af6ab5fSopenharmony_ci 5473af6ab5fSopenharmony_ci if (astNode.exportClause.kind === SyntaxKind.NamespaceExport) { 5483af6ab5fSopenharmony_ci mCurrentExportedPropertySet.add(astNode.exportClause.name.getText()); 5493af6ab5fSopenharmony_ci return; 5503af6ab5fSopenharmony_ci } 5513af6ab5fSopenharmony_ci } 5523af6ab5fSopenharmony_ci } 5533af6ab5fSopenharmony_ci 5543af6ab5fSopenharmony_ci /** 5553af6ab5fSopenharmony_ci * extract the class, enum, and object properties of the export in the project before obfuscation 5563af6ab5fSopenharmony_ci * class A{}; 5573af6ab5fSopenharmony_ci * export = A; need to be considered 5583af6ab5fSopenharmony_ci * export = namespace; 5593af6ab5fSopenharmony_ci * This statement also needs to determine whether there is an export in the namespace, and namespaces are also allowed in the namespace 5603af6ab5fSopenharmony_ci * @param astNode 5613af6ab5fSopenharmony_ci */ 5623af6ab5fSopenharmony_ci const visitProjectNode = function (astNode): void { 5633af6ab5fSopenharmony_ci const currentPropsSet: Set<string> = new Set(); 5643af6ab5fSopenharmony_ci let nodeName: string | undefined = astNode.name?.text; 5653af6ab5fSopenharmony_ci if ((isClassDeclaration(astNode) || isStructDeclaration(astNode))) { 5663af6ab5fSopenharmony_ci getClassProperties(astNode, currentPropsSet); 5673af6ab5fSopenharmony_ci } else if (isEnumDeclaration(astNode)) { // collect export enum structure properties 5683af6ab5fSopenharmony_ci getEnumProperties(astNode, currentPropsSet); 5693af6ab5fSopenharmony_ci } else if (isVariableDeclaration(astNode)) { 5703af6ab5fSopenharmony_ci if (astNode.initializer) { 5713af6ab5fSopenharmony_ci if (isObjectLiteralExpression(astNode.initializer)) { 5723af6ab5fSopenharmony_ci getObjectProperties(astNode.initializer, currentPropsSet); 5733af6ab5fSopenharmony_ci } else if (isClassExpression(astNode.initializer)) { 5743af6ab5fSopenharmony_ci getClassProperties(astNode.initializer, currentPropsSet); 5753af6ab5fSopenharmony_ci } 5763af6ab5fSopenharmony_ci } 5773af6ab5fSopenharmony_ci nodeName = astNode.name?.getText(); 5783af6ab5fSopenharmony_ci } else if (isInterfaceDeclaration(astNode)) { 5793af6ab5fSopenharmony_ci getInterfaceProperties(astNode, currentPropsSet); 5803af6ab5fSopenharmony_ci } else if (isTypeAliasDeclaration(astNode)) { 5813af6ab5fSopenharmony_ci getTypeAliasProperties(astNode, currentPropsSet); 5823af6ab5fSopenharmony_ci } else if (isElementAccessExpression(astNode)) { 5833af6ab5fSopenharmony_ci getElementAccessExpressionProperties(astNode, currentPropsSet); 5843af6ab5fSopenharmony_ci } else if (isObjectLiteralExpression(astNode)) { 5853af6ab5fSopenharmony_ci getObjectProperties(astNode, currentPropsSet); 5863af6ab5fSopenharmony_ci } else if (isClassExpression(astNode)) { 5873af6ab5fSopenharmony_ci getClassProperties(astNode, currentPropsSet); 5883af6ab5fSopenharmony_ci } 5893af6ab5fSopenharmony_ci 5903af6ab5fSopenharmony_ci addPropWhiteList(nodeName, astNode, currentPropsSet); 5913af6ab5fSopenharmony_ci 5923af6ab5fSopenharmony_ci forEachChild(astNode, visitProjectNode); 5933af6ab5fSopenharmony_ci }; 5943af6ab5fSopenharmony_ci 5953af6ab5fSopenharmony_ci function addPropWhiteList(nodeName: string | undefined, astNode: Node, currentPropsSet: Set<string>): void { 5963af6ab5fSopenharmony_ci if (nodeName && (mCurrentExportNameSet.has(nodeName) || exportOriginalNameSet.has(nodeName))) { 5973af6ab5fSopenharmony_ci addElement(currentPropsSet); 5983af6ab5fSopenharmony_ci } 5993af6ab5fSopenharmony_ci 6003af6ab5fSopenharmony_ci if (scanProjectConfig.isHarCompiled && scanProjectConfig.mPropertyObfuscation && isEnumDeclaration(astNode)) { 6013af6ab5fSopenharmony_ci addEnumElement(currentPropsSet); 6023af6ab5fSopenharmony_ci } 6033af6ab5fSopenharmony_ci } 6043af6ab5fSopenharmony_ci 6053af6ab5fSopenharmony_ci function addElement(currentPropsSet: Set<string>): void { 6063af6ab5fSopenharmony_ci currentPropsSet.forEach((element: string) => { 6073af6ab5fSopenharmony_ci mCurrentExportedPropertySet.add(element); 6083af6ab5fSopenharmony_ci }); 6093af6ab5fSopenharmony_ci } 6103af6ab5fSopenharmony_ci 6113af6ab5fSopenharmony_ci function addEnumElement(currentPropsSet: Set<string>): void { 6123af6ab5fSopenharmony_ci currentPropsSet.forEach((element: string) => { 6133af6ab5fSopenharmony_ci enumPropsSet.add(element); 6143af6ab5fSopenharmony_ci }); 6153af6ab5fSopenharmony_ci } 6163af6ab5fSopenharmony_ci /** 6173af6ab5fSopenharmony_ci * parse file to api list and save to json object 6183af6ab5fSopenharmony_ci * @param fileName file name of api file 6193af6ab5fSopenharmony_ci * @param apiType 6203af6ab5fSopenharmony_ci * @private 6213af6ab5fSopenharmony_ci */ 6223af6ab5fSopenharmony_ci const parseFile = function (fileName: string, apiType: ApiType): void { 6233af6ab5fSopenharmony_ci if (!FileUtils.isReadableFile(fileName) || !isParsableFile(fileName)) { 6243af6ab5fSopenharmony_ci return; 6253af6ab5fSopenharmony_ci } 6263af6ab5fSopenharmony_ci 6273af6ab5fSopenharmony_ci const sourceFile: SourceFile = createSourceFile(fileName, fs.readFileSync(fileName).toString(), ScriptTarget.ES2015, true); 6283af6ab5fSopenharmony_ci mCurrentExportedPropertySet.clear(); 6293af6ab5fSopenharmony_ci // get export name list 6303af6ab5fSopenharmony_ci switch (apiType) { 6313af6ab5fSopenharmony_ci case ApiType.COMPONENT: 6323af6ab5fSopenharmony_ci forEachChild(sourceFile, visitChildNode); 6333af6ab5fSopenharmony_ci break; 6343af6ab5fSopenharmony_ci case ApiType.API: 6353af6ab5fSopenharmony_ci mCurrentExportNameSet.clear(); 6363af6ab5fSopenharmony_ci forEachChild(sourceFile, node => visitExport(node, true)); 6373af6ab5fSopenharmony_ci mCurrentExportNameSet.forEach(item => mSystemExportSet.add(item)); 6383af6ab5fSopenharmony_ci 6393af6ab5fSopenharmony_ci forEachChild(sourceFile, visitPropertyAndName); 6403af6ab5fSopenharmony_ci mCurrentExportNameSet.clear(); 6413af6ab5fSopenharmony_ci break; 6423af6ab5fSopenharmony_ci case ApiType.PROJECT_DEPENDS: 6433af6ab5fSopenharmony_ci case ApiType.PROJECT: 6443af6ab5fSopenharmony_ci mCurrentExportNameSet.clear(); 6453af6ab5fSopenharmony_ci if (fileName.endsWith('.d.ts') || fileName.endsWith('.d.ets')) { 6463af6ab5fSopenharmony_ci forEachChild(sourceFile, visitChildNode); 6473af6ab5fSopenharmony_ci } 6483af6ab5fSopenharmony_ci 6493af6ab5fSopenharmony_ci let isRemoteHarFile = isRemoteHar(fileName); 6503af6ab5fSopenharmony_ci forEachChild(sourceFile, node => visitProjectExport(node, isRemoteHarFile)); 6513af6ab5fSopenharmony_ci forEachChild(sourceFile, visitProjectNode); 6523af6ab5fSopenharmony_ci mCurrentExportedPropertySet = handleWhiteListWhenExportObfs(fileName, mCurrentExportedPropertySet); 6533af6ab5fSopenharmony_ci mCurrentExportNameSet = handleWhiteListWhenExportObfs(fileName, mCurrentExportNameSet); 6543af6ab5fSopenharmony_ci break; 6553af6ab5fSopenharmony_ci case ApiType.CONSTRUCTOR_PROPERTY: 6563af6ab5fSopenharmony_ci forEachChild(sourceFile, visitNodeForConstructorProperty); 6573af6ab5fSopenharmony_ci break; 6583af6ab5fSopenharmony_ci default: 6593af6ab5fSopenharmony_ci break; 6603af6ab5fSopenharmony_ci } 6613af6ab5fSopenharmony_ci 6623af6ab5fSopenharmony_ci // collect export names. 6633af6ab5fSopenharmony_ci mCurrentExportNameSet.forEach(item => mExportNames.add(item)); 6643af6ab5fSopenharmony_ci mCurrentExportNameSet.clear(); 6653af6ab5fSopenharmony_ci // collect export names and properties. 6663af6ab5fSopenharmony_ci mCurrentExportedPropertySet.forEach(item => mPropertySet.add(item)); 6673af6ab5fSopenharmony_ci mCurrentExportedPropertySet.clear(); 6683af6ab5fSopenharmony_ci exportOriginalNameSet.clear(); 6693af6ab5fSopenharmony_ci }; 6703af6ab5fSopenharmony_ci 6713af6ab5fSopenharmony_ci function handleWhiteListWhenExportObfs(fileName: string, collectedExportNamesAndProperties: Set<string>): Set<string> { 6723af6ab5fSopenharmony_ci // If mExportObfuscation is not enabled, collect the export names and their properties into the whitelist. 6733af6ab5fSopenharmony_ci if (!scanProjectConfig.mExportObfuscation) { 6743af6ab5fSopenharmony_ci return collectedExportNamesAndProperties; 6753af6ab5fSopenharmony_ci } 6763af6ab5fSopenharmony_ci // If the current file is a keep file or its dependent file, collect the export names and their properties into the whitelist. 6773af6ab5fSopenharmony_ci if (scanProjectConfig.mkeepFilesAndDependencies?.has(fileName)) { 6783af6ab5fSopenharmony_ci return collectedExportNamesAndProperties; 6793af6ab5fSopenharmony_ci } 6803af6ab5fSopenharmony_ci // If it is a project source code file, the names and their properties of the export will not be collected. 6813af6ab5fSopenharmony_ci if (!isRemoteHar(fileName)) { 6823af6ab5fSopenharmony_ci collectedExportNamesAndProperties.clear(); 6833af6ab5fSopenharmony_ci return collectedExportNamesAndProperties; 6843af6ab5fSopenharmony_ci } 6853af6ab5fSopenharmony_ci // If it is a third-party library file. 6863af6ab5fSopenharmony_ci return collectedExportNamesAndProperties; 6873af6ab5fSopenharmony_ci } 6883af6ab5fSopenharmony_ci 6893af6ab5fSopenharmony_ci const projectExtensions: string[] = ['.ets', '.ts', '.js']; 6903af6ab5fSopenharmony_ci const projectDependencyExtensions: string[] = ['.d.ets', '.d.ts', '.ets', '.ts', '.js']; 6913af6ab5fSopenharmony_ci const resolvedModules = new Set(); 6923af6ab5fSopenharmony_ci 6933af6ab5fSopenharmony_ci function tryGetPackageID(filePath: string): string { 6943af6ab5fSopenharmony_ci const ohPackageJsonPath = path.join(filePath, 'oh-package.json5'); 6953af6ab5fSopenharmony_ci let packgeNameAndVersion = ''; 6963af6ab5fSopenharmony_ci if (fs.existsSync(ohPackageJsonPath)) { 6973af6ab5fSopenharmony_ci const ohPackageContent = json5.parse(fs.readFileSync(ohPackageJsonPath, 'utf-8')); 6983af6ab5fSopenharmony_ci packgeNameAndVersion = ohPackageContent.name + ohPackageContent.version; 6993af6ab5fSopenharmony_ci } 7003af6ab5fSopenharmony_ci return packgeNameAndVersion; 7013af6ab5fSopenharmony_ci } 7023af6ab5fSopenharmony_ci 7033af6ab5fSopenharmony_ci function traverseFilesInDir(apiPath: string, apiType: ApiType): void { 7043af6ab5fSopenharmony_ci let fileNames: string[] = fs.readdirSync(apiPath); 7053af6ab5fSopenharmony_ci for (let fileName of fileNames) { 7063af6ab5fSopenharmony_ci let filePath: string = path.join(apiPath, fileName); 7073af6ab5fSopenharmony_ci try { 7083af6ab5fSopenharmony_ci fs.accessSync(filePath, fs.constants.R_OK); 7093af6ab5fSopenharmony_ci } catch (err) { 7103af6ab5fSopenharmony_ci continue; 7113af6ab5fSopenharmony_ci } 7123af6ab5fSopenharmony_ci if (fs.statSync(filePath).isDirectory()) { 7133af6ab5fSopenharmony_ci const packgeNameAndVersion = tryGetPackageID(filePath); 7143af6ab5fSopenharmony_ci if (resolvedModules.has(packgeNameAndVersion)) { 7153af6ab5fSopenharmony_ci continue; 7163af6ab5fSopenharmony_ci } 7173af6ab5fSopenharmony_ci traverseApiFiles(filePath, apiType); 7183af6ab5fSopenharmony_ci packgeNameAndVersion.length > 0 && resolvedModules.add(packgeNameAndVersion); 7193af6ab5fSopenharmony_ci continue; 7203af6ab5fSopenharmony_ci } 7213af6ab5fSopenharmony_ci const suffix: string = path.extname(filePath); 7223af6ab5fSopenharmony_ci if ((apiType !== ApiType.PROJECT) && !projectDependencyExtensions.includes(suffix)) { 7233af6ab5fSopenharmony_ci continue; 7243af6ab5fSopenharmony_ci } 7253af6ab5fSopenharmony_ci 7263af6ab5fSopenharmony_ci if (apiType === ApiType.PROJECT && !projectExtensions.includes(suffix)) { 7273af6ab5fSopenharmony_ci continue; 7283af6ab5fSopenharmony_ci } 7293af6ab5fSopenharmony_ci parseFile(filePath, apiType); 7303af6ab5fSopenharmony_ci } 7313af6ab5fSopenharmony_ci } 7323af6ab5fSopenharmony_ci 7333af6ab5fSopenharmony_ci /** 7343af6ab5fSopenharmony_ci * traverse files of api directory 7353af6ab5fSopenharmony_ci * @param apiPath api directory path 7363af6ab5fSopenharmony_ci * @param apiType 7373af6ab5fSopenharmony_ci * @private 7383af6ab5fSopenharmony_ci */ 7393af6ab5fSopenharmony_ci export const traverseApiFiles = function (apiPath: string, apiType: ApiType): void { 7403af6ab5fSopenharmony_ci if (fs.statSync(apiPath).isDirectory()) { 7413af6ab5fSopenharmony_ci traverseFilesInDir(apiPath, apiType); 7423af6ab5fSopenharmony_ci } else { 7433af6ab5fSopenharmony_ci parseFile(apiPath, apiType); 7443af6ab5fSopenharmony_ci } 7453af6ab5fSopenharmony_ci }; 7463af6ab5fSopenharmony_ci 7473af6ab5fSopenharmony_ci /** 7483af6ab5fSopenharmony_ci * desc: parse openHarmony sdk to get api list 7493af6ab5fSopenharmony_ci * @param version version of api, e.g. version 5.0.1.0 for api 9 7503af6ab5fSopenharmony_ci * @param sdkPath sdk real path of openHarmony 7513af6ab5fSopenharmony_ci * @param isEts true for ets, false for js 7523af6ab5fSopenharmony_ci * @param outputDir: sdk api output directory 7533af6ab5fSopenharmony_ci */ 7543af6ab5fSopenharmony_ci export function parseOhSdk(sdkPath: string, version: string, isEts: boolean, outputDir: string): void { 7553af6ab5fSopenharmony_ci mPropertySet.clear(); 7563af6ab5fSopenharmony_ci 7573af6ab5fSopenharmony_ci // visit api directory 7583af6ab5fSopenharmony_ci const apiPath: string = path.join(sdkPath, (isEts ? 'ets' : 'js'), version, 'api'); 7593af6ab5fSopenharmony_ci traverseApiFiles(apiPath, ApiType.API); 7603af6ab5fSopenharmony_ci 7613af6ab5fSopenharmony_ci // visit component directory if ets 7623af6ab5fSopenharmony_ci if (isEts) { 7633af6ab5fSopenharmony_ci const componentPath: string = path.join(sdkPath, 'ets', version, 'component'); 7643af6ab5fSopenharmony_ci traverseApiFiles(componentPath, ApiType.COMPONENT); 7653af6ab5fSopenharmony_ci } 7663af6ab5fSopenharmony_ci 7673af6ab5fSopenharmony_ci // visit the UI conversion API 7683af6ab5fSopenharmony_ci const uiConversionPath: string = path.join(sdkPath, (isEts ? 'ets' : 'js'), version, 7693af6ab5fSopenharmony_ci 'build-tools', 'ets-loader', 'lib', 'pre_define.js'); 7703af6ab5fSopenharmony_ci extractStringsFromFile(uiConversionPath); 7713af6ab5fSopenharmony_ci 7723af6ab5fSopenharmony_ci const reservedProperties: string[] = [...mPropertySet.values()]; 7733af6ab5fSopenharmony_ci mPropertySet.clear(); 7743af6ab5fSopenharmony_ci 7753af6ab5fSopenharmony_ci writeToFile(reservedProperties, path.join(outputDir, 'propertiesReserved.json')); 7763af6ab5fSopenharmony_ci } 7773af6ab5fSopenharmony_ci 7783af6ab5fSopenharmony_ci export function extractStringsFromFile(filePath: string): void { 7793af6ab5fSopenharmony_ci let collections: string[] = []; 7803af6ab5fSopenharmony_ci const fileContent = fs.readFileSync(filePath, 'utf-8'); 7813af6ab5fSopenharmony_ci const regex = /"([^"]*)"/g; 7823af6ab5fSopenharmony_ci const matches = fileContent.match(regex); 7833af6ab5fSopenharmony_ci 7843af6ab5fSopenharmony_ci if (matches) { 7853af6ab5fSopenharmony_ci collections = matches.map(match => match.slice(1, -1)); 7863af6ab5fSopenharmony_ci } 7873af6ab5fSopenharmony_ci 7883af6ab5fSopenharmony_ci collections.forEach(name => mPropertySet.add(name)); 7893af6ab5fSopenharmony_ci } 7903af6ab5fSopenharmony_ci 7913af6ab5fSopenharmony_ci /** 7923af6ab5fSopenharmony_ci * save api json object to file 7933af6ab5fSopenharmony_ci * @private 7943af6ab5fSopenharmony_ci */ 7953af6ab5fSopenharmony_ci export function writeToFile(reservedProperties: string[], outputPath: string): void { 7963af6ab5fSopenharmony_ci let str: string = JSON.stringify(reservedProperties, null, '\t'); 7973af6ab5fSopenharmony_ci fs.writeFileSync(outputPath, str); 7983af6ab5fSopenharmony_ci } 7993af6ab5fSopenharmony_ci 8003af6ab5fSopenharmony_ci export function isRemoteHar(filePath: string): boolean { 8013af6ab5fSopenharmony_ci const realPath: string = sys.realpath(filePath); 8023af6ab5fSopenharmony_ci return isInOhModuleFile(realPath); 8033af6ab5fSopenharmony_ci } 8043af6ab5fSopenharmony_ci 8053af6ab5fSopenharmony_ci export function isInOhModuleFile(filePath: string): boolean { 8063af6ab5fSopenharmony_ci return filePath.indexOf('/oh_modules/') !== -1 || filePath.indexOf('\\oh_modules\\') !== -1; 8073af6ab5fSopenharmony_ci } 8083af6ab5fSopenharmony_ci 8093af6ab5fSopenharmony_ci export function isParsableFile(path: string): boolean { 8103af6ab5fSopenharmony_ci return supportedParsingExtension.some(extension => path.endsWith(extension)); 8113af6ab5fSopenharmony_ci } 8123af6ab5fSopenharmony_ci 8133af6ab5fSopenharmony_ci /** 8143af6ab5fSopenharmony_ci * parse common project or file to extract exported api list 8153af6ab5fSopenharmony_ci * @return reserved api names 8163af6ab5fSopenharmony_ci */ 8173af6ab5fSopenharmony_ci export function parseFileByPaths(projectPaths: Set<string>, scanningApiType: ApiType): 8183af6ab5fSopenharmony_ci {reservedExportPropertyAndName: Set<string> | undefined; reservedExportNames: Set<string> | undefined} { 8193af6ab5fSopenharmony_ci mPropertySet.clear(); 8203af6ab5fSopenharmony_ci mExportNames.clear(); 8213af6ab5fSopenharmony_ci projectPaths.forEach(path => { 8223af6ab5fSopenharmony_ci parseFile(path, scanningApiType); 8233af6ab5fSopenharmony_ci }); 8243af6ab5fSopenharmony_ci let reservedExportPropertyAndName: Set<string>; 8253af6ab5fSopenharmony_ci let reservedExportNames: Set<string>; 8263af6ab5fSopenharmony_ci if (scanProjectConfig.mPropertyObfuscation) { 8273af6ab5fSopenharmony_ci reservedExportPropertyAndName = new Set(mPropertySet); 8283af6ab5fSopenharmony_ci } 8293af6ab5fSopenharmony_ci if (scanProjectConfig.mExportObfuscation) { 8303af6ab5fSopenharmony_ci reservedExportNames = new Set(mExportNames); 8313af6ab5fSopenharmony_ci } 8323af6ab5fSopenharmony_ci mPropertySet.clear(); 8333af6ab5fSopenharmony_ci mExportNames.clear(); 8343af6ab5fSopenharmony_ci return { 8353af6ab5fSopenharmony_ci reservedExportPropertyAndName: reservedExportPropertyAndName, 8363af6ab5fSopenharmony_ci reservedExportNames: reservedExportNames 8373af6ab5fSopenharmony_ci }; 8383af6ab5fSopenharmony_ci } 8393af6ab5fSopenharmony_ci 8403af6ab5fSopenharmony_ci /** 8413af6ab5fSopenharmony_ci * Collect all property names in the AST. 8423af6ab5fSopenharmony_ci * @param astNode Nodes of the AST. 8433af6ab5fSopenharmony_ci */ 8443af6ab5fSopenharmony_ci function collectPropertyNames(astNode: Node): void { 8453af6ab5fSopenharmony_ci visitElementsWithProperties(astNode); 8463af6ab5fSopenharmony_ci } 8473af6ab5fSopenharmony_ci 8483af6ab5fSopenharmony_ci /** 8493af6ab5fSopenharmony_ci * Visit elements that can contain properties. 8503af6ab5fSopenharmony_ci * @param node The current AST node. 8513af6ab5fSopenharmony_ci */ 8523af6ab5fSopenharmony_ci function visitElementsWithProperties(node: Node): void { 8533af6ab5fSopenharmony_ci switch (node.kind) { 8543af6ab5fSopenharmony_ci case SyntaxKind.ClassDeclaration: 8553af6ab5fSopenharmony_ci forEachChild(node, visitClass); 8563af6ab5fSopenharmony_ci break; 8573af6ab5fSopenharmony_ci case SyntaxKind.InterfaceDeclaration: 8583af6ab5fSopenharmony_ci case SyntaxKind.TypeLiteral: 8593af6ab5fSopenharmony_ci forEachChild(node, visitInterfaceOrType); 8603af6ab5fSopenharmony_ci break; 8613af6ab5fSopenharmony_ci case SyntaxKind.EnumDeclaration: 8623af6ab5fSopenharmony_ci forEachChild(node, visitEnum); 8633af6ab5fSopenharmony_ci break; 8643af6ab5fSopenharmony_ci case SyntaxKind.ObjectLiteralExpression: 8653af6ab5fSopenharmony_ci forEachChild(node, visitObjectLiteral); 8663af6ab5fSopenharmony_ci break; 8673af6ab5fSopenharmony_ci case SyntaxKind.ModuleDeclaration: 8683af6ab5fSopenharmony_ci forEachChild(node, visitModule); 8693af6ab5fSopenharmony_ci break; 8703af6ab5fSopenharmony_ci } 8713af6ab5fSopenharmony_ci forEachChild(node, visitElementsWithProperties); 8723af6ab5fSopenharmony_ci } 8733af6ab5fSopenharmony_ci 8743af6ab5fSopenharmony_ci function visitClass(node: Node): void { 8753af6ab5fSopenharmony_ci if (isPropertyDeclaration(node) || isMethodDeclaration(node)) { 8763af6ab5fSopenharmony_ci if (isIdentifier(node.name)) { 8773af6ab5fSopenharmony_ci mCurrentExportedPropertySet.add(node.name.text); 8783af6ab5fSopenharmony_ci } 8793af6ab5fSopenharmony_ci } 8803af6ab5fSopenharmony_ci forEachChild(node, visitClass); 8813af6ab5fSopenharmony_ci } 8823af6ab5fSopenharmony_ci 8833af6ab5fSopenharmony_ci function visitInterfaceOrType(node: Node): void { 8843af6ab5fSopenharmony_ci if (isPropertySignature(node) || isMethodSignature(node)) { 8853af6ab5fSopenharmony_ci if (isIdentifier(node.name)) { 8863af6ab5fSopenharmony_ci mCurrentExportedPropertySet.add(node.name.text); 8873af6ab5fSopenharmony_ci } 8883af6ab5fSopenharmony_ci } 8893af6ab5fSopenharmony_ci forEachChild(node, visitInterfaceOrType); 8903af6ab5fSopenharmony_ci } 8913af6ab5fSopenharmony_ci 8923af6ab5fSopenharmony_ci function visitEnum(node: Node): void { 8933af6ab5fSopenharmony_ci if (isEnumMember(node) && isIdentifier(node.name)) { 8943af6ab5fSopenharmony_ci mCurrentExportedPropertySet.add(node.name.text); 8953af6ab5fSopenharmony_ci } 8963af6ab5fSopenharmony_ci } 8973af6ab5fSopenharmony_ci 8983af6ab5fSopenharmony_ci function visitObjectLiteral(node: Node): void { 8993af6ab5fSopenharmony_ci if (isPropertyAssignment(node)) { 9003af6ab5fSopenharmony_ci if (isIdentifier(node.name)) { 9013af6ab5fSopenharmony_ci mCurrentExportedPropertySet.add(node.name.text); 9023af6ab5fSopenharmony_ci } 9033af6ab5fSopenharmony_ci } 9043af6ab5fSopenharmony_ci forEachChild(node, visitObjectLiteral); 9053af6ab5fSopenharmony_ci } 9063af6ab5fSopenharmony_ci 9073af6ab5fSopenharmony_ci function visitModule(node: Node): void { 9083af6ab5fSopenharmony_ci forEachChild(node, visitElementsWithProperties); 9093af6ab5fSopenharmony_ci } 9103af6ab5fSopenharmony_ci 9113af6ab5fSopenharmony_ci function collectNodeName(name: string): void { 9123af6ab5fSopenharmony_ci mCurrentExportNameSet.add(name); 9133af6ab5fSopenharmony_ci mCurrentExportedPropertySet.add(name); 9143af6ab5fSopenharmony_ci } 9153af6ab5fSopenharmony_ci} 916