From 439586f1a9560ff134f6ab959b08c16128aa1396 Mon Sep 17 00:00:00 2001 From: zhangzezhong Date: Wed, 13 Aug 2025 17:24:50 +0800 Subject: [PATCH 01/31] =?UTF-8?q?=E8=93=9D=E9=BB=84=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangzezhong --- compiler/src/fast_build/ets_ui/rollup-plugin-ets-typescript.ts | 2 +- compiler/src/process_ui_syntax.ts | 2 +- 2 files changed, 2 insertions(+), 2 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 8f0e19096..4fe0e8fd9 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 @@ -417,7 +417,7 @@ async function transform(code: string, id: string) { const result: ts.TranspileOutput = ts.transpileModule(newContent, { compilerOptions: compilerOptions, fileName: id, - transformers: { before: [processUISyntax(null, false, null, id, metaInfo)] } + transformers: { before: [processUISyntax(null, false, undefined, id, null, metaInfo)] } }); resetCollection(); diff --git a/compiler/src/process_ui_syntax.ts b/compiler/src/process_ui_syntax.ts index 68209e23d..e8c2932a2 100644 --- a/compiler/src/process_ui_syntax.ts +++ b/compiler/src/process_ui_syntax.ts @@ -171,12 +171,12 @@ import { createAndStartEvent, stopEvent } from './performance'; +import parseIntent from './userIntents_parser/parseUserIntents'; export let transformLog: IFileLog = new createAstNodeUtils.FileLog(); export let contextGlobal: ts.TransformationContext; export let resourceFileName: string = ''; export const builderTypeParameter: { params: string[] } = { params: [] }; -import parseIntent from './userIntents_parser/parseUserIntents'; export function processUISyntax(program: ts.Program, ut = false, parentEvent?: CompileEvent, filePath: string = '', share: object = null, metaInfo: Object = {}): Function { -- Gitee From 3f25edfca435cfd8b2c81032ed03ef2e34dcd131 Mon Sep 17 00:00:00 2001 From: zhangzezhong Date: Fri, 15 Aug 2025 14:15:21 +0800 Subject: [PATCH 02/31] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=86=E6=94=AF?= =?UTF-8?q?=E5=88=A4=E6=96=AD=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangzezhong --- compiler/src/userIntents_parser/parseUserIntents.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/userIntents_parser/parseUserIntents.ts b/compiler/src/userIntents_parser/parseUserIntents.ts index fa4bc79bd..1b8e02177 100644 --- a/compiler/src/userIntents_parser/parseUserIntents.ts +++ b/compiler/src/userIntents_parser/parseUserIntents.ts @@ -882,7 +882,7 @@ class ParseIntent { const formBlackList: string[] = ['context']; if (decoratorType === COMPONENT_USER_INTENTS_DECORATOR_ENTRY && entryBlackList.includes(propName)) { return obj; - } else if (decoratorType === COMPONENT_USER_INTENTS_DECORATOR_ENTRY && formBlackList.includes(propName)) { + } else if (decoratorType === COMPONENT_USER_INTENTS_DECORATOR_FORM && formBlackList.includes(propName)) { return obj; } const tempschemaVerifyType: schemaVerifyType = { -- Gitee From d408c086a9694b3a25a748fbd3496faf93fd002a Mon Sep 17 00:00:00 2001 From: kleene Date: Mon, 18 Aug 2025 10:25:25 +0800 Subject: [PATCH 03/31] rebase 0702 Issue: ICTDUE Signed-off-by: kleene Change-Id: I99f6ef2e5dd1744a3e5b3e33c8de17e448ba0f2b --- compiler/compile_plugin.js | 17 + compiler/src/interop/main.js | 18 +- .../ark_compiler/interop/interop_manager.ts | 144 ++++-- .../ark_compiler/interop/pre_define.ts | 9 +- .../fast_build/ark_compiler/interop/type.ts | 11 +- .../fast_build/ark_compiler/interop/utils.ts | 25 ++ .../interop/interop_manager.test.ts | 422 ++++++++++++++++++ .../interop/process_arkts_evolution.test.ts | 117 +++++ 8 files changed, 718 insertions(+), 45 deletions(-) create mode 100644 compiler/src/interop/src/fast_build/ark_compiler/interop/utils.ts create mode 100644 compiler/test/ark_compiler_ut/interop/interop_manager.test.ts create mode 100644 compiler/test/ark_compiler_ut/interop/process_arkts_evolution.test.ts diff --git a/compiler/compile_plugin.js b/compiler/compile_plugin.js index 675dae30d..73297fc82 100644 --- a/compiler/compile_plugin.js +++ b/compiler/compile_plugin.js @@ -28,7 +28,24 @@ const { generateConsumerObConfigFile } = require('./lib/fast_build/ark_compiler/ const { etsStandaloneChecker } = require('./lib/ets_checker'); const { memoryMonitor } = require('./lib/fast_build/meomry_monitor/rollup-plugin-memory-monitor'); +let initConfigForInterop = (interopConfig) => { + return {}; +}; + +try { + ({ initConfigForInterop } = require('./lib/fast_build/ark_compiler/interop/interop_manager')); +} catch (err) { + if (err.code !== 'MODULE_NOT_FOUND') { + throw err; + } +} + +function initInteropConfig(interopConfig) { + return initConfigForInterop(interopConfig); +} + exports.initConfig = initConfig; +exports.initInteropConfig = initInteropConfig; exports.getCleanConfig = getCleanConfig; exports.generateConsumerObConfigFile = generateConsumerObConfigFile; exports.etsStandaloneChecker = etsStandaloneChecker; diff --git a/compiler/src/interop/main.js b/compiler/src/interop/main.js index 36cbe76f2..c76d06e60 100644 --- a/compiler/src/interop/main.js +++ b/compiler/src/interop/main.js @@ -44,14 +44,14 @@ const { } = require('log4js'); const { - entryFileLanguageInfo, + setEntryFileLanguage, isMixCompile, processAbilityPagesFullPath, transformAbilityPages } = require('./lib/fast_build/ark_compiler/interop/interop_manager'); const { - ARKTS_1_2 + ARKTS_MODE } = require('./lib/fast_build/ark_compiler/interop/pre_define'); configure({ @@ -123,6 +123,8 @@ function initProjectConfig(projectConfig) { projectConfig.allowEmptyBundleName = false; projectConfig.uiTransformOptimization = false; projectConfig.ignoreCrossplatformCheck = false; + projectConfig.isolatedDeclarations = false; + projectConfig.noCheck = false; } function initProjectPathConfig(projectConfig) { @@ -505,16 +507,16 @@ function readAbilityEntrance(moduleJson) { if (moduleJson.module) { const moduleSrcEntrance = moduleJson.module.srcEntrance; const moduleSrcEntry = moduleJson.module.srcEntry; - const isStatic = moduleJson.module?.abilityStageCodeLanguage === ARKTS_1_2; + const isStatic = moduleJson.module?.arkTSMode === ARKTS_MODE.STATIC; if (moduleSrcEntry) { abilityPages.push(moduleSrcEntry); abilityPagesFullPath.add(getAbilityFullPath(projectConfig.projectPath, moduleSrcEntry)); - entryFileLanguageInfo.set(moduleSrcEntry, isStatic); + setEntryFileLanguage(moduleSrcEntry, isStatic); } else if (moduleSrcEntrance) { abilityPages.push(moduleSrcEntrance); abilityPagesFullPath.add(getAbilityFullPath(projectConfig.projectPath, moduleSrcEntrance)); - entryFileLanguageInfo.set(moduleSrcEntrance, isStatic); + setEntryFileLanguage(moduleSrcEntrance, isStatic); } if (moduleJson.module.abilities && moduleJson.module.abilities.length > 0) { setEntrance(moduleJson.module.abilities, abilityPages); @@ -530,14 +532,14 @@ function readAbilityEntrance(moduleJson) { function setEntrance(abilityConfig, abilityPages) { if (abilityConfig && abilityConfig.length > 0) { abilityConfig.forEach(ability => { - const isStatic = ability.codeLanguage === ARKTS_1_2; + const isStatic = ability.arkTSMode === ARKTS_MODE.STATIC; if (ability.srcEntry) { abilityPages.push(ability.srcEntry); - entryFileLanguageInfo.set(ability.srcEntry, isStatic); + setEntryFileLanguage(ability.srcEntry, isStatic); abilityPagesFullPath.add(getAbilityFullPath(projectConfig.projectPath, ability.srcEntry)); } else if (ability.srcEntrance) { abilityPages.push(ability.srcEntrance); - entryFileLanguageInfo.set(ability.srcEntrance, isStatic); + setEntryFileLanguage(ability.srcEntrance, isStatic); abilityPagesFullPath.add(getAbilityFullPath(projectConfig.projectPath, ability.srcEntrance)); } }); diff --git a/compiler/src/interop/src/fast_build/ark_compiler/interop/interop_manager.ts b/compiler/src/interop/src/fast_build/ark_compiler/interop/interop_manager.ts index 3fe736afd..4ec3efcc8 100644 --- a/compiler/src/interop/src/fast_build/ark_compiler/interop/interop_manager.ts +++ b/compiler/src/interop/src/fast_build/ark_compiler/interop/interop_manager.ts @@ -17,14 +17,23 @@ import fs from 'fs'; import path from 'path'; import { + globalModulePaths, + initBuildInfo, + loadEntryObj, + loadModuleInfo, + loadWorker, projectConfig, + readAppResource, + readPatchConfig, + readWorkerFile, sdkConfigs } from '../../../../main'; import { toUnixPath } from '../../../utils'; import { ArkTSEvolutionModule, FileInfo, - AliasConfig + AliasConfig, + InteropConfig } from './type'; import { hasExistingPaths, @@ -46,8 +55,15 @@ import { ARKTS_1_2, ARKTS_HYBRID } from './pre_define'; +import { readFirstLineSync } from './utils'; -export let entryFileLanguageInfo = new Map(); +let entryFileLanguageInfo = new Map(); +export let workerFile = null; +export let mixCompile = undefined; + +export function setEntryFileLanguage(filePath: string, language: string): void { + entryFileLanguageInfo.set(filePath, language); +} export class FileManager { private static instance: FileManager | undefined = undefined; @@ -60,7 +76,7 @@ export class FileManager { static mixCompile: boolean = false; static glueCodeFileInfos: Map = new Map(); static isInteropSDKEnabled: boolean = false; - static sharedObj: Object | undefined = undefined; + interopConfig: InteropConfig | undefined = undefined; private constructor() { } @@ -101,14 +117,18 @@ export class FileManager { return FileManager.instance; } - public static setRollUpObj(shared: Object): void { - FileManager.sharedObj = shared; - } - public static setMixCompile(mixCompile: boolean): void { FileManager.mixCompile = mixCompile; } + public setInteropConfig(interopConfig: InteropConfig): void { + this.interopConfig = interopConfig; + } + + public getInteropConfig(): InteropConfig { + return this.interopConfig; + } + private static initLanguageVersionFromDependentModuleMap( dependentModuleMap: Map ): void { @@ -217,7 +237,6 @@ export class FileManager { FileManager.glueCodeFileInfos?.clear(); FileManager.aliasConfig?.clear(); FileManager.mixCompile = false; - entryFileLanguageInfo.clear(); } getLanguageVersionByFilePath(filePath: string): { @@ -302,11 +321,7 @@ export class FileManager { } private static logError(error: LogData): void { - if (FileManager.sharedObj) { - CommonLogger.getInstance(FileManager.sharedObj).printErrorAndExit(error); - } else { - console.error(error.toString()); - } + console.error(error.toString()); } private static matchSDKPath(path: string): { @@ -369,22 +384,22 @@ export class FileManager { } } -export function initFileManagerInRollup(share: Object): void { - if (!share.projectConfig.mixCompile) { +export function initFileManagerInRollup(InteropConfig: InteropConfig): void { + if (!isMixCompile()) { return; } FileManager.mixCompile = true; - const sdkInfo = collectSDKInfo(share); + const sdkInfo = collectSDKInfo(InteropConfig); FileManager.init( - share.projectConfig.dependentModuleMap, - share.projectConfig.aliasPaths, + InteropConfig.projectConfig.dependentModuleMap, + InteropConfig.projectConfig.aliasPaths, sdkInfo.dynamicSDKPath, sdkInfo.staticSDKInteropDecl, sdkInfo.staticSDKGlueCodePath ); - FileManager.setRollUpObj(share); + FileManager.getInstance().setInteropConfig(InteropConfig); } export function collectSDKInfo(share: Object): { @@ -433,15 +448,6 @@ export function collectSDKInfo(share: Object): { }; } -function readFirstLineSync(filePath: string): string { - const buffer = fs.readFileSync(filePath, 'utf-8'); - const newlineIndex = buffer.indexOf('\n'); - if (newlineIndex === -1) { - return buffer.trim(); - } - return buffer.substring(0, newlineIndex).trim(); -} - export function isBridgeCode(filePath: string, projectConfig: Object): boolean { if (!projectConfig?.mixCompile) { return false; @@ -455,6 +461,9 @@ export function isBridgeCode(filePath: string, projectConfig: Object): boolean { } export function isMixCompile(): boolean { + if (typeof mixCompile === 'boolean') { + return mixCompile; + } return process.env.mixCompile === 'true'; } @@ -493,7 +502,7 @@ export function processAbilityPagesFullPath(abilityPagesFullPath: Set): export function transformAbilityPages(abilityPath: string): boolean { - const entryBridgeCodePath = process.env.entryBridgeCodePath; + const entryBridgeCodePath = getBrdigeCodeRootPath(abilityPath, FileManager.getInstance().getInteropConfig()); if (!entryBridgeCodePath) { const errInfo = LogDataFactory.newInstance( ErrorCode.ETS2BUNDLE_INTERNAL_MISSING_BRIDGECODE_PATH_INFO, @@ -516,9 +525,12 @@ export function transformAbilityPages(abilityPath: string): boolean { return false; } -function transformModuleNameToRelativePath(moduleName): string { +export function transformModuleNameToRelativePath(filePath: string): string { let defaultSourceRoot = 'src/main'; - const normalizedModuleName = moduleName.replace(/\\/g, '/'); + if (FileManager.getInstance().getInteropConfig()?.projectConfig?.isOhosTest) { + defaultSourceRoot = 'src/ohosTest'; + } + const normalizedModuleName = filePath.replace(/\\/g, '/'); const normalizedRoot = defaultSourceRoot.replace(/\\/g, '/'); const rootIndex = normalizedModuleName.indexOf(`/${normalizedRoot}/`); @@ -527,15 +539,16 @@ function transformModuleNameToRelativePath(moduleName): string { ErrorCode.ETS2BUNDLE_INTERNAL_WRONG_MODULE_NAME_FROM_ACEMODULEJSON, ArkTSInternalErrorDescription, `defaultSourceRoot '${defaultSourceRoot}' not found ` + - `when process moduleName '${moduleName}'` + `when process moduleName '${filePath}'` ); throw Error(errInfo.toString()); } - const relativePath = normalizedModuleName.slice(rootIndex + normalizedRoot.length + 1); + const relativePath = normalizedModuleName.slice(rootIndex + normalizedRoot.length + 1).replace(/^\/+/, ''); return './' + relativePath; } + export function getApiPathForInterop(apiDirs: string[], languageVersion: string): void { if (languageVersion !== ARKTS_1_2) { return; @@ -545,7 +558,7 @@ export function getApiPathForInterop(apiDirs: string[], languageVersion: string) apiDirs.unshift(...staticPaths); } -export function rebuildEntryObj(projectConfig: Object): void { +export function rebuildEntryObj(projectConfig: Object, interopConfig: InteropConfig): void { const entryObj = projectConfig.entryObj; const removeExt = (p: string): string => p.replace(/\.[^/.]+$/, ''); @@ -562,7 +575,7 @@ export function rebuildEntryObj(projectConfig: Object): void { if (!firstLine.includes('use static')) { newEntry[newKey] = rawPath; } else if (rawPath.startsWith(projectConfig.projectRootPath)) { - const bridgePath = process.env.entryBridgeCodePath; + const bridgePath = getBrdigeCodeRootPath(rawPath, interopConfig); if (!bridgePath) { const errInfo = LogDataFactory.newInstance( ErrorCode.ETS2BUNDLE_INTERNAL_MISSING_BRIDGECODE_PATH_INFO, @@ -580,3 +593,64 @@ export function rebuildEntryObj(projectConfig: Object): void { return newEntry; }, {} as Record); } + + +/** + * corresponds to compiler/src/fast_build/common/init_config.ts - initConfig() + * As the entry for mix compile,so mixCompile status will be set true + */ +export function initConfigForInterop(interopConfig: InteropConfig): Object { + initFileManagerInRollup(interopConfig); + + function getEntryObj(): void { + loadEntryObj(projectConfig); + initBuildInfo(); + readPatchConfig(); + loadModuleInfo(projectConfig); + workerFile = readWorkerFile(); + if (!projectConfig.isPreview) { + loadWorker(projectConfig, workerFile); + } + if (isMixCompile()) { + rebuildEntryObj(projectConfig, interopConfig); + return; + } + projectConfig.entryObj = Object.keys(projectConfig.entryObj).reduce((newEntry, key) => { + const newKey: string = key.replace(/^\.\//, ''); + newEntry[newKey] = projectConfig.entryObj[key].replace('?entry', ''); + return newEntry; + }, {}); + } + mixCompile = true; + getEntryObj(); + if (process.env.appResource) { + readAppResource(process.env.appResource); + } + return { + entryObj: Object.assign({}, projectConfig.entryObj, projectConfig.otherCompileFiles), + cardEntryObj: projectConfig.cardEntryObj, + workerFile: workerFile, + globalModulePaths: globalModulePaths + }; +} + +export function getBrdigeCodeRootPath(filePath: string, interopConfig: InteropConfig): string | undefined { + if (!interopConfig) { + return process.env.entryBridgeCodePath; + } + + for (const [moduleRootPath, InteropInfo] of interopConfig.interopModuleInfo) { + if (isSubPathOf(filePath, moduleRootPath)) { + return InteropInfo.declgenBridgeCodePath; + } + } + + return undefined; +} + +export function destroyInterop(): void { + FileManager.cleanFileManagerObject(); + entryFileLanguageInfo.clear(); + mixCompile = false; +} + diff --git a/compiler/src/interop/src/fast_build/ark_compiler/interop/pre_define.ts b/compiler/src/interop/src/fast_build/ark_compiler/interop/pre_define.ts index eaa908d41..82aaebb55 100644 --- a/compiler/src/interop/src/fast_build/ark_compiler/interop/pre_define.ts +++ b/compiler/src/interop/src/fast_build/ark_compiler/interop/pre_define.ts @@ -16,4 +16,11 @@ export const ARKTS_1_2: string = '1.2'; export const ARKTS_1_1: string = '1.1'; export const ARKTS_1_0: string = '1.0'; -export const ARKTS_HYBRID: string = 'hybrid'; \ No newline at end of file +export const ARKTS_HYBRID: string = 'hybrid'; + +export const DECLGEN_CACHE_FILE = 'declgen_cache.json'; + +export enum ARKTS_MODE { + STATIC = 'static', + DYNAMIC = 'dynamic' +} \ No newline at end of file diff --git a/compiler/src/interop/src/fast_build/ark_compiler/interop/type.ts b/compiler/src/interop/src/fast_build/ark_compiler/interop/type.ts index 3a3dc2a11..cb4b3a29e 100644 --- a/compiler/src/interop/src/fast_build/ark_compiler/interop/type.ts +++ b/compiler/src/interop/src/fast_build/ark_compiler/interop/type.ts @@ -112,4 +112,13 @@ export interface FileInfo { baseUrl: string; abstractPath: string; } -export const DECLGEN_CACHE_FILE = 'declgen_cache.json'; + +export interface InteropInfo { + declgenBridgeCodePath: string; + declgenV1OutPath: string; +} + +export interface InteropConfig { + interopModuleInfo: Map; + projectConfig: Object; +} diff --git a/compiler/src/interop/src/fast_build/ark_compiler/interop/utils.ts b/compiler/src/interop/src/fast_build/ark_compiler/interop/utils.ts new file mode 100644 index 000000000..757c30f8d --- /dev/null +++ b/compiler/src/interop/src/fast_build/ark_compiler/interop/utils.ts @@ -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. + */ + +import fs from 'fs'; + +export function readFirstLineSync(filePath: string): string { + const buffer = fs.readFileSync(filePath, 'utf-8'); + const newlineIndex = buffer.indexOf('\n'); + if (newlineIndex === -1) { + return buffer.trim(); + } + return buffer.substring(0, newlineIndex).trim(); +} \ No newline at end of file diff --git a/compiler/test/ark_compiler_ut/interop/interop_manager.test.ts b/compiler/test/ark_compiler_ut/interop/interop_manager.test.ts new file mode 100644 index 000000000..5f3569ad7 --- /dev/null +++ b/compiler/test/ark_compiler_ut/interop/interop_manager.test.ts @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2025 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 path from "path"; + +import { + FileManager, + collectSDKInfo, + isBridgeCode, + getBrdigeCodeRootPath, + isMixCompile, + initConfigForInterop, + destroyInterop, + transformModuleNameToRelativePath + } from '../../../lib/fast_build/ark_compiler/interop/interop_manager'; +import { ARKTS_1_1, ARKTS_1_2, ARKTS_HYBRID } from '../../../lib/fast_build/ark_compiler/interop/pre_define'; +import { sdkConfigs } from '../../../main'; +import { toUnixPath } from '../../../lib/utils'; +import RollUpPluginMock from '../mock/rollup_mock/rollup_plugin_mock'; + +export interface ArkTSEvolutionModule { + language: string; + packageName: string; + moduleName: string; + modulePath: string; + declgenV1OutPath?: string; + declgenV2OutPath?: string; + declgenBridgeCodePath?: string; + declFilesPath?: string; + dynamicFiles: string[]; + staticFiles: string[]; + cachePath: string; + byteCodeHarInfo?: Object; +} + +mocha.describe('test interop_manager file api', function () { + mocha.before(function () { + const dependentModuleMap: Map = new Map(); + const dynamicSDKPath: Set = new Set([ + '/sdk/default/openharmony/ets/ets1.1/api', + '/sdk/default/openharmony/ets/ets1.1/arkts', + '/sdk/default/openharmony/ets/ets1.1/kits', + '/sdk/default/openharmony/ets/ets1.1/build-tools/ets-loader/declarations', + '/sdk/default/openharmony/ets/ets1.1/build-tools/ets-loader/component', + '/sdk/default/openharmony/ets/ets1.1/build-tools/components' + ]); + const staticSDKDeclPath: Set = new Set([ + '/sdk/default/openharmony/ets/ets1.2interop/declarations/kit', + '/sdk/default/openharmony/ets/ets1.2interop/declarations/api', + '/sdk/default/openharmony/ets/ets1.2interop/declarations/arkts' + ]); + const staticSDKGlueCodePath: Set = new Set([ + '/sdk/default/openharmony/ets/ets1.2interop/bridge/kit', + '/sdk/default/openharmony/ets/ets1.2interop/bridge/api', + '/sdk/default/openharmony/ets/ets1.2interop/bridge/arkts' + ]); + dependentModuleMap.set('application', { + language: ARKTS_1_1, + packageName: 'application', + moduleName: 'application', + modulePath: '/MyApplication16/application', + declgenV1OutPath: '/MyApplication16/application/build/default/intermediates/declgen/default/declgenV1', + declgenV2OutPath: '/MyApplication16/application/build/default/intermediates/declgen/default/declgenV2', + declgenBridgeCodePath: '/MyApplication16/application/build/default/intermediates/declgen/default/declgenBridgeCode', + declFilesPath: '/MyApplication16/application/build/default/intermediates/declgen/default/decl-fileInfo.json', + dynamicFiles: [], + staticFiles: [], + cachePath: '/MyApplication16/application/build/cache', + byteCodeHarInfo: {} + }); + + dependentModuleMap.set('harv2', { + language: ARKTS_1_2, + packageName: 'harv2', + moduleName: 'harv2', + modulePath: '/MyApplication16/harv2', + declgenV1OutPath: '/MyApplication16/harv2/build/default/intermediates/declgen/default/declgenV1', + declgenV2OutPath: '/MyApplication16/harv2/build/default/intermediates/declgen/default/declgenV2', + declgenBridgeCodePath: '/MyApplication16/harv2/build/default/intermediates/declgen/default/declgenBridgeCode', + declFilesPath: '/MyApplication16/harv2/build/default/intermediates/declgen/default/decl-fileInfo.json', + dynamicFiles: [], + staticFiles: [], + cachePath: '/MyApplication16/harv2/build/cache', + byteCodeHarInfo: {} + }); + + dependentModuleMap.set('dynamic1', { + language: ARKTS_1_1, + packageName: 'dynamic1', + moduleName: 'dynamic1', + modulePath: '/MyApplication16/dynamic1', + declgenV1OutPath: '/MyApplication16/dynamic1/build/default/intermediates/declgen/default/declgenV1', + declgenV2OutPath: '/MyApplication16/dynamic1/build/default/intermediates/declgen/default/declgenV2', + declgenBridgeCodePath: '/MyApplication16/dynamic1/build/default/intermediates/declgen/default/declgenBridgeCode', + declFilesPath: '/MyApplication16/dynamic1/build/default/intermediates/declgen/default/decl-fileInfo.json', + dynamicFiles: [], + staticFiles: [], + cachePath: '/MyApplication16/dynamic1/build/cache', + byteCodeHarInfo: {} + }); + + dependentModuleMap.set('hybrid', { + language: ARKTS_HYBRID, + packageName: 'hybrid', + moduleName: 'hybrid', + modulePath: '/MyApplication16/hybrid', + declgenV1OutPath: '/MyApplication16/hybrid/build/default/intermediates/declgen/default/declgenV1', + declgenV2OutPath: '/MyApplication16/hybrid/build/default/intermediates/declgen/default/declgenV2', + declgenBridgeCodePath: '/MyApplication16/hybrid/build/default/intermediates/declgen/default/declgenBridgeCode', + declFilesPath: '/MyApplication16/hybrid/build/default/intermediates/declgen/default/decl-fileInfo.json', + dynamicFiles: ['/MyApplication16/hybrid/fileV1.ets'], + staticFiles: ['/MyApplication16/hybrid/fileV2.ets'], + cachePath: '/MyApplication16/hybrid/build/cache', + byteCodeHarInfo: {} + }); + FileManager.cleanFileManagerObject(); + FileManager.initForTest( + dependentModuleMap, + undefined, + dynamicSDKPath, + staticSDKDeclPath, + staticSDKGlueCodePath); + }); + + mocha.after(() => { + FileManager.cleanFileManagerObject(); + }); + + mocha.it('1-1: test SDK path', function() { + const filePath = '/sdk/default/openharmony/ets/ets1.1/api/TestAPI.ets'; + const result = FileManager.getInstance().getLanguageVersionByFilePath(filePath); + expect(result?.languageVersion).to.equal(ARKTS_1_1); + expect(result?.pkgName).to.equal('SDK'); + }); + + mocha.it('1-2: test ets-loader/declarations path', function() { + const filePath = '/sdk/default/openharmony/ets/ets1.1/build-tools/ets-loader/declarations/TestAPI.ets'; + const result = FileManager.getInstance().getLanguageVersionByFilePath(filePath); + expect(result?.languageVersion).to.equal(ARKTS_1_1); + expect(result?.pkgName).to.equal('SDK'); + }); + + mocha.it('1-3: test ets-loader/component path', function() { + const filePath = '/sdk/default/openharmony/ets/ets1.1/build-tools/ets-loader/component/TestAPI.d.ts'; + const result = FileManager.getInstance().getLanguageVersionByFilePath(filePath); + expect(result?.languageVersion).to.equal(ARKTS_1_1); + expect(result?.pkgName).to.equal('SDK'); + }); + + mocha.it('1-4: test SDK glue code path', function() { + const filePath = '/sdk/default/openharmony/ets/ets1.2interop/bridge/arkts/TestAPI.d.ts'; + const result = FileManager.getInstance().getLanguageVersionByFilePath(filePath); + expect(result?.languageVersion).to.equal(ARKTS_1_2); + expect(result?.pkgName).to.equal('SDK'); + }); + + mocha.it('1-5: test SDK interop decl path', function() { + const filePath = '/sdk/default/openharmony/ets/ets1.2interop/declarations/kit/TestAPI.d.ts'; + const result = FileManager.getInstance().getLanguageVersionByFilePath(filePath); + expect(result?.languageVersion).to.equal(ARKTS_1_2); + expect(result?.pkgName).to.equal('SDK'); + }); + + mocha.it('1-6: test source code from 1.1 module', function() { + const filePath = '/MyApplication16/application/sourceCode.ets'; + const result = FileManager.getInstance().getLanguageVersionByFilePath(filePath); + expect(result?.languageVersion).to.equal(ARKTS_1_1); + expect(result?.pkgName).to.equal('application'); + }); + + mocha.it('1-7: test glue code file from 1.2 module', function() { + const filePath = '/MyApplication16/harv2/build/default/intermediates/declgen/default/declgenBridgeCode/sourceCode.ets'; + const result = FileManager.getInstance().getLanguageVersionByFilePath(filePath); + expect(result?.languageVersion).to.equal(ARKTS_1_2); + expect(result?.pkgName).to.equal('harv2'); + }); + + mocha.it('1-8: test decl file from 1.2 module', function() { + const filePath = '/MyApplication16/harv2/build/default/intermediates/declgen/default/declgenV1/sourceCode.ets'; + const result = FileManager.getInstance().getLanguageVersionByFilePath(filePath); + expect(result?.languageVersion).to.equal(ARKTS_1_2); + expect(result?.pkgName).to.equal('harv2'); + }); + + mocha.it('1-9: test source code file from hybrid module', function() { + const filePath = '/MyApplication16/hybrid/fileV1.ets'; + const result = FileManager.getInstance().getLanguageVersionByFilePath(filePath); + expect(result?.languageVersion).to.equal(ARKTS_1_1); + expect(result?.pkgName).to.equal('hybrid'); + }); + + mocha.it('1-10: test source code file from hybrid module', function() { + const filePath = '/MyApplication16/hybrid/build/default/intermediates/declgen/default/declgenV1/file1'; + const result = FileManager.getInstance().getLanguageVersionByFilePath(filePath); + expect(result?.languageVersion).to.equal(ARKTS_1_2); + expect(result?.pkgName).to.equal('hybrid'); + }); + + mocha.it('2-1: test matchModulePath api with 1.1 module', function() { + const filePath = '/MyApplication16/dynamic1/sourceCode.ets'; + const moduleInfo = FileManager.matchModulePath(filePath); + expect(moduleInfo.languageVersion).to.equal(ARKTS_1_1); + expect(moduleInfo.pkgName).to.equal('dynamic1'); + }) + + mocha.it('2-2: test matchModulePath api with 1.2 module', function() { + const filePath = '/MyApplication16/harv2/sourceCode.ets'; + const moduleInfo = FileManager.matchModulePath(filePath); + expect(moduleInfo.languageVersion).to.equal(ARKTS_1_2); + expect(moduleInfo.pkgName).to.equal('harv2'); + }) + + mocha.it('2-3: test matchModulePath api with isHybrid module', function() { + const dymanicFilePath = '/MyApplication16/hybrid/fileV1.ets'; + const staticFilePath = '/MyApplication16/hybrid/fileV2.ets'; + + const moduleInfoV1 = FileManager.matchModulePath(dymanicFilePath); + expect(moduleInfoV1.languageVersion).to.equal(ARKTS_1_1); + expect(moduleInfoV1.pkgName).to.equal('hybrid'); + + const moduleInfoV2 = FileManager.matchModulePath(staticFilePath); + expect(moduleInfoV2.languageVersion).to.equal(ARKTS_1_2); + expect(moduleInfoV2.pkgName).to.equal('hybrid'); + }) + + mocha.it('3-1: test init SDK', function () { + const share = { + projectConfig: { + etsLoaderPath: '/mock/ets-loader', + } + }; + + const result = collectSDKInfo(share); + const expectedDynamicSDKPath = new Set([ + '/mock/ets-loader/declarations', + '/mock/ets-loader/components', + '/component', + '/mock/ets-loader' + ]); + sdkConfigs.forEach(({ apiPath }) => { + apiPath.forEach(path => { + expectedDynamicSDKPath.add(toUnixPath(path)); + }); + }); + const expectedStaticInteropDecl = new Set([ + '/ets1.2/build-tools/interop/declarations/kits', + '/ets1.2/build-tools/interop/declarations/api', + '/ets1.2/build-tools/interop/declarations/arkts' + ]); + + const expectedStaticGlueCode = new Set([ + '/ets1.2/build-tools/interop/bridge/kits', + '/ets1.2/build-tools/interop/bridge/api', + '/ets1.2/build-tools/interop/bridge/arkts' + ]); + expect([...result.dynamicSDKPath]).to.have.deep.members([...expectedDynamicSDKPath]); + expect([...result.staticSDKInteropDecl]).to.have.deep.members([...expectedStaticInteropDecl]); + expect([...result.staticSDKGlueCodePath]).to.have.deep.members([...expectedStaticGlueCode]); + }); +}); + +mocha.describe('isBridgeCode', function () { + const mockConfig = { + mixCompile: true, + dependentModuleMap: new Map([ + ['pkgA', { declgenBridgeCodePath: path.resolve('project/bridge/pkgA') }], + ['pkgB', { declgenBridgeCodePath: path.resolve('project/bridge/pkgB') }], + ]), + }; + + mocha.it('1-1: should return true when filePath is inside a declgenBridgeCodePath', function () { + const filePath = path.resolve('project/bridge/pkgA/utils/helper.ts'); + expect(isBridgeCode(filePath, mockConfig)).to.be.true; + }); + + mocha.it('1-2: should return false when filePath is outside all bridge code paths', function () { + const filePath = path.resolve('project/otherpkg/index.ts'); + expect(isBridgeCode(filePath, mockConfig)).to.be.false; + }); + + mocha.it('1-3: should return false when mixCompile is false', function () { + const config = { ...mockConfig, mixCompile: false }; + const filePath = path.resolve('project/bridge/pkgA/utils/helper.ts'); + expect(isBridgeCode(filePath, config)).to.be.false; + }); + + mocha.it('1-4: should return false when dependentModuleMap is empty', function () { + const config = { mixCompile: true, dependentModuleMap: new Map() }; + const filePath = path.resolve('project/bridge/pkgA/file.ts'); + expect(isBridgeCode(filePath, config)).to.be.false; + }); + + mocha.it('1-5: should return true for multiple matches, stop at first match', function () { + const config = { + mixCompile: true, + dependentModuleMap: new Map([ + ['pkg1', { declgenBridgeCodePath: path.resolve('path/one') }], + ['pkg2', { declgenBridgeCodePath: path.resolve('path/two') }], + ]), + }; + const filePath = path.resolve('path/one/module.ts'); + expect(isBridgeCode(filePath, config)).to.be.true; + }); +}); + +mocha.describe('test getBrdigeCodeRootPath api', function () { + mocha.it('1-1: should return bridgeCodePath from interopConfig when filePath matches moduleRootPath', function () { + const filePath = '/a/b/c/file.ts'; + const mockConfig: InteropConfig = { + mixCompile: false, + interopModuleInfo: new Map([ + ['/a/b', { + declgenBridgeCodePath: '/bridge/a/b', + declgenV1OutPath: '/v1' + }] + ]) + }; + + const result = getBrdigeCodeRootPath(filePath, mockConfig); + expect(result).to.equal('/bridge/a/b'); + }); + + mocha.it('1-2: should return undefined when filePath does not match any moduleRootPath', function () { + const filePath = '/x/y/z/file.ts'; + const mockConfig: InteropConfig = { + mixCompile: false, + interopModuleInfo: new Map([ + ['/a/b', { + declgenBridgeCodePath: '/bridge/a/b', + declgenV1OutPath: '/v1' + }] + ]) + }; + + const result = getBrdigeCodeRootPath(filePath, mockConfig); + expect(result).to.be.undefined; + }); + + mocha.it('1-3: should return process.env.entryBridgeCodePath when interopConfig is null', function () { + process.env.entryBridgeCodePath = '/default/bridge/path'; + const filePath = '/any/file.ts'; + + const result = getBrdigeCodeRootPath(filePath, undefined as any); + expect(result).to.equal('/default/bridge/path'); + }); +}); + +mocha.describe('test mixCompile', function () { + mocha.it('1-1 test mixCompile is false', function () { + expect(isMixCompile()).to.be.false; + }) + + mocha.it('1-2 test mixCompile is true', function () { + this.rollup = new RollUpPluginMock(); + this.rollup.build(); + this.rollup.share.projectConfig.mixCompile = true; + initConfigForInterop(this.rollup.share); + expect(isMixCompile()).to.be.true; + }) + + mocha.it('1-3 test mixCompile is false when destroy interop', function () { + this.rollup = new RollUpPluginMock(); + this.rollup.build(); + this.rollup.share.projectConfig.mixCompile = true; + initConfigForInterop(this.rollup.share); + destroyInterop() + expect(isMixCompile()).to.be.false; + }) +}) + +mocha.describe('test transformModuleNameToRelativePath api', function () { + mocha.before(function () { + this.rollup = new RollUpPluginMock(); + this.rollup.build(); + this.rollup.share.projectConfig.mixCompile = true; + initConfigForInterop(this.rollup.share); + }); + + mocha.it('1-1 test transformModuleNameToRelativePath when compile common module', function () { + this.rollup.share.projectConfig.isOhosTest = false; + + const moduleName = '/a/b/c/src/main/ets/module/file.ets'; + const result = transformModuleNameToRelativePath(moduleName); + + expect(result).to.equal('./ets/module/file.ets'); + }); + + mocha.it('1-2 test transformModuleNameToRelativePath when compile ohostest', function () { + this.rollup.share.projectConfig.isOhosTest = true; + initConfigForInterop(this.rollup.share); + const moduleName = '/a/b/c/src/ohosTest/ets/module/testfile.ets'; + const result = transformModuleNameToRelativePath(moduleName); + + expect(result).to.equal('./ets/module/testfile.ets'); + }); + + mocha.it('1-3 test transformModuleNameToRelativePath throws when sourceRoot not in path', function () { + this.rollup.share.projectConfig.isOhosTest = false; + + const invalidModuleName = '/a/b/c/invalidroot/ets/module/file.ets'; + + expect(() => transformModuleNameToRelativePath(invalidModuleName)).to.throw(Error); + }); + + mocha.after(() => { + delete this.rollup; + }); +}) diff --git a/compiler/test/ark_compiler_ut/interop/process_arkts_evolution.test.ts b/compiler/test/ark_compiler_ut/interop/process_arkts_evolution.test.ts new file mode 100644 index 000000000..6119d6bd3 --- /dev/null +++ b/compiler/test/ark_compiler_ut/interop/process_arkts_evolution.test.ts @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2025 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 sinon from 'sinon'; + +import { + collectArkTSEvolutionModuleInfo, + addDeclFilesConfig, + pkgDeclFilesConfig, + arkTSModuleMap +} from '../../../lib/fast_build/ark_compiler/interop/process_arkts_evolution'; +import RollUpPluginMock from '../mock/rollup_mock/rollup_plugin_mock'; +import { + BUNDLE_NAME_DEFAULT, + HAR_DECLGENV2OUTPATH +} from '../mock/rollup_mock/common'; +import { CommonLogger } from '../../../lib/fast_build/ark_compiler/logger'; +import { ErrorCode } from '../../../lib/fast_build/ark_compiler/error_code'; + +mocha.describe('process arkts evolution tests', function () { + mocha.before(function () { + this.rollup = new RollUpPluginMock(); + }); + + mocha.after(() => { + delete this.rollup; + }); + + mocha.it('1-1: test error message of collectArkTSEvolutionModuleInfo (useNormalizedOHMUrl is false)', function () { + this.rollup.build(); + this.rollup.share.projectConfig.useNormalizedOHMUrl = false; + this.rollup.share.projectConfig.dependentModuleMap.set('evohar', { language: '1.2' }); + const throwArkTsCompilerErrorStub = sinon.stub(CommonLogger.getInstance(this.rollup), 'printErrorAndExit'); + try { + collectArkTSEvolutionModuleInfo(this.rollup.share); + } catch (e) { + } + expect(throwArkTsCompilerErrorStub.getCall(0).args[0].code === ErrorCode.ETS2BUNDLE_EXTERNAL_COLLECT_INTEROP_INFO_FAILED).to.be.true; + throwArkTsCompilerErrorStub.restore(); + }); + + mocha.it('1-2: test error message of collectArkTSEvolutionModuleInfo (1.2 module information is incorrect)', function () { + this.rollup.build(); + this.rollup.share.projectConfig.useNormalizedOHMUrl = true; + this.rollup.share.projectConfig.dependentModuleMap.set('evohar', { language: '1.2' }); + const throwArkTsCompilerErrorStub = sinon.stub(this.rollup.share, 'throwArkTsCompilerError'); + try { + collectArkTSEvolutionModuleInfo(this.rollup.share); + } catch(e) { + } + const errMsg: string = 'ArkTS:INTERNAL ERROR: Failed to collect arkTs evolution module info.\n' + + `Error Message: Failed to collect arkTs evolution module "evohar" info from rollup.`; + expect(throwArkTsCompilerErrorStub.getCall(0).args[1] === errMsg).to.be.true; + throwArkTsCompilerErrorStub.restore(); + }); + + mocha.it('1-3: test error message of collectArkTSEvolutionModuleInfo (1.1 module information is incorrect)', function () { + this.rollup.build(); + this.rollup.share.projectConfig.useNormalizedOHMUrl = true; + this.rollup.share.projectConfig.dependentModuleMap.set('har', { language: '1.1' }); + const throwArkTsCompilerErrorStub = sinon.stub(this.rollup.share, 'throwArkTsCompilerError'); + try { + collectArkTSEvolutionModuleInfo(this.rollup.share); + } catch(e) { + } + const errMsg: string = 'ArkTS:INTERNAL ERROR: Failed to collect arkTs evolution module info.\n' + + `Error Message: Failed to collect arkTs evolution module "har" info from rollup.`; + expect(throwArkTsCompilerErrorStub.getCall(0).args[1] === errMsg).to.be.true; + throwArkTsCompilerErrorStub.restore(); + }); + + mocha.it('2-1: test generate declFilesInfo in mixed compilation', function () { + pkgDeclFilesConfig['har'] = { + packageName: 'har', + files: {} + }; + const filePath = '/har/Index.ets' + const projectConfig = { + mainModuleName: 'entry', + bundleName: BUNDLE_NAME_DEFAULT, + pkgContextInfo: { + 'har': { + packageName: 'har', + version: '1.0.0', + isSO: false + } + } + } + arkTSModuleMap.set('har', { + language: '1.1', + pkgName: 'har', + declgenV2OutPath: HAR_DECLGENV2OUTPATH + }) + addDeclFilesConfig(filePath, projectConfig, undefined, '/har', 'har'); + const expectDeclPath: string = `${HAR_DECLGENV2OUTPATH}/Index.d.ets`; + const expectOhmUrl: string = `@normalized:N&entry&${BUNDLE_NAME_DEFAULT}&har/Index&1.0.0`; + expect(pkgDeclFilesConfig['har'].files.length !== 0).to.be.true; + expect(pkgDeclFilesConfig['har'].files['Index'].length !== 0).to.be.true; + expect(pkgDeclFilesConfig['har'].files['Index'].declPath === expectDeclPath).to.be.true; + expect(pkgDeclFilesConfig['har'].files['Index'].ohmUrl === expectOhmUrl).to.be.true; + arkTSModuleMap.clear(); + }); +}); \ No newline at end of file -- Gitee From ae9818a80a3d2495635699601b8a5e8a4d754938 Mon Sep 17 00:00:00 2001 From: liyancheng2 Date: Thu, 14 Aug 2025 23:15:48 +0800 Subject: [PATCH 04/31] fix the incremental compilation of types option Issue: https://gitee.com/openharmony/developtools_ace_ets2bundle/issues/ICT1ET Signed-off-by: liyancheng2 Change-Id: Ie74cbc8b0247476d1ef19880091c0931519d2bb4 --- compiler/src/ets_checker.ts | 41 +++++++-- compiler/src/interop/src/ets_checker.ts | 37 ++++++-- .../test/ark_compiler_ut/ets_checker.test.ts | 88 ++++++++++++++++++- 3 files changed, 151 insertions(+), 15 deletions(-) diff --git a/compiler/src/ets_checker.ts b/compiler/src/ets_checker.ts index 716d75244..85857608e 100644 --- a/compiler/src/ets_checker.ts +++ b/compiler/src/ets_checker.ts @@ -110,6 +110,7 @@ export interface LanguageServiceCache { service?: ts.LanguageService; pkgJsonFileHash?: string; targetESVersion?: ts.ScriptTarget; + types?: string[]; maxFlowDepth?: number; preTsImportSendable?: boolean; preSkipOhModulesLint?: boolean; @@ -437,30 +438,34 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi let service: ts.LanguageService | undefined = cache?.service; const currentHash: string | undefined = rollupShareObject?.projectConfig?.pkgJsonFileHash; const currentTargetESVersion: ts.ScriptTarget = compilerOptions.target; + const currentTypes: string[] | undefined = compilerOptions.types; const currentMaxFlowDepth: number | undefined = compilerOptions.maxFlowDepth; const lastHash: string | undefined = cache?.pkgJsonFileHash; const lastTargetESVersion: ts.ScriptTarget | undefined = cache?.targetESVersion; + const lastTypes: string[] | undefined = cache?.types; const lastMaxFlowDepth: number | undefined = cache?.maxFlowDepth; const hashDiffers: boolean | undefined = currentHash && lastHash && currentHash !== lastHash; const shouldRebuildForDepDiffers: boolean | undefined = reuseLanguageServiceForDepChange ? (hashDiffers && !rollupShareObject?.depInfo?.enableIncre) : hashDiffers; const targetESVersionDiffers: boolean | undefined = lastTargetESVersion && currentTargetESVersion && lastTargetESVersion !== currentTargetESVersion; + const typesDiff: boolean | undefined = !areEqualArrays(lastTypes, currentTypes); const maxFlowDepthDiffers: boolean | undefined = lastMaxFlowDepth && currentMaxFlowDepth && lastMaxFlowDepth !== currentMaxFlowDepth; const tsImportSendableDiff: boolean = (cache?.preTsImportSendable === undefined && !tsImportSendable) ? false : cache?.preTsImportSendable !== tsImportSendable; - const skipOhModulesLintDiff: boolean = (cache?.preSkipOhModulesLint === undefined && !skipOhModulesLint) ? + const skipOhModulesLintDiff: boolean = (cache?.preSkipOhModulesLint === undefined && !skipOhModulesLint) ? false : cache?.preSkipOhModulesLint !== skipOhModulesLint; - const mixCompileDiff: boolean = (cache?.preMixCompile === undefined && !mixCompile) ? + const mixCompileDiff: boolean = (cache?.preMixCompile === undefined && !mixCompile) ? false : cache?.preMixCompile !== mixCompile; const shouldRebuild: boolean | undefined = shouldRebuildForDepDiffers || targetESVersionDiffers || - tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; + tsImportSendableDiff || typesDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; + const onlyDeleteBuildInfoCache: boolean | undefined = tsImportSendableDiff || typesDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; if (reuseLanguageServiceForDepChange && hashDiffers && rollupShareObject?.depInfo?.enableIncre) { needReCheckForChangedDepUsers = true; } if (!service || shouldRebuild) { - rebuildProgram(targetESVersionDiffers, tsImportSendableDiff, maxFlowDepthDiffers, skipOhModulesLintDiff, mixCompileDiff); + rebuildProgram(targetESVersionDiffers, onlyDeleteBuildInfoCache); service = ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); } else { // Found language service from cache, update root files @@ -472,6 +477,7 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi service: service, pkgJsonFileHash: currentHash, targetESVersion: currentTargetESVersion, + types: currentTypes, maxFlowDepth: currentMaxFlowDepth, preTsImportSendable: tsImportSendable, preSkipOhModulesLint: skipOhModulesLint, @@ -481,14 +487,33 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi return service; } -function rebuildProgram(targetESVersionDiffers: boolean | undefined, tsImportSendableDiff: boolean, - maxFlowDepthDiffers: boolean | undefined, skipOhModulesLintDiff: boolean, mixCompileDiff: boolean): void { +export function areEqualArrays(lastArray: string[] | undefined, currentArray: string[] | undefined): boolean { + if (!lastArray || !currentArray) { + return lastArray === currentArray; + } + + const currentSet = new Set(currentArray); + const lastSet = new Set(lastArray); + + if (lastSet.size !== currentSet.size) { + return false; + } + + for (const item of lastSet) { + if (!currentSet.has(item)) { + return false; + } + } + return true; +} + +function rebuildProgram(targetESVersionDiffers: boolean | undefined, onlyDeleteBuildInfoCache: boolean | undefined): void { if (targetESVersionDiffers) { // If the targetESVersion is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); targetESVersionChanged = true; - } else if (tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff) { - // When tsImportSendable or maxFlowDepth is changed, we need to delete the build info cahce files + } else if (onlyDeleteBuildInfoCache) { + // When tsImportSendable or types or maxFlowDepth or skipOhModuleslint or mixCompile is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); } } diff --git a/compiler/src/interop/src/ets_checker.ts b/compiler/src/interop/src/ets_checker.ts index e1d5381b3..fe11635c6 100644 --- a/compiler/src/interop/src/ets_checker.ts +++ b/compiler/src/interop/src/ets_checker.ts @@ -123,6 +123,7 @@ export interface LanguageServiceCache { service?: ts.LanguageService; pkgJsonFileHash?: string; targetESVersion?: ts.ScriptTarget; + types?: string[]; maxFlowDepth?: number; preTsImportSendable?: boolean; preSkipOhModulesLint?: boolean; @@ -457,14 +458,17 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi let service: ts.LanguageService | undefined = cache?.service; const currentHash: string | undefined = rollupShareObject?.projectConfig?.pkgJsonFileHash; const currentTargetESVersion: ts.ScriptTarget = compilerOptions.target; + const currentTypes: string[] | undefined = compilerOptions.types; const currentMaxFlowDepth: number | undefined = compilerOptions.maxFlowDepth; const lastHash: string | undefined = cache?.pkgJsonFileHash; const lastTargetESVersion: ts.ScriptTarget | undefined = cache?.targetESVersion; + const lastTypes: string[] | undefined = cache?.types; const lastMaxFlowDepth: number | undefined = cache?.maxFlowDepth; const hashDiffers: boolean | undefined = currentHash && lastHash && currentHash !== lastHash; const shouldRebuildForDepDiffers: boolean | undefined = reuseLanguageServiceForDepChange ? (hashDiffers && !rollupShareObject?.depInfo?.enableIncre) : hashDiffers; const targetESVersionDiffers: boolean | undefined = lastTargetESVersion && currentTargetESVersion && lastTargetESVersion !== currentTargetESVersion; + const typesDiff: boolean | undefined = !areEqualArrays(lastTypes, currentTypes); const maxFlowDepthDiffers: boolean | undefined = lastMaxFlowDepth && currentMaxFlowDepth && lastMaxFlowDepth !== currentMaxFlowDepth; const tsImportSendableDiff: boolean = (cache?.preTsImportSendable === undefined && !tsImportSendable) ? false : @@ -474,13 +478,14 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi const mixCompileDiff: boolean = (cache?.preMixCompile === undefined && !mixCompile) ? false : cache?.preMixCompile !== mixCompile; const shouldRebuild: boolean | undefined = shouldRebuildForDepDiffers || targetESVersionDiffers || - tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; + tsImportSendableDiff || typesDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; + const onlyDeleteBuildInfoCache: boolean | undefined = tsImportSendableDiff || typesDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; if (reuseLanguageServiceForDepChange && hashDiffers && rollupShareObject?.depInfo?.enableIncre) { needReCheckForChangedDepUsers = true; } if (!service || shouldRebuild) { - rebuildProgram(targetESVersionDiffers, tsImportSendableDiff, maxFlowDepthDiffers, skipOhModulesLintDiff, mixCompileDiff); + rebuildProgram(targetESVersionDiffers, onlyDeleteBuildInfoCache); service = ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); } else { // Found language service from cache, update root files @@ -492,6 +497,7 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi service: service, pkgJsonFileHash: currentHash, targetESVersion: currentTargetESVersion, + types: currentTypes, maxFlowDepth: currentMaxFlowDepth, preTsImportSendable: tsImportSendable, preSkipOhModulesLint: skipOhModulesLint, @@ -501,14 +507,33 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi return service; } -function rebuildProgram(targetESVersionDiffers: boolean | undefined, tsImportSendableDiff: boolean, - maxFlowDepthDiffers: boolean | undefined, skipOhModulesLintDiff: boolean, mixCompileDiff: boolean): void { +export function areEqualArrays(lastArray: string[] | undefined, currentArray: string[] | undefined): boolean { + if (!lastArray || !currentArray) { + return lastArray === currentArray; + } + + const currentSet = new Set(currentArray); + const lastSet = new Set(lastArray); + + if (lastSet.size !== currentSet.size) { + return false; + } + + for (const item of lastSet) { + if (!currentSet.has(item)) { + return false; + } + } + return true; +} + +function rebuildProgram(targetESVersionDiffers: boolean | undefined, onlyDeleteBuildInfoCache: boolean | undefined): void { if (targetESVersionDiffers) { // If the targetESVersion is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); targetESVersionChanged = true; - } else if (tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff) { - // When tsImportSendable or maxFlowDepth is changed, we need to delete the build info cahce files + } else if (onlyDeleteBuildInfoCache) { + // When tsImportSendable or types or maxFlowDepth or skipOhModuleslint or mixCompile is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); } } diff --git a/compiler/test/ark_compiler_ut/ets_checker.test.ts b/compiler/test/ark_compiler_ut/ets_checker.test.ts index 17d258b70..4a1785e74 100644 --- a/compiler/test/ark_compiler_ut/ets_checker.test.ts +++ b/compiler/test/ark_compiler_ut/ets_checker.test.ts @@ -36,6 +36,7 @@ import { resetEtsCheck, serviceChecker, resolveModuleNames as resolveModuleNamesMain, + areEqualArrays, getMaxFlowDepth, MAX_FLOW_DEPTH_DEFAULT_VALUE, fileCache, @@ -204,6 +205,91 @@ mocha.describe('test ets_checker file api', function () { }); }); +mocha.describe('test areEqualArrays function', () => { + // test cases for basic functions + mocha.it('1-1: should return true for identical arrays', () => { + expect(areEqualArrays(['a', 'b', 'c'], ['a', 'b', 'c'])).to.equal(true); + }); + + mocha.it('1-2: should return true for arrays with same elements in different order', () => { + expect(areEqualArrays(['a', 'b', 'c'], ['c', 'a', 'b'])).to.equal(true); + }); + + mocha.it('1-3: should return false for arrays with different elements', () => { + expect(areEqualArrays(['a', 'b', 'c'], ['a', 'b', 'd'])).to.equal(false); + }); + + mocha.it('1-4: should return false for arrays with different lengths', () => { + expect(areEqualArrays(['a', 'b', 'c'], ['a', 'b'])).to.equal(false); + expect(areEqualArrays(['a', 'b'], ['a', 'b', 'c'])).to.equal(false); + }); + + // test cases for boundary conditions + mocha.it('1-5: should return true for empty arrays', () => { + expect(areEqualArrays([], [])).to.equal(true); + }); + + mocha.it('1-6: should return false when one array is empty and other is not', () => { + expect(areEqualArrays([], ['a'])).to.equal(false); + expect(areEqualArrays(['a'], [])).to.equal(false); + }); + + // test cases for null and undefined scenarios + mocha.it('1-7: should return true when both arrays are undefined', () => { + expect(areEqualArrays(undefined, undefined)).to.equal(true); + }); + + mocha.it('1-8: should return true when both arrays are null', () => { + expect(areEqualArrays(null as any, null as any)).to.equal(true); + }); + + mocha.it('1-9: should return false when one array is undefined and other is not', () => { + expect(areEqualArrays(undefined, ['a'])).to.equal(false); + expect(areEqualArrays(['a'], undefined)).to.equal(false); + }); + + mocha.it('1-10: should return false when one array is null and other is not', () => { + expect(areEqualArrays(null as any, ['a'])).to.equal(false); + expect(areEqualArrays(['a'], null as any)).to.equal(false); + }); + + // test cases for duplicate elements + mocha.it('1-11: should handle duplicate elements correctly', () => { + expect(areEqualArrays(['a', 'a', 'b'], ['a', 'b', 'a'])).to.equal(true); + expect(areEqualArrays(['a', 'a', 'b'], ['a', 'b', 'b'])).to.equal(true); + }); + + // test case sensitivity scenarios + mocha.it('1-12: should be case sensitive', () => { + expect(areEqualArrays(['A', 'B'], ['a', 'b'])).to.equal(false); + expect(areEqualArrays(['A', 'B'], ['A', 'B'])).to.equal(true); + }); + + // test cases for special value scenarios + mocha.it('1-13: should handle special values', () => { + expect(areEqualArrays(['', 'null'], ['', 'null'])).to.equal(true); + expect(areEqualArrays(['0', '1'], ['0', '1'])).to.equal(true); + }); + + // test cases for performance + mocha.it('1-14: should handle large arrays efficiently', () => { + const largeArray1 = Array(10000).fill('item'); + const largeArray2 = Array(10000).fill('item'); + + expect(areEqualArrays(largeArray1, largeArray2)).to.equal(true); + }); + + // test cases for the edge condition + mocha.it('1-15: should return false for arrays with same length but different content', () => { + expect(areEqualArrays(['a', 'b'], ['a', 'c'])).to.equal(false); + }); + + mocha.it('1-16: should return true for single element arrays', () => { + expect(areEqualArrays(['a'], ['a'])).to.equal(true); + expect(areEqualArrays(['a'], ['b'])).to.equal(false); + }); + }); + mocha.describe('getMaxFlowDepth', () => { mocha.it('1-1: test should return the default value when maxFlowDepth is undefined', () => { const result = getMaxFlowDepth(); @@ -219,7 +305,7 @@ mocha.describe('getMaxFlowDepth', () => { } const result = getMaxFlowDepth(); expect(result).to.equal(MAX_FLOW_DEPTH_DEFAULT_VALUE); - }); + }); mocha.it('1-3: test should return the value of maxFlowDepth when it is 2000 within the valid range', () => { const validMaxFlowDepth = 2000; -- Gitee From 6d5e79cc17a734d6d1dcb053946f1c49a9bd6a87 Mon Sep 17 00:00:00 2001 From: oh_ci Date: Thu, 21 Aug 2025 02:11:58 +0000 Subject: [PATCH 05/31] =?UTF-8?q?=E5=9B=9E=E9=80=80=20'Pull=20Request=20!5?= =?UTF-8?q?304=20:=20fix=20the=20incremental=20compilation=20of=20types=20?= =?UTF-8?q?option'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compiler/src/ets_checker.ts | 41 ++------- compiler/src/interop/src/ets_checker.ts | 37 ++------ .../test/ark_compiler_ut/ets_checker.test.ts | 88 +------------------ 3 files changed, 15 insertions(+), 151 deletions(-) diff --git a/compiler/src/ets_checker.ts b/compiler/src/ets_checker.ts index 85857608e..716d75244 100644 --- a/compiler/src/ets_checker.ts +++ b/compiler/src/ets_checker.ts @@ -110,7 +110,6 @@ export interface LanguageServiceCache { service?: ts.LanguageService; pkgJsonFileHash?: string; targetESVersion?: ts.ScriptTarget; - types?: string[]; maxFlowDepth?: number; preTsImportSendable?: boolean; preSkipOhModulesLint?: boolean; @@ -438,34 +437,30 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi let service: ts.LanguageService | undefined = cache?.service; const currentHash: string | undefined = rollupShareObject?.projectConfig?.pkgJsonFileHash; const currentTargetESVersion: ts.ScriptTarget = compilerOptions.target; - const currentTypes: string[] | undefined = compilerOptions.types; const currentMaxFlowDepth: number | undefined = compilerOptions.maxFlowDepth; const lastHash: string | undefined = cache?.pkgJsonFileHash; const lastTargetESVersion: ts.ScriptTarget | undefined = cache?.targetESVersion; - const lastTypes: string[] | undefined = cache?.types; const lastMaxFlowDepth: number | undefined = cache?.maxFlowDepth; const hashDiffers: boolean | undefined = currentHash && lastHash && currentHash !== lastHash; const shouldRebuildForDepDiffers: boolean | undefined = reuseLanguageServiceForDepChange ? (hashDiffers && !rollupShareObject?.depInfo?.enableIncre) : hashDiffers; const targetESVersionDiffers: boolean | undefined = lastTargetESVersion && currentTargetESVersion && lastTargetESVersion !== currentTargetESVersion; - const typesDiff: boolean | undefined = !areEqualArrays(lastTypes, currentTypes); const maxFlowDepthDiffers: boolean | undefined = lastMaxFlowDepth && currentMaxFlowDepth && lastMaxFlowDepth !== currentMaxFlowDepth; const tsImportSendableDiff: boolean = (cache?.preTsImportSendable === undefined && !tsImportSendable) ? false : cache?.preTsImportSendable !== tsImportSendable; - const skipOhModulesLintDiff: boolean = (cache?.preSkipOhModulesLint === undefined && !skipOhModulesLint) ? + const skipOhModulesLintDiff: boolean = (cache?.preSkipOhModulesLint === undefined && !skipOhModulesLint) ? false : cache?.preSkipOhModulesLint !== skipOhModulesLint; - const mixCompileDiff: boolean = (cache?.preMixCompile === undefined && !mixCompile) ? + const mixCompileDiff: boolean = (cache?.preMixCompile === undefined && !mixCompile) ? false : cache?.preMixCompile !== mixCompile; const shouldRebuild: boolean | undefined = shouldRebuildForDepDiffers || targetESVersionDiffers || - tsImportSendableDiff || typesDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; - const onlyDeleteBuildInfoCache: boolean | undefined = tsImportSendableDiff || typesDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; + tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; if (reuseLanguageServiceForDepChange && hashDiffers && rollupShareObject?.depInfo?.enableIncre) { needReCheckForChangedDepUsers = true; } if (!service || shouldRebuild) { - rebuildProgram(targetESVersionDiffers, onlyDeleteBuildInfoCache); + rebuildProgram(targetESVersionDiffers, tsImportSendableDiff, maxFlowDepthDiffers, skipOhModulesLintDiff, mixCompileDiff); service = ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); } else { // Found language service from cache, update root files @@ -477,7 +472,6 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi service: service, pkgJsonFileHash: currentHash, targetESVersion: currentTargetESVersion, - types: currentTypes, maxFlowDepth: currentMaxFlowDepth, preTsImportSendable: tsImportSendable, preSkipOhModulesLint: skipOhModulesLint, @@ -487,33 +481,14 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi return service; } -export function areEqualArrays(lastArray: string[] | undefined, currentArray: string[] | undefined): boolean { - if (!lastArray || !currentArray) { - return lastArray === currentArray; - } - - const currentSet = new Set(currentArray); - const lastSet = new Set(lastArray); - - if (lastSet.size !== currentSet.size) { - return false; - } - - for (const item of lastSet) { - if (!currentSet.has(item)) { - return false; - } - } - return true; -} - -function rebuildProgram(targetESVersionDiffers: boolean | undefined, onlyDeleteBuildInfoCache: boolean | undefined): void { +function rebuildProgram(targetESVersionDiffers: boolean | undefined, tsImportSendableDiff: boolean, + maxFlowDepthDiffers: boolean | undefined, skipOhModulesLintDiff: boolean, mixCompileDiff: boolean): void { if (targetESVersionDiffers) { // If the targetESVersion is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); targetESVersionChanged = true; - } else if (onlyDeleteBuildInfoCache) { - // When tsImportSendable or types or maxFlowDepth or skipOhModuleslint or mixCompile is changed, we need to delete the build info cahce files + } else if (tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff) { + // When tsImportSendable or maxFlowDepth is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); } } diff --git a/compiler/src/interop/src/ets_checker.ts b/compiler/src/interop/src/ets_checker.ts index fe11635c6..e1d5381b3 100644 --- a/compiler/src/interop/src/ets_checker.ts +++ b/compiler/src/interop/src/ets_checker.ts @@ -123,7 +123,6 @@ export interface LanguageServiceCache { service?: ts.LanguageService; pkgJsonFileHash?: string; targetESVersion?: ts.ScriptTarget; - types?: string[]; maxFlowDepth?: number; preTsImportSendable?: boolean; preSkipOhModulesLint?: boolean; @@ -458,17 +457,14 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi let service: ts.LanguageService | undefined = cache?.service; const currentHash: string | undefined = rollupShareObject?.projectConfig?.pkgJsonFileHash; const currentTargetESVersion: ts.ScriptTarget = compilerOptions.target; - const currentTypes: string[] | undefined = compilerOptions.types; const currentMaxFlowDepth: number | undefined = compilerOptions.maxFlowDepth; const lastHash: string | undefined = cache?.pkgJsonFileHash; const lastTargetESVersion: ts.ScriptTarget | undefined = cache?.targetESVersion; - const lastTypes: string[] | undefined = cache?.types; const lastMaxFlowDepth: number | undefined = cache?.maxFlowDepth; const hashDiffers: boolean | undefined = currentHash && lastHash && currentHash !== lastHash; const shouldRebuildForDepDiffers: boolean | undefined = reuseLanguageServiceForDepChange ? (hashDiffers && !rollupShareObject?.depInfo?.enableIncre) : hashDiffers; const targetESVersionDiffers: boolean | undefined = lastTargetESVersion && currentTargetESVersion && lastTargetESVersion !== currentTargetESVersion; - const typesDiff: boolean | undefined = !areEqualArrays(lastTypes, currentTypes); const maxFlowDepthDiffers: boolean | undefined = lastMaxFlowDepth && currentMaxFlowDepth && lastMaxFlowDepth !== currentMaxFlowDepth; const tsImportSendableDiff: boolean = (cache?.preTsImportSendable === undefined && !tsImportSendable) ? false : @@ -478,14 +474,13 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi const mixCompileDiff: boolean = (cache?.preMixCompile === undefined && !mixCompile) ? false : cache?.preMixCompile !== mixCompile; const shouldRebuild: boolean | undefined = shouldRebuildForDepDiffers || targetESVersionDiffers || - tsImportSendableDiff || typesDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; - const onlyDeleteBuildInfoCache: boolean | undefined = tsImportSendableDiff || typesDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; + tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; if (reuseLanguageServiceForDepChange && hashDiffers && rollupShareObject?.depInfo?.enableIncre) { needReCheckForChangedDepUsers = true; } if (!service || shouldRebuild) { - rebuildProgram(targetESVersionDiffers, onlyDeleteBuildInfoCache); + rebuildProgram(targetESVersionDiffers, tsImportSendableDiff, maxFlowDepthDiffers, skipOhModulesLintDiff, mixCompileDiff); service = ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); } else { // Found language service from cache, update root files @@ -497,7 +492,6 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi service: service, pkgJsonFileHash: currentHash, targetESVersion: currentTargetESVersion, - types: currentTypes, maxFlowDepth: currentMaxFlowDepth, preTsImportSendable: tsImportSendable, preSkipOhModulesLint: skipOhModulesLint, @@ -507,33 +501,14 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi return service; } -export function areEqualArrays(lastArray: string[] | undefined, currentArray: string[] | undefined): boolean { - if (!lastArray || !currentArray) { - return lastArray === currentArray; - } - - const currentSet = new Set(currentArray); - const lastSet = new Set(lastArray); - - if (lastSet.size !== currentSet.size) { - return false; - } - - for (const item of lastSet) { - if (!currentSet.has(item)) { - return false; - } - } - return true; -} - -function rebuildProgram(targetESVersionDiffers: boolean | undefined, onlyDeleteBuildInfoCache: boolean | undefined): void { +function rebuildProgram(targetESVersionDiffers: boolean | undefined, tsImportSendableDiff: boolean, + maxFlowDepthDiffers: boolean | undefined, skipOhModulesLintDiff: boolean, mixCompileDiff: boolean): void { if (targetESVersionDiffers) { // If the targetESVersion is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); targetESVersionChanged = true; - } else if (onlyDeleteBuildInfoCache) { - // When tsImportSendable or types or maxFlowDepth or skipOhModuleslint or mixCompile is changed, we need to delete the build info cahce files + } else if (tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff) { + // When tsImportSendable or maxFlowDepth is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); } } diff --git a/compiler/test/ark_compiler_ut/ets_checker.test.ts b/compiler/test/ark_compiler_ut/ets_checker.test.ts index 4a1785e74..17d258b70 100644 --- a/compiler/test/ark_compiler_ut/ets_checker.test.ts +++ b/compiler/test/ark_compiler_ut/ets_checker.test.ts @@ -36,7 +36,6 @@ import { resetEtsCheck, serviceChecker, resolveModuleNames as resolveModuleNamesMain, - areEqualArrays, getMaxFlowDepth, MAX_FLOW_DEPTH_DEFAULT_VALUE, fileCache, @@ -205,91 +204,6 @@ mocha.describe('test ets_checker file api', function () { }); }); -mocha.describe('test areEqualArrays function', () => { - // test cases for basic functions - mocha.it('1-1: should return true for identical arrays', () => { - expect(areEqualArrays(['a', 'b', 'c'], ['a', 'b', 'c'])).to.equal(true); - }); - - mocha.it('1-2: should return true for arrays with same elements in different order', () => { - expect(areEqualArrays(['a', 'b', 'c'], ['c', 'a', 'b'])).to.equal(true); - }); - - mocha.it('1-3: should return false for arrays with different elements', () => { - expect(areEqualArrays(['a', 'b', 'c'], ['a', 'b', 'd'])).to.equal(false); - }); - - mocha.it('1-4: should return false for arrays with different lengths', () => { - expect(areEqualArrays(['a', 'b', 'c'], ['a', 'b'])).to.equal(false); - expect(areEqualArrays(['a', 'b'], ['a', 'b', 'c'])).to.equal(false); - }); - - // test cases for boundary conditions - mocha.it('1-5: should return true for empty arrays', () => { - expect(areEqualArrays([], [])).to.equal(true); - }); - - mocha.it('1-6: should return false when one array is empty and other is not', () => { - expect(areEqualArrays([], ['a'])).to.equal(false); - expect(areEqualArrays(['a'], [])).to.equal(false); - }); - - // test cases for null and undefined scenarios - mocha.it('1-7: should return true when both arrays are undefined', () => { - expect(areEqualArrays(undefined, undefined)).to.equal(true); - }); - - mocha.it('1-8: should return true when both arrays are null', () => { - expect(areEqualArrays(null as any, null as any)).to.equal(true); - }); - - mocha.it('1-9: should return false when one array is undefined and other is not', () => { - expect(areEqualArrays(undefined, ['a'])).to.equal(false); - expect(areEqualArrays(['a'], undefined)).to.equal(false); - }); - - mocha.it('1-10: should return false when one array is null and other is not', () => { - expect(areEqualArrays(null as any, ['a'])).to.equal(false); - expect(areEqualArrays(['a'], null as any)).to.equal(false); - }); - - // test cases for duplicate elements - mocha.it('1-11: should handle duplicate elements correctly', () => { - expect(areEqualArrays(['a', 'a', 'b'], ['a', 'b', 'a'])).to.equal(true); - expect(areEqualArrays(['a', 'a', 'b'], ['a', 'b', 'b'])).to.equal(true); - }); - - // test case sensitivity scenarios - mocha.it('1-12: should be case sensitive', () => { - expect(areEqualArrays(['A', 'B'], ['a', 'b'])).to.equal(false); - expect(areEqualArrays(['A', 'B'], ['A', 'B'])).to.equal(true); - }); - - // test cases for special value scenarios - mocha.it('1-13: should handle special values', () => { - expect(areEqualArrays(['', 'null'], ['', 'null'])).to.equal(true); - expect(areEqualArrays(['0', '1'], ['0', '1'])).to.equal(true); - }); - - // test cases for performance - mocha.it('1-14: should handle large arrays efficiently', () => { - const largeArray1 = Array(10000).fill('item'); - const largeArray2 = Array(10000).fill('item'); - - expect(areEqualArrays(largeArray1, largeArray2)).to.equal(true); - }); - - // test cases for the edge condition - mocha.it('1-15: should return false for arrays with same length but different content', () => { - expect(areEqualArrays(['a', 'b'], ['a', 'c'])).to.equal(false); - }); - - mocha.it('1-16: should return true for single element arrays', () => { - expect(areEqualArrays(['a'], ['a'])).to.equal(true); - expect(areEqualArrays(['a'], ['b'])).to.equal(false); - }); - }); - mocha.describe('getMaxFlowDepth', () => { mocha.it('1-1: test should return the default value when maxFlowDepth is undefined', () => { const result = getMaxFlowDepth(); @@ -305,7 +219,7 @@ mocha.describe('getMaxFlowDepth', () => { } const result = getMaxFlowDepth(); expect(result).to.equal(MAX_FLOW_DEPTH_DEFAULT_VALUE); - }); + }); mocha.it('1-3: test should return the value of maxFlowDepth when it is 2000 within the valid range', () => { const validMaxFlowDepth = 2000; -- Gitee From 64af4e6532c3409770b1cb646805460e962b602c Mon Sep 17 00:00:00 2001 From: Cuecuexiaoyu Date: Thu, 21 Aug 2025 11:32:44 +0800 Subject: [PATCH 06/31] fix code-Check on branch master Signed-off-by: Cuecuexiaoyu Change-Id: If66526a9bbd69b3e0edd57efaaab4e2887bd2393 --- .gitee/CODEOWNERS | 2 +- arkui-plugins/interop-plugins/index.ts | 2 +- .../memo-plugins/parameter-transformer.ts | 11 +- .../ui-plugins/property-translators/utils.ts | 10 +- .../observedV2-trace-usage-validation.ts | 30 ++-- .../interop/src/cpp/interop-logging.cc | 8 +- .../src/arkts-api/factory/nodeFactory.ts | 125 ++++++++--------- koala-wrapper/src/arkts-api/index.ts | 132 +++++++++--------- .../generated/peers/ETSImportDeclaration.ts | 76 ++++++---- .../src/generated/peers/TryStatement.ts | 10 +- 10 files changed, 219 insertions(+), 187 deletions(-) diff --git a/.gitee/CODEOWNERS b/.gitee/CODEOWNERS index 53ea029d5..281eab68d 100755 --- a/.gitee/CODEOWNERS +++ b/.gitee/CODEOWNERS @@ -26,7 +26,7 @@ compiler/test/ut/ @lixingchi1 compiler/test/utForPartialUpdate/ @lixingchi1 compiler/test/utForValidate/ @lixingchi1 compiler/test/transform_ut/ @lixingchi1 -koala-wrapper/ @keerecles +koala-wrapper/ @VictorS67 # Code owners for ArkCompiler ace_ets2bundle diff --git a/arkui-plugins/interop-plugins/index.ts b/arkui-plugins/interop-plugins/index.ts index 404892c34..841f74e11 100644 --- a/arkui-plugins/interop-plugins/index.ts +++ b/arkui-plugins/interop-plugins/index.ts @@ -28,7 +28,7 @@ export function interopTransform():Plugins { name: 'interop-plugin', parsed: parsedTransform, checked: checkedTransform, - clean() { + clean(): void { arkts.arktsGlobal.clearContext(); }, }; diff --git a/arkui-plugins/memo-plugins/parameter-transformer.ts b/arkui-plugins/memo-plugins/parameter-transformer.ts index 061e5b80b..050333da7 100644 --- a/arkui-plugins/memo-plugins/parameter-transformer.ts +++ b/arkui-plugins/memo-plugins/parameter-transformer.ts @@ -235,24 +235,23 @@ export class ParameterTransformer extends AbstractVisitor { } private updateVariableReDeclarationFromParam(node: arkts.VariableDeclaration): arkts.VariableDeclaration { - const that = this; return arkts.factory.updateVariableDeclaration( node, node.modifiers, node.declarationKind, node.declarators.map((declarator) => { - if (that.rewriteMemoInfos?.has(declarator.name.originalPeer)) { - const memoInfo = that.rewriteMemoInfos.get(declarator.name.originalPeer)!; - return that.updateParamReDeclare(declarator, memoInfo); + if (this.rewriteMemoInfos?.has(declarator.name.originalPeer)) { + const memoInfo = this.rewriteMemoInfos.get(declarator.name.originalPeer)!; + return this.updateParamReDeclare(declarator, memoInfo); } if (!!declarator.initializer && arkts.isIdentifier(declarator.initializer)) { const decl = arkts.getPeerDecl(declarator.initializer.originalPeer); - if (decl && that.rewriteIdentifiers?.has(decl.peer)) { + if (decl && this.rewriteIdentifiers?.has(decl.peer)) { return arkts.factory.updateVariableDeclarator( declarator, declarator.flag, declarator.name, - that.rewriteIdentifiers.get(decl.peer)!() + this.rewriteIdentifiers.get(decl.peer)!() ); } } diff --git a/arkui-plugins/ui-plugins/property-translators/utils.ts b/arkui-plugins/ui-plugins/property-translators/utils.ts index 9feb4c4b2..cda1293fc 100644 --- a/arkui-plugins/ui-plugins/property-translators/utils.ts +++ b/arkui-plugins/ui-plugins/property-translators/utils.ts @@ -246,7 +246,7 @@ export function getValueInAnnotation(node: arkts.ClassProperty, decoratorName: D } export interface ProvideOptions { - alias: string; + alias: string | undefined; allowOverride: boolean; } @@ -255,7 +255,7 @@ export function getValueInProvideAnnotation(node: arkts.ClassProperty): ProvideO for (let i = 0; i < annotations.length; i++) { const anno: arkts.AnnotationUsage = annotations[i]; if (anno.expr && arkts.isIdentifier(anno.expr) && anno.expr.name === DecoratorNames.PROVIDE) { - const alias: string = getValueInObjectAnnotation(anno, DecoratorNames.PROVIDE, 'alias'); + const alias = getValueInObjectAnnotation(anno, DecoratorNames.PROVIDE, 'alias') as string | undefined; const allowOverride: boolean = getValueInObjectAnnotation(anno, DecoratorNames.PROVIDE, 'allowOverride') ? true : false; @@ -265,7 +265,11 @@ export function getValueInProvideAnnotation(node: arkts.ClassProperty): ProvideO return undefined; } -function getValueInObjectAnnotation(anno: arkts.AnnotationUsage, decoratorName: DecoratorNames, key: string): any { +function getValueInObjectAnnotation( + anno: arkts.AnnotationUsage, + decoratorName: DecoratorNames, + key: string +): string | boolean | undefined { const isSuitableAnnotation: boolean = !!anno.expr && arkts.isIdentifier(anno.expr) && anno.expr.name === decoratorName; if (!isSuitableAnnotation) { diff --git a/arkui-plugins/ui-syntax-plugins/rules/observedV2-trace-usage-validation.ts b/arkui-plugins/ui-syntax-plugins/rules/observedV2-trace-usage-validation.ts index d6285abd1..278a9bc73 100644 --- a/arkui-plugins/ui-syntax-plugins/rules/observedV2-trace-usage-validation.ts +++ b/arkui-plugins/ui-syntax-plugins/rules/observedV2-trace-usage-validation.ts @@ -67,18 +67,26 @@ function reportTraceMemberVariableError(context: UISyntaxRuleContext, hasTraceDe } function tracePerportyRule( - context: UISyntaxRuleContext, - currentNode: arkts.AstNode, - hasTraceDecorator: arkts.AnnotationUsage): void { - if (arkts.isStructDeclaration(currentNode)) { - reportTraceDecoratorError(context, hasTraceDecorator); - } else if (arkts.isClassDeclaration(currentNode)) { - // The '@Trace' decorator can only be used in a 'class' decorated with '@ObservedV2' - if (!currentNode.definition?.annotations?.some((annotation: any) => annotation.expr.name === - PresetDecorators.OBSERVED_V2)) { - reportTraceInObservedV2Error(context, hasTraceDecorator, currentNode); + context: UISyntaxRuleContext, + currentNode: arkts.AstNode, + hasTraceDecorator: arkts.AnnotationUsage +): void { + if (arkts.isStructDeclaration(currentNode)) { + reportTraceDecoratorError(context, hasTraceDecorator); + } else if (arkts.isClassDeclaration(currentNode)) { + // The '@Trace' decorator can only be used in a 'class' decorated with '@ObservedV2' + if ( + !currentNode.definition?.annotations?.some((annotation: arkts.AnnotationUsage) => { + return ( + !!annotation.expr && + arkts.isIdentifier(annotation.expr) && + annotation.expr.name === PresetDecorators.OBSERVED_V2 + ); + }) + ) { + reportTraceInObservedV2Error(context, hasTraceDecorator, currentNode); + } } - } } function reportTraceDecoratorError(context: UISyntaxRuleContext, hasTraceDecorator: arkts.AnnotationUsage) diff --git a/koala-wrapper/koalaui/interop/src/cpp/interop-logging.cc b/koala-wrapper/koalaui/interop/src/cpp/interop-logging.cc index 60f5eb3e9..349e420ee 100644 --- a/koala-wrapper/koalaui/interop/src/cpp/interop-logging.cc +++ b/koala-wrapper/koalaui/interop/src/cpp/interop-logging.cc @@ -35,7 +35,9 @@ void startGroupedLog(int index) { if (index >= static_cast(groupedLogs.size())) { groupedLogs.resize(index + 1); for (int i = 0; i <= index; i++) { - if (!groupedLogs[i]) groupedLogs[i] = new Log(); + if (!groupedLogs[i]) { + groupedLogs[i] = new Log(); + } } } groupedLogs[index]->isActive = true; @@ -55,10 +57,6 @@ void appendGroupedLog(int index, const char* str) { } const char* getGroupedLog(int index) { - if (index < static_cast(groupedLogs.size())) { - const std::string& log = groupedLogs[index]->log; - return log.c_str(); - } return ""; } diff --git a/koala-wrapper/src/arkts-api/factory/nodeFactory.ts b/koala-wrapper/src/arkts-api/factory/nodeFactory.ts index 1f66f9148..f8307a69b 100644 --- a/koala-wrapper/src/arkts-api/factory/nodeFactory.ts +++ b/koala-wrapper/src/arkts-api/factory/nodeFactory.ts @@ -13,7 +13,7 @@ * limitations under the License. */ -import { updateNodeByNode } from "../utilities/private" +import { updateNodeByNode } from '../utilities/private'; import { ArrowFunctionExpression, AssignmentExpression, @@ -29,10 +29,10 @@ import { StructDeclaration, VariableDeclaration, VariableDeclarator, - ETSStringLiteralType -} from "../types" -import { MemberExpression } from "../to-be-generated/MemberExpression" -import { AstNode } from "../peers/AstNode" + ETSStringLiteralType, +} from '../types'; +import { MemberExpression } from '../to-be-generated/MemberExpression'; +import { AstNode } from '../peers/AstNode'; import { AnnotationUsage, BinaryExpression, @@ -79,66 +79,61 @@ import { ForUpdateStatement, ForInStatement, ForOfStatement, -} from "../../generated" -import { - Es2pandaModifierFlags -} from "../../generated/Es2pandaEnums" -import { - classPropertySetOptional, - hasModifierFlag -} from "../utilities/public" -import { updateIdentifier } from "../node-utilities/Identifier" -import { updateCallExpression } from "../node-utilities/CallExpression" -import { updateExpressionStatement } from "../node-utilities/ExpressionStatement" -import { updateMemberExpression } from "../node-utilities/MemberExpression" -import { updateFunctionDeclaration } from "../node-utilities/FunctionDeclaration" -import { updateBlockStatement } from "../node-utilities/BlockStatement" -import { updateArrowFunctionExpression } from "../node-utilities/ArrowFunctionExpression" -import { updateScriptFunction } from "../node-utilities/ScriptFunction" -import { updateStringLiteral } from "../node-utilities/StringLiteral" -import { updateNumberLiteral } from "../node-utilities/NumberLiteral" -import { updateETSParameterExpression } from "../node-utilities/ETSParameterExpression" -import { updateTSTypeParameter } from "../node-utilities/TSTypeParameter" -import { updateTSTypeParameterDeclaration } from "../node-utilities/TSTypeParameterDeclaration" -import { updateETSPrimitiveType } from "../node-utilities/ETSPrimitiveType" -import { updateETSTypeReference } from "../node-utilities/ETSTypeReference" -import { updateETSTypeReferencePart } from "../node-utilities/ETSTypeReferencePart" -import { updateETSImportDeclaration } from "../node-utilities/ETSImportDeclaration" -import { updateImportSpecifier } from "../node-utilities/ImportSpecifier" -import { updateVariableDeclaration } from "../node-utilities/VariableDeclaration" -import { updateVariableDeclarator } from "../node-utilities/VariableDeclarator" -import { updateETSUnionType } from "../node-utilities/ETSUnionType" -import { updateReturnStatement } from "../node-utilities/ReturnStatement" -import { updateIfStatement } from "../node-utilities/IfStatement" -import { updateBinaryExpression } from "../node-utilities/BinaryExpression" -import { updateClassDeclaration } from "../node-utilities/ClassDeclaration" -import { updateStructDeclaration } from "../node-utilities/StructDeclaration" -import { updateClassDefinition } from "../node-utilities/ClassDefinition" -import { updateClassProperty } from "../node-utilities/ClassProperty" -import { updateETSFunctionType } from "../node-utilities/ETSFunctionType" -import { updateFunctionExpression } from "../node-utilities/FunctionExpression" -import { updateMethodDefinition } from "../node-utilities/MethodDefinition" -import { updateSuperExpression } from "../node-utilities/SuperExpression" -import { updateTSTypeParameterInstantiation } from "../node-utilities/TSTypeParameterInstantiation" -import { updateTSInterfaceDeclaration } from "../node-utilities/TSInterfaceDeclaration" -import { updateTSInterfaceBody } from "../node-utilities/TSInterfaceBody" -import { updateUndefinedLiteral } from "../node-utilities/UndefinedLiteral" -import { updateAnnotationUsage, update1AnnotationUsage } from "../node-utilities/AnnotationUsage" -import { updateAssignmentExpression } from "../node-utilities/AssignmentExpression" -import { updateETSUndefinedType } from "../node-utilities/ETSUndefinedType" -import { updateConditionalExpression } from "../node-utilities/ConditionalExpression" -import { updateTSAsExpression } from "../node-utilities/TSAsExpression" -import { updateThisExpression } from "../node-utilities/ThisExpression" -import { updateTSTypeAliasDeclaration } from "../node-utilities/TSTypeAliasDeclaration" -import { updateTSNonNullExpression } from "../node-utilities/TSNonNullExpression" -import { updateChainExpression } from "../node-utilities/ChainExpression" -import { updateBlockExpression } from "../node-utilities/BlockExpression" -import { updateNullLiteral } from "../node-utilities/NullLiteral" -import { updateETSNewClassInstanceExpression } from "../node-utilities/ETSNewClassInstanceExpression" -import { updateObjectExpression } from "../node-utilities/ObjectExpression" -import { updateProperty } from "../node-utilities/Property" -import { updateTemplateLiteral } from "../node-utilities/TemplateLiteral" -import { updateArrayExpression } from "../node-utilities/ArrayExpression"; +} from '../../generated'; +import { Es2pandaModifierFlags } from '../../generated/Es2pandaEnums'; +import { classPropertySetOptional, hasModifierFlag } from '../utilities/public'; +import { updateIdentifier } from '../node-utilities/Identifier'; +import { updateCallExpression } from '../node-utilities/CallExpression'; +import { updateExpressionStatement } from '../node-utilities/ExpressionStatement'; +import { updateMemberExpression } from '../node-utilities/MemberExpression'; +import { updateFunctionDeclaration } from '../node-utilities/FunctionDeclaration'; +import { updateBlockStatement } from '../node-utilities/BlockStatement'; +import { updateArrowFunctionExpression } from '../node-utilities/ArrowFunctionExpression'; +import { updateScriptFunction } from '../node-utilities/ScriptFunction'; +import { updateStringLiteral } from '../node-utilities/StringLiteral'; +import { updateNumberLiteral } from '../node-utilities/NumberLiteral'; +import { updateETSParameterExpression } from '../node-utilities/ETSParameterExpression'; +import { updateTSTypeParameter } from '../node-utilities/TSTypeParameter'; +import { updateTSTypeParameterDeclaration } from '../node-utilities/TSTypeParameterDeclaration'; +import { updateETSPrimitiveType } from '../node-utilities/ETSPrimitiveType'; +import { updateETSTypeReference } from '../node-utilities/ETSTypeReference'; +import { updateETSTypeReferencePart } from '../node-utilities/ETSTypeReferencePart'; +import { updateETSImportDeclaration } from '../node-utilities/ETSImportDeclaration'; +import { updateImportSpecifier } from '../node-utilities/ImportSpecifier'; +import { updateVariableDeclaration } from '../node-utilities/VariableDeclaration'; +import { updateVariableDeclarator } from '../node-utilities/VariableDeclarator'; +import { updateETSUnionType } from '../node-utilities/ETSUnionType'; +import { updateReturnStatement } from '../node-utilities/ReturnStatement'; +import { updateIfStatement } from '../node-utilities/IfStatement'; +import { updateBinaryExpression } from '../node-utilities/BinaryExpression'; +import { updateClassDeclaration } from '../node-utilities/ClassDeclaration'; +import { updateStructDeclaration } from '../node-utilities/StructDeclaration'; +import { updateClassDefinition } from '../node-utilities/ClassDefinition'; +import { updateClassProperty } from '../node-utilities/ClassProperty'; +import { updateETSFunctionType } from '../node-utilities/ETSFunctionType'; +import { updateFunctionExpression } from '../node-utilities/FunctionExpression'; +import { updateMethodDefinition } from '../node-utilities/MethodDefinition'; +import { updateSuperExpression } from '../node-utilities/SuperExpression'; +import { updateTSTypeParameterInstantiation } from '../node-utilities/TSTypeParameterInstantiation'; +import { updateTSInterfaceDeclaration } from '../node-utilities/TSInterfaceDeclaration'; +import { updateTSInterfaceBody } from '../node-utilities/TSInterfaceBody'; +import { updateUndefinedLiteral } from '../node-utilities/UndefinedLiteral'; +import { updateAnnotationUsage, update1AnnotationUsage } from '../node-utilities/AnnotationUsage'; +import { updateAssignmentExpression } from '../node-utilities/AssignmentExpression'; +import { updateETSUndefinedType } from '../node-utilities/ETSUndefinedType'; +import { updateConditionalExpression } from '../node-utilities/ConditionalExpression'; +import { updateTSAsExpression } from '../node-utilities/TSAsExpression'; +import { updateThisExpression } from '../node-utilities/ThisExpression'; +import { updateTSTypeAliasDeclaration } from '../node-utilities/TSTypeAliasDeclaration'; +import { updateTSNonNullExpression } from '../node-utilities/TSNonNullExpression'; +import { updateChainExpression } from '../node-utilities/ChainExpression'; +import { updateBlockExpression } from '../node-utilities/BlockExpression'; +import { updateNullLiteral } from '../node-utilities/NullLiteral'; +import { updateETSNewClassInstanceExpression } from '../node-utilities/ETSNewClassInstanceExpression'; +import { updateObjectExpression } from '../node-utilities/ObjectExpression'; +import { updateProperty } from '../node-utilities/Property'; +import { updateTemplateLiteral } from '../node-utilities/TemplateLiteral'; +import { updateArrayExpression } from '../node-utilities/ArrayExpression'; import { updateTryStatement } from '../node-utilities/TryStatement'; import { updateForUpdateStatement } from '../node-utilities/ForUpdateStatement'; import { updateForInStatement } from '../node-utilities/ForInStatement'; diff --git a/koala-wrapper/src/arkts-api/index.ts b/koala-wrapper/src/arkts-api/index.ts index 936a9b0f8..5976735bf 100644 --- a/koala-wrapper/src/arkts-api/index.ts +++ b/koala-wrapper/src/arkts-api/index.ts @@ -13,71 +13,71 @@ * limitations under the License. */ -export * from "../Es2pandaEnums" -export * from "../generated/Es2pandaEnums" -export * from "../generated/peers/AnnotationUsage" -export * from "../generated/peers/BlockStatement" -export * from "../generated/peers/ETSPrimitiveType" -export * from "../generated/peers/TSInterfaceBody" -export * from "../generated/peers/TSInterfaceDeclaration" -export * from "../generated/peers/TSTypeParameterInstantiation" -export * from "../generated/peers/UndefinedLiteral" -export * from "../generated/peers/ETSUnionType" -export * from "../generated/peers/FunctionSignature" -export * from "../generated/peers/ETSFunctionType" -export * from "../generated/peers/StringLiteral" -export * from "../generated/peers/ThrowStatement" -export * from "../generated/peers/TypeNode" -export * from "../generated/peers/ClassDeclaration" -export * from "../generated/peers/ClassDefinition" -export * from "../generated/peers/Identifier" -export * from "../generated/peers/ETSTypeReference" -export * from "../generated/peers/ETSTypeReferencePart" -export * from "../generated/peers/ClassProperty" -export * from "../generated/peers/ReturnStatement" -export * from "../generated/peers/Expression" -export * from "../generated/peers/Statement" -export * from "../generated/peers/ImportSpecifier" -export * from "../generated/peers/TSAsExpression" -export * from "../generated/peers/ThisExpression" -export * from "../generated/peers/TSThisType" -export * from "../generated/peers/ETSImportDeclaration" -export * from "../generated/peers/ImportSource" -export * from "../generated/peers/ScriptFunction" -export * from "../generated/peers/TSTypeParameterDeclaration" -export * from "../generated/peers/TSTypeParameter" -export * from "../generated/peers/TSNonNullExpression" -export * from "../generated/peers/ChainExpression" -export * from "../generated/peers/ConditionalExpression" -export * from "../generated/peers/NullLiteral" -export * from "../generated/peers/TSTypeAliasDeclaration" -export * from "../generated/peers/ETSUndefinedType" -export * from "../generated/peers/ETSNewClassInstanceExpression" -export * from "../generated/peers/ObjectExpression" -export * from "../generated/peers/Property" -export * from "../generated/peers/BlockExpression" -export * from "../generated/peers/TSClassImplements" -export * from "../generated/peers/BooleanLiteral" -export * from "../generated/peers/TSArrayType" -export * from "../generated/peers/ArrayExpression"; -export * from "../generated/peers/ETSNullType"; +export * from '../Es2pandaEnums'; +export * from '../generated/Es2pandaEnums'; +export * from '../generated/peers/AnnotationUsage'; +export * from '../generated/peers/BlockStatement'; +export * from '../generated/peers/ETSPrimitiveType'; +export * from '../generated/peers/TSInterfaceBody'; +export * from '../generated/peers/TSInterfaceDeclaration'; +export * from '../generated/peers/TSTypeParameterInstantiation'; +export * from '../generated/peers/UndefinedLiteral'; +export * from '../generated/peers/ETSUnionType'; +export * from '../generated/peers/FunctionSignature'; +export * from '../generated/peers/ETSFunctionType'; +export * from '../generated/peers/StringLiteral'; +export * from '../generated/peers/ThrowStatement'; +export * from '../generated/peers/TypeNode'; +export * from '../generated/peers/ClassDeclaration'; +export * from '../generated/peers/ClassDefinition'; +export * from '../generated/peers/Identifier'; +export * from '../generated/peers/ETSTypeReference'; +export * from '../generated/peers/ETSTypeReferencePart'; +export * from '../generated/peers/ClassProperty'; +export * from '../generated/peers/ReturnStatement'; +export * from '../generated/peers/Expression'; +export * from '../generated/peers/Statement'; +export * from '../generated/peers/ImportSpecifier'; +export * from '../generated/peers/TSAsExpression'; +export * from '../generated/peers/ThisExpression'; +export * from '../generated/peers/TSThisType'; +export * from '../generated/peers/ETSImportDeclaration'; +export * from '../generated/peers/ImportSource'; +export * from '../generated/peers/ScriptFunction'; +export * from '../generated/peers/TSTypeParameterDeclaration'; +export * from '../generated/peers/TSTypeParameter'; +export * from '../generated/peers/TSNonNullExpression'; +export * from '../generated/peers/ChainExpression'; +export * from '../generated/peers/ConditionalExpression'; +export * from '../generated/peers/NullLiteral'; +export * from '../generated/peers/TSTypeAliasDeclaration'; +export * from '../generated/peers/ETSUndefinedType'; +export * from '../generated/peers/ETSNewClassInstanceExpression'; +export * from '../generated/peers/ObjectExpression'; +export * from '../generated/peers/Property'; +export * from '../generated/peers/BlockExpression'; +export * from '../generated/peers/TSClassImplements'; +export * from '../generated/peers/BooleanLiteral'; +export * from '../generated/peers/TSArrayType'; +export * from '../generated/peers/ArrayExpression'; +export * from '../generated/peers/ETSNullType'; -export * from "./types" -export * from "./utilities/private" -export * from "./utilities/public" -export * from "./utilities/performance" -export * from "./factory/nodeFactory" -export * from "./factory/nodeTests" -export * from "./visitor" -export * from "./peers/AstNode" -import "../generated" +export * from './types'; +export * from './utilities/private'; +export * from './utilities/public'; +export * from './utilities/performance'; +export * from './factory/nodeFactory'; +export * from './factory/nodeTests'; +export * from './visitor'; +export * from './peers/AstNode'; +import '../generated'; -export * from "./peers/Config" -export * from "./peers/Context" -export * from "./peers/Program" -export * from "./peers/ImportPathManager" -export * from "./peers/SourcePosition" -export * from "./peers/SourceRange" -export * from "./to-be-generated/MemberExpression" -export * from "./static/globalUtils" -export { global as arktsGlobal } from "./static/global"; +export * from './peers/Config'; +export * from './peers/Context'; +export * from './peers/Program'; +export * from './peers/ImportPathManager'; +export * from './peers/SourcePosition'; +export * from './peers/SourceRange'; +export * from './to-be-generated/MemberExpression'; +export * from './static/globalUtils'; +export { global as arktsGlobal } from './static/global'; diff --git a/koala-wrapper/src/generated/peers/ETSImportDeclaration.ts b/koala-wrapper/src/generated/peers/ETSImportDeclaration.ts index 919394d2a..0752fe1de 100644 --- a/koala-wrapper/src/generated/peers/ETSImportDeclaration.ts +++ b/koala-wrapper/src/generated/peers/ETSImportDeclaration.ts @@ -26,45 +26,73 @@ import { KNativePointer, nodeByType, ArktsObject, - unpackString -} from "../../reexport-for-generated" + unpackString, +} from '../../reexport-for-generated'; +import { ImportDeclaration } from './ImportDeclaration'; +import { ImportSource } from './ImportSource'; +import { Es2pandaImportKinds } from './../Es2pandaEnums'; +import { StringLiteral } from './StringLiteral'; +import { Es2pandaImportFlags } from './../../Es2pandaEnums'; -import { ImportDeclaration } from "./ImportDeclaration" -import { ImportSource } from "./ImportSource" -import { Es2pandaImportKinds } from "./../Es2pandaEnums" -import { StringLiteral } from "./StringLiteral" -import { Es2pandaImportFlags } from "./../../Es2pandaEnums" export class ETSImportDeclaration extends ImportDeclaration { - constructor(pointer: KNativePointer) { - assertValidPeer(pointer, Es2pandaAstNodeType.AST_NODE_TYPE_ETS_IMPORT_DECLARATION) - super(pointer) - + constructor(pointer: KNativePointer) { + assertValidPeer(pointer, Es2pandaAstNodeType.AST_NODE_TYPE_ETS_IMPORT_DECLARATION); + super(pointer); } - static createETSImportDeclaration(source: StringLiteral | undefined, specifiers: readonly AstNode[], importKind: Es2pandaImportKinds, program: ArktsObject, flags: Es2pandaImportFlags): ETSImportDeclaration { - return new ETSImportDeclaration(global.es2panda._CreateETSImportDeclaration(global.context, passNode(source), passNodeArray(specifiers), specifiers.length, importKind, passNode(program), flags)) + static createETSImportDeclaration( + source: StringLiteral | undefined, + specifiers: readonly AstNode[], + importKind: Es2pandaImportKinds, + program: ArktsObject, + flags: Es2pandaImportFlags + ): ETSImportDeclaration { + return new ETSImportDeclaration( + global.es2panda._CreateETSImportDeclaration( + global.context, + passNode(source), + passNodeArray(specifiers), + specifiers.length, + importKind, + passNode(program), + flags + ) + ); } - static updateETSImportDeclaration(original: ETSImportDeclaration | undefined, source: StringLiteral | undefined, specifiers: readonly AstNode[], importKind: Es2pandaImportKinds): ETSImportDeclaration { - return new ETSImportDeclaration(global.generatedEs2panda._UpdateETSImportDeclaration(global.context, passNode(original), passNode(source), passNodeArray(specifiers), specifiers.length, importKind)) + static updateETSImportDeclaration( + original: ETSImportDeclaration | undefined, + source: StringLiteral | undefined, + specifiers: readonly AstNode[], + importKind: Es2pandaImportKinds + ): ETSImportDeclaration { + return new ETSImportDeclaration( + global.generatedEs2panda._UpdateETSImportDeclaration( + global.context, + passNode(original), + passNode(source), + passNodeArray(specifiers), + specifiers.length, + importKind + ) + ); } get hasDecl(): boolean { - return global.generatedEs2panda._ETSImportDeclarationHasDeclConst(global.context, this.peer) + return global.generatedEs2panda._ETSImportDeclarationHasDeclConst(global.context, this.peer); } get isPureDynamic(): boolean { - return global.generatedEs2panda._ETSImportDeclarationIsPureDynamicConst(global.context, this.peer) + return global.generatedEs2panda._ETSImportDeclarationIsPureDynamicConst(global.context, this.peer); } get assemblerName(): string { - return unpackString(global.generatedEs2panda._ETSImportDeclarationAssemblerNameConst(global.context, this.peer)) + return unpackString( + global.generatedEs2panda._ETSImportDeclarationAssemblerNameConst(global.context, this.peer) + ); } - // get source(): StringLiteral | undefined { - // return unpackNode(global.generatedEs2panda._ETSImportDeclarationSourceConst(global.context, this.peer)) - // } get resolvedSource(): StringLiteral | undefined { - return unpackNode(global.generatedEs2panda._ETSImportDeclarationResolvedSourceConst(global.context, this.peer)) + return unpackNode(global.generatedEs2panda._ETSImportDeclarationResolvedSourceConst(global.context, this.peer)); } } export function isETSImportDeclaration(node: AstNode): node is ETSImportDeclaration { - return node instanceof ETSImportDeclaration + return node instanceof ETSImportDeclaration; } if (!nodeByType.has(Es2pandaAstNodeType.AST_NODE_TYPE_ETS_IMPORT_DECLARATION)) { - nodeByType.set(Es2pandaAstNodeType.AST_NODE_TYPE_ETS_IMPORT_DECLARATION, ETSImportDeclaration) + nodeByType.set(Es2pandaAstNodeType.AST_NODE_TYPE_ETS_IMPORT_DECLARATION, ETSImportDeclaration); } diff --git a/koala-wrapper/src/generated/peers/TryStatement.ts b/koala-wrapper/src/generated/peers/TryStatement.ts index 5c7c1a756..72141cddc 100644 --- a/koala-wrapper/src/generated/peers/TryStatement.ts +++ b/koala-wrapper/src/generated/peers/TryStatement.ts @@ -27,12 +27,12 @@ import { ArktsObject, unpackString, Es2pandaAstNodeType -} from "../../reexport-for-generated"; +} from '../../reexport-for-generated'; +import { BlockStatement } from './BlockStatement'; +import { CatchClause } from './CatchClause'; +import { LabelPair } from './LabelPair'; +import { Statement } from './Statement'; -import { BlockStatement } from "./BlockStatement"; -import { CatchClause } from "./CatchClause"; -import { LabelPair } from "./LabelPair"; -import { Statement } from "./Statement"; export class TryStatement extends Statement { constructor(pointer: KNativePointer) { assertValidPeer(pointer, Es2pandaAstNodeType.AST_NODE_TYPE_TRY_STATEMENT) -- Gitee From 1cd36cd8610060dd3a10ffed17f86f1666951e14 Mon Sep 17 00:00:00 2001 From: Yenan Date: Sun, 24 Aug 2025 17:03:36 +0800 Subject: [PATCH 07/31] =?UTF-8?q?=E4=BC=98=E5=8C=96rawfile=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E5=A2=9E=E9=87=8F=E7=BC=96=E8=AF=91=E9=9C=80=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yenan --- .../common/rollup-plugin-watch-change.ts | 5 +- .../ets_ui/rollup-plugin-ets-typescript.ts | 50 ++++++++++++++++--- compiler/src/process_ui_syntax.ts | 9 +++- compiler/src/utils.ts | 49 +++++++++++------- 4 files changed, 85 insertions(+), 28 deletions(-) diff --git a/compiler/src/fast_build/common/rollup-plugin-watch-change.ts b/compiler/src/fast_build/common/rollup-plugin-watch-change.ts index 69803a752..13197d677 100644 --- a/compiler/src/fast_build/common/rollup-plugin-watch-change.ts +++ b/compiler/src/fast_build/common/rollup-plugin-watch-change.ts @@ -60,8 +60,9 @@ export function watchChangeFiles() { resources.app = {}; readAppResource(process.env.appResource); if (process.env.rawFileResource) { - resourcesRawfile(process.env.rawFileResource, storedFileInfo.resourcesArr); - this.share.rawfilechanged = differenceResourcesRawfile(storedFileInfo.lastResourcesSet, storedFileInfo.resourcesArr); + resourcesRawfile(process.env.rawFileResource, storedFileInfo.resourcesArr, this.share.getHashByFilePath); + this.share.rawfilechanged = differenceResourcesRawfile(storedFileInfo.lastResourcesSet, + storedFileInfo.resourcesArr, storedFileInfo.changedResourcesSet); } } ShouldEnableDebugLine.enableDebugLine = false; 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 4fe0e8fd9..3a4e9f0cd 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 @@ -161,12 +161,19 @@ export function etsTransform() { cacheFile = this.cache.get('transformCacheFiles'); storedFileInfo.addGlobalCacheInfo(this.cache.get('resourceListCacheInfo'), this.cache.get('resourceToFileCacheInfo'), cacheFile); - if (this.cache.get('lastResourcesArr')) { - storedFileInfo.lastResourcesSet = new Set([...this.cache.get('lastResourcesArr')]); + if (this.cache.has('lastResourcesArr') && this.cache.has('lastResourcesForFiles')) { + storedFileInfo.lastResourcesSet = this.cache.get('lastResourcesArr'); + storedFileInfo.lastResourcesForFiles = this.cache.get('lastResourcesForFiles'); + storedFileInfo.hasResourcesCache = true; + } else { + storedFileInfo.lastResourcesSet = new Map(); + storedFileInfo.lastResourcesForFiles = new Map(); + storedFileInfo.hasResourcesCache = false; } if (process.env.rawFileResource) { - resourcesRawfile(process.env.rawFileResource, storedFileInfo.resourcesArr); - this.share.rawfilechanged = differenceResourcesRawfile(storedFileInfo.lastResourcesSet, storedFileInfo.resourcesArr); + resourcesRawfile(process.env.rawFileResource, storedFileInfo.resourcesArr, this.share.getHashByFilePath); + this.share.rawfilechanged = differenceResourcesRawfile(storedFileInfo.lastResourcesSet, + storedFileInfo.resourcesArr, storedFileInfo.changedResourcesSet); } } if (!!this.cache.get('enableDebugLine') !== projectConfig.enableDebugLine) { @@ -198,7 +205,7 @@ export function etsTransform() { const fileName: string = path.resolve(options.id); let shouldDisable: boolean = shouldDisableCache || disableNonEntryFileCache(fileName) || ShouldEnableDebugLine.enableDebugLine; if (process.env.compileMode === 'moduleJson') { - shouldDisable = shouldDisable || storedFileInfo.shouldInvalidFiles.has(fileName) || this.share.rawfilechanged; + shouldDisable = shouldDisable || storedFileInfo.shouldInvalidFiles.has(fileName) || checkRawFileChange(fileName); if (cacheFile && cacheFile[fileName] && cacheFile[fileName].children.length) { for (let child of cacheFile[fileName].children) { const newTimeMs: number = fs.existsSync(child.fileName) ? fs.statSync(child.fileName).mtimeMs : -1; @@ -280,7 +287,11 @@ export function etsTransform() { } shouldDisableCache = false; this.cache.set('disableCacheOptions', disableCacheOptions); - this.cache.set('lastResourcesArr', [...storedFileInfo.resourcesArr]); + this.cache.set('lastResourcesArr', new Map(storedFileInfo.resourcesArr)); + storedFileInfo.resourcesForFiles.forEach((value, key) => { + storedFileInfo.lastResourcesForFiles.set(key, value); + }); + this.cache.set('lastResourcesForFiles', new Map(storedFileInfo.lastResourcesForFiles)); if (projectConfig.enableDebugLine) { this.cache.set('enableDebugLine', true); } else { @@ -338,6 +349,33 @@ function judgeCacheShouldDisabled(): void { } } + +/** + * Checks if a given file needs to be recompiled due to changes in raw resource files. + * + * This function determines whether the specified file has dependencies on raw files + * (resources) that have been modified since the last compilation. It checks against + * a cache of stored file information and a set of changed resources. + * + * @param {string} file - The path or identifier of the file to check for recompilation need + * @returns {boolean} Returns true if the file needs recompilation due to raw file changes, + * false otherwise + */ +function checkRawFileChange(file: string): boolean { + if (!storedFileInfo.hasResourcesCache) { + return true; + } + if (!storedFileInfo.lastResourcesForFiles.has(file)) { + return false; + } + for (const singleRawfiles of storedFileInfo.lastResourcesForFiles.get(file)) { + if (storedFileInfo.changedResourcesSet.has(singleRawfiles)) { + return true; + } + } + return false; +} + interface EmitResult { outputText: string, sourceMapText: string, diff --git a/compiler/src/process_ui_syntax.ts b/compiler/src/process_ui_syntax.ts index e8c2932a2..cf0a880fc 100644 --- a/compiler/src/process_ui_syntax.ts +++ b/compiler/src/process_ui_syntax.ts @@ -747,7 +747,7 @@ export function processResourceData(node: ts.CallExpression, filePath: string, const resourceData: string[] = (node.arguments[0] as ts.StringLiteral).text.trim().split('.'); const isResourceModule: boolean = resourceData.length && /^\[.*\]$/g.test(resourceData[0]); if (node.expression.getText() === RESOURCE_RAWFILE) { - isResourcefile(node, previewLog, isResourceModule, isTemplateString, isCorrectResources); + isResourcefile(node, previewLog, isResourceModule, isTemplateString, isCorrectResources, filePath); if (isCorrectResources.booleanValue) { resourcePreviewMessage(previewLog); return createResourceParamWithVariable(node, -1, RESOURCE_TYPE.rawfile); @@ -815,7 +815,7 @@ function getResourceDataNode(node: ts.CallExpression, previewLog: {isAccelerateP } function isResourcefile(node: ts.CallExpression, previewLog: {isAcceleratePreview: boolean, log: LogInfo[]}, isResourceModule: boolean, - isTemplateString: boolean, isCorrectResources: isCorrectResourcesType): void { + isTemplateString: boolean, isCorrectResources: isCorrectResourcesType, filePath: string): void { if (!isResourceModule && process.env.rawFileResource && !storedFileInfo.resourcesArr.has(node.arguments[0].text) && !previewLog.isAcceleratePreview && process.env.compileMode === 'moduleJson') { isTemplateString && (isCorrectResources.booleanValue = true); @@ -825,6 +825,11 @@ function isResourcefile(node: ts.CallExpression, previewLog: {isAcceleratePrevie pos: node.getStart(), code: '10904333' }); + } else if (!isResourceModule && process.env.rawFileResource) { + if (!storedFileInfo.resourcesForFiles.has(filePath)) { + storedFileInfo.resourcesForFiles.set(filePath, []); + } + storedFileInfo.resourcesForFiles.get(filePath).push(node.arguments[0].text); } } diff --git a/compiler/src/utils.ts b/compiler/src/utils.ts index 7b0a287a9..2686ddb48 100644 --- a/compiler/src/utils.ts +++ b/compiler/src/utils.ts @@ -787,8 +787,12 @@ export class ProcessFileInfo { resourceTableChanged: boolean = false; currentArkTsFile: SpecialArkTSFileInfo; reUseProgram: boolean = false; - resourcesArr: Set = new Set(); - lastResourcesSet: Set = new Set(); + resourcesArr: Map = new Map(); // Rawfile and its hash + lastResourcesSet: Map = new Map(); + changedResourcesSet: Set = new Set(); // Rawfiles that are modified + resourcesForFiles: Map = new Map(); // Rawfiles used by each source file + lastResourcesForFiles: Map = new Map(); + hasResourcesCache: boolean = false; transformCacheFiles: { [fileName: string]: CacheFile } = {}; processBuilder: boolean = false; processGlobalBuilder: boolean = false; @@ -961,6 +965,10 @@ export class ProcessFileInfo { this.lastResourceList = new Set([...this.resourceList]); this.shouldInvalidFiles.clear(); this.resourcesArr.clear(); + this.lastResourcesSet.clear(); + this.changedResourcesSet.clear(); + this.resourcesForFiles.clear(); + this.lastResourcesForFiles.clear(); } setCurrentArkTsFile(): void { this.currentArkTsFile = new SpecialArkTSFileInfo(); @@ -1031,36 +1039,41 @@ export interface ExtendResult { componentName: string; } -export function resourcesRawfile(rawfilePath: string, resourcesArr: Set, resourceName: string = ''): void { +export function resourcesRawfile(rawfilePath: string, resourcesArr: Map, + getHashByFilePathFunc: Function | undefined, resourceName: string = ''): void { + if (!getHashByFilePathFunc) { + getHashByFilePathFunc = (filePath: string): string => '0'; + } if (fs.existsSync(process.env.rawFileResource) && fs.statSync(rawfilePath).isDirectory()) { const files: string[] = fs.readdirSync(rawfilePath); files.forEach((file: string) => { if (fs.statSync(path.join(rawfilePath, file)).isDirectory()) { - resourcesRawfile(path.join(rawfilePath, file), resourcesArr, resourceName ? resourceName + '/' + file : file); + resourcesRawfile(path.join(rawfilePath, file), resourcesArr, getHashByFilePathFunc, + resourceName ? resourceName + '/' + file : file); } else { if (resourceName) { - resourcesArr.add(resourceName + '/' + file); + resourcesArr.set(resourceName + '/' + file, getHashByFilePathFunc(rawfilePath + '/' + file)); } else { - resourcesArr.add(file); + resourcesArr.set(file, getHashByFilePathFunc(rawfilePath + '/' + file)); } } }); } } -export function differenceResourcesRawfile(oldRawfile: Set, newRawfile: Set): boolean { - if (oldRawfile.size !== 0 && oldRawfile.size === newRawfile.size) { - for (const singleRawfiles of oldRawfile.values()) { - if (!newRawfile.has(singleRawfiles)) { - return true; - } +export function differenceResourcesRawfile(oldRawfile: Map, newRawfile: Map, + changedRawFile: Set): boolean { + let res: boolean = oldRawfile.size !== newRawfile.size; + oldRawfile.forEach((hash, file) => { + if (!newRawfile.has(file)) { + changedRawFile.add(file); + res = true; + } else if (newRawfile.get(file) !== hash || newRawfile.get(file) === '0') { + changedRawFile.add(file); + res = true; } - return false; - } else if (oldRawfile.size === 0 && oldRawfile.size === newRawfile.size) { - return false; - } else { - return true; - } + }); + return res; } export function isString(text: unknown): text is string { -- Gitee From c5aeadadb2737d6f2523b7b147980e3eaaee3cf7 Mon Sep 17 00:00:00 2001 From: liyancheng2 Date: Fri, 22 Aug 2025 17:13:03 +0800 Subject: [PATCH 08/31] annotation cannot be used in the har where the compilation output is a js file Issue: https://gitee.com/openharmony/third_party_typescript/issues/ICU4O8 Signed-off-by: liyancheng2 Change-Id: I944ef8a59878d3da96e5235f68d99a6f35047eb0 --- compiler/src/ets_checker.ts | 8 +++++++- compiler/src/interop/src/ets_checker.ts | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/compiler/src/ets_checker.ts b/compiler/src/ets_checker.ts index 716d75244..a56cd183d 100644 --- a/compiler/src/ets_checker.ts +++ b/compiler/src/ets_checker.ts @@ -210,7 +210,8 @@ function setCompilerOptions(resolveModulePaths: string[]): void { 'compatibleSdkVersionStage': projectConfig.compatibleSdkVersionStage, 'compatibleSdkVersion': projectConfig.compatibleSdkVersion, 'skipOhModulesLint': skipOhModulesLint, - 'mixCompile': mixCompile + 'mixCompile': mixCompile, + 'isCompileJsHar': isCompileJsHar(), }); if (projectConfig.compileMode === ESMODULE) { Object.assign(compilerOptions, { @@ -224,6 +225,11 @@ function setCompilerOptions(resolveModulePaths: string[]): void { readTsBuildInfoFileInCrementalMode(buildInfoPath, projectConfig); } +function isCompileJsHar(): boolean { + return projectConfig.compileHar && projectConfig.byteCodeHar === false && projectConfig.buildMode === 'Release' && + projectConfig.obfuscationOptions?.selfConfig.ruleOptions.enable && !projectConfig.useTsHar; +} + function checkArkTSVersion(): void { const etsCheckerLogger = fastBuildLogger || logger; if (getArkTSVersion() === ArkTSVersion.ArkTS_1_0 && tsImportSendable) { diff --git a/compiler/src/interop/src/ets_checker.ts b/compiler/src/interop/src/ets_checker.ts index e1d5381b3..cf94e3828 100644 --- a/compiler/src/interop/src/ets_checker.ts +++ b/compiler/src/interop/src/ets_checker.ts @@ -226,7 +226,8 @@ function setCompilerOptions(resolveModulePaths: string[]): void { 'compatibleSdkVersionStage': projectConfig.compatibleSdkVersionStage, 'compatibleSdkVersion': projectConfig.compatibleSdkVersion, 'skipOhModulesLint': skipOhModulesLint, - 'mixCompile': mixCompile + 'mixCompile': mixCompile, + 'isCompileJsHar': isCompileJsHar(), }); if (projectConfig.compileMode === ESMODULE) { Object.assign(compilerOptions, { @@ -240,6 +241,11 @@ function setCompilerOptions(resolveModulePaths: string[]): void { readTsBuildInfoFileInCrementalMode(buildInfoPath, projectConfig); } +function isCompileJsHar(): boolean { + return projectConfig.compileHar && projectConfig.byteCodeHar === false && projectConfig.buildMode === 'Release' && + projectConfig.obfuscationOptions?.selfConfig.ruleOptions.enable && !projectConfig.useTsHar; +} + function checkArkTSVersion(): void { const etsCheckerLogger = fastBuildLogger || logger; if (getArkTSVersion() === ArkTSVersion.ArkTS_1_0 && tsImportSendable) { -- Gitee From b7b07606531f8508447f24871b343c69f3aa6219 Mon Sep 17 00:00:00 2001 From: zhangzezhong Date: Thu, 21 Aug 2025 17:13:20 +0800 Subject: [PATCH 09/31] =?UTF-8?q?=E6=84=8F=E5=9B=BE=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E6=A3=80=E8=A7=86=E6=84=8F=E8=A7=81=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangzezhong --- compiler/src/pre_define.ts | 12 ++--- compiler/src/userIntents_parser/intentType.ts | 11 ++-- .../userIntents_parser/parseUserIntents.ts | 50 +++++++++---------- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/compiler/src/pre_define.ts b/compiler/src/pre_define.ts index 659f618b2..17a174368 100644 --- a/compiler/src/pre_define.ts +++ b/compiler/src/pre_define.ts @@ -66,6 +66,12 @@ export const REUSABLE_V2_INNER_DECORATOR: string = '__ReusableV2_Inner_Decorator export const REUSE_ATTRIBUTE: string = 'reuse'; export const COMPONENT_USER_INTENTS_DECORATOR_PAGE: string = '@InsightIntentPage'; +export const COMPONENT_USER_INTENTS_DECORATOR_LINK: string = '@InsightIntentLink'; +export const COMPONENT_USER_INTENTS_DECORATOR_ENTRY: string = '@InsightIntentEntry'; +export const COMPONENT_USER_INTENTS_DECORATOR_FUNCTION: string = '@InsightIntentFunction'; +export const COMPONENT_USER_INTENTS_DECORATOR_METHOD: string = '@InsightIntentFunctionMethod'; +export const COMPONENT_USER_INTENTS_DECORATOR_ENTITY: string = '@InsightIntentEntity'; +export const COMPONENT_USER_INTENTS_DECORATOR_FORM: string = '@InsightIntentForm'; export const COMPONENT_DECORATORS_PARAMS: Set = new Set([COMPONENT_CONSUME_DECORATOR, COMPONENT_STORAGE_PROP_DECORATOR, COMPONENT_STORAGE_LINK_DECORATOR, COMPONENT_PROVIDE_DECORATOR, @@ -95,12 +101,6 @@ export const COMPONENT_STYLES_DECORATOR: string = '@Styles'; export const COMPONENT_ANIMATABLE_EXTEND_DECORATOR: string = '@AnimatableExtend'; export const COMPONENT_CONCURRENT_DECORATOR: string = '@Concurrent'; export const COMPONENT_SENDABLE_DECORATOR: string = '@Sendable'; -export const COMPONENT_USER_INTENTS_DECORATOR: string = '@InsightIntentLink'; -export const COMPONENT_USER_INTENTS_DECORATOR_ENTRY: string = '@InsightIntentEntry'; -export const COMPONENT_USER_INTENTS_DECORATOR_FUNCTION: string = '@InsightIntentFunction'; -export const COMPONENT_USER_INTENTS_DECORATOR_METHOD: string = '@InsightIntentFunctionMethod'; -export const COMPONENT_USER_INTENTS_DECORATOR_ENTITY: string = '@InsightIntentEntity'; -export const COMPONENT_USER_INTENTS_DECORATOR_FORM: string = '@InsightIntentForm'; export const CHECK_COMPONENT_EXTEND_DECORATOR: string = 'Extend'; export const STRUCT_CONTEXT_METHOD_DECORATORS: Set = new Set([COMPONENT_BUILDER_DECORATOR, COMPONENT_STYLES_DECORATOR, COMPONENT_LOCAL_BUILDER_DECORATOR]); diff --git a/compiler/src/userIntents_parser/intentType.ts b/compiler/src/userIntents_parser/intentType.ts index 9ac1f7fdf..4babcbd76 100644 --- a/compiler/src/userIntents_parser/intentType.ts +++ b/compiler/src/userIntents_parser/intentType.ts @@ -227,13 +227,14 @@ intentEntryInfoChecker.paramValidators = { executeMode(v: ts.Expression): boolean { return v !== undefined && v !== null && ts.isArrayLiteralExpression(v) && v.elements.every(e => { + const enumValue: string = e?.getText().split('.').pop(); const validModes = [ - 'insightIntent.ExecuteMode.UI_ABILITY_FOREGROUND', - 'insightIntent.ExecuteMode.UI_ABILITY_BACKGROUND', - 'insightIntent.ExecuteMode.UI_EXTENSION_ABILITY', - 'insightIntent.ExecuteMode.SERVICE_EXTENSION_ABILITY' + 'UI_ABILITY_FOREGROUND', + 'UI_ABILITY_BACKGROUND', + 'UI_EXTENSION_ABILITY', + 'SERVICE_EXTENSION_ABILITY' ]; - return (ts.isNumericLiteral(e) && [0, 1, 2, 3].includes(Number(e.text))) || validModes.includes(e.getText()); + return (ts.isNumericLiteral(e) && [0, 1, 2, 3].includes(Number(e.text))) || validModes.includes(enumValue); }); }, intentName: validateRequiredString, diff --git a/compiler/src/userIntents_parser/parseUserIntents.ts b/compiler/src/userIntents_parser/parseUserIntents.ts index 1b8e02177..418b9804d 100644 --- a/compiler/src/userIntents_parser/parseUserIntents.ts +++ b/compiler/src/userIntents_parser/parseUserIntents.ts @@ -34,7 +34,7 @@ import fs from 'fs'; import json5 from 'json5'; import { ProjectCollections } from 'arkguard'; import { - COMPONENT_USER_INTENTS_DECORATOR, + COMPONENT_USER_INTENTS_DECORATOR_LINK, COMPONENT_USER_INTENTS_DECORATOR_ENTITY, COMPONENT_USER_INTENTS_DECORATOR_ENTRY, COMPONENT_USER_INTENTS_DECORATOR_FUNCTION, @@ -44,7 +44,7 @@ import { } from '../pre_define'; import { CompileEvent, createAndStartEvent, stopEvent } from '../performance'; import {emitLogInfo, getTransformLog, LogInfo, LogType} from '../utils'; -import {ABILITY_SUBSYSTEM_CODE} from '../../lib/hvigor_error_code/hvigor_error_info'; +import {ABILITY_SUBSYSTEM_CODE} from '../hvigor_error_code/hvigor_error_info'; import {resetLog, transformLog} from '../process_ui_syntax'; type StaticValue = string | number | boolean | null | undefined | StaticValue[] | { [key: string]: StaticValue }; @@ -110,7 +110,7 @@ class ParseIntent { node: ts.ClassDeclaration, metaInfo: object, filePath: string, eventOrEventFactory: CompileEvent | undefined, transformLog: LogInfo[]): ts.Node { this.initInsightIntent(node, metaInfo, transformLog, filePath); const eventParseIntentTime: CompileEvent | undefined = createAndStartEvent(eventOrEventFactory, 'parseIntentTime'); - const definedDecorators: string[] = [COMPONENT_USER_INTENTS_DECORATOR, COMPONENT_USER_INTENTS_DECORATOR_ENTRY, + const definedDecorators: string[] = [COMPONENT_USER_INTENTS_DECORATOR_LINK, COMPONENT_USER_INTENTS_DECORATOR_ENTRY, COMPONENT_USER_INTENTS_DECORATOR_FUNCTION, COMPONENT_USER_INTENTS_DECORATOR_PAGE, COMPONENT_USER_INTENTS_DECORATOR_ENTITY, COMPONENT_USER_INTENTS_DECORATOR_FORM]; if (ts.isClassDeclaration(node) && !this.hasDecorator(node, [COMPONENT_USER_INTENTS_DECORATOR_FUNCTION])) { @@ -183,6 +183,16 @@ class ParseIntent { }); return; } + if (!projectConfig.pkgContextInfo) { + const errorMessage: string = 'Failed to generate standard OHMUrl.'; + this.transformLog.push({ + type: LogType.ERROR, message: errorMessage, pos: this.currentNode.getStart(), + code: '10111027', + description: 'InsightIntent Compiler Error', + solutions: ['Set useNormalizedOHMUrl to true in build-profile.json5'] + }); + return; + } const pkgParams: object = { pkgName: metaInfo.pkgName, pkgPath: metaInfo.pkgPath @@ -211,16 +221,6 @@ class ParseIntent { if (!isGlobalPathFlag) { return; } - if (!projectConfig.pkgContextInfo) { - const errorMessage: string = 'Failed to generate standard OHMUrl.'; - this.transformLog.push({ - type: LogType.ERROR, message: errorMessage, pos: this.currentNode.getStart(), - code: '10111027', - description: 'InsightIntent Compiler Error', - solutions: ['Set useNormalizedOHMUrl to true in build-profile.json5'] - }); - return; - } const Logger: IntentLogger = IntentLogger.getInstance(); const recordName: string = getNormalizedOhmUrlByFilepath(filepath, projectConfig, Logger, pkgParams, null); const intentObj: object = { @@ -228,7 +228,7 @@ class ParseIntent { 'decoratorClass': node.name.text }; const originalDecorator: string = '@' + decorator.expression.expression.getText(); - if (originalDecorator === COMPONENT_USER_INTENTS_DECORATOR) { + if (originalDecorator === COMPONENT_USER_INTENTS_DECORATOR_LINK) { this.handleLinkDecorator(intentObj, node, decorator); } else if (originalDecorator === COMPONENT_USER_INTENTS_DECORATOR_ENTRY) { this.handleEntryDecorator(intentObj, node, decorator, pkgParams); @@ -427,7 +427,7 @@ class ParseIntent { Object.assign(intentObj, { 'bundleName': projectConfig.bundleName, 'moduleName': projectConfig.moduleName, - 'decoratorType': COMPONENT_USER_INTENTS_DECORATOR + 'decoratorType': COMPONENT_USER_INTENTS_DECORATOR_LINK }); this.createObfuscation(node); if (this.isUpdateCompile) { @@ -572,14 +572,14 @@ class ParseIntent { if (!projectConfig.modulePathMap) { return; } - const jsonStr: string = fs.readFileSync(moduleJsonPath, 'utf8'); - const obj: object = json5.parse(jsonStr); - if (obj.module?.abilities) { - this.moduleJsonInfo.set('abilities', obj.module.abilities); - } - if (obj.module?.extensionAbilities) { - this.moduleJsonInfo.set('extensionAbilities', obj.module.extensionAbilities); - } + const jsonStr: string = fs.readFileSync(moduleJsonPath, 'utf8'); + const obj: object = json5.parse(jsonStr); + if (obj.module?.abilities) { + this.moduleJsonInfo.set('abilities', obj.module.abilities); + } + if (obj.module?.extensionAbilities) { + this.moduleJsonInfo.set('extensionAbilities', obj.module.extensionAbilities); + } } private validatePagePath(intentObj: object, pkgParams: object): void { @@ -1675,7 +1675,7 @@ class ParseIntent { } } catch (e) { const errorMessage: string = `Failed to write to the intent configuration file.`; - this.transformLog.push({ + transformLog.errors.push({ type: LogType.ERROR, message: errorMessage, pos: this.currentNode.getStart(), code: '10110025', description: 'InsightIntent Compiler Error', @@ -1836,7 +1836,7 @@ class ParseIntent { writeJsonData.extractInsightIntents?.forEach(item => { if (duplicates.has(item.intentName)) { const errorMessage: string = `Duplicate intentName definitions found.`; - this.transformLog.push({ + transformLog.errors.push({ type: LogType.ERROR, message: errorMessage, pos: this.currentNode.getStart(), -- Gitee From ae4069dcce2b3fd3c9c0648ae4039b4eaf780467 Mon Sep 17 00:00:00 2001 From: liyancheng2 Date: Tue, 26 Aug 2025 14:50:58 +0800 Subject: [PATCH 10/31] =?UTF-8?q?=E3=80=90add=20the=20moduleRootPath=20to?= =?UTF-8?q?=20compilerOptions=E3=80=91annotation=20cannot=20be=20used=20in?= =?UTF-8?q?=20the=20har=20where=20the=20compilation=20output=20is=20a=20js?= =?UTF-8?q?=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: https://gitee.com/openharmony/developtools_ace_ets2bundle/issues/ICUU2N Signed-off-by: liyancheng2 Change-Id: Ie756a5aa6b5655cb817ca6f14307476cdad107c3 --- compiler/src/ets_checker.ts | 1 + compiler/src/interop/src/ets_checker.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/compiler/src/ets_checker.ts b/compiler/src/ets_checker.ts index a56cd183d..bea5c9ec5 100644 --- a/compiler/src/ets_checker.ts +++ b/compiler/src/ets_checker.ts @@ -212,6 +212,7 @@ function setCompilerOptions(resolveModulePaths: string[]): void { 'skipOhModulesLint': skipOhModulesLint, 'mixCompile': mixCompile, 'isCompileJsHar': isCompileJsHar(), + 'moduleRootPath': projectConfig.moduleRootPath, }); if (projectConfig.compileMode === ESMODULE) { Object.assign(compilerOptions, { diff --git a/compiler/src/interop/src/ets_checker.ts b/compiler/src/interop/src/ets_checker.ts index cf94e3828..fe7ada262 100644 --- a/compiler/src/interop/src/ets_checker.ts +++ b/compiler/src/interop/src/ets_checker.ts @@ -228,6 +228,7 @@ function setCompilerOptions(resolveModulePaths: string[]): void { 'skipOhModulesLint': skipOhModulesLint, 'mixCompile': mixCompile, 'isCompileJsHar': isCompileJsHar(), + 'moduleRootPath': projectConfig.moduleRootPath, }); if (projectConfig.compileMode === ESMODULE) { Object.assign(compilerOptions, { -- Gitee From 58758d694289a3877423948bf1176f4fd05f8183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=95=E7=BB=B4=E5=89=8D?= Date: Wed, 20 Aug 2025 16:41:26 +0800 Subject: [PATCH 11/31] Fix for widget cards overwriting the cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: https://gitee.com/openharmony/developtools_ace_ets2bundle/issues/ICTVXB Signed-off-by: 单维前 --- compiler/src/ets_checker.ts | 6 ++++-- compiler/src/interop/src/ets_checker.ts | 6 ++++-- compiler/test/ark_compiler_ut/ets_checker.test.ts | 12 ++++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/compiler/src/ets_checker.ts b/compiler/src/ets_checker.ts index 716d75244..8aaec8d56 100644 --- a/compiler/src/ets_checker.ts +++ b/compiler/src/ets_checker.ts @@ -177,7 +177,8 @@ function setCompilerOptions(resolveModulePaths: string[]): void { allPath.push('../*'); } } - const suffix: string = projectConfig.hotReload ? HOT_RELOAD_BUILD_INFO_SUFFIX : TS_BUILD_INFO_SUFFIX; + const suffix: string = projectConfig?.hotReload ? HOT_RELOAD_BUILD_INFO_SUFFIX : + `${TS_BUILD_INFO_SUFFIX}${projectConfig?.widgetCompile === 'true' ? '_widget' : ''}`; const buildInfoPath: string = path.resolve(projectConfig.cachePath, '..', suffix); checkArkTSVersion(); Object.assign(compilerOptions, { @@ -568,7 +569,8 @@ export function serviceChecker(rootFileNames: string[], newLogger: Object = null MemoryMonitor.stopRecordStage(recordInfo); props = languageService.getProps(); } else { - cacheFile = path.resolve(projectConfig.cachePath, '../.ts_checker_cache'); + cacheFile = rollupShareObject?.projectConfig?.widgetCompile === 'true' ? path.resolve(projectConfig.cachePath, '../.ts_checker_cache_widget') : + path.resolve(projectConfig.cachePath, '../.ts_checker_cache'); const [isJsonObject, cacheJsonObject]: [boolean, WholeCache | undefined] = isJsonString(cacheFile); const wholeCache: WholeCache = isJsonObject ? cacheJsonObject : { 'runtimeOS': projectConfig.runtimeOS, 'sdkInfo': projectConfig.sdkInfo, 'fileList': {} }; if (wholeCache.runtimeOS === projectConfig.runtimeOS && wholeCache.sdkInfo === projectConfig.sdkInfo) { diff --git a/compiler/src/interop/src/ets_checker.ts b/compiler/src/interop/src/ets_checker.ts index e1d5381b3..92393f8db 100644 --- a/compiler/src/interop/src/ets_checker.ts +++ b/compiler/src/interop/src/ets_checker.ts @@ -193,7 +193,8 @@ function setCompilerOptions(resolveModulePaths: string[]): void { if (isMixCompile()) { compilerOptions.preserveValueImports = true; } - const suffix: string = projectConfig.hotReload ? HOT_RELOAD_BUILD_INFO_SUFFIX : TS_BUILD_INFO_SUFFIX; + const suffix: string = projectConfig?.hotReload ? HOT_RELOAD_BUILD_INFO_SUFFIX : + `${TS_BUILD_INFO_SUFFIX}${projectConfig?.widgetCompile === 'true' ? '_widget' : ''}`; const buildInfoPath: string = path.resolve(projectConfig.cachePath, '..', suffix); checkArkTSVersion(); Object.assign(compilerOptions, { @@ -588,7 +589,8 @@ export function serviceChecker(rootFileNames: string[], newLogger: Object = null MemoryMonitor.stopRecordStage(recordInfo); props = languageService.getProps(); } else { - cacheFile = path.resolve(projectConfig.cachePath, '../.ts_checker_cache'); + cacheFile = rollupShareObject?.projectConfig?.widgetCompile === 'true' ? path.resolve(projectConfig.cachePath, '../.ts_checker_cache_widget') : + path.resolve(projectConfig.cachePath, '../.ts_checker_cache'); const [isJsonObject, cacheJsonObject]: [boolean, WholeCache | undefined] = isJsonString(cacheFile); const wholeCache: WholeCache = isJsonObject ? cacheJsonObject : { 'runtimeOS': projectConfig.runtimeOS, 'sdkInfo': projectConfig.sdkInfo, 'fileList': {} }; if (wholeCache.runtimeOS === projectConfig.runtimeOS && wholeCache.sdkInfo === projectConfig.sdkInfo) { diff --git a/compiler/test/ark_compiler_ut/ets_checker.test.ts b/compiler/test/ark_compiler_ut/ets_checker.test.ts index 17d258b70..b0dceb320 100644 --- a/compiler/test/ark_compiler_ut/ets_checker.test.ts +++ b/compiler/test/ark_compiler_ut/ets_checker.test.ts @@ -60,17 +60,29 @@ mocha.describe('test ets_checker file api', function () { mocha.after(() => { delete this.rollup; const cacheFile: string = path.resolve(projectConfig.cachePath, '../.ts_checker_cache'); + const cacheFileWidget: string = path.resolve(projectConfig.cachePath, '../.ts_checker_cache_widget'); if (fs.existsSync(cacheFile)) { fs.unlinkSync(cacheFile); } + if (fs.existsSync(cacheFileWidget)) { + fs.unlinkSync(cacheFileWidget); + } const tsBuildInfoFilePath: string = path.resolve(projectConfig.cachePath, '..', TS_BUILD_INFO_SUFFIX); + const tsBuildInfoWidgetFilePath: string = path.resolve(projectConfig.cachePath, '..', TS_BUILD_INFO_SUFFIX + '_widget'); if (fs.existsSync(tsBuildInfoFilePath)) { fs.unlinkSync(tsBuildInfoFilePath); } + if (fs.existsSync(tsBuildInfoWidgetFilePath)) { + fs.unlinkSync(tsBuildInfoWidgetFilePath); + } const tsBuildInfoLinterFilePath: string = tsBuildInfoFilePath + '.linter'; + const tsBuildInfoWidgetLinterFilePath: string = tsBuildInfoWidgetFilePath + '.linter'; if (fs.existsSync(tsBuildInfoLinterFilePath)) { fs.unlinkSync(tsBuildInfoLinterFilePath); } + if (fs.existsSync(tsBuildInfoWidgetLinterFilePath)) { + fs.unlinkSync(tsBuildInfoWidgetLinterFilePath); + } }); mocha.it('1-1: test addLocalPackageSet for original ohmurl', function () { -- Gitee From e5e643c0ae03a62b870ab1cfbf3d2b90199645aa Mon Sep 17 00:00:00 2001 From: zju_wyx <22125041@zju.edu.cn> Date: Thu, 28 Aug 2025 10:14:25 +0800 Subject: [PATCH 12/31] skip .d.ets, .d.ts, js and oh_modules files when emit and printDeclarationDiagnostics Signed-off-by: zju_wyx <22125041@zju.edu.cn> Change-Id: Ic929a56172b842645205204b9729011cb3fef3e3 --- compiler/src/ets_checker.ts | 14 +++++++++++--- compiler/src/interop/src/ets_checker.ts | 14 +++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compiler/src/ets_checker.ts b/compiler/src/ets_checker.ts index a56cd183d..71becdf93 100644 --- a/compiler/src/ets_checker.ts +++ b/compiler/src/ets_checker.ts @@ -772,7 +772,7 @@ function processBuildHap(cacheFile: string, rootFileNames: string[], parentEvent if ((/\.d\.e?ts$/).test(moduleFile)) { generateSourceFilesInHar(moduleFile, fs.readFileSync(moduleFile, 'utf-8'), path.extname(moduleFile), projectConfig, projectConfig.modulePathMap); - } else if ((/\.e?ts$/).test(moduleFile)) { + } else if ((/\.e?ts$/).test(moduleFile) && !toUnixPath(moduleFile).includes('/oh_modules/')) { emit = undefined; let sourcefile = globalProgram.program.getSourceFile(moduleFile); if (sourcefile) { @@ -790,8 +790,16 @@ function processBuildHap(cacheFile: string, rootFileNames: string[], parentEvent } function printDeclarationDiagnostics(errorCodeLogger?: Object | undefined): void { - globalProgram.builderProgram.getDeclarationDiagnostics().forEach((diagnostic: ts.Diagnostic) => { - printDiagnostic(diagnostic, ErrorCodeModule.TSC, errorCodeLogger); + globalProgram.program.getSourceFiles().forEach((sourceFile: ts.SourceFile) => { + if ((/\.d\.e?ts$/).test(sourceFile.fileName) || (/\.js$/).test(sourceFile.fileName)) { + return; + } + if (toUnixPath(sourceFile.fileName).includes('/oh_modules/')) { + return; + } + globalProgram.builderProgram.getDeclarationDiagnostics(sourceFile).forEach((diagnostic: ts.Diagnostic) => { + printDiagnostic(diagnostic, ErrorCodeModule.TSC, errorCodeLogger); + }); }); } diff --git a/compiler/src/interop/src/ets_checker.ts b/compiler/src/interop/src/ets_checker.ts index cf94e3828..9ac1b9d94 100644 --- a/compiler/src/interop/src/ets_checker.ts +++ b/compiler/src/interop/src/ets_checker.ts @@ -792,7 +792,7 @@ function processBuildHap(cacheFile: string, rootFileNames: string[], parentEvent if ((/\.d\.e?ts$/).test(moduleFile)) { generateSourceFilesInHar(moduleFile, fs.readFileSync(moduleFile, 'utf-8'), path.extname(moduleFile), projectConfig, projectConfig.modulePathMap); - } else if ((/\.e?ts$/).test(moduleFile)) { + } else if ((/\.e?ts$/).test(moduleFile) && !toUnixPath(moduleFile).includes('/oh_modules/')) { emit = undefined; let sourcefile = globalProgram.program.getSourceFile(moduleFile); if (sourcefile) { @@ -810,8 +810,16 @@ function processBuildHap(cacheFile: string, rootFileNames: string[], parentEvent } function printDeclarationDiagnostics(errorCodeLogger?: Object | undefined): void { - globalProgram.builderProgram.getDeclarationDiagnostics().forEach((diagnostic: ts.Diagnostic) => { - printDiagnostic(diagnostic, ErrorCodeModule.TSC, errorCodeLogger); + globalProgram.program.getSourceFiles().forEach((sourceFile: ts.SourceFile) => { + if ((/\.d\.e?ts$/).test(sourceFile.fileName) || (/\.js$/).test(sourceFile.fileName)) { + return; + } + if (toUnixPath(sourceFile.fileName).includes('/oh_modules/')) { + return; + } + globalProgram.builderProgram.getDeclarationDiagnostics(sourceFile).forEach((diagnostic: ts.Diagnostic) => { + printDiagnostic(diagnostic, ErrorCodeModule.TSC, errorCodeLogger); + }); }); } -- Gitee From acfc04dd4c9e9c1a7d5b3f8c5fa9f83c3bee6ce2 Mon Sep 17 00:00:00 2001 From: majie77 Date: Fri, 15 Aug 2025 15:49:45 +0800 Subject: [PATCH 13/31] Collect entry files of startup and router Issue:https://gitee.com/openharmony/developtools_ace_ets2bundle/issues/ICT6Z8 Signed-off-by: majie77 Change-Id: If73e6cd122b2daadc49ba7d4ed20d9ff41bc3426 --- compiler/main.js | 33 +++++++++++++++++++ compiler/test/ark_compiler_ut/main.test.ts | 14 +++++++- .../collectEntryFile/ark_module.json | 5 +++ .../collectEntryFile/startupConfig.json | 14 ++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 compiler/test/ark_compiler_ut/testdata/obfuscation/collectEntryFile/ark_module.json create mode 100644 compiler/test/ark_compiler_ut/testdata/obfuscation/collectEntryFile/startupConfig.json diff --git a/compiler/main.js b/compiler/main.js index c1e72c927..aa0f9590b 100644 --- a/compiler/main.js +++ b/compiler/main.js @@ -155,6 +155,7 @@ function loadEntryObj(projectConfig) { setFaTestRunnerFile(projectConfig); } if (process.env.aceModuleJsonPath) { + setStartupPagesForObf(projectConfig); setIntentEntryPages(projectConfig); setAbilityPages(projectConfig); setStageTestRunnerFile(projectConfig); @@ -206,11 +207,42 @@ function loadEntryObj(projectConfig) { } } +function readJsonFile(filePath) { + try { + if (filePath && fs.existsSync(filePath)) { + return JSON.parse(fs.readFileSync(filePath).toString()); + } + } catch (e) { + throw Error('\x1B[31m' + `BUIDERROR: the ${filePath} file format is invalid.` + + '\x1B[39m').message; + } + return null; +} + +function setStartupPagesForObf(projectConfig) { + const moduleJson = readJsonFile(projectConfig.aceModuleJsonPath); + if (moduleJson && moduleJson.module && moduleJson.module.appStartup) { + const startupFileName = `${moduleJson.module.appStartup.replace(/\$profile\:/, '')}.json`; + const startupFilePath = path.resolve(projectConfig.aceProfilePath, startupFileName); + const startupConfig = readJsonFile(startupFilePath); + if (startupConfig) { + return; + } + setEntryArrayForObf(startupConfig.configEntry); + startupConfig.startupTasks.forEach(task => { + if (task.srcEntry) { + setEntryArrayForObf(task.srcEntry); + } + }); + } +} + function loadNavigationConfig(aceBuildJson) { if (aceBuildJson && aceBuildJson.routerMap && Array.isArray(aceBuildJson.routerMap)) { aceBuildJson.routerMap.forEach((item) => { if (item.pageSourceFile && (item.name || item.name === '') && item.buildFunction) { const filePath = path.resolve(item.pageSourceFile); + setEntryArrayForObf(filePath); const storedFileInfo = getStoredFileInfo(); if (storedFileInfo.routerInfo.has(filePath)) { storedFileInfo.routerInfo.get(filePath).push({name: item.name, buildFunction: item.buildFunction}); @@ -1186,3 +1218,4 @@ exports.resetGlobalProgram = resetGlobalProgram; exports.setEntryArrayForObf = setEntryArrayForObf; exports.getPackageJsonEntryPath = getPackageJsonEntryPath; exports.setIntentEntryPages = setIntentEntryPages; +exports.setStartupPagesForObf = setStartupPagesForObf; diff --git a/compiler/test/ark_compiler_ut/main.test.ts b/compiler/test/ark_compiler_ut/main.test.ts index 4c753981a..2ebe19a91 100644 --- a/compiler/test/ark_compiler_ut/main.test.ts +++ b/compiler/test/ark_compiler_ut/main.test.ts @@ -16,8 +16,9 @@ import mocha from 'mocha'; import fs from 'fs'; import { expect } from 'chai'; +import path from "path"; -import { setEntryArrayForObf, projectConfig } from '../../main'; +import { setEntryArrayForObf, projectConfig, setStartupPagesForObf } from '../../main'; mocha.describe('test main file api', function () { mocha.it('1-1: test setEntryArrayForObf', function () { @@ -36,4 +37,15 @@ mocha.describe('test main file api', function () { expect(projectConfig.entryArrayForObf[2]).to.equal('index'); expect(projectConfig.entryArrayForObf[3]).to.equal(''); }); + + mocha.it('1-2: test setStartupPagesForObf', function () { + projectConfig.aceModuleJsonPath = path.join(__dirname, '../../test/ark_compiler_ut/testdata/obfuscation/collectEntryFile/ark_module.json'); + projectConfig.aceProfilePath = path.join(__dirname, '../../test/ark_compiler_ut/testdata/obfuscation/collectEntryFile'); + projectConfig.entryArrayForObf = []; + setStartupPagesForObf(projectConfig); + expect(projectConfig.entryArrayForObf[0]).to.equal('pages/mainPage'); + expect(projectConfig.entryArrayForObf[1]).to.equal('pages/test0'); + expect(projectConfig.entryArrayForObf[2]).to.equal('pages/test1'); + expect(projectConfig.entryArrayForObf[3]).to.equal('pages/test2'); + }); }); \ No newline at end of file diff --git a/compiler/test/ark_compiler_ut/testdata/obfuscation/collectEntryFile/ark_module.json b/compiler/test/ark_compiler_ut/testdata/obfuscation/collectEntryFile/ark_module.json new file mode 100644 index 000000000..d372cddb1 --- /dev/null +++ b/compiler/test/ark_compiler_ut/testdata/obfuscation/collectEntryFile/ark_module.json @@ -0,0 +1,5 @@ +{ + "module": { + "appStartup": "$profile:startupConfig" + } +} \ No newline at end of file diff --git a/compiler/test/ark_compiler_ut/testdata/obfuscation/collectEntryFile/startupConfig.json b/compiler/test/ark_compiler_ut/testdata/obfuscation/collectEntryFile/startupConfig.json new file mode 100644 index 000000000..6307c3aaf --- /dev/null +++ b/compiler/test/ark_compiler_ut/testdata/obfuscation/collectEntryFile/startupConfig.json @@ -0,0 +1,14 @@ +{ + "startupTasks": [ + { + "srcEntry": "pages/test0" + }, + { + "srcEntry": "pages/test1" + }, + { + "srcEntry": "pages/test2" + } + ], + "configEntry": "pages/mainPage" +} \ No newline at end of file -- Gitee From bcf7779cc56b646cc09dc3167a1632085577b82e Mon Sep 17 00:00:00 2001 From: majie77 Date: Fri, 29 Aug 2025 11:49:38 +0800 Subject: [PATCH 14/31] Fix collect entry files codeCheck Issue:https://gitee.com/openharmony/developtools_ace_ets2bundle/issues/ICVDWL Fix collect entry files codeCheck Signed-off-by: majie77 Change-Id: I46cd9e5081f14185fc32c2257b910bc178702fab --- compiler/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/main.js b/compiler/main.js index aa0f9590b..82ca0cbae 100644 --- a/compiler/main.js +++ b/compiler/main.js @@ -225,7 +225,7 @@ function setStartupPagesForObf(projectConfig) { const startupFileName = `${moduleJson.module.appStartup.replace(/\$profile\:/, '')}.json`; const startupFilePath = path.resolve(projectConfig.aceProfilePath, startupFileName); const startupConfig = readJsonFile(startupFilePath); - if (startupConfig) { + if (!startupConfig) { return; } setEntryArrayForObf(startupConfig.configEntry); -- Gitee From 0f519823a157723e2052d647b805ccb9e3e14ebe Mon Sep 17 00:00:00 2001 From: liuqian Date: Wed, 20 Aug 2025 17:03:19 +0800 Subject: [PATCH 15/31] add enableStrictCheckOHModule Issue: https://gitee.com/openharmony/developtools_ace_ets2bundle/issues/ICTW67 Signed-off-by: liuqian --- compiler/src/ets_checker.ts | 45 ++++++++++++++++++------- compiler/src/interop/src/ets_checker.ts | 45 ++++++++++++++++++------- 2 files changed, 64 insertions(+), 26 deletions(-) diff --git a/compiler/src/ets_checker.ts b/compiler/src/ets_checker.ts index bea5c9ec5..0090d9f0b 100644 --- a/compiler/src/ets_checker.ts +++ b/compiler/src/ets_checker.ts @@ -113,9 +113,19 @@ export interface LanguageServiceCache { maxFlowDepth?: number; preTsImportSendable?: boolean; preSkipOhModulesLint?: boolean; + preEnableStrictCheckOHModule?: boolean; preMixCompile?: boolean; } +export interface RebuildOptions { + targetESVersionDiffers?: boolean; + tsImportSendableDiff?: boolean; + maxFlowDepthDiffers?: boolean; + skipOhModulesLintDiff?: boolean; + enableStrictCheckOHModuleDiff?: boolean; + mixCompileDiff?: boolean; +} + export const SOURCE_FILES: Map = new Map(); export let localPackageSet: Set = new Set(); export const TSC_SYSTEM_CODE = '105'; @@ -210,6 +220,7 @@ function setCompilerOptions(resolveModulePaths: string[]): void { 'compatibleSdkVersionStage': projectConfig.compatibleSdkVersionStage, 'compatibleSdkVersion': projectConfig.compatibleSdkVersion, 'skipOhModulesLint': skipOhModulesLint, + 'enableStrictCheckOHModule': enableStrictCheckOHModule, 'mixCompile': mixCompile, 'isCompileJsHar': isCompileJsHar(), 'moduleRootPath': projectConfig.moduleRootPath, @@ -458,16 +469,20 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi cache?.preTsImportSendable !== tsImportSendable; const skipOhModulesLintDiff: boolean = (cache?.preSkipOhModulesLint === undefined && !skipOhModulesLint) ? false : cache?.preSkipOhModulesLint !== skipOhModulesLint; + const enableStrictCheckOHModuleDiff: boolean = (cache?.preEnableStrictCheckOHModule === undefined && !enableStrictCheckOHModule) ? + false : cache?.preEnableStrictCheckOHModule !== enableStrictCheckOHModule; const mixCompileDiff: boolean = (cache?.preMixCompile === undefined && !mixCompile) ? false : cache?.preMixCompile !== mixCompile; const shouldRebuild: boolean | undefined = shouldRebuildForDepDiffers || targetESVersionDiffers || - tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; + tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || enableStrictCheckOHModuleDiff || mixCompileDiff; if (reuseLanguageServiceForDepChange && hashDiffers && rollupShareObject?.depInfo?.enableIncre) { needReCheckForChangedDepUsers = true; } if (!service || shouldRebuild) { - rebuildProgram(targetESVersionDiffers, tsImportSendableDiff, maxFlowDepthDiffers, skipOhModulesLintDiff, mixCompileDiff); + const options: RebuildOptions = {targetESVersionDiffers, tsImportSendableDiff, maxFlowDepthDiffers, skipOhModulesLintDiff, + enableStrictCheckOHModuleDiff, mixCompileDiff}; + rebuildProgram(options); service = ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); } else { // Found language service from cache, update root files @@ -476,25 +491,27 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi } const newCache: LanguageServiceCache = { - service: service, - pkgJsonFileHash: currentHash, - targetESVersion: currentTargetESVersion, - maxFlowDepth: currentMaxFlowDepth, - preTsImportSendable: tsImportSendable, - preSkipOhModulesLint: skipOhModulesLint, - preMixCompile: mixCompile - }; + service: service, pkgJsonFileHash: currentHash, targetESVersion: currentTargetESVersion, maxFlowDepth: currentMaxFlowDepth, + preTsImportSendable: tsImportSendable, preSkipOhModulesLint: skipOhModulesLint, preEnableStrictCheckOHModule: enableStrictCheckOHModule, + preMixCompile: mixCompile}; setRollupCache(rollupShareObject, projectConfig, cacheKey, newCache); return service; } -function rebuildProgram(targetESVersionDiffers: boolean | undefined, tsImportSendableDiff: boolean, - maxFlowDepthDiffers: boolean | undefined, skipOhModulesLintDiff: boolean, mixCompileDiff: boolean): void { +function rebuildProgram(options: RebuildOptions): void { + const { + targetESVersionDiffers, + tsImportSendableDiff, + maxFlowDepthDiffers, + skipOhModulesLintDiff, + enableStrictCheckOHModuleDiff, + mixCompileDiff + } = options; if (targetESVersionDiffers) { // If the targetESVersion is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); targetESVersionChanged = true; - } else if (tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff) { + } else if (tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || enableStrictCheckOHModuleDiff || mixCompileDiff) { // When tsImportSendable or maxFlowDepth is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); } @@ -555,6 +572,7 @@ export const warnCheckerResult: WarnCheckerResult = { count: 0 }; export let languageService: ts.LanguageService = null; let tsImportSendable: boolean = false; let skipOhModulesLint: boolean = false; +let enableStrictCheckOHModule: boolean = false; let mixCompile: boolean = false; export let maxMemoryInServiceChecker: number = 0; export function serviceChecker(rootFileNames: string[], newLogger: Object = null, resolveModulePaths: string[] = null, @@ -563,6 +581,7 @@ export function serviceChecker(rootFileNames: string[], newLogger: Object = null let cacheFile: string = null; tsImportSendable = rollupShareObject?.projectConfig.tsImportSendable; skipOhModulesLint = rollupShareObject?.projectConfig.skipOhModulesLint; + enableStrictCheckOHModule = rollupShareObject?.projectConfig.enableStrictCheckOHModule; mixCompile = rollupShareObject?.projectConfig.mixCompile; if (projectConfig.xtsMode || process.env.watchMode === 'true') { if (projectConfig.hotReload) { diff --git a/compiler/src/interop/src/ets_checker.ts b/compiler/src/interop/src/ets_checker.ts index fe7ada262..02c68f4f2 100644 --- a/compiler/src/interop/src/ets_checker.ts +++ b/compiler/src/interop/src/ets_checker.ts @@ -126,9 +126,19 @@ export interface LanguageServiceCache { maxFlowDepth?: number; preTsImportSendable?: boolean; preSkipOhModulesLint?: boolean; + preEnableStrictCheckOHModule?: boolean; preMixCompile?: boolean; } +export interface RebuildOptions { + targetESVersionDiffers?: boolean; + tsImportSendableDiff?: boolean; + maxFlowDepthDiffers?: boolean; + skipOhModulesLintDiff?: boolean; + enableStrictCheckOHModuleDiff?: boolean; + mixCompileDiff?: boolean; +} + export const SOURCE_FILES: Map = new Map(); export let localPackageSet: Set = new Set(); export const TSC_SYSTEM_CODE = '105'; @@ -226,6 +236,7 @@ function setCompilerOptions(resolveModulePaths: string[]): void { 'compatibleSdkVersionStage': projectConfig.compatibleSdkVersionStage, 'compatibleSdkVersion': projectConfig.compatibleSdkVersion, 'skipOhModulesLint': skipOhModulesLint, + 'enableStrictCheckOHModule': enableStrictCheckOHModule, 'mixCompile': mixCompile, 'isCompileJsHar': isCompileJsHar(), 'moduleRootPath': projectConfig.moduleRootPath, @@ -478,16 +489,20 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi cache?.preTsImportSendable !== tsImportSendable; const skipOhModulesLintDiff: boolean = (cache?.preSkipOhModulesLint === undefined && !skipOhModulesLint) ? false : cache?.preSkipOhModulesLint !== skipOhModulesLint; + const enableStrictCheckOHModuleDiff: boolean = (cache?.preEnableStrictCheckOHModule === undefined && !enableStrictCheckOHModule) ? + false : cache?.preEnableStrictCheckOHModule !== enableStrictCheckOHModule; const mixCompileDiff: boolean = (cache?.preMixCompile === undefined && !mixCompile) ? false : cache?.preMixCompile !== mixCompile; const shouldRebuild: boolean | undefined = shouldRebuildForDepDiffers || targetESVersionDiffers || - tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; + tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || enableStrictCheckOHModuleDiff || mixCompileDiff; if (reuseLanguageServiceForDepChange && hashDiffers && rollupShareObject?.depInfo?.enableIncre) { needReCheckForChangedDepUsers = true; } if (!service || shouldRebuild) { - rebuildProgram(targetESVersionDiffers, tsImportSendableDiff, maxFlowDepthDiffers, skipOhModulesLintDiff, mixCompileDiff); + const options: RebuildOptions = {targetESVersionDiffers, tsImportSendableDiff, maxFlowDepthDiffers, skipOhModulesLintDiff, + enableStrictCheckOHModuleDiff, mixCompileDiff}; + rebuildProgram(options); service = ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); } else { // Found language service from cache, update root files @@ -496,25 +511,27 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi } const newCache: LanguageServiceCache = { - service: service, - pkgJsonFileHash: currentHash, - targetESVersion: currentTargetESVersion, - maxFlowDepth: currentMaxFlowDepth, - preTsImportSendable: tsImportSendable, - preSkipOhModulesLint: skipOhModulesLint, - preMixCompile: mixCompile - }; + service: service, pkgJsonFileHash: currentHash, targetESVersion: currentTargetESVersion, + maxFlowDepth: currentMaxFlowDepth, preTsImportSendable: tsImportSendable, preSkipOhModulesLint: skipOhModulesLint, + preEnableStrictCheckOHModule: enableStrictCheckOHModule, preMixCompile: mixCompile}; setRollupCache(rollupShareObject, projectConfig, cacheKey, newCache); return service; } -function rebuildProgram(targetESVersionDiffers: boolean | undefined, tsImportSendableDiff: boolean, - maxFlowDepthDiffers: boolean | undefined, skipOhModulesLintDiff: boolean, mixCompileDiff: boolean): void { +function rebuildProgram(options: RebuildOptions): void { + const { + targetESVersionDiffers, + tsImportSendableDiff, + maxFlowDepthDiffers, + skipOhModulesLintDiff, + enableStrictCheckOHModuleDiff, + mixCompileDiff + } = options; if (targetESVersionDiffers) { // If the targetESVersion is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); targetESVersionChanged = true; - } else if (tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff) { + } else if (tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || enableStrictCheckOHModuleDiff || mixCompileDiff) { // When tsImportSendable or maxFlowDepth is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); } @@ -575,6 +592,7 @@ export const warnCheckerResult: WarnCheckerResult = { count: 0 }; export let languageService: ts.LanguageService = null; let tsImportSendable: boolean = false; let skipOhModulesLint: boolean = false; +let enableStrictCheckOHModule: boolean = false; let mixCompile: boolean = false; export let maxMemoryInServiceChecker: number = 0; export function serviceChecker(rootFileNames: string[], newLogger: Object = null, resolveModulePaths: string[] = null, @@ -583,6 +601,7 @@ export function serviceChecker(rootFileNames: string[], newLogger: Object = null let cacheFile: string = null; tsImportSendable = rollupShareObject?.projectConfig.tsImportSendable; skipOhModulesLint = rollupShareObject?.projectConfig.skipOhModulesLint; + enableStrictCheckOHModule = rollupShareObject?.projectConfig.enableStrictCheckOHModule; mixCompile = rollupShareObject?.projectConfig.mixCompile; if (projectConfig.xtsMode || process.env.watchMode === 'true') { if (projectConfig.hotReload) { -- Gitee From 261ee46a7d486548f1717c2e662f4a454eff2b40 Mon Sep 17 00:00:00 2001 From: shitao Date: Sat, 30 Aug 2025 16:52:15 +0800 Subject: [PATCH 16/31] Change write file to once Issue: ICVKLE Signed-off-by: shitao --- .../ark_compiler/generate_sourcemap.ts | 32 ++++++++----------- .../ark_compiler/generate_sourcemap.ts | 32 ++++++++----------- 2 files changed, 26 insertions(+), 38 deletions(-) diff --git a/compiler/src/fast_build/ark_compiler/generate_sourcemap.ts b/compiler/src/fast_build/ark_compiler/generate_sourcemap.ts index 732ef220f..292b37b46 100644 --- a/compiler/src/fast_build/ark_compiler/generate_sourcemap.ts +++ b/compiler/src/fast_build/ark_compiler/generate_sourcemap.ts @@ -81,8 +81,8 @@ export class SourceMapGenerator { private logger: CommonLogger; private isFirstAppend: boolean = true; private isCompileSingle: boolean = false; - private originFd: number; - private tempFd: number; + private originFileEdited: boolean = false; + private tempFileEdited: boolean = false; public sourceMapKeyMappingForObf: Map = new Map(); @@ -227,7 +227,7 @@ export class SourceMapGenerator { } public writeOrigin(content: string): void { - if (!this.originFd) { + if (!this.originFileEdited) { if (fs.existsSync(this.sourceMapPath)) { fs.unlinkSync(this.sourceMapPath); } @@ -235,13 +235,13 @@ export class SourceMapGenerator { if (!fs.existsSync(sourceMapPathDir)) { fs.mkdirSync(sourceMapPathDir, { recursive: true }); } - this.originFd = fs.openSync(this.sourceMapPath, 'a'); + this.originFileEdited = true; } - fs.appendFileSync(this.originFd, content, { encoding: 'utf8' }); + fs.appendFileSync(this.sourceMapPath, content, 'utf8'); } public writeTemp(content: string): void { - if (!this.tempFd) { + if (!this.tempFileEdited) { if (fs.existsSync(this.sourceMapPathTmp)) { fs.unlinkSync(this.sourceMapPathTmp); } @@ -249,20 +249,14 @@ export class SourceMapGenerator { if (!fs.existsSync(sourceMapPathTmpDir)) { fs.mkdirSync(sourceMapPathTmpDir, { recursive: true }); } - this.tempFd = fs.openSync(this.sourceMapPathTmp, 'a'); + this.tempFileEdited = true; } - fs.appendFileSync(this.tempFd, content, { encoding: 'utf8' }); + fs.appendFileSync(this.sourceMapPathTmp, content, 'utf8'); } - public closeFd(): void { - if (this.originFd) { - fs.closeSync(this.originFd); - this.originFd = undefined; - } - if (this.tempFd) { - fs.closeSync(this.tempFd); - this.tempFd = undefined; - } + public resetFileEdited(): void { + this.originFileEdited = false; + this.tempFileEdited = false; } public convertSourceMapToCache(maps: Object): string { @@ -318,7 +312,7 @@ export class SourceMapGenerator { if (!fs.existsSync(this.sourceMapPathTmp)) { this.writeTemp(''); } - this.closeFd(); + this.resetFileEdited(); if (fs.existsSync(this.cacheSourceMapPath)) { fs.unlinkSync(this.cacheSourceMapPath); } @@ -625,7 +619,7 @@ export class SourceMapGenerator { public static cleanSourceMapObject(): void { if (this.instance) { - this.instance.closeFd(); + this.instance.resetFileEdited(); this.instance.keyCache.clear(); this.instance.sourceMaps = undefined; this.instance = undefined; diff --git a/compiler/src/interop/src/fast_build/ark_compiler/generate_sourcemap.ts b/compiler/src/interop/src/fast_build/ark_compiler/generate_sourcemap.ts index a8549f003..6453b2490 100644 --- a/compiler/src/interop/src/fast_build/ark_compiler/generate_sourcemap.ts +++ b/compiler/src/interop/src/fast_build/ark_compiler/generate_sourcemap.ts @@ -81,8 +81,8 @@ export class SourceMapGenerator { private logger: CommonLogger; private isFirstAppend: boolean = true; private isCompileSingle: boolean = false; - private originFd: number; - private tempFd: number; + private originFileEdited: boolean = false; + private tempFileEdited: boolean = false; public sourceMapKeyMappingForObf: Map = new Map(); @@ -227,7 +227,7 @@ export class SourceMapGenerator { } public writeOrigin(content: string): void { - if (!this.originFd) { + if (!this.originFileEdited) { if (fs.existsSync(this.sourceMapPath)) { fs.unlinkSync(this.sourceMapPath); } @@ -235,13 +235,13 @@ export class SourceMapGenerator { if (!fs.existsSync(sourceMapPathDir)) { fs.mkdirSync(sourceMapPathDir, { recursive: true }); } - this.originFd = fs.openSync(this.sourceMapPath, 'a'); + this.originFileEdited = true; } - fs.appendFileSync(this.originFd, content, { encoding: 'utf8' }); + fs.appendFileSync(this.sourceMapPath, content, 'utf8'); } public writeTemp(content: string): void { - if (!this.tempFd) { + if (!this.tempFileEdited) { if (fs.existsSync(this.sourceMapPathTmp)) { fs.unlinkSync(this.sourceMapPathTmp); } @@ -249,20 +249,14 @@ export class SourceMapGenerator { if (!fs.existsSync(sourceMapPathTmpDir)) { fs.mkdirSync(sourceMapPathTmpDir, { recursive: true }); } - this.tempFd = fs.openSync(this.sourceMapPathTmp, 'a'); + this.tempFileEdited = true; } - fs.appendFileSync(this.tempFd, content, { encoding: 'utf8' }); + fs.appendFileSync(this.sourceMapPathTmp, content, 'utf8'); } - public closeFd(): void { - if (this.originFd) { - fs.closeSync(this.originFd); - this.originFd = undefined; - } - if (this.tempFd) { - fs.closeSync(this.tempFd); - this.tempFd = undefined; - } + public resetFileEdited(): void { + this.originFileEdited = false; + this.tempFileEdited = false; } public convertSourceMapToCache(maps: Object): string { @@ -318,7 +312,7 @@ export class SourceMapGenerator { if (!fs.existsSync(this.sourceMapPathTmp)) { this.writeTemp(''); } - this.closeFd(); + this.resetFileEdited(); if (fs.existsSync(this.sourceMapForMergePath)) { fs.unlinkSync(this.sourceMapForMergePath); } @@ -637,7 +631,7 @@ export class SourceMapGenerator { public static cleanSourceMapObject(): void { if (this.instance) { - this.instance.closeFd(); + this.instance.resetFileEdited(); this.instance.keyCache.clear(); this.instance.sourceMaps = undefined; this.instance = undefined; -- Gitee From 477fcdb48633c44854eed5eabf8394d4de2dbf0e Mon Sep 17 00:00:00 2001 From: oh_ci Date: Sat, 30 Aug 2025 14:47:25 +0000 Subject: [PATCH 17/31] =?UTF-8?q?=E5=9B=9E=E9=80=80=20'Pull=20Request=20!5?= =?UTF-8?q?333=20:=20add=20enableStrictCheckOHModule'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compiler/src/ets_checker.ts | 45 +++++++------------------ compiler/src/interop/src/ets_checker.ts | 45 +++++++------------------ 2 files changed, 26 insertions(+), 64 deletions(-) diff --git a/compiler/src/ets_checker.ts b/compiler/src/ets_checker.ts index dd490b471..d3506861c 100644 --- a/compiler/src/ets_checker.ts +++ b/compiler/src/ets_checker.ts @@ -113,19 +113,9 @@ export interface LanguageServiceCache { maxFlowDepth?: number; preTsImportSendable?: boolean; preSkipOhModulesLint?: boolean; - preEnableStrictCheckOHModule?: boolean; preMixCompile?: boolean; } -export interface RebuildOptions { - targetESVersionDiffers?: boolean; - tsImportSendableDiff?: boolean; - maxFlowDepthDiffers?: boolean; - skipOhModulesLintDiff?: boolean; - enableStrictCheckOHModuleDiff?: boolean; - mixCompileDiff?: boolean; -} - export const SOURCE_FILES: Map = new Map(); export let localPackageSet: Set = new Set(); export const TSC_SYSTEM_CODE = '105'; @@ -221,7 +211,6 @@ function setCompilerOptions(resolveModulePaths: string[]): void { 'compatibleSdkVersionStage': projectConfig.compatibleSdkVersionStage, 'compatibleSdkVersion': projectConfig.compatibleSdkVersion, 'skipOhModulesLint': skipOhModulesLint, - 'enableStrictCheckOHModule': enableStrictCheckOHModule, 'mixCompile': mixCompile, 'isCompileJsHar': isCompileJsHar(), 'moduleRootPath': projectConfig.moduleRootPath, @@ -470,20 +459,16 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi cache?.preTsImportSendable !== tsImportSendable; const skipOhModulesLintDiff: boolean = (cache?.preSkipOhModulesLint === undefined && !skipOhModulesLint) ? false : cache?.preSkipOhModulesLint !== skipOhModulesLint; - const enableStrictCheckOHModuleDiff: boolean = (cache?.preEnableStrictCheckOHModule === undefined && !enableStrictCheckOHModule) ? - false : cache?.preEnableStrictCheckOHModule !== enableStrictCheckOHModule; const mixCompileDiff: boolean = (cache?.preMixCompile === undefined && !mixCompile) ? false : cache?.preMixCompile !== mixCompile; const shouldRebuild: boolean | undefined = shouldRebuildForDepDiffers || targetESVersionDiffers || - tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || enableStrictCheckOHModuleDiff || mixCompileDiff; + tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; if (reuseLanguageServiceForDepChange && hashDiffers && rollupShareObject?.depInfo?.enableIncre) { needReCheckForChangedDepUsers = true; } if (!service || shouldRebuild) { - const options: RebuildOptions = {targetESVersionDiffers, tsImportSendableDiff, maxFlowDepthDiffers, skipOhModulesLintDiff, - enableStrictCheckOHModuleDiff, mixCompileDiff}; - rebuildProgram(options); + rebuildProgram(targetESVersionDiffers, tsImportSendableDiff, maxFlowDepthDiffers, skipOhModulesLintDiff, mixCompileDiff); service = ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); } else { // Found language service from cache, update root files @@ -492,27 +477,25 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi } const newCache: LanguageServiceCache = { - service: service, pkgJsonFileHash: currentHash, targetESVersion: currentTargetESVersion, maxFlowDepth: currentMaxFlowDepth, - preTsImportSendable: tsImportSendable, preSkipOhModulesLint: skipOhModulesLint, preEnableStrictCheckOHModule: enableStrictCheckOHModule, - preMixCompile: mixCompile}; + service: service, + pkgJsonFileHash: currentHash, + targetESVersion: currentTargetESVersion, + maxFlowDepth: currentMaxFlowDepth, + preTsImportSendable: tsImportSendable, + preSkipOhModulesLint: skipOhModulesLint, + preMixCompile: mixCompile + }; setRollupCache(rollupShareObject, projectConfig, cacheKey, newCache); return service; } -function rebuildProgram(options: RebuildOptions): void { - const { - targetESVersionDiffers, - tsImportSendableDiff, - maxFlowDepthDiffers, - skipOhModulesLintDiff, - enableStrictCheckOHModuleDiff, - mixCompileDiff - } = options; +function rebuildProgram(targetESVersionDiffers: boolean | undefined, tsImportSendableDiff: boolean, + maxFlowDepthDiffers: boolean | undefined, skipOhModulesLintDiff: boolean, mixCompileDiff: boolean): void { if (targetESVersionDiffers) { // If the targetESVersion is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); targetESVersionChanged = true; - } else if (tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || enableStrictCheckOHModuleDiff || mixCompileDiff) { + } else if (tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff) { // When tsImportSendable or maxFlowDepth is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); } @@ -573,7 +556,6 @@ export const warnCheckerResult: WarnCheckerResult = { count: 0 }; export let languageService: ts.LanguageService = null; let tsImportSendable: boolean = false; let skipOhModulesLint: boolean = false; -let enableStrictCheckOHModule: boolean = false; let mixCompile: boolean = false; export let maxMemoryInServiceChecker: number = 0; export function serviceChecker(rootFileNames: string[], newLogger: Object = null, resolveModulePaths: string[] = null, @@ -582,7 +564,6 @@ export function serviceChecker(rootFileNames: string[], newLogger: Object = null let cacheFile: string = null; tsImportSendable = rollupShareObject?.projectConfig.tsImportSendable; skipOhModulesLint = rollupShareObject?.projectConfig.skipOhModulesLint; - enableStrictCheckOHModule = rollupShareObject?.projectConfig.enableStrictCheckOHModule; mixCompile = rollupShareObject?.projectConfig.mixCompile; if (projectConfig.xtsMode || process.env.watchMode === 'true') { if (projectConfig.hotReload) { diff --git a/compiler/src/interop/src/ets_checker.ts b/compiler/src/interop/src/ets_checker.ts index 9fffb6876..d943be387 100644 --- a/compiler/src/interop/src/ets_checker.ts +++ b/compiler/src/interop/src/ets_checker.ts @@ -126,19 +126,9 @@ export interface LanguageServiceCache { maxFlowDepth?: number; preTsImportSendable?: boolean; preSkipOhModulesLint?: boolean; - preEnableStrictCheckOHModule?: boolean; preMixCompile?: boolean; } -export interface RebuildOptions { - targetESVersionDiffers?: boolean; - tsImportSendableDiff?: boolean; - maxFlowDepthDiffers?: boolean; - skipOhModulesLintDiff?: boolean; - enableStrictCheckOHModuleDiff?: boolean; - mixCompileDiff?: boolean; -} - export const SOURCE_FILES: Map = new Map(); export let localPackageSet: Set = new Set(); export const TSC_SYSTEM_CODE = '105'; @@ -237,7 +227,6 @@ function setCompilerOptions(resolveModulePaths: string[]): void { 'compatibleSdkVersionStage': projectConfig.compatibleSdkVersionStage, 'compatibleSdkVersion': projectConfig.compatibleSdkVersion, 'skipOhModulesLint': skipOhModulesLint, - 'enableStrictCheckOHModule': enableStrictCheckOHModule, 'mixCompile': mixCompile, 'isCompileJsHar': isCompileJsHar(), 'moduleRootPath': projectConfig.moduleRootPath, @@ -490,20 +479,16 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi cache?.preTsImportSendable !== tsImportSendable; const skipOhModulesLintDiff: boolean = (cache?.preSkipOhModulesLint === undefined && !skipOhModulesLint) ? false : cache?.preSkipOhModulesLint !== skipOhModulesLint; - const enableStrictCheckOHModuleDiff: boolean = (cache?.preEnableStrictCheckOHModule === undefined && !enableStrictCheckOHModule) ? - false : cache?.preEnableStrictCheckOHModule !== enableStrictCheckOHModule; const mixCompileDiff: boolean = (cache?.preMixCompile === undefined && !mixCompile) ? false : cache?.preMixCompile !== mixCompile; const shouldRebuild: boolean | undefined = shouldRebuildForDepDiffers || targetESVersionDiffers || - tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || enableStrictCheckOHModuleDiff || mixCompileDiff; + tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; if (reuseLanguageServiceForDepChange && hashDiffers && rollupShareObject?.depInfo?.enableIncre) { needReCheckForChangedDepUsers = true; } if (!service || shouldRebuild) { - const options: RebuildOptions = {targetESVersionDiffers, tsImportSendableDiff, maxFlowDepthDiffers, skipOhModulesLintDiff, - enableStrictCheckOHModuleDiff, mixCompileDiff}; - rebuildProgram(options); + rebuildProgram(targetESVersionDiffers, tsImportSendableDiff, maxFlowDepthDiffers, skipOhModulesLintDiff, mixCompileDiff); service = ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); } else { // Found language service from cache, update root files @@ -512,27 +497,25 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi } const newCache: LanguageServiceCache = { - service: service, pkgJsonFileHash: currentHash, targetESVersion: currentTargetESVersion, - maxFlowDepth: currentMaxFlowDepth, preTsImportSendable: tsImportSendable, preSkipOhModulesLint: skipOhModulesLint, - preEnableStrictCheckOHModule: enableStrictCheckOHModule, preMixCompile: mixCompile}; + service: service, + pkgJsonFileHash: currentHash, + targetESVersion: currentTargetESVersion, + maxFlowDepth: currentMaxFlowDepth, + preTsImportSendable: tsImportSendable, + preSkipOhModulesLint: skipOhModulesLint, + preMixCompile: mixCompile + }; setRollupCache(rollupShareObject, projectConfig, cacheKey, newCache); return service; } -function rebuildProgram(options: RebuildOptions): void { - const { - targetESVersionDiffers, - tsImportSendableDiff, - maxFlowDepthDiffers, - skipOhModulesLintDiff, - enableStrictCheckOHModuleDiff, - mixCompileDiff - } = options; +function rebuildProgram(targetESVersionDiffers: boolean | undefined, tsImportSendableDiff: boolean, + maxFlowDepthDiffers: boolean | undefined, skipOhModulesLintDiff: boolean, mixCompileDiff: boolean): void { if (targetESVersionDiffers) { // If the targetESVersion is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); targetESVersionChanged = true; - } else if (tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || enableStrictCheckOHModuleDiff || mixCompileDiff) { + } else if (tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff) { // When tsImportSendable or maxFlowDepth is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); } @@ -593,7 +576,6 @@ export const warnCheckerResult: WarnCheckerResult = { count: 0 }; export let languageService: ts.LanguageService = null; let tsImportSendable: boolean = false; let skipOhModulesLint: boolean = false; -let enableStrictCheckOHModule: boolean = false; let mixCompile: boolean = false; export let maxMemoryInServiceChecker: number = 0; export function serviceChecker(rootFileNames: string[], newLogger: Object = null, resolveModulePaths: string[] = null, @@ -602,7 +584,6 @@ export function serviceChecker(rootFileNames: string[], newLogger: Object = null let cacheFile: string = null; tsImportSendable = rollupShareObject?.projectConfig.tsImportSendable; skipOhModulesLint = rollupShareObject?.projectConfig.skipOhModulesLint; - enableStrictCheckOHModule = rollupShareObject?.projectConfig.enableStrictCheckOHModule; mixCompile = rollupShareObject?.projectConfig.mixCompile; if (projectConfig.xtsMode || process.env.watchMode === 'true') { if (projectConfig.hotReload) { -- Gitee From 70f9cdeca8a0d4edd03ef79cd2a8d7075bb6634f Mon Sep 17 00:00:00 2001 From: liuqian Date: Wed, 20 Aug 2025 17:03:19 +0800 Subject: [PATCH 18/31] add enableStrictCheckOHModule Issue: https://gitee.com/openharmony/developtools_ace_ets2bundle/issues/ICTW67 Signed-off-by: liuqian --- compiler/src/ets_checker.ts | 35 ++++++++++++++++--------- compiler/src/interop/src/ets_checker.ts | 35 ++++++++++++++++--------- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/compiler/src/ets_checker.ts b/compiler/src/ets_checker.ts index bea5c9ec5..20e1023cd 100644 --- a/compiler/src/ets_checker.ts +++ b/compiler/src/ets_checker.ts @@ -113,6 +113,7 @@ export interface LanguageServiceCache { maxFlowDepth?: number; preTsImportSendable?: boolean; preSkipOhModulesLint?: boolean; + preEnableStrictCheckOHModule?: boolean; preMixCompile?: boolean; } @@ -210,6 +211,7 @@ function setCompilerOptions(resolveModulePaths: string[]): void { 'compatibleSdkVersionStage': projectConfig.compatibleSdkVersionStage, 'compatibleSdkVersion': projectConfig.compatibleSdkVersion, 'skipOhModulesLint': skipOhModulesLint, + 'enableStrictCheckOHModule': enableStrictCheckOHModule, 'mixCompile': mixCompile, 'isCompileJsHar': isCompileJsHar(), 'moduleRootPath': projectConfig.moduleRootPath, @@ -453,21 +455,19 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi (hashDiffers && !rollupShareObject?.depInfo?.enableIncre) : hashDiffers; const targetESVersionDiffers: boolean | undefined = lastTargetESVersion && currentTargetESVersion && lastTargetESVersion !== currentTargetESVersion; const maxFlowDepthDiffers: boolean | undefined = lastMaxFlowDepth && currentMaxFlowDepth && lastMaxFlowDepth !== currentMaxFlowDepth; - const tsImportSendableDiff: boolean = (cache?.preTsImportSendable === undefined && !tsImportSendable) ? - false : - cache?.preTsImportSendable !== tsImportSendable; - const skipOhModulesLintDiff: boolean = (cache?.preSkipOhModulesLint === undefined && !skipOhModulesLint) ? - false : cache?.preSkipOhModulesLint !== skipOhModulesLint; - const mixCompileDiff: boolean = (cache?.preMixCompile === undefined && !mixCompile) ? - false : cache?.preMixCompile !== mixCompile; + const tsImportSendableDiff: boolean = checkValueDiff(cache?.preTsImportSendable, tsImportSendable); + const skipOhModulesLintDiff: boolean = checkValueDiff(cache?.preSkipOhModulesLint, skipOhModulesLint); + const enableStrictCheckOHModuleDiff: boolean = checkValueDiff(cache?.preEnableStrictCheckOHModule, enableStrictCheckOHModule); + const mixCompileDiff: boolean = checkValueDiff(cache?.preMixCompile, mixCompile); const shouldRebuild: boolean | undefined = shouldRebuildForDepDiffers || targetESVersionDiffers || - tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; + tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || enableStrictCheckOHModuleDiff || mixCompileDiff; if (reuseLanguageServiceForDepChange && hashDiffers && rollupShareObject?.depInfo?.enableIncre) { needReCheckForChangedDepUsers = true; } if (!service || shouldRebuild) { - rebuildProgram(targetESVersionDiffers, tsImportSendableDiff, maxFlowDepthDiffers, skipOhModulesLintDiff, mixCompileDiff); + rebuildProgram(targetESVersionChanged, tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || + enableStrictCheckOHModuleDiff || mixCompileDiff); service = ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); } else { // Found language service from cache, update root files @@ -488,13 +488,22 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi return service; } -function rebuildProgram(targetESVersionDiffers: boolean | undefined, tsImportSendableDiff: boolean, - maxFlowDepthDiffers: boolean | undefined, skipOhModulesLintDiff: boolean, mixCompileDiff: boolean): void { +/** + * compare cache value and current value, check if they are different + * @param cacheValue cache value + * @param currentValue current value + * @returns true if they are different, false otherwise + */ +function checkValueDiff(cacheValue: boolean | undefined, currentValue: boolean): boolean { + return !(cacheValue === undefined && !currentValue) && cacheValue !== currentValue; +} + +function rebuildProgram(targetESVersionDiffers: boolean, languageSwithchDiffers: boolean): void { if (targetESVersionDiffers) { // If the targetESVersion is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); targetESVersionChanged = true; - } else if (tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff) { + } else if (languageSwithchDiffers) { // When tsImportSendable or maxFlowDepth is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); } @@ -555,6 +564,7 @@ export const warnCheckerResult: WarnCheckerResult = { count: 0 }; export let languageService: ts.LanguageService = null; let tsImportSendable: boolean = false; let skipOhModulesLint: boolean = false; +let enableStrictCheckOHModule: boolean = false; let mixCompile: boolean = false; export let maxMemoryInServiceChecker: number = 0; export function serviceChecker(rootFileNames: string[], newLogger: Object = null, resolveModulePaths: string[] = null, @@ -563,6 +573,7 @@ export function serviceChecker(rootFileNames: string[], newLogger: Object = null let cacheFile: string = null; tsImportSendable = rollupShareObject?.projectConfig.tsImportSendable; skipOhModulesLint = rollupShareObject?.projectConfig.skipOhModulesLint; + enableStrictCheckOHModule = rollupShareObject?.projectConfig.enableStrictCheckOHModule; mixCompile = rollupShareObject?.projectConfig.mixCompile; if (projectConfig.xtsMode || process.env.watchMode === 'true') { if (projectConfig.hotReload) { diff --git a/compiler/src/interop/src/ets_checker.ts b/compiler/src/interop/src/ets_checker.ts index fe7ada262..e4cf91b8c 100644 --- a/compiler/src/interop/src/ets_checker.ts +++ b/compiler/src/interop/src/ets_checker.ts @@ -126,6 +126,7 @@ export interface LanguageServiceCache { maxFlowDepth?: number; preTsImportSendable?: boolean; preSkipOhModulesLint?: boolean; + preEnableStrictCheckOHModule?: boolean; preMixCompile?: boolean; } @@ -226,6 +227,7 @@ function setCompilerOptions(resolveModulePaths: string[]): void { 'compatibleSdkVersionStage': projectConfig.compatibleSdkVersionStage, 'compatibleSdkVersion': projectConfig.compatibleSdkVersion, 'skipOhModulesLint': skipOhModulesLint, + 'enableStrictCheckOHModule': enableStrictCheckOHModule, 'mixCompile': mixCompile, 'isCompileJsHar': isCompileJsHar(), 'moduleRootPath': projectConfig.moduleRootPath, @@ -473,21 +475,19 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi (hashDiffers && !rollupShareObject?.depInfo?.enableIncre) : hashDiffers; const targetESVersionDiffers: boolean | undefined = lastTargetESVersion && currentTargetESVersion && lastTargetESVersion !== currentTargetESVersion; const maxFlowDepthDiffers: boolean | undefined = lastMaxFlowDepth && currentMaxFlowDepth && lastMaxFlowDepth !== currentMaxFlowDepth; - const tsImportSendableDiff: boolean = (cache?.preTsImportSendable === undefined && !tsImportSendable) ? - false : - cache?.preTsImportSendable !== tsImportSendable; - const skipOhModulesLintDiff: boolean = (cache?.preSkipOhModulesLint === undefined && !skipOhModulesLint) ? - false : cache?.preSkipOhModulesLint !== skipOhModulesLint; - const mixCompileDiff: boolean = (cache?.preMixCompile === undefined && !mixCompile) ? - false : cache?.preMixCompile !== mixCompile; + const tsImportSendableDiff: boolean = checkValueDiff(cache?.preTsImportSendable, tsImportSendable); + const skipOhModulesLintDiff: boolean = checkValueDiff(cache?.preSkipOhModulesLint, skipOhModulesLint); + const enableStrictCheckOHModuleDiff: boolean = checkValueDiff(cache?.preEnableStrictCheckOHModule, enableStrictCheckOHModule); + const mixCompileDiff: boolean = checkValueDiff(cache?.preMixCompile, mixCompile); const shouldRebuild: boolean | undefined = shouldRebuildForDepDiffers || targetESVersionDiffers || - tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff; + tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || enableStrictCheckOHModuleDiff || mixCompileDiff; if (reuseLanguageServiceForDepChange && hashDiffers && rollupShareObject?.depInfo?.enableIncre) { needReCheckForChangedDepUsers = true; } if (!service || shouldRebuild) { - rebuildProgram(targetESVersionDiffers, tsImportSendableDiff, maxFlowDepthDiffers, skipOhModulesLintDiff, mixCompileDiff); + rebuildProgram(targetESVersionDiffers, tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || + enableStrictCheckOHModuleDiff || mixCompileDiff); service = ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); } else { // Found language service from cache, update root files @@ -508,13 +508,22 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi return service; } -function rebuildProgram(targetESVersionDiffers: boolean | undefined, tsImportSendableDiff: boolean, - maxFlowDepthDiffers: boolean | undefined, skipOhModulesLintDiff: boolean, mixCompileDiff: boolean): void { +/** + * compare cache value and current value, check if they are different + * @param cacheValue cache value + * @param currentValue current value + * @returns true if they are different, false otherwise + */ +function checkValueDiff(cacheValue: boolean | undefined, currentValue: boolean): boolean { + return !(cacheValue === undefined && !currentValue) && cacheValue !== currentValue; +} + +function rebuildProgram(targetESVersionDiffers: boolean, languageSwithchDiffers: boolean): void { if (targetESVersionDiffers) { // If the targetESVersion is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); targetESVersionChanged = true; - } else if (tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || mixCompileDiff) { + } else if (languageSwithchDiffers) { // When tsImportSendable or maxFlowDepth is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); } @@ -575,6 +584,7 @@ export const warnCheckerResult: WarnCheckerResult = { count: 0 }; export let languageService: ts.LanguageService = null; let tsImportSendable: boolean = false; let skipOhModulesLint: boolean = false; +let enableStrictCheckOHModule: boolean = false; let mixCompile: boolean = false; export let maxMemoryInServiceChecker: number = 0; export function serviceChecker(rootFileNames: string[], newLogger: Object = null, resolveModulePaths: string[] = null, @@ -583,6 +593,7 @@ export function serviceChecker(rootFileNames: string[], newLogger: Object = null let cacheFile: string = null; tsImportSendable = rollupShareObject?.projectConfig.tsImportSendable; skipOhModulesLint = rollupShareObject?.projectConfig.skipOhModulesLint; + enableStrictCheckOHModule = rollupShareObject?.projectConfig.enableStrictCheckOHModule; mixCompile = rollupShareObject?.projectConfig.mixCompile; if (projectConfig.xtsMode || process.env.watchMode === 'true') { if (projectConfig.hotReload) { -- Gitee From e532161be7ad79240bd9eed9c02d6c33d3ab25e8 Mon Sep 17 00:00:00 2001 From: Yenan Date: Tue, 2 Sep 2025 16:20:01 +0800 Subject: [PATCH 19/31] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dextend=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E4=BC=A0=E8=87=AA=E5=AE=9A=E4=B9=89=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E6=97=A0=E5=91=8A=E8=AD=A6=E6=88=96=E6=8A=A5?= =?UTF-8?q?=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yenan --- compiler/src/process_ui_syntax.ts | 16 ++++++- .../ExtendInnerComponents.ets | 43 +++++++++++++++++++ .../test/transform_ut/helpers/pathConfig.ts | 1 + compiler/test/transform_ut_error.json | 4 ++ 4 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 compiler/test/transform_ut/application/entry/src/main/ets/pages/utForValidate/Decorators/process_ui_syntax/ExtendInnerComponents.ets diff --git a/compiler/src/process_ui_syntax.ts b/compiler/src/process_ui_syntax.ts index cf0a880fc..6a5607db1 100644 --- a/compiler/src/process_ui_syntax.ts +++ b/compiler/src/process_ui_syntax.ts @@ -80,7 +80,8 @@ import { PAGE_FULL_PATH, LENGTH, PUV2_VIEW_BASE, - CONTEXT_STACK + CONTEXT_STACK, + CHECK_COMPONENT_EXTEND_DECORATOR } from './pre_define'; import { componentInfo, @@ -131,7 +132,8 @@ import { GLOBAL_STYLE_FUNCTION, INTERFACE_NODE_SET, ID_ATTRS, - GLOBAL_CUSTOM_BUILDER_METHOD + GLOBAL_CUSTOM_BUILDER_METHOD, + INNER_COMPONENT_NAMES } from './component_map'; import { resources, @@ -1282,6 +1284,16 @@ function parseExtendNode(node: ts.CallExpression, extendResult: ExtendResult, ch code: '10905108' }); } + if (checkArguments && CHECK_EXTEND_DECORATORS.includes(extendResult.decoratorName) && + node.arguments && node.arguments.length === 1 && ts.isIdentifier(node.arguments[0]) && + !INNER_COMPONENT_NAMES.has(node.arguments[0].getText())) { + transformLog.errors.push({ + type: LogType.WARN, + message: `'${node.arguments[0].getText()}' parameter cannot be` + + ` passed in the '@${extendResult.decoratorName}' decorator.`, + pos: node.getStart() + }); + } } if (node.arguments.length && ts.isIdentifier(node.arguments[0])) { extendResult.componentName = node.arguments[0].escapedText.toString(); diff --git a/compiler/test/transform_ut/application/entry/src/main/ets/pages/utForValidate/Decorators/process_ui_syntax/ExtendInnerComponents.ets b/compiler/test/transform_ut/application/entry/src/main/ets/pages/utForValidate/Decorators/process_ui_syntax/ExtendInnerComponents.ets new file mode 100644 index 000000000..381312e25 --- /dev/null +++ b/compiler/test/transform_ut/application/entry/src/main/ets/pages/utForValidate/Decorators/process_ui_syntax/ExtendInnerComponents.ets @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022-2024 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. + */ +@Extend(Text) +function fancyText(weightValue: number, color: Color) { + .fontStyle(FontStyle.Italic) + .fontWeight(weightValue) + .backgroundColor(color) +} + +@Extend(testExtend) +function extendTestExtend () { + +} + +@Component +struct testExtend { + @State stringOne: string = 'stringOne'; + + build() { + Column() { + Text(this.stringOne) + } + } +} + +@Entry +@Component +struct ExtendInnerComponentsSummerpockets { + build(){ + } +} \ No newline at end of file diff --git a/compiler/test/transform_ut/helpers/pathConfig.ts b/compiler/test/transform_ut/helpers/pathConfig.ts index f981685eb..49b950ba5 100644 --- a/compiler/test/transform_ut/helpers/pathConfig.ts +++ b/compiler/test/transform_ut/helpers/pathConfig.ts @@ -279,6 +279,7 @@ export const UT_VALIDATE_PAGES: string[] = [ 'Decorators/process_ui_syntax/EntryDecoParam', 'Decorators/process_ui_syntax/ExtendOneChild', + 'Decorators/process_ui_syntax/ExtendInnerComponents', 'Decorators/process_ui_syntax/NoSrc', 'Decorators/process_ui_syntax/NotSupportResrcParam', 'Decorators/process_ui_syntax/NotSupportResrcType', diff --git a/compiler/test/transform_ut_error.json b/compiler/test/transform_ut_error.json index a3d04ea0a..09c16a5f3 100644 --- a/compiler/test/transform_ut_error.json +++ b/compiler/test/transform_ut_error.json @@ -316,6 +316,10 @@ "type": "ERROR", "code": "10905108" }, + "ExtendInnerComponents": { + "message": "'testExtend' parameter cannot be passed in the '@Extend' decorator.", + "type": "WARN" + }, "UnknownSrc": { "message": "Unknown resource source 'hap'.", "type": "ERROR", -- Gitee From e55797f1f5e5da9e5c33eea66a41a8b5bf94ab4d Mon Sep 17 00:00:00 2001 From: Yenan Date: Wed, 3 Sep 2025 11:47:22 +0800 Subject: [PATCH 20/31] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dextend=E4=BC=A0if?= =?UTF-8?q?=E6=88=96switch=E8=AF=AD=E5=8F=A5=E6=B2=A1=E6=9C=89=E5=91=8A?= =?UTF-8?q?=E8=AD=A6=E6=88=96=E8=80=85=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yenan --- compiler/src/process_ui_syntax.ts | 52 ++++++++++++++++++ .../process_ui_syntax/ExtendUISyntax.ets | 53 +++++++++++++++++++ .../test/transform_ut/helpers/pathConfig.ts | 1 + compiler/test/transform_ut_error.json | 10 ++++ 4 files changed, 116 insertions(+) create mode 100644 compiler/test/transform_ut/application/entry/src/main/ets/pages/utForValidate/Decorators/process_ui_syntax/ExtendUISyntax.ets diff --git a/compiler/src/process_ui_syntax.ts b/compiler/src/process_ui_syntax.ts index 6a5607db1..d4d323d9d 100644 --- a/compiler/src/process_ui_syntax.ts +++ b/compiler/src/process_ui_syntax.ts @@ -1031,6 +1031,7 @@ export function processAnimateToOrImmediately(node: ts.CallExpression): ts.CallE function processExtend(node: ts.FunctionDeclaration, log: LogInfo[], decoratorName: string): ts.FunctionDeclaration { const componentName: string = isExtendFunction(node, { decoratorName: '', componentName: '' }, true); + checkExtendNode(node, componentName, log); if (componentName && node.body && !node.body.statements.length && decoratorName === COMPONENT_EXTEND_DECORATOR) { const statementArray: ts.Statement[] = []; const bodynode: ts.Block = ts.visitEachChild(node.body, traverseExtendExpression, contextGlobal); @@ -1300,6 +1301,57 @@ function parseExtendNode(node: ts.CallExpression, extendResult: ExtendResult, ch } } +function checkExtendNode(node: ts.FunctionDeclaration, componentName: string, + log: LogInfo[]): void { + const componentInstance: string = `${componentName}Instance`; + if (node.body && node.body.statements && node.body.statements.length > 1) { + validateExtendFunctionFormat(log, node.body.statements[0]); + return; + } + if (node.body && node.body.statements && node.body.statements.length === 1 && + ts.isExpressionStatement(node.body.statements[0])) { + !validateComponentInstance(node.body.statements[0], componentInstance) && + validateExtendFunctionFormat(log, node.body.statements[0]); + return; + } + if (node.body && node.body.statements && node.body.statements.length === 1 && + !ts.isExpressionStatement(node.body.statements[0])) { + validateExtendFunctionFormat(log, node.body.statements[0]); + return; + } +} + +function validateComponentInstance(node: ts.ExpressionStatement, targetInstanceName: string): boolean { + if (!ts.isCallExpression(node.expression)) { + return false; + } + const instanceName: string = findInstanceIdentifier(node.expression); + return instanceName === targetInstanceName; +} + +function findInstanceIdentifier(node: ts.CallExpression): string { + let instanceName: string = ''; + if (!ts.isPropertyAccessExpression(node.expression)) { + return instanceName; + } + const newNode: ts.PropertyAccessExpression = node.expression; + if (ts.isIdentifier(newNode.expression)) { + instanceName = newNode.expression.escapedText.toString(); + return instanceName; + } else if (ts.isCallExpression(newNode.expression)) { + instanceName = findInstanceIdentifier(newNode.expression); + } + return instanceName; +} + +function validateExtendFunctionFormat(log: LogInfo[], block: ts.Statement): void { + log.push({ + message: `Only UI component syntax can be written here.`, + type: LogType.WARN, + pos: block.getStart() + }); +} + function createEntryNode(node: ts.SourceFile, context: ts.TransformationContext, entryNodeKey: ts.Expression, id: number): ts.SourceFile { let cardRelativePath: string; diff --git a/compiler/test/transform_ut/application/entry/src/main/ets/pages/utForValidate/Decorators/process_ui_syntax/ExtendUISyntax.ets b/compiler/test/transform_ut/application/entry/src/main/ets/pages/utForValidate/Decorators/process_ui_syntax/ExtendUISyntax.ets new file mode 100644 index 000000000..b9ffae0f8 --- /dev/null +++ b/compiler/test/transform_ut/application/entry/src/main/ets/pages/utForValidate/Decorators/process_ui_syntax/ExtendUISyntax.ets @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022-2024 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. + */ +@Extend(Text) +function fancyText(weightValue: number, color: Color) { + .fontStyle(FontStyle.Italic) + .fontWeight(weightValue) + .backgroundColor(color) +} + +@Extend(Button) +function extendButton() { + if (true) { + } else { + } +} + +@Extend(Button) +function extendButtonOne() { + switch (true){ + case true: + break; + } +} + +@Component +struct testExtend { + @State stringOne: string = 'stringOne'; + + build() { + Column() { + Text(this.stringOne) + } + } +} + +@Entry +@Component +struct ExtendInnerComponentsSummerpockets { + build(){ + } +} \ No newline at end of file diff --git a/compiler/test/transform_ut/helpers/pathConfig.ts b/compiler/test/transform_ut/helpers/pathConfig.ts index 49b950ba5..fe2c744d8 100644 --- a/compiler/test/transform_ut/helpers/pathConfig.ts +++ b/compiler/test/transform_ut/helpers/pathConfig.ts @@ -280,6 +280,7 @@ export const UT_VALIDATE_PAGES: string[] = [ 'Decorators/process_ui_syntax/EntryDecoParam', 'Decorators/process_ui_syntax/ExtendOneChild', 'Decorators/process_ui_syntax/ExtendInnerComponents', + 'Decorators/process_ui_syntax/ExtendUISyntax', 'Decorators/process_ui_syntax/NoSrc', 'Decorators/process_ui_syntax/NotSupportResrcParam', 'Decorators/process_ui_syntax/NotSupportResrcType', diff --git a/compiler/test/transform_ut_error.json b/compiler/test/transform_ut_error.json index 09c16a5f3..222e4ec13 100644 --- a/compiler/test/transform_ut_error.json +++ b/compiler/test/transform_ut_error.json @@ -320,6 +320,16 @@ "message": "'testExtend' parameter cannot be passed in the '@Extend' decorator.", "type": "WARN" }, + "ExtendUISyntax": [ + { + "message": "Only UI component syntax can be written here.", + "type": "WARN" + }, + { + "message": "Only UI component syntax can be written here.", + "type": "WARN" + } + ], "UnknownSrc": { "message": "Unknown resource source 'hap'.", "type": "ERROR", -- Gitee From 40b82f25bee98648a2391096097cffddbbf564bd Mon Sep 17 00:00:00 2001 From: Yenan Date: Thu, 4 Sep 2025 15:45:08 +0800 Subject: [PATCH 21/31] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dstyles=E8=AF=AD?= =?UTF-8?q?=E5=8F=A5=E4=B8=AD=E4=BC=A0=E5=85=A5=E9=9D=9EUI=E8=AF=AD?= =?UTF-8?q?=E5=8F=A5=E7=BC=96=E8=AF=91=E6=B2=A1=E6=9C=89=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E6=88=96=E5=91=8A=E8=AD=A6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yenan --- compiler/src/process_component_class.ts | 4 +- compiler/src/process_ui_syntax.ts | 32 ++++++++--- .../process_ui_syntax/StylesUISyntax.ets | 55 +++++++++++++++++++ .../test/transform_ut/helpers/pathConfig.ts | 1 + compiler/test/transform_ut_error.json | 14 +++++ 5 files changed, 96 insertions(+), 10 deletions(-) create mode 100644 compiler/test/transform_ut/application/entry/src/main/ets/pages/utForValidate/Decorators/process_ui_syntax/StylesUISyntax.ets diff --git a/compiler/src/process_component_class.ts b/compiler/src/process_component_class.ts index e39e30174..160a4d911 100644 --- a/compiler/src/process_component_class.ts +++ b/compiler/src/process_component_class.ts @@ -153,7 +153,8 @@ import { import { builderTypeParameter, initializeMYIDS, - globalBuilderParamAssignment + globalBuilderParamAssignment, + parseStylesNode } from './process_ui_syntax'; import constantDefine from './constant_define'; import processStructComponentV2, { StructInfo } from './process_struct_componentV2'; @@ -626,6 +627,7 @@ export function processComponentMethod(node: ts.MethodDeclaration, context: ts.T storedFileInfo.processBuilder = false; storedFileInfo.processLocalBuilder = false; } else if (hasDecorator(node, COMPONENT_STYLES_DECORATOR)) { + parseStylesNode(node, log); if (node.parameters && node.parameters.length === 0) { if (ts.isBlock(node.body) && node.body.statements && node.body.statements.length) { INNER_STYLE_FUNCTION.set(name, node.body); diff --git a/compiler/src/process_ui_syntax.ts b/compiler/src/process_ui_syntax.ts index d4d323d9d..7c9da6ef8 100644 --- a/compiler/src/process_ui_syntax.ts +++ b/compiler/src/process_ui_syntax.ts @@ -356,6 +356,7 @@ export function processUISyntax(program: ts.Program, ut = false, storedFileInfo.processBuilder = false; storedFileInfo.processGlobalBuilder = false; } else if (hasDecorator(node, COMPONENT_STYLES_DECORATOR)) { + parseStylesNode(node, transformLog.errors); if (node.parameters.length === 0) { node = undefined; } else { @@ -1304,19 +1305,20 @@ function parseExtendNode(node: ts.CallExpression, extendResult: ExtendResult, ch function checkExtendNode(node: ts.FunctionDeclaration, componentName: string, log: LogInfo[]): void { const componentInstance: string = `${componentName}Instance`; - if (node.body && node.body.statements && node.body.statements.length > 1) { - validateExtendFunctionFormat(log, node.body.statements[0]); + if (node.body && ts.isBlock(node.body) && node.body.statements && + node.body.statements.length > 1) { + validateUIFunctionFormat(log, node.body.statements[0]); return; } - if (node.body && node.body.statements && node.body.statements.length === 1 && - ts.isExpressionStatement(node.body.statements[0])) { + if (node.body && ts.isBlock(node.body) && node.body.statements && + node.body.statements.length === 1 && ts.isExpressionStatement(node.body.statements[0])) { !validateComponentInstance(node.body.statements[0], componentInstance) && - validateExtendFunctionFormat(log, node.body.statements[0]); + validateUIFunctionFormat(log, node.body.statements[0]); return; } - if (node.body && node.body.statements && node.body.statements.length === 1 && - !ts.isExpressionStatement(node.body.statements[0])) { - validateExtendFunctionFormat(log, node.body.statements[0]); + if (node.body && ts.isBlock(node.body) && node.body.statements && + node.body.statements.length === 1 && !ts.isExpressionStatement(node.body.statements[0])) { + validateUIFunctionFormat(log, node.body.statements[0]); return; } } @@ -1344,7 +1346,7 @@ function findInstanceIdentifier(node: ts.CallExpression): string { return instanceName; } -function validateExtendFunctionFormat(log: LogInfo[], block: ts.Statement): void { +function validateUIFunctionFormat(log: LogInfo[], block: ts.Statement): void { log.push({ message: `Only UI component syntax can be written here.`, type: LogType.WARN, @@ -1352,6 +1354,18 @@ function validateExtendFunctionFormat(log: LogInfo[], block: ts.Statement): void }); } +export function parseStylesNode(node: ts.FunctionDeclaration | ts.MethodDeclaration, log: LogInfo[]): void { + const commonInstance: string = 'CommonInstance'; + if (node.body && ts.isBlock(node.body) && node.body.statements && node.body.statements.length) { + if (node.body.statements.length === 1 && ts.isExpressionStatement(node.body.statements[0])) { + !validateComponentInstance(node.body.statements[0], commonInstance) && + validateUIFunctionFormat(log, node.body.statements[0]); + return; + } + validateUIFunctionFormat(log, node.body.statements[0]); + } +} + function createEntryNode(node: ts.SourceFile, context: ts.TransformationContext, entryNodeKey: ts.Expression, id: number): ts.SourceFile { let cardRelativePath: string; diff --git a/compiler/test/transform_ut/application/entry/src/main/ets/pages/utForValidate/Decorators/process_ui_syntax/StylesUISyntax.ets b/compiler/test/transform_ut/application/entry/src/main/ets/pages/utForValidate/Decorators/process_ui_syntax/StylesUISyntax.ets new file mode 100644 index 000000000..8c1882152 --- /dev/null +++ b/compiler/test/transform_ut/application/entry/src/main/ets/pages/utForValidate/Decorators/process_ui_syntax/StylesUISyntax.ets @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022-2024 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. + */ +@Styles +function stylesOne() { + .width(100) + console.log(`this is a function`); +} + +@Styles +function stylesTwo() { + .height(200) +} + +@Entry +@ComponentV2 +struct testStylesV2 { + @Styles + innerStylesOne() { + .width(100) + console.log(`method`); + } + + build() { + Column() { + } + } +} + +@Component +struct testStyles { + @Styles + innerStyles(){ + if(true){ + .width(100) + } + } + + build() { + Row(){ + + } + } +} \ No newline at end of file diff --git a/compiler/test/transform_ut/helpers/pathConfig.ts b/compiler/test/transform_ut/helpers/pathConfig.ts index fe2c744d8..98a015267 100644 --- a/compiler/test/transform_ut/helpers/pathConfig.ts +++ b/compiler/test/transform_ut/helpers/pathConfig.ts @@ -285,6 +285,7 @@ export const UT_VALIDATE_PAGES: string[] = [ 'Decorators/process_ui_syntax/NotSupportResrcParam', 'Decorators/process_ui_syntax/NotSupportResrcType', 'Decorators/process_ui_syntax/StylesNoParam', + 'Decorators/process_ui_syntax/StylesUISyntax', 'Decorators/process_ui_syntax/UnknownSrc', 'Decorators/process_ui_syntax/UnknownSrcName', 'Decorators/process_ui_syntax/UnknownSrcType', diff --git a/compiler/test/transform_ut_error.json b/compiler/test/transform_ut_error.json index 222e4ec13..91dec88b0 100644 --- a/compiler/test/transform_ut_error.json +++ b/compiler/test/transform_ut_error.json @@ -364,6 +364,20 @@ "type": "ERROR", "code": "10905105" }, + "StylesUISyntax": [ + { + "message": "Only UI component syntax can be written here.", + "type": "WARN" + }, + { + "message": "Only UI component syntax can be written here.", + "type": "WARN" + }, + { + "message": "Only UI component syntax can be written here.", + "type": "WARN" + } + ], "ExceededPreview": { "message": "A page can contain at most 10 '@Preview' decorators.", "type": "ERROR", -- Gitee From 6d83136cef6581b58b925f4c45ee81523d84c0c9 Mon Sep 17 00:00:00 2001 From: liyancheng2 Date: Thu, 21 Aug 2025 11:27:26 +0800 Subject: [PATCH 22/31] fix types incremental about xts test and tdd test Issue: https://gitee.com/openharmony/developtools_ace_ets2bundle/issues/ICTZZ6 Signed-off-by: liyancheng2 Change-Id: I26209fbb997f6426d709c05e0ebad2166c91933a Signed-off-by: liyancheng2 --- compiler/src/ets_checker.ts | 39 ++++++-- compiler/src/interop/src/ets_checker.ts | 39 ++++++-- .../test/ark_compiler_ut/ets_checker.test.ts | 96 ++++++++++++++++++- 3 files changed, 155 insertions(+), 19 deletions(-) diff --git a/compiler/src/ets_checker.ts b/compiler/src/ets_checker.ts index f20968572..8ad8a7c17 100644 --- a/compiler/src/ets_checker.ts +++ b/compiler/src/ets_checker.ts @@ -110,6 +110,7 @@ export interface LanguageServiceCache { service?: ts.LanguageService; pkgJsonFileHash?: string; targetESVersion?: ts.ScriptTarget; + types?: string[]; maxFlowDepth?: number; preTsImportSendable?: boolean; preSkipOhModulesLint?: boolean; @@ -447,28 +448,31 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi let service: ts.LanguageService | undefined = cache?.service; const currentHash: string | undefined = rollupShareObject?.projectConfig?.pkgJsonFileHash; const currentTargetESVersion: ts.ScriptTarget = compilerOptions.target; + const currentTypes: string[] | undefined = compilerOptions.types; const currentMaxFlowDepth: number | undefined = compilerOptions.maxFlowDepth; const lastHash: string | undefined = cache?.pkgJsonFileHash; const lastTargetESVersion: ts.ScriptTarget | undefined = cache?.targetESVersion; + const lastTypes: string[] | undefined = cache?.types; const lastMaxFlowDepth: number | undefined = cache?.maxFlowDepth; const hashDiffers: boolean | undefined = currentHash && lastHash && currentHash !== lastHash; const shouldRebuildForDepDiffers: boolean | undefined = reuseLanguageServiceForDepChange ? (hashDiffers && !rollupShareObject?.depInfo?.enableIncre) : hashDiffers; const targetESVersionDiffers: boolean | undefined = lastTargetESVersion && currentTargetESVersion && lastTargetESVersion !== currentTargetESVersion; + const typesDiff: boolean | undefined = lastTypes && currentTypes && !areEqualArrays(lastTypes, currentTypes); const maxFlowDepthDiffers: boolean | undefined = lastMaxFlowDepth && currentMaxFlowDepth && lastMaxFlowDepth !== currentMaxFlowDepth; const tsImportSendableDiff: boolean = checkValueDiff(cache?.preTsImportSendable, tsImportSendable); const skipOhModulesLintDiff: boolean = checkValueDiff(cache?.preSkipOhModulesLint, skipOhModulesLint); const enableStrictCheckOHModuleDiff: boolean = checkValueDiff(cache?.preEnableStrictCheckOHModule, enableStrictCheckOHModule); const mixCompileDiff: boolean = checkValueDiff(cache?.preMixCompile, mixCompile); - const shouldRebuild: boolean | undefined = shouldRebuildForDepDiffers || targetESVersionDiffers || - tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || enableStrictCheckOHModuleDiff || mixCompileDiff; + const onlyDeleteBuildInfoCache: boolean | undefined = tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || + enableStrictCheckOHModuleDiff || mixCompileDiff || typesDiff; + const shouldRebuild: boolean | undefined = shouldRebuildForDepDiffers || targetESVersionDiffers || onlyDeleteBuildInfoCache; if (reuseLanguageServiceForDepChange && hashDiffers && rollupShareObject?.depInfo?.enableIncre) { needReCheckForChangedDepUsers = true; } if (!service || shouldRebuild) { - rebuildProgram(targetESVersionChanged, tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || - enableStrictCheckOHModuleDiff || mixCompileDiff); + rebuildProgram(targetESVersionDiffers, onlyDeleteBuildInfoCache); service = ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); } else { // Found language service from cache, update root files @@ -480,6 +484,7 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi service: service, pkgJsonFileHash: currentHash, targetESVersion: currentTargetESVersion, + types: currentTypes, maxFlowDepth: currentMaxFlowDepth, preTsImportSendable: tsImportSendable, preSkipOhModulesLint: skipOhModulesLint, @@ -499,13 +504,33 @@ function checkValueDiff(cacheValue: boolean | undefined, currentValue: boolean): return !(cacheValue === undefined && !currentValue) && cacheValue !== currentValue; } -function rebuildProgram(targetESVersionDiffers: boolean, languageSwithchDiffers: boolean): void { +export function areEqualArrays(lastArray: string[] | undefined, currentArray: string[] | undefined): boolean { + if (!lastArray || !currentArray) { + return lastArray === currentArray; + } + + const currentSet: Set = new Set(currentArray!); + const lastSet: Set = new Set(lastArray!); + + if (lastSet.size !== currentSet.size) { + return false; + } + + for (const item of lastSet) { + if (!currentSet.has(item)) { + return false; + } + } + return true; +} + +function rebuildProgram(targetESVersionDiffers: boolean | undefined, onlyDeleteBuildInfoCache: boolean | undefined): void { if (targetESVersionDiffers) { // If the targetESVersion is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); targetESVersionChanged = true; - } else if (languageSwithchDiffers) { - // When tsImportSendable or maxFlowDepth is changed, we need to delete the build info cahce files + } else if (onlyDeleteBuildInfoCache) { + // When tsImportSendable or types or maxFlowDepth or skipOhModuleslint or mixCompile is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); } } diff --git a/compiler/src/interop/src/ets_checker.ts b/compiler/src/interop/src/ets_checker.ts index 1e85db905..543618eb9 100644 --- a/compiler/src/interop/src/ets_checker.ts +++ b/compiler/src/interop/src/ets_checker.ts @@ -123,6 +123,7 @@ export interface LanguageServiceCache { service?: ts.LanguageService; pkgJsonFileHash?: string; targetESVersion?: ts.ScriptTarget; + types?: string[]; maxFlowDepth?: number; preTsImportSendable?: boolean; preSkipOhModulesLint?: boolean; @@ -467,28 +468,31 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi let service: ts.LanguageService | undefined = cache?.service; const currentHash: string | undefined = rollupShareObject?.projectConfig?.pkgJsonFileHash; const currentTargetESVersion: ts.ScriptTarget = compilerOptions.target; + const currentTypes: string[] | undefined = compilerOptions.types; const currentMaxFlowDepth: number | undefined = compilerOptions.maxFlowDepth; const lastHash: string | undefined = cache?.pkgJsonFileHash; const lastTargetESVersion: ts.ScriptTarget | undefined = cache?.targetESVersion; + const lastTypes: string[] | undefined = cache?.types; const lastMaxFlowDepth: number | undefined = cache?.maxFlowDepth; const hashDiffers: boolean | undefined = currentHash && lastHash && currentHash !== lastHash; const shouldRebuildForDepDiffers: boolean | undefined = reuseLanguageServiceForDepChange ? (hashDiffers && !rollupShareObject?.depInfo?.enableIncre) : hashDiffers; const targetESVersionDiffers: boolean | undefined = lastTargetESVersion && currentTargetESVersion && lastTargetESVersion !== currentTargetESVersion; + const typesDiff: boolean | undefined = lastTypes && currentTypes && !areEqualArrays(lastTypes, currentTypes); const maxFlowDepthDiffers: boolean | undefined = lastMaxFlowDepth && currentMaxFlowDepth && lastMaxFlowDepth !== currentMaxFlowDepth; const tsImportSendableDiff: boolean = checkValueDiff(cache?.preTsImportSendable, tsImportSendable); const skipOhModulesLintDiff: boolean = checkValueDiff(cache?.preSkipOhModulesLint, skipOhModulesLint); const enableStrictCheckOHModuleDiff: boolean = checkValueDiff(cache?.preEnableStrictCheckOHModule, enableStrictCheckOHModule); const mixCompileDiff: boolean = checkValueDiff(cache?.preMixCompile, mixCompile); - const shouldRebuild: boolean | undefined = shouldRebuildForDepDiffers || targetESVersionDiffers || - tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || enableStrictCheckOHModuleDiff || mixCompileDiff; + const onlyDeleteBuildInfoCache: boolean | undefined = tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || + enableStrictCheckOHModuleDiff || mixCompileDiff || typesDiff; + const shouldRebuild: boolean | undefined = shouldRebuildForDepDiffers || targetESVersionDiffers || onlyDeleteBuildInfoCache; if (reuseLanguageServiceForDepChange && hashDiffers && rollupShareObject?.depInfo?.enableIncre) { needReCheckForChangedDepUsers = true; } if (!service || shouldRebuild) { - rebuildProgram(targetESVersionDiffers, tsImportSendableDiff || maxFlowDepthDiffers || skipOhModulesLintDiff || - enableStrictCheckOHModuleDiff || mixCompileDiff); + rebuildProgram(targetESVersionDiffers, onlyDeleteBuildInfoCache); service = ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); } else { // Found language service from cache, update root files @@ -500,6 +504,7 @@ function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFi service: service, pkgJsonFileHash: currentHash, targetESVersion: currentTargetESVersion, + types: currentTypes, maxFlowDepth: currentMaxFlowDepth, preTsImportSendable: tsImportSendable, preSkipOhModulesLint: skipOhModulesLint, @@ -519,13 +524,33 @@ function checkValueDiff(cacheValue: boolean | undefined, currentValue: boolean): return !(cacheValue === undefined && !currentValue) && cacheValue !== currentValue; } -function rebuildProgram(targetESVersionDiffers: boolean, languageSwithchDiffers: boolean): void { +export function areEqualArrays(lastArray: string[] | undefined, currentArray: string[] | undefined): boolean { + if (!lastArray || !currentArray) { + return lastArray === currentArray; + } + + const currentSet: Set = new Set(currentArray!); + const lastSet: Set = new Set(lastArray!); + + if (lastSet.size !== currentSet.size) { + return false; + } + + for (const item of lastSet) { + if (!currentSet.has(item)) { + return false; + } + } + return true; +} + +function rebuildProgram(targetESVersionDiffers: boolean | undefined, onlyDeleteBuildInfoCache: boolean | undefined): void { if (targetESVersionDiffers) { // If the targetESVersion is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); targetESVersionChanged = true; - } else if (languageSwithchDiffers) { - // When tsImportSendable or maxFlowDepth is changed, we need to delete the build info cahce files + } else if (onlyDeleteBuildInfoCache) { + // When tsImportSendable or types or maxFlowDepth or skipOhModuleslint or mixCompile is changed, we need to delete the build info cahce files deleteBuildInfoCache(compilerOptions.tsBuildInfoFile); } } diff --git a/compiler/test/ark_compiler_ut/ets_checker.test.ts b/compiler/test/ark_compiler_ut/ets_checker.test.ts index b0dceb320..dd6d070a6 100644 --- a/compiler/test/ark_compiler_ut/ets_checker.test.ts +++ b/compiler/test/ark_compiler_ut/ets_checker.test.ts @@ -39,7 +39,8 @@ import { getMaxFlowDepth, MAX_FLOW_DEPTH_DEFAULT_VALUE, fileCache, - getFileContentWithHash + getFileContentWithHash, + areEqualArrays } from '../../lib/ets_checker'; import { TS_BUILD_INFO_SUFFIX } from '../../lib/pre_define'; import { @@ -216,12 +217,97 @@ mocha.describe('test ets_checker file api', function () { }); }); +mocha.describe('test areEqualArrays function', () => { + // test cases for basic functions + mocha.it('1-1: should return true for identical arrays', () => { + expect(areEqualArrays(['a', 'b', 'c'], ['a', 'b', 'c'])).to.equal(true); + }); + + mocha.it('1-2: should return true for arrays with same elements in different order', () => { + expect(areEqualArrays(['a', 'b', 'c'], ['c', 'a', 'b'])).to.equal(true); + }); + + mocha.it('1-3: should return false for arrays with different elements', () => { + expect(areEqualArrays(['a', 'b', 'c'], ['a', 'b', 'd'])).to.equal(false); + }); + + mocha.it('1-4: should return false for arrays with different lengths', () => { + expect(areEqualArrays(['a', 'b', 'c'], ['a', 'b'])).to.equal(false); + expect(areEqualArrays(['a', 'b'], ['a', 'b', 'c'])).to.equal(false); + }); + + // test cases for boundary conditions + mocha.it('1-5: should return true for empty arrays', () => { + expect(areEqualArrays([], [])).to.equal(true); + }); + + mocha.it('1-6: should return false when one array is empty and other is not', () => { + expect(areEqualArrays([], ['a'])).to.equal(false); + expect(areEqualArrays(['a'], [])).to.equal(false); + }); + + // test cases for null and undefined scenarios + mocha.it('1-7: should return true when both arrays are undefined', () => { + expect(areEqualArrays(undefined, undefined)).to.equal(true); + }); + + mocha.it('1-8: should return true when both arrays are null', () => { + expect(areEqualArrays(null as any, null as any)).to.equal(true); + }); + + mocha.it('1-9: should return false when one array is undefined and other is not', () => { + expect(areEqualArrays(undefined, ['a'])).to.equal(false); + expect(areEqualArrays(['a'], undefined)).to.equal(false); + }); + + mocha.it('1-10: should return false when one array is null and other is not', () => { + expect(areEqualArrays(null as any, ['a'])).to.equal(false); + expect(areEqualArrays(['a'], null as any)).to.equal(false); + }); + + // test cases for duplicate elements + mocha.it('1-11: should handle duplicate elements correctly', () => { + expect(areEqualArrays(['a', 'a', 'b'], ['a', 'b', 'a'])).to.equal(true); + expect(areEqualArrays(['a', 'a', 'b'], ['a', 'b', 'b'])).to.equal(true); + }); + + // test case sensitivity scenarios + mocha.it('1-12: should be case sensitive', () => { + expect(areEqualArrays(['A', 'B'], ['a', 'b'])).to.equal(false); + expect(areEqualArrays(['A', 'B'], ['A', 'B'])).to.equal(true); + }); + + // test cases for special value scenarios + mocha.it('1-13: should handle special values', () => { + expect(areEqualArrays(['', 'null'], ['', 'null'])).to.equal(true); + expect(areEqualArrays(['0', '1'], ['0', '1'])).to.equal(true); + }); + + // test cases for performance + mocha.it('1-14: should handle large arrays efficiently', () => { + const largeArray1 = Array(10000).fill('item'); + const largeArray2 = Array(10000).fill('item'); + + expect(areEqualArrays(largeArray1, largeArray2)).to.equal(true); + }); + + // test cases for the edge condition + mocha.it('1-15: should return false for arrays with same length but different content', () => { + expect(areEqualArrays(['a', 'b'], ['a', 'c'])).to.equal(false); + }); + + mocha.it('1-16: should return true for single element arrays', () => { + expect(areEqualArrays(['a'], ['a'])).to.equal(true); + expect(areEqualArrays(['a'], ['b'])).to.equal(false); + }); + }); + mocha.describe('getMaxFlowDepth', () => { mocha.it('1-1: test should return the default value when maxFlowDepth is undefined', () => { const result = getMaxFlowDepth(); expect(result).to.equal(MAX_FLOW_DEPTH_DEFAULT_VALUE); }); - + mocha.it('1-2: test should return the default value and log a warning when maxFlowDepth is less than the minimum valid value', () => { const invalidMaxFlowDepth = 1999; projectConfig.projectArkOption = { @@ -231,7 +317,7 @@ mocha.describe('getMaxFlowDepth', () => { } const result = getMaxFlowDepth(); expect(result).to.equal(MAX_FLOW_DEPTH_DEFAULT_VALUE); - }); + }); mocha.it('1-3: test should return the value of maxFlowDepth when it is 2000 within the valid range', () => { const validMaxFlowDepth = 2000; @@ -243,7 +329,7 @@ mocha.describe('getMaxFlowDepth', () => { const result = getMaxFlowDepth(); expect(result).to.equal(validMaxFlowDepth); }); - + mocha.it('1-4: test should return the value of maxFlowDepth when it is 3000 within the valid range', () => { const validMaxFlowDepth = 3000; projectConfig.projectArkOption = { @@ -265,7 +351,7 @@ mocha.describe('getMaxFlowDepth', () => { const result = getMaxFlowDepth(); expect(result).to.equal(validMaxFlowDepth); }); - + mocha.it('1-6: test should return the default value and log a warning when maxFlowDepth is greater than the maximum valid value', () => { const invalidMaxFlowDepth = 65536; projectConfig.projectArkOption = { -- Gitee From d53f5b2341376026ffef791b1704c12c5a689844 Mon Sep 17 00:00:00 2001 From: bulutcangocer Date: Fri, 5 Sep 2025 01:04:13 +0300 Subject: [PATCH 23/31] feat: added node validator for use cases like try, comparison, undefined part 1 Signed-off-by: bulutcangocer --- compiler/main.js | 22 ++ .../fast_build/system_api/api_check_utils.ts | 218 +++++++++++++----- 2 files changed, 188 insertions(+), 52 deletions(-) diff --git a/compiler/main.js b/compiler/main.js index c1e72c927..46bec5433 100644 --- a/compiler/main.js +++ b/compiler/main.js @@ -72,6 +72,8 @@ let sdkConfigPrefix = 'ohos|system|kit|arkts'; let ohosSystemModulePaths = []; let ohosSystemModuleSubDirPaths = []; let allModulesPaths = []; +let externalApiCheckPlugin = new Map(); + function initProjectConfig(projectConfig) { initProjectPathConfig(projectConfig); @@ -760,6 +762,19 @@ function filterWorker(workerPath) { sdkConfigs = [...defaultSdkConfigs, ...extendSdkConfigs]; })(); +function collectExternalApiCheckPlugin(sdkConfig, sdkPath) { + const pluginConfigs = sdkConfig.apiCheckPlugin; + pluginConfigs.forEach(config => { + const pluginPrefix = sdkConfig.osName + '/' + config.tag; + config.path = path.resolve(sdkPath, config.path); + if (externalApiCheckPlugin.get(pluginPrefix)) { + externalApiCheckPlugin.set(pluginPrefix, externalApiCheckPlugin.get(pluginPrefix).push(...pluginConfigs)); + } else { + externalApiCheckPlugin.set(pluginPrefix, [...pluginConfigs]); + } + }); +} + function collectExternalModules(sdkPaths) { for (let i = 0; i < sdkPaths.length; i++) { const sdkPath = sdkPaths[i]; @@ -771,6 +786,10 @@ function collectExternalModules(sdkPaths) { if (!sdkConfig.apiPath) { continue; } + + if (sdkConfig.apiCheckPlugin && sdkConfig.apiCheckPlugin.length > 0) { + collectExternalApiCheckPlugin(sdkConfig, sdkPath); + } let externalApiPathArray = []; if (Array.isArray(sdkConfig.apiPath)) { externalApiPathArray = sdkConfig.apiPath; @@ -1096,6 +1115,7 @@ function resetMain() { ohosSystemModulePaths = []; ohosSystemModuleSubDirPaths = []; allModulesPaths = []; + externalApiCheckPlugin = new Map(); } function resetAbilityConfig() { @@ -1186,3 +1206,5 @@ exports.resetGlobalProgram = resetGlobalProgram; exports.setEntryArrayForObf = setEntryArrayForObf; exports.getPackageJsonEntryPath = getPackageJsonEntryPath; exports.setIntentEntryPages = setIntentEntryPages; +exports.externalApiCheckPlugin = externalApiCheckPlugin; + diff --git a/compiler/src/fast_build/system_api/api_check_utils.ts b/compiler/src/fast_build/system_api/api_check_utils.ts index 71be695cd..421e98302 100644 --- a/compiler/src/fast_build/system_api/api_check_utils.ts +++ b/compiler/src/fast_build/system_api/api_check_utils.ts @@ -24,13 +24,15 @@ import { ohosSystemModulePaths, systemModules, allModulesPaths, - ohosSystemModuleSubDirPaths + ohosSystemModuleSubDirPaths, + externalApiCheckPlugin } from '../../../main'; import { LogType, LogInfo, IFileLog, - CurrentProcessFile + CurrentProcessFile, + compilerOptions } from '../../utils'; import { type ResolveModuleInfo } from '../../ets_checker'; import { @@ -73,6 +75,7 @@ import { VERSION_CHECK_FUNCTION_NAME } from './api_check_define'; import { JsDocCheckService } from './api_check_permission'; +import { SdkVersionValidator } from './sdk_version_validator'; /** * bundle info @@ -89,7 +92,7 @@ export interface CheckValidCallbackInterface { } export interface CheckJsDocSpecialValidCallbackInterface { - (jsDocTags: readonly ts.JSDocTag[], config: ts.JsDocNodeCheckConfigItem): boolean; + (jsDocTags: readonly ts.JSDocTag[], config: ts.JsDocNodeCheckConfigItem, node?: ts.Node): boolean; } export interface checkConditionValidCallbackInterface { @@ -545,55 +548,174 @@ function collectExternalSyscapInfos( } /** - * Determine the necessity of since check. + * Validates if a since tag requires version checking based on JSDoc and project configuration. * - * @param jsDocTags - * @param config - * @returns + * @param jsDocTags - Array of JSDoc tags to analyze + * @param config - Configuration object that will receive error messages + * @param node - Optional TypeScript node for additional validation + * @returns True if since check is required and validation fails, false otherwise */ -function checkSinceValue(jsDocTags: readonly ts.JSDocTag[], config: ts.JsDocNodeCheckConfigItem): boolean { +function checkSinceValue( + jsDocTags: readonly ts.JSDocTag[], + config: ts.JsDocNodeCheckConfigItem, + node?: ts.Node +): boolean { + // Validate basic input structure if (!jsDocTags[0]?.parent?.parent || !projectConfig.compatibleSdkVersion) { return false; } - const currentNode: HasJSDocNode = jsDocTags[0].parent.parent as HasJSDocNode; - if (!currentNode.jsDoc) { + + const jsDocNode = jsDocTags[0].parent.parent as HasJSDocNode; + if (!jsDocNode?.jsDoc) { + return false; + } + const apiMinVersion = getMinVersion(jsDocNode.jsDoc); + if (!apiMinVersion) { return false; } - const minSince: string = getMinVersion(currentNode.jsDoc); - const hasSince: boolean = minSince !== ''; - const compatibleSdkVersion: string = projectConfig.compatibleSdkVersion.toString(); - if (!isCompliantSince(minSince) || !isCompliantSince(compatibleSdkVersion)) { + const sourceFile = jsDocNode.getSourceFile(); + if (!sourceFile) { return false; } - if (hasSince && comparePointVersion(compatibleSdkVersion.toString(), minSince) === -1) { - config.message = SINCE_TAG_CHECK_ERROER.replace('$SINCE1', minSince).replace('$SINCE2', compatibleSdkVersion); + + // Perform version validation check + const versionChecker = getVersionValidationFunction(); + let projectTargetVersion: string; + if (versionChecker === compareVersionsWithPointSystem) { + projectTargetVersion = projectConfig.compatibleSdkVersion.toString(); + } else { + projectTargetVersion = projectConfig.originCompatibleSdkVersion?.toString() + || projectConfig.compatibleSdkVersion.toString(); + } + const validationResult = versionChecker(apiMinVersion, projectTargetVersion, 0); + if (validationResult.result) { + return false; + } + + // Check if SDK version is already properly handled in code + const typeChecker = CurrentProcessFile.getChecker(); + const sdkValidator = new SdkVersionValidator(projectTargetVersion, apiMinVersion, typeChecker); + + if (sdkValidator.isSdkApiVersionHandled(node)) { + return false; + } + + config.message = SINCE_TAG_CHECK_ERROER + .replace('$SINCE1', apiMinVersion) + .replace('$SINCE2', projectTargetVersion); + + return true; +} + +/** + * Retrieves the appropriate version validation function. + * First attempts to load external plugin validation, falls back to default if unavailable. + * + * @returns Version validation function (external or default) + */ +export function getVersionValidationFunction(): VersionValidationFunction { + const pluginKey = getPluginKey(projectConfig.runtimeOS, SINCE_TAG_NAME); + const plugins = externalApiCheckPlugin.get(pluginKey); + + // Check if external plugins exist and try to load them + if (plugins && plugins.length > 0) { + try { + for (const plugin of plugins) { + const externalMethod = require(plugin.path)[plugin.functionName]; + if (typeof externalMethod === 'function') { + return externalMethod; + } + } + } catch (error) { + console.warn(`Failed to load external version validator: ${error}`); + } + } + + return compareVersionsWithPointSystem; +} + +/** + * Default version comparison function using point-based version numbering. + * Validates version format and compares numerical values. + * + * @param sinceVersion - Minimum version requirement + * @param targetVersion - Current project target version + * @param _triggerScene - Trigger scene identifier (unused in default implementation) + * @returns Validation result with success status and optional message + */ +export function compareVersionsWithPointSystem( + sinceVersion: string, + targetVersion: string, + _triggerScene: number +): VersionValidationResult { + const versionFormatRegex = /^(?:\d{0,2}|\d\.\d\.\d)$/; + + // Validate version format + if (!versionFormatRegex.test(sinceVersion) || !versionFormatRegex.test(targetVersion)) { + return { + result: false, + message: "Invalid version number format" + }; + } + + // Compare version numbers + const sinceVersionNumber = getVersionNumber(sinceVersion); + const targetVersionNumber = getVersionNumber(targetVersion); + const isTargetGreater = sinceVersionNumber < targetVersionNumber; + + return { + result: isTargetGreater, + message: isTargetGreater ? "API version requirement not met" : "Version requirement satisfied" + }; +} + +/** + * Function signature for version validation. + * Takes two version strings and a trigger scene (0-1-2), returns validation result. + */ +export interface VersionValidationFunction { + (sinceVersion: string, targetVersion: string, triggerScene: number): VersionValidationResult; +} + +/** + * Result object returned by version validation functions. + */ +export interface VersionValidationResult { + result: boolean; + message?: string; +} + +/** + * 是否需要使用拓展SDK自定义校验接口 + * @param { string } pluginKey prefix/tagname + * @returns { boolean } + */ +function isExternalApiCheck(pluginKey: string): boolean { + if (externalApiCheckPlugin.get(pluginKey)) { return true; } return false; } /** - * Confirm compliance since - * Only major version can be passed in, such as "19"; - * major and minor version can be passed in, such as "19.1"; major minor and patch - * patch version can be passed in, such as "19.1.2" - * the major version be from 1-999 - * the minor version be from 0-999 - * the patch version be from 0-999 - * - * @param {string} since - * @return {boolean} + * 获取externalApiCheckPlugin的key + * @param { string } apiFilePath + * @param { string } tagName + * @returns { string } */ -function isCompliantSince(since: string): boolean { - return /^(?!0\d)[1-9]\d{0,2}(?:\.[1-9]\d{0,2}|\.0){0,2}$\d{0,2}$/.test(since); +function getPluginKey(apiFilePath: string, tagName: string): string { + const apiFileName: string = path.basename(apiFilePath); + const apiPrefix: string = apiFileName.split('.')[0]; + const pluginKey: string = apiPrefix + '/' + tagName; + return pluginKey; } /** * Determine the necessity of syscap check. - * @param jsDocTags - * @param config - * @returns + * @param jsDocTags + * @param config + * @returns */ export function checkSyscapAbility(jsDocTags: readonly ts.JSDocTag[], config: ts.JsDocNodeCheckConfigItem): boolean { let currentSyscapValue: string = ''; @@ -783,7 +905,7 @@ function checkSyscapConditionValidCallback(node: ts.CallExpression, specifyFuncN /** * get minversion - * @param { ts.JSDoc[] } jsDocs + * @param { ts.JSDoc[] } jsDocs * @returns string */ function getMinVersion(jsDocs: ts.JSDoc[]): string { @@ -803,25 +925,17 @@ function getMinVersion(jsDocs: ts.JSDoc[]): string { return minVersion; } -/** - * compare point version - * @param { string } firstVersion - * @param { string } secondVersion - * @returns { number } - */ +function getVersionNumber(version: string): number { + const parenMatch = version.match(/\((\d+)\)/); + if (parenMatch) return parseInt(parenMatch[1], 10); + + const parts = version.split('.'); + return parseInt(parts[parts.length - 1], 10); +} + function comparePointVersion(firstVersion: string, secondVersion: string): number { - const firstPointVersion = firstVersion.split('.'); - const secondPointVersion = secondVersion.split('.'); - for (let i = 0; i < 3; i++) { - const part1 = parseInt(firstPointVersion[i] || '0', 10); - const part2 = parseInt(secondPointVersion[i] || '0', 10); - - if (part1 < part2) { - return -1; - } - if (part1 > part2) { - return 1; - } - } - return 0; + const firstNum = getVersionNumber(firstVersion); + const secondNum = getVersionNumber(secondVersion); + + return firstNum > secondNum ? 1 : -1; } \ No newline at end of file -- Gitee From 9657001e7d512aff77feb3376a2834359060b97b Mon Sep 17 00:00:00 2001 From: bulutcangocer Date: Fri, 5 Sep 2025 01:04:23 +0300 Subject: [PATCH 24/31] feat: added node validator for use cases like try, comparison, undefined part 2 Signed-off-by: bulutcangocer --- .../system_api/sdk_version_validator.ts | 500 ++++++++++++++++++ 1 file changed, 500 insertions(+) create mode 100644 compiler/src/fast_build/system_api/sdk_version_validator.ts diff --git a/compiler/src/fast_build/system_api/sdk_version_validator.ts b/compiler/src/fast_build/system_api/sdk_version_validator.ts new file mode 100644 index 000000000..2b5169795 --- /dev/null +++ b/compiler/src/fast_build/system_api/sdk_version_validator.ts @@ -0,0 +1,500 @@ +/* + * 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 ts from 'typescript'; +import { + projectConfig +} from '../../../main'; +import { + VersionValidationResult, + VersionValidationFunction, + compareVersionsWithPointSystem, + getVersionValidationFunction +} from './api_check_utils' + +/** + * The node is considered **valid** if it satisfies **at least one** of the following: + * 1. It is wrapped in a `try/catch` block. + * 2. It is wrapped in an `undefined` check. + * 3. It is wrapped in an SDK version comparison. + */ +export class SdkVersionValidator { + private readonly compatibleSdkVersion: string; + private readonly minSinceVersion: string; + private readonly closeSourceDeviceInfo: string = "distributionOSApiVersion"; + private readonly openSourceDeviceInfo: string = "sdkApiVersion"; + private readonly openSourceRuntime: string = "OpenHarmony"; + private readonly deviceInfoChecker: Map = new Map([ + [this.closeSourceDeviceInfo, ['@ohos.deviceInfo.d.ts']], + [this.openSourceDeviceInfo, ['@ohos.deviceInfo.d.ts']] +]); + private readonly typeChecker?: ts.TypeChecker; + + + constructor(projectCompatibleSdkVersion: string, minSinceValue: string, typeChecker?: ts.TypeChecker) { + this.compatibleSdkVersion = projectCompatibleSdkVersion; + this.minSinceVersion = minSinceValue; + this.typeChecker = typeChecker; + } + + /** + * Checks whether a given node is valid for at least one condition. + * @param node - The AST node to check. + * @returns `true` if the node meets any of the handling rules, otherwise `false`. + */ + public isSdkApiVersionHandled(node: ts.Node): boolean { + if (!node) { + return false; + } + + return ( + this.isNodeWrappedInTryCatch(node) || + this.isNodeWrappedInUndefinedCheck(node) || + this.isNodeWrappedInSdkComparison(node) + ); + } + + private isNodeWrappedInTryCatch(node: ts.Node): boolean { + return this.findParentNode(node, (parent) => { + if (ts.isTryStatement(parent)) { + return node.getStart() >= parent.tryBlock.getStart(); + } + return false; + }) !== null; + } + + private isNodeWrappedInUndefinedCheck(node: ts.Node): boolean { + const targetName = this.getPrimaryNameFromNode(node); + if (!targetName) { + return false; + } + + return this.findParentNode(node, (parent) => { + if (ts.isIfStatement(parent)) { + return this.isUndefinedCheckHelper(parent.expression, targetName); + } + return false; + }) !== null; + } + + private isUndefinedCheckHelper(expression: ts.Expression, name: string): boolean { + if (!ts.isBinaryExpression(expression)) { + return false; + } + + // Check if the operator is a "not equal" comparison (!== or !=) + const isNotEqualOperator = [ + ts.SyntaxKind.ExclamationEqualsEqualsToken, + ts.SyntaxKind.ExclamationEqualsToken + ].includes(expression.operatorToken.kind); + + if (!isNotEqualOperator) { + return false; + } + + const { left, right } = expression; + + // Determine if either side is the literal "undefined" + const isLeftUndefined = this.isUndefinedNode(left); + const isRightUndefined = this.isUndefinedNode(right); + + const isLeftTarget = this.isTargetNode(left, name); + const isRightTarget = this.isTargetNode(right, name); + return (isLeftTarget && isRightUndefined) || (isLeftUndefined && isRightTarget); + } + + private isUndefinedNode(node: ts.Node): boolean { + return ts.isIdentifier(node) && node.text === 'undefined'; + } + + private isNodeWrappedInSdkComparison(node: ts.Node): boolean { + if (this.compatibleSdkVersion === '' || !this.typeChecker) { + return false; + } + + return this.findParentNode(node, (parent) => { + if (ts.isIfStatement(parent)) { + try { + const isInThenBlock = this.isNodeInIfThenBlock(node, parent); + if (!isInThenBlock) { + return false; + } + + const sdkComparisonResult = this.isSdkComparisonHelper(parent.expression); + return sdkComparisonResult; + } catch (error) { + return false; + } + } + return false; + }) !== null; + } + + private isSdkComparisonHelper(expression: ts.Expression): boolean { + const expressionText = expression.getText(); + + const runtimeType = projectConfig.runtimeOS; + const matchedEntry = Array.from(this.deviceInfoChecker.entries()) + .find(([api]) => expressionText.includes(api)); + if (!matchedEntry) { + return false; + } + + const [matchedApi, validPackagePaths] = matchedEntry; + if (runtimeType === this.openSourceRuntime && matchedApi === this.closeSourceDeviceInfo) { + return false; + } + + const parts = this.extractComparisonParts(expression, matchedApi); + if (!parts) { + return false + } + + if (!this.validateSdkVersionCompatibility(parts.operator, parts.value, matchedApi, runtimeType)){ + return false + } + + // Try to resolve the actual identifier used for this API in the expression + const apiIdentifier = this.findValidImportApiIdentifier(expression, matchedApi); + + // Validate that the identifier comes from one of the allowed SDK package paths + return apiIdentifier + ? this.isValidSdkDeclaration(apiIdentifier, validPackagePaths) + : false; + } + +/** + * Extracts comparison parts from a binary expression and resolves declaration values. + * If the comparison value has a declaration (e.g., variable/constant), returns the declaration value. + * + * @param expression - The binary expression to analyze + * @param matchedApi - The API identifier to match against + * @returns Object with operator and resolved value, or undefined if invalid + */ +private extractComparisonParts( + expression: ts.Expression, + matchedApi: string +): { operator: string; value: string } | undefined { + if (!ts.isBinaryExpression(expression)) { + return undefined; + } + + const operator = expression.operatorToken.getText(); + const left = expression.left.getText(); + const right = expression.right.getText(); + + let targetValue: string; + let valueExpression: ts.Expression; + + // Determine which side contains the API and get the comparison value + if (left.includes(matchedApi)) { + targetValue = right; + valueExpression = expression.right; + } else if (right.includes(matchedApi)) { + targetValue = left; + valueExpression = expression.left; + } else { + return undefined; + } + + // Try to resolve declaration value if it exists + const resolvedValue = this.resolveDeclarationValue(valueExpression, targetValue); + + return { operator, value: resolvedValue }; +} + +/** + * Resolves the declaration value of an expression if it exists. + * If the expression is a variable/constant reference, returns its declared value. + * Otherwise, returns the original text value. + * + * @param expression - The expression to resolve + * @param fallbackValue - The fallback text value if resolution fails + * @returns The resolved declaration value or fallback value + */ +private resolveDeclarationValue(expression: ts.Expression, fallbackValue: string): string { + if (!this.typeChecker) { + return fallbackValue; + } + + try { + // Only resolve if the expression is an identifier (variable/constant reference) + if (!ts.isIdentifier(expression)) { + return fallbackValue; + } + + const symbol = this.typeChecker.getSymbolAtLocation(expression); + if (!symbol?.declarations?.length) { + return fallbackValue; + } + + const declaration = symbol.declarations[0]; + + // Handle variable declarations with initializers + if (ts.isVariableDeclaration(declaration) && declaration.initializer) { + return this.extractValueFromInitializer(declaration.initializer); + } + + // Handle const assertions and other declaration types + if (ts.isBindingElement(declaration) && declaration.initializer) { + return this.extractValueFromInitializer(declaration.initializer); + } + + return fallbackValue; + } catch (error) { + // If resolution fails, return the original value + return fallbackValue; + } +} + +/** + * Extracts the actual value from a variable initializer expression. + * Handles literals, numeric values, and string values. + * + * @param initializer - The initializer expression + * @returns The extracted value as string + */ +private extractValueFromInitializer(initializer: ts.Expression): string { + // Handle numeric literals + if (ts.isNumericLiteral(initializer)) { + return initializer.text; + } + + // Handle string literals (remove quotes) + if (ts.isStringLiteral(initializer)) { + return initializer.text; + } + + // Handle boolean literals + if (initializer.kind === ts.SyntaxKind.TrueKeyword) { + return 'true'; + } + if (initializer.kind === ts.SyntaxKind.FalseKeyword) { + return 'false'; + } + + // Handle other expression types by returning their text + return initializer.getText(); +} + +/** Validates SDK version compatibility by comparing operator, value, and API type. + * + * @param operator - Comparison operator from the expression + * @param value - Version value to compare against + * @param matchedApi - The matched API identifier + * @param runtimeType - Runtime environment type (HarmonyOS or OpenHarmony) + * @returns True if SDK version is compatible, false otherwise + */ +private validateSdkVersionCompatibility( + operator: string, + value: string, + matchedApi: string, + runtimeType: string +): boolean { + // Handle OpenHarmony runtime with direct comparison + if (runtimeType === this.openSourceRuntime) { + return this.sdkOpenSourceComparison(operator, value, matchedApi); + } + + const versionChecker = getVersionValidationFunction(); + const triggerScene = matchedApi === this.openSourceDeviceInfo ? 1 : 2; + + const validationResult = versionChecker(this.minSinceVersion, value, triggerScene); + return validationResult.result; +} + +/** + * Compares SDK version with open source device info to determine if version check is valid. + * + * Logic: If the condition ensures that the SDK version meets or exceeds the minimum required version, + * then the check is considered valid (returns true). + * + * Examples: + * - deviceInfo.sdkApiVersion > 15 with sinceVersion 16: Valid (ensures >= 16) + * - deviceInfo.sdkApiVersion < 16 with sinceVersion 16: Invalid (ensures < 16, not meeting requirement) + * - deviceInfo.sdkApiVersion >= 16 with sinceVersion 16: Valid (ensures >= 16) + * + * @param operator - Comparison operator from the condition + * @param value - The value being compared against in the condition + * @param matchedApi - The matched API identifier + * @returns True if the condition ensures minimum version requirement is met + */ +private sdkOpenSourceComparison(operator: string, value: string, matchedApi: string): boolean { + const minRequiredVersion = Number(this.minSinceVersion); + const comparisonValue = Number(value); + + switch (operator) { + case ">": + // deviceInfo.sdkApiVersion > 15 with sinceVersion 16 + // Ensures SDK version is at least 16 (15 + 1), so valid + return comparisonValue >= minRequiredVersion - 1; + + case ">=": + // deviceInfo.sdkApiVersion >= 16 with sinceVersion 16 + // Ensures SDK version is at least 16, so valid + return comparisonValue >= minRequiredVersion; + + case "<": + // deviceInfo.sdkApiVersion < 16 with sinceVersion 16 + // Ensures SDK version is less than 16, so invalid (doesn't meet requirement) + return false; + + case "<=": + // deviceInfo.sdkApiVersion <= 15 with sinceVersion 16 + // Ensures SDK version is at most 15, so invalid (doesn't meet requirement) + return false; + + case "==": + case "===": + // deviceInfo.sdkApiVersion === 16 with sinceVersion 16 + // Ensures SDK version is exactly 16, so valid if matches or exceeds requirement + return comparisonValue >= minRequiredVersion; + + case "!=": + case "!==": + // deviceInfo.sdkApiVersion !== 15 with sinceVersion 16 + // This doesn't guarantee meeting the requirement, so invalid + return false; + + default: + throw new Error(`Unsupported operator: ${operator}`); + } +} + + private findValidImportApiIdentifier(expression: ts.Expression, api: string): ts.Identifier | undefined { + if (ts.isBinaryExpression(expression)) { + return this.extractApiIdentifierFromExpression(expression.left, api) || + this.extractApiIdentifierFromExpression(expression.right, api); + } + return this.extractApiIdentifierFromExpression(expression, api); + } + + private extractApiIdentifierFromExpression( + expression: ts.Expression, + targetProperty: string + ): ts.Identifier | undefined { + if (!ts.isPropertyAccessExpression(expression)) { + return undefined; + } + if (expression.name.text !== targetProperty) { + return undefined; + } + return this.getRootIdentifier(expression.expression); + } + + private getRootIdentifier(expression: ts.Expression): ts.Identifier | undefined { + let current: ts.Expression = expression; + while (ts.isPropertyAccessExpression(current)) { + current = current.expression; + } + return ts.isIdentifier(current) ? current : undefined; + } + + private isValidSdkDeclaration(identifier: ts.Identifier, validPackagePaths: string[]): boolean { + if (!this.typeChecker) { + return false; + } + const symbol = this.typeChecker.getSymbolAtLocation(identifier); + if (!symbol) { + return false; + } + const declarationFile = this.getActualDeclarationFile(symbol); + return declarationFile ? + this.isValidSdkDeclarationPath(declarationFile, validPackagePaths) : + false; + } + + private getActualDeclarationFile(symbol: ts.Symbol): string | undefined { + if (!this.typeChecker) { + return undefined; + } + const targetSymbol = this.typeChecker.getAliasedSymbol(symbol); + const actualSymbol = targetSymbol !== symbol ? targetSymbol : symbol; + if (!actualSymbol.declarations?.length) { + return undefined; + } + const declarationFile = actualSymbol.declarations[0].getSourceFile().fileName; + + // This regex removes the leading path up to and including the last "sdk//" or "sdk\\" + // before the "@", leaving only the part starting from the package name. + return declarationFile.replace(/^.*sdk[\\/].*[\\/](?=@)/, ''); + } + + private isValidSdkDeclarationPath(filePath: string, validPackagePaths: string[]): boolean { + const normalizedPath = this.normalizePath(filePath); + return validPackagePaths.some(validPath => + normalizedPath.includes(this.normalizePath(validPath)) + ); + } + + private normalizePath(path: string): string { + return path.replace(/\\/g, '/').toLowerCase(); + } + + private isNodeInIfThenBlock(node: ts.Node, ifStatement: ts.IfStatement): boolean { + if (!ifStatement.thenStatement) { + return false; + } + + const nodeStart = node.getStart(); + const nodeEnd = node.getEnd(); + const thenStart = ifStatement.thenStatement.getStart(); + const thenEnd = ifStatement.thenStatement.getEnd(); + const isInRange = nodeStart >= thenStart && nodeEnd <= thenEnd; + return isInRange; + } + + /** + * Traverses upward in the AST from the given node to find the first parent + * that satisfies the provided predicate function. + * + * @param node - The starting AST node. + * @param predicate - A function that returns `true` for the desired parent node. + * @returns The first matching parent node, or `null` if none is found. + */ + private findParentNode( + node: ts.Node, + predicate: (parent: ts.Node) => boolean + ): ts.Node | null { + let currentNode = node.parent; + + // Walk up the AST until we reach the root or find a match + while (currentNode) { + if (predicate(currentNode)) { + return currentNode; + } + currentNode = currentNode.parent; + } + return null; + } + + private getPrimaryNameFromNode(node: ts.Node): string | undefined { + if (ts.isIdentifier(node)) { + return node.text; + } + if (ts.isCallExpression(node)) { + return this.getPrimaryNameFromNode(node.expression); + } + if (ts.isPropertyAccessExpression(node)) { + return node.name.text; + } + return undefined; + } + + private isTargetNode(node: ts.Node, name: string): boolean { + const nodePrimaryName = this.getPrimaryNameFromNode(node); + return nodePrimaryName === name; + } +} -- Gitee From 6c13ca132f4c3f204ada9ba232d2ecf41509962b Mon Sep 17 00:00:00 2001 From: xieziang Date: Sat, 6 Sep 2025 14:19:20 +0800 Subject: [PATCH 25/31] add koala_wrapper(toolchain_linux) to sub_component Signed-off-by: xieziang Change-Id: I8af1ddc7118be15d429d06aedbe874a3b556517d --- bundle.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bundle.json b/bundle.json index db3e1fcbf..3754e3cfc 100644 --- a/bundle.json +++ b/bundle.json @@ -35,7 +35,8 @@ "//developtools/ace_ets2bundle:server", "//developtools/ace_ets2bundle:codegen", "//developtools/ace_ets2bundle:ets_loader_declaration", - "//developtools/ace_ets2bundle:ets_loader_ark_hap" + "//developtools/ace_ets2bundle:ets_loader_ark_hap", + "//developtools/ace_ets2bundle/koala-wrapper:ohos_ets_koala_wrapper(//build/toolchain/linux:clang_x64)" ], "inner_kits": [ { -- Gitee From 7da928366c24bcd033ed7b7506ef666902143544 Mon Sep 17 00:00:00 2001 From: bulutcangocer Date: Fri, 5 Sep 2025 19:57:51 +0300 Subject: [PATCH 26/31] refactor: comments fixed Signed-off-by: bulutcangocer --- .../fast_build/system_api/api_check_utils.ts | 86 ++-- .../system_api/sdk_version_validator.ts | 451 ++++++++++-------- 2 files changed, 299 insertions(+), 238 deletions(-) diff --git a/compiler/src/fast_build/system_api/api_check_utils.ts b/compiler/src/fast_build/system_api/api_check_utils.ts index 421e98302..09ac5201d 100644 --- a/compiler/src/fast_build/system_api/api_check_utils.ts +++ b/compiler/src/fast_build/system_api/api_check_utils.ts @@ -32,7 +32,6 @@ import { LogInfo, IFileLog, CurrentProcessFile, - compilerOptions } from '../../utils'; import { type ResolveModuleInfo } from '../../ets_checker'; import { @@ -615,6 +614,9 @@ function checkSinceValue( * @returns Version validation function (external or default) */ export function getVersionValidationFunction(): VersionValidationFunction { + if (projectConfig.originCompatibleSdkVersion?.toString() === undefined) { + return compareVersionsWithPointSystem; + } const pluginKey = getPluginKey(projectConfig.runtimeOS, SINCE_TAG_NAME); const plugins = externalApiCheckPlugin.get(pluginKey); @@ -649,23 +651,17 @@ export function compareVersionsWithPointSystem( targetVersion: string, _triggerScene: number ): VersionValidationResult { - const versionFormatRegex = /^(?:\d{0,2}|\d\.\d\.\d)$/; - // Validate version format - if (!versionFormatRegex.test(sinceVersion) || !versionFormatRegex.test(targetVersion)) { + if (!isCompliantSince(sinceVersion) || !isCompliantSince(targetVersion)) { return { - result: false, + result: true, message: "Invalid version number format" }; } - - // Compare version numbers - const sinceVersionNumber = getVersionNumber(sinceVersion); - const targetVersionNumber = getVersionNumber(targetVersion); - const isTargetGreater = sinceVersionNumber < targetVersionNumber; + const isTargetGreater = comparePointVersion(targetVersion, sinceVersion); return { - result: isTargetGreater, + result: isTargetGreater == 1, message: isTargetGreater ? "API version requirement not met" : "Version requirement satisfied" }; } @@ -686,18 +682,6 @@ export interface VersionValidationResult { message?: string; } -/** - * 是否需要使用拓展SDK自定义校验接口 - * @param { string } pluginKey prefix/tagname - * @returns { boolean } - */ -function isExternalApiCheck(pluginKey: string): boolean { - if (externalApiCheckPlugin.get(pluginKey)) { - return true; - } - return false; -} - /** * 获取externalApiCheckPlugin的key * @param { string } apiFilePath @@ -711,11 +695,27 @@ function getPluginKey(apiFilePath: string, tagName: string): string { return pluginKey; } +/** + * Confirm compliance since + * Only major version can be passed in, such as "19"; + * major and minor version can be passed in, such as "19.1"; major minor and patch + * patch version can be passed in, such as "19.1.2" + * the major version be from 1-999 + * the minor version be from 0-999 + * the patch version be from 0-999 + * + * @param {string} since + * @return {boolean} + */ +function isCompliantSince(since: string): boolean { + return /^(?!0\d)[1-9]\d{0,2}(?:\.[1-9]\d{0,2}|\.0){0,2}$\d{0,2}$/.test(since); +} + /** * Determine the necessity of syscap check. - * @param jsDocTags - * @param config - * @returns + * @param jsDocTags + * @param config + * @returns */ export function checkSyscapAbility(jsDocTags: readonly ts.JSDocTag[], config: ts.JsDocNodeCheckConfigItem): boolean { let currentSyscapValue: string = ''; @@ -905,7 +905,7 @@ function checkSyscapConditionValidCallback(node: ts.CallExpression, specifyFuncN /** * get minversion - * @param { ts.JSDoc[] } jsDocs + * @param { ts.JSDoc[] } jsDocs * @returns string */ function getMinVersion(jsDocs: ts.JSDoc[]): string { @@ -925,17 +925,25 @@ function getMinVersion(jsDocs: ts.JSDoc[]): string { return minVersion; } -function getVersionNumber(version: string): number { - const parenMatch = version.match(/\((\d+)\)/); - if (parenMatch) return parseInt(parenMatch[1], 10); - - const parts = version.split('.'); - return parseInt(parts[parts.length - 1], 10); -} - +/** + * compare point version + * @param { string } firstVersion + * @param { string } secondVersion + * @returns { number } + */ function comparePointVersion(firstVersion: string, secondVersion: string): number { - const firstNum = getVersionNumber(firstVersion); - const secondNum = getVersionNumber(secondVersion); - - return firstNum > secondNum ? 1 : -1; + const firstPointVersion = firstVersion.split('.'); + const secondPointVersion = secondVersion.split('.'); + for (let i = 0; i < 3; i++) { + const part1 = parseInt(firstPointVersion[i] || '0', 10); + const part2 = parseInt(secondPointVersion[i] || '0', 10); + + if (part1 < part2) { + return -1; + } + if (part1 > part2) { + return 1; + } + } + return 0; } \ No newline at end of file diff --git a/compiler/src/fast_build/system_api/sdk_version_validator.ts b/compiler/src/fast_build/system_api/sdk_version_validator.ts index 2b5169795..9cc9f370d 100644 --- a/compiler/src/fast_build/system_api/sdk_version_validator.ts +++ b/compiler/src/fast_build/system_api/sdk_version_validator.ts @@ -18,9 +18,6 @@ import { projectConfig } from '../../../main'; import { - VersionValidationResult, - VersionValidationFunction, - compareVersionsWithPointSystem, getVersionValidationFunction } from './api_check_utils' @@ -144,234 +141,290 @@ export class SdkVersionValidator { private isSdkComparisonHelper(expression: ts.Expression): boolean { const expressionText = expression.getText(); - - const runtimeType = projectConfig.runtimeOS; + + const runtimeType = projectConfig.runtimeOS; const matchedEntry = Array.from(this.deviceInfoChecker.entries()) - .find(([api]) => expressionText.includes(api)); + .find(([api]) => expressionText.includes(api)); if (!matchedEntry) { return false; } - - const [matchedApi, validPackagePaths] = matchedEntry; + + const [matchedApi, validPackagePath] = matchedEntry; if (runtimeType === this.openSourceRuntime && matchedApi === this.closeSourceDeviceInfo) { return false; } - + const parts = this.extractComparisonParts(expression, matchedApi); if (!parts) { return false } - - if (!this.validateSdkVersionCompatibility(parts.operator, parts.value, matchedApi, runtimeType)){ + + if (!this.validateSdkVersionCompatibility(parts.operator, parts.value, matchedApi, runtimeType, parts.apiPosition)) { return false } - + // Try to resolve the actual identifier used for this API in the expression const apiIdentifier = this.findValidImportApiIdentifier(expression, matchedApi); - - // Validate that the identifier comes from one of the allowed SDK package paths + + // Validate that the identifier comes from the allowed SDK package path return apiIdentifier - ? this.isValidSdkDeclaration(apiIdentifier, validPackagePaths) - : false; - } - -/** - * Extracts comparison parts from a binary expression and resolves declaration values. - * If the comparison value has a declaration (e.g., variable/constant), returns the declaration value. - * - * @param expression - The binary expression to analyze - * @param matchedApi - The API identifier to match against - * @returns Object with operator and resolved value, or undefined if invalid - */ -private extractComparisonParts( - expression: ts.Expression, - matchedApi: string -): { operator: string; value: string } | undefined { - if (!ts.isBinaryExpression(expression)) { - return undefined; - } - - const operator = expression.operatorToken.getText(); - const left = expression.left.getText(); - const right = expression.right.getText(); - - let targetValue: string; - let valueExpression: ts.Expression; - - // Determine which side contains the API and get the comparison value - if (left.includes(matchedApi)) { - targetValue = right; - valueExpression = expression.right; - } else if (right.includes(matchedApi)) { - targetValue = left; - valueExpression = expression.left; - } else { - return undefined; + ? this.isValidSdkDeclaration(apiIdentifier, validPackagePath) + : false; } - - // Try to resolve declaration value if it exists - const resolvedValue = this.resolveDeclarationValue(valueExpression, targetValue); - - return { operator, value: resolvedValue }; -} - -/** - * Resolves the declaration value of an expression if it exists. - * If the expression is a variable/constant reference, returns its declared value. - * Otherwise, returns the original text value. - * - * @param expression - The expression to resolve - * @param fallbackValue - The fallback text value if resolution fails - * @returns The resolved declaration value or fallback value - */ -private resolveDeclarationValue(expression: ts.Expression, fallbackValue: string): string { - if (!this.typeChecker) { - return fallbackValue; + + /** + * Extracts comparison parts from a binary expression and resolves declaration values. + * Also determines which side of the comparison contains the API. + * + * @param expression - The binary expression to analyze + * @param matchedApi - The API identifier to match against + * @returns Object with operator, resolved value, and API position, or undefined if invalid + */ + private extractComparisonParts( + expression: ts.Expression, + matchedApi: string + ): { operator: string; value: string; apiPosition: 'left' | 'right' } | undefined { + if (!ts.isBinaryExpression(expression)) { + return undefined; + } + + const operator = expression.operatorToken.getText(); + const left = expression.left.getText(); + const right = expression.right.getText(); + + let targetValue: string; + let valueExpression: ts.Expression; + let apiPosition: 'left' | 'right'; + + // Determine which side contains the API and get the comparison value + if (left.includes(matchedApi)) { + targetValue = right; + valueExpression = expression.right; + apiPosition = 'left'; + } else if (right.includes(matchedApi)) { + targetValue = left; + valueExpression = expression.left; + apiPosition = 'right'; + } else { + return undefined; + } + + // Try to resolve declaration value if it exists + const resolvedValue = this.resolveDeclarationValue(valueExpression, targetValue); + + return { operator, value: resolvedValue, apiPosition }; } - - try { - // Only resolve if the expression is an identifier (variable/constant reference) - if (!ts.isIdentifier(expression)) { + + /** + * Resolves the declaration value of an expression if it exists. + * If the expression is a variable/constant reference, returns its declared value. + * Otherwise, returns the original text value. + * + * @param expression - The expression to resolve + * @param fallbackValue - The fallback text value if resolution fails + * @returns The resolved declaration value or fallback value + */ + private resolveDeclarationValue(expression: ts.Expression, fallbackValue: string): string { + if (!this.typeChecker) { return fallbackValue; } - - const symbol = this.typeChecker.getSymbolAtLocation(expression); - if (!symbol?.declarations?.length) { + + try { + // Only resolve if the expression is an identifier (variable/constant reference) + if (!ts.isIdentifier(expression)) { + return fallbackValue; + } + + const symbol = this.typeChecker.getSymbolAtLocation(expression); + if (!symbol?.declarations?.length) { + return fallbackValue; + } + + const declaration = symbol.declarations[0]; + + // Handle variable declarations with initializers + if (ts.isVariableDeclaration(declaration) && declaration.initializer) { + return this.extractValueFromInitializer(declaration.initializer); + } + + // Handle const assertions and other declaration types + if (ts.isBindingElement(declaration) && declaration.initializer) { + return this.extractValueFromInitializer(declaration.initializer); + } + + return fallbackValue; + } catch (error) { + // If resolution fails, return the original value return fallbackValue; } - - const declaration = symbol.declarations[0]; - - // Handle variable declarations with initializers - if (ts.isVariableDeclaration(declaration) && declaration.initializer) { - return this.extractValueFromInitializer(declaration.initializer); + } + + /** + * Extracts the actual value from a variable initializer expression. + * Handles literals, numeric values, and string values. + * + * @param initializer - The initializer expression + * @returns The extracted value as string + */ + private extractValueFromInitializer(initializer: ts.Expression): string { + // Handle numeric literals + if (ts.isNumericLiteral(initializer)) { + return initializer.text; } - - // Handle const assertions and other declaration types - if (ts.isBindingElement(declaration) && declaration.initializer) { - return this.extractValueFromInitializer(declaration.initializer); + + // Handle string literals (remove quotes) + if (ts.isStringLiteral(initializer)) { + return initializer.text; } - - return fallbackValue; - } catch (error) { - // If resolution fails, return the original value - return fallbackValue; - } -} - -/** - * Extracts the actual value from a variable initializer expression. - * Handles literals, numeric values, and string values. - * - * @param initializer - The initializer expression - * @returns The extracted value as string - */ -private extractValueFromInitializer(initializer: ts.Expression): string { - // Handle numeric literals - if (ts.isNumericLiteral(initializer)) { - return initializer.text; + + // Handle boolean literals + if (initializer.kind === ts.SyntaxKind.TrueKeyword) { + return 'true'; + } + if (initializer.kind === ts.SyntaxKind.FalseKeyword) { + return 'false'; + } + + // Handle other expression types by returning their text + return initializer.getText(); } + + /** + * Validates SDK version compatibility by comparing operator, value, and API type. + * + * @param operator - Comparison operator from the expression + * @param value - Version value to compare against + * @param matchedApi - The matched API identifier + * @param runtimeType - Runtime environment type (OpenHarmony or Other) + * @param apiPosition - Position of API in comparison: 'left' or 'right' + * @returns True if SDK version is compatible, false otherwise + */ + private validateSdkVersionCompatibility( + operator: string, + value: string, + matchedApi: string, + runtimeType: string, + apiPosition: 'left' | 'right' + ): boolean { + const comparisonValue = Number(value); + // comparisonValue should conform to the integer format. + if (!Number.isInteger(comparisonValue)) { + return false; + } + // Adjust comparison values based on operators + const assignedSdkVersion = this.calculateAssignedSdkVersion(operator, comparisonValue, apiPosition); - // Handle string literals (remove quotes) - if (ts.isStringLiteral(initializer)) { - return initializer.text; - } + // Handle OpenHarmony runtime with direct comparison - // Handle boolean literals - if (initializer.kind === ts.SyntaxKind.TrueKeyword) { - return 'true'; + if (runtimeType === this.openSourceRuntime) { + return this.sdkOpenSourceComparison(comparisonValue); + } + + // Handle other runtime with version validation function + const versionChecker = getVersionValidationFunction(); + const triggerScene = matchedApi === this.openSourceDeviceInfo ? 1 : 2; + + const validationResult = versionChecker(this.minSinceVersion, assignedSdkVersion.toString(), triggerScene); + return validationResult.result; } - if (initializer.kind === ts.SyntaxKind.FalseKeyword) { - return 'false'; + + /** + * Compares SDK version using value assignment logic to determine if version check is valid. + * + * Logic: Determines what value the SDK version would have based on the condition, + * then compares that assigned value with the minimum required version. + * + * Examples: + * - sdkVersion > 15: SDK gets value 16, compare 16 >= minSince + * - sdkVersion >= 16: SDK gets value 16, compare 16 >= minSince + * - sdkVersion < 16: SDK gets value 15, compare 15 >= minSince + * - 16 < sdkVersion: SDK gets value 17, compare 17 >= minSince (flipped logic) + * + * @param assignedSdkVersion - The value being compared against in the condition + * @returns True if the assigned SDK version meets the minimum requirement + */ + private sdkOpenSourceComparison( + assignedSdkVersion: number + ): boolean { + const minRequiredVersion = Number(this.minSinceVersion); + + if (!Number.isInteger(minRequiredVersion) || assignedSdkVersion === null) { + return false; + } + + // Compare the assigned SDK version with minimum requirement + return assignedSdkVersion >= minRequiredVersion; } - - // Handle other expression types by returning their text - return initializer.getText(); -} - -/** Validates SDK version compatibility by comparing operator, value, and API type. - * - * @param operator - Comparison operator from the expression - * @param value - Version value to compare against - * @param matchedApi - The matched API identifier - * @param runtimeType - Runtime environment type (HarmonyOS or OpenHarmony) - * @returns True if SDK version is compatible, false otherwise - */ -private validateSdkVersionCompatibility( - operator: string, - value: string, - matchedApi: string, - runtimeType: string -): boolean { - // Handle OpenHarmony runtime with direct comparison - if (runtimeType === this.openSourceRuntime) { - return this.sdkOpenSourceComparison(operator, value, matchedApi); + + /** + * Calculates what value the SDK version would have based on the comparison condition. + * + * @param operator - Comparison operator + * @param comparisonValue - Value being compared against + * @param apiPosition - Whether API is on left or right side + * @returns Assigned SDK version value, or null if indeterminate + */ + private calculateAssignedSdkVersion( + operator: string, + comparisonValue: number, + apiPosition: 'left' | 'right' + ): number | null { + // Flip operator if API is on the right side + const effectiveOperator = apiPosition === 'right' ? this.flipOperator(operator) : operator; + + switch (effectiveOperator) { + case ">": + // sdkVersion > 15 → SDK version would be at least 16 + return comparisonValue + 1; + + case ">=": + // sdkVersion >= 16 → SDK version would be at least 16 + return comparisonValue; + + case "<": + // sdkVersion < 16 → SDK version would be at most 15 + return comparisonValue - 1; + + case "<=": + // sdkVersion <= 15 → SDK version would be at most 15 + return comparisonValue; + + case "==": + case "===": + // sdkVersion === 16 → SDK version would be exactly 16 + return comparisonValue; + + case "!=": + case "!==": + // sdkVersion !== 15 → Cannot determine specific value + return null; + + default: + return null; + } } - - const versionChecker = getVersionValidationFunction(); - const triggerScene = matchedApi === this.openSourceDeviceInfo ? 1 : 2; - const validationResult = versionChecker(this.minSinceVersion, value, triggerScene); - return validationResult.result; -} - -/** - * Compares SDK version with open source device info to determine if version check is valid. - * - * Logic: If the condition ensures that the SDK version meets or exceeds the minimum required version, - * then the check is considered valid (returns true). - * - * Examples: - * - deviceInfo.sdkApiVersion > 15 with sinceVersion 16: Valid (ensures >= 16) - * - deviceInfo.sdkApiVersion < 16 with sinceVersion 16: Invalid (ensures < 16, not meeting requirement) - * - deviceInfo.sdkApiVersion >= 16 with sinceVersion 16: Valid (ensures >= 16) - * - * @param operator - Comparison operator from the condition - * @param value - The value being compared against in the condition - * @param matchedApi - The matched API identifier - * @returns True if the condition ensures minimum version requirement is met - */ -private sdkOpenSourceComparison(operator: string, value: string, matchedApi: string): boolean { - const minRequiredVersion = Number(this.minSinceVersion); - const comparisonValue = Number(value); - - switch (operator) { - case ">": - // deviceInfo.sdkApiVersion > 15 with sinceVersion 16 - // Ensures SDK version is at least 16 (15 + 1), so valid - return comparisonValue >= minRequiredVersion - 1; - - case ">=": - // deviceInfo.sdkApiVersion >= 16 with sinceVersion 16 - // Ensures SDK version is at least 16, so valid - return comparisonValue >= minRequiredVersion; - - case "<": - // deviceInfo.sdkApiVersion < 16 with sinceVersion 16 - // Ensures SDK version is less than 16, so invalid (doesn't meet requirement) - return false; - - case "<=": - // deviceInfo.sdkApiVersion <= 15 with sinceVersion 16 - // Ensures SDK version is at most 15, so invalid (doesn't meet requirement) - return false; - - case "==": - case "===": - // deviceInfo.sdkApiVersion === 16 with sinceVersion 16 - // Ensures SDK version is exactly 16, so valid if matches or exceeds requirement - return comparisonValue >= minRequiredVersion; - - case "!=": - case "!==": - // deviceInfo.sdkApiVersion !== 15 with sinceVersion 16 - // This doesn't guarantee meeting the requirement, so invalid - return false; - - default: - throw new Error(`Unsupported operator: ${operator}`); + /** + * Flips comparison operators for when API is on the right side of comparison. + * + * @param operator - Original operator + * @returns Flipped operator + */ + private flipOperator(operator: string): string { + switch (operator) { + case ">": return "<"; + case "<": return ">"; + case ">=": return "<="; + case "<=": return ">="; + case "==": + case "===": + case "!=": + case "!==": + return operator; // These don't need flipping + default: + return operator; + } } -} private findValidImportApiIdentifier(expression: ts.Expression, api: string): ts.Identifier | undefined { if (ts.isBinaryExpression(expression)) { -- Gitee From 48b695192d5c5c31aa5d5af4949bfd256e63e2d8 Mon Sep 17 00:00:00 2001 From: bulutcangocer Date: Sat, 6 Sep 2025 12:55:42 +0300 Subject: [PATCH 27/31] hotfix: bug catch and fix Signed-off-by: bulutcangocer --- compiler/src/fast_build/system_api/sdk_version_validator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/fast_build/system_api/sdk_version_validator.ts b/compiler/src/fast_build/system_api/sdk_version_validator.ts index 9cc9f370d..7aa4e69bd 100644 --- a/compiler/src/fast_build/system_api/sdk_version_validator.ts +++ b/compiler/src/fast_build/system_api/sdk_version_validator.ts @@ -317,7 +317,7 @@ export class SdkVersionValidator { // Handle OpenHarmony runtime with direct comparison if (runtimeType === this.openSourceRuntime) { - return this.sdkOpenSourceComparison(comparisonValue); + return this.sdkOpenSourceComparison(assignedSdkVersion); } // Handle other runtime with version validation function -- Gitee From 9d1af5ebf17b7e7d57c591632c70d042b1fa7cea Mon Sep 17 00:00:00 2001 From: bulutcangocer Date: Mon, 8 Sep 2025 10:07:55 +0300 Subject: [PATCH 28/31] refactor: code check errors Signed-off-by: bulutcangocer --- .../fast_build/system_api/api_check_utils.ts | 31 ++++--- .../system_api/sdk_version_validator.ts | 81 ++++++++++--------- 2 files changed, 57 insertions(+), 55 deletions(-) diff --git a/compiler/src/fast_build/system_api/api_check_utils.ts b/compiler/src/fast_build/system_api/api_check_utils.ts index 09ac5201d..8eff0797f 100644 --- a/compiler/src/fast_build/system_api/api_check_utils.ts +++ b/compiler/src/fast_build/system_api/api_check_utils.ts @@ -584,8 +584,7 @@ function checkSinceValue( if (versionChecker === compareVersionsWithPointSystem) { projectTargetVersion = projectConfig.compatibleSdkVersion.toString(); } else { - projectTargetVersion = projectConfig.originCompatibleSdkVersion?.toString() - || projectConfig.compatibleSdkVersion.toString(); + projectTargetVersion = projectConfig.originCompatibleSdkVersion?.toString() || projectConfig.compatibleSdkVersion.toString(); } const validationResult = versionChecker(apiMinVersion, projectTargetVersion, 0); if (validationResult.result) { @@ -655,14 +654,15 @@ export function compareVersionsWithPointSystem( if (!isCompliantSince(sinceVersion) || !isCompliantSince(targetVersion)) { return { result: true, - message: "Invalid version number format" + message: 'Invalid version number format' }; } - const isTargetGreater = comparePointVersion(targetVersion, sinceVersion); + const triggerResult = comparePointVersion(targetVersion, sinceVersion); + const isTargetGreaterOrEqual = triggerResult >= 0; return { - result: isTargetGreater == 1, - message: isTargetGreater ? "API version requirement not met" : "Version requirement satisfied" + result: isTargetGreaterOrEqual, + message: isTargetGreaterOrEqual ? 'Version requirement satisfied' : 'API version requirement not met' }; } @@ -931,19 +931,18 @@ function getMinVersion(jsDocs: ts.JSDoc[]): string { * @param { string } secondVersion * @returns { number } */ -function comparePointVersion(firstVersion: string, secondVersion: string): number { - const firstPointVersion = firstVersion.split('.'); - const secondPointVersion = secondVersion.split('.'); +function comparePointVersion(firstVersion: string, secondVersion: string): -1 | 0 | 1 { + const firstParts = firstVersion.split('.'); + const secondParts = secondVersion.split('.'); + for (let i = 0; i < 3; i++) { - const part1 = parseInt(firstPointVersion[i] || '0', 10); - const part2 = parseInt(secondPointVersion[i] || '0', 10); + const part1 = parseInt(firstParts[i] || '0', 10); + const part2 = parseInt(secondParts[i] || '0', 10); - if (part1 < part2) { - return -1; - } - if (part1 > part2) { - return 1; + if (part1 !== part2) { + return part1 > part2 ? 1 : -1; } } + return 0; } \ No newline at end of file diff --git a/compiler/src/fast_build/system_api/sdk_version_validator.ts b/compiler/src/fast_build/system_api/sdk_version_validator.ts index 7aa4e69bd..74b9901c8 100644 --- a/compiler/src/fast_build/system_api/sdk_version_validator.ts +++ b/compiler/src/fast_build/system_api/sdk_version_validator.ts @@ -19,7 +19,7 @@ import { } from '../../../main'; import { getVersionValidationFunction -} from './api_check_utils' +} from './api_check_utils'; /** * The node is considered **valid** if it satisfies **at least one** of the following: @@ -30,11 +30,11 @@ import { export class SdkVersionValidator { private readonly compatibleSdkVersion: string; private readonly minSinceVersion: string; - private readonly closeSourceDeviceInfo: string = "distributionOSApiVersion"; - private readonly openSourceDeviceInfo: string = "sdkApiVersion"; - private readonly openSourceRuntime: string = "OpenHarmony"; + private readonly otherSourceDeviceInfo: string = 'distributionOSApiVersion'; + private readonly openSourceDeviceInfo: string = 'sdkApiVersion'; + private readonly openSourceRuntime: string = 'OpenHarmony'; private readonly deviceInfoChecker: Map = new Map([ - [this.closeSourceDeviceInfo, ['@ohos.deviceInfo.d.ts']], + [this.otherSourceDeviceInfo, ['@ohos.deviceInfo.d.ts']], [this.openSourceDeviceInfo, ['@ohos.deviceInfo.d.ts']] ]); private readonly typeChecker?: ts.TypeChecker; @@ -115,28 +115,31 @@ export class SdkVersionValidator { private isUndefinedNode(node: ts.Node): boolean { return ts.isIdentifier(node) && node.text === 'undefined'; } - + private isNodeWrappedInSdkComparison(node: ts.Node): boolean { if (this.compatibleSdkVersion === '' || !this.typeChecker) { return false; } - return this.findParentNode(node, (parent) => { - if (ts.isIfStatement(parent)) { - try { - const isInThenBlock = this.isNodeInIfThenBlock(node, parent); - if (!isInThenBlock) { - return false; - } - - const sdkComparisonResult = this.isSdkComparisonHelper(parent.expression); - return sdkComparisonResult; - } catch (error) { - return false; - } + return ( + this.findParentNode(node, (parent) => this.isParentIfSdkComparison(node, parent)) !== null + ); + } + + private isParentIfSdkComparison(node: ts.Node, parent: ts.Node): boolean { + if (!ts.isIfStatement(parent)) { + return false; + } + + try { + const isInThenBlock = this.isNodeInIfThenBlock(node, parent); + if (!isInThenBlock) { + return false; } + return this.isSdkComparisonHelper(parent.expression); + } catch { return false; - }) !== null; + } } private isSdkComparisonHelper(expression: ts.Expression): boolean { @@ -150,17 +153,17 @@ export class SdkVersionValidator { } const [matchedApi, validPackagePath] = matchedEntry; - if (runtimeType === this.openSourceRuntime && matchedApi === this.closeSourceDeviceInfo) { + if (runtimeType === this.openSourceRuntime && matchedApi === this.otherSourceDeviceInfo) { return false; } const parts = this.extractComparisonParts(expression, matchedApi); if (!parts) { - return false + return false; } if (!this.validateSdkVersionCompatibility(parts.operator, parts.value, matchedApi, runtimeType, parts.apiPosition)) { - return false + return false; } // Try to resolve the actual identifier used for this API in the expression @@ -373,29 +376,29 @@ export class SdkVersionValidator { const effectiveOperator = apiPosition === 'right' ? this.flipOperator(operator) : operator; switch (effectiveOperator) { - case ">": + case '>': // sdkVersion > 15 → SDK version would be at least 16 return comparisonValue + 1; - case ">=": + case '>=': // sdkVersion >= 16 → SDK version would be at least 16 return comparisonValue; - case "<": + case '<': // sdkVersion < 16 → SDK version would be at most 15 return comparisonValue - 1; - case "<=": + case '<=': // sdkVersion <= 15 → SDK version would be at most 15 return comparisonValue; - case "==": - case "===": + case '==': + case '===': // sdkVersion === 16 → SDK version would be exactly 16 return comparisonValue; - case "!=": - case "!==": + case '!=': + case '!==': // sdkVersion !== 15 → Cannot determine specific value return null; @@ -412,14 +415,14 @@ export class SdkVersionValidator { */ private flipOperator(operator: string): string { switch (operator) { - case ">": return "<"; - case "<": return ">"; - case ">=": return "<="; - case "<=": return ">="; - case "==": - case "===": - case "!=": - case "!==": + case '>': return '<'; + case '<': return '>'; + case '>=': return '<='; + case '<=': return '>='; + case '==': + case '===': + case '!=': + case '!==': return operator; // These don't need flipping default: return operator; -- Gitee From 1232fa2868ef74100a821309014c892f65a68ec6 Mon Sep 17 00:00:00 2001 From: xieziang Date: Tue, 9 Sep 2025 09:31:19 +0800 Subject: [PATCH 29/31] use node-api-headers instead of third_party Signed-off-by: xieziang Change-Id: Ia2b8974ee37b5fc60d415b7e0a9347b7964477e6 --- koala-wrapper/native/BUILD.gn | 3 +-- koala-wrapper/package.json | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/koala-wrapper/native/BUILD.gn b/koala-wrapper/native/BUILD.gn index a79c063ec..fdef3d53a 100644 --- a/koala-wrapper/native/BUILD.gn +++ b/koala-wrapper/native/BUILD.gn @@ -15,8 +15,7 @@ import("//build/ohos.gni") shared_library("es2panda") { external_deps = [ - "ets_frontend:libes2panda_public_headers", - "node:node_header_notice", + "ets_frontend:libes2panda_public_headers" ] sources = [ "../koalaui/interop/src/cpp/common-interop.cc", diff --git a/koala-wrapper/package.json b/koala-wrapper/package.json index 397203cec..57f7692fa 100644 --- a/koala-wrapper/package.json +++ b/koala-wrapper/package.json @@ -24,7 +24,8 @@ "@tsconfig/recommended": "1.0.8", "node-addon-api": "^8.3.0", "typescript": "^5.0.0", - "@types/node": "^18.0.0" + "@types/node": "^18.0.0", + "node-api-headers": "0.0.5" }, "imports": { "#koalaui/interop": { -- Gitee From 8c278d41e6df4ea07e3ebf7f948222f51dd07612 Mon Sep 17 00:00:00 2001 From: x30053363 Date: Tue, 9 Sep 2025 16:50:49 +0800 Subject: [PATCH 30/31] Fix bug of ScriptKind Issue:https://gitee.com/openharmony/developtools_ace_ets2bundle/issues/ICX5OG Signed-off-by: x30053363 Change-Id: Iec1ad3ba28d627321d9ae81c164c31f5966c6715 --- compiler/src/ets_checker.ts | 2 -- compiler/src/interop/src/ets_checker.ts | 2 -- 2 files changed, 4 deletions(-) diff --git a/compiler/src/ets_checker.ts b/compiler/src/ets_checker.ts index 8ad8a7c17..97422740d 100644 --- a/compiler/src/ets_checker.ts +++ b/compiler/src/ets_checker.ts @@ -1930,8 +1930,6 @@ export function etsStandaloneChecker(entryObj, logger, projectConfig): void { export function resetEtsCheckTypeScript(): void { if (globalProgram.program) { globalProgram.program.releaseTypeChecker(); - } else if (languageService) { - languageService.getProgram().releaseTypeChecker(); } resetGlobalProgram(); languageService = null; diff --git a/compiler/src/interop/src/ets_checker.ts b/compiler/src/interop/src/ets_checker.ts index 543618eb9..e3318c32c 100644 --- a/compiler/src/interop/src/ets_checker.ts +++ b/compiler/src/interop/src/ets_checker.ts @@ -1972,8 +1972,6 @@ export function etsStandaloneChecker(entryObj, logger, projectConfig): void { export function resetEtsCheckTypeScript(): void { if (globalProgram.program) { globalProgram.program.releaseTypeChecker(); - } else if (languageService) { - languageService.getProgram().releaseTypeChecker(); } resetGlobalProgram(); languageService = null; -- Gitee From 98aedec7fd91acf4edd6915d04fead15e8ccfc6c Mon Sep 17 00:00:00 2001 From: wangxinyu Date: Tue, 9 Sep 2025 09:48:54 +0800 Subject: [PATCH 31/31] title: add absolute path check Issue: https://gitee.com/openharmony/developtools_ace_ets2bundle/issues/ICWTLV Signed-off-by: wangxinyu Change-Id: I2e66e1dcc7ffacf85358b405b5310982431defd6 --- compiler/src/interop/src/utils.ts | 2 +- compiler/src/utils.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/interop/src/utils.ts b/compiler/src/interop/src/utils.ts index 7b0a287a9..247f74696 100644 --- a/compiler/src/interop/src/utils.ts +++ b/compiler/src/interop/src/utils.ts @@ -1303,7 +1303,7 @@ export function removeDecorator(decorators: readonly ts.Decorator[], decoratorNa export function isFileInProject(filePath: string, projectRootPath: string): boolean { const relativeFilePath: string = toUnixPath(path.relative(toUnixPath(projectRootPath), toUnixPath(filePath))); // When processing ohmurl, hsp's filePath is consistent with moduleRequest - return fs.existsSync(filePath) && fs.statSync(filePath).isFile() && !relativeFilePath.startsWith('../'); + return path.isAbsolute(filePath) && fs.existsSync(filePath) && fs.statSync(filePath).isFile() && !relativeFilePath.startsWith('../'); } export function getProjectRootPath(filePath: string, projectConfig: Object, rootPathSet: Object): string { diff --git a/compiler/src/utils.ts b/compiler/src/utils.ts index 2686ddb48..ab86f0eea 100644 --- a/compiler/src/utils.ts +++ b/compiler/src/utils.ts @@ -1316,7 +1316,7 @@ export function removeDecorator(decorators: readonly ts.Decorator[], decoratorNa export function isFileInProject(filePath: string, projectRootPath: string): boolean { const relativeFilePath: string = toUnixPath(path.relative(toUnixPath(projectRootPath), toUnixPath(filePath))); // When processing ohmurl, hsp's filePath is consistent with moduleRequest - return fs.existsSync(filePath) && fs.statSync(filePath).isFile() && !relativeFilePath.startsWith('../'); + return path.isAbsolute(filePath) && fs.existsSync(filePath) && fs.statSync(filePath).isFile() && !relativeFilePath.startsWith('../'); } export function getProjectRootPath(filePath: string, projectConfig: Object, rootPathSet: Object): string { -- Gitee