* 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 path = require('path');
const fs = require('fs');
const commander = require('commander');
const ts = require('typescript');
function transformFiles(inputDir, outputPath, exportFlag) {
try {
if (exportFlag) {
initGlobalESValueFile(outputPath);
}
const utFiles = [];
readFile(inputDir, utFiles);
tsTransform(utFiles, deleteNonInteropApi, exportFlag, inputDir, outputPath);
} catch (error) {
}
}
function tsTransform(utFiles, callback, exportFlag, inputDir,
outputPath) {
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 deleteNonInteropApi(url, exportFlag, inputDir,
outputPath) {
return (context) => {
return (node) => {
const fullText = String(node.getFullText());
let fileAndKitComment = getFileAndKitComment(fullText);
const copyrightMessage = fullText.replace(node.getText(), '').split(/\/\*\*/)[0] +
fileAndKitComment + '\n';
let kitName = '';
if (fullText.match(/\@kit (.*)\r?\n/g)) {
kitName = RegExp.$1.replace(/\s/g, '');
}
const fileName = processFileName(url);
sourceFile = node;
const deleteNode = processSourceFile(node, url);
node = processVisitEachChild(context, deleteNode.node, exportFlag);
if (needProcessLabelNonInterop(fileName, kitName, inputDir)) {
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
const result = printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
ts.transpileModule(result, {
compilerOptions: {
target: ts.ScriptTarget.ES2017,
},
fileName: fileName,
transformers: {
before: [formatImportDeclaration(url, exportFlag, inputDir, outputPath,
copyrightMessage, deleteNode.isCopyrightDeleted)]
},
});
}
return ts.factory.createSourceFile([], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken),
ts.NodeFlags.None);
};
};
}
function processVisitEachChild(context, node,
exportFlag) {
return ts.visitEachChild(node, processAllNodes, context);
function processAllNodes(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.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 getNewStatements(node) {
const newStatements = [];
(node.body).statements.forEach((statement) => {
if (!isNonInterop(statement)) {
newStatements.push(statement);
}
});
return newStatements;
}
function formatImportDeclaration(url, exportFlag, inputDir,
outputPath, copyrightMessage = '', isCopyrightDeleted = false) {
return (context) => {
return (node) => {
sourceFile = node;
const allIdentifierSet = collectAllIdentifier(node, context);
const formatValue = 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 formatAllNodes(url, inputDir, node,
allIdentifierSet, copyrightMessage = '', isCopyrightDeleted = false) {
let referencesMessage = '';
let currReferencesModule = [];
if (!ts.isSourceFile(node) || !node.statements) {
return { node, referencesMessage, copyrightMessage, isCopyrightDeleted };
}
const newStatements = [];
node.statements.forEach((statement) => {
if (ts.isImportDeclaration(statement)) {
const importInfo = 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, statement,
url, inputDir, currReferencesModule,
allIdentifierSet) {
const clauseSet = getClauseSet(statement);
const importSpecifier = statement.moduleSpecifier.getText().replace(/[\'\"]/g, '');
const fileDir = path.dirname(url);
const hasImportSpecifierFile = hasFileByImportPath(importSpecifier, fileDir, inputDir);
let hasImportSpecifierInModules = 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 = getExsitClauseSet(hasImportSpecifierInModules, importSpecifier,
currReferencesModule, clauseSet, allIdentifierSet);
const hasExsitStatus = clauseSetValue.hasExsitStatus;
const hasNonExsitStatus = clauseSetValue.hasNonExsitStatus;
let exsitClauseSet = 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, newStatements) {
const fileName = getCoreFilename(path.basename(node.fileName));
if (fileName === FRAMENODE) {
newStatements.push(createFrameNodeTypeNode());
}
}
function initGlobalESValueFile(outputPath) {
const filePath = `${path.resolve(outputPath, '../api')}/${GLOBAL_ESVALUE_FILE}`;
const dir = path.dirname(filePath);
fs.mkdirSync(dir, { recursive: true });
fs.writeFileSync(filePath, '');
}
function writeGlobalESValueFile(content, outputPath) {
content = content.replace("'use static';", '').replace(/\.\.\/api/g, '.');
fs.appendFileSync(`${path.resolve(outputPath, '../api')}/${GLOBAL_ESVALUE_FILE}`, content);
}
function readFile(dir, utFiles) {
try {
const files = fs.readdirSync(dir);
files.forEach((element) => {
const filePath = path.join(dir, element);
const status = fs.statSync(filePath);
if (status.isDirectory()) {
readFile(filePath, utFiles);
} else {
utFiles.push(filePath);
}
});
} catch (e) {
}
}
function processSourceFile(node, url) {
let isCopyrightDeleted = false;
const newStatements = [];
const newStatementsWithoutExport = [];
const deleteNonInteropApiSet = new Set();
let needDeleteExport = {
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 addNewStatements(node, newStatements,
deleteNonInteropApiSet, needDeleteExport) {
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).escapedText) {
deleteNonInteropApiSet.add((statement.name).escapedText.toString());
}
setDeleteExport(statement, node, needDeleteExport, deleteNonInteropApiSet);
} else if (ts.isExportAssignment(statement) || ts.isExportDeclaration(statement)) {
setDeleteExport(statement, node, needDeleteExport, deleteNonInteropApiSet);
}
});
return isCopyrightDeleted;
}
function processExportNode(statement, node,
needDeleteExport, names, deleteNonInteropApiSet,
newStatementsWithoutExport) {
if (ts.isExportAssignment(statement)) {
needDeleteExport.fileName = processFileNameWithoutExt(node.fileName);
needDeleteExport.default = (statement.expression).escapedText.toString();
} else if (ts.isExportDeclaration(statement)) {
let needExport = false;
const newSpecifiers = [];
names.forEach((name, index) => {
const exportSpecifier =
(statement.exportClause).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) = ts.factory.updateNamedExports(
statement.exportClause, newSpecifiers);
newStatementsWithoutExport.push(statement);
}
}
}
function getPureName(name) {
const pureName = path.basename(name)
.replace(EXTNAME_D_TS, '')
.replace(EXTNAME_D_ETS, '')
.replace(/_/g, '')
.toLowerCase();
return pureName;
}
function processFileName(filePath) {
return path
.basename(filePath)
.replace(/\.d\.ts$/g, EXTNAME_TS)
.replace(/\.d\.ets$/g, EXTNAME_ETS);
}
function processFileNameWithoutExt(filePath) {
return path
.basename(filePath)
.replace(/\.d\.ts$/g, '')
.replace(/\.d\.ets$/g, '')
.replace(/\.ts$/g, '')
.replace(/\.ets$/g, '');
}
function hasFileByImportPath(importPath, apiDir, inputDir) {
let fileDir = 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, importPath, inputDir) {
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 isExistImportFile(fileDir, importPath) {
return [EXTNAME_D_TS, EXTNAME_D_ETS].some(ext => {
return fs.existsSync(path.resolve(fileDir, `${importPath}${ext}`));
});
}
function preprocessContent(fileName, content) {
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 = 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;
}
function processSpecialFileContext(fileName, context) {
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) {
return specialFileList.includes(path.basename(url, EXTNAME_TS));
}
function writeFile(url, data, inputDir, outputPath) {
const newFilePath = path.resolve(outputPath, path.relative(inputDir, url));
fs.mkdirSync(path.dirname(newFilePath), { recursive: true });
fs.writeFileSync(newFilePath, data);
}
function postProcessContent(content) {
for (const [originalStmt, transformedStmt] of stmtReplacementMap) {
content = content.replace(transformedStmt, originalStmt);
}
return content.replace(/^(\s*)\/\*\*\@reserved (.*) \*\/$/mg, '$1$2');
}
function outputFile(url, exportFlag, inputDir, outputPath,
node, sourceFile, referencesMessage,
copyrightMessage, isCopyrightDeleted) {
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
let result = 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);
if (exportFlag) {
writeGlobalESValueFile(removeComments(result), outputPath);
}
}
function removeComments(content) {
let result = content.replace(/\/\*[\s\S]*?\*\//g, '');
result = result.replace(/\/\/.*$/gm, '');
result = result.replace(/^\s*[\r\n]/gm, '');
return result;
}
function collectAllIdentifier(node, context) {
const identifierSet = 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) {
if (ts.isIdentifier(node)) {
identifierSet.add(node.escapedText.toString());
}
return ts.visitEachChild(node, collectAllNodes, context);
}
return identifierSet;
}
function getCoreFilename(fileName) {
if (fileName.endsWith(EXTNAME_TS)) {
return fileName.slice(0, -EXTNAME_TS.length);
}
return fileName;
}
function createFrameNodeTypeNode() {
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) {
return /http\:\/\/www\.apache\.org\/licenses\/LICENSE\-2\.0/g.test(node.getFullText()
.replace(node.getText(), ''));
}
function getClauseSet(statement) {
const clauseSet = new Set([]);
if (!statement.importClause || !ts.isImportClause(statement.importClause)) {
return clauseSet;
}
const clauseNode = 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, importSpecifier,
currReferencesModule, clauseSet, allIdentifierSet) {
let currModule = [];
if (hasImportSpecifierInModules) {
let index = globalModules.get(importSpecifier);
const referenceModule = currReferencesModule[index];
currModule = referenceModule.modules[importSpecifier];
}
const clasueCheckList = [];
let exsitClauseSet = new Set([]);
for (const clause of clauseSet) {
let flag = allIdentifierSet.has(clause);
if (hasImportSpecifierInModules) {
flag = allIdentifierSet.has(clause) && currModule.includes(clause);
}
if (flag) {
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, statement,
exsitClauseSet, hasImportSpecifierInModules,
currReferencesModule, importSpecifier) {
if (hasNonExsitStatus) {
const newSpecifiers = [];
(statement.importClause.namedBindings).elements.forEach((element) => {
if (exsitClauseSet.has(element.name.escapedText.toString())) {
newSpecifiers.push(element);
}
});
(statement.importClause).namedBindings = ts.factory.updateNamedImports(
statement.importClause.namedBindings,
newSpecifiers
);
}
if (hasImportSpecifierInModules) {
let index = globalModules.get(importSpecifier);
currReferencesModule[index].isUsed = true;
}
return { statement };
}
function getFileAndKitComment(fileFullText) {
let fileAndKitComment = '';
let pattern = /\/\*\*\s*\*\s*@file[\s\S]*?@kit[\s\S]*?\*\//;
let comment = fileFullText.match(pattern);
if (comment) {
fileAndKitComment = comment[0];
}
return fileAndKitComment;
}
function removeNonInteropDoc(result) {
return result.replace(/\/\*\*[\s\S]*?\*\//g, (substring, p1) => {
return /@noninterop/g.test(substring) ? '' : substring;
});
}
function needProcessLabelNonInterop(fileName, kitName, inputDir) {
if (inputDir.endsWith(COMPONENT) || fileName.startsWith(OHOS_ARKUI) ||
kitName.toLowerCase() === ARKUI || whiteFileList.includes(fileName.slice(0, -EXTNAME_TS.length))) {
return true;
}
return false;
}
function setDeleteExport(statement, node, needDeleteExport,
deleteNonInteropApiSet) {
if (ts.isExportAssignment(statement) &&
deleteNonInteropApiSet.has((statement.expression).escapedText.toString())) {
needDeleteExport.fileName = processFileNameWithoutExt(node.fileName);
needDeleteExport.default = (statement.expression).escapedText.toString();
} else if (ts.isExportDeclaration(statement)) {
needDeleteExport.fileName = processFileNameWithoutExt(node.fileName);
(statement.exportClause).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());
}
});
}
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).name.escapedText.toString();
} else if (exportFlag) {
needDeleteExport.fileName = processFileNameWithoutExt(node.fileName);
needDeleteExport.exportName.add((statement).name.escapedText.toString());
}
}
function getExportIdentifierName(statement) {
const names = [];
if (ts.isExpressionStatement(statement)) {
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)) {
names.push((statement.expression).escapedText.toString());
} else if (ts.isExportDeclaration(statement) && statement.exportClause) {
const specifiers = (statement.exportClause).elements;
specifiers.forEach((specifier) => {
if (ts.isExportSpecifier(specifier)) {
const name = specifier.propertyName ? specifier.propertyName : specifier.name;
names.push(name.escapedText.toString());
}
});
}
return names;
}
function addExport2Modifiers(
modifiers) {
modifiers = modifiers || [];
const isAlreadyExported = modifiers.some(m => m.kind === ts.SyntaxKind.ExportKeyword);
if (!isAlreadyExported) {
modifiers = [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword),
...modifiers];
}
return modifiers;
}
function processTypeAliasDeclaration(node,
exportFlag) {
if (exportFlag) {
return ts.factory.updateTypeAliasDeclaration(
node,
addExport2Modifiers(node.modifiers),
node.name,
node.typeParameters,
node.type
);
} else {
return node;
}
}
function processInterfaceDeclaration(node,
exportFlag) {
const newMembers = [];
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, exportFlag) {
const newMembers = [];
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, exportFlag) {
const newMembers = [];
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) {
const newMembers = [];
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 variableStatementGetEscapedText(statement) {
let name = '';
if (
statement &&
statement.declarationList &&
statement.declarationList.declarations &&
statement.declarationList.declarations.length > 0 &&
statement.declarationList.declarations[0].name &&
(statement.declarationList.declarations[0].name).escapedText
) {
name = (statement.declarationList.declarations[0].name).escapedText.toString();
}
return name;
}
function isNonInterop(node) {
const notesContent = node.getFullText().replace(node.getText(), '').replace(/[\s]/g, '');
const notesArr = notesContent.split(/\/\*\*/);
for (const note of notesArr) {
if (note.length !== 0 && /@noninterop/g.test(note)) {
return true;
}
}
return false;
}
exports.transformFiles = transformFiles;
let outputPath = '';
let inputDir = '';
let exportFlag = false;
let sourceFile = null;
let componentEtsFiles = [];
let componentEtsDeleteFiles = [];
const kitFileNeedDeleteMap = new Map();
const stmtReplacementMap = new Map();
const globalModules = new Map();
const GLOBAL_ESVALUE_FILE = '@ohos.arkui.GlobalESValue.d.ts';
const ARKUI = 'arkui';
const ARKTS = 'arkts';
const COMPONENT = 'component';
const ANY = 'Any';
const EXTNAME_D_TS = '.d.ts';
const EXTNAME_D_ETS = '.d.ets';
const EXTNAME_TS = '.ts';
const EXTNAME_ETS = '.ets';
const ETS = 'ets';
const INTERNAL = '@internal';
const EXIST = 'exist';
const NON_EXIST = 'non-exist';
const OHOS_ARKUI = '@ohos.arkui';
const FRAMENODE = 'FrameNode';
const TRUE = 'true';
const TYPENODE = 'typeNode';
const XCOMPONENT = 'XComponent';
const ALERT_DIALOG = 'alert_dialog';
const ALERT_DIALOG_TEXT_STYLE = 'AlertDialogTextStyle';
const COMMON = 'common';
const COMMON_LINEAR_GRADIENT = 'CommonLinearGradient';
const whiteFileList = [
'web',
];
const specialFileList = [
'alert_dialog',
'common',
];
function start() {
const program = new commander.Command();
program
.name('noninterop')
.version('0.0.1');
program
.option('--input <string>', 'input path')
.option('--output <string>', 'output path')
.option('--export <string>', 'export flag', false)
.action((opts) => {
outputPath = opts.output;
inputDir = opts.input;
exportFlag = opts.export === TRUE;
transformFiles(inputDir, outputPath, exportFlag);
});
program.parse(process.argv);
}
start();