From 85d57cbb704f59febe8bb9139c30be404cf89f2e Mon Sep 17 00:00:00 2001 From: hufeng Date: Tue, 19 Dec 2023 14:36:48 +0000 Subject: [PATCH 1/6] Support compiling with Kit module Signed-off-by: hufeng Change-Id: I899700fdcad3fb4c89b98346b6d501669eab9cb2 --- .gitignore | 2 + compiler/src/ets_checker.ts | 6 + compiler/src/process_kit_import.ts | 348 +++++++++++++++++++++++++++++ 3 files changed, 356 insertions(+) create mode 100644 compiler/src/process_kit_import.ts diff --git a/.gitignore b/.gitignore index ace4a03ce..2fe023f40 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,12 @@ .vscode/ +compiler/arkTest_build/ compiler/node_modules/ compiler/lib/ compiler/declarations/ compiler/sample/build/ compiler/component_config.json compiler/form_config.json +compiler/kit_configs/ compiler/syntax_parser/dist/ compiler/.nyc_output compiler/.test_output diff --git a/compiler/src/ets_checker.ts b/compiler/src/ets_checker.ts index 889599ddb..f52aafe89 100644 --- a/compiler/src/ets_checker.ts +++ b/compiler/src/ets_checker.ts @@ -657,6 +657,8 @@ export function resolveModuleNames(moduleNames: string[], containingFile: string } else { const modulePath: string = path.resolve(__dirname, '../../../api', moduleName + '.d.ts'); const systemDETSModulePath: string = path.resolve(__dirname, '../../../api', moduleName + '.d.ets'); + const kitModulePath: string = path.resolve(__dirname, '../../../kits', moduleName + '.d.ts'); + const kitSystemDETSModulePath: string = path.resolve(__dirname, '../../../kits', moduleName + '.d.ets'); const suffix: string = /\.js$/.test(moduleName) ? '' : '.js'; const jsModulePath: string = path.resolve(__dirname, '../node_modules', moduleName + suffix); const fileModulePath: string = @@ -667,6 +669,10 @@ export function resolveModuleNames(moduleNames: string[], containingFile: string resolvedModules.push(getResolveModule(modulePath, '.d.ts')); } else if (ts.sys.fileExists(systemDETSModulePath)) { resolvedModules.push(getResolveModule(systemDETSModulePath, '.d.ets')); + } else if (ts.sys.fileExists(kitModulePath)) { + resolvedModules.push(getResolveModule(kitModulePath, '.d.ts')); + } else if (ts.sys.fileExists(kitSystemDETSModulePath)) { + resolvedModules.push(getResolveModule(kitSystemDETSModulePath, '.d.ets')); } else if (ts.sys.fileExists(jsModulePath)) { resolvedModules.push(getResolveModule(jsModulePath, '.js')); } else if (ts.sys.fileExists(fileModulePath)) { diff --git a/compiler/src/process_kit_import.ts b/compiler/src/process_kit_import.ts new file mode 100644 index 000000000..81537e52b --- /dev/null +++ b/compiler/src/process_kit_import.ts @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2023 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 fs from 'fs'; +import path from 'path'; + + +/* +* basic implementation logic: +* tsc -> transformer +* | -> iterate top-level static import/export declaration +* | -> for each declaration +* | -> collect KitImportInfo +* | -> generate corresponding ohosImports for each ohos-source +* | -> replace each origin declaration with corresponding ohosImports +*/ + +const KIT_CONFIGS = 'kit_configs'; +const KIT_PREFIX = '@kit.'; +const JSON_SUFFIX = '.json'; +/* +* This API is the TSC Transformer for transforming `KitImport` into `OhosImport` +* e.g. +* ``` +* import { ability, ErrorCode } from '@kit.AbilityKit' +* ---> +* import ability from '@ohos.ability.ability' +* import ErrorCode from '@ohos.ability.errorCode' +* ``` +*/ +export function processKitImport(program: ts.Program): Function { + return (context: ts.TransformationContext) => { + const visitor: ts.Visitor = node => { + // static import/export declaration + if (ts.isImportDeclaration(node) || (ts.isExportDeclaration(node) && node.moduleSpecifier)) { + // moduleSpecifier.getText() returns string carrying on quotation marks which the importMap's key does not, + // so we need to remove the quotation marks from moduleRequest. + const moduleRequest: string = node.moduleSpecifier.getText().replace(/'|"/g, ''); + if (moduleRequest.startsWith(KIT_PREFIX)) { + const kitDefs = JSON.parse(fs.readFileSync(`../${KIT_CONFIGS}/${moduleRequest}${JSON_SUFFIX}`, 'utf-8')); + if (kitDefs.symbols) { + KitImportInfo.processKitImportInfo(kitDefs.symbols as KitSymbols, node); + } + return [...KitImportInfo.getCurrentKitImportInfo().getOhosImportNodes()]; + } + } + return node; + } + + return (node: ts.SourceFile) => { + if (/\.ts$/.test(node.fileName)) { + KitImportInfo.setFileType(FileType.TS); + } else { + KitImportInfo.setFileType(FileType.ETS); + } + ts.visitEachChild(node, visitor, context); + }; + } +} + + +/* +* Implementation part of Transforming +*/ + +const DEFAULT_BINDINGS = 'default'; + +enum FileType { + ETS, + TS +} + +interface Symbol { + source: string + bindings: string +} + +declare type KitSymbols = Record; +declare type TSspecifier = ts.ImportSpecifier | ts.ExportSpecifier; +declare type TSModuleDeclaration = ts.ImportDeclaration | ts.ExportDeclaration; + +class SpecificerInfo { + private localName: string; + private symbol: Symbol; + private renamed: boolean; + + private originElement: TSspecifier; + + constructor(localName: string, symbol: Symbol, originElement: TSspecifier) { + this.localName = localName; + this.symbol = symbol; + this.originElement = originElement; + this.renamed = (this.localName === this.symbol.bindings); + + this.validateImportingETSDeclarationSymbol(); + } + + getSource(): string { + return this.symbol.source; + } + + getLocalName(): string { + return this.localName; + } + + isRenamed(): boolean { + return this.renamed; + } + + getBindings(): string { + return this.symbol.bindings; + } + + isDefaultBinding(): boolean { + return this.symbol.bindings === DEFAULT_BINDINGS; + } + + validateImportingETSDeclarationSymbol() { + if (KitImportInfo.isTSFile() && /.d.ets$/.test(this.symbol.source)) { + // ts file can not import symbol from .d.ets file + // logger.error() + } + } + + setOriginElementNode(originElement: TSspecifier) { + this.originElement = originElement; + } + + getOriginElementNode(): TSspecifier { + return this.originElement; + } +} + +class KitImportInfo { + private static currentKitImportInfo: KitImportInfo; + private static currentFileType: FileType = FileType.ETS; + + private symbols: KitSymbols; + private kitNode: TSModuleDeclaration; + private specifiers: Map = new Map(); + + private ohosImportNodes: ts.ImportDeclaration[] = []; + + constructor(kitNode: TSModuleDeclaration, symbols: Record) { + this.kitNode = kitNode; + this.symbols = symbols; + } + + static getCurrentKitImportInfo(): KitImportInfo { + return this.currentKitImportInfo; + } + + static setFileType(fileType: FileType): void { + this.currentFileType = fileType; + } + + static isTSFile(): boolean { + return this.currentFileType === FileType.TS; + } + + static processImportDecl(kitNode: ts.ImportDeclaration, symbols: Record) { + // this.kitNode = this.kitNode as ts.ImportDeclaration; + if (kitNode.importClause!.name) { + // import default from "@kit.xxx" + // todo: throw error msg + } + if (kitNode.importClause!.namedBindings) { + const namedBindings: ts.NamedImportBindings = kitNode.importClause.namedBindings; + if (ts.isNamespaceImport(namedBindings)) { + // import * as ns from "@kit.xxx" + // todo: logger.warn to reminder developer the side-effect of using namespace import with Kit + this.currentKitImportInfo = new NameSpaceKitImportInfo(kitNode, symbols); + } + if (ts.isNamedImports(namedBindings) && namedBindings.elements.length !== 0) { + // import { ... } from "@kit.xxx" + this.currentKitImportInfo = new ImportSpecifierKitImportInfo(kitNode, symbols); + namedBindings.elements.forEach(element => { this.currentKitImportInfo.collectSpecifier(element) }); + } + } + } + + static processExportDecl(kitNode: ts.ExportDeclaration, symbols: Record) { + if (kitNode.exportClause) { + const namedExportBindings: ts.NamedExportBindings = kitNode.exportClause; + if (ts.isNamespaceExport(namedExportBindings)) { + // export * as ns from "@kit.xxx" + // todo + } else if (ts.isNamedExports(namedExportBindings) && namedExportBindings.elements.length !== 0) { + // export { ... } from "@kit.xxx" + this.currentKitImportInfo = new ExportSpecifierKitImportInfo(kitNode, symbols); + namedExportBindings.elements.forEach(element => { this.currentKitImportInfo.collectSpecifier(element) }); + } + } else { + // export * from "@kit.xxx" + // equals expanding all the ohos with export-star + // export * from "@ohos.xxx";export * from "@ohos.yyy"; + // iterate kit + } + } + + static processKitImportInfo(symbols: Record, kitNode: TSModuleDeclaration): void { + // do not handle an empty import + if (ts.isImportDeclaration(kitNode) && kitNode.importClause) { + // import { ... } from '@kit.xxx' + // import * as ns from '@kit.xxx' + // import defalutValue from '@kit.xxx' - forbidden + this.processImportDecl(kitNode, symbols); + } + + if (ts.isExportDeclaration(kitNode) && kitNode.moduleSpecifier) { + // export { ... } from '@kit.xxx' + // export * from '@kit.xxx' + // export * as ns from '@kit.xxx' - considering forbidden + this.processExportDecl(kitNode, symbols); + } + // transform into ohos imports or exports + this.currentKitImportInfo.transform(); + } + + getSymbols(): KitSymbols { + return this.symbols; + } + + getKitNode(): TSModuleDeclaration { + return this.kitNode; + } + + getSpecifiers(): Map { + return this.specifiers; + } + + getOhosImportNodes(): ts.ImportDeclaration[] { + return this.ohosImportNodes; + } + + newSpecificerInfo(localName: string, importName: string, originElement: TSspecifier): SpecificerInfo { + const symbol: Symbol = this.symbols[importName]; + const specifier: SpecificerInfo = new SpecificerInfo(localName, symbol, originElement); + if (this.specifiers.has(symbol.source)) { + this.specifiers.get(symbol.source).push(specifier); + } else { + this.specifiers.set(symbol.source, [specifier]); + } + return specifier; + } + + collectSpecifier(element: TSspecifier) { + const localName: string = element.name.getText(); + const importName: string = element.propertyName ? element.propertyName.getText() : localName; + this.newSpecificerInfo(localName, importName, element); + } + + // @ts-ignore + transform() {} //override api +} + +class NameSpaceKitImportInfo extends KitImportInfo { + namespaceName: string; + localNameTable: string[] = []; + + constructor(kitNode: ts.ImportDeclaration, symbols: Record) { + super(kitNode, symbols); + + this.namespaceName = (kitNode.importClause!.namedBindings as ts.NamespaceImport).name.getText(); + } + + + + transform() { + for (const symbol in this.getSymbols()) { + + } + + // issue: how to insert the `const ns = {}` + } +} + +class ImportSpecifierKitImportInfo extends KitImportInfo { + private namedBindings: ts.ImportSpecifier[] = []; + private defaultName: ts.Identifier | undefined = undefined; + + constructor(kitNode: ts.ImportDeclaration, symbols: Record) { + super(kitNode, symbols); + } + + transform() { + const node: ts.ImportDeclaration = this.getKitNode() as ts.ImportDeclaration; + this.getSpecifiers().forEach((specifiers: SpecificerInfo[], source: string) => { + const modifier: readonly ts.Modifier[] = ts.canHaveDecorators(node) ? ts.getModifiers(node) : undefined; + + specifiers.forEach((specifier: SpecificerInfo) => { + if (specifier.isDefaultBinding()) { + this.defaultName = ts.factory.createIdentifier(specifier.getLocalName()); + } else { + this.namedBindings.push( + ts.factory.createImportSpecifier( + (specifier.getOriginElementNode() as ts.ImportSpecifier).isTypeOnly, + specifier.isRenamed() ? ts.factory.createIdentifier(specifier.getBindings()) : undefined, + ts.factory.createIdentifier(specifier.getLocalName()) + ) + ); + } + }); + + this.getOhosImportNodes().push(ts.factory.createImportDeclaration( + modifier, + ts.factory.createImportClause( + node.importClause!.isTypeOnly, + this.defaultName, + ts.factory.createNamedImports(this.namedBindings) + ), + ts.factory.createStringLiteral(trimSourceSuffix(source)) + )); + }); + } +} + +class ExportSpecifierKitImportInfo extends KitImportInfo { + transform() { + + } +} + +class ExportStarKitImportInfo extends KitImportInfo { + transform() { + + } +} + +/* +* utils part +*/ +function trimSourceSuffix(source: string): string { + return source.replace(/\.d.[e]?ts$/, ''); +} \ No newline at end of file -- Gitee From dc30a5013b8da71581edae3db1d391bb1b55dd04 Mon Sep 17 00:00:00 2001 From: hufeng Date: Tue, 19 Dec 2023 14:48:04 +0000 Subject: [PATCH 2/6] Rename the class `KitImportInfo` into `KitInfo` Signed-off-by: hufeng Change-Id: I5bdca2c0142463559db87d822b526c85a18a89f4 --- .../ets_ui/rollup-plugin-ets-typescript.ts | 16 +++- compiler/src/process_kit_import.ts | 87 ++++++++++++------- 2 files changed, 67 insertions(+), 36 deletions(-) diff --git a/compiler/src/fast_build/ets_ui/rollup-plugin-ets-typescript.ts b/compiler/src/fast_build/ets_ui/rollup-plugin-ets-typescript.ts index 7daee56f0..a6b5aee28 100644 --- a/compiler/src/fast_build/ets_ui/rollup-plugin-ets-typescript.ts +++ b/compiler/src/fast_build/ets_ui/rollup-plugin-ets-typescript.ts @@ -72,6 +72,7 @@ import { GLOBAL_CUSTOM_BUILDER_METHOD, INNER_CUSTOM_BUILDER_METHOD } from '../../component_map'; +import { kitTransformLog, processKitImport } from '../../process_kit_import'; const filter:any = createFilter(/(? transformer * | -> iterate top-level static import/export declaration * | -> for each declaration -* | -> collect KitImportInfo +* | -> collect KitInfo * | -> generate corresponding ohosImports for each ohos-source * | -> replace each origin declaration with corresponding ohosImports */ @@ -31,6 +32,9 @@ import path from 'path'; const KIT_CONFIGS = 'kit_configs'; const KIT_PREFIX = '@kit.'; const JSON_SUFFIX = '.json'; + +export const kitTransformLog: FileLog = new FileLog(); + /* * This API is the TSC Transformer for transforming `KitImport` into `OhosImport` * e.g. @@ -50,32 +54,31 @@ export function processKitImport(program: ts.Program): Function { // so we need to remove the quotation marks from moduleRequest. const moduleRequest: string = node.moduleSpecifier.getText().replace(/'|"/g, ''); if (moduleRequest.startsWith(KIT_PREFIX)) { - const kitDefs = JSON.parse(fs.readFileSync(`../${KIT_CONFIGS}/${moduleRequest}${JSON_SUFFIX}`, 'utf-8')); + const kitDefs = + JSON.parse( + fs.readFileSync(path.join(__dirname, `../${KIT_CONFIGS}/${moduleRequest}${JSON_SUFFIX}`), + 'utf-8' + ) + ); if (kitDefs.symbols) { - KitImportInfo.processKitImportInfo(kitDefs.symbols as KitSymbols, node); + KitInfo.processKitInfo(kitDefs.symbols as KitSymbols, node); + return [...KitInfo.getCurrentKitInfo().getOhosImportNodes()]; } - return [...KitImportInfo.getCurrentKitImportInfo().getOhosImportNodes()]; } } return node; } return (node: ts.SourceFile) => { - if (/\.ts$/.test(node.fileName)) { - KitImportInfo.setFileType(FileType.TS); - } else { - KitImportInfo.setFileType(FileType.ETS); - } + KitInfo.init(node); ts.visitEachChild(node, visitor, context); }; } } - /* -* Implementation part of Transforming +* Main implementation of Transforming */ - const DEFAULT_BINDINGS = 'default'; enum FileType { @@ -92,15 +95,21 @@ declare type KitSymbols = Record; declare type TSspecifier = ts.ImportSpecifier | ts.ExportSpecifier; declare type TSModuleDeclaration = ts.ImportDeclaration | ts.ExportDeclaration; + +/* +* class SpecificerInfo represents the corresponding info of each imported identifier which coming from Kit +*/ class SpecificerInfo { private localName: string; + private importName: string; private symbol: Symbol; private renamed: boolean; private originElement: TSspecifier; - constructor(localName: string, symbol: Symbol, originElement: TSspecifier) { + constructor(localName: string, importName: string, symbol: Symbol, originElement: TSspecifier) { this.localName = localName; + this.importName = importName; this.symbol = symbol; this.originElement = originElement; this.renamed = (this.localName === this.symbol.bindings); @@ -129,9 +138,13 @@ class SpecificerInfo { } validateImportingETSDeclarationSymbol() { - if (KitImportInfo.isTSFile() && /.d.ets$/.test(this.symbol.source)) { - // ts file can not import symbol from .d.ets file - // logger.error() + if (KitInfo.isTSFile() && /.d.ets$/.test(this.symbol.source)) { + kitTransformLog.errors.push({ + type: LogType.ERROR, + message: `Identifier '${this.importName}' comes from '${this.symbol.source}' ` + + `which can not be imported in .ts file.`, + pos: this.getOriginElementNode().getStart() + }); } } @@ -144,8 +157,8 @@ class SpecificerInfo { } } -class KitImportInfo { - private static currentKitImportInfo: KitImportInfo; +class KitInfo { + private static currentKitInfo: KitInfo = undefined; private static currentFileType: FileType = FileType.ETS; private symbols: KitSymbols; @@ -159,8 +172,18 @@ class KitImportInfo { this.symbols = symbols; } - static getCurrentKitImportInfo(): KitImportInfo { - return this.currentKitImportInfo; + static init(node: ts.SourceFile): void { + if (/\.ts$/.test(node.fileName)) { + this.setFileType(FileType.TS); + } else { + this.setFileType(FileType.ETS); + } + + kitTransformLog.sourceFile = node; + } + + static getCurrentKitInfo(): KitInfo { + return this.currentKitInfo; } static setFileType(fileType: FileType): void { @@ -182,12 +205,12 @@ class KitImportInfo { if (ts.isNamespaceImport(namedBindings)) { // import * as ns from "@kit.xxx" // todo: logger.warn to reminder developer the side-effect of using namespace import with Kit - this.currentKitImportInfo = new NameSpaceKitImportInfo(kitNode, symbols); + this.currentKitInfo = new NameSpaceKitInfo(kitNode, symbols); } if (ts.isNamedImports(namedBindings) && namedBindings.elements.length !== 0) { // import { ... } from "@kit.xxx" - this.currentKitImportInfo = new ImportSpecifierKitImportInfo(kitNode, symbols); - namedBindings.elements.forEach(element => { this.currentKitImportInfo.collectSpecifier(element) }); + this.currentKitInfo = new ImportSpecifierKitInfo(kitNode, symbols); + namedBindings.elements.forEach(element => { this.currentKitInfo.collectSpecifier(element) }); } } } @@ -200,8 +223,8 @@ class KitImportInfo { // todo } else if (ts.isNamedExports(namedExportBindings) && namedExportBindings.elements.length !== 0) { // export { ... } from "@kit.xxx" - this.currentKitImportInfo = new ExportSpecifierKitImportInfo(kitNode, symbols); - namedExportBindings.elements.forEach(element => { this.currentKitImportInfo.collectSpecifier(element) }); + this.currentKitInfo = new ExportSpecifierKitInfo(kitNode, symbols); + namedExportBindings.elements.forEach(element => { this.currentKitInfo.collectSpecifier(element) }); } } else { // export * from "@kit.xxx" @@ -211,7 +234,7 @@ class KitImportInfo { } } - static processKitImportInfo(symbols: Record, kitNode: TSModuleDeclaration): void { + static processKitInfo(symbols: Record, kitNode: TSModuleDeclaration): void { // do not handle an empty import if (ts.isImportDeclaration(kitNode) && kitNode.importClause) { // import { ... } from '@kit.xxx' @@ -227,7 +250,7 @@ class KitImportInfo { this.processExportDecl(kitNode, symbols); } // transform into ohos imports or exports - this.currentKitImportInfo.transform(); + this.currentKitInfo && this.currentKitInfo.transform(); } getSymbols(): KitSymbols { @@ -248,7 +271,7 @@ class KitImportInfo { newSpecificerInfo(localName: string, importName: string, originElement: TSspecifier): SpecificerInfo { const symbol: Symbol = this.symbols[importName]; - const specifier: SpecificerInfo = new SpecificerInfo(localName, symbol, originElement); + const specifier: SpecificerInfo = new SpecificerInfo(localName, importName, symbol, originElement); if (this.specifiers.has(symbol.source)) { this.specifiers.get(symbol.source).push(specifier); } else { @@ -267,7 +290,7 @@ class KitImportInfo { transform() {} //override api } -class NameSpaceKitImportInfo extends KitImportInfo { +class NameSpaceKitInfo extends KitInfo { namespaceName: string; localNameTable: string[] = []; @@ -288,7 +311,7 @@ class NameSpaceKitImportInfo extends KitImportInfo { } } -class ImportSpecifierKitImportInfo extends KitImportInfo { +class ImportSpecifierKitInfo extends KitInfo { private namedBindings: ts.ImportSpecifier[] = []; private defaultName: ts.Identifier | undefined = undefined; @@ -328,13 +351,13 @@ class ImportSpecifierKitImportInfo extends KitImportInfo { } } -class ExportSpecifierKitImportInfo extends KitImportInfo { +class ExportSpecifierKitInfo extends KitInfo { transform() { } } -class ExportStarKitImportInfo extends KitImportInfo { +class ExportStarKitInfo extends KitInfo { transform() { } -- Gitee From 027855482a83a9ed76697b94591d860ad7dd1a33 Mon Sep 17 00:00:00 2001 From: hufeng Date: Wed, 20 Dec 2023 03:44:35 +0000 Subject: [PATCH 3/6] Fix visitor Signed-off-by: hufeng Change-Id: Ib0fda755b8fa76ad939b2365efe544336a46b88c --- .../ark_compiler/module/module_source_file.ts | 2 +- .../ets_ui/rollup-plugin-ets-typescript.ts | 2 +- compiler/src/process_kit_import.ts | 59 ++++++++++++++----- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/compiler/src/fast_build/ark_compiler/module/module_source_file.ts b/compiler/src/fast_build/ark_compiler/module/module_source_file.ts index 6a35327df..3b815a3b7 100644 --- a/compiler/src/fast_build/ark_compiler/module/module_source_file.ts +++ b/compiler/src/fast_build/ark_compiler/module/module_source_file.ts @@ -360,7 +360,7 @@ export class ModuleSourceFile { if (ts.isImportDeclaration(node) || (ts.isExportDeclaration(node) && node.moduleSpecifier)) { // moduleSpecifier.getText() returns string carrying on quotation marks which the importMap's key does not, // so we need to remove the quotation marks from moduleRequest. - const moduleRequest: string = node.moduleSpecifier.getText().replace(/'|"/g, ''); + const moduleRequest: string = (node.moduleSpecifier! as ts.StringLiteral).text.replace(/'|"/g, ''); let ohmUrl: string | undefined = this.getOhmUrl(rollupObject, moduleRequest, importMap[moduleRequest]); if (ohmUrl !== undefined) { // the import module are added with ".origin" at the end of the ohm url in every mock file. diff --git a/compiler/src/fast_build/ets_ui/rollup-plugin-ets-typescript.ts b/compiler/src/fast_build/ets_ui/rollup-plugin-ets-typescript.ts index a6b5aee28..2fcd0283f 100644 --- a/compiler/src/fast_build/ets_ui/rollup-plugin-ets-typescript.ts +++ b/compiler/src/fast_build/ets_ui/rollup-plugin-ets-typescript.ts @@ -330,7 +330,7 @@ async function transform(code: string, id: string) { tsProgram.emit(targetSourceFile, writeFile, undefined, undefined, { before: [ - processKitImport(null), + processKitImport(), processUISyntax(null, false, eventSetEmit, compilationTime) ] } diff --git a/compiler/src/process_kit_import.ts b/compiler/src/process_kit_import.ts index 5bdbd5241..d9a77d07e 100644 --- a/compiler/src/process_kit_import.ts +++ b/compiler/src/process_kit_import.ts @@ -18,6 +18,7 @@ import fs from 'fs'; import path from 'path'; import { FileLog, LogType } from './utils'; +import { projectConfig } from '../main'; /* * basic implementation logic: @@ -29,9 +30,10 @@ import { FileLog, LogType } from './utils'; * | -> replace each origin declaration with corresponding ohosImports */ -const KIT_CONFIGS = 'kit_configs'; -const KIT_PREFIX = '@kit.'; const JSON_SUFFIX = '.json'; +const KIT_PREFIX = '@kit.'; +const KIT_CONFIGS = 'kit_configs'; +const KIT_CONFIG_PATH = './build-tools/ets-loader/kit_configs'; export const kitTransformLog: FileLog = new FileLog(); @@ -45,22 +47,18 @@ export const kitTransformLog: FileLog = new FileLog(); * import ErrorCode from '@ohos.ability.errorCode' * ``` */ -export function processKitImport(program: ts.Program): Function { +export function processKitImport(): Function { return (context: ts.TransformationContext) => { const visitor: ts.Visitor = node => { + // node = ts.visitEachChild(node, visitor, context); // static import/export declaration if (ts.isImportDeclaration(node) || (ts.isExportDeclaration(node) && node.moduleSpecifier)) { // moduleSpecifier.getText() returns string carrying on quotation marks which the importMap's key does not, // so we need to remove the quotation marks from moduleRequest. const moduleRequest: string = node.moduleSpecifier.getText().replace(/'|"/g, ''); if (moduleRequest.startsWith(KIT_PREFIX)) { - const kitDefs = - JSON.parse( - fs.readFileSync(path.join(__dirname, `../${KIT_CONFIGS}/${moduleRequest}${JSON_SUFFIX}`), - 'utf-8' - ) - ); - if (kitDefs.symbols) { + const kitDefs = getKitDefs(moduleRequest); + if (kitDefs && kitDefs.symbols) { KitInfo.processKitInfo(kitDefs.symbols as KitSymbols, node); return [...KitInfo.getCurrentKitInfo().getOhosImportNodes()]; } @@ -70,8 +68,11 @@ export function processKitImport(program: ts.Program): Function { } return (node: ts.SourceFile) => { - KitInfo.init(node); - ts.visitEachChild(node, visitor, context); + if (projectConfig.compileMode === 'esmodule' && process.env.compileTool === 'rollup') { + KitInfo.init(node); + return ts.visitEachChild(node, visitor, context); + } + return node; }; } } @@ -95,7 +96,6 @@ declare type KitSymbols = Record; declare type TSspecifier = ts.ImportSpecifier | ts.ExportSpecifier; declare type TSModuleDeclaration = ts.ImportDeclaration | ts.ExportDeclaration; - /* * class SpecificerInfo represents the corresponding info of each imported identifier which coming from Kit */ @@ -112,7 +112,7 @@ class SpecificerInfo { this.importName = importName; this.symbol = symbol; this.originElement = originElement; - this.renamed = (this.localName === this.symbol.bindings); + this.renamed = (this.localName !== this.symbol.bindings); this.validateImportingETSDeclarationSymbol(); } @@ -319,6 +319,14 @@ class ImportSpecifierKitInfo extends KitInfo { super(kitNode, symbols); } + hasNamedBindings(): boolean { + return this.namedBindings.length !== 0; + } + + clearNamedBindings(): void { + this.namedBindings = []; + } + transform() { const node: ts.ImportDeclaration = this.getKitNode() as ts.ImportDeclaration; this.getSpecifiers().forEach((specifiers: SpecificerInfo[], source: string) => { @@ -343,10 +351,12 @@ class ImportSpecifierKitInfo extends KitInfo { ts.factory.createImportClause( node.importClause!.isTypeOnly, this.defaultName, - ts.factory.createNamedImports(this.namedBindings) + this.hasNamedBindings() ? ts.factory.createNamedImports(this.namedBindings) : undefined ), ts.factory.createStringLiteral(trimSourceSuffix(source)) )); + + this.clearNamedBindings(); }); } } @@ -366,6 +376,25 @@ class ExportStarKitInfo extends KitInfo { /* * utils part */ + +function getKitDefs(kitModuleRequest: string) { + const kitConfigs: string[] = [path.resolve(__dirname, `../${KIT_CONFIGS}`)]; + if (process.env.externalApiPaths) { + const externalApiPaths = process.env.externalApiPaths.split(path.delimiter); + externalApiPaths.forEach(sdkPath => { + kitConfigs.push(path.resolve(sdkPath, KIT_CONFIG_PATH)); + }); + } + + for (const kitConfig of kitConfigs) { + const kitModuleConfigJson = path.resolve(kitConfig, `./${kitModuleRequest}${JSON_SUFFIX}`); + if (fs.existsSync(kitModuleConfigJson)) { + return JSON.parse(fs.readFileSync(kitModuleConfigJson, 'utf-8')); + } + } + return undefined; +} + function trimSourceSuffix(source: string): string { return source.replace(/\.d.[e]?ts$/, ''); } \ No newline at end of file -- Gitee From 63a4e0328ca71a8583cd322fcce6cbaf347e4f0d Mon Sep 17 00:00:00 2001 From: hufeng Date: Sat, 23 Dec 2023 07:51:55 +0000 Subject: [PATCH 4/6] Fix ArkUI issue Signed-off-by: hufeng Change-Id: Ib7a8376d6b245d8737213c6aa95ac7ae258cf977 --- compiler/src/process_import.ts | 7 ++++--- compiler/src/process_ui_syntax.ts | 13 +++---------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/compiler/src/process_import.ts b/compiler/src/process_import.ts index 9dbe3f41e..8fe483ed7 100644 --- a/compiler/src/process_import.ts +++ b/compiler/src/process_import.ts @@ -79,7 +79,8 @@ import { import { validatorCard } from './process_ui_syntax'; import { SOURCE_FILES } from './ets_checker'; -const IMPORT_FILE_ASTCACHE: Map = process.env.watchMode === 'true' ? new Map() : SOURCE_FILES; +const IMPORT_FILE_ASTCACHE: Map = + process.env.watchMode === 'true' ? new Map() : (SOURCE_FILES ? SOURCE_FILES : new Map()); export default function processImport(node: ts.ImportDeclaration | ts.ImportEqualsDeclaration | ts.ExportDeclaration, pagesDir: string, log: LogInfo[], asName: Map = new Map(), @@ -87,7 +88,7 @@ isEntryPage: boolean = true, pathCollection: Set = new Set()): void { let filePath: string; let defaultName: string; if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) { - filePath = node.moduleSpecifier.getText().replace(/'|"/g, ''); + filePath = (node.moduleSpecifier! as ts.StringLiteral).text.replace(/'|"/g, ''); if (ts.isImportDeclaration(node) && node.importClause && node.importClause.name && ts.isIdentifier(node.importClause.name)) { defaultName = node.importClause.name.escapedText.toString(); @@ -296,7 +297,7 @@ function visitAllNode(node: ts.Node, sourceFile: ts.SourceFile, defaultNameFromP } if (ts.isImportDeclaration(node)) { if (node.importClause && node.importClause.name && ts.isIdentifier(node.importClause.name) && - asNameFromParent.has(node.importClause.name.getText())) { + asNameFromParent.has(node.importClause.name.text)) { processImport(node, pagesDir, log, asNameFromParent, false, new Set(pathCollection)); } else if (node.importClause && node.importClause.namedBindings && ts.isNamedImports(node.importClause.namedBindings) && node.importClause.namedBindings.elements) { diff --git a/compiler/src/process_ui_syntax.ts b/compiler/src/process_ui_syntax.ts index 55b585f99..0936dfa4e 100644 --- a/compiler/src/process_ui_syntax.ts +++ b/compiler/src/process_ui_syntax.ts @@ -235,17 +235,10 @@ export function processUISyntax(program: ts.Program, ut = false, parentEvent?: a } function processAllNodes(node: ts.Node): ts.Node { - if (projectConfig.compileMode === 'esmodule' && process.env.compileTool === 'rollup' && - ts.isImportDeclaration(node)) { - startTimeStatisticsLocation(compilationTime ? compilationTime.processImportTime : undefined); - processImportModule(node, pageFile); - stopTimeStatisticsLocation(compilationTime ? compilationTime.processImportTime : undefined); - } else if ((projectConfig.compileMode !== 'esmodule' || process.env.compileTool !== 'rollup') && - (ts.isImportDeclaration(node) || ts.isImportEqualsDeclaration(node) || - ts.isExportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier))) { + if (ts.isImportDeclaration(node) || ts.isImportEqualsDeclaration(node) || + ts.isExportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) { processImport(node, pagesDir, transformLog.errors); - } - if (ts.isStructDeclaration(node)) { + } else if (ts.isStructDeclaration(node)) { componentCollection.currentClassName = node.name.getText(); componentCollection.entryComponent === componentCollection.currentClassName && entryKeyNode(node); startTimeStatisticsLocation(compilationTime ? compilationTime.processComponentClassTime : undefined); -- Gitee From d55413037f8386fc01679d15c201262b66346314 Mon Sep 17 00:00:00 2001 From: hufeng Date: Sat, 23 Dec 2023 16:07:58 +0000 Subject: [PATCH 5/6] Enhance supporting Scenarios Signed-off-by: hufeng Change-Id: I28a8a311f6da4777d23f201546b1ea4b11df7c57 --- .gitignore | 1 - .../ets_ui/rollup-plugin-ets-typescript.ts | 5 +- compiler/src/process_kit_import.ts | 236 ++++++++++++------ 3 files changed, 159 insertions(+), 83 deletions(-) diff --git a/.gitignore b/.gitignore index 2fe023f40..8481c75bc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ compiler/declarations/ compiler/sample/build/ compiler/component_config.json compiler/form_config.json -compiler/kit_configs/ compiler/syntax_parser/dist/ compiler/.nyc_output compiler/.test_output diff --git a/compiler/src/fast_build/ets_ui/rollup-plugin-ets-typescript.ts b/compiler/src/fast_build/ets_ui/rollup-plugin-ets-typescript.ts index 2fcd0283f..536d2763f 100644 --- a/compiler/src/fast_build/ets_ui/rollup-plugin-ets-typescript.ts +++ b/compiler/src/fast_build/ets_ui/rollup-plugin-ets-typescript.ts @@ -72,7 +72,10 @@ import { GLOBAL_CUSTOM_BUILDER_METHOD, INNER_CUSTOM_BUILDER_METHOD } from '../../component_map'; -import { kitTransformLog, processKitImport } from '../../process_kit_import'; +import { + kitTransformLog, + processKitImport +} from '../../process_kit_import'; const filter:any = createFilter(/(? replace each origin declaration with corresponding ohosImports */ -const JSON_SUFFIX = '.json'; -const KIT_PREFIX = '@kit.'; -const KIT_CONFIGS = 'kit_configs'; -const KIT_CONFIG_PATH = './build-tools/ets-loader/kit_configs'; - export const kitTransformLog: FileLog = new FileLog(); +const KIT_PREFIX = '@kit.'; + /* * This API is the TSC Transformer for transforming `KitImport` into `OhosImport` * e.g. @@ -50,16 +49,13 @@ export const kitTransformLog: FileLog = new FileLog(); export function processKitImport(): Function { return (context: ts.TransformationContext) => { const visitor: ts.Visitor = node => { - // node = ts.visitEachChild(node, visitor, context); - // static import/export declaration + // only transform static import/export declaration if (ts.isImportDeclaration(node) || (ts.isExportDeclaration(node) && node.moduleSpecifier)) { - // moduleSpecifier.getText() returns string carrying on quotation marks which the importMap's key does not, - // so we need to remove the quotation marks from moduleRequest. - const moduleRequest: string = node.moduleSpecifier.getText().replace(/'|"/g, ''); + const moduleRequest: string = (node.moduleSpecifier as ts.StringLiteral).text.replace(/'|"/g, ''); if (moduleRequest.startsWith(KIT_PREFIX)) { const kitDefs = getKitDefs(moduleRequest); if (kitDefs && kitDefs.symbols) { - KitInfo.processKitInfo(kitDefs.symbols as KitSymbols, node); + KitInfo.processKitInfo(moduleRequest, kitDefs.symbols as KitSymbols, node); return [...KitInfo.getCurrentKitInfo().getOhosImportNodes()]; } } @@ -68,11 +64,8 @@ export function processKitImport(): Function { } return (node: ts.SourceFile) => { - if (projectConfig.compileMode === 'esmodule' && process.env.compileTool === 'rollup') { KitInfo.init(node); return ts.visitEachChild(node, visitor, context); - } - return node; }; } } @@ -87,12 +80,12 @@ enum FileType { TS } -interface Symbol { +interface KitSymbol { source: string bindings: string } -declare type KitSymbols = Record; +declare type KitSymbols = Record; declare type TSspecifier = ts.ImportSpecifier | ts.ExportSpecifier; declare type TSModuleDeclaration = ts.ImportDeclaration | ts.ExportDeclaration; @@ -102,12 +95,12 @@ declare type TSModuleDeclaration = ts.ImportDeclaration | ts.ExportDeclaration; class SpecificerInfo { private localName: string; private importName: string; - private symbol: Symbol; + private symbol: KitSymbol; private renamed: boolean; - private originElement: TSspecifier; + private originElement: TSspecifier | undefined; - constructor(localName: string, importName: string, symbol: Symbol, originElement: TSspecifier) { + constructor(localName: string, importName: string, symbol: KitSymbol, originElement: TSspecifier | undefined) { this.localName = localName; this.importName = importName; this.symbol = symbol; @@ -160,16 +153,20 @@ class SpecificerInfo { class KitInfo { private static currentKitInfo: KitInfo = undefined; private static currentFileType: FileType = FileType.ETS; + private static currentKitName: string = ''; private symbols: KitSymbols; private kitNode: TSModuleDeclaration; + private kitNodeModifier: readonly ts.Modifier[] | undefined; private specifiers: Map = new Map(); - private ohosImportNodes: ts.ImportDeclaration[] = []; + private ohosImportNodes: TSModuleDeclaration[] = []; - constructor(kitNode: TSModuleDeclaration, symbols: Record) { + constructor(kitNode: TSModuleDeclaration, symbols: Record) { this.kitNode = kitNode; this.symbols = symbols; + + this.kitNodeModifier = ts.canHaveDecorators(this.kitNode) ? ts.getModifiers(this.kitNode) : undefined; } static init(node: ts.SourceFile): void { @@ -182,6 +179,10 @@ class KitInfo { kitTransformLog.sourceFile = node; } + static getCurrentKitName(): string { + return this.currentKitName; + } + static getCurrentKitInfo(): KitInfo { return this.currentKitInfo; } @@ -194,59 +195,58 @@ class KitInfo { return this.currentFileType === FileType.TS; } - static processImportDecl(kitNode: ts.ImportDeclaration, symbols: Record) { - // this.kitNode = this.kitNode as ts.ImportDeclaration; - if (kitNode.importClause!.name) { - // import default from "@kit.xxx" - // todo: throw error msg - } + static processImportDecl(kitNode: ts.ImportDeclaration, symbols: Record) { if (kitNode.importClause!.namedBindings) { const namedBindings: ts.NamedImportBindings = kitNode.importClause.namedBindings; if (ts.isNamespaceImport(namedBindings)) { - // import * as ns from "@kit.xxx" - // todo: logger.warn to reminder developer the side-effect of using namespace import with Kit + // e.g. import * as ns from "@kit.xxx" this.currentKitInfo = new NameSpaceKitInfo(kitNode, symbols); } if (ts.isNamedImports(namedBindings) && namedBindings.elements.length !== 0) { - // import { ... } from "@kit.xxx" + // e.g. import { ... } from "@kit.xxx" this.currentKitInfo = new ImportSpecifierKitInfo(kitNode, symbols); namedBindings.elements.forEach(element => { this.currentKitInfo.collectSpecifier(element) }); } } + + if (kitNode.importClause!.name) { + // e.g. import default from "@kit.xxx" + const defaultName: string = kitNode.importClause.name.text; + this.currentKitInfo.newSpecificerInfo(defaultName, DEFAULT_BINDINGS, undefined); + } } - static processExportDecl(kitNode: ts.ExportDeclaration, symbols: Record) { + static processExportDecl(kitNode: ts.ExportDeclaration, symbols: Record) { if (kitNode.exportClause) { const namedExportBindings: ts.NamedExportBindings = kitNode.exportClause; if (ts.isNamespaceExport(namedExportBindings)) { - // export * as ns from "@kit.xxx" - // todo + // e.g. export * as ns from "@kit.xxx" + this.currentKitInfo = new NameSpaceKitInfo(kitNode, symbols); } else if (ts.isNamedExports(namedExportBindings) && namedExportBindings.elements.length !== 0) { - // export { ... } from "@kit.xxx" + // e.g. export { ... } from "@kit.xxx" this.currentKitInfo = new ExportSpecifierKitInfo(kitNode, symbols); namedExportBindings.elements.forEach(element => { this.currentKitInfo.collectSpecifier(element) }); } } else { - // export * from "@kit.xxx" - // equals expanding all the ohos with export-star - // export * from "@ohos.xxx";export * from "@ohos.yyy"; - // iterate kit + this.currentKitInfo = new ExportStarKitInfo(kitNode, symbols); } } - static processKitInfo(symbols: Record, kitNode: TSModuleDeclaration): void { + static processKitInfo(kitName: string, symbols: Record, kitNode: TSModuleDeclaration): void { + this.currentKitName = kitName; + // do not handle an empty import if (ts.isImportDeclaration(kitNode) && kitNode.importClause) { - // import { ... } from '@kit.xxx' - // import * as ns from '@kit.xxx' - // import defalutValue from '@kit.xxx' - forbidden + // case 1: import { ... } from '@kit.xxx' + // case 2: import * as ns from '@kit.xxx' + // case 3: import defalutValue from '@kit.xxx' this.processImportDecl(kitNode, symbols); } if (ts.isExportDeclaration(kitNode) && kitNode.moduleSpecifier) { - // export { ... } from '@kit.xxx' - // export * from '@kit.xxx' - // export * as ns from '@kit.xxx' - considering forbidden + // case 1: export { ... } from '@kit.xxx' + // case 2: export * from '@kit.xxx' + // case 3: export * as ns from '@kit.xxx' - considering forbidden this.processExportDecl(kitNode, symbols); } // transform into ohos imports or exports @@ -261,23 +261,34 @@ class KitInfo { return this.kitNode; } + getKitNodeModifier(): readonly ts.Modifier[] | undefined { + return this.kitNodeModifier; + } + getSpecifiers(): Map { return this.specifiers; } - getOhosImportNodes(): ts.ImportDeclaration[] { + getOhosImportNodes(): TSModuleDeclaration[] { return this.ohosImportNodes; } - newSpecificerInfo(localName: string, importName: string, originElement: TSspecifier): SpecificerInfo { - const symbol: Symbol = this.symbols[importName]; - const specifier: SpecificerInfo = new SpecificerInfo(localName, importName, symbol, originElement); - if (this.specifiers.has(symbol.source)) { - this.specifiers.get(symbol.source).push(specifier); + newSpecificerInfo(localName: string, importName: string, originElement: TSspecifier | undefined): void { + const symbol: KitSymbol | undefined = this.symbols[importName]; + if (symbol) { + const specifier: SpecificerInfo = new SpecificerInfo(localName, importName, symbol, originElement); + if (this.specifiers.has(symbol.source)) { + this.specifiers.get(symbol.source).push(specifier); + } else { + this.specifiers.set(symbol.source, [specifier]); + } } else { - this.specifiers.set(symbol.source, [specifier]); + kitTransformLog.errors.push({ + type: LogType.ERROR, + message: `Kit '${KitInfo.getCurrentKitName()} has not exported the Identifier '${importName}'.`, + pos: originElement ? originElement.getStart() : this.getKitNode().getStart() + }); } - return specifier; } collectSpecifier(element: TSspecifier) { @@ -287,58 +298,56 @@ class KitInfo { } // @ts-ignore - transform() {} //override api + transform(): void {} //override api } class NameSpaceKitInfo extends KitInfo { - namespaceName: string; - localNameTable: string[] = []; + private namespaceName: string; + private localNameTable: string[] = []; - constructor(kitNode: ts.ImportDeclaration, symbols: Record) { + constructor(kitNode: ts.ImportDeclaration | ts.ExportDeclaration, symbols: Record) { super(kitNode, symbols); - this.namespaceName = (kitNode.importClause!.namedBindings as ts.NamespaceImport).name.getText(); + kitTransformLog.errors.push({ + type: LogType.ERROR, + message: `Namespace import or export of Kit is not supported currently.`, + pos: kitNode.getStart() + }); } - - - transform() { - for (const symbol in this.getSymbols()) { - - } - - // issue: how to insert the `const ns = {}` + transform(): void { } } class ImportSpecifierKitInfo extends KitInfo { private namedBindings: ts.ImportSpecifier[] = []; - private defaultName: ts.Identifier | undefined = undefined; + private specifierDefaultName: ts.Identifier | undefined = undefined; - constructor(kitNode: ts.ImportDeclaration, symbols: Record) { + constructor(kitNode: ts.ImportDeclaration, symbols: Record) { super(kitNode, symbols); } - hasNamedBindings(): boolean { + private hasNamedBindings(): boolean { return this.namedBindings.length !== 0; } - clearNamedBindings(): void { + private clearSpecifierKitInfo(): void { this.namedBindings = []; + this.specifierDefaultName = undefined; } transform() { const node: ts.ImportDeclaration = this.getKitNode() as ts.ImportDeclaration; - this.getSpecifiers().forEach((specifiers: SpecificerInfo[], source: string) => { - const modifier: readonly ts.Modifier[] = ts.canHaveDecorators(node) ? ts.getModifiers(node) : undefined; + this.getSpecifiers().forEach((specifiers: SpecificerInfo[], source: string) => { specifiers.forEach((specifier: SpecificerInfo) => { if (specifier.isDefaultBinding()) { - this.defaultName = ts.factory.createIdentifier(specifier.getLocalName()); + this.specifierDefaultName = ts.factory.createIdentifier(specifier.getLocalName()); } else { this.namedBindings.push( ts.factory.createImportSpecifier( - (specifier.getOriginElementNode() as ts.ImportSpecifier).isTypeOnly, + specifier.getOriginElementNode() ? + (specifier.getOriginElementNode() as ts.ImportSpecifier).isTypeOnly : node.importClause.isTypeOnly, specifier.isRenamed() ? ts.factory.createIdentifier(specifier.getBindings()) : undefined, ts.factory.createIdentifier(specifier.getLocalName()) ) @@ -347,35 +356,100 @@ class ImportSpecifierKitInfo extends KitInfo { }); this.getOhosImportNodes().push(ts.factory.createImportDeclaration( - modifier, + this.getKitNodeModifier(), ts.factory.createImportClause( node.importClause!.isTypeOnly, - this.defaultName, + this.specifierDefaultName, this.hasNamedBindings() ? ts.factory.createNamedImports(this.namedBindings) : undefined ), ts.factory.createStringLiteral(trimSourceSuffix(source)) )); - this.clearNamedBindings(); + this.clearSpecifierKitInfo(); }); } } class ExportSpecifierKitInfo extends KitInfo { - transform() { + private namedBindings: ts.ExportSpecifier[] = []; + + constructor(kitNode: ts.ExportDeclaration, symbols: Record) { + super(kitNode, symbols); + } + + private hasNamedBindings(): boolean { + return this.namedBindings.length !== 0; + } + + private clearSpecifierKitInfo(): void { + this.namedBindings = []; + } + + transform(): void { + const node: ts.ExportDeclaration = this.getKitNode() as ts.ExportDeclaration; + + this.getSpecifiers().forEach((specifiers: SpecificerInfo[], source: string) => { + specifiers.forEach((specifier: SpecificerInfo) => { + this.namedBindings.push( + ts.factory.createExportSpecifier( + (specifier.getOriginElementNode() as ts.ExportSpecifier).isTypeOnly, + specifier.isRenamed() ? ts.factory.createIdentifier(specifier.getBindings()) : undefined, + ts.factory.createIdentifier(specifier.getLocalName()) + ) + ); + }); + + this.getOhosImportNodes().push(ts.factory.createExportDeclaration( + this.getKitNodeModifier(), + node.isTypeOnly, + this.hasNamedBindings() ? ts.factory.createNamedExports(this.namedBindings) : undefined, + ts.factory.createStringLiteral(trimSourceSuffix(source)), + node.assertClause + )); + this.clearSpecifierKitInfo(); + }); } } class ExportStarKitInfo extends KitInfo { - transform() { + private sourceSet: Set = new Set(); + + constructor(kitNode: ts.ExportDeclaration, symbols: Record) { + super(kitNode, symbols); + + for (const symbol in symbols) { + this.sourceSet.add(symbols[symbol].source); + } + + kitTransformLog.errors.push({ + type: LogType.WARN, + message: `Using 'export *' will load all the sub-module of Kit in runtime.`, + pos: this.getKitNode().getStart() + }); + } + transform(): void { + const node: ts.ExportDeclaration = this.getKitNode() as ts.ExportDeclaration; + + this.sourceSet.forEach((source: string) => { + this.getOhosImportNodes().push(ts.factory.createExportDeclaration( + this.getKitNodeModifier(), + node.isTypeOnly, + undefined, + ts.factory.createStringLiteral(trimSourceSuffix(source)), + node.assertClause + )); + }); } } /* * utils part */ +const JSON_SUFFIX = '.json'; +const KIT_CONFIGS = 'kit_configs'; +const KIT_CONFIG_PATH = './build-tools/ets-loader/kit_configs'; function getKitDefs(kitModuleRequest: string) { const kitConfigs: string[] = [path.resolve(__dirname, `../${KIT_CONFIGS}`)]; -- Gitee From 321fcf2806b001c68a2b11c465143914918dfb5a Mon Sep 17 00:00:00 2001 From: hufeng Date: Sun, 24 Dec 2023 11:24:24 +0000 Subject: [PATCH 6/6] Add UT Signed-off-by: hufeng Change-Id: I4b4a116369489df182ff390471963af17b931f84 --- .../common/process_kit_import.test.ts | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 compiler/test/ark_compiler_ut/common/process_kit_import.test.ts diff --git a/compiler/test/ark_compiler_ut/common/process_kit_import.test.ts b/compiler/test/ark_compiler_ut/common/process_kit_import.test.ts new file mode 100644 index 000000000..db559da05 --- /dev/null +++ b/compiler/test/ark_compiler_ut/common/process_kit_import.test.ts @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use rollupObject 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 { expect } from 'chai'; +import mocha from 'mocha'; +import * as ts from 'typescript'; +import path from 'path'; + +import { processKitImport } from '../../../lib/process_kit_import' + +const KIT_IMPORT_CODE: string = +` +import { Ability, featureAbility, ErrorCode } from "@kit.AbilityKit"; +let localAbility = new Ability(); +let localFeature = new featureAbility(); +let noError = ErrorCode.NO_ERROR; +` + +const KIT_IMPORT_CODE_EXPECT: string = +'import Ability from "@ohos.app.ability.Ability";\n' + +'import featureAbility from "@ohos.ability.featureAbility";\n'+ +'import { ErrorCode } from "@ohos.ability.errorCode";\n'+ +'let localAbility = new Ability();\n'+ +'let localFeature = new featureAbility();\n'+ +'let noError = ErrorCode.NO_ERROR;\n'+ +'//# sourceMappingURL=kitTest.js.map' + +const KIT_EXPORT_CODE: string = +` +export { Ability, featureAbility, ErrorCode } from "@kit.AbilityKit"; +` + +const KIT_EXPORT_CODE_EXPECT: string = +'export { default as Ability } from "@ohos.app.ability.Ability";\n' + +'export { default as featureAbility } from "@ohos.ability.featureAbility";\n'+ +'export { ErrorCode } from "@ohos.ability.errorCode";\n'+ +'//# sourceMappingURL=kitTest.js.map' + +const KIT_STAR_EXPORT_CODE: string = +` +export * from "@kit.AudioKit"; +` + +const KIT_STAR_EXPORT_CODE_EXPECT: string = +'export * from "@ohos.multimedia.audio";\n' + +'export * from "@ohos.multimedia.audioHaptic";\n'+ +'export * from "@ohos.multimedia.systemSoundManager";\n'+ +'//# sourceMappingURL=kitTest.js.map' + +const compilerOptions = ts.readConfigFile( + path.resolve(__dirname, '../../../tsconfig.json'), ts.sys.readFile).config.compilerOptions; +compilerOptions['moduleResolution'] = 'nodenext'; +compilerOptions['module'] = 'es2020'; + +// !! The Kit transform result would be changed once the kit config file has updated. +mocha.describe('process Kit Imports tests', function () { + mocha.it('process specifier imports', function () { + const result: ts.TranspileOutput = ts.transpileModule(KIT_IMPORT_CODE, { + compilerOptions: compilerOptions, + fileName: "kitTest.ts", + transformers: { before: [ processKitImport() ] } + }); + expect(result.outputText == KIT_IMPORT_CODE_EXPECT).to.be.true; + }); + + mocha.it('process specifier exports', function () { + const result: ts.TranspileOutput = ts.transpileModule(KIT_EXPORT_CODE, { + compilerOptions: compilerOptions, + fileName: "kitTest.ts", + transformers: { before: [ processKitImport() ] } + }); + expect(result.outputText == KIT_EXPORT_CODE_EXPECT).to.be.true; + }); + + mocha.it('process star export', function () { + const result: ts.TranspileOutput = ts.transpileModule(KIT_STAR_EXPORT_CODE, { + compilerOptions: compilerOptions, + fileName: "kitTest.ts", + transformers: { before: [ processKitImport() ] } + }); + expect(result.outputText == KIT_STAR_EXPORT_CODE_EXPECT).to.be.true; + }); +}); -- Gitee