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