diff --git a/OAT.xml b/OAT.xml
index 60823ce49d78d126eff09f60448d4aa7d1e3497a..df35b64bc4871f88adf1867e0c866a0b28181ca0 100644
--- a/OAT.xml
+++ b/OAT.xml
@@ -27,6 +27,7 @@
+
diff --git a/arkui_noninterop_plugin/.gitignore b/arkui_noninterop_plugin/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..eada254a5130310fd4a3f7acac4b3d36eecd305d
--- /dev/null
+++ b/arkui_noninterop_plugin/.gitignore
@@ -0,0 +1,6 @@
+node_modules/*
+dist/*
+dist-test/*
+package-lock.json
+tsconfig.tsbuildinfo
+ut/build/*
diff --git a/arkui_noninterop_plugin/.prettierignore b/arkui_noninterop_plugin/.prettierignore
new file mode 100644
index 0000000000000000000000000000000000000000..da6099ce5559e911814e6b9ed69fa78afecc567c
--- /dev/null
+++ b/arkui_noninterop_plugin/.prettierignore
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2025 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+dist/**
+dist-test/**
+node_modules/**
+test/target/**
+test/ut/**
+tsconfig.json
+**.json5
+**.js
+**.md
+**.ets
diff --git a/arkui_noninterop_plugin/.prettierrc.json b/arkui_noninterop_plugin/.prettierrc.json
new file mode 100644
index 0000000000000000000000000000000000000000..b7bc67defc1e53b73f89851cfed22ca9deda3b69
--- /dev/null
+++ b/arkui_noninterop_plugin/.prettierrc.json
@@ -0,0 +1,9 @@
+{
+ "singleQuote": true,
+ "arrowParens": "always",
+ "printWidth": 120,
+ "tabWidth": 2,
+ "useTabs": false,
+ "semi": true,
+ "trailingComma": "none"
+}
diff --git a/arkui_noninterop_plugin/package.json b/arkui_noninterop_plugin/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..f2a1affb1cfb455629ecfb35a9339ae4ca957909
--- /dev/null
+++ b/arkui_noninterop_plugin/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "arkui_noninterop_plugin",
+ "version": "0.1.0",
+ "description": "transform arkui sdk for ArkTS1.2 interop",
+ "keywords": [
+ "interop"
+ ],
+ "scripts": {
+ "compile": "tsc --build --verbose tsconfig.json",
+ "clean": "rimraf dist tsconfig.tsbuildinfo package-lock.json",
+ "build": "npm run clean && npm run compile",
+ "format": "npx prettier --write .",
+ "test:compile": "tsc --build --verbose test/tsconfig.json",
+ "test:clean": "rimraf dist-test test/build_add_import test/build_delete_noninterop",
+ "test:build": "npm run test:clean && npm run test:compile",
+ "build:all": "npm run build && npm run test:build",
+ "test": "npm run build:all && mocha \"dist-test/test/test.js\" --reporter-option maxDiffSize=200000",
+ "sample:clean": "rimraf test/build_sample test/build_sample_result tsconfig.tsbuildinfo",
+ "sample": "npm run sample:clean && npm run test:build && node \"dist-test/test/testSample.js\"",
+ "clean:all": "npm run clean && npm run test:clean && npm run sample:clean && rimraf node_modules"
+ },
+ "devDependencies": {
+ "@tsconfig/recommended": "^1.0.2",
+ "@types/chai": "^5.2.2",
+ "@types/mocha": "^10.0.10",
+ "@types/node": "^18.19.122",
+ "chai": "4.3.7",
+ "mocha": "10.2.0",
+ "prettier": "latest",
+ "rimraf": "^6.0.1"
+ },
+ "dependencies": {
+ "commander": "^13.1.0",
+ "fs": "^0.0.1-security",
+ "path": "^0.12.7",
+ "typescript": "npm:ohos-typescript@4.9.5-r9"
+ }
+}
diff --git a/arkui_noninterop_plugin/src/add_import/annotation.ts b/arkui_noninterop_plugin/src/add_import/annotation.ts
new file mode 100644
index 0000000000000000000000000000000000000000..68f968332ed3dcc0a06edaed839f637bed613c58
--- /dev/null
+++ b/arkui_noninterop_plugin/src/add_import/annotation.ts
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from 'path';
+import * as fs from 'fs';
+
+export default function writeAnnotationFile(inputPath: string, outputPath: string): void {
+ if (!outputPath) {
+ outputPath = inputPath;
+ }
+
+ fs.writeFileSync(path.resolve(outputPath, ANNOTATION_FILENAME), ANNOTATION, 'utf8');
+}
+
+const ANNOTATION_FILENAME: string = '@ohos.arkui.GlobalAnnotation.d.ets';
+
+const ANNOTATION: string = `
+@Retention({policy: "SOURCE"})
+export declare @interface State {};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Prop {};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Link {};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Observed {};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Track {};
+
+@Retention({policy: "SOURCE"})
+export declare @interface ObjectLink {};
+
+@Retention({policy: "SOURCE"})
+export declare @interface StorageProp {
+ property: string;
+};
+
+@Retention({policy: "SOURCE"})
+export declare @interface StorageLink {
+ property: string;
+};
+
+@Retention({policy: "SOURCE"})
+export declare @interface LocalStorageProp {
+ property: string;
+};
+
+@Retention({policy: "SOURCE"})
+export declare @interface LocalStorageLink {
+ property: string;
+};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Provide {
+ alias: string = "";
+ allowOverride: boolean = false;
+};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Consume {
+ alias: string = "";
+};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Watch {
+ callback: string;
+};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Require {};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Local {};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Param {};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Once {};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Event {};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Provider {
+ alias: string = "";
+};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Consumer {
+ alias: string = "";
+};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Monitor {
+ path: string[];
+};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Computed {};
+
+@Retention({policy: "SOURCE"})
+export declare @interface ObservedV2 {};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Trace {};
+
+@Retention({policy: "SOURCE"})
+export declare @interface Builder {}
+
+@Retention({policy: "SOURCE"})
+export declare @interface BuilderParam {}
+
+@Retention({policy: "SOURCE"})
+export declare @interface AnimatableExtend {}
+
+@Retention({policy: "SOURCE"})
+export declare @interface Styles {}
+
+@Retention({policy: "SOURCE"})
+export declare @interface Extend {
+ extend: Any
+}
+
+@Retention({policy: "SOURCE"})
+export declare @interface Type {
+ type: Any
+}
+
+@Retention({policy: "SOURCE"})
+export @interface Reusable {}
+
+@Retention({policy: "SOURCE"})
+export @interface ReusableV2 {}
+
+@Retention({policy: "SOURCE"})
+export @interface Entry {
+ routeName: string = "";
+ storage: string = "";
+ useSharedStorage: boolean = false;
+}
+
+@Retention({policy: "SOURCE"})
+export @interface Component {}
+
+@Retention({policy: "SOURCE"})
+export @interface ComponentV2 {}
+
+@Retention({policy: "SOURCE"})
+export @interface CustomDialog {}
+`;
diff --git a/arkui_noninterop_plugin/src/add_import/handle_ui_imports.ts b/arkui_noninterop_plugin/src/add_import/handle_ui_imports.ts
new file mode 100644
index 0000000000000000000000000000000000000000..739931dee81ffca974d9b3cd297048b2e21512f4
--- /dev/null
+++ b/arkui_noninterop_plugin/src/add_import/handle_ui_imports.ts
@@ -0,0 +1,683 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from 'path';
+import * as fs from 'fs';
+
+import * as ts from 'typescript';
+
+import {
+ API_PATH,
+ ARKUI_BUILDER,
+ ARKUI_EXTEND,
+ ARKUI_STYLES,
+ COMPONENT,
+ DEFAULT,
+ EXTNAME_D_ETS,
+ EXTNAME_D_TS,
+ GENERIC_T,
+ NODE_MODULES,
+ OHOS_ARKUI,
+ OHOS_ARKUI_COMPONENT,
+ OHOS_ARKUI_GLOBAL_ESVALUE,
+ OHOS_ARKUI_STATEMANAGEMENT,
+ OHOS_KIT_ARKUI,
+} from './pre_define';
+import {
+ apiDir,
+ apiInternalDir,
+ whiteList,
+ decoratorsWhiteList,
+ whiteFileList,
+} from './white_management';
+
+export default class HandleUIImports {
+ private readonly typeChecker: ts.TypeChecker;
+ private readonly context: ts.TransformationContext;
+ private readonly outPath: string;
+ private readonly inputDir: string;
+ private readonly exportFlag: boolean;
+ private readonly printer: ts.Printer;
+
+ private importedInterfaces: Set;
+ private interfacesNeedToImport: Set;
+ private readonly trueSymbolAtLocationCache: Map;
+
+ private dynamicImportCollection: Map>;
+ private dynamicImportType: Map;
+
+ private insertPosition: number;
+
+ constructor(program: ts.Program, context: ts.TransformationContext, outPath: string,
+ inputDir: string, exportFlag: boolean) {
+ this.typeChecker = program.getTypeChecker();
+ this.context = context;
+ this.outPath = outPath;
+ this.inputDir = inputDir;
+ this.exportFlag = exportFlag;
+ this.printer = ts.createPrinter();
+
+ this.importedInterfaces = new Set();
+ this.interfacesNeedToImport = new Set();
+ this.trueSymbolAtLocationCache = new Map();
+
+ this.dynamicImportCollection = new Map();
+ this.dynamicImportType = new Map();
+
+ this.insertPosition = 0;
+ }
+
+ createCustomTransformer(sourceFile: ts.SourceFile): ts.SourceFile {
+ if (sourceFile?.fileName) {
+ const name = path.basename(sourceFile.fileName, path.extname(sourceFile.fileName));
+ if (name.includes(OHOS_ARKUI_GLOBAL_ESVALUE)) {
+ if (this.outPath) {
+ this.writeSourceFileToOutPut(sourceFile);
+ }
+ if (this.exportFlag) {
+ return ts.visitNode(sourceFile, this.visitGlobalESValueNode.bind(this));
+ }
+ return sourceFile;
+ }
+ }
+
+ this.extractImportedNames(sourceFile);
+
+ const statements = sourceFile.statements;
+ for (let i = 0; i < statements.length; ++i) {
+ const statement = statements[i];
+ if (!ts.isJSDoc(statement) && !(ts.isExpressionStatement(statement) &&
+ ts.isStringLiteral(statement.expression))) {
+ this.insertPosition = i;
+ break;
+ }
+ }
+
+ return ts.visitNode(sourceFile, this.visitNode.bind(this));
+ }
+
+ visitGlobalESValueNode(node: ts.Node): ts.Node | undefined {
+ if (ts.isTypeAliasDeclaration(node) && ts.isImportTypeNode(node.type)) {
+ return this.processDynamicImportInType(node);
+ }
+
+ if (ts.isImportTypeNode(node)) {
+ return this.processDynamicImportInImportTypeNode(node);
+ }
+
+ const result = ts.visitEachChild(node, this.visitGlobalESValueNode.bind(this), this.context);
+
+ if (ts.isSourceFile(result)) {
+ this.processSourceFileForDynamicImport(node as ts.SourceFile, result);
+ }
+
+ return result;
+ }
+
+ isStructDeclaration(node: ts.Node): boolean {
+ // @ts-ignore
+ return ts.isStructDeclaration(node);
+ }
+
+ visitNode(node: ts.Node): ts.Node | undefined {
+ // @ts-ignore
+ if (node.parent && this.isStructDeclaration(node.parent) && ts.isConstructorDeclaration(node)) {
+ return undefined;
+ }
+
+ if (ts.isImportDeclaration(node)) {
+ const moduleSpecifier = node.moduleSpecifier;
+ if (ts.isStringLiteral(moduleSpecifier)) {
+ const modulePath = moduleSpecifier.text;
+ if ([OHOS_ARKUI_STATEMANAGEMENT, OHOS_ARKUI_COMPONENT].includes(modulePath)) {
+ return node;
+ } else if (modulePath.includes(COMPONENT + '/')) {
+ return this.updateImportComponentPath(node, modulePath);
+ }
+ }
+ }
+
+ this.handleImportBuilder(node);
+ const result = ts.visitEachChild(node, this.visitNode.bind(this), this.context);
+
+ if (ts.isIdentifier(result) && !this.shouldSkipIdentifier(result)) {
+ this.interfacesNeedToImport.add(result.text);
+ } else if (ts.isSourceFile(result)) {
+ this.addUIImports(result);
+ }
+
+ return result;
+ }
+
+ updateImportComponentPath(node: ts.ImportDeclaration, modulePath: string): ts.ImportDeclaration {
+ return ts.factory.updateImportDeclaration(
+ node,
+ node.modifiers,
+ node.importClause,
+ ts.factory.createStringLiteral(
+ modulePath.replace(/\.\.\/component\/.*/, OHOS_ARKUI_COMPONENT)
+ ),
+ node.assertClause
+ );
+ }
+
+ processTypeWithLongMemberChain(node: ts.TypeAliasDeclaration, moduleName: string,
+ memberChain: string[]): ts.TypeAliasDeclaration {
+ return ts.factory.updateTypeAliasDeclaration(node,
+ node.modifiers,
+ node.name,
+ node.typeParameters,
+ ts.factory.createTypeReferenceNode(
+ ts.factory.createQualifiedName(
+ ts.factory.createIdentifier(moduleName),
+ ts.factory.createIdentifier(memberChain[1])
+ ),
+ undefined
+ )
+ );
+ }
+
+ getModulePath(node: ts.ImportTypeNode): string {
+ return ((node.argument as unknown as ts.LiteralTypeNode)
+ .literal as unknown as ts.StringLiteral).text;
+ }
+
+ processDynamicImportInType(node: ts.TypeAliasDeclaration): ts.Node {
+ const typeName = node.name.text;
+ const importType = node.type as ts.ImportTypeNode;
+ const modulePath = this.getModulePath(importType);
+ const moduleName = this.extractLastSegment(modulePath);
+ const memberChain = this.extractFromImportTypeNode(importType);
+ const hasGeneric = !!node.typeParameters?.length;
+
+ if (!this.hasDefaultInMemberChain(memberChain) &&
+ (!hasGeneric || !node.typeParameters[0].default)) {
+
+ if (memberChain.length > 1) {
+ return this.processTypeWithLongMemberChain(node, moduleName, memberChain);
+ }
+ this.collectDynamicImport(modulePath, typeName);
+ return this.processTypeWithoutDefaultOnly(typeName, modulePath);
+ }
+
+ if (this.hasDefaultInMemberChain(memberChain) && memberChain.length > 1) {
+ this.collectDynamicImport(modulePath, moduleName);
+ return this.processTypeWithDefaultAndLongMemberChain(node, modulePath, moduleName, memberChain);
+ }
+
+ if (this.hasDefaultInMemberChain(memberChain) && memberChain.length === 1) {
+ this.collectDynamicImport(modulePath, typeName);
+ return this.processTypeWithDefaultAndOneMember(typeName, modulePath);
+ }
+
+ if (hasGeneric && node.typeParameters[0].default) {
+ this.collectDynamicImport(modulePath, typeName);
+ return this.processHasGeneric(node, typeName, modulePath);
+ }
+
+ return node;
+ }
+
+ processDynamicImportInImportTypeNode(node: ts.ImportTypeNode): ts.Node {
+ const modulePath = this.getModulePath(node);
+ const moduleName = this.extractLastSegment(modulePath);
+ const memberChain = this.extractFromImportTypeNode(node);
+
+ if (memberChain.includes(DEFAULT)) {
+ this.setImportType(modulePath, ImportType.DEFAULT);
+ this.collectDynamicImport(modulePath, moduleName);
+ return ts.factory.createIdentifier(moduleName);
+ } else if (memberChain.length) {
+ this.setImportType(modulePath, ImportType.NAMED);
+ this.collectDynamicImport(modulePath, memberChain[0]);
+ return ts.factory.createTypeReferenceNode(
+ node.qualifier as ts.Identifier,
+ node.typeArguments
+ );
+ }
+ return node;
+ }
+
+ processSourceFileForDynamicImport(node: ts.SourceFile, result: ts.SourceFile): void {
+ const newStatements = [...result.statements];
+ if (this.dynamicImportCollection.size) {
+ this.addImportForDynamicImport(newStatements);
+ }
+
+ const updatedStatements = ts.factory.createNodeArray(newStatements);
+ const updatedSourceFile = ts.factory.updateSourceFile(node,
+ updatedStatements,
+ node.isDeclarationFile,
+ node.referencedFiles,
+ node.typeReferenceDirectives,
+ node.hasNoDefaultLib,
+ node.libReferenceDirectives
+ );
+
+ const updatedCode = this.printer.printFile(updatedSourceFile);
+ if (this.outPath) {
+ this.writeSourceFileToOutPut(updatedSourceFile, updatedCode);
+ } else {
+ fs.writeFileSync(updatedSourceFile.fileName, updatedCode);
+ }
+ }
+
+ addUIImports(node: ts.SourceFile): void {
+ const newStatements = [...node.statements];
+
+ const compImportSpecifiers: ts.ImportSpecifier[] = [];
+ const stateImportSpecifiers: ts.ImportSpecifier[] = [];
+
+ this.interfacesNeedToImport.forEach((interfaceName) => {
+ if (this.importedInterfaces.has(interfaceName)) {
+ return;
+ }
+ const identifier = ts.factory.createIdentifier(interfaceName);
+ if (decoratorsWhiteList.includes(interfaceName)) {
+ stateImportSpecifiers.push(ts.factory.createImportSpecifier(false, undefined, identifier));
+ } else {
+ compImportSpecifiers.push(ts.factory.createImportSpecifier(false, undefined, identifier));
+ }
+ });
+
+ if (compImportSpecifiers.length + stateImportSpecifiers.length > 0) {
+ this.processAddUIImport(node, compImportSpecifiers, stateImportSpecifiers, newStatements);
+ }
+
+ this.processSourceFileForUIImport(node, newStatements);
+ }
+
+ processTypeWithoutDefaultOnly(typeName: string, modulePath: string): ts.ExportDeclaration {
+ this.setImportType(modulePath, ImportType.NAMED);
+ return ts.factory.createExportDeclaration(
+ undefined,
+ false,
+ ts.factory.createNamedExports([ts.factory.createExportSpecifier(
+ false,
+ undefined,
+ ts.factory.createIdentifier(typeName)
+ )]),
+ undefined,
+ undefined
+ );
+ }
+
+ processTypeWithDefaultAndLongMemberChain(node: ts.TypeAliasDeclaration, modulePath: string,
+ moduleName: string, memberChain: string[]): ts.TypeAliasDeclaration {
+ this.setImportType(modulePath, ImportType.DEFAULT);
+ return ts.factory.updateTypeAliasDeclaration(node,
+ node.modifiers,
+ node.name,
+ node.typeParameters,
+ ts.factory.createTypeReferenceNode(
+ ts.factory.createQualifiedName(
+ ts.factory.createIdentifier(moduleName),
+ ts.factory.createIdentifier(memberChain[1])
+ ),
+ undefined
+ )
+ );
+ }
+
+ processTypeWithDefaultAndOneMember(typeName: string, modulePath: string): ts.ExportDeclaration {
+ this.setImportType(modulePath, ImportType.DEFAULT);
+ return ts.factory.createExportDeclaration(
+ undefined,
+ false,
+ ts.factory.createNamedExports([ts.factory.createExportSpecifier(
+ false,
+ undefined,
+ ts.factory.createIdentifier(typeName)
+ )]),
+ undefined,
+ undefined
+ );
+ }
+
+ processHasGeneric(node: ts.TypeAliasDeclaration, typeName: string,
+ modulePath: string): ts.TypeAliasDeclaration {
+ this.setImportType(modulePath, ImportType.ALIAS);
+ return ts.factory.updateTypeAliasDeclaration(node,
+ node.modifiers,
+ node.name,
+ node.typeParameters,
+ ts.factory.createTypeReferenceNode(
+ ts.factory.createIdentifier(typeName + GENERIC_T),
+ [ts.factory.createTypeReferenceNode(
+ ts.factory.createIdentifier(GENERIC_T),
+ undefined
+ )]
+ )
+ );
+ }
+
+ addImportForDynamicImport(newStatements: ts.Statement[]): void {
+ this.dynamicImportCollection.forEach((value, key) => {
+ if (this.dynamicImportType.get(key) === ImportType.DEFAULT) {
+ newStatements.splice(1, 0, ts.factory.createImportDeclaration(undefined,
+ ts.factory.createImportClause(false,
+ ts.factory.createIdentifier(Array.from(value)[0]), undefined),
+ ts.factory.createStringLiteral(key),
+ undefined
+ ));
+ } else if (this.dynamicImportType.get(key) === ImportType.NAMED) {
+ const namedImports = ts.factory.createNamedImports(Array.from(value).map(v => {
+ return ts.factory.createImportSpecifier(false, undefined,
+ ts.factory.createIdentifier(v));
+ }));
+ newStatements.splice(1, 0, ts.factory.createImportDeclaration(undefined,
+ ts.factory.createImportClause(false, undefined, namedImports),
+ ts.factory.createStringLiteral(key), undefined
+ ));
+ } else {
+ newStatements.splice(1, 0, ts.factory.createImportDeclaration(undefined,
+ ts.factory.createImportClause(false, undefined,
+ ts.factory.createNamedImports([ts.factory.createImportSpecifier(false,
+ ts.factory.createIdentifier(Array.from(value)[0]),
+ ts.factory.createIdentifier(Array.from(value)[0] + 'T')
+ )])
+ ),
+ ts.factory.createStringLiteral(key), undefined
+ ));
+ }
+ });
+
+ this.createPromptActionDefaultImport(newStatements);
+ }
+
+ createPromptActionDefaultImport(newStatements: ts.Statement[]): void {
+ newStatements.splice(1, 0, ts.factory.createImportDeclaration(
+ undefined,
+ ts.factory.createImportClause(
+ false,
+ ts.factory.createIdentifier('promptAction'),
+ undefined
+ ),
+ ts.factory.createStringLiteral('./@ohos.promptAction'),
+ undefined
+ ));
+ }
+
+ extractFromImportTypeNode(importTypeNode: ts.ImportTypeNode): string[] {
+ if (!importTypeNode.qualifier) {
+ return [];
+ }
+
+ return importTypeNode.qualifier.getText().split('.');
+ }
+
+ collectDynamicImport(k: string, v: string): void {
+ if (this.dynamicImportCollection.has(k)) {
+ this.dynamicImportCollection.get(k)!.add(v);
+ } else {
+ this.dynamicImportCollection.set(k, new Set([v]));
+ }
+ }
+
+ extractLastSegment(path: string): string {
+ const slashIndex = path.lastIndexOf('/');
+ const dotIndex = path.lastIndexOf('.');
+
+ const lastSeparatorIndex = Math.max(slashIndex, dotIndex);
+ if (lastSeparatorIndex !== -1 && lastSeparatorIndex < path.length - 1) {
+ return path.slice(lastSeparatorIndex + 1);
+ }
+
+ return '';
+ }
+
+ hasDefaultInMemberChain(memberChain: string[]): boolean {
+ return memberChain.includes(DEFAULT);
+ }
+
+ setImportType(modulePath: string, type: ImportType): void {
+ this.dynamicImportType.set(modulePath, type);
+ }
+
+ handleImportBuilder(node: ts.Node): void {
+ ts.getDecorators(node as ts.HasDecorators)?.forEach(element => {
+ if (element?.getText() === '@' + ARKUI_BUILDER) {
+ this.interfacesNeedToImport.add(ARKUI_BUILDER);
+ return;
+ }
+ });
+ }
+
+ hasKitArkUI(node: ts.SourceFile): boolean {
+ return node.text?.includes(OHOS_KIT_ARKUI);
+ }
+
+ getCoreFilename(fileName: string): string {
+ if (fileName.endsWith(EXTNAME_D_ETS)) {
+ return fileName.slice(0, -EXTNAME_D_ETS.length);
+ }
+ if (fileName.endsWith(EXTNAME_D_TS)) {
+ return fileName.slice(0, -EXTNAME_D_TS.length);
+ }
+ return fileName;
+ }
+
+ isNeedAddImports(node: ts.SourceFile): boolean {
+ if (!ts.isSourceFile(node)) {
+ return false;
+ }
+
+ if (node.fileName.includes(OHOS_ARKUI) ||
+ whiteFileList.includes(this.getCoreFilename(path.basename(node.fileName))) ||
+ this.hasKitArkUI(node)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ processSourceFileForUIImport(node: ts.SourceFile, newStatements: ts.Statement[]): void {
+ const updatedStatements = ts.factory.createNodeArray(newStatements);
+ const updatedSourceFile = ts.factory.updateSourceFile(node,
+ updatedStatements,
+ node.isDeclarationFile,
+ node.referencedFiles,
+ node.typeReferenceDirectives,
+ node.hasNoDefaultLib,
+ node.libReferenceDirectives
+ );
+
+ const updatedCode = this.printer.printFile(updatedSourceFile);
+ if (this.outPath) {
+ this.writeSourceFileToOutPut(updatedSourceFile, updatedCode);
+ } else {
+ fs.writeFileSync(updatedSourceFile.fileName, updatedCode);
+ }
+ }
+
+ writeSourceFileToOutPut(sourceFile: ts.SourceFile, context: string = sourceFile.text): void {
+ const outFile: string = path.resolve(sourceFile.fileName.replace(this.inputDir,
+ this.outPath));
+ this.safeWriteFileSync(outFile, context);
+ }
+
+ safeWriteFileSync(filePath: string, content: string): void {
+ const dir: string = path.dirname(filePath);
+
+ if (!fs.existsSync(dir)) {
+ fs.mkdirSync(dir, { recursive: true });
+ }
+
+ fs.writeFileSync(filePath, content);
+ }
+
+ addArkUIPath(node: ts.SourceFile, moduleName: string): string {
+ if (ts.isSourceFile(node)) {
+ const fileName = node.fileName;
+ if (apiDir.some(path => fileName.includes(API_PATH + path + '/'))) {
+ return '.' + moduleName;
+ } else if (apiInternalDir.some(path => fileName.includes(API_PATH + path + '/'))) {
+ return '../.' + moduleName;
+ }
+ }
+ return moduleName;
+ }
+
+ processAddUIImport(node: ts.SourceFile, compImportSpecifiers: ts.ImportSpecifier[],
+ stateImportSpecifiers: ts.ImportSpecifier[], newStatements: ts.Statement[]): void {
+ if (!this.isNeedAddImports(node)) {
+ return;
+ }
+
+ if (compImportSpecifiers.length) {
+ const moduleName = this.addArkUIPath(node, OHOS_ARKUI_COMPONENT);
+ const compImportDeclaration = ts.factory.createImportDeclaration(
+ undefined,
+ ts.factory.createImportClause(false,
+ undefined,
+ ts.factory.createNamedImports(
+ compImportSpecifiers
+ )
+ ),
+ ts.factory.createStringLiteral(moduleName, true),
+ undefined
+ );
+ newStatements.splice(this.insertPosition, 0, compImportDeclaration);
+ }
+
+ if (stateImportSpecifiers.length) {
+ const moduleName = this.addArkUIPath(node, OHOS_ARKUI_STATEMANAGEMENT);
+ const stateImportDeclaration = ts.factory.createImportDeclaration(
+ undefined,
+ ts.factory.createImportClause(false,
+ undefined,
+ ts.factory.createNamedImports(
+ stateImportSpecifiers
+ )
+ ),
+ ts.factory.createStringLiteral(moduleName, true),
+ undefined
+ );
+ newStatements.splice(this.insertPosition, 0, stateImportDeclaration);
+ }
+ }
+
+ getDeclarationNode(node: ts.Node): ts.Declaration | undefined {
+ const symbol = this.trueSymbolAtLocation(node);
+ return HandleUIImports.getDeclaration(symbol);
+ }
+
+ static getDeclaration(tsSymbol: ts.Symbol | undefined): ts.Declaration | undefined {
+ if (tsSymbol?.declarations && tsSymbol.declarations.length > 0) {
+ return tsSymbol.declarations[0];
+ }
+
+ return undefined;
+ }
+
+ followIfAliased(symbol: ts.Symbol): ts.Symbol {
+ if ((symbol.getFlags() & ts.SymbolFlags.Alias) !== 0) {
+ return this.typeChecker.getAliasedSymbol(symbol);
+ }
+
+ return symbol;
+ }
+
+ trueSymbolAtLocation(node: ts.Node): ts.Symbol | undefined {
+ const cache = this.trueSymbolAtLocationCache;
+ const val = cache.get(node);
+
+ if (val !== undefined) {
+ return val !== null ? val : undefined;
+ }
+
+ let symbol = this.typeChecker.getSymbolAtLocation(node);
+
+ if (symbol === undefined) {
+ cache.set(node, null);
+ return undefined;
+ }
+
+ symbol = this.followIfAliased(symbol);
+ cache.set(node, symbol);
+
+ return symbol;
+ }
+
+ shouldSkipIdentifier(identifier: ts.Identifier): boolean {
+ const name = identifier.text;
+ const skippedList = new Set([ARKUI_EXTEND, ARKUI_STYLES]);
+ if (skippedList.has(name)) {
+ return true;
+ }
+
+ if (!whiteList.has(name)) {
+ return true;
+ }
+
+ const symbol = this.typeChecker.getSymbolAtLocation(identifier);
+ if (symbol) {
+ const decl = this.getDeclarationNode(identifier);
+ if (this.isDeclFromSDK(decl, identifier)) {
+ return true;
+ }
+ }
+
+ return this.interfacesNeedToImport.has(name);
+ }
+
+ isDeclFromSDK(decl: ts.Declaration | undefined, identifier: ts.Identifier): boolean {
+ const rootNode = decl?.getSourceFile();
+ if (!rootNode) {
+ return false;
+ }
+
+ if (rootNode === identifier.getSourceFile()) {
+ return true;
+ }
+
+ const fileName = rootNode.fileName;
+ if (!fileName.includes(NODE_MODULES) && fileName.includes(this.inputDir)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ extractImportedNames(sourceFile: ts.SourceFile): void {
+ for (const statement of sourceFile.statements) {
+ if (!ts.isImportDeclaration(statement)) {
+ continue;
+ }
+
+ const importClause = statement.importClause;
+ if (!importClause) {
+ continue;
+ }
+
+ const namedBindings = importClause.namedBindings;
+ if (!namedBindings || !ts.isNamedImports(namedBindings)) {
+ continue;
+ }
+
+ for (const specifier of namedBindings.elements) {
+ const importedName = specifier.name.getText(sourceFile);
+ this.importedInterfaces.add(importedName);
+ }
+ }
+ }
+}
+
+enum ImportType {
+ DEFAULT = 0,
+ NAMED = 1,
+ ALIAS = 2,
+ DEFAULT_AND_NAMED = 3,
+}
diff --git a/arkui_noninterop_plugin/src/add_import/index.ts b/arkui_noninterop_plugin/src/add_import/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ea0f9905dab4f47b514473ce4ae7f7563edd9bcb
--- /dev/null
+++ b/arkui_noninterop_plugin/src/add_import/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import start from './start';
+
+start();
diff --git a/arkui_noninterop_plugin/src/add_import/pre_define.ts b/arkui_noninterop_plugin/src/add_import/pre_define.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ee1f1e9ecf60b59db7df1aba9943584064a300de
--- /dev/null
+++ b/arkui_noninterop_plugin/src/add_import/pre_define.ts
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export const API_PATH = '/api/';
+export const ARKUI_BUILDER = 'Builder';
+export const ARKUI_EXTEND = 'Extend';
+export const ARKUI_STYLES = 'Styles';
+export const COMPONENT = 'component';
+export const DEFAULT = 'default';
+export const EXTNAME_D_ETS = '.d.ets';
+export const EXTNAME_D_TS = '.d.ts';
+export const GENERIC_T = 'T';
+export const NODE_MODULES = 'node_modules';
+export const OHOS_ARKUI = '@ohos.arkui.';
+export const OHOS_ARKUI_COMPONENT = './@ohos.arkui.GlobalESValue';
+export const OHOS_ARKUI_GLOBAL_ESVALUE = '@ohos.arkui.GlobalESValue';
+export const OHOS_ARKUI_STATEMANAGEMENT = './@ohos.arkui.GlobalESValue';
+export const OHOS_KIT_ARKUI = '@kit ArkUI';
diff --git a/arkui_noninterop_plugin/src/add_import/process_interop_ui.ts b/arkui_noninterop_plugin/src/add_import/process_interop_ui.ts
new file mode 100644
index 0000000000000000000000000000000000000000..44d06b29da8d561aab851d5b3b3dc87b3d271dbf
--- /dev/null
+++ b/arkui_noninterop_plugin/src/add_import/process_interop_ui.ts
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from 'path';
+import * as fs from 'fs';
+
+import * as ts from 'typescript';
+
+import HandleUIImports from './handle_ui_imports';
+import writeAnnotationFile from './annotation';
+import { EXTNAME_D_ETS, EXTNAME_D_TS } from './pre_define';
+
+export default function processInteropUI(inputPath: string, exportFlag: boolean,
+ outputPath = ''): ts.TransformationResult {
+ const filePaths = getDeclgenFiles(inputPath);
+
+ const program = ts.createProgram(filePaths, defaultCompilerOptions());
+ const sourceFiles = getSourceFiles(program, filePaths);
+
+ const createTransformer = (ctx: ts.TransformationContext) => {
+ return (sourceFile: ts.SourceFile) => {
+ const handleUIImports = new HandleUIImports(program, ctx, outputPath, inputPath, exportFlag);
+ return handleUIImports.createCustomTransformer(sourceFile);
+ };
+ };
+ const res = ts.transform(sourceFiles, [createTransformer]);
+
+ writeAnnotationFile(inputPath, outputPath);
+ return res;
+}
+
+function getDeclgenFiles(dir: string, filePaths: string[] = []): string[] {
+ const files = fs.readdirSync(dir);
+
+ files.forEach(file => {
+ const filePath: string = path.join(dir, file);
+ const stat: fs.Stats = fs.statSync(filePath);
+
+ if (stat.isDirectory()) {
+ getDeclgenFiles(filePath, filePaths);
+ } else if (stat.isFile() && (file.endsWith(EXTNAME_D_ETS) || file.endsWith(EXTNAME_D_TS))) {
+ filePaths.push(filePath);
+ }
+ });
+
+ return filePaths;
+}
+
+function defaultCompilerOptions(): ts.CompilerOptions {
+ return {
+ target: ts.ScriptTarget.Latest,
+ module: ts.ModuleKind.CommonJS,
+ allowJs: true,
+ checkJs: true,
+ declaration: true,
+ emitDeclarationOnly: true,
+ noEmit: false
+ };
+}
+
+function getSourceFiles(program: ts.Program, filePaths: string[]): ts.SourceFile[] {
+ const sourceFiles: ts.SourceFile[] = [];
+
+ filePaths.forEach(filePath => {
+ sourceFiles.push(program.getSourceFile(filePath)!);
+ });
+
+ return sourceFiles;
+}
diff --git a/arkui_noninterop_plugin/src/add_import/start.ts b/arkui_noninterop_plugin/src/add_import/start.ts
new file mode 100644
index 0000000000000000000000000000000000000000..884e6bd3e22c7a4f683aa0b3615349ab36a87101
--- /dev/null
+++ b/arkui_noninterop_plugin/src/add_import/start.ts
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as commander from 'commander';
+
+import processInteropUI from './process_interop_ui';
+
+let outputPath = '';
+let inputDir = '';
+let exportFlag = false;
+
+export default function start(): void {
+ const program = new commander.Command();
+ program
+ .name('noninterop_global_import')
+ .version('0.0.1');
+ program
+ .option('--input ', 'input path')
+ .option('--output ', 'output path')
+ .option('--export ', 'export flag', false)
+ .action((opts) => {
+ outputPath = opts.output;
+ inputDir = opts.input;
+ exportFlag = opts.export === 'true';
+ processInteropUI(inputDir, exportFlag);
+ });
+ program.parse(process.argv);
+}
\ No newline at end of file
diff --git a/arkui_noninterop_plugin/src/add_import/white_management.ts b/arkui_noninterop_plugin/src/add_import/white_management.ts
new file mode 100644
index 0000000000000000000000000000000000000000..80ee7429ebf474ea17da51a093a92b0d1fd79aed
--- /dev/null
+++ b/arkui_noninterop_plugin/src/add_import/white_management.ts
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const whiteList = new Set([
+ 'ASTCResource', 'AbstractProperty', 'AccelerationOptions', 'AccessibilityAction',
+ 'AccessibilityActionInterceptResult', 'AccessibilityCallback', 'AccessibilityHoverEvent',
+ 'AccessibilityHoverType', 'AccessibilityOptions', 'AccessibilityRoleType',
+ 'AccessibilitySamePageMode', 'ActionSheet', 'ActionSheetButtonOptions', 'ActionSheetOffset',
+ 'ActionSheetOptions', 'AdaptiveColor', 'AdsBlockedDetails', 'Affinity', 'AlertDialog',
+ 'AlertDialogButtonBaseOptions', 'AlertDialogButtonOptions', 'AlertDialogParam',
+ 'AlertDialogParamWithButtons', 'AlertDialogParamWithConfirm', 'AlertDialogParamWithOptions',
+ 'AlignRuleOption', 'Alignment', 'AlphabetIndexerOptions', 'AnchoredColorMode',
+ 'AnimatableArithmetic', 'AnimatableExtend', 'AnimateParam', 'AnimationExtender',
+ 'AnimationMode', 'AnimationPropertyType', 'AnimationRange', 'AnimationStatus',
+ 'AnimatorInterface', 'AppRotation', 'AppStorage', 'AppearSymbolEffect', 'Area',
+ 'ArrowPointPosition', 'ArrowPosition', 'ArrowStyle', 'AutoCapitalizationMode',
+ 'AutoPlayOptions', 'AvailableLayoutArea', 'AvoidanceMode', 'Axis', 'AxisAction',
+ 'AxisEvent', 'AxisModel', 'BackgroundBlurStyleOptions', 'BackgroundBrightnessOptions',
+ 'BackgroundColorStyle', 'BackgroundEffectOptions', 'BackgroundImageOptions', 'BadgeParam',
+ 'BadgeParamWithNumber', 'BadgeParamWithString', 'BadgePosition', 'BadgeStyle',
+ 'BarGridColumnOptions', 'BarMode', 'BarPosition', 'BarState', 'BarStyle',
+ 'BarrierDirection', 'BarrierStyle', 'BaseCustomComponent', 'BaseEvent', 'BaseGestureEvent',
+ 'BaseHandlerOptions', 'BaseShape', 'BaseSpan', 'BaselineOffsetStyle', 'Bias', 'BindOptions',
+ 'BlendApplyType', 'BlendMode', 'Blender', 'BlurOptions', 'BlurStyle',
+ 'BlurStyleActivePolicy', 'BlurStyleOptions', 'BoardStyle', 'BorderImageOption',
+ 'BorderOptions', 'BorderRadiuses', 'BorderStyle', 'BottomTabBarStyle', 'BounceSymbolEffect',
+ 'BreakPoints', 'BreakpointsReference', 'Builder', 'BuilderAttachment',
+ 'BuilderAttachmentInterface', 'BuilderParam', 'BusinessError', 'ButtonConfiguration',
+ 'ButtonIconOptions', 'ButtonOptions', 'ButtonRole', 'ButtonStyle', 'ButtonStyleMode',
+ 'ButtonTriggerClickCallback', 'ButtonType', 'CacheMode', 'CalendarAlign',
+ 'CalendarController', 'CalendarDay', 'CalendarDialogOptions', 'CalendarOptions',
+ 'CalendarPickerDialog', 'CalendarRequestedData', 'CalendarSelectedDate', 'Callback',
+ 'CallbackBuffer', 'CallbackKind', 'CallbackResource', 'CallbackResourceHolder',
+ 'CancelButtonOptions', 'CancelButtonStyle', 'CancelButtonSymbolOptions', 'CanvasDirection',
+ 'CanvasFillRule', 'CanvasGradient', 'CanvasLineCap', 'CanvasLineJoin', 'CanvasOptions',
+ 'CanvasPath', 'CanvasPattern', 'CanvasRenderer', 'CanvasRenderingContext2D',
+ 'CanvasTextAlign', 'CanvasTextBaseline', 'CapsuleStyleOptions', 'CaretOffset', 'CaretStyle',
+ 'ChainAnimationOptions', 'ChainEdgeEffect', 'ChainStyle', 'ChainWeightOptions',
+ 'CheckBoxConfiguration', 'CheckBoxShape', 'CheckboxGroupOptions', 'CheckboxGroupResult',
+ 'CheckboxOptions', 'ChildHitFilterOption', 'ChildrenMainSize', 'CircleOptions',
+ 'CircleShape', 'CircleStyleOptions', 'ClickEffect', 'ClickEffectLevel', 'ClickEvent',
+ 'ClientAuthenticationHandler', 'CloseSwipeActionOptions', 'Color', 'ColorContent',
+ 'ColorFilter', 'ColorMetrics', 'ColorMode', 'ColorSpace', 'ColorStop', 'ColoringStrategy',
+ 'ColumnOptions', 'ColumnOptionsV2', 'ColumnSplitDividerStyle', 'CommonConfiguration',
+ 'CommonProgressStyleOptions', 'CommonShape', 'CommonShapeMethod', 'CommonTransition',
+ 'ComponentContent', 'ComponentOptions', 'ComponentRoot', 'Configuration',
+ 'ConsoleMessage', 'ConstraintSizeOptions', 'Content', 'ContentClipMode', 'ContentCoverOptions',
+ 'ContentDidScrollCallback', 'ContentType', 'Context', 'ContextMenu',
+ 'ContextMenuAnimationOptions', 'ContextMenuEditStateFlags', 'ContextMenuInputFieldType',
+ 'ContextMenuMediaType', 'ContextMenuOptions', 'ContextMenuSourceType', 'ControlSize',
+ 'ControllerHandler', 'CopyEvent', 'CopyOptions', 'CrownAction', 'CrownEvent',
+ 'CrownSensitivity', 'CurrentDayStyle', 'Curve', 'CustomBuilder', 'CustomComponent',
+ 'CustomComponentV2', 'CustomDialogController', 'CustomDialogControllerOptions',
+ 'CustomNodeBuilder', 'CustomPopupOptions', 'CustomSpan', 'CustomSpanDrawInfo',
+ 'CustomSpanMeasureInfo', 'CustomSpanMetrics', 'CustomTheme', 'CutEvent',
+ 'DataAddOperation', 'DataChangeListener', 'DataChangeOperation', 'DataDeleteOperation',
+ 'DataExchangeOperation', 'DataMoveOperation', 'DataOperation', 'DataOperationType',
+ 'DataPanelConfiguration', 'DataPanelOptions', 'DataPanelShadowOptions', 'DataPanelType',
+ 'DataReloadOperation', 'DataResubmissionHandler', 'DatePickerDialog',
+ 'DatePickerDialogOptions', 'DatePickerMode', 'DatePickerOptions', 'DatePickerResult',
+ 'DateRange', 'DateTimeOptions', 'DecorationStyle', 'DecorationStyleInterface',
+ 'DecorationStyleResult', 'Degree', 'DeleteValue', 'Deserializer', 'DialogAlignment',
+ 'DialogButtonDirection', 'DialogButtonStyle', 'DialogDisplayMode', 'DigitIndicator',
+ 'Dimension', 'Direction', 'DirectionalEdgesT', 'DisableSymbolEffect', 'DisappearSymbolEffect',
+ 'DismissContentCoverAction', 'DismissContinueReason', 'DismissDialogAction',
+ 'DismissFollowUpAction', 'DismissMenuAction', 'DismissPopupAction', 'DismissReason',
+ 'DismissSheetAction', 'DistributionType', 'DisturbanceFieldOptions', 'DisturbanceFieldShape',
+ 'DividerMode', 'DividerOptions', 'DividerStyle', 'DividerStyleOptions', 'DotIndicator',
+ 'DoubleAnimationParam', 'DpiFollowStrategy', 'DragBehavior', 'DragEvent',
+ 'DragInteractionOptions', 'DragItemInfo', 'DragPointCoordinate', 'DragPreviewLiftingScale',
+ 'DragPreviewMode', 'DragPreviewOptions', 'DragResult', 'DraggingSizeChangeEffect',
+ 'DrawContext', 'DrawModifier', 'DrawableDescriptor', 'DrawingCanvas', 'DrawingColorFilter',
+ 'DrawingLattice', 'DrawingRenderingContext', 'DropOptions', 'DynamicNode',
+ 'DynamicRangeMode', 'EclipseStyleOptions', 'Edge', 'EdgeColors', 'EdgeEffect',
+ 'EdgeEffectOptions', 'EdgeOutlineStyles', 'EdgeOutlineWidths', 'EdgeStyles', 'EdgeWidth',
+ 'EdgeWidths', 'Edges', 'EditMenuOptions', 'EditMode', 'EditableTextChangeValue',
+ 'EditableTextOnChangeCallback', 'EffectDirection', 'EffectEdge', 'EffectFillStyle',
+ 'EffectScope', 'EffectType', 'EllipseOptions', 'EllipseShape', 'EllipsisMode',
+ 'EmbeddedDpiFollowStrategy', 'EmbeddedOptions', 'EmbeddedType',
+ 'EmbeddedWindowModeFollowStrategy', 'EmitterOptions', 'EmitterParticleOptions',
+ 'EmitterProperty', 'EnterKeyType', 'Entry', 'EntryOptions', 'EnvPropsOptions',
+ 'Environment', 'ErrorCallback', 'Event', 'EventEmulator', 'EventLocationInfo',
+ 'EventQueryType', 'EventResult', 'EventTarget', 'EventTargetInfo', 'ExchangeIndex',
+ 'ExchangeKey', 'ExpandedMenuItemOptions', 'ExpectedFrameRateRange', 'Extend', 'FP',
+ 'FadingEdgeOptions', 'FileSelectorMode', 'FileSelectorParam', 'FileSelectorResult',
+ 'FillMode', 'Filter', 'FingerInfo', 'FinishCallbackType', 'FirstMeaningfulPaint',
+ 'FlexAlign', 'FlexDirection', 'FlexOptions', 'FlexSpaceOptions', 'FlexWrap',
+ 'FocusAxisEvent', 'FocusBoxStyle', 'FocusController', 'FocusDrawLevel', 'FocusMovement',
+ 'FocusPriority', 'FocusWrapMode', 'FoldStatus', 'FolderStackOptions', 'Font',
+ 'FontInfo', 'FontOptions', 'FontSettingOptions', 'FontStyle', 'FontWeight',
+ 'ForegroundBlurStyleOptions', 'ForegroundEffectOptions', 'FormCallbackInfo',
+ 'FormDimension', 'FormInfo', 'FormLinkOptions', 'FormRenderingMode', 'FormShape',
+ 'FractionStop', 'FrameNode', 'FrictionMotion', 'FullScreenEnterEvent',
+ 'FullScreenExitHandler', 'FullscreenInfo', 'FunctionKey', 'GaugeConfiguration',
+ 'GaugeIndicatorOptions', 'GaugeOptions', 'GaugeShadowOptions', 'GeometryInfo',
+ 'GeometryTransitionOptions', 'Gesture', 'GestureControl', 'GestureEvent', 'GestureGroup',
+ 'GestureGroupGestureHandlerOptions', 'GestureGroupHandler', 'GestureHandler',
+ 'GestureInfo', 'GestureJudgeResult', 'GestureMask', 'GestureMode', 'GestureModifier',
+ 'GesturePriority', 'GestureRecognizer', 'GestureRecognizerJudgeBeginCallback',
+ 'GestureRecognizerState', 'GestureStyle', 'GestureType', 'GetItemMainSizeByIndex',
+ 'GradientDirection', 'GridColColumnOption', 'GridColOptions', 'GridContainerOptions',
+ 'GridDirection', 'GridItemAlignment', 'GridItemOptions', 'GridItemStyle',
+ 'GridLayoutOptions', 'GridRowColumnOption', 'GridRowDirection', 'GridRowOptions',
+ 'GridRowSizeOption', 'GuideLinePosition', 'GuideLineStyle', 'GutterOption',
+ 'HapticFeedbackMode', 'Header', 'HeightBreakpoint', 'HierarchicalSymbolEffect',
+ 'HistoricalPoint', 'HitTestMode', 'HitTestType', 'HorizontalAlign', 'HoverCallback',
+ 'HoverEffect', 'HoverEvent', 'HoverEventParam', 'HoverModeAreaType', 'HttpAuthHandler',
+ 'ICurve', 'IDataSource', 'IMonitor', 'IMonitorValue', 'IPropertySubscriber',
+ 'ISinglePropertyChangeSubscriber', 'IconOptions', 'IlluminatedType', 'ImageAIOptions',
+ 'ImageAnalyzerConfig', 'ImageAnalyzerController', 'ImageAnalyzerType', 'ImageAttachment',
+ 'ImageAttachmentInterface', 'ImageAttachmentLayoutStyle', 'ImageBitmap',
+ 'ImageCompleteCallback', 'ImageContent', 'ImageData', 'ImageError', 'ImageErrorCallback',
+ 'ImageFit', 'ImageFrameInfo', 'ImageInterpolation', 'ImageLoadResult', 'ImageModifier',
+ 'ImageParticleParameters', 'ImageRenderMode', 'ImageRepeat', 'ImageRotateOrientation',
+ 'ImageSize', 'ImageSmoothingQuality', 'ImageSourceSize', 'ImageSpanAlignment',
+ 'IndexerAlign', 'Indicator', 'IndicatorComponentController', 'IndicatorStyle',
+ 'InputCounterOptions', 'InputType', 'InsertValue', 'IntelligentTrackingPreventionDetails',
+ 'IntentionCode', 'InteractionHand', 'InterceptionModeCallback', 'InterceptionShowCallback',
+ 'Interop', 'InvertOptions', 'IsolatedOptions', 'ItemAlign', 'ItemDragEventHandler',
+ 'ItemDragInfo', 'ItemState', 'JavaScriptProxy', 'JsGeolocation', 'JsResult', 'KVMContext',
+ 'KeyEvent', 'KeyProcessingMode', 'KeySource', 'KeyType', 'KeyboardAppearance',
+ 'KeyboardAvoidMode', 'KeyboardOptions', 'KeyframeAnimateParam', 'KeyframeState', 'LPX',
+ 'LabelStyle', 'LargestContentfulPaint', 'LaunchMode', 'LayoutBorderInfo', 'LayoutChild',
+ 'LayoutDirection', 'LayoutInfo', 'LayoutManager', 'LayoutMode', 'LayoutPolicy',
+ 'LayoutSafeAreaEdge', 'LayoutSafeAreaType', 'LayoutStyle', 'Layoutable', 'LazyForEachOps',
+ 'LeadingMarginPlaceholder', 'Length', 'LengthConstrain', 'LengthMetrics',
+ 'LengthMetricsUnit', 'LengthUnit', 'LetterSpacingStyle', 'LightSource',
+ 'LineBreakStrategy', 'LineCapStyle', 'LineHeightStyle', 'LineJoinStyle', 'LineMetrics',
+ 'LineOptions', 'LineSpacingOptions', 'LinearGradient', 'LinearGradientBlurOptions',
+ 'LinearGradientOptions', 'LinearIndicatorController', 'LinearIndicatorStartOptions',
+ 'LinearIndicatorStyle', 'LinearStyleOptions', 'ListDividerOptions', 'ListItemAlign',
+ 'ListItemGroupArea', 'ListItemGroupOptions', 'ListItemGroupStyle', 'ListItemOptions',
+ 'ListItemStyle', 'ListOptions', 'ListScroller', 'LoadCommittedDetails', 'Loader',
+ 'LoadingProgressConfiguration', 'LoadingProgressStyle', 'LocalBuilder', 'LocalStorage',
+ 'LocalizedAlignRuleOptions', 'LocalizedAlignment', 'LocalizedBarrierDirection',
+ 'LocalizedBarrierStyle', 'LocalizedBorderRadiuses', 'LocalizedDragPointCoordinate',
+ 'LocalizedEdgeColors', 'LocalizedEdgeWidths', 'LocalizedEdges',
+ 'LocalizedHorizontalAlignParam', 'LocalizedMargin', 'LocalizedPadding',
+ 'LocalizedPosition', 'LocalizedVerticalAlignParam', 'LocationDescription',
+ 'LocationIconStyle', 'LongPressGesture', 'LongPressGestureEvent', 'LongPressGestureHandler',
+ 'LongPressGestureHandlerOptions', 'LongPressGestureParams', 'LongPressRecognizer',
+ 'LunarSwitchStyle', 'Margin', 'MarkStyle', 'MarqueeOptions', 'MarqueeStartPolicy',
+ 'MarqueeState', 'MarqueeUpdateStrategy', 'Materialized', 'Matrix2D', 'MaxLinesMode',
+ 'MaxLinesOptions', 'Measurable', 'MeasureOptions', 'MeasureResult', 'MenuAlignType',
+ 'MenuElement', 'MenuItemConfiguration', 'MenuItemGroupOptions', 'MenuItemOptions',
+ 'MenuItemOptionsV2', 'MenuMaskType', 'MenuOnAppearCallback', 'MenuOptions',
+ 'MenuOutlineOptions', 'MenuPolicy', 'MenuPreviewMode', 'MenuType', 'MessageLevel',
+ 'MixedMode', 'ModalMode', 'ModalTransition', 'ModelType', 'ModifierKey', 'Monitor',
+ 'MonthData', 'MoreButtonOptions', 'MotionBlurAnchor', 'MotionBlurOptions',
+ 'MotionPathOptions', 'MouseAction', 'MouseButton', 'MouseEvent', 'MoveIndex',
+ 'MultiShadowOptions', 'MutableStyledString', 'NativeEmbedDataInfo', 'NativeEmbedInfo',
+ 'NativeEmbedStatus', 'NativeEmbedTouchInfo', 'NativeEmbedVisibilityInfo',
+ 'NativeMediaPlayerConfig', 'NativeXComponentParameters', 'NavBar', 'NavBarPosition',
+ 'NavContentInfo', 'NavDestinationActiveReason', 'NavDestinationCommonTitle',
+ 'NavDestinationContext', 'NavDestinationCustomTitle', 'NavDestinationInfo',
+ 'NavDestinationMode', 'NavDestinationTransition', 'NavExtender', 'NavPathInfo',
+ 'NavPathStack', 'NavRouteMode', 'NavigationAnimatedTransition', 'NavigationCommonTitle',
+ 'NavigationCustomTitle', 'NavigationDividerStyle', 'NavigationInfo',
+ 'NavigationInterception', 'NavigationMenuItem', 'NavigationMenuOptions',
+ 'NavigationMode', 'NavigationOperation', 'NavigationOptions',
+ 'NavigationSystemTransitionType', 'NavigationTitleMode', 'NavigationTitleOptions',
+ 'NavigationToolbarOptions', 'NavigationTransitionProxy', 'NavigationType',
+ 'NestedScrollInfo', 'NestedScrollMode', 'NestedScrollOptions', 'NestedScrollOptionsExt',
+ 'Node', 'NodeController', 'NonCurrentDayStyle', 'Nullable', 'ObscuredReasons',
+ 'OffscreenCanvas', 'OffscreenCanvasRenderingContext2D', 'Offset', 'OffsetOptions',
+ 'OffsetResult', 'OnAdsBlockedCallback', 'OnAlertEvent', 'OnAlphabetIndexerPopupSelectCallback',
+ 'OnAlphabetIndexerRequestPopupDataCallback', 'OnAlphabetIndexerSelectCallback',
+ 'OnAudioStateChangedEvent', 'OnBeforeUnloadEvent', 'OnCheckboxChangeCallback',
+ 'OnCheckboxGroupChangeCallback', 'OnClientAuthenticationEvent', 'OnConfirmEvent',
+ 'OnConsoleEvent', 'OnContentScrollCallback', 'OnContextMenuHideCallback',
+ 'OnContextMenuShowEvent', 'OnDataResubmittedEvent', 'OnDidChangeCallback',
+ 'OnDownloadStartEvent', 'OnErrorReceiveEvent', 'OnFaviconReceivedEvent',
+ 'OnFirstContentfulPaintEvent', 'OnFirstMeaningfulPaintCallback', 'OnFoldStatusChangeCallback',
+ 'OnFoldStatusChangeInfo', 'OnFullScreenEnterCallback', 'OnGeolocationShowEvent',
+ 'OnHoverStatusChangeCallback', 'OnHttpAuthRequestEvent', 'OnHttpErrorReceiveEvent',
+ 'OnIntelligentTrackingPreventionCallback', 'OnInterceptRequestEvent',
+ 'OnLargestContentfulPaintCallback', 'OnLinearIndicatorChangeCallback', 'OnLoadInterceptEvent',
+ 'OnMoveHandler', 'OnNativeEmbedVisibilityChangeCallback', 'OnNativeLoadCallback',
+ 'OnNavigationEntryCommittedCallback', 'OnOverScrollEvent', 'OnOverrideUrlLoadingCallback',
+ 'OnPageBeginEvent', 'OnPageEndEvent', 'OnPageVisibleEvent', 'OnPasteCallback',
+ 'OnPermissionRequestEvent', 'OnProgressChangeEvent', 'OnPromptEvent',
+ 'OnRefreshAccessedHistoryEvent', 'OnRenderExitedEvent',
+ 'OnRenderProcessNotRespondingCallback', 'OnRenderProcessRespondingCallback',
+ 'OnResourceLoadEvent', 'OnSafeBrowsingCheckResultCallback', 'OnScaleChangeEvent',
+ 'OnScreenCaptureRequestEvent', 'OnScrollCallback', 'OnScrollEdgeCallback', 'OnScrollEvent',
+ 'OnScrollFrameBeginCallback', 'OnScrollFrameBeginHandlerResult',
+ 'OnScrollVisibleContentChangeCallback', 'OnSearchResultReceiveEvent',
+ 'OnShowFileSelectorEvent', 'OnSslErrorEventCallback', 'OnSslErrorEventReceiveEvent',
+ 'OnSubmitCallback', 'OnSwiperAnimationEndCallback', 'OnSwiperAnimationStartCallback',
+ 'OnSwiperGestureSwipeCallback', 'OnTabsAnimationEndCallback', 'OnTabsAnimationStartCallback',
+ 'OnTabsContentWillChangeCallback', 'OnTabsGestureSwipeCallback',
+ 'OnTextSelectionChangeCallback', 'OnTitleReceiveEvent', 'OnTouchIconUrlReceivedEvent',
+ 'OnViewportFitChangedCallback', 'OnWillScrollCallback', 'OnWindowNewEvent', 'Once',
+ 'OptionWidthMode', 'Optional', 'OutlineOptions', 'OutlineRadiuses', 'OutlineStyle',
+ 'OverScrollMode', 'OverlayOffset', 'OverlayOptions', 'PX', 'Padding', 'PageFlipMode',
+ 'PageTransitionCallback', 'PageTransitionEnter', 'PageTransitionExit',
+ 'PageTransitionOptions', 'PanDirection', 'PanGesture', 'PanGestureEvent',
+ 'PanGestureHandler', 'PanGestureHandlerOptions', 'PanGestureOptions', 'PanGestureParams',
+ 'PanRecognizer', 'PanelHeight', 'PanelMode', 'PanelType', 'ParagraphStyle',
+ 'ParagraphStyleInterface', 'ParticleAnnulusRegion', 'ParticleColorOptions',
+ 'ParticleColorPropertyOptions', 'ParticleColorPropertyUpdaterConfigs',
+ 'ParticleColorUpdaterOptions', 'ParticleConfigs', 'ParticleEmitterShape',
+ 'ParticleOptions', 'ParticlePropertyAnimation', 'ParticlePropertyOptions',
+ 'ParticlePropertyUpdaterConfigs', 'ParticleTuple', 'ParticleType', 'ParticleUpdater',
+ 'ParticleUpdaterOptions', 'Particles', 'PasswordIcon', 'PasteButtonOnClickResult',
+ 'PasteButtonOptions', 'PasteDescription', 'PasteEvent', 'PasteEventCallback',
+ 'PasteIconStyle', 'Path2D', 'PathOptions', 'PathShape', 'PathShapeOptions',
+ 'PatternLockChallengeResult', 'PatternLockController', 'Percentage',
+ 'PerfMonitorActionType', 'PerfMonitorSourceType', 'PermissionRequest',
+ 'PersistPropsOptions', 'PersistentStorage', 'PickerBackgroundStyle',
+ 'PickerDialogButtonStyle', 'PickerTextStyle', 'PinchGesture', 'PinchGestureEvent',
+ 'PinchGestureHandler', 'PinchGestureHandlerOptions', 'PinchGestureParams',
+ 'PinchRecognizer', 'PixelMap', 'PixelMapMock', 'PixelRoundCalcPolicy', 'PixelRoundMode',
+ 'PixelRoundPolicy', 'PixelStretchEffectOptions', 'PlaceholderStyle', 'Placement',
+ 'PlayMode', 'PlaybackInfo', 'PlaybackSpeed', 'PluginComponentOptions',
+ 'PluginComponentTemplate', 'PluginErrorCallback', 'PluginErrorData', 'Point',
+ 'PointLightStyle', 'PointParticleParameters', 'PointerStyle', 'PolygonOptions',
+ 'PolylineOptions', 'PopInfo', 'PopupBorderLinearGradient', 'PopupCommonOptions',
+ 'PopupMaskType', 'PopupMessageOptions', 'PopupOptions', 'PopupStateChangeParam',
+ 'Position', 'PositionT', 'PositionWithAffinity', 'PosterOptions', 'PreDragStatus',
+ 'PreparedInfo', 'Preview', 'PreviewConfiguration', 'PreviewMenuOptions', 'PreviewParams',
+ 'PreviewText', 'Profiler', 'ProgressConfiguration', 'ProgressMask', 'ProgressOptions',
+ 'ProgressStatus', 'ProgressStyle', 'ProgressStyleMap', 'ProgressStyleOptions',
+ 'ProgressType', 'Prop', 'ProtectedResourceType', 'Provide', 'ProvideOptions',
+ 'Provider', 'PulseSymbolEffect', 'QuickReplaceSymbolEffect', 'RRect',
+ 'RadialGradientOptions', 'RadioConfiguration', 'RadioIndicatorType', 'RadioOptions',
+ 'RadioStyle', 'RatingConfiguration', 'RatingOptions', 'RawFileDescriptor',
+ 'ReceiveCallback', 'RectHeightStyle', 'RectOptions', 'RectResult', 'RectShape',
+ 'RectShapeOptions', 'RectWidthStyle', 'Rectangle', 'RefreshOptions', 'RefreshStatus',
+ 'RelateType', 'RenderExitReason', 'RenderFit', 'RenderMode',
+ 'RenderProcessNotRespondingData', 'RenderProcessNotRespondingReason',
+ 'RenderingContextSettings', 'RepeatItem', 'RepeatMode', 'ReplaceSymbolEffect',
+ 'ResizableOptions', 'ResolutionQuality', 'Resource', 'ResourceColor',
+ 'ResourceImageAttachmentOptions', 'ResourceStr', 'ResponseType', 'RestrictedWorker',
+ 'ReuseOptions', 'RichEditorBaseController', 'RichEditorBuilderSpanOptions',
+ 'RichEditorChangeValue', 'RichEditorController', 'RichEditorDeleteDirection',
+ 'RichEditorDeleteValue', 'RichEditorGesture', 'RichEditorImageSpan',
+ 'RichEditorImageSpanOptions', 'RichEditorImageSpanResult', 'RichEditorImageSpanStyle',
+ 'RichEditorImageSpanStyleResult', 'RichEditorInsertValue', 'RichEditorLayoutStyle',
+ 'RichEditorOptions', 'RichEditorParagraphResult', 'RichEditorParagraphStyle',
+ 'RichEditorParagraphStyleOptions', 'RichEditorRange', 'RichEditorResponseType',
+ 'RichEditorSelection', 'RichEditorSpan', 'RichEditorSpanPosition',
+ 'RichEditorSpanStyleOptions', 'RichEditorSpanType', 'RichEditorStyledStringController',
+ 'RichEditorStyledStringOptions', 'RichEditorSymbolSpanOptions',
+ 'RichEditorSymbolSpanStyle', 'RichEditorSymbolSpanStyleResult', 'RichEditorTextSpan',
+ 'RichEditorTextSpanOptions', 'RichEditorTextSpanResult', 'RichEditorTextStyle',
+ 'RichEditorTextStyleResult', 'RichEditorUpdateImageSpanStyleOptions',
+ 'RichEditorUpdateSymbolSpanStyleOptions', 'RichEditorUpdateTextSpanStyleOptions',
+ 'RichEditorUrlStyle', 'RingStyleOptions', 'Root', 'RootSceneSession', 'RotateOptions',
+ 'RotationGesture', 'RotationGestureEvent', 'RotationGestureHandler',
+ 'RotationGestureHandlerOptions', 'RotationGestureParams', 'RotationRecognizer',
+ 'RoundRectShapeOptions', 'RoundedRectOptions', 'RouteInfo', 'RouteMapConfig',
+ 'RouteType', 'RouterPageInfo', 'RowOptions', 'RowOptionsV2', 'RuntimeType',
+ 'SafeAreaEdge', 'SafeAreaType', 'SaveButtonOnClickResult', 'SaveButtonOptions',
+ 'SaveDescription', 'SaveIconStyle', 'ScaleOptions', 'ScaleRingStyleOptions',
+ 'ScaleSymbolEffect', 'ScanEffectOptions', 'Scene', 'SceneOptions', 'ScreenCaptureConfig',
+ 'ScreenCaptureHandler', 'ScriptItem', 'ScrollAlign', 'ScrollAnimationOptions',
+ 'ScrollBarDirection', 'ScrollBarMargin', 'ScrollBarOptions', 'ScrollDirection',
+ 'ScrollEdgeOptions', 'ScrollMotion', 'ScrollOnScrollCallback', 'ScrollOnWillScrollCallback',
+ 'ScrollOptions', 'ScrollPageOptions', 'ScrollResult', 'ScrollSizeMode',
+ 'ScrollSnapAlign', 'ScrollSnapOptions', 'ScrollSource', 'ScrollState',
+ 'ScrollToIndexOptions', 'ScrollableBarModeOptions', 'ScrollableCommonMethod',
+ 'ScrollableTargetInfo', 'Scroller', 'SearchButtonOptions', 'SearchController',
+ 'SearchOptions', 'SearchSubmitCallback', 'SearchType', 'SectionOptions',
+ 'SecurityComponentLayoutDirection', 'SecurityComponentMethod', 'SeekMode',
+ 'SelectOption', 'SelectStatus', 'SelectedMode', 'SelectionMenuOptions',
+ 'SelectionMenuOptionsExt', 'SelectionOptions', 'Serializer', 'ShadowOptions',
+ 'ShadowStyle', 'ShadowType', 'ShapeSize', 'SharedTransitionEffectType', 'SheetDismiss',
+ 'SheetInfo', 'SheetKeyboardAvoidMode', 'SheetMode', 'SheetOptions', 'SheetSize',
+ 'SheetTitleOptions', 'SheetType', 'ShouldBuiltInRecognizerParallelWithCallback',
+ 'SideBarContainerType', 'SideBarPosition', 'Size', 'SizeChangeCallback', 'SizeOptions',
+ 'SizeResult', 'SizeT', 'SizeType', 'SlideEffect', 'SlideRange', 'SliderBlockStyle',
+ 'SliderBlockType', 'SliderChangeMode', 'SliderConfiguration', 'SliderCustomContentOptions',
+ 'SliderInteraction', 'SliderOptions', 'SliderPrefixOptions', 'SliderShowStepOptions',
+ 'SliderStepItemAccessibility', 'SliderStyle', 'SliderSuffixOptions',
+ 'SliderTriggerChangeCallback', 'SnapshotOptions', 'SourceTool', 'SourceType',
+ 'SpanStyle', 'SpringBackAction', 'SpringMotion', 'SpringProp', 'SslError',
+ 'SslErrorEvent', 'SslErrorHandler', 'StackOptions', 'StarStyleOptions', 'State',
+ 'StateStyles', 'Sticky', 'StickyStyle', 'Storage', 'StyleOptions', 'StyledString',
+ 'StyledStringChangeValue', 'StyledStringChangedListener', 'StyledStringController',
+ 'StyledStringKey', 'StyledStringValue', 'Styles', 'SubMenuExpandingMode',
+ 'SubTabBarStyle', 'SubmitCallback', 'SubmitEvent', 'SubscribaleAbstract',
+ 'SubscribedAbstractProperty', 'Summary', 'SuperscriptStyle', 'SurfaceRect',
+ 'SurfaceRotationOptions', 'SweepGradientOptions', 'SwipeActionItem', 'SwipeActionOptions',
+ 'SwipeActionState', 'SwipeDirection', 'SwipeEdgeEffect', 'SwipeGesture',
+ 'SwipeGestureEvent', 'SwipeGestureHandler', 'SwipeGestureHandlerOptions',
+ 'SwipeGestureParams', 'SwipeRecognizer', 'Swiper', 'SwiperAnimationEvent',
+ 'SwiperAnimationMode', 'SwiperAutoFill', 'SwiperContentAnimatedTransition',
+ 'SwiperContentTransitionProxy', 'SwiperContentWillScrollResult', 'SwiperController',
+ 'SwiperDisplayMode', 'SwiperNestedScrollMode', 'SwitchStyle', 'SymbolEffect',
+ 'SymbolEffectStrategy', 'SymbolGlyphModifier', 'SymbolRenderingStrategy',
+ 'SyncedPropertyOneWay', 'SyncedPropertyTwoWay', 'SystemAdaptiveOptions',
+ 'SystemBarStyle', 'SystemOps', 'TabBarIconStyle', 'TabBarOptions', 'TabBarSymbol',
+ 'TabContentAnimatedTransition', 'TabContentTransitionProxy', 'TabsAnimationEvent',
+ 'TabsCacheMode', 'TabsController', 'TabsCustomContentTransitionCallback',
+ 'TabsOptions', 'Tag', 'TapGesture', 'TapGestureEvent', 'TapGestureHandler',
+ 'TapGestureHandlerOptions', 'TapGestureParameters', 'TapGestureParams',
+ 'TapRecognizer', 'TemplateOptions', 'TerminationInfo', 'Test', 'TextAlign',
+ 'TextAreaController', 'TextAreaOptions', 'TextAreaSubmitCallback', 'TextAreaType',
+ 'TextBackgroundStyle', 'TextBaseController', 'TextBox', 'TextCascadePickerRangeContent',
+ 'TextCase', 'TextChangeOptions', 'TextChangeReason', 'TextClockConfiguration',
+ 'TextClockController', 'TextClockOptions', 'TextContentControllerBase',
+ 'TextContentControllerOptions', 'TextContentStyle', 'TextController',
+ 'TextDataDetectorConfig', 'TextDataDetectorType', 'TextDecorationOptions',
+ 'TextDecorationStyle', 'TextDecorationType', 'TextDeleteDirection',
+ 'TextEditControllerEx', 'TextHeightAdaptivePolicy', 'TextLayoutOptions',
+ 'TextInputController', 'TextInputOptions', 'TextInputStyle', 'TextMarqueeOptions',
+ 'TextMenuItem', 'TextMenuItemId', 'TextMenuOptions', 'TextMenuShowMode', 'TextMetrics',
+ 'TextModifier', 'TextOptions', 'TextOverflow', 'TextOverflowOptions',
+ 'TextPickerDialog', 'TextPickerDialogOptions', 'TextPickerOptions',
+ 'TextPickerRangeContent', 'TextPickerResult', 'TextPickerTextStyle', 'TextRange',
+ 'TextResponseType', 'TextSelectableMode', 'TextShadowStyle', 'TextSpanType',
+ 'TextStyle', 'TextTimerConfiguration', 'TextTimerController', 'TextTimerOptions',
+ 'Theme', 'ThemeColorMode', 'ThreatType', 'TimePickerDialog', 'TimePickerDialogOptions',
+ 'TimePickerFormat', 'TimePickerOptions', 'TimePickerResult', 'TipsOptions',
+ 'TitleHeight', 'TodayStyle', 'ToggleConfiguration', 'ToggleOptions', 'ToggleType',
+ 'ToolBarItemInterface', 'ToolBarItemOptions', 'ToolBarItemPlacement', 'ToolbarItem',
+ 'ToolbarItemStatus', 'TouchEvent', 'TouchObject', 'TouchPoint', 'TouchResult',
+ 'TouchTestInfo', 'TouchTestStrategy', 'TouchType', 'Trace', 'Track', 'TransitionEdge',
+ 'TransitionEffect', 'TransitionEffects', 'TransitionFinishCallback',
+ 'TransitionHierarchyStrategy', 'TransitionOptions', 'TransitionType',
+ 'TranslateOptions', 'UICommonEvent', 'UIContext', 'UIExtensionOptions',
+ 'UIExtensionProxy', 'UIGestureEvent', 'UnderlineColor', 'UnifiedData',
+ 'UniformDataType', 'UrlStyle', 'UserDataSpan', 'VMContext', 'VP', 'VelocityOptions',
+ 'VerticalAlign', 'VideoController', 'VideoOptions', 'View', 'ViewportFit',
+ 'ViewportRect', 'VirtualScrollOptions', 'Visibility', 'VisibleAreaChangeCallback',
+ 'VisibleAreaEventOptions', 'VisibleListContentInfo', 'VisualEffect', 'VoiceButtonOptions',
+ 'VoidCallback', 'Want', 'Watch', 'WaterFlowLayoutMode', 'WaterFlowOptions',
+ 'WaterFlowSections', 'WebCaptureMode', 'WebContextMenuParam', 'WebContextMenuResult',
+ 'WebController', 'WebCookie', 'WebDarkMode', 'WebElementType', 'WebHeader',
+ 'WebKeyboardAvoidMode', 'WebKeyboardCallback', 'WebKeyboardCallbackInfo',
+ 'WebKeyboardController', 'WebKeyboardOptions', 'WebLayoutMode', 'WebMediaOptions',
+ 'WebNavigationType', 'WebOptions', 'WebResourceError', 'WebResourceRequest',
+ 'WebResourceResponse', 'WebResponseType', 'WebviewController', 'Week', 'WeekStyle',
+ 'WidthBreakpoint', 'WindowAnimationTarget', 'WindowModeFollowStrategy',
+ 'WindowStatusType', 'WithThemeOptions', 'WordBreak', 'WorkStateStyle', 'WrappedBuilder',
+ 'XComponentController', 'XComponentOptions', 'XComponentType', 'animateTo',
+ 'animateToImmediately', 'cursorControl', 'focusControl', 'fp2px', 'getContext',
+ 'getInspectorNodeById', 'getInspectorNodes', 'lpx2px', 'postCardAction', 'px2fp',
+ 'px2lpx', 'px2vp', 'setAppBgColor', 'sharedTransitionOptions', 'vp2px'
+]);
+
+const decoratorsWhiteList = [
+ 'State', 'Prop', 'Link', 'Observed', 'Track', 'ObjectLink', 'StorageProp', 'StorageLink',
+ 'LocalStorageProp', 'LocalStorageLink', 'Provide', 'Consume', 'Watch',
+ 'Local', 'Param', 'Once', 'Event', 'Provider', 'Consumer', 'Monitor', 'Computed', '@ObservedV2', 'Trace',
+ 'Builder', 'BuildParam', 'Styles', 'Extend', 'AnimatableExtend', 'Type', 'Require',
+ 'Reusable', 'ReusableV2', 'Entry', 'Component', 'ComponentV2', 'CustomDialog'
+];
+
+const whiteFileList = [
+ '@ohos.app.ability.continueManager',
+ '@ohos.app.ability.InsightIntentDecorator',
+ '@ohos.app.ability.UIExtensionContentSession',
+ '@ohos.distributedsched.proxyChannelManager',
+ '@ohos.graphics.displaySync',
+ '@ohos.graphics.drawing',
+ '@ohos.graphics.text',
+ '@ohos.i18n',
+ '@ohos.inputMethodEngine',
+ '@ohos.userIAM.userAuth',
+ '@ohos.web.webview',
+ 'LiveFormExtensionContext',
+ 'Scene',
+ 'SceneResources',
+ 'UIAbilityContext',
+];
+
+const apiDir = [
+ 'ability', 'advertising', 'app', 'application', 'arkui', 'bundle', 'bundleManager', 'commonEvent',
+ 'continuation', 'data', 'global', 'graphics3d', 'multimedia', 'notification', 'security', 'tag',
+ 'wantAgent'
+];
+
+const apiInternalDir = [
+ '@internal/full'
+];
+
+export {
+ apiDir,
+ apiInternalDir,
+ whiteList,
+ decoratorsWhiteList,
+ whiteFileList,
+};
diff --git a/arkui_noninterop_plugin/src/collect_symbol/config.ts b/arkui_noninterop_plugin/src/collect_symbol/config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..630de068b0015c2f812551d947f8c41dd34a6f90
--- /dev/null
+++ b/arkui_noninterop_plugin/src/collect_symbol/config.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export const input: string = '';
+export const output: string = './export.ts';
diff --git a/arkui_noninterop_plugin/src/collect_symbol/index.ts b/arkui_noninterop_plugin/src/collect_symbol/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3693e104e62ebaa1b404bdb6d37563ca2e69902e
--- /dev/null
+++ b/arkui_noninterop_plugin/src/collect_symbol/index.ts
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from 'path';
+import * as fs from 'fs';
+
+import * as ts from 'typescript';
+
+import {
+ input,
+ output,
+} from './config';
+
+function readTsFile(filePath: string): string {
+ const absolutePath = path.resolve(filePath);
+ return fs.readFileSync(absolutePath, 'utf8');
+}
+
+function traverseAst(node: ts.Node, result: Set): void {
+ if (ts.isClassDeclaration(node) && node.name) {
+ result.add(node.name.text);
+ }
+
+ if (ts.isEnumDeclaration(node) && node.name) {
+ result.add(node.name.text);
+ }
+
+ ts.forEachChild(node, child => traverseAst(child, result));
+}
+
+function generateExportFile(identifiers: Array, outputPath: string): void {
+ if (identifiers.length === 0) {
+ return;
+ }
+
+ const exportContent = `export { ${identifiers.join(', ')} };\n`;
+ fs.writeFileSync(outputPath, exportContent, 'utf8');
+}
+
+function main(inputFilePath: string, outputFilePath: string): void {
+ const fileContent = readTsFile(inputFilePath);
+
+ const sourceFile = ts.createSourceFile(
+ inputFilePath,
+ fileContent,
+ ts.ScriptTarget.ESNext,
+ true
+ );
+
+ const identifiers: Set = new Set();
+ traverseAst(sourceFile, identifiers);
+
+ generateExportFile(Array.from(identifiers).sort(), outputFilePath);
+}
+
+main(input, output);
diff --git a/arkui_noninterop_plugin/src/delete_noninterop/add_export.ts b/arkui_noninterop_plugin/src/delete_noninterop/add_export.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8ce4792fcd87213cee4f946f144b5d7cd2d4b4a5
--- /dev/null
+++ b/arkui_noninterop_plugin/src/delete_noninterop/add_export.ts
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as ts from 'typescript';
+
+import { isNonInterop } from './utils';
+
+// add export for interface/class/enum/type/namespace, delete struct
+export default function processVisitEachChild(context: ts.TransformationContext, node: ts.SourceFile,
+ exportFlag: boolean): ts.SourceFile {
+ return ts.visitEachChild(node, processAllNodes, context);
+
+ function processAllNodes(node: ts.Node): ts.Node {
+ if (ts.isInterfaceDeclaration(node)) {
+ node = processInterfaceDeclaration(node, exportFlag);
+ } else if (ts.isClassDeclaration(node)) {
+ node = processClassDeclaration(node, exportFlag);
+ } else if (ts.isModuleDeclaration(node) && node.body && ts.isModuleBlock(node.body)) {
+ const newModuleBody: ts.ModuleBlock =
+ ts.factory.updateModuleBlock(node.body, getNewStatements(node));
+ node = ts.factory.updateModuleDeclaration(node, node.modifiers, node.name, newModuleBody);
+ } else if (ts.isEnumDeclaration(node)) {
+ node = processEnumDeclaration(node, exportFlag);
+ } else if (ts.isStructDeclaration(node)) {
+ node = processStructDeclaration(node);
+ } else if (ts.isTypeAliasDeclaration(node)) {
+ node = processTypeAliasDeclaration(node, exportFlag);
+ }
+ return ts.visitEachChild(node, processAllNodes, context);
+ }
+}
+
+function processInterfaceDeclaration(node: ts.InterfaceDeclaration,
+ exportFlag: boolean): ts.InterfaceDeclaration {
+ const newMembers: ts.TypeElement[] = [];
+ node.members.forEach((member) => {
+ if (!isNonInterop(member)) {
+ newMembers.push(member);
+ }
+ });
+ let modifiers = exportFlag ? addExport2Modifiers(node.modifiers!) : node.modifiers;
+ return ts.factory.updateInterfaceDeclaration(
+ node,
+ modifiers,
+ node.name,
+ node.typeParameters,
+ node.heritageClauses,
+ newMembers
+ );
+}
+
+function processClassDeclaration(node: ts.ClassDeclaration, exportFlag: boolean): ts.ClassDeclaration {
+ const newMembers: ts.ClassElement[] = [];
+ node.members.forEach((member) => {
+ if (!isNonInterop(member)) {
+ newMembers.push(member);
+ }
+ });
+ let modifiers = exportFlag ? addExport2Modifiers(node.modifiers!) : node.modifiers;
+ return ts.factory.updateClassDeclaration(
+ node,
+ modifiers,
+ node.name,
+ node.typeParameters,
+ node.heritageClauses,
+ newMembers
+ );
+}
+
+function processEnumDeclaration(node: ts.EnumDeclaration, exportFlag: boolean): ts.EnumDeclaration {
+ const newMembers: ts.EnumMember[] = [];
+ node.members.forEach((member) => {
+ if (!isNonInterop(member)) {
+ newMembers.push(member);
+ }
+ });
+ let modifiers = exportFlag ? addExport2Modifiers(node.modifiers!) : node.modifiers;
+ return ts.factory.updateEnumDeclaration(
+ node,
+ modifiers,
+ node.name,
+ newMembers
+ );
+}
+
+function processStructDeclaration(node: ts.StructDeclaration): ts.StructDeclaration {
+ const newMembers: ts.ClassElement[] = [];
+ node.members.forEach((member, index) => {
+ if (index >= 1 && !isNonInterop(member)) {
+ newMembers.push(member);
+ }
+ });
+ node = ts.factory.updateStructDeclaration(
+ node,
+ node.modifiers,
+ node.name,
+ node.typeParameters,
+ node.heritageClauses,
+ newMembers
+ );
+ return node;
+}
+
+function processTypeAliasDeclaration(node: ts.TypeAliasDeclaration,
+ exportFlag: boolean): ts.TypeAliasDeclaration {
+ if (exportFlag) {
+ return ts.factory.updateTypeAliasDeclaration(
+ node,
+ addExport2Modifiers(node.modifiers!),
+ node.name,
+ node.typeParameters,
+ node.type
+ );
+ } else {
+ return node;
+ }
+}
+
+function getNewStatements(node: ts.ModuleDeclaration): ts.Statement[] {
+ const newStatements: ts.Statement[] = [];
+ (node.body! as ts.ModuleBlock).statements.forEach((statement) => {
+ if (!isNonInterop(statement)) {
+ newStatements.push(statement);
+ }
+ });
+ return newStatements;
+}
+
+function addExport2Modifiers(
+ modifiers: ts.NodeArray): ts.NodeArray {
+ modifiers = modifiers || [];
+ const isAlreadyExported = modifiers.some(m => m.kind === ts.SyntaxKind.ExportKeyword);
+ if (!isAlreadyExported) {
+ modifiers = [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword),
+ ...modifiers] as unknown as ts.NodeArray;
+ }
+ return modifiers as ts.NodeArray;
+}
diff --git a/arkui_noninterop_plugin/src/delete_noninterop/delete_noninterop_api.ts b/arkui_noninterop_plugin/src/delete_noninterop/delete_noninterop_api.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f6c032c5de2cfd910a6384b75abe2bf796fa5f9e
--- /dev/null
+++ b/arkui_noninterop_plugin/src/delete_noninterop/delete_noninterop_api.ts
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from 'path';
+
+import * as ts from 'typescript';
+
+import {
+ ARKUI,
+ COMPONENT,
+ EXTNAME_TS,
+ OHOS_ARKUI,
+} from './pre_define';
+import { whiteFileList } from './white_management';
+import {
+ getFileAndKitComment,
+ getPureName,
+ isExistImportFile,
+ isNonInterop,
+ processFileName,
+ processFileNameWithoutExt,
+ } from './utils';
+import type {
+ ExportStatementType,
+ FormatNodeInfo,
+ NeedDeleteExportInfo,
+ ProcessSourceFileResult,
+ } from './type';
+import { componentEtsFiles } from './global_var';
+
+import processVisitEachChild from './add_export';
+import formatAllNodes from './format_import';
+import outputFile from './output_file';
+
+let sourceFile: ts.SourceFile | null = null;
+let componentEtsDeleteFiles: string[] = [];
+const kitFileNeedDeleteMap = new Map();
+
+export function deleteNonInteropApi(url: string, exportFlag: boolean, inputDir: string,
+ outputPath: string): ts.TransformerFactory {
+ return (context: ts.TransformationContext) => {
+ return (node: ts.SourceFile): ts.SourceFile => {
+ const fullText: string = String(node.getFullText());
+ let fileAndKitComment: string = getFileAndKitComment(fullText);
+ const copyrightMessage: string = fullText.replace(node.getText(), '').split(/\/\*\*/)[0] +
+ fileAndKitComment + '\n';
+ let kitName: string = '';
+ if (fullText.match(/\@kit (.*)\r?\n/g)) {
+ kitName = RegExp.$1.replace(/\s/g, '');
+ }
+ const fileName: string = processFileName(url);
+ sourceFile = node;
+
+ const deleteNode: ProcessSourceFileResult = processSourceFile(node, url);
+
+ node = processVisitEachChild(context, deleteNode.node, exportFlag);
+
+ if (needProcessLabelNonInterop(fileName, kitName, inputDir)) {
+ const printer: ts.Printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
+ const result: string = printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
+
+ ts.transpileModule(result, {
+ compilerOptions: {
+ target: ts.ScriptTarget.ES2017,
+ },
+ fileName: fileName,
+ transformers: {
+ before: [processDeleteNoninterop(url, exportFlag, inputDir, outputPath,
+ copyrightMessage, deleteNode.isCopyrightDeleted)]
+ },
+ });
+ }
+ return ts.factory.createSourceFile([], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken),
+ ts.NodeFlags.None);
+ };
+ };
+}
+
+function processSourceFile(node: ts.SourceFile, url: string): ProcessSourceFileResult {
+ let isCopyrightDeleted = false;
+ const newStatements: ts.Statement[] = [];
+ const newStatementsWithoutExport: ts.Statement[] = [];
+ const deleteNonInteropApiSet: Set = new Set();
+ let needDeleteExport: NeedDeleteExportInfo = {
+ fileName: '',
+ default: '',
+ exportName: new Set(),
+ };
+ isCopyrightDeleted = addNewStatements(node, newStatements, deleteNonInteropApiSet, needDeleteExport);
+ newStatements.forEach((statement) => {
+ const names = getExportIdentifierName(statement);
+ if (ts.isExportDeclaration(statement) && statement.moduleSpecifier &&
+ ts.isStringLiteral(statement.moduleSpecifier) &&
+ statement.moduleSpecifier.text.startsWith(`./${ARKUI}/${COMPONENT}/`)) {
+ const importPath = statement.moduleSpecifier.text.replace(`./${ARKUI}/${COMPONENT}/`, '');
+ const isDeleteSystemFile = componentEtsDeleteFiles.includes(getPureName(importPath));
+ const hasEtsFile = componentEtsFiles.includes(getPureName(importPath));
+ const existFile = isExistImportFile(path.dirname(url), statement.moduleSpecifier.text.toString());
+ if (isDeleteSystemFile || !hasEtsFile && !existFile) {
+ return;
+ }
+ }
+ if (names.length === 0) {
+ newStatementsWithoutExport.push(statement);
+ return;
+ }
+ if (names.length === 1 && !deleteNonInteropApiSet.has(names[0])) {
+ newStatementsWithoutExport.push(statement);
+ return;
+ }
+ processExportNode(statement, node, needDeleteExport, names, deleteNonInteropApiSet,
+ newStatementsWithoutExport);
+ });
+ if (needDeleteExport.fileName !== '') {
+ kitFileNeedDeleteMap.set(needDeleteExport.fileName, needDeleteExport);
+ }
+ return {
+ node: ts.factory.updateSourceFile(node, newStatementsWithoutExport, node.isDeclarationFile,
+ node.referencedFiles),
+ isCopyrightDeleted,
+ };
+}
+
+function needProcessLabelNonInterop(fileName: string, kitName: string, inputDir: string): boolean {
+ if (inputDir.endsWith(COMPONENT) || fileName.startsWith(OHOS_ARKUI) ||
+ kitName.toLowerCase() === ARKUI || whiteFileList.includes(fileName.slice(0, -EXTNAME_TS.length))) {
+ return true;
+ }
+ return false;
+}
+
+function processDeleteNoninterop(url: string, exportFlag: boolean, inputDir: string,
+ outputPath: string, copyrightMessage = '', isCopyrightDeleted = false) {
+ return (context: ts.TransformationContext) => {
+ return (node: ts.SourceFile): ts.SourceFile => {
+ sourceFile = node;
+ const allIdentifierSet: Set = collectAllIdentifier(node, context);
+ const formatValue: FormatNodeInfo = formatAllNodes(url, inputDir, node, allIdentifierSet);
+ node = formatValue.node;
+ const referencesMessage = formatValue.referencesMessage;
+ if (formatValue.isCopyrightDeleted) {
+ copyrightMessage = formatValue.copyrightMessage;
+ isCopyrightDeleted = formatValue.isCopyrightDeleted;
+ }
+ outputFile(url, exportFlag, inputDir, outputPath, node, sourceFile, referencesMessage,
+ copyrightMessage, isCopyrightDeleted);
+ return ts.factory.createSourceFile([], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken),
+ ts.NodeFlags.None);
+ };
+ };
+}
+
+function collectAllIdentifier(node: ts.SourceFile, context: ts.TransformationContext): Set {
+ const identifierSet: Set = new Set([]);
+ if (!ts.isSourceFile(node) || !node.statements) {
+ return identifierSet;
+ }
+ node.statements.forEach((stat) => {
+ if (!ts.isImportDeclaration(stat)) {
+ ts.visitEachChild(stat, collectAllNodes, context);
+ }
+ });
+
+ function collectAllNodes(node: ts.Node): ts.Node {
+ if (ts.isIdentifier(node)) {
+ identifierSet.add(node.escapedText.toString());
+ }
+ return ts.visitEachChild(node, collectAllNodes, context);
+ }
+
+ return identifierSet;
+}
+
+function addNewStatements(node: ts.SourceFile, newStatements: ts.Statement[],
+ deleteNonInteropApiSet: Set, needDeleteExport: NeedDeleteExportInfo): boolean {
+ let isCopyrightDeleted = false;
+ node.statements.forEach((statement, index) => {
+ if (!isNonInterop(statement)) {
+ newStatements.push(statement);
+ return;
+ }
+ if (index === 0) {
+ isCopyrightDeleted = true;
+ }
+ if (ts.isVariableStatement(statement)) {
+ deleteNonInteropApiSet.add(variableStatementGetEscapedText(statement));
+ } else if (
+ ts.isModuleDeclaration(statement) ||
+ ts.isInterfaceDeclaration(statement) ||
+ ts.isClassDeclaration(statement) ||
+ ts.isEnumDeclaration(statement) ||
+ ts.isStructDeclaration(statement) ||
+ ts.isTypeAliasDeclaration(statement)
+ ) {
+ if (statement && statement.name && (statement.name as ts.Identifier).escapedText) {
+ deleteNonInteropApiSet.add((statement.name as ts.Identifier).escapedText.toString());
+ }
+ setDeleteExport(statement, node, needDeleteExport, deleteNonInteropApiSet);
+ } else if (ts.isExportAssignment(statement) || ts.isExportDeclaration(statement)) {
+ setDeleteExport(statement, node, needDeleteExport, deleteNonInteropApiSet);
+ }
+ });
+
+ return isCopyrightDeleted;
+}
+
+function variableStatementGetEscapedText(statement: ts.VariableStatement): string {
+ let name = '';
+ if (
+ statement &&
+ statement.declarationList &&
+ statement.declarationList.declarations &&
+ statement.declarationList.declarations.length > 0 &&
+ statement.declarationList.declarations[0].name &&
+ (statement.declarationList.declarations[0].name as ts.Identifier).escapedText
+ ) {
+ name = (statement.declarationList.declarations[0].name as ts.Identifier).escapedText.toString();
+ }
+ return name;
+}
+
+function processExportNode(statement: ts.Statement, node: ts.SourceFile,
+ needDeleteExport: NeedDeleteExportInfo, names: string[], deleteNonInteropApiSet: Set,
+ newStatementsWithoutExport: ts.Statement[]): void {
+ if (ts.isExportAssignment(statement)) {
+ needDeleteExport.fileName = processFileNameWithoutExt(node.fileName);
+ needDeleteExport.default = (statement.expression as ts.Identifier).escapedText.toString();
+ } else if (ts.isExportDeclaration(statement)) {
+ let needExport = false;
+ const newSpecifiers: ts.ExportSpecifier[] = [];
+ names.forEach((name, index) => {
+ const exportSpecifier: ts.ExportSpecifier =
+ (statement.exportClause! as ts.NamedExports).elements![index];
+ if (!deleteNonInteropApiSet.has(name)) {
+ newSpecifiers.push(exportSpecifier);
+ needExport = true;
+ } else {
+ needDeleteExport.fileName = processFileNameWithoutExt(node.fileName);
+ needDeleteExport.exportName.add(exportSpecifier.name.escapedText.toString());
+ }
+ });
+ if (needExport) {
+ (statement.exportClause as ts.NamedExports) = ts.factory.updateNamedExports(
+ statement.exportClause as ts.NamedExports, newSpecifiers);
+ newStatementsWithoutExport.push(statement);
+ }
+ }
+}
+
+function setDeleteExport(statement: ts.Statement, node: ts.SourceFile, needDeleteExport: NeedDeleteExportInfo,
+ deleteNonInteropApiSet: Set): void {
+ if (ts.isExportAssignment(statement) &&
+ deleteNonInteropApiSet.has((statement.expression as ts.Identifier).escapedText.toString())) {
+ needDeleteExport.fileName = processFileNameWithoutExt(node.fileName);
+ needDeleteExport.default = (statement.expression as ts.Identifier).escapedText.toString();
+ } else if (ts.isExportDeclaration(statement)) {
+ needDeleteExport.fileName = processFileNameWithoutExt(node.fileName);
+ (statement.exportClause! as ts.NamedExports).elements.forEach((element) => {
+ const exportName = element.propertyName ?
+ element.propertyName.escapedText.toString() :
+ element.name.escapedText.toString();
+ if (deleteNonInteropApiSet.has(exportName)) {
+ needDeleteExport.exportName.add(element.name.escapedText.toString());
+ }
+ });
+ }
+ //export namespace xxx {}
+ const modifiers = statement.modifiers;
+ if (modifiers === undefined) {
+ return;
+ }
+ const exportFlag = modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword);
+ const defaultFlag = modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword);
+ if (exportFlag && defaultFlag) {
+ needDeleteExport.fileName = processFileNameWithoutExt(node.fileName);
+ needDeleteExport.default = ((statement! as ExportStatementType)!.name! as ts.Identifier)
+ .escapedText.toString();
+ } else if (exportFlag) {
+ needDeleteExport.fileName = processFileNameWithoutExt(node.fileName);
+ needDeleteExport.exportName.add(((statement! as ExportStatementType)!.name! as ts.Identifier)
+ .escapedText.toString());
+ }
+}
+
+function getExportIdentifierName(statement: ts.Statement): string[] {
+ const names = [];
+ if (ts.isExpressionStatement(statement)) {
+ // exports.name = xxx;
+ if (ts.isBinaryExpression(statement.expression) && ts.isIdentifier(statement.expression.right) &&
+ statement.expression.right.escapedText) {
+ names.push(statement.expression.right.escapedText.toString());
+ }
+ } else if (ts.isExportAssignment(statement)) {
+ // export default xxx
+ names.push((statement.expression as ts.Identifier).escapedText.toString());
+ } else if (ts.isExportDeclaration(statement) && statement.exportClause) {
+ // export {xxx} 、export {xxx as yyy} 、export * from './zzz'
+ const specifiers = (statement.exportClause as ts.NamedExports).elements;
+ specifiers.forEach((specifier) => {
+ if (ts.isExportSpecifier(specifier)) {
+ const name = specifier.propertyName ? specifier.propertyName : specifier.name;
+ names.push(name.escapedText.toString());
+ }
+ });
+ }
+ return names;
+}
diff --git a/arkui_noninterop_plugin/src/delete_noninterop/format_import.ts b/arkui_noninterop_plugin/src/delete_noninterop/format_import.ts
new file mode 100644
index 0000000000000000000000000000000000000000..43043f6177da90f845f09d1d79bd55acdd90d339
--- /dev/null
+++ b/arkui_noninterop_plugin/src/delete_noninterop/format_import.ts
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from 'path';
+
+import * as ts from 'typescript';
+
+import {
+ ARKUI,
+ ARKTS,
+ COMPONENT,
+ ANY,
+ ETS,
+ INTERNAL,
+ EXIST,
+ NON_EXIST,
+ FRAMENODE,
+ TYPENODE,
+ XCOMPONENT,
+} from './pre_define';
+import {
+ getCoreFilename,
+ getPureName,
+ isExistImportFile,
+ } from './utils';
+import type {
+ ClauseSetValueInfo,
+ FormatImportInfo,
+ FormatNodeInfo,
+ ReferenceModuleInfo,
+ } from './type';
+import { componentEtsFiles } from './global_var';
+
+const globalModules = new Map();
+
+export default function formatAllNodes(url: string, inputDir: string, node: ts.SourceFile,
+ allIdentifierSet: Set, copyrightMessage = '',
+ isCopyrightDeleted = false): FormatNodeInfo {
+ let referencesMessage: string = '';
+ let currReferencesModule: ReferenceModuleInfo[] = [];
+ if (!ts.isSourceFile(node) || !node.statements) {
+ return { node, referencesMessage, copyrightMessage, isCopyrightDeleted };
+ }
+ const newStatements: ts.Statement[] = [];
+ node.statements.forEach((statement) => {
+ if (ts.isImportDeclaration(statement)) {
+ const importInfo: FormatImportInfo = formatAllNodesImportDeclaration(node, statement, url,
+ inputDir, currReferencesModule, allIdentifierSet);
+ if (importInfo.statement) {
+ newStatements.push(statement);
+ } else if (importInfo.isCopyrightDeleted) {
+ copyrightMessage = importInfo.copyrightMessage!;
+ isCopyrightDeleted = importInfo.isCopyrightDeleted;
+ }
+ } else if (ts.isStructDeclaration(statement)) {
+ statement = ts.factory.updateStructDeclaration(statement, statement.modifiers, statement.name,
+ statement.typeParameters, statement.heritageClauses, statement.members.slice(1));
+ newStatements.push(statement);
+ } else {
+ newStatements.push(statement);
+ }
+ });
+
+ addForSpecialFiles(node, newStatements);
+
+ currReferencesModule.forEach((item) => {
+ if (item.isUsed) {
+ referencesMessage += item.reference + '\n';
+ }
+ });
+ node = ts.factory.updateSourceFile(node, newStatements);
+ return { node, referencesMessage, copyrightMessage, isCopyrightDeleted };
+}
+
+function formatAllNodesImportDeclaration(node: ts.SourceFile, statement: ts.ImportDeclaration,
+ url: string, inputDir: string, currReferencesModule: ReferenceModuleInfo[],
+ allIdentifierSet: Set): FormatImportInfo {
+ const clauseSet: Set = getClauseSet(statement);
+ const importSpecifier: string = statement.moduleSpecifier.getText().replace(/[\'\"]/g, '');
+ const fileDir: string = path.dirname(url);
+ const hasImportSpecifierFile: boolean = hasFileByImportPath(importSpecifier, fileDir, inputDir);
+ let hasImportSpecifierInModules: boolean = globalModules.has(importSpecifier);
+ if ((!hasImportSpecifierFile && !hasImportSpecifierInModules) || clauseSet.size === 0) {
+ if (hasCopyright(statement)) {
+ return { copyrightMessage: node.getFullText().replace(node.getText(), ''), isCopyrightDeleted: true };
+ } else {
+ return { statement: undefined, copyrightMessage: '', isCopyrightDeleted: false };
+ }
+ }
+ const clauseSetValue: ClauseSetValueInfo = getExsitClauseSet(hasImportSpecifierInModules, importSpecifier,
+ currReferencesModule, clauseSet, allIdentifierSet);
+ const hasExsitStatus: boolean = clauseSetValue.hasExsitStatus;
+ const hasNonExsitStatus: boolean = clauseSetValue.hasNonExsitStatus;
+ const exsitClauseSet: Set = clauseSetValue.exsitClauseSet;
+ if (hasExsitStatus) {
+ return handleUsedImport(hasNonExsitStatus, statement, exsitClauseSet,
+ hasImportSpecifierInModules, currReferencesModule, importSpecifier);
+ } else if (hasCopyright(statement)) {
+ return { copyrightMessage: node.getFullText().replace(node.getText(), ''), isCopyrightDeleted: true };
+ } else {
+ return { statement: undefined, copyrightMessage: '', isCopyrightDeleted: false };
+ }
+}
+
+function addForSpecialFiles(node: ts.SourceFile, newStatements: ts.Statement[]): void {
+ const fileName = getCoreFilename(path.basename(node.fileName));
+ if (fileName === FRAMENODE) {
+ newStatements.push(createFrameNodeTypeNode());
+ }
+}
+
+function hasFileByImportPath(importPath: string, apiDir: string, inputDir: string): boolean {
+ let fileDir: string = path.resolve(apiDir);
+ if (importPath.startsWith(`@${ARKTS}`)) {
+ fileDir = path.resolve(inputDir, `../${ARKTS}`);
+ }
+ return isExistArkUIFile(path.resolve(inputDir, ARKUI, COMPONENT), importPath, inputDir) ||
+ isExistImportFile(fileDir, importPath);
+}
+
+function isExistArkUIFile(resolvedPath: string, importPath: string, inputDir: string): boolean {
+ const filePath = path.resolve(resolvedPath, importPath);
+ if (filePath.includes(path.resolve(inputDir, INTERNAL, COMPONENT, ETS)) ||
+ filePath.includes(path.resolve(inputDir, ARKUI, COMPONENT))
+ ) {
+ const fileName = getPureName(filePath);
+ return componentEtsFiles.includes(fileName);
+ }
+ return isExistImportFile(resolvedPath, importPath);
+}
+
+function createFrameNodeTypeNode(): ts.ModuleDeclaration {
+ return ts.factory.createModuleDeclaration(
+ [
+ ts.factory.createToken(ts.SyntaxKind.ExportKeyword),
+ ts.factory.createToken(ts.SyntaxKind.DeclareKeyword)
+ ],
+ ts.factory.createIdentifier(TYPENODE),
+ ts.factory.createModuleBlock([ts.factory.createTypeAliasDeclaration(
+ undefined,
+ ts.factory.createIdentifier(XCOMPONENT),
+ undefined,
+ ts.factory.createTypeReferenceNode(
+ ts.factory.createIdentifier(ANY),
+ undefined
+ )
+ )]),
+ ts.NodeFlags.Namespace | ts.NodeFlags.ExportContext | ts.NodeFlags.ContextFlags
+ );
+}
+
+function hasCopyright(node: ts.ImportDeclaration): boolean {
+ return /http\:\/\/www\.apache\.org\/licenses\/LICENSE\-2\.0/g.test(node.getFullText()
+ .replace(node.getText(), ''));
+}
+
+function getClauseSet(statement: ts.ImportDeclaration): Set {
+ const clauseSet: Set = new Set([]);
+ if (!statement.importClause || !ts.isImportClause(statement.importClause)) {
+ return clauseSet;
+ }
+ const clauseNode: ts.ImportClause = statement.importClause;
+ if (!clauseNode.namedBindings && clauseNode.name && ts.isIdentifier(clauseNode.name)) {
+ clauseSet.add(clauseNode.name.escapedText.toString());
+ } else if (clauseNode.namedBindings && ts.isNamespaceImport(clauseNode.namedBindings) &&
+ clauseNode.namedBindings.name && ts.isIdentifier(clauseNode.namedBindings.name)) {
+ clauseSet.add(clauseNode.namedBindings.name.escapedText.toString());
+ } else if (clauseNode.namedBindings && ts.isNamedImports(clauseNode.namedBindings) &&
+ clauseNode.namedBindings.elements) {
+ clauseNode.namedBindings.elements.forEach((ele) => {
+ if (ele.name && ts.isIdentifier(ele.name)) {
+ clauseSet.add(ele.name.escapedText.toString());
+ }
+ });
+ }
+ return clauseSet;
+}
+
+function getExsitClauseSet(hasImportSpecifierInModules: boolean, importSpecifier: string,
+ currReferencesModule: ReferenceModuleInfo[], clauseSet: Set,
+ allIdentifierSet: Set): ClauseSetValueInfo {
+ let currModule: string[] = [];
+ if (hasImportSpecifierInModules) {
+ let index: number = globalModules.get(importSpecifier);
+ const referenceModule: ReferenceModuleInfo = currReferencesModule[index];
+ currModule = referenceModule.modules[importSpecifier]!;
+ }
+ const clasueCheckList = [];
+ let exsitClauseSet: Set = new Set([]);
+ for (const clause of clauseSet) {
+ let flag = allIdentifierSet.has(clause);
+ if (hasImportSpecifierInModules) {
+ flag = allIdentifierSet.has(clause) && currModule.includes(clause);
+ }
+ if (flag) {
+ // use import
+ exsitClauseSet.add(clause);
+ clasueCheckList.push(EXIST);
+ } else {
+ clasueCheckList.push(NON_EXIST);
+ }
+ }
+ let hasExsitStatus = false;
+ let hasNonExsitStatus = false;
+ clasueCheckList.forEach((ele) => {
+ if (ele === EXIST) {
+ hasExsitStatus = true;
+ } else {
+ hasNonExsitStatus = true;
+ }
+ });
+ return { exsitClauseSet, hasExsitStatus, hasNonExsitStatus };
+}
+
+function handleUsedImport(hasNonExsitStatus: boolean, statement: ts.ImportDeclaration,
+ exsitClauseSet: Set, hasImportSpecifierInModules: boolean,
+ currReferencesModule: ReferenceModuleInfo[], importSpecifier: string): FormatImportInfo {
+ if (hasNonExsitStatus) {
+ const newSpecifiers: ts.ImportSpecifier[] = [];
+ (statement.importClause!.namedBindings! as ts.NamedImports).elements.forEach((element) => {
+ if (exsitClauseSet.has(element.name.escapedText.toString())) {
+ newSpecifiers.push(element);
+ }
+ });
+ if (statement.importClause && ts.isNamedImports(statement.importClause.namedBindings!)) {
+ // @ts-ignore
+ statement.importClause.namedBindings = ts.factory.updateNamedImports(
+ statement.importClause.namedBindings,
+ newSpecifiers
+ );
+ }
+ }
+ if (hasImportSpecifierInModules) {
+ let index = globalModules.get(importSpecifier);
+ currReferencesModule[index].isUsed = true;
+ }
+ return { statement };
+}
diff --git a/arkui_noninterop_plugin/src/delete_noninterop/global_var.ts b/arkui_noninterop_plugin/src/delete_noninterop/global_var.ts
new file mode 100644
index 0000000000000000000000000000000000000000..def2cc05094e55859683e7b942d1674d39aecf7a
--- /dev/null
+++ b/arkui_noninterop_plugin/src/delete_noninterop/global_var.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export const stmtReplacementMap = new Map();
+export const componentEtsFiles: string[] = [];
diff --git a/arkui_noninterop_plugin/src/delete_noninterop/index.ts b/arkui_noninterop_plugin/src/delete_noninterop/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ea0f9905dab4f47b514473ce4ae7f7563edd9bcb
--- /dev/null
+++ b/arkui_noninterop_plugin/src/delete_noninterop/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import start from './start';
+
+start();
diff --git a/arkui_noninterop_plugin/src/delete_noninterop/output_file.ts b/arkui_noninterop_plugin/src/delete_noninterop/output_file.ts
new file mode 100644
index 0000000000000000000000000000000000000000..53defd9e461bfc96d498d23c21f4f32492bf8c92
--- /dev/null
+++ b/arkui_noninterop_plugin/src/delete_noninterop/output_file.ts
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from 'path';
+import * as fs from 'fs';
+
+import * as ts from 'typescript';
+
+import { GLOBAL_ESVALUE_FILE } from './pre_define';
+import {
+ removeNonInteropDoc,
+ removeComments,
+ writeFile,
+ } from './utils';
+
+import { stmtReplacementMap } from './global_var';
+
+export default function outputFile(url: string, exportFlag: boolean, inputDir: string,
+ outputPath: string, node: ts.SourceFile, sourceFile: ts.SourceFile, referencesMessage: string,
+ copyrightMessage: string, isCopyrightDeleted: boolean): void {
+ const printer: ts.Printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
+ let result: string = printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
+ if (isCopyrightDeleted) {
+ result = copyrightMessage + '\n' + result;
+ }
+ copyrightMessage = node.getFullText().replace(node.getText(), '');
+ if (referencesMessage) {
+ result = result.substring(0, copyrightMessage.length) + '\n' + referencesMessage +
+ result.substring(copyrightMessage.length);
+ }
+ result = removeNonInteropDoc(result);
+ result = postProcessContent(result);
+ writeFile(url, result, inputDir, outputPath);
+ // api in component need merge
+ if (exportFlag) {
+ writeGlobalESValueFile(removeComments(result), outputPath);
+ }
+}
+
+function postProcessContent(content: string): string {
+ for (const [originalStmt, transformedStmt] of stmtReplacementMap) {
+ content = content.replace(transformedStmt, originalStmt);
+ }
+ return content.replace(/^(\s*)\/\*\*\@reserved (.*) \*\/$/mg, '$1$2');
+}
+
+function writeGlobalESValueFile(content: string, outputPath: string): void {
+ content = content.replace("'use static';", '').replace(/\.\.\/api/g, '.');
+ fs.appendFileSync(`${path.resolve(outputPath, '../api')}/${GLOBAL_ESVALUE_FILE}`, content);
+}
diff --git a/arkui_noninterop_plugin/src/delete_noninterop/pre_define.ts b/arkui_noninterop_plugin/src/delete_noninterop/pre_define.ts
new file mode 100644
index 0000000000000000000000000000000000000000..80e433bd395f54e7fb641628609cc487a61f3c92
--- /dev/null
+++ b/arkui_noninterop_plugin/src/delete_noninterop/pre_define.ts
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export const GLOBAL_ESVALUE_FILE: string = '@ohos.arkui.GlobalESValue.d.ts';
+export const ARKUI: string = 'arkui';
+export const ARKTS: string = 'arkts';
+export const COMPONENT: string = 'component';
+
+export const ANY: string = 'Any';
+export const EXTNAME_D_TS: string = '.d.ts';
+export const EXTNAME_D_ETS: string = '.d.ets';
+export const EXTNAME_TS: string = '.ts';
+export const EXTNAME_ETS: string = '.ets';
+export const ETS: string = 'ets';
+export const INTERNAL: string = '@internal';
+export const EXIST: string = 'exist';
+export const NON_EXIST: string = 'non-exist';
+export const OHOS_ARKUI: string = '@ohos.arkui';
+
+export const FRAMENODE: string = 'FrameNode';
+export const TRUE: string = 'true';
+export const TYPENODE: string = 'typeNode';
+export const XCOMPONENT: string = 'XComponent';
+
+export const ALERT_DIALOG: string = 'alert_dialog';
+export const ALERT_DIALOG_TEXT_STYLE: string = 'AlertDialogTextStyle';
+export const COMMON: string = 'common';
+export const COMMON_LINEAR_GRADIENT: string = 'CommonLinearGradient';
diff --git a/arkui_noninterop_plugin/src/delete_noninterop/process_label_noninterop.ts b/arkui_noninterop_plugin/src/delete_noninterop/process_label_noninterop.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c4c64e7875433d949b4d18dcaf1b370ceab57dd9
--- /dev/null
+++ b/arkui_noninterop_plugin/src/delete_noninterop/process_label_noninterop.ts
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from 'path';
+import * as fs from 'fs';
+
+import * as ts from 'typescript';
+
+import {
+ processFileName,
+ writeFile,
+ } from './utils';
+import { stmtReplacementMap } from './global_var';
+import {
+ isSpecialFile,
+ processSpecialFileContext,
+} from './process_special_file';
+
+export function tsTransform(utFiles: string[], callback: Function, exportFlag: boolean,
+ inputDir: string, outputPath: string): void {
+ utFiles.forEach((url) => {
+ const apiBaseName = path.basename(url);
+ let content = fs.readFileSync(url, 'utf-8');
+ let isTransformer = /\.d\.ts/.test(apiBaseName) || /\.d\.ets/.test(apiBaseName);
+ if (/\.json/.test(url)) {
+ isTransformer = false;
+ }
+ if (!isTransformer) {
+ writeFile(url, content, inputDir, outputPath);
+ return;
+ }
+ const fileName = processFileName(url);
+ ts.transpileModule(preprocessContent(fileName, content), {
+ compilerOptions: {
+ target: ts.ScriptTarget.ES2017,
+ },
+ fileName: fileName,
+ transformers: { before: [callback(url, exportFlag, inputDir, outputPath)] },
+ });
+ });
+}
+
+function preprocessContent(fileName: string, content: string): string {
+ stmtReplacementMap.clear();
+ let result = content.replace(/^(\s*)(\@Retention\(\{[^\(\)\{\}]*\}\)$)/mg,
+ '$1/**@reserved $2 */');
+ const matches = result.match(/(^[^\*]*\s+\@interface\s+.*$)/mg);
+ if (matches) {
+ for (const match of matches) {
+ const transformedStmt: string = match.replace(/(?<=\s+)\@interface(\s+\w+)\s*\{\}/g, 'const$1');
+ result = result.replace(match, transformedStmt);
+ stmtReplacementMap.set(match, transformedStmt);
+ }
+ }
+
+ if (isSpecialFile(fileName)) {
+ result = processSpecialFileContext(fileName, result);
+ }
+ return result;
+}
diff --git a/arkui_noninterop_plugin/src/delete_noninterop/process_special_file.ts b/arkui_noninterop_plugin/src/delete_noninterop/process_special_file.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9705f33960c1a6347ed407a57eead80e4cc9c78f
--- /dev/null
+++ b/arkui_noninterop_plugin/src/delete_noninterop/process_special_file.ts
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from 'path';
+
+import {
+ ALERT_DIALOG,
+ ALERT_DIALOG_TEXT_STYLE,
+ COMMON,
+ COMMON_LINEAR_GRADIENT,
+ EXTNAME_TS,
+} from './pre_define';
+
+import { specialFileList } from './white_management';
+
+function processSpecialFileContext(fileName: string, context: string): string {
+ fileName = path.basename(fileName, EXTNAME_TS);
+ if (fileName === ALERT_DIALOG) {
+ context = context.replace(/\bTextStyle\b/g, ALERT_DIALOG_TEXT_STYLE);
+ }
+ if (fileName === COMMON) {
+ context = context.replace(/\bLinearGradient\b/g, COMMON_LINEAR_GRADIENT);
+ }
+ return context;
+}
+
+function isSpecialFile(url: string): boolean {
+ return specialFileList.includes(path.basename(url, EXTNAME_TS));
+}
+
+export {
+ isSpecialFile,
+ processSpecialFileContext,
+};
diff --git a/arkui_noninterop_plugin/src/delete_noninterop/start.ts b/arkui_noninterop_plugin/src/delete_noninterop/start.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cba2f0d11284f98c544924111951434d8dd4d525
--- /dev/null
+++ b/arkui_noninterop_plugin/src/delete_noninterop/start.ts
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as commander from 'commander';
+
+import { TRUE } from './pre_define';
+import { transformFiles } from './transform_plugin';
+
+let outputPath: string = '';
+let inputDir: string = '';
+let exportFlag: boolean = false;
+
+export default function start(): void {
+ const program = new commander.Command();
+ program
+ .name('noninterop')
+ .version('0.0.1');
+ program
+ .option('--input ', 'input path')
+ .option('--output ', 'output path')
+ .option('--export ', 'export flag', false)
+ .action((opts) => {
+ outputPath = opts.output;
+ inputDir = opts.input;
+ exportFlag = opts.export === TRUE;
+ transformFiles(inputDir, outputPath, exportFlag);
+ });
+ program.parse(process.argv);
+}
diff --git a/arkui_noninterop_plugin/src/delete_noninterop/transform_plugin.ts b/arkui_noninterop_plugin/src/delete_noninterop/transform_plugin.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c23e49e25a5507b0d62e228cb912726c3f460233
--- /dev/null
+++ b/arkui_noninterop_plugin/src/delete_noninterop/transform_plugin.ts
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from 'path';
+import * as fs from 'fs';
+
+import { GLOBAL_ESVALUE_FILE } from './pre_define';
+import { readFile } from './utils';
+
+import { tsTransform } from './process_label_noninterop';
+import { deleteNonInteropApi } from './delete_noninterop_api';
+
+export function transformFiles(inputDir: string, outputPath: string, exportFlag: boolean): void {
+ try {
+ if (exportFlag) {
+ initGlobalESValueFile(outputPath);
+ }
+ const utFiles: string[] = [];
+ readFile(inputDir, utFiles);
+ tsTransform(utFiles, deleteNonInteropApi, exportFlag, inputDir, outputPath);
+ } catch (error) {
+ // ignore
+ }
+}
+
+function initGlobalESValueFile(outputPath: string): void {
+ const filePath: string = `${path.resolve(outputPath, '../api')}/${GLOBAL_ESVALUE_FILE}`;
+ const dir: string = path.dirname(filePath);
+ fs.mkdirSync(dir, { recursive: true });
+ fs.writeFileSync(filePath, '');
+}
diff --git a/arkui_noninterop_plugin/src/delete_noninterop/type.ts b/arkui_noninterop_plugin/src/delete_noninterop/type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..240a0313c801d64e0165bd90da995614511fd078
--- /dev/null
+++ b/arkui_noninterop_plugin/src/delete_noninterop/type.ts
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as ts from 'typescript';
+
+interface ProcessSourceFileResult {
+ node: ts.SourceFile;
+ isCopyrightDeleted: boolean;
+}
+
+interface NeedDeleteExportInfo {
+ fileName: string;
+ default: string;
+ exportName: Set;
+}
+
+interface ReferenceModuleInfo {
+ isUsed: boolean;
+ modules: Record;
+ reference?: string;
+}
+
+interface FormatNodeInfo {
+ node: ts.SourceFile;
+ referencesMessage: string;
+ copyrightMessage: string;
+ isCopyrightDeleted: boolean;
+}
+
+interface FormatImportInfo {
+ statement?: ts.ImportDeclaration;
+ copyrightMessage?: string;
+ isCopyrightDeleted?: boolean;
+}
+
+interface ClauseSetValueInfo {
+ exsitClauseSet: Set;
+ hasExsitStatus: boolean;
+ hasNonExsitStatus: boolean;
+}
+
+type ExportStatementType = ts.ModuleDeclaration |
+ ts.InterfaceDeclaration |
+ ts.ClassDeclaration |
+ ts.EnumDeclaration |
+ ts.StructDeclaration |
+ ts.TypeAliasDeclaration;
+
+export type {
+ ClauseSetValueInfo,
+ ExportStatementType,
+ FormatImportInfo,
+ FormatNodeInfo,
+ NeedDeleteExportInfo,
+ ProcessSourceFileResult,
+ ReferenceModuleInfo,
+};
diff --git a/arkui_noninterop_plugin/src/delete_noninterop/utils.ts b/arkui_noninterop_plugin/src/delete_noninterop/utils.ts
new file mode 100644
index 0000000000000000000000000000000000000000..049f0e47892747a4cb91f7c23fa67c41358e7fda
--- /dev/null
+++ b/arkui_noninterop_plugin/src/delete_noninterop/utils.ts
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from 'path';
+import * as fs from 'fs';
+
+import * as ts from 'typescript';
+
+import {
+ EXTNAME_D_TS,
+ EXTNAME_D_ETS,
+ EXTNAME_TS,
+ EXTNAME_ETS,
+} from './pre_define';
+
+function readFile(dir: string, utFiles: string[]): void {
+ try {
+ const files = fs.readdirSync(dir);
+ files.forEach((element: string): void => {
+ const filePath = path.join(dir, element);
+ const status = fs.statSync(filePath);
+ if (status.isDirectory()) {
+ readFile(filePath, utFiles);
+ } else {
+ utFiles.push(filePath);
+ }
+ });
+ } catch (e) {
+ // ignore
+ }
+}
+
+function processFileName(filePath: string): string {
+ return path.basename(filePath)
+ .replace(/\.d\.ts$/g, EXTNAME_TS)
+ .replace(/\.d\.ets$/g, EXTNAME_ETS);
+}
+
+function processFileNameWithoutExt(filePath: string): string {
+ return path.basename(filePath)
+ .replace(/\.d\.ts$/g, '')
+ .replace(/\.d\.ets$/g, '')
+ .replace(/\.ts$/g, '')
+ .replace(/\.ets$/g, '');
+}
+
+function getPureName(name: string): string {
+ return path.basename(name)
+ .replace(EXTNAME_D_TS, '')
+ .replace(EXTNAME_D_ETS, '')
+ .replace(/_/g, '')
+ .toLowerCase();
+}
+
+function isExistImportFile(fileDir: string, importPath: string): boolean {
+ return [EXTNAME_D_TS, EXTNAME_D_ETS].some(ext => {
+ return fs.existsSync(path.resolve(fileDir, `${importPath}${ext}`));
+ });
+}
+
+function getCoreFilename(fileName: string): string {
+ if (fileName.endsWith(EXTNAME_TS)) {
+ return fileName.slice(0, -EXTNAME_TS.length);
+ }
+ return fileName;
+}
+
+function getFileAndKitComment(fileFullText: string): string {
+ let fileAndKitComment: string = '';
+ let pattern: RegExp = /\/\*\*\s*\*\s*@file[\s\S]*?@kit[\s\S]*?\*\//;
+ let comment: RegExpMatchArray | null = fileFullText.match(pattern);
+ if (comment) {
+ fileAndKitComment = comment[0];
+ }
+ return fileAndKitComment;
+}
+
+function removeNonInteropDoc(result: string): string {
+ return result.replace(/\/\*\*[\s\S]*?\*\//g, (substring: string): string => {
+ return /@noninterop/g.test(substring) ? '' : substring;
+ });
+}
+
+function writeFile(url: string, data: string, inputDir: string, outputPath: string): void {
+ const newFilePath: string = path.resolve(outputPath, path.relative(inputDir, url));
+ fs.mkdirSync(path.dirname(newFilePath), { recursive: true });
+ fs.writeFileSync(newFilePath, data);
+}
+
+function removeComments(content: string): string {
+ return content
+ .replace(/\/\*[\s\S]*?\*\//g, '')
+ .replace(/\/\/.*$/gm, '')
+ .replace(/^\s*[\r\n]/gm, '');
+}
+
+function isNonInterop(node: ts.Node): boolean {
+ const notesContent: string = node.getFullText().replace(node.getText(), '').replace(/[\s]/g, '');
+ const notesArr: string[] = notesContent.split(/\/\*\*/);
+ for (const note of notesArr) {
+ if (note.length !== 0 && /@noninterop/g.test(note)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+export {
+ getCoreFilename,
+ getFileAndKitComment,
+ getPureName,
+ isExistImportFile,
+ isNonInterop,
+ processFileName,
+ processFileNameWithoutExt,
+ readFile,
+ removeNonInteropDoc,
+ removeComments,
+ writeFile,
+};
diff --git a/arkui_noninterop_plugin/src/delete_noninterop/white_management.ts b/arkui_noninterop_plugin/src/delete_noninterop/white_management.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e46a551a8818fd24d78682fdec42d69ac9140a2a
--- /dev/null
+++ b/arkui_noninterop_plugin/src/delete_noninterop/white_management.ts
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export const whiteFileList: string[] = [
+ 'web',
+];
+
+export const specialFileList: string[] = [
+ 'alert_dialog',
+ 'common',
+];
diff --git a/arkui_noninterop_plugin/test/config.ts b/arkui_noninterop_plugin/test/config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e022ce148921bb1e3340aef4f41a6a3670db869d
--- /dev/null
+++ b/arkui_noninterop_plugin/test/config.ts
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from 'path';
+
+const GLOBAL_ESVALUE_FILE: string = '@ohos.arkui.GlobalESValue.d.ts';
+const API: string = 'api';
+const COMPONENT: string = 'component';
+const SOURCE: string = 'source';
+const BUILD: string = 'build_delete_noninterop';
+const UT: string = 'ut';
+const UTF_8: BufferEncoding = 'utf8';
+
+const PROJECT_ROOT: string = path.resolve(__dirname, '../../test');
+const ADD_IMPORT_SOURCE_PATH: string = path.resolve(PROJECT_ROOT, 'ut', API);
+const ADD_IMPORT_OUTPUTS_PATH: string = path.resolve(PROJECT_ROOT, 'build_add_import', API);
+const ADD_IMPORT_TARGET_PATH: string = path.resolve(PROJECT_ROOT, 'target', API);
+
+const SAMPLE: string = 'sample';
+const SAMPLE_BUILD: string = 'build_sample';
+const SAMPLE_RESULT: string = 'build_sample_result';
+
+const SAMPLE_API: string[] = [
+ './api/@ohos.arkui.xxx.d.ts',
+ './component/yyy.d.ts',
+];
+
+export {
+ ADD_IMPORT_OUTPUTS_PATH,
+ ADD_IMPORT_SOURCE_PATH,
+ ADD_IMPORT_TARGET_PATH,
+ API,
+ BUILD,
+ COMPONENT,
+ GLOBAL_ESVALUE_FILE,
+ PROJECT_ROOT,
+ SAMPLE,
+ SAMPLE_API,
+ SAMPLE_BUILD,
+ SAMPLE_RESULT,
+ SOURCE,
+ UT,
+ UTF_8,
+}
diff --git a/arkui_noninterop_plugin/test/sample/api/@ohos.arkui.xxx.d.ts b/arkui_noninterop_plugin/test/sample/api/@ohos.arkui.xxx.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5b9fea2d0afe1f794a208cd5b6e0bc9bbaab7efc
--- /dev/null
+++ b/arkui_noninterop_plugin/test/sample/api/@ohos.arkui.xxx.d.ts
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file
+ * @kit ArkUI
+ */
+
+/**
+ * xxx1.
+ *
+ * @interface Xxx1
+ * @syscap SystemCapability.ArkUI.ArkUI.Full
+ * @form
+ * @atomicservice
+ * @since 11
+ * @noninterop
+ */
+export interface Xxx1 {
+}
+
+/**
+ * xxx2.
+ *
+ * @interface Xxx2
+ * @syscap SystemCapability.ArkUI.ArkUI.Full
+ * @form
+ * @atomicservice
+ * @since 11
+ */
+export interface Xxx2 {
+}
diff --git a/arkui_noninterop_plugin/test/sample/component/yyy.d.ts b/arkui_noninterop_plugin/test/sample/component/yyy.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4fffb7f8cb6838943d1dabc3a20008548e518255
--- /dev/null
+++ b/arkui_noninterop_plugin/test/sample/component/yyy.d.ts
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file
+ * @kit ArkUI
+ */
+
+/**
+ * yyy1.
+ *
+ * @interface Yyy1
+ * @syscap SystemCapability.ArkUI.ArkUI.Full
+ * @form
+ * @atomicservice
+ * @since 11
+ */
+interface Yyy1 {
+}
+
+/**
+ * xxx2.
+ *
+ * @interface Xxx2
+ * @syscap SystemCapability.ArkUI.ArkUI.Full
+ * @form
+ * @atomicservice
+ * @since 11
+ * @noninterop
+ */
+interface Yyy2 {
+}
diff --git a/arkui_noninterop_plugin/test/test.ts b/arkui_noninterop_plugin/test/test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5b45cb7a65edffeff3798eda5b733742fafdb7a2
--- /dev/null
+++ b/arkui_noninterop_plugin/test/test.ts
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from 'path';
+import * as fs from 'fs';
+import * as mocha from 'mocha';
+import { expect } from 'chai';
+
+import * as ts from 'typescript';
+
+import {
+ ADD_IMPORT_OUTPUTS_PATH,
+ ADD_IMPORT_SOURCE_PATH,
+ ADD_IMPORT_TARGET_PATH,
+ API,
+ BUILD,
+ COMPONENT,
+ GLOBAL_ESVALUE_FILE,
+ PROJECT_ROOT,
+ SOURCE,
+ UT,
+ UTF_8,
+} from './config';
+import { getFiles, parseCode } from './utils';
+
+import { transformFiles } from '../src/delete_noninterop/transform_plugin';
+import processInteropUI from '../src/add_import/process_interop_ui';
+
+mocha.describe('add import for 1.1 interop sdk', () => {
+ const deleteNoninteropOutputPath: string = path.resolve(PROJECT_ROOT, BUILD);
+ const sourceFilePath: string = path.resolve(PROJECT_ROOT, SOURCE);
+
+ transformFiles(path.resolve(sourceFilePath, API),
+ path.resolve(deleteNoninteropOutputPath, API), false);
+ transformFiles(path.resolve(sourceFilePath, COMPONENT),
+ path.resolve(deleteNoninteropOutputPath, COMPONENT), true);
+
+ const utFiles: string[] = [];
+ getFiles(sourceFilePath, utFiles);
+ utFiles.push(path.resolve(sourceFilePath, API, GLOBAL_ESVALUE_FILE));
+
+ utFiles.forEach((filePath: string, index: number) => {
+ const buildFilePath: string = path.resolve(filePath.replace(`/${SOURCE}/`, `/${BUILD}/`));
+ const targetFilePath: string = path.resolve(filePath.replace(`/${SOURCE}/`, `/${UT}/`));
+
+ if (fs.existsSync(buildFilePath) && fs.existsSync(targetFilePath)) {
+ mocha.it(`${index + 1}: test delete noninterop ${path.basename(filePath)}`, function (done) {
+ const buildCode: string = fs.readFileSync(buildFilePath, UTF_8);
+ const targetCode: string = fs.readFileSync(targetFilePath, UTF_8);
+ expect(parseCode(buildCode)).eql(parseCode(targetCode));
+ done();
+ });
+ }
+ });
+
+ const intputDir: string = ADD_IMPORT_SOURCE_PATH;
+ const outputDir: string = ADD_IMPORT_OUTPUTS_PATH;
+ const targetDir: string = ADD_IMPORT_TARGET_PATH;
+ const res: ts.TransformationResult = processInteropUI(intputDir, false, outputDir);
+
+ res.transformed.map((sourcefile:ts.SourceFile, index: number) => {
+ const buildFilePath: string = path.resolve(sourcefile.fileName.replace(intputDir, outputDir));
+ const targetFilePath: string = path.resolve(sourcefile.fileName.replace(intputDir, targetDir));
+
+ if (fs.existsSync(targetFilePath) && !targetFilePath.includes(`/${COMPONENT}/`)) {
+ mocha.it(`${index + 1}: test add import ${sourcefile.fileName.replace(intputDir, '')}`,
+ function (done) {
+ const buildCode: string = fs.readFileSync(buildFilePath, UTF_8);
+ const targetCode: string = fs.readFileSync(targetFilePath, UTF_8);
+ expect(parseCode(buildCode)).eql(parseCode(targetCode));
+ done();
+ });
+ }
+ });
+});
diff --git a/arkui_noninterop_plugin/test/testSample.ts b/arkui_noninterop_plugin/test/testSample.ts
new file mode 100644
index 0000000000000000000000000000000000000000..01eef77dd155942491b4bef84340c276889d274e
--- /dev/null
+++ b/arkui_noninterop_plugin/test/testSample.ts
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from 'path';
+
+import {
+ API,
+ COMPONENT,
+ PROJECT_ROOT,
+ SAMPLE,
+ SAMPLE_BUILD,
+ SAMPLE_RESULT,
+} from './config';
+
+const { transformFiles } = require(path.resolve(PROJECT_ROOT, '../../process_label_noninterop'));
+const { processInteropUI } = require(path.resolve(PROJECT_ROOT, '../../process_global_import'));
+
+const sourceFilePath: string = path.resolve(PROJECT_ROOT, SAMPLE);
+const deleteNoninteropOutputPath: string = path.resolve(PROJECT_ROOT, SAMPLE_BUILD);
+transformFiles(path.resolve(sourceFilePath, API),
+ path.resolve(deleteNoninteropOutputPath, API), false);
+transformFiles(path.resolve(sourceFilePath, COMPONENT),
+ path.resolve(deleteNoninteropOutputPath, COMPONENT), true);
+
+const addExportIntputDir: string = deleteNoninteropOutputPath;
+const outPath: string = path.resolve(PROJECT_ROOT, SAMPLE_RESULT);
+processInteropUI(addExportIntputDir, false, outPath);
diff --git a/arkui_noninterop_plugin/test/tsconfig.json b/arkui_noninterop_plugin/test/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..37d80913c73b1cc49410eba13346c4a2a348375c
--- /dev/null
+++ b/arkui_noninterop_plugin/test/tsconfig.json
@@ -0,0 +1,29 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "rootDir": "..",
+ "outDir": "../dist-test",
+ "types": [
+ "node",
+ "mocha",
+ "chai"
+ ]
+ },
+ "include": [
+ "./**/*.ts",
+ "../src/**/*.ts"
+ ],
+ "exclude": [
+ "../node_modules",
+ "../dist",
+ "../dist-test",
+ "./build_delete_noninterop",
+ "./build_add_import",
+ "./build_sample",
+ "./build_sample_result",
+ "./source",
+ "./ut",
+ "./target",
+ "./sample"
+ ]
+}
diff --git a/arkui_noninterop_plugin/test/utils.ts b/arkui_noninterop_plugin/test/utils.ts
new file mode 100644
index 0000000000000000000000000000000000000000..18ff76b49928b623fe7a7495c6a9f291ce16842b
--- /dev/null
+++ b/arkui_noninterop_plugin/test/utils.ts
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as path from 'path';
+import * as fs from 'fs';
+
+function parseCode(code: string): string {
+ return normalizeFileContent(cleanCopyRight(code));
+}
+
+function normalizeFileContent(content: string): string {
+ // Replace all types of line endings with a single newline character
+ const normalizedLineEndings = content.replace(/\r\n|\r/g, '\n');
+
+ // Remove leading and trailing whitespace from each line
+ const normalizedWhitespace = normalizedLineEndings.split('\n').map(line => line.trim()).join('\n');
+
+ // Remove empty lines
+ const normalizedEmptyLines = normalizedWhitespace.split('\n').filter(line => line !== '').join('\n');
+
+ return normalizedEmptyLines;
+}
+
+function cleanCopyRight(str: string): string {
+ const copyrightBlockRegex = /(?:\/\*.*Copyright \([c|C]\) [- \d]+ [\w ]+\., Ltd\..*\*\/)/gs;
+
+ return str.replace(copyrightBlockRegex, '');
+}
+
+function getFiles(dir: string, allFiles: string[] = []): void {
+ const files: string[] = fs.readdirSync(dir);
+ files.forEach((element) => {
+ const filePath = path.join(dir, element);
+ const status = fs.statSync(filePath);
+ if (status.isDirectory()) {
+ getFiles(filePath, allFiles);
+ } else {
+ allFiles.push(filePath);
+ }
+ });
+}
+
+export {
+ getFiles,
+ parseCode,
+}
diff --git a/arkui_noninterop_plugin/tsconfig.json b/arkui_noninterop_plugin/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..f5e196e0bd9d0b4708d8a0405b20766c5b836b86
--- /dev/null
+++ b/arkui_noninterop_plugin/tsconfig.json
@@ -0,0 +1,32 @@
+{
+ "extends": "@tsconfig/recommended/tsconfig.json",
+ "compilerOptions": {
+ "target": "es2021",
+ "module": "commonjs",
+ "moduleResolution": "node",
+ "composite": true,
+ "incremental": true,
+ "declarationMap": true,
+ "sourceMap": true,
+ "declaration": true,
+ "noEmitOnError": true,
+ "strict": true,
+ "skipLibCheck": false,
+ "removeComments": false,
+ "forceConsistentCasingInFileNames": true,
+ "outDir": "./dist",
+ "baseUrl": ".",
+ "rootDir": "./src",
+ "types": [
+ "node",
+ ],
+ "lib": [
+ "es2021",
+ ]
+ },
+ "include": [
+ "./src/add_import/*.ts",
+ "./src/collect_symbol/*.ts",
+ "./src/delete_noninterop/*.ts",
+ ]
+}