From 6263fcb9e7819c3a6027b3f9c91549cac268cc8e Mon Sep 17 00:00:00 2001 From: yy8545 <854551495@qq.com> Date: Tue, 10 Oct 2023 20:22:14 +0800 Subject: [PATCH 1/2] =?UTF-8?q?master=E5=88=86=E6=94=AF=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=9B=9E=E5=90=883.2-Release=E5=88=86=E6=94=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yy8545 <854551495@qq.com> --- build_jsmock_system_plugin.js | 13 +- mock-generate/package.json | 2 +- mock-generate/src/common/commonUtils.ts | 168 +++++++- mock-generate/src/common/constants.ts | 1 + .../callSignatureDeclaration.ts | 10 +- .../src/declaration-node/classDeclaration.ts | 22 +- .../constructorDeclaration.ts | 5 +- .../src/declaration-node/enumDeclaration.ts | 4 +- .../declaration-node/functionDeclaration.ts | 7 +- .../heritageClauseDeclaration.ts | 11 +- .../importAndExportDeclaration.ts | 7 +- .../indexSignatureDeclaration.ts | 4 +- .../declaration-node/interfaceDeclaration.ts | 29 +- .../src/declaration-node/methodDeclaration.ts | 9 +- .../methodSignatureDeclaration.ts | 10 +- .../src/declaration-node/moduleDeclaration.ts | 36 +- .../declaration-node/propertyDeclaration.ts | 4 +- .../propertySignatureDeclaration.ts | 4 +- .../sourceFileElementsAssemply.ts | 43 +- .../declaration-node/typeAliasDeclaration.ts | 8 +- .../typeParameterDeclaration.ts | 4 +- .../variableStatementResolve.ts | 6 +- .../src/generate/generateClassDeclaration.ts | 48 ++- .../src/generate/generateCommonFunction.ts | 69 ++- .../src/generate/generateCommonMethod.ts | 71 ++- .../generate/generateCommonMethodSignature.ts | 66 ++- .../src/generate/generateCommonUtil.ts | 408 ++++++++++++++++-- mock-generate/src/generate/generateEntry.ts | 2 +- .../src/generate/generateEnumDeclaration.ts | 8 +- .../src/generate/generateExportFunction.ts | 47 ++ .../src/generate/generateImportEqual.ts | 4 +- mock-generate/src/generate/generateIndex.ts | 13 +- .../src/generate/generateIndexSignature.ts | 6 +- .../generate/generateInterfaceDeclaration.ts | 100 ++++- .../src/generate/generateMockJsFile.ts | 227 +++++++--- .../src/generate/generateModuleDeclaration.ts | 101 +++-- .../generate/generatePropertyDeclaration.ts | 11 +- .../generatePropertySignatureDeclaration.ts | 46 +- .../src/generate/generateStaticFunction.ts | 11 +- .../src/generate/generateSystemIndex.ts | 2 +- .../src/generate/generateTypeAlias.ts | 119 ++++- .../generateVariableStatementDeclaration.ts | 21 +- mock-generate/src/main.ts | 100 +++-- 43 files changed, 1466 insertions(+), 421 deletions(-) create mode 100644 mock-generate/src/common/constants.ts create mode 100644 mock-generate/src/generate/generateExportFunction.ts diff --git a/build_jsmock_system_plugin.js b/build_jsmock_system_plugin.js index 3676afde..47c077a0 100644 --- a/build_jsmock_system_plugin.js +++ b/build_jsmock_system_plugin.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -35,9 +35,9 @@ const { eslint } = require('rollup-plugin-eslint'); -const frameworkBanner = `var global=this; var process={env:{}}; ` + `var setTimeout=global.setTimeout;\n`; +const frameworkBanner = 'var global=this; var process={env:{}}; ' + 'var setTimeout=global.setTimeout;\n'; -const frameworkBannerForJSAPIMock = `var global=globalThis;`; +const frameworkBannerForJSAPIMock = 'var global=globalThis;'; const onwarn = warning => { // Silence circular dependency warning @@ -75,12 +75,15 @@ const configJSAPIMockInput = { const configJSAPIMockOutput = { file: path.resolve(__dirname, 'dist/jsMockSystemPlugin.js'), format: 'umd', + treeshake: false, banner: frameworkBannerForJSAPIMock }; rollup.rollup(configJSAPIMockInput).then(bundle => { bundle.write(configJSAPIMockOutput).then(() => { countSize(configJSAPIMockOutput.file); + const fileContent = fs.readFileSync(configJSAPIMockOutput.file, 'utf-8'); + fs.writeFileSync(configJSAPIMockOutput.file, fileContent.replace(/CommonMethod\$\d*/g, 'CommonMethod'), 'utf-8'); }); }); @@ -90,7 +93,9 @@ function countSize(filePath) { if (error) { console.error('file size is wrong'); } else { - const size = (stats.size / 1024).toFixed(2) + 'KB'; + const KB_BYTE_LENGTH = 1024; + const num = 2; + const size = (stats.size / KB_BYTE_LENGTH).toFixed(num) + 'KB'; console.log(`generate snapshot file: ${file}...\nthe snapshot file size: ${size}...`); } }); diff --git a/mock-generate/package.json b/mock-generate/package.json index 25a24faa..692765e2 100644 --- a/mock-generate/package.json +++ b/mock-generate/package.json @@ -4,7 +4,7 @@ "description": "generate mock", "main": "main.js", "scripts": { - "build": "npm install && node ../node_modules/typescript/bin/tsc && cd dist && node main.js && cd .. && eslint -c .eslintrc --fix ../runtime/**/systemplugin/**/*.js" + "build": "npm install && node ../node_modules/typescript/bin/tsc && cd dist && node main.js && cd .. " }, "keywords": [ "mock" diff --git a/mock-generate/src/common/commonUtils.ts b/mock-generate/src/common/commonUtils.ts index b764a273..1a6c3e87 100644 --- a/mock-generate/src/common/commonUtils.ts +++ b/mock-generate/src/common/commonUtils.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -14,16 +14,24 @@ */ import path from 'path'; -import { - CallSignatureDeclaration, ComputedPropertyName, FunctionDeclaration, Identifier, isClassDeclaration, - isComputedPropertyName, isIdentifier, isModuleBlock, isModuleDeclaration, isPrivateIdentifier, MethodDeclaration, +import os from 'os'; +import type { + CallSignatureDeclaration, ComputedPropertyName, FunctionDeclaration, Identifier, MethodDeclaration, MethodSignature, ModifiersArray, ModuleDeclaration, NodeArray, ParameterDeclaration, PropertyName, SourceFile } from 'typescript'; +import { + isClassDeclaration, isComputedPropertyName, isIdentifier, isModuleBlock, isModuleDeclaration, isPrivateIdentifier +} from 'typescript'; +import fs from 'fs'; +import type { ImportElementEntity } from '../declaration-node/importAndExportDeclaration'; +const paramIndex = 2; const allLegalImports = new Set(); const fileNameList = new Set(); const allClassSet = new Set(); +export const dtsFileList: Array = []; + /** * get all legal imports * @returns @@ -36,7 +44,7 @@ export function getAllLegalImports(): Set { * get all legal imports * @param element */ -export function collectAllLegalImports(element: string) { +export function collectAllLegalImports(element: string): void { allLegalImports.add(element); } @@ -51,8 +59,15 @@ export function getAllFileNameList(): Set { /** * collect all file name */ -export function collectAllFileName(filePath: string) { - const fileName = path.basename(filePath).split('.d.ts')[0]; +export function collectAllFileName(filePath: string): void { + const fullFileName = path.basename(filePath); + let fileName = ''; + if (fullFileName.endsWith('d.ts')) { + fileName = fullFileName.split('.d.ts')[0]; + } else if (fullFileName.endsWith('d.ets')) { + fileName = fullFileName.split('.d.ets')[0]; + } + let outputFileName = ''; if (fileName.includes('@')) { outputFileName = fileName.split('@')[1].replace(/\./g, '_'); @@ -213,3 +228,142 @@ export interface ReturnTypeEntity { returnKindName: string, returnKind: number } + +/** + * Get OpenHarmony project dir + * @return project dir + */ + +export function getProjectDir(): string { + const apiInputPath = getApiInputPath(); + const privateInterface = path.join('vendor', 'huawei', 'interface', 'hmscore_sdk_js', 'api'); + const openInterface = path.join('interface', 'sdk-js', 'api'); + if (apiInputPath.indexOf(openInterface) > -1) { + return apiInputPath.replace(`${path.sep}${openInterface}`, ''); + } else { + return apiInputPath.replace(`${path.sep}${privateInterface}`, ''); + } +} + +/** + * return interface api dir in OpenHarmony + */ +export function getOhosInterfacesDir(): string { + return path.join(getProjectDir(), 'interface', 'sdk-js', 'api'); +} + +/** + * return interface api root path + * @returns apiInputPath + */ +export function getApiInputPath(): string { + let interfaceRootDir = ''; + if (os.platform() === 'linux' || os.platform() === 'darwin') { + interfaceRootDir = __dirname.split('/out')[0]; + } else { + interfaceRootDir = __dirname.split('\\out')[0]; + } + return path.join(interfaceRootDir, './interface/sdk-js/api'); +} + +/** + * return OpenHarmony file path dependent on by HarmonyOs + * @param importPath path of depend imported + * @param sourceFile sourceFile of current file + * @returns dependsFilePath + */ +export function findOhosDependFile(importPath: string, sourceFile: SourceFile): string { + const interFaceDir = getOhosInterfacesDir(); + const tmpImportPath = importPath.replace(/'/g, '').replace('.d.ts', '').replace('.d.ets', ''); + const sourceFileDir = path.dirname(sourceFile.fileName); + let dependsFilePath: string; + if (tmpImportPath.startsWith('./')) { + const subIndex = 2; + dependsFilePath = path.join(sourceFileDir, tmpImportPath.substring(subIndex)); + } else if (tmpImportPath.startsWith('../')) { + const backSymbolList = tmpImportPath.split('/').filter(step => step === '..'); + dependsFilePath = [ + ...sourceFileDir.split(path.sep).slice(0, -backSymbolList.length), + ...tmpImportPath.split('/').filter(step => step !== '..') + ].join(path.sep); + } else if (tmpImportPath.startsWith('@ohos.inner.')) { + const pathSteps = tmpImportPath.replace(/@ohos\.inner\./g, '').split('.'); + for (let i = 0; i < pathSteps.length; i++) { + const tmpInterFaceDir = path.join(interFaceDir, ...pathSteps.slice(0, i), pathSteps.slice(i).join('.')); + if (fs.existsSync(tmpInterFaceDir + '.d.ts')) { + return tmpInterFaceDir + '.d.ts'; + } + + if (fs.existsSync(tmpInterFaceDir + '.d.ets')) { + return tmpInterFaceDir + '.d.ets'; + } + } + } else if (tmpImportPath.startsWith('@ohos.')) { + dependsFilePath = path.join(getOhosInterfacesDir(), tmpImportPath); + } + + if (fs.existsSync(dependsFilePath + '.d.ts')) { + return dependsFilePath + '.d.ts'; + } + + if (fs.existsSync(dependsFilePath + '.d.ets')) { + return dependsFilePath + '.d.ets'; + } + + console.warn(`Cannot find module '${importPath}'`); + return ''; +} + +/** + * Determine if the file is a openHarmony interface file + * @param path: interface file path + * @returns + */ +export function isOhosInterface(path: string): boolean { + return path.startsWith(getOhosInterfacesDir()); +} + +/** + * reutn js-sdk root folder full path + * @returns + */ +export function getJsSdkDir(): string { + let sdkJsDir = process.argv[paramIndex].split(path.sep).slice(0, -1).join(path.sep); + sdkJsDir += sdkJsDir.endsWith(path.sep) ? '' : path.sep; + return sdkJsDir; +} + +/** + * Determine whether the object has been imported + * @param importDeclarations imported Declaration list in current file + * @param typeName Object being inspected + * @returns + */ +export function hasBeenImported(importDeclarations: ImportElementEntity[], typeName: string): boolean { + if (!typeName.trim()) { + return true; + } + if (isFirstCharLowerCase(typeName)) { + return true; + } + return importDeclarations.some(importDeclaration => importDeclaration.importElements.includes(typeName)); +} + +/** + * Determine whether the first character in a string is a lowercase letter + * @param str target string + * @returns + */ +function isFirstCharLowerCase(str: string): boolean { + const lowerCaseFirstChar = str[0].toLowerCase(); + return str[0] === lowerCaseFirstChar; +} + +export const specialFiles = [ + '@internal/component/ets/common.d.ts', + '@internal/component/ets/units.d.ts', + '@internal/component/ets/common_ts_ets_api.d.ts', + '@internal/component/ets/enums.d.ts', + '@internal/component/ets/alert_dialog.d.ts', + '@internal/component/ets/ability_component.d.ts' +]; diff --git a/mock-generate/src/common/constants.ts b/mock-generate/src/common/constants.ts new file mode 100644 index 00000000..bdb4b5ba --- /dev/null +++ b/mock-generate/src/common/constants.ts @@ -0,0 +1 @@ +export const INTERFACE_DIR = ['interface', 'sdk-js', 'api']; \ No newline at end of file diff --git a/mock-generate/src/declaration-node/callSignatureDeclaration.ts b/mock-generate/src/declaration-node/callSignatureDeclaration.ts index 885032f2..2b8e6674 100644 --- a/mock-generate/src/declaration-node/callSignatureDeclaration.ts +++ b/mock-generate/src/declaration-node/callSignatureDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,11 +13,9 @@ * limitations under the License. */ -import { CallSignatureDeclaration, Node, SourceFile } from 'typescript'; -import { - getFunctionAndMethodReturnInfo, getParameter, getPropertyName, - ParameterEntity, ReturnTypeEntity -} from '../common/commonUtils'; +import type { CallSignatureDeclaration, Node, SourceFile } from 'typescript'; +import { getFunctionAndMethodReturnInfo, getParameter, getPropertyName } from '../common/commonUtils'; +import type { ParameterEntity, ReturnTypeEntity } from '../common/commonUtils'; /** * get nameless function info diff --git a/mock-generate/src/declaration-node/classDeclaration.ts b/mock-generate/src/declaration-node/classDeclaration.ts index 8f1592bc..00c0db3b 100644 --- a/mock-generate/src/declaration-node/classDeclaration.ts +++ b/mock-generate/src/declaration-node/classDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,17 +13,21 @@ * limitations under the License. */ +import type { ClassDeclaration, SourceFile } from 'typescript'; import { - ClassDeclaration, isConstructorDeclaration, - isMethodDeclaration, isPropertyDeclaration, - isTypeParameterDeclaration, SourceFile, SyntaxKind + isConstructorDeclaration, isMethodDeclaration, isPropertyDeclaration, isTypeParameterDeclaration, SyntaxKind } from 'typescript'; import { getExportKeyword } from '../common/commonUtils'; -import { ConstructorEntity, getConstructorDeclaration } from './constructorDeclaration'; -import { getHeritageClauseDeclaration, HeritageClauseEntity } from './heritageClauseDeclaration'; -import { getMethodDeclaration, MethodEntity, StaticMethodEntity } from './methodDeclaration'; -import { getPropertyDeclaration, PropertyEntity } from './propertyDeclaration'; -import { getTypeParameterDeclaration, TypeParameterEntity } from './typeParameterDeclaration'; +import { getConstructorDeclaration } from './constructorDeclaration'; +import type { ConstructorEntity } from './constructorDeclaration'; +import { getHeritageClauseDeclaration } from './heritageClauseDeclaration'; +import type { HeritageClauseEntity } from './heritageClauseDeclaration'; +import { getMethodDeclaration } from './methodDeclaration'; +import type { MethodEntity, StaticMethodEntity } from './methodDeclaration'; +import { getPropertyDeclaration } from './propertyDeclaration'; +import type { PropertyEntity } from './propertyDeclaration'; +import { getTypeParameterDeclaration } from './typeParameterDeclaration'; +import type { TypeParameterEntity } from './typeParameterDeclaration'; /** * get class info diff --git a/mock-generate/src/declaration-node/constructorDeclaration.ts b/mock-generate/src/declaration-node/constructorDeclaration.ts index ee544768..6cae2186 100644 --- a/mock-generate/src/declaration-node/constructorDeclaration.ts +++ b/mock-generate/src/declaration-node/constructorDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,7 +13,8 @@ * limitations under the License. */ -import { ConstructorDeclaration, isIdentifier, Node, SourceFile } from 'typescript'; +import type { ConstructorDeclaration, Node, SourceFile } from 'typescript'; +import { isIdentifier } from 'typescript'; /** * get constructors info diff --git a/mock-generate/src/declaration-node/enumDeclaration.ts b/mock-generate/src/declaration-node/enumDeclaration.ts index abac4762..23b3fc94 100644 --- a/mock-generate/src/declaration-node/enumDeclaration.ts +++ b/mock-generate/src/declaration-node/enumDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,7 +13,7 @@ * limitations under the License. */ -import { EnumDeclaration, SourceFile } from 'typescript'; +import type { EnumDeclaration, SourceFile } from 'typescript'; import { getExportKeyword, getPropertyName } from '../common/commonUtils'; /** diff --git a/mock-generate/src/declaration-node/functionDeclaration.ts b/mock-generate/src/declaration-node/functionDeclaration.ts index 990fbb7e..2911047d 100644 --- a/mock-generate/src/declaration-node/functionDeclaration.ts +++ b/mock-generate/src/declaration-node/functionDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,8 +13,9 @@ * limitations under the License. */ -import { FunctionDeclaration, Node, SourceFile } from 'typescript'; -import { getFunctionAndMethodReturnInfo, getParameter, ParameterEntity, ReturnTypeEntity } from '../common/commonUtils'; +import type { FunctionDeclaration, Node, SourceFile } from 'typescript'; +import { getFunctionAndMethodReturnInfo, getParameter } from '../common/commonUtils'; +import type { ParameterEntity, ReturnTypeEntity } from '../common/commonUtils'; /** * get function info diff --git a/mock-generate/src/declaration-node/heritageClauseDeclaration.ts b/mock-generate/src/declaration-node/heritageClauseDeclaration.ts index 39b6f2da..b952ee12 100644 --- a/mock-generate/src/declaration-node/heritageClauseDeclaration.ts +++ b/mock-generate/src/declaration-node/heritageClauseDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,7 +13,8 @@ * limitations under the License. */ -import { HeritageClause, Node, SourceFile, SyntaxKind } from 'typescript'; +import type { HeritageClause, Node, SourceFile } from 'typescript'; +import { SyntaxKind } from 'typescript'; /** * get heritage info @@ -22,11 +23,11 @@ import { HeritageClause, Node, SourceFile, SyntaxKind } from 'typescript'; * @returns */ export function getHeritageClauseDeclaration(node: Node, sourceFile: SourceFile): HeritageClauseEntity { - const HeritageClauseNode = node as HeritageClause; - const clauseToken = HeritageClauseNode.token === SyntaxKind.ExtendsKeyword ? 'extends' : 'implements'; + const heritageClauseNode = node as HeritageClause; + const clauseToken = heritageClauseNode.token === SyntaxKind.ExtendsKeyword ? 'extends' : 'implements'; const types: Array = []; - HeritageClauseNode.types.forEach(value => { + heritageClauseNode.types.forEach(value => { types.push(sourceFile.text.substring(value.pos, value.end).trimStart().trimEnd()); }); diff --git a/mock-generate/src/declaration-node/importAndExportDeclaration.ts b/mock-generate/src/declaration-node/importAndExportDeclaration.ts index 4d502782..926746e2 100644 --- a/mock-generate/src/declaration-node/importAndExportDeclaration.ts +++ b/mock-generate/src/declaration-node/importAndExportDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,8 +13,9 @@ * limitations under the License. */ -import { ExportAssignment, ExportDeclaration, ImportDeclaration, - ImportEqualsDeclaration, isImportDeclaration, Node, SourceFile } from 'typescript'; +import type { ExportAssignment, ExportDeclaration, ImportDeclaration, + ImportEqualsDeclaration, Node, SourceFile } from 'typescript'; +import { isImportDeclaration } from 'typescript'; /** * get current sourceFile all imports diff --git a/mock-generate/src/declaration-node/indexSignatureDeclaration.ts b/mock-generate/src/declaration-node/indexSignatureDeclaration.ts index 461d2ae1..7c2fe3de 100644 --- a/mock-generate/src/declaration-node/indexSignatureDeclaration.ts +++ b/mock-generate/src/declaration-node/indexSignatureDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,7 +13,7 @@ * limitations under the License. */ -import { IndexSignatureDeclaration, SourceFile } from 'typescript'; +import type { IndexSignatureDeclaration, SourceFile } from 'typescript'; /** * get index signature info diff --git a/mock-generate/src/declaration-node/interfaceDeclaration.ts b/mock-generate/src/declaration-node/interfaceDeclaration.ts index 31477b52..88a8d126 100644 --- a/mock-generate/src/declaration-node/interfaceDeclaration.ts +++ b/mock-generate/src/declaration-node/interfaceDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -14,18 +14,25 @@ */ import { - InterfaceDeclaration, isCallSignatureDeclaration, isConstructSignatureDeclaration, - isHeritageClause, isIndexSignatureDeclaration, isMethodSignature, isPropertySignature, - isTypeParameterDeclaration, SourceFile + isCallSignatureDeclaration, isConstructSignatureDeclaration, isHeritageClause, isIndexSignatureDeclaration, + isMethodSignature, isPropertySignature, isTypeParameterDeclaration } from 'typescript'; +import type { InterfaceDeclaration, SourceFile } from 'typescript'; import { getExportKeyword } from '../common/commonUtils'; -import { CallSignatureEntity, getCallSignatureDeclaration } from './callSignatureDeclaration'; -import { ConstructorEntity, getConstructorDeclaration } from './constructorDeclaration'; -import { getHeritageClauseDeclaration, HeritageClauseEntity } from './heritageClauseDeclaration'; -import { getIndexSignatureDeclaration, IndexSignatureEntity } from './indexSignatureDeclaration'; -import { getMethodSignatureDeclaration, MethodSignatureEntity } from './methodSignatureDeclaration'; -import { getPropertySignatureDeclaration, PropertySignatureEntity } from './propertySignatureDeclaration'; -import { getTypeParameterDeclaration, TypeParameterEntity } from './typeParameterDeclaration'; +import { getCallSignatureDeclaration } from './callSignatureDeclaration'; +import type { CallSignatureEntity } from './callSignatureDeclaration'; +import { getConstructorDeclaration } from './constructorDeclaration'; +import type { ConstructorEntity } from './constructorDeclaration'; +import { getHeritageClauseDeclaration } from './heritageClauseDeclaration'; +import type { HeritageClauseEntity } from './heritageClauseDeclaration'; +import { getIndexSignatureDeclaration } from './indexSignatureDeclaration'; +import type { IndexSignatureEntity } from './indexSignatureDeclaration'; +import { getMethodSignatureDeclaration } from './methodSignatureDeclaration'; +import type { MethodSignatureEntity } from './methodSignatureDeclaration'; +import { getPropertySignatureDeclaration } from './propertySignatureDeclaration'; +import type { PropertySignatureEntity } from './propertySignatureDeclaration'; +import { getTypeParameterDeclaration } from './typeParameterDeclaration'; +import type { TypeParameterEntity } from './typeParameterDeclaration'; /** * get interface info diff --git a/mock-generate/src/declaration-node/methodDeclaration.ts b/mock-generate/src/declaration-node/methodDeclaration.ts index dec63959..63d9e6f9 100644 --- a/mock-generate/src/declaration-node/methodDeclaration.ts +++ b/mock-generate/src/declaration-node/methodDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,11 +13,12 @@ * limitations under the License. */ -import { isComputedPropertyName, MethodDeclaration, Node, SourceFile } from 'typescript'; +import { isComputedPropertyName } from 'typescript'; +import type { MethodDeclaration, Node, SourceFile } from 'typescript'; import { - getFunctionAndMethodReturnInfo, getModifiers, getParameter, - getPropertyName, ParameterEntity, ReturnTypeEntity + getFunctionAndMethodReturnInfo, getModifiers, getParameter, getPropertyName } from '../common/commonUtils'; +import type { ParameterEntity, ReturnTypeEntity } from '../common/commonUtils'; /** * get method info diff --git a/mock-generate/src/declaration-node/methodSignatureDeclaration.ts b/mock-generate/src/declaration-node/methodSignatureDeclaration.ts index 15f7d14c..39c96dd1 100644 --- a/mock-generate/src/declaration-node/methodSignatureDeclaration.ts +++ b/mock-generate/src/declaration-node/methodSignatureDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,11 +13,9 @@ * limitations under the License. */ -import { MethodSignature, Node, SourceFile } from 'typescript'; -import { - getFunctionAndMethodReturnInfo, getParameter, getPropertyName, - ParameterEntity, ReturnTypeEntity -} from '../common/commonUtils'; +import type { MethodSignature, Node, SourceFile } from 'typescript'; +import { getFunctionAndMethodReturnInfo, getParameter, getPropertyName } from '../common/commonUtils'; +import type { ParameterEntity, ReturnTypeEntity } from '../common/commonUtils'; /** * get interface signature info diff --git a/mock-generate/src/declaration-node/moduleDeclaration.ts b/mock-generate/src/declaration-node/moduleDeclaration.ts index 27b9673a..9b05bffe 100644 --- a/mock-generate/src/declaration-node/moduleDeclaration.ts +++ b/mock-generate/src/declaration-node/moduleDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,16 +16,24 @@ import { isClassDeclaration, isEnumDeclaration, isExportDeclaration, isFunctionDeclaration, isIdentifier, isImportEqualsDeclaration, isInterfaceDeclaration, isModuleBlock, isModuleDeclaration, isTypeAliasDeclaration, - isVariableStatement, ModuleDeclaration, Node, SourceFile + isVariableStatement } from 'typescript'; +import type { ModuleDeclaration, Node, SourceFile } from 'typescript'; import { getExportKeyword } from '../common/commonUtils'; -import { ClassEntity, getClassDeclaration } from './classDeclaration'; -import { EnumEntity, getEnumDeclaration } from './enumDeclaration'; -import { FunctionEntity, getFunctionDeclaration } from './functionDeclaration'; -import { getExportDeclaration, getModuleImportEqual, ImportEuqalEntity } from './importAndExportDeclaration'; -import { getInterfaceDeclaration, InterfaceEntity } from './interfaceDeclaration'; -import { getTypeAliasDeclaration, TypeAliasEntity } from './typeAliasDeclaration'; -import { getVariableStatementDeclaration, StatementEntity } from './variableStatementResolve'; +import { getClassDeclaration } from './classDeclaration'; +import type { ClassEntity } from './classDeclaration'; +import { getEnumDeclaration } from './enumDeclaration'; +import type { EnumEntity } from './enumDeclaration'; +import { getFunctionDeclaration } from './functionDeclaration'; +import type { FunctionEntity } from './functionDeclaration'; +import { getExportDeclaration, getModuleImportEqual } from './importAndExportDeclaration'; +import type { ImportEuqalEntity } from './importAndExportDeclaration'; +import { getInterfaceDeclaration } from './interfaceDeclaration'; +import type { InterfaceEntity } from './interfaceDeclaration'; +import { getTypeAliasDeclaration } from './typeAliasDeclaration'; +import type { TypeAliasEntity } from './typeAliasDeclaration'; +import { getVariableStatementDeclaration } from './variableStatementResolve'; +import type { StatementEntity } from './variableStatementResolve'; /** * get module info @@ -63,13 +71,13 @@ export function getModuleDeclaration(node: Node, sourceFile: SourceFile, fileNam if (moduleBody !== undefined && isModuleBlock(moduleBody)) { moduleBody.statements.forEach(value => { if (isFunctionDeclaration(value)) { - const FunctionEntity = getFunctionDeclaration(value, sourceFile); - if (functionDeclarations.get(FunctionEntity.functionName) !== undefined) { - functionDeclarations.get(FunctionEntity.functionName)?.push(FunctionEntity); + const functionEntity = getFunctionDeclaration(value, sourceFile); + if (functionDeclarations.get(functionEntity.functionName) !== undefined) { + functionDeclarations.get(functionEntity.functionName)?.push(functionEntity); } else { const functionArray: Array = []; - functionArray.push(FunctionEntity); - functionDeclarations.set(FunctionEntity.functionName, functionArray); + functionArray.push(functionEntity); + functionDeclarations.set(functionEntity.functionName, functionArray); } } else if (isTypeAliasDeclaration(value)) { typeAliasDeclarations.push(getTypeAliasDeclaration(value, sourceFile)); diff --git a/mock-generate/src/declaration-node/propertyDeclaration.ts b/mock-generate/src/declaration-node/propertyDeclaration.ts index c22f8a66..b7d5c847 100644 --- a/mock-generate/src/declaration-node/propertyDeclaration.ts +++ b/mock-generate/src/declaration-node/propertyDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,7 +13,7 @@ * limitations under the License. */ -import { PropertyDeclaration, SourceFile } from 'typescript'; +import type { PropertyDeclaration, SourceFile } from 'typescript'; import { getPropertyName } from '../common/commonUtils'; /** diff --git a/mock-generate/src/declaration-node/propertySignatureDeclaration.ts b/mock-generate/src/declaration-node/propertySignatureDeclaration.ts index f137d478..eb646031 100644 --- a/mock-generate/src/declaration-node/propertySignatureDeclaration.ts +++ b/mock-generate/src/declaration-node/propertySignatureDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,7 +13,7 @@ * limitations under the License. */ -import { PropertySignature, SourceFile } from 'typescript'; +import type { PropertySignature, SourceFile } from 'typescript'; import { getPropertyName } from '../common/commonUtils'; /** diff --git a/mock-generate/src/declaration-node/sourceFileElementsAssemply.ts b/mock-generate/src/declaration-node/sourceFileElementsAssemply.ts index d889f954..30568e5b 100644 --- a/mock-generate/src/declaration-node/sourceFileElementsAssemply.ts +++ b/mock-generate/src/declaration-node/sourceFileElementsAssemply.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,17 +16,26 @@ import { isClassDeclaration, isEnumDeclaration, isExportAssignment, isExportDeclaration, isFunctionDeclaration, isImportDeclaration, isInterfaceDeclaration, isModuleDeclaration, isTypeAliasDeclaration, isVariableStatement, - SourceFile, SyntaxKind + SyntaxKind } from 'typescript'; -import { ClassEntity, getClassDeclaration } from './classDeclaration'; -import { EnumEntity, getEnumDeclaration } from './enumDeclaration'; -import { FunctionEntity, getFunctionDeclaration } from './functionDeclaration'; -import { getExportAssignment, getImportDeclaration, ImportElementEntity } from './importAndExportDeclaration'; -import { getInterfaceDeclaration, InterfaceEntity } from './interfaceDeclaration'; -import { StaticMethodEntity } from './methodDeclaration'; -import { getModuleDeclaration, ModuleBlockEntity } from './moduleDeclaration'; -import { getTypeAliasDeclaration, TypeAliasEntity } from './typeAliasDeclaration'; -import { getVariableStatementDeclaration, StatementEntity } from './variableStatementResolve'; +import type { SourceFile } from 'typescript'; +import { getClassDeclaration } from './classDeclaration'; +import type { ClassEntity } from './classDeclaration'; +import { getEnumDeclaration } from './enumDeclaration'; +import type { EnumEntity } from './enumDeclaration'; +import { getFunctionDeclaration } from './functionDeclaration'; +import type { FunctionEntity } from './functionDeclaration'; +import { getExportAssignment, getImportDeclaration } from './importAndExportDeclaration'; +import type { ImportElementEntity } from './importAndExportDeclaration'; +import { getInterfaceDeclaration } from './interfaceDeclaration'; +import type { InterfaceEntity } from './interfaceDeclaration'; +import type { StaticMethodEntity } from './methodDeclaration'; +import { getModuleDeclaration } from './moduleDeclaration'; +import type { ModuleBlockEntity } from './moduleDeclaration'; +import { getTypeAliasDeclaration } from './typeAliasDeclaration'; +import type { TypeAliasEntity } from './typeAliasDeclaration'; +import { getVariableStatementDeclaration } from './variableStatementResolve'; +import type { StatementEntity } from './variableStatementResolve'; /** * assembly all sourceFile node info @@ -44,6 +53,7 @@ export function getSourceFileAssembly(sourceFile: SourceFile, fileName: string): let exportAssignment: Array = []; const staticMethods: Array> = []; const exportDeclarations: Array = []; + const functionDeclarations: Array = []; sourceFile.forEachChild(node => { if (isImportDeclaration(node)) { @@ -76,7 +86,10 @@ export function getSourceFileAssembly(sourceFile: SourceFile, fileName: string): enumDeclarations.push(getEnumDeclaration(node, sourceFile)); } else if (isExportDeclaration(node)) { exportDeclarations.push(sourceFile.text.substring(node.pos, node.end).trimStart().trimEnd()); - } else { + } else if (isFunctionDeclaration(node)){ + functionDeclarations.push(getFunctionDeclaration(node, sourceFile)); + } + else { if (node.kind !== SyntaxKind.EndOfFileToken && !isFunctionDeclaration(node) && !isVariableStatement(node)) { console.log('--------------------------- uncaught sourceFile type start -----------------------'); console.log('fileName: ' + fileName); @@ -95,7 +108,8 @@ export function getSourceFileAssembly(sourceFile: SourceFile, fileName: string): enumDeclarations: enumDeclarations, exportAssignment: exportAssignment, staticMethods: staticMethods, - exportDeclarations: exportDeclarations + exportDeclarations: exportDeclarations, + functionDeclarations: functionDeclarations, }; } @@ -160,5 +174,6 @@ export interface SourceFileEntity { enumDeclarations: Array, exportAssignment: Array, staticMethods: Array>, - exportDeclarations: Array + exportDeclarations: Array, + functionDeclarations: Array } diff --git a/mock-generate/src/declaration-node/typeAliasDeclaration.ts b/mock-generate/src/declaration-node/typeAliasDeclaration.ts index 2a5acc81..09a268b4 100644 --- a/mock-generate/src/declaration-node/typeAliasDeclaration.ts +++ b/mock-generate/src/declaration-node/typeAliasDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,10 +13,8 @@ * limitations under the License. */ -import { - isTypeLiteralNode, isTypeReferenceNode, - isUnionTypeNode, Node, SourceFile, TypeAliasDeclaration -} from 'typescript'; +import { isTypeLiteralNode, isTypeReferenceNode, isUnionTypeNode } from 'typescript'; +import type { Node, SourceFile, TypeAliasDeclaration } from 'typescript'; /** * get type alias info diff --git a/mock-generate/src/declaration-node/typeParameterDeclaration.ts b/mock-generate/src/declaration-node/typeParameterDeclaration.ts index f4a1d7fb..b801ae80 100644 --- a/mock-generate/src/declaration-node/typeParameterDeclaration.ts +++ b/mock-generate/src/declaration-node/typeParameterDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,7 +13,7 @@ * limitations under the License. */ -import { Node, SourceFile, TypeParameterDeclaration } from 'typescript'; +import type { Node, SourceFile, TypeParameterDeclaration } from 'typescript'; /** * get generic type node info diff --git a/mock-generate/src/declaration-node/variableStatementResolve.ts b/mock-generate/src/declaration-node/variableStatementResolve.ts index b16d84a4..755fa136 100644 --- a/mock-generate/src/declaration-node/variableStatementResolve.ts +++ b/mock-generate/src/declaration-node/variableStatementResolve.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,7 +13,8 @@ * limitations under the License. */ -import { isIdentifier, SourceFile, VariableStatement } from 'typescript'; +import { isIdentifier } from 'typescript'; +import type { SourceFile, VariableStatement } from 'typescript'; /** * get const declaration variable @@ -36,6 +37,7 @@ export function getVariableStatementDeclaration(variableStatement: VariableState } if (value.initializer !== undefined) { initializer = sourceFile.text.substring(value.initializer.pos, value.initializer.end); + typeKind = value.initializer.kind; } if (value.type !== undefined) { typeName = sourceFile.text.substring(value.type.pos, value.type.end); diff --git a/mock-generate/src/generate/generateClassDeclaration.ts b/mock-generate/src/generate/generateClassDeclaration.ts index 7f0bdb3b..11e931e4 100644 --- a/mock-generate/src/generate/generateClassDeclaration.ts +++ b/mock-generate/src/generate/generateClassDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,9 +13,10 @@ * limitations under the License. */ -import { SourceFile, SyntaxKind } from 'typescript'; +import type { SourceFile } from 'typescript'; +import { SyntaxKind } from 'typescript'; import { firstCharacterToUppercase } from '../common/commonUtils'; -import { ClassEntity } from '../declaration-node/classDeclaration'; +import type { ClassEntity } from '../declaration-node/classDeclaration'; import { generateCommonMethod } from './generateCommonMethod'; import { getWarnConsole } from './generateCommonUtil'; import { generatePropertyDeclaration } from './generatePropertyDeclaration'; @@ -33,14 +34,16 @@ import { generateStaticFunction } from './generateStaticFunction'; * @returns */ export function generateClassDeclaration(rootName: string, classEntity: ClassEntity, isSystem: boolean, globalName: string, - filename: string, sourceFile: SourceFile, isInnerMockFunction: boolean): string { + filename: string, sourceFile: SourceFile, isInnerMockFunction: boolean, mockApi: string): string { if (isSystem) { return ''; } const className = firstCharacterToUppercase(classEntity.className); let classBody = ''; - if (classEntity.exportModifiers.includes(SyntaxKind.ExportKeyword) && !isInnerMockFunction) { + if ((classEntity.exportModifiers.includes(SyntaxKind.ExportKeyword) || + classEntity.exportModifiers.includes(SyntaxKind.DeclareKeyword)) && + !isInnerMockFunction) { classBody += `export const ${className} = class ${className} `; } else { classBody += `const ${className} = class ${className} `; @@ -54,10 +57,19 @@ export function generateClassDeclaration(rootName: string, classEntity: ClassEnt isExtend = true; classBody += `${value.clauseToken} `; value.types.forEach((val, index) => { + const extendClassName = val.split('<')[0]; + const moduleName = firstCharacterToUppercase(rootName); + if (val.startsWith('Array<')) { + val = 'Array'; + } else { + if (classEntity.exportModifiers.includes(SyntaxKind.ExportKeyword) && rootName !== '') { + val = `mock${moduleName}().${val}`; + } + } if (index !== value.types.length - 1) { - classBody += `${val},`; + classBody += `${extendClassName},`; } else { - classBody += `${val}`; + classBody += `${extendClassName}`; } }); } @@ -67,12 +79,12 @@ export function generateClassDeclaration(rootName: string, classEntity: ClassEnt if (!isSystem) { classBody += '{'; if (classEntity.classConstructor.length > 1) { - classBody += `constructor(...arg) { `; + classBody += 'constructor(...arg) { '; } else { - classBody += `constructor() { `; + classBody += 'constructor() { '; } if (isExtend) { - classBody += `super();`; + classBody += 'super();\n'; } classBody += getWarnConsole(className, 'constructor'); } @@ -84,19 +96,31 @@ export function generateClassDeclaration(rootName: string, classEntity: ClassEnt if (classEntity.classMethod.size > 0) { classEntity.classMethod.forEach(value => { - classBody += generateCommonMethod(className, value, sourceFile); + classBody += generateCommonMethod(className, value, sourceFile, mockApi); }); } classBody += '}\n};'; + if ((classEntity.exportModifiers.includes(SyntaxKind.ExportKeyword) || + classEntity.exportModifiers.includes(SyntaxKind.DeclareKeyword)) && + !isInnerMockFunction) { + classBody += ` + if (!global.${className}) { + global.${className} = ${className};\n + } + `; + } if (!filename.startsWith('system_')) { if (classEntity.staticMethods.length > 0) { let staticMethodBody = ''; classEntity.staticMethods.forEach(value => { - staticMethodBody += generateStaticFunction(value, false, sourceFile) + '\n'; + staticMethodBody += generateStaticFunction(value, false, sourceFile, mockApi) + '\n'; }); classBody += staticMethodBody; } } + if (classEntity.exportModifiers.includes(SyntaxKind.DefaultKeyword)) { + classBody += `\nexport default ${className};`; + } return classBody; } diff --git a/mock-generate/src/generate/generateCommonFunction.ts b/mock-generate/src/generate/generateCommonFunction.ts index 8c337a18..6e3bd9f1 100644 --- a/mock-generate/src/generate/generateCommonFunction.ts +++ b/mock-generate/src/generate/generateCommonFunction.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,9 +13,10 @@ * limitations under the License. */ -import { SourceFile, SyntaxKind } from 'typescript'; -import { FunctionEntity } from '../declaration-node/functionDeclaration'; -import { getCallbackStatement, getReturnStatement, getWarnConsole } from './generateCommonUtil'; +import type { SourceFile } from 'typescript'; +import { SyntaxKind } from 'typescript'; +import type { FunctionEntity } from '../declaration-node/functionDeclaration'; +import { getCallbackStatement, getReturnStatement, getWarnConsole, getReturnData } from './generateCommonUtil'; /** * generate function @@ -24,7 +25,7 @@ import { getCallbackStatement, getReturnStatement, getWarnConsole } from './gene * @param sourceFile * @returns */ -export function generateCommonFunction(rootName: string, functionArray: Array, sourceFile: SourceFile): string { +export function generateCommonFunction(rootName: string, functionArray: Array, sourceFile: SourceFile, mockApi: string): string { let functionBody = ''; const functionEntity = functionArray[0]; functionBody = `${functionEntity.functionName}: function(...args) {`; @@ -34,19 +35,20 @@ export function generateCommonFunction(rootName: string, functionArray: Array 0 && args[len - 1].paramName.toLowerCase().includes('callback')) { - functionBody += getCallbackStatement(); + functionBody += getCallbackStatement(mockApi, args[len - 1]?.paramTypeString); } if (functionEntity.returnType.returnKind !== SyntaxKind.VoidKeyword) { if (rootName === 'featureAbility' && functionEntity.returnType.returnKindName === 'Context') { functionBody += 'return _Context;'; } else if (rootName === 'inputMethod' && functionEntity.returnType.returnKindName === 'InputMethodSubtype') { - functionBody += 'return mockInputMethodSubtype().InputMethodSubtype;' + functionBody += 'return mockInputMethodSubtype().InputMethodSubtype;'; } else { functionBody += getReturnStatement(functionEntity.returnType, sourceFile); } } } else { const argSet: Set = new Set(); + let argParamsSet: string = ''; const returnSet: Set = new Set(); let isCallBack = false; functionArray.forEach(value => { @@ -55,25 +57,60 @@ export function generateCommonFunction(rootName: string, functionArray: Array { - if (value.startsWith('Promise')) { + if (value.includes('Promise<')) { isReturnPromise = true; + promiseReturnValue = value; + } else { + if (!otherReturnValue) { + otherReturnValue = value; + } } }); - - if (isReturnPromise && isCallBack) { - functionBody += `else { - return new Promise((resolve, reject) => { - resolve('[PC Preview] unknow boolean'); - }) - }`; + if (isReturnPromise) { + if (promiseReturnValue) { + let returnType = null; + functionArray.forEach(value => { + if (value.returnType.returnKindName === promiseReturnValue) { + returnType = value.returnType; + } + }); + functionBody += getReturnData(isCallBack, isReturnPromise, returnType, sourceFile, mockApi); + } else { + if (isCallBack) { + functionBody += `else { + return new Promise((resolve, reject) => { + resolve('[PC Preview] unknow boolean'); + }) + }`; + } else { + functionBody += ` + return new Promise((resolve, reject) => { + resolve('[PC Preview] unknow boolean'); + }) + `; + } + } + } else if (otherReturnValue) { + let returnType = null; + functionArray.forEach(value => { + if (value.returnType.returnKindName === otherReturnValue) { + returnType = value.returnType; + } + }); + functionBody += getReturnData(isCallBack, isReturnPromise, returnType, sourceFile, mockApi); } } functionBody += '},'; diff --git a/mock-generate/src/generate/generateCommonMethod.ts b/mock-generate/src/generate/generateCommonMethod.ts index d733fa32..e0997daf 100644 --- a/mock-generate/src/generate/generateCommonMethod.ts +++ b/mock-generate/src/generate/generateCommonMethod.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,11 +13,12 @@ * limitations under the License. */ -import { SourceFile, SyntaxKind } from 'typescript'; -import { MethodEntity } from '../declaration-node/methodDeclaration'; +import type { SourceFile } from 'typescript'; +import { SyntaxKind } from 'typescript'; +import type { MethodEntity } from '../declaration-node/methodDeclaration'; import { generateSymbolIterator, getCallbackStatement, - getReturnStatement, getWarnConsole + getReturnStatement, getWarnConsole, getReturnData } from './generateCommonUtil'; /** @@ -27,7 +28,7 @@ import { * @param sourceFile * @returns */ -export function generateCommonMethod(rootName: string, methodArray: Array, sourceFile: SourceFile): string { +export function generateCommonMethod(rootName: string, methodArray: Array, sourceFile: SourceFile, mockApi: string): string { let methodBody = ''; const methodEntity = methodArray[0]; if (methodEntity.functionName.name === 'Symbol.iterator') { @@ -45,7 +46,7 @@ export function generateCommonMethod(rootName: string, methodArray: Array 0 && args[len - 1].paramName.toLowerCase().includes('callback')) { - methodBody += getCallbackStatement(); + methodBody += getCallbackStatement(mockApi, args[len - 1]?.paramTypeString); } if (methodEntity.returnType.returnKind !== SyntaxKind.VoidKeyword) { if (methodEntity.functionName.name === 'getApplicationContext') { @@ -56,6 +57,7 @@ export function generateCommonMethod(rootName: string, methodArray: Array = new Set(); + let argParamsSet: string = ''; const returnSet: Set = new Set(); let isCallBack = false; methodArray.forEach(value => { @@ -64,29 +66,60 @@ export function generateCommonMethod(rootName: string, methodArray: Array { - if (value.startsWith('Promise')) { + if (value.includes('Promise<')) { isReturnPromise = true; + promiseReturnValue = value; + } else { + if (!otherReturnValue) { + otherReturnValue = value; + } } }); - - if (isReturnPromise && isCallBack) { - methodBody += `else { - return new Promise((resolve, reject) => { - resolve('[PC Preview] unknow boolean'); - }) - }`; - } else { - methodBody += `return new Promise((resolve, reject) => { - resolve('[PC preview] unknown type'); - });`; + if (isReturnPromise) { + if (promiseReturnValue) { + let returnType = null; + methodArray.forEach(value => { + if (value.returnType.returnKindName === promiseReturnValue) { + returnType = value.returnType; + } + }); + methodBody += getReturnData(isCallBack, isReturnPromise, returnType, sourceFile, mockApi); + } else { + if (isCallBack) { + methodBody += `else { + return new Promise((resolve, reject) => { + resolve('[PC Preview] unknow boolean'); + }) + }`; + } else { + methodBody += ` + return new Promise((resolve, reject) => { + resolve('[PC Preview] unknow boolean'); + }) + `; + } + } + } else if (otherReturnValue) { + let returnType = null; + methodArray.forEach(value => { + if (value.returnType.returnKindName === otherReturnValue) { + returnType = value.returnType; + } + }); + methodBody += getReturnData(isCallBack, isReturnPromise, returnType, sourceFile, mockApi); } } methodBody += '};\n'; diff --git a/mock-generate/src/generate/generateCommonMethodSignature.ts b/mock-generate/src/generate/generateCommonMethodSignature.ts index 048b9072..115116c0 100644 --- a/mock-generate/src/generate/generateCommonMethodSignature.ts +++ b/mock-generate/src/generate/generateCommonMethodSignature.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,9 +13,10 @@ * limitations under the License. */ -import { SourceFile, SyntaxKind } from 'typescript'; -import { MethodSignatureEntity } from '../declaration-node/methodSignatureDeclaration'; -import { getCallbackStatement, getReturnStatement, getWarnConsole } from './generateCommonUtil'; +import type { SourceFile } from 'typescript'; +import { SyntaxKind } from 'typescript'; +import type { MethodSignatureEntity } from '../declaration-node/methodSignatureDeclaration'; +import { getCallbackStatement, getReturnStatement, getWarnConsole, getReturnData } from './generateCommonUtil'; /** * generate interface signature method @@ -24,7 +25,7 @@ import { getCallbackStatement, getReturnStatement, getWarnConsole } from './gene * @param sourceFile * @returns */ -export function generateCommonMethodSignature(rootName: string, methodSignatureArray: Array, sourceFile: SourceFile): string { +export function generateCommonMethodSignature(rootName: string, methodSignatureArray: Array, sourceFile: SourceFile, mockApi: string): string { let methodSignatureBody = ''; const methodEntity = methodSignatureArray[0]; methodSignatureBody += `${methodEntity.functionName}: function(...args) {`; @@ -33,7 +34,7 @@ export function generateCommonMethodSignature(rootName: string, methodSignatureA const args = methodEntity.args; const len = args.length; if (args.length > 0 && args[len - 1].paramName.toLowerCase().includes('callback')) { - methodSignatureBody += getCallbackStatement(); + methodSignatureBody += getCallbackStatement(mockApi, args[len - 1]?.paramTypeString); } if (methodEntity.returnType.returnKind !== SyntaxKind.VoidKeyword) { if (rootName === 'Context' && methodEntity.returnType.returnKindName === 'Context') { @@ -44,6 +45,7 @@ export function generateCommonMethodSignature(rootName: string, methodSignatureA } } else { const argSet: Set = new Set(); + let argParamsSet: string = ''; const returnSet: Set = new Set(); let isCallBack = false; methodSignatureArray.forEach(value => { @@ -52,24 +54,60 @@ export function generateCommonMethodSignature(rootName: string, methodSignatureA argSet.add(arg.paramName); if (arg.paramName.toLowerCase().includes('callback')) { isCallBack = true; + if (arg.paramTypeString) { + argParamsSet = arg.paramTypeString; + } } }); }); if (isCallBack) { - methodSignatureBody += getCallbackStatement(); + methodSignatureBody += getCallbackStatement(mockApi, argParamsSet); } let isReturnPromise = false; + let promiseReturnValue = ''; + let otherReturnValue = ''; returnSet.forEach(value => { - if (value.startsWith('Promise')) { + if (value.includes('Promise<')) { isReturnPromise = true; + promiseReturnValue = value; + } else { + if (!otherReturnValue) { + otherReturnValue = value; + } } }); - if (isReturnPromise && isCallBack) { - methodSignatureBody += `else { - return new Promise((resolve, reject) => { - resolve('[PC Preview] unknow boolean'); - }) - }`; + if (isReturnPromise) { + if (promiseReturnValue) { + let returnType = null; + methodSignatureArray.forEach(value => { + if (value.returnType.returnKindName === promiseReturnValue) { + returnType = value.returnType; + } + }); + methodSignatureBody += getReturnData(isCallBack, isReturnPromise, returnType, sourceFile, mockApi); + } else { + if (isCallBack) { + methodSignatureBody += `else { + return new Promise((resolve, reject) => { + resolve('[PC Preview] unknow boolean'); + }) + }`; + } else { + methodSignatureBody += ` + return new Promise((resolve, reject) => { + resolve('[PC Preview] unknow boolean'); + }) + `; + } + } + } else if (otherReturnValue) { + let returnType = null; + methodSignatureArray.forEach(value => { + if (value.returnType.returnKindName === otherReturnValue) { + returnType = value.returnType; + } + }); + methodSignatureBody += getReturnData(isCallBack, isReturnPromise, returnType, sourceFile, mockApi); } } methodSignatureBody += '},\n'; diff --git a/mock-generate/src/generate/generateCommonUtil.ts b/mock-generate/src/generate/generateCommonUtil.ts index 8d933828..66308381 100644 --- a/mock-generate/src/generate/generateCommonUtil.ts +++ b/mock-generate/src/generate/generateCommonUtil.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,10 +13,13 @@ * limitations under the License. */ -import { SourceFile, SyntaxKind } from 'typescript'; -import { firstCharacterToUppercase, getClassNameSet, ReturnTypeEntity } from '../common/commonUtils'; -import { getImportDeclarationArray, ImportElementEntity } from '../declaration-node/importAndExportDeclaration'; -import { MethodEntity } from '../declaration-node/methodDeclaration'; +import type { SourceFile } from 'typescript'; +import { SyntaxKind } from 'typescript'; +import { firstCharacterToUppercase, getClassNameSet } from '../common/commonUtils'; +import type { ReturnTypeEntity } from '../common/commonUtils'; +import { getImportDeclarationArray } from '../declaration-node/importAndExportDeclaration'; +import type { ImportElementEntity } from '../declaration-node/importAndExportDeclaration'; +import type { MethodEntity } from '../declaration-node/methodDeclaration'; /** * get warn console template @@ -25,7 +28,7 @@ import { MethodEntity } from '../declaration-node/methodDeclaration'; * @returns */ export function getWarnConsole(interfaceNameOrClassName: string, functionNameOrPropertyName: string): string { - return `console.warn('${interfaceNameOrClassName}.${functionNameOrPropertyName} interface mocked in the Previewer. How this interface works on the Previewer may be different from that on a real device.');\n`; + return `console.warn('The ${interfaceNameOrClassName}.${functionNameOrPropertyName} interface in the Previewer is a mocked implementation and may behave differently than on a real device.');\n`; } /** @@ -38,10 +41,10 @@ export function getReturnStatement(returnType: ReturnTypeEntity, sourceFile: Sou if (returnType.returnKind === SyntaxKind.TypeReference) { if (returnType.returnKindName.startsWith('Promise')) { return `return new Promise((resolve, reject) => { - resolve('[PC Preview] unkonwn type'); + resolve('[PC Preview] unknown type'); })`; } else if (returnType.returnKindName === 'T') { - return `return '[PC Preview] unkonwn type'`; + return 'return \'[PC Preview] unknown type\''; } else if (returnType.returnKindName === 'String') { return `return ${returnType.returnKindName}(...args)`; } else if (returnType.returnKindName === 'ArrayBuffer') { @@ -55,7 +58,7 @@ export function getReturnStatement(returnType: ReturnTypeEntity, sourceFile: Sou } else if (returnType.returnKindName.startsWith('Readonly')) { return `return ${returnType.returnKindName.split('<')[1].split('>')[0]}`; } else if (checkIsGenericSymbol(returnType.returnKindName)) { - return `return '[PC Preview] unkonwn iterableiterator_${returnType.returnKindName}'`; + return `return '[PC Preview] unknown iterableiterator_${returnType.returnKindName}'`; } else if (returnType.returnKindName.startsWith('Uint8Array')) { return `return new ${returnType.returnKindName}()`; } else if (returnType.returnKindName.startsWith('IterableIterator')) { @@ -63,11 +66,11 @@ export function getReturnStatement(returnType: ReturnTypeEntity, sourceFile: Sou return `let index = 0; const IteratorEntriesMock = { *[Symbol.iterator]() { - yield ['[PC Preview] unkonwn paramIterMock_K', '[PC Preview] unkonwn paramIterMock_V']; + yield ['[PC Preview] unknown paramIterMock_K', '[PC Preview] unknown paramIterMock_V']; }, next: () => { if (index < 1) { - const returnValue = ['[PC Previwe] unkonwn paramIterMock_K', '[PC Previwe] unkonwn paramIterMock_V']; + const returnValue = ['[PC Previwe] unknown paramIterMock_K', '[PC Previwe] unknown paramIterMock_V']; index++; return { value: returnValue, @@ -85,11 +88,11 @@ export function getReturnStatement(returnType: ReturnTypeEntity, sourceFile: Sou return `let index = 0; const IteratorStringMock = { *[Symbol.iterator]() { - yield '[PC Preview] unkonwn string'; + yield '[PC Preview] unknown string'; }, next: () => { if (index < 1) { - const returnValue = '[PC Previwe] unkonwn string'; + const returnValue = '[PC Previwe] unknown string'; index++; return { value: returnValue, @@ -107,7 +110,7 @@ export function getReturnStatement(returnType: ReturnTypeEntity, sourceFile: Sou } else if (returnType.returnKindName.includes('')) { const tmpReturn = returnType.returnKindName.split('<')[0]; if (tmpReturn.startsWith('Array')) { - return `return []`; + return 'return []'; } else { `return new ${tmpReturn}()`; } @@ -116,7 +119,7 @@ export function getReturnStatement(returnType: ReturnTypeEntity, sourceFile: Sou } else { if (getClassNameSet().has(returnType.returnKindName)) { if (returnType.returnKindName === 'Want') { - return `return mockWant().Want`; + return 'return mockWant().Want'; } else { return `return new ${returnType.returnKindName}()`; } @@ -136,7 +139,7 @@ export function getReturnStatement(returnType: ReturnTypeEntity, sourceFile: Sou } } if (returnName.trimStart().trimEnd() === 'void') { - return ``; + return ''; } if (getClassNameSet().has(returnName)) { return `return new ${returnName}()`; @@ -144,9 +147,9 @@ export function getReturnStatement(returnType: ReturnTypeEntity, sourceFile: Sou return `return ${getBaseReturnValue(returnName.trimStart().trimEnd())}`; } } else { - return `return '[PC Preview] unkonwn type'`; + return 'return \'[PC Preview] unknown type\''; } - return `return '[PC Preview] unkonwn type'`; + return 'return \'[PC Preview] unknown type\''; } /** @@ -154,11 +157,11 @@ export function getReturnStatement(returnType: ReturnTypeEntity, sourceFile: Sou * @param propertyTypeName * @returns */ -export function propertyTypeWhiteList(propertyTypeName: string): any { +export function propertyTypeWhiteList(propertyTypeName: string): boolean | number | string { const whiteList = ['GLboolean', 'GLuint', 'GLenum', 'GLint', 'NotificationFlags']; if (whiteList.includes(propertyTypeName)) { if (propertyTypeName === 'NotificationFlags' || propertyTypeName === 'GLenum') { - return `'[PC Preview] unkonwn ${propertyTypeName}'`; + return `'[PC Preview] unknown ${propertyTypeName}'`; } else if (propertyTypeName === 'GLboolean') { return true; } else { @@ -176,17 +179,17 @@ export function propertyTypeWhiteList(propertyTypeName: string): any { */ export function getBaseReturnValue(value: string): string | number | boolean { if (value === 'string') { - return `''`; + return '\'\''; } else if (value === 'number') { return 0; } else if (value === 'boolean') { return true; } else if (value === 'Object' || value === 'object') { - return `{}`; + return '{}'; } else if (checkIsGenericSymbol(value)) { - return `'[PC Preview] unkonwn type'`; + return '\'[PC Preview] unknown type\''; } else if (value === 'WebGLActiveInfo') { - return `{size: '[PC Preview] unkonwn GLint', type: 0, name: '[PC Preview] unkonwn name'}`; + return '{size: \'[PC Preview] unknown GLint\', type: 0, name: \'[PC Preview] unknown name\'}'; } else { return value; } @@ -228,7 +231,7 @@ export function getTheRealReferenceFromImport(sourceFile: SourceFile, typeName: } else { returnName = getImportTypeAliasNameFromImportElements(importArray, typeName); } - return returnName; + return returnName.split('<')[0]; } /** @@ -237,22 +240,28 @@ export function getTheRealReferenceFromImport(sourceFile: SourceFile, typeName: * @param typeName * @returns */ - function getImportTypeAliasNameFromImportElements(importElementEntity: ImportElementEntity[], typeName: string): string { +function getImportTypeAliasNameFromImportElements(importElementEntity: ImportElementEntity[], typeName: string): string { for (let i = 0; i < importElementEntity.length; i++) { if (importElementEntity[i].importElements.includes('_')) { const importElements = importElementEntity[i].importElements.replace('{', '').replace('}', '').split(','); for (let j = 0; j < importElements.length; j++) { const element = importElements[j].trimStart().trimEnd(); - if (`_${typeName}` === element.split('as')[1].trimStart().trimEnd()) { + if (!element) { + continue; + } + if (`_${typeName}` === element.trim()) { + return `_${typeName}`; + } + if (element.includes(' as ') && `_${typeName}` === element.split('as')[1].trim()) { return `_${typeName}`; } } } } if (typeName === 'Want') { - typeName = `mockWant().Want`; + typeName = 'mockWant().Want'; } else if (typeName === 'InputMethodExtensionContext') { - typeName = `mockInputmethodextensioncontext().InputMethodExtensionContext`; + typeName = 'mockInputMethodExtensionContext().InputMethodExtensionContext'; } return typeName; } @@ -272,10 +281,10 @@ export function checkIsGenericSymbol(type: string): boolean { * @param kindName * @returns */ -export function generateGenericTypeToMockValue(kindName: string): any { +export function generateGenericTypeToMockValue(kindName: string): string | number | boolean { const genericTypeName = kindName.split('<')[1].split('>')[0]; if (genericTypeName === 'string') { - return `''`; + return '\'\''; } else if (genericTypeName === 'number') { return 0; } else if (genericTypeName === 'boolean') { @@ -283,19 +292,146 @@ export function generateGenericTypeToMockValue(kindName: string): any { } else if (genericTypeName === 'Object' || genericTypeName === 'object') { return '{}'; } else { - return ``; + return ''; } } +const paramsTypeStart = { + 'void': '[PC Preview] unknown type', + 'Array': '[]', + 'Object': '{}', + '{': '{}', + 'string': '""', + 'number': 0, + 'boolean': false, + 'ArrayBuffer': 'new ArrayBuffer(0)', + 'Uint8Array': 'new Uint8Array()', + 'unknown': '[PC Preview] unknown type' +}; + +const removeCallback = (str: string) => { + const callbackParams = { + type: 'Callback', + value: '' + }; + if (str.startsWith('Callback')) { + callbackParams.value = str.slice(0, str.length - 1).slice(9).trim(); + callbackParams.type = 'Callback'; + } else if (str.startsWith('AsyncCallback')) { + callbackParams.value = str.slice(0, str.length - 1).slice(14).trim(); + callbackParams.type = 'AsyncCallback'; + } + if (callbackParams.value.includes(',')) { + callbackParams.value = callbackParams.value.split(',')[0].trim(); + } + return callbackParams; +}; + +const isInImportType = (mockApi: string, value: string) => { + let hasDotFirstWorld = ''; + if (value.includes('.')) { + hasDotFirstWorld = value.split('.')[0].trim(); + } + if (hasDotFirstWorld && mockApi.includes(`import { mock${firstLetterWord(hasDotFirstWorld)} `)) { + return 'isHasDotImportMock'; + } + if (hasDotFirstWorld && mockApi.includes(`import { ${firstLetterWord(hasDotFirstWorld)} `)) { + return 'isNoHasDotImportMock'; + } + if (mockApi.includes(`import { mock${firstLetterWord(value)} `)) { + return 'isImportMock'; + } + if (mockApi.includes(`import { ${value} `)) { + return 'isImport'; + } + return 'noImport'; +}; + +const firstLetterWord = (word: string) => { + return word.slice(0, 1).toUpperCase() + word.slice(1); +}; + +const hasDotFirstWord = (str: string) => { + return str.includes('.') ? str.split('.')[0] : str; +}; + +/** + * get callback parameters data + * @returns data: parameters data: type: AsyncCallback or Callback + */ +const setCallbackData = (mockApi: string, paramTypeString: string): {data: string, type: string} => { + const callbackParams = removeCallback(paramTypeString); + let callbackData = ''; + let importType = ''; + if (callbackParams.value) { + importType = isInImportType(mockApi, callbackParams.value); + } + if (importType === 'isHasDotImportMock') { + const upperWord = firstLetterWord(callbackParams.value); // Image.PixelMap + const firstWord = hasDotFirstWord(upperWord); // Image + callbackData = `mock${firstWord}()${upperWord.slice(firstWord.length)}`; + } else if (importType === 'isNoHasDotImportMock') { + callbackData = callbackParams.value; + } else if (importType === 'isImportMock') { + callbackData = `mock${firstLetterWord(callbackParams.value)}()`; + } else if (importType === 'isImport') { + callbackData = callbackParams.value; + } else if (importType === 'noImport') { + let paramsTypeNoHas = true; + if (callbackParams.value.endsWith(']')) { + callbackData = '[]'; + } else { + Object.keys(paramsTypeStart).forEach(item => { + if (callbackParams.value.startsWith(item)) { + callbackData = paramsTypeStart[item]; + paramsTypeNoHas = false; + } + }); + if (paramsTypeNoHas) { + callbackData = callbackParams.value; + if (callbackParams.value.includes('<')) { + callbackData = `${callbackParams.value.split('<')[0]}`; + } + } + if (callbackParams.value === 'Date') { + callbackData = 'new Date()'; + } + if (callbackParams.value === 'Uint8Array') { + callbackData = 'new Uint8Array()'; + } + if (callbackParams.value === 'T') { + callbackData = '[PC Preview] unknown type'; + } + } + } else { + callbackData = '[PC Preview] unknown type'; + } + return { + data: callbackData, + type: callbackParams.type + }; +}; + /** * get callback statement - * @returns + * @returns callback statement */ -export function getCallbackStatement(): string { - return `const len = args.length; - if (typeof args[len - 1] === 'function') { - args[len - 1].call(this, null, '[PC Preview] unkonwn type') - }`; +export function getCallbackStatement(mockApi: string, paramTypeString?: string): string { + let outPut = `if (args && typeof args[args.length - 1] === 'function') { + args[args.length - 1].call(this,`; + const callbackError = "{'code': '','data': '','name': '','message': '','stack': ''}"; + let callbackDataParams = { + type: '', + data: '[PC Preview] unknown type' + }; + if (paramTypeString) { + callbackDataParams = setCallbackData(mockApi, paramTypeString); + } + if (callbackDataParams?.type === 'AsyncCallback') { + outPut += ` ${callbackError},`; + } + outPut += callbackDataParams.data === '[PC Preview] unknown type' ? ` '${callbackDataParams.data}');\n}` : ` ${callbackDataParams.data});\n}`; + return outPut; } /** @@ -310,7 +446,7 @@ export function generateSymbolIterator(methodEntity: MethodEntity): string { const IteratorMock = { next: () => { if (index < 1) { - const returnValue = ['[PC Previwe] unkonwn iterableiterator_k', '[PC Previwe] unkonwn iterableiterator_v']; + const returnValue = ['[PC Previwe] unknown iterableiterator_k', '[PC Previwe] unknown iterableiterator_v']; index++; return { value: returnValue, @@ -331,7 +467,7 @@ export function generateSymbolIterator(methodEntity: MethodEntity): string { if (index < 1) { index++; return { - value: '[PC Preview] unkonwn any', + value: '[PC Preview] unknown any', done: false }; } else { @@ -346,3 +482,195 @@ export function generateSymbolIterator(methodEntity: MethodEntity): string { return iteratorMethod; } + +/** + * generate more function name return statement; + * @param isReturnPromise + * @param returnType + * @param sourceFile + * @param mockApi + * @returns + */ +export function getReturnData(isCallBack: boolean, isReturnPromise: boolean, returnType: ReturnTypeEntity, sourceFile: SourceFile, mockApi: string): string { + // If the return value is an iterator IterableIterator, then IteratorEntriesMock is directly returned + if (returnType.returnKindName.startsWith('IterableIterator')) { + if (returnType.returnKindName.includes(',')) { + return `let index = 0; + const IteratorEntriesMock = { + *[Symbol.iterator]() { + yield ['[PC Preview] unknown paramIterMock_K', '[PC Preview] unknown paramIterMock_V']; + }, + next: () => { + if (index < 1) { + const returnValue = ['[PC Previwe] unknown paramIterMock_K', '[PC Previwe] unknown paramIterMock_V']; + index++; + return { + value: returnValue, + done: false + }; + } else { + return { + done: true + }; + } + } + }; + return IteratorEntriesMock;`; + } else { + return `let index = 0; + const IteratorStringMock = { + *[Symbol.iterator]() { + yield '[PC Preview] unknown string'; + }, + next: () => { + if (index < 1) { + const returnValue = '[PC Previwe] unknown string'; + index++; + return { + value: returnValue, + done: false + }; + } else { + return { + done: true + }; + } + } + }; + return IteratorStringMock;`; + } + } + // If it is a promise, intercept the content of x in promise, which may have the following formats: + // fun(): y | Promise、 fun(): Promise、 fun(): Promise、 fun(): Promise + // If it is not a promise, the returned type may be x, x | y | z, x.y + let returnPromiseParams = returnType.returnKindName; + if (isReturnPromise) { + if (returnType.returnKind === SyntaxKind.UnionType) { + // fun(): y | Promise + const returnNames = returnPromiseParams.split('|'); + for (let i = 0; i < returnNames.length; i++) { + if (returnNames[i].trim().startsWith('Promise<')) { + // Promise + returnPromiseParams = returnNames[i].trim(); + break; + } + } + } + // At this point, obtain the values in these formats: Promise, Promise, Promise, Promise + const kindName = returnPromiseParams; + returnPromiseParams = kindName.slice(0, kindName.length - 1).slice(8).trim(); + } + // At this point, the value type of param in promisemay be x, x | y | z, x.y + if (returnPromiseParams.includes('|')) { + returnPromiseParams = getSeparatorParam(returnPromiseParams); + } + + // At this point, the possible types of promiseParam are x, x.y x [] Array + // Check if it was imported + let returnData = '"[PC Preview] unknown type"'; + const importType = isInImportType(mockApi, returnPromiseParams); + if (importType === 'isHasDotImportMock') { + const upperWord = firstLetterWord(returnPromiseParams); // Image.PixelMap + const firstWord = hasDotFirstWord(upperWord); // Image + returnData = `mock${firstWord}()${upperWord.slice(firstWord.length)}`; + } else if (importType === 'isNoHasDotImportMock') { + returnData = returnPromiseParams; + } else if (importType === 'isImportMock') { + returnData = `mock${firstLetterWord(returnPromiseParams)}()`; + } else if (importType === 'isImport') { + returnData = returnPromiseParams; + } else if (importType === 'noImport') { + if (returnPromiseParams.endsWith(']')) { + returnData = '[]'; + } else { + let paramsTypeNoHas = true; + Object.keys(paramsTypeStart).forEach(item => { + if (returnPromiseParams.startsWith(item)) { + returnData = paramsTypeStart[item]; + paramsTypeNoHas = false; + } + }); + if (paramsTypeNoHas) { + returnData = returnPromiseParams; + if (returnPromiseParams.includes('<')) { + returnData = `${returnPromiseParams.split('<')[0]}`; + } + } + if (returnPromiseParams === 'Date') { + returnData = 'new Date()'; + } + if (returnPromiseParams === 'T') { + returnData = '"[PC Preview] unknown type"'; + } + if (returnType.returnKindName.startsWith('Readonly')) { + returnData = `${returnType.returnKindName.split('<')[1].split('>')[0]}`; + } + if (checkIsGenericSymbol(returnType.returnKindName)) { + returnData = `'[PC Preview] unknown iterableiterator_${returnType.returnKindName}'`; + } + } + } else { + returnData = '"[PC Preview] unknown type"'; + } + const data = typeof returnData === 'string' && returnData.startsWith('[PC Preview] unknown') ? `'${returnData}'` : `${returnData}`; + if (isReturnPromise) { + if (isCallBack) { + return `else { + return new Promise((resolve, reject) => { + resolve(${data}); + }) + }`; + } else { + return ` + return new Promise((resolve, reject) => { + resolve(${data}); + }) + `; + } + } else { + return `return ${data}`; + } +} + +/** + * + * @param returnPromiseParams + * @returns + */ +function getSeparatorParam(returnPromiseParams: string): string { + let hasObj = ''; + let hasArr = ''; + let hasUint8Array = ''; + let hasArrayBuffer = ''; + let otherValue = ''; + const paramsArr = returnPromiseParams.split('|'); + for (let i = 0; i < paramsArr.length; i++) { + const param = paramsArr[i].trim(); + if (param.startsWith('{') || param.startsWith('Object')) { + hasObj = '{}'; + } else if (param.endsWith(']') || param.startsWith('[') || param.startsWith('Array<')) { + hasArr = '[]'; + } else if (param.startsWith('Uint8Array')) { + hasUint8Array = 'Uint8Array'; + } else if (param.startsWith('ArrayBuffer')) { + hasArrayBuffer = 'ArrayBuffer'; + } else { + if (param !== null) { + otherValue = param; + } + } + } + if (hasObj) { + return hasObj; + } + if (hasArr) { + return hasArr; + } + if (hasUint8Array) { + return hasUint8Array; + } + if (hasArrayBuffer) { + return hasArrayBuffer; + } + return otherValue; +} diff --git a/mock-generate/src/generate/generateEntry.ts b/mock-generate/src/generate/generateEntry.ts index e91aa650..e32ba993 100644 --- a/mock-generate/src/generate/generateEntry.ts +++ b/mock-generate/src/generate/generateEntry.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at diff --git a/mock-generate/src/generate/generateEnumDeclaration.ts b/mock-generate/src/generate/generateEnumDeclaration.ts index e97ad98c..022b2335 100644 --- a/mock-generate/src/generate/generateEnumDeclaration.ts +++ b/mock-generate/src/generate/generateEnumDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -14,7 +14,7 @@ */ import { SyntaxKind } from 'typescript'; -import { EnumEntity } from '../declaration-node/enumDeclaration'; +import type { EnumEntity } from '../declaration-node/enumDeclaration'; /** * generate enum @@ -35,7 +35,9 @@ export function generateEnumDeclaration(rootName: string, enumDeclaration: EnumE if (member.enumKind === SyntaxKind.TypeReference) { enumBody += `${member.enumValueName}: new ${member.enumValue},\n`; } else if (member.enumKind === SyntaxKind.NumericLiteral) { - enumBody += `${member.enumValueName}: ${member.enumValue.replace(/"/g, '')},\n`; + defaultValue = parseInt(member.enumValue.replace(/"/g, '').replace(/'/g, '')); + enumBody += `${member.enumValueName}: ${defaultValue},\n`; + defaultValue++; } else if (member.enumKind === SyntaxKind.StringLiteral) { enumBody += `${member.enumValueName}: ${member.enumValue},\n`; } else { diff --git a/mock-generate/src/generate/generateExportFunction.ts b/mock-generate/src/generate/generateExportFunction.ts new file mode 100644 index 00000000..d45972fb --- /dev/null +++ b/mock-generate/src/generate/generateExportFunction.ts @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { SourceFile } from 'typescript'; +import { SyntaxKind } from 'typescript'; +import type { FunctionEntity } from '../declaration-node/functionDeclaration'; +import { getCallbackStatement, getReturnStatement } from './generateCommonUtil'; + +/** + * generate function + * @param rootName + * @param functionArray + * @param sourceFile + * @param mockApi + * @returns + */ +export function generateExportFunction(functionEntity: FunctionEntity, sourceFile: SourceFile, mockApi: string): string { + if (functionEntity.functionName !== 'getContext') { + return ''; + } + let functionBody = ''; + functionBody = `global.${functionEntity.functionName} = function (...args) {`; + functionBody += `console.warn('The ${functionEntity.functionName} interface in the Previewer is a mocked implementation and may behave differently than on a real device.');\n`; + + const args = functionEntity.args; + const len = args.length; + if (args.length > 0 && args[len - 1].paramName.toLowerCase().includes('callback')) { + functionBody += getCallbackStatement(mockApi); + } + if (functionEntity.returnType.returnKind !== SyntaxKind.VoidKeyword) { + functionBody += getReturnStatement(functionEntity.returnType, sourceFile); + } + functionBody += '}'; + return functionBody; +} diff --git a/mock-generate/src/generate/generateImportEqual.ts b/mock-generate/src/generate/generateImportEqual.ts index b47cc100..55bec562 100644 --- a/mock-generate/src/generate/generateImportEqual.ts +++ b/mock-generate/src/generate/generateImportEqual.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,7 +13,7 @@ * limitations under the License. */ -import { ImportEuqalEntity } from '../declaration-node/importAndExportDeclaration'; +import type { ImportEuqalEntity } from '../declaration-node/importAndExportDeclaration'; /** * generate import equal node info diff --git a/mock-generate/src/generate/generateIndex.ts b/mock-generate/src/generate/generateIndex.ts index 7b0fca69..0f50a208 100644 --- a/mock-generate/src/generate/generateIndex.ts +++ b/mock-generate/src/generate/generateIndex.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,14 +13,14 @@ * limitations under the License. */ -import { firstCharacterToUppercase } from "../common/commonUtils"; +import { firstCharacterToUppercase } from '../common/commonUtils'; /** * save all mock function */ const indexArray: Array = []; -export function addToIndexArray(indexEntity: IndexEntity) { +export function addToIndexArray(indexEntity: IndexEntity): void { indexArray.push(indexEntity); } @@ -57,14 +57,14 @@ export function generateIndex(): string { } if (value.fileName.startsWith('ohos_')) { - caseBody += `case '${value.fileName.split('ohos_')[1].replace('_', '.')}':\n\treturn ${functionName}();\n`; + caseBody += `case '${value.fileName.split('ohos_')[1].replace(/_/g, '.')}':\n\treturn ${functionName}();\n`; } else { caseBody += `case '${value.fileName}':\n\treturn ${functionName}();\n`; } }); indexBody += `export function mockRequireNapiFun() { - global.requireNapi = function (...args) { + global.requireNapi = function(...args) { const globalNapi = global.requireNapiPreview(...args); if (globalNapi !== undefined) { return globalNapi; @@ -72,6 +72,9 @@ export function generateIndex(): string { switch (args[0]) {`; indexBody += caseBody; const endBody = `} + if (global.hosMockFunc !== undefined) { + return global.hosMockFunc(args[0]); + } } }`; indexBody += endBody; diff --git a/mock-generate/src/generate/generateIndexSignature.ts b/mock-generate/src/generate/generateIndexSignature.ts index 6582e265..fe96ec3c 100644 --- a/mock-generate/src/generate/generateIndexSignature.ts +++ b/mock-generate/src/generate/generateIndexSignature.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -14,7 +14,7 @@ */ import { SyntaxKind } from 'typescript'; -import { IndexSignatureEntity } from '../declaration-node/indexSignatureDeclaration'; +import type { IndexSignatureEntity } from '../declaration-node/indexSignatureDeclaration'; /** * generate index signature @@ -27,7 +27,7 @@ export function generateIndexSignature(signatureEntity: IndexSignatureEntity): s if (signatureEntity.indexSignatureKind === SyntaxKind.TypeReference) { signatureTypeName = signatureEntity.indexSignatureTypeName; } else { - signatureTypeName = `'[PC Preview] unkonwn type',\n`; + signatureTypeName = '\'[PC Preview] unknown type\',\n'; } return `${signatureKey}: ${signatureTypeName}`; } diff --git a/mock-generate/src/generate/generateInterfaceDeclaration.ts b/mock-generate/src/generate/generateInterfaceDeclaration.ts index 05c1cbc8..f5fcfcfe 100644 --- a/mock-generate/src/generate/generateInterfaceDeclaration.ts +++ b/mock-generate/src/generate/generateInterfaceDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,11 +13,17 @@ * limitations under the License. */ -import { SourceFile } from 'typescript'; -import { InterfaceEntity } from '../declaration-node/interfaceDeclaration'; +import fs from 'fs'; +import path from 'path'; +import type { SourceFile } from 'typescript'; +import { SyntaxKind } from 'typescript'; +import type { InterfaceEntity } from '../declaration-node/interfaceDeclaration'; import { generateCommonMethodSignature } from './generateCommonMethodSignature'; import { generateIndexSignature } from './generateIndexSignature'; import { generatePropertySignatureDeclaration } from './generatePropertySignatureDeclaration'; +import { dtsFileList, getApiInputPath, hasBeenImported, specialFiles } from '../common/commonUtils'; +import type { ImportElementEntity } from '../declaration-node/importAndExportDeclaration'; +import type { PropertySignatureEntity } from '../declaration-node/propertySignatureDeclaration'; /** * generate interface @@ -28,7 +34,7 @@ import { generatePropertySignatureDeclaration } from './generatePropertySignatur * @returns */ export function generateInterfaceDeclaration(rootName: string, interfaceEntity: InterfaceEntity, sourceFile: SourceFile, isSourceFile: boolean, - currentSourceInterfaceArray: InterfaceEntity[]): string { + mockApi: string, currentSourceInterfaceArray: InterfaceEntity[], importDeclarations?: ImportElementEntity[], extraImport?: string[]): string { const interfaceName = interfaceEntity.interfaceName; let interfaceBody = ''; const interfaceElementSet = new Set(); @@ -40,14 +46,15 @@ export function generateInterfaceDeclaration(rootName: string, interfaceEntity: if (interfaceEntity.interfacePropertySignatures.length > 0) { interfaceEntity.interfacePropertySignatures.forEach(value => { - interfaceBody += generatePropertySignatureDeclaration(interfaceName, value, sourceFile) + '\n'; + interfaceBody += generatePropertySignatureDeclaration(interfaceName, value, sourceFile, mockApi) + '\n'; interfaceElementSet.add(value.propertyName); + addExtraImport(extraImport, importDeclarations, sourceFile, value); }); } if (interfaceEntity.interfaceMethodSignature.size > 0) { interfaceEntity.interfaceMethodSignature.forEach(value => { - interfaceBody += generateCommonMethodSignature(interfaceName, value, sourceFile) + '\n'; + interfaceBody += generateCommonMethodSignature(interfaceName, value, sourceFile, mockApi) + '\n'; interfaceElementSet.add(value[0].functionName); }); } @@ -63,23 +70,30 @@ export function generateInterfaceDeclaration(rootName: string, interfaceEntity: interfaceEntity.heritageClauses.forEach(value => { currentSourceInterfaceArray.forEach(currentInterface => { if (value.types.includes(currentInterface.interfaceName)) { - interfaceBody += generateHeritageInterface(currentInterface, sourceFile, interfaceElementSet); + interfaceBody += generateHeritageInterface(currentInterface, sourceFile, interfaceElementSet, mockApi); } }); }); } - interfaceBody += '}'; + interfaceBody += '}\n'; + if (interfaceEntity.exportModifiers.includes(SyntaxKind.DeclareKeyword)) { + interfaceBody += ` + if (!global.${interfaceName}) { + global.${interfaceName} = ${interfaceName};\n + } + `; + } return interfaceBody; } -function generateHeritageInterface(interfaceEntity: InterfaceEntity, sourceFile: SourceFile, elements: Set): string { +function generateHeritageInterface(interfaceEntity: InterfaceEntity, sourceFile: SourceFile, elements: Set, mockApi: string): string { const interfaceName = interfaceEntity.interfaceName; let interfaceBody = ''; if (interfaceEntity.interfacePropertySignatures.length > 0) { interfaceEntity.interfacePropertySignatures.forEach(value => { if (!elements.has(value.propertyName)) { - interfaceBody += generatePropertySignatureDeclaration(interfaceName, value, sourceFile) + '\n'; + interfaceBody += generatePropertySignatureDeclaration(interfaceName, value, sourceFile, mockApi) + '\n'; } }); } @@ -87,7 +101,7 @@ function generateHeritageInterface(interfaceEntity: InterfaceEntity, sourceFile: if (interfaceEntity.interfaceMethodSignature.size > 0) { interfaceEntity.interfaceMethodSignature.forEach(value => { if (!elements.has(value[0].functionName)) { - interfaceBody += generateCommonMethodSignature(interfaceName, value, sourceFile) + '\n'; + interfaceBody += generateCommonMethodSignature(interfaceName, value, sourceFile, mockApi) + '\n'; } }); } @@ -101,3 +115,67 @@ function generateHeritageInterface(interfaceEntity: InterfaceEntity, sourceFile: } return interfaceBody; } + +/** + * + * @param extraImport + * @param importDeclarations + * @param sourceFile + * @param value + * @returns + */ +function addExtraImport( + extraImport: string[], + importDeclarations: ImportElementEntity[], + sourceFile: SourceFile, + value: PropertySignatureEntity): void { + if (extraImport && importDeclarations) { + const propertyTypeName = value.propertyTypeName.split('.')[0].split('|')[0].split('&')[0].replace(/"'/g, '').trim(); + if (propertyTypeName.includes('/')) { + return; + } + if (hasBeenImported(importDeclarations, propertyTypeName)) { + return; + } + const specialFilesList = [...specialFiles.map(specialFile => path.join(getApiInputPath(), ...specialFile.split('/')))]; + if (!specialFilesList.includes(sourceFile.fileName)) { + specialFilesList.unshift(sourceFile.fileName); + } + for (let i = 0; i < specialFilesList.length; i++) { + const specialFilePath = specialFilesList[i]; + let specialFileContent = fs.readFileSync(specialFilePath, 'utf-8'); + const removeNoteRegx = /\/\*[\s\S]*?\*\//g; + specialFileContent = specialFileContent.replace(removeNoteRegx, ''); + const regex = new RegExp(`\\s${propertyTypeName}\\s({|=|extends)`); + const results = specialFileContent.match(regex); + if (!results) { + continue; + } + if (sourceFile.fileName === specialFilePath) { + return; + } + let specialFileRelatePath = path.relative(path.dirname(sourceFile.fileName), path.dirname(specialFilePath)); + if (!specialFileRelatePath.startsWith('./') && !specialFileRelatePath.startsWith('../')) { + specialFileRelatePath = './' + specialFileRelatePath; + } + if (!dtsFileList.includes(specialFilePath)) { + dtsFileList.push(specialFilePath); + } + specialFileRelatePath = specialFileRelatePath.split(path.sep).join('/'); + const importStr = `import {${propertyTypeName}} from '${ + specialFileRelatePath}${ + specialFileRelatePath.endsWith('/') ? '' : '/'}${ + path.basename(specialFilePath).replace('.d.ts', '').replace('.d.ets', '')}'\n`; + if (extraImport.includes(importStr)) { + return; + } + extraImport.push(importStr); + return; + } + if (propertyTypeName.includes('<') || propertyTypeName.includes('[')) { + return; + } + console.log(sourceFile.fileName, 'propertyTypeName', propertyTypeName); + return; + } +} diff --git a/mock-generate/src/generate/generateMockJsFile.ts b/mock-generate/src/generate/generateMockJsFile.ts index 3e584345..7df4e79e 100644 --- a/mock-generate/src/generate/generateMockJsFile.ts +++ b/mock-generate/src/generate/generateMockJsFile.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,12 +13,15 @@ * limitations under the License. */ -import { SourceFile, SyntaxKind } from 'typescript'; -import { collectAllLegalImports, firstCharacterToUppercase, getAllFileNameList } from '../common/commonUtils'; -import { ImportElementEntity } from '../declaration-node/importAndExportDeclaration'; -import { getDefaultExportClassDeclaration, getSourceFileFunctions, getSourceFileVariableStatements, SourceFileEntity } from '../declaration-node/sourceFileElementsAssemply'; +import fs from 'fs'; +import path from 'path'; +import { ScriptTarget, SyntaxKind, createSourceFile } from 'typescript'; +import type { SourceFile } from 'typescript'; +import { collectAllLegalImports, dtsFileList, firstCharacterToUppercase, getAllFileNameList, getApiInputPath } from '../common/commonUtils'; +import type { ImportElementEntity } from '../declaration-node/importAndExportDeclaration'; +import { getDefaultExportClassDeclaration } from '../declaration-node/sourceFileElementsAssemply'; +import type { SourceFileEntity } from '../declaration-node/sourceFileElementsAssemply'; import { generateClassDeclaration } from './generateClassDeclaration'; -import { generateCommonFunction } from './generateCommonFunction'; import { generateEnumDeclaration } from './generateEnumDeclaration'; import { addToIndexArray } from './generateIndex'; import { generateInterfaceDeclaration } from './generateInterfaceDeclaration'; @@ -26,7 +29,7 @@ import { generateModuleDeclaration } from './generateModuleDeclaration'; import { generateStaticFunction } from './generateStaticFunction'; import { addToSystemIndexArray } from './generateSystemIndex'; import { generateTypeAliasDeclaration } from './generateTypeAlias'; -import { generateVariableStatementDelcatation } from './generateVariableStatementDeclaration'; +import { generateExportFunction } from './generateExportFunction'; /** * generate mock file string @@ -37,25 +40,29 @@ import { generateVariableStatementDelcatation } from './generateVariableStatemen * @returns */ export function generateSourceFileElements(rootName: string, sourceFileEntity: SourceFileEntity, sourceFile: SourceFile, fileName: string): string { + let mockApi = ''; const mockFunctionElements: Array = []; + const dependsSourceFileList = collectReferenceFiles(sourceFile); const heritageClausesArray = getCurrentApiHeritageArray(sourceFileEntity, sourceFile); + const extraImport = []; + if (sourceFileEntity.importDeclarations.length > 0) { sourceFileEntity.importDeclarations.forEach(value => { - mockApi += generateImportDeclaration(value, fileName, heritageClausesArray); + mockApi += generateImportDeclaration(value, fileName, heritageClausesArray, sourceFile.fileName, dependsSourceFileList); }); } if (sourceFileEntity.moduleDeclarations.length > 0) { sourceFileEntity.moduleDeclarations.forEach(value => { - mockApi += generateModuleDeclaration('', value, sourceFile, fileName) + '\n'; + mockApi += generateModuleDeclaration('', value, sourceFile, fileName, mockApi, extraImport) + '\n'; }); } if (sourceFileEntity.classDeclarations.length > 0) { sourceFileEntity.classDeclarations.forEach(value => { if (!fileName.startsWith('system_') && !value.exportModifiers.includes(SyntaxKind.DefaultKeyword)) { - mockApi += generateClassDeclaration('', value, false, '', fileName, sourceFile, false) + '\n'; + mockApi += generateClassDeclaration('', value, false, '', fileName, sourceFile, false, mockApi) + '\n'; mockFunctionElements.push({ elementName: value.className, type: 'class' }); } }); @@ -63,7 +70,8 @@ export function generateSourceFileElements(rootName: string, sourceFileEntity: S if (sourceFileEntity.interfaceDeclarations.length > 0) { sourceFileEntity.interfaceDeclarations.forEach(value => { - mockApi += generateInterfaceDeclaration('', value, sourceFile, true, sourceFileEntity.interfaceDeclarations) + '\n'; + mockApi += generateInterfaceDeclaration('', value, sourceFile, true, mockApi, sourceFileEntity.interfaceDeclarations, + sourceFileEntity.importDeclarations, extraImport) + '\n'; mockFunctionElements.push({ elementName: value.interfaceName, type: 'interface' }); }); } @@ -77,18 +85,24 @@ export function generateSourceFileElements(rootName: string, sourceFileEntity: S if (sourceFileEntity.typeAliasDeclarations.length > 0) { sourceFileEntity.typeAliasDeclarations.forEach(value => { - mockApi += generateTypeAliasDeclaration(value, false) + '\n'; + mockApi += generateTypeAliasDeclaration(value, false, sourceFile, extraImport) + '\n'; mockFunctionElements.push({ elementName: value.typeAliasName, type: 'typeAlias' }); }); } + if (sourceFileEntity.functionDeclarations.length > 0) { + sourceFileEntity.functionDeclarations.forEach(value => { + mockApi += generateExportFunction(value, sourceFile, mockApi) + '\n'; + }); + } + if (sourceFileEntity.moduleDeclarations.length === 0 && (fileName.startsWith('ohos_') || fileName.startsWith('system_') || fileName.startsWith('webgl'))) { const mockNameArr = fileName.split('_'); const mockName = mockNameArr[mockNameArr.length - 1]; const defaultExportClass = getDefaultExportClassDeclaration(sourceFile); if (defaultExportClass.length > 0) { defaultExportClass.forEach(value => { - mockApi += generateClassDeclaration(rootName, value, false, mockName, '', sourceFile, false) + '\n'; + mockApi += generateClassDeclaration(rootName, value, false, mockName, '', sourceFile, false, mockApi) + '\n'; mockFunctionElements.push({ elementName: value.className, type: 'class' }); }); } @@ -104,7 +118,7 @@ export function generateSourceFileElements(rootName: string, sourceFileEntity: S if (defaultClass.length > 0) { defaultClass.forEach(value => { value.staticMethods.forEach(val => { - staticMethodBody += generateStaticFunction(val, true, sourceFile); + staticMethodBody += generateStaticFunction(val, true, sourceFile, mockApi); }); }); } @@ -128,17 +142,21 @@ export function generateSourceFileElements(rootName: string, sourceFileEntity: S const mockNameArr = fileName.split('_'); const mockName = mockNameArr[mockNameArr.length - 1]; defaultExportClass.forEach(value => { - mockApi += generateClassDeclaration(rootName, value, false, mockName, '', sourceFile, false) + '\n'; + mockApi += generateClassDeclaration(rootName, value, false, mockName, '', sourceFile, false, mockApi) + '\n'; }); } } if (sourceFileEntity.exportDeclarations.length > 0) { sourceFileEntity.exportDeclarations.forEach(value => { + if (value.includes('export type {')) { + return; + } if (!value.includes('export {')) { mockApi += `${value}\n`; } }); } + mockApi = extraImport.join('') + mockApi; return mockApi; } @@ -146,63 +164,51 @@ export function generateSourceFileElements(rootName: string, sourceFileEntity: S * generate import definition * @param importEntity * @param sourceFileName + * @param heritageClausesArray + * @param currentFilePath + * @param dependsSourceFileList * @returns */ -export function generateImportDeclaration(importEntity: ImportElementEntity, sourceFileName: string, heritageClausesArray: string[]): string { - let importPathName = ''; - const importPathSplit = importEntity.importPath.split('/'); - let fileName = importPathSplit[importPathSplit.length - 1]; - if (fileName.endsWith('.d.ts')) { - fileName = fileName.split('.d.')[0]; +export function generateImportDeclaration( + importEntity: ImportElementEntity, + sourceFileName: string, + heritageClausesArray: string[], + currentFilePath: string, + dependsSourceFileList: SourceFile[]): string { + const importDeclaration = referenctImport2ModuleImport(importEntity, currentFilePath, dependsSourceFileList); + if (importDeclaration) { + return importDeclaration; } - if (fileName.includes('@')) { - importPathName = fileName.replace('@', '').replace(/\./g, '_'); - } else { - importPathName = fileName.replace(/\./g, '_'); + + const importPathSplit = importEntity.importPath.split('/'); + + let importPath = importPathSplit.slice(0, -1).join('/') + '/'; + importPath += getImportPathName(importPathSplit); + + let importElements = generateImportElements(importEntity, heritageClausesArray); + if (importElements === '{ mockWantAgent }' && importPath.includes('ohos_app_ability_wantAgent')) { + importElements = '{ mockWantAgent as mockAbilityWantAgent }'; } - let importPath = ''; - for (let i = 0; i < importPathSplit.length - 1; i++) { - importPath += importPathSplit[i] + '/'; + const testPath = importPath.replace(/"/g, '').replace(/'/g, '').split('/'); + if (!getAllFileNameList().has(testPath[testPath.length - 1]) && testPath[testPath.length - 1] !== 'ohos_application_want') { + return ''; } - importPath += importPathName; - let importElements = importEntity.importElements; - if (!importElements.includes('{') && !importElements.includes('* as') && !heritageClausesArray.includes(importElements)) { - if (importEntity.importPath.includes('@ohos')) { - const tmpArr = importEntity.importPath.split('.'); - importElements = `{ mock${firstCharacterToUppercase(tmpArr[tmpArr.length - 1].replace('"', '').replace('\'', ''))} }`; - } else { - importElements = `{ ${importElements} }`; - } + + let tmpImportPath = importPath.replace(/'/g, '').replace(/"/g, ''); + if (!tmpImportPath.startsWith('./') && !tmpImportPath.startsWith('../')) { + importPath = `'./${tmpImportPath}'`; } - if (checIsDefaultExportClass(importEntity.importElements)) { - importElements = `{ ${importEntity.importElements} }`; + if (sourceFileName === 'tagSession' && tmpImportPath === './basic' || sourceFileName === 'notificationContent' && + tmpImportPath === './ohos_multimedia_image') { + importPath = `'.${importPath.replace(/'/g, '')}'`; } - const testPath = importPath.replace(/"/g, '').replace(/'/g, '').split('/'); - if (getAllFileNameList().has(testPath[testPath.length - 1]) || testPath[testPath.length - 1] === 'ohos_application_want') { - const tmpImportPath = importPath.replace(/'/g, '').replace(/"/g, ''); - if (!tmpImportPath.startsWith('./') && !tmpImportPath.startsWith('../')) { - importPath = `'./${tmpImportPath}'`; - } - if (sourceFileName === 'tagSession' && importPath === `'./basic'` || sourceFileName === 'notificationContent' && importPath === `'./ohos_multimedia_image'`) { - importPath = `'.${importPath.replace(/'/g, '')}'`; - } - // adapt no rules .d.ts - if (importElements.trimRight().trimEnd() === 'AccessibilityExtensionContext, { AccessibilityElement }') { - importElements = '{ AccessibilityExtensionContext, AccessibilityElement }'; - } - if (importElements.trimRight().trimEnd() === '{ image }') { - importElements = '{ mockImage as image }'; - } - if (sourceFileName === 'AbilityContext' && importPath === `'../ohos_application_Ability'` || - sourceFileName === 'Context' && importPath === `"./ApplicationContext"`) { - return ''; - } - collectAllLegalImports(importElements); - return `import ${importElements} from ${importPath}\n`; - } else { + if (sourceFileName === 'AbilityContext' && tmpImportPath === '../ohos_application_Ability' || + sourceFileName === 'Context' && tmpImportPath === './ApplicationContext') { return ''; } + collectAllLegalImports(importElements); + return `import ${importElements} from ${importPath}\n`; } /** @@ -210,8 +216,9 @@ export function generateImportDeclaration(importEntity: ImportElementEntity, sou * @param importName * @returns */ - function checIsDefaultExportClass(importName: string): boolean { - const defaultExportClass = ['Context', 'BaseContext', 'ExtensionContext', 'ApplicationContext', 'ExtensionAbility', 'Ability']; +function checIsDefaultExportClass(importName: string): boolean { + const defaultExportClass = ['Context', 'BaseContext', 'ExtensionContext', 'ApplicationContext', + 'ExtensionAbility', 'Ability', 'UIExtensionAbility', 'UIExtensionContext']; return defaultExportClass.includes(importName); } @@ -241,6 +248,98 @@ function getCurrentApiHeritageArray(sourceFileEntity: SourceFileEntity, sourceFi return heritageClausesArray; } +function collectReferenceFiles(sourceFile: SourceFile): SourceFile[] { + const referenceElementTemplate = /\/\/\/\s* { + const referenceRelatePath = element.split(/path=["']/g)[1]; + const realReferenceFilePath = contentRelatePath2RealRelatePath(sourceFile.fileName, referenceRelatePath); + if (!realReferenceFilePath) { + return; + } + + if (!fs.existsSync(realReferenceFilePath)) { + console.error(`Can not resolve file: ${realReferenceFilePath}`); + return; + } + const code = fs.readFileSync(realReferenceFilePath); + referenceFiles.push(createSourceFile(realReferenceFilePath, code.toString(), ScriptTarget.Latest)); + !dtsFileList.includes(realReferenceFilePath) && dtsFileList.push(realReferenceFilePath); + }); + return referenceFiles; +} + +function contentRelatePath2RealRelatePath(currentFilePath: string, contentReferenceRelatePath: string): string { + const conmponentSourceFileTemplate = /component\/[^'"\/]+\.d\.ts/; + const currentFolderSourceFileTemplate = /\.\/[^\/]+\.d\.ts/; + const baseFileNameTemplate = /[^\/]+\.d\.ts/; + + let realReferenceFilePath: string; + if (conmponentSourceFileTemplate.test(contentReferenceRelatePath)) { + const newRelateReferencePath = contentReferenceRelatePath.match(conmponentSourceFileTemplate)[0]; + const referenceFileName = path.basename(newRelateReferencePath); + realReferenceFilePath = path.join(getApiInputPath(), '@internal', 'component', 'ets', referenceFileName); + } else if (currentFolderSourceFileTemplate.test(contentReferenceRelatePath)) { + const referenceFileName = path.basename(contentReferenceRelatePath); + realReferenceFilePath = currentFilePath.replace(baseFileNameTemplate, referenceFileName).replace(/\//g, path.sep); + } else { + console.error(`Can not find reference ${contentReferenceRelatePath} from ${currentFilePath}`); + return ''; + } + return realReferenceFilePath; +} + +export function referenctImport2ModuleImport(importEntity: ImportElementEntity, currentFilePath: string, + dependsSourceFileList: SourceFile[]): string { + if (dependsSourceFileList.length && !importEntity.importPath.includes('.')) { + for (let i = 0; i < dependsSourceFileList.length; i++) { + if (dependsSourceFileList[i].text.includes(`declare module ${importEntity.importPath.replace(/'/g, '"')}`)) { + let relatePath = path.relative(path.dirname(currentFilePath), dependsSourceFileList[i].fileName) + .replace(/\\/g, '/') + .replace(/.d.ts/g, '') + .replace(/.d.es/g, ''); + relatePath = (relatePath.startsWith('@internal/component') ? './' : '') + relatePath; + return `import ${importEntity.importElements} from "${relatePath}"\n`; + } + } + } + return ''; +} + +function getImportPathName(importPathSplit: string[]): string { + let importPathName: string; + let fileName = importPathSplit[importPathSplit.length - 1]; + if (fileName.endsWith('.d.ts') || fileName.endsWith('.d.ets')) { + fileName = fileName.split(/\.d\.e?ts/)[0]; + } + if (fileName.includes('@')) { + importPathName = fileName.replace('@', '').replace(/\./g, '_'); + } else { + importPathName = fileName.replace(/\./g, '_'); + } + return importPathName; +} + +function generateImportElements(importEntity: ImportElementEntity, heritageClausesArray: string[]): string { + let importElements = importEntity.importElements; + if (!importElements.includes('{') && !importElements.includes('* as') && !heritageClausesArray.includes(importElements) && importEntity.importPath.includes('@ohos')) { + const tmpArr = importEntity.importPath.split('.'); + importElements = `{ mock${firstCharacterToUppercase(tmpArr[tmpArr.length - 1].replace('"', '').replace('\'', ''))} }`; + } else { + // adapt no rules .d.ts + if (importElements.trimRight().trimEnd() === 'AccessibilityExtensionContext, { AccessibilityElement }') { + importElements = '{ AccessibilityExtensionContext, AccessibilityElement }'; + } else if (importElements.trimRight().trimEnd() === '{ image }') { + importElements = '{ mockImage as image }'; + } + } + return importElements; +} + + interface MockFunctionElementEntity { elementName: string, type: string diff --git a/mock-generate/src/generate/generateModuleDeclaration.ts b/mock-generate/src/generate/generateModuleDeclaration.ts index 8c5f9289..4967044b 100644 --- a/mock-generate/src/generate/generateModuleDeclaration.ts +++ b/mock-generate/src/generate/generateModuleDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,9 +13,11 @@ * limitations under the License. */ -import { SourceFile, SyntaxKind } from 'typescript'; +import path from 'path'; +import { SyntaxKind } from 'typescript'; +import type { SourceFile } from 'typescript'; import { firstCharacterToUppercase } from '../common/commonUtils'; -import { ModuleBlockEntity } from '../declaration-node/moduleDeclaration'; +import type { ModuleBlockEntity } from '../declaration-node/moduleDeclaration'; import { getDefaultExportClassDeclaration, getSourceFileFunctions, getSourceFileVariableStatements @@ -37,14 +39,19 @@ import { generateVariableStatementDelcatation } from './generateVariableStatemen * @param moduleEntity * @param sourceFile * @param filename + * @param extraImport * @returns */ -export function generateModuleDeclaration(rootName: string, moduleEntity: ModuleBlockEntity, sourceFile: SourceFile, filename: string): string { - const moduleName = moduleEntity.moduleName; - const mockNameArr = filename.split('_'); - const mockName = mockNameArr[mockNameArr.length - 1]; - let moduleBody = `export function mock${firstCharacterToUppercase(mockName)}() {\n`; - addToIndexArray({ fileName: filename, mockFunctionName: `mock${firstCharacterToUppercase(mockName)}` }); +export function generateModuleDeclaration(rootName: string, moduleEntity: ModuleBlockEntity, sourceFile: SourceFile, + filename: string, mockApi: string, extraImport: string[]): string { + let moduleName = moduleEntity.moduleName.replace(/["']/g, ''); + let moduleBody = `export function mock${firstCharacterToUppercase(moduleName)}() {\n`; + if (!(moduleEntity.exportModifiers.includes(SyntaxKind.DeclareKeyword) && + (moduleEntity.moduleName.startsWith('"') || moduleEntity.moduleName.startsWith('\''))) && + path.basename(sourceFile.fileName).startsWith('@ohos') + ) { + addToIndexArray({ fileName: filename, mockFunctionName: `mock${firstCharacterToUppercase(moduleName)}` }); + } let outBody = ''; const defaultExportClass = getDefaultExportClassDeclaration(sourceFile); @@ -63,13 +70,13 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module if (value.staticMethods.length > 0) { let staticMethodBody = ''; value.staticMethods.forEach(val => { - staticMethodBody += generateStaticFunction(val, true, sourceFile) + '\n'; + staticMethodBody += generateStaticFunction(val, true, sourceFile, mockApi) + '\n'; }); moduleBody += staticMethodBody; } moduleBody += '}'; } else { - outBody += generateClassDeclaration('', value, false, '', filename, sourceFile, false); + outBody += generateClassDeclaration('', value, false, '', filename, sourceFile, false, mockApi); } } }); @@ -77,7 +84,7 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module if (moduleEntity.typeAliasDeclarations.length > 0) { moduleEntity.typeAliasDeclarations.forEach(value => { - outBody += generateTypeAliasDeclaration(value, true) + '\n'; + outBody += generateTypeAliasDeclaration(value, true, sourceFile, extraImport) + '\n'; }); } @@ -90,9 +97,9 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module if (moduleEntity.classDeclarations.length > 0) { moduleEntity.classDeclarations.forEach(value => { if (value.exportModifiers.length > 0 && value.exportModifiers.includes(SyntaxKind.ExportKeyword)) { - outBody += generateClassDeclaration(moduleName, value, false, '', '', sourceFile, false) + '\n'; + outBody += generateClassDeclaration(moduleName, value, false, '', '', sourceFile, false, mockApi) + '\n'; } else { - moduleBody += '\t' + generateClassDeclaration(moduleName, value, false, '', '', sourceFile, true) + '\n'; + moduleBody += '\t' + generateClassDeclaration(moduleName, value, false, '', '', sourceFile, true, mockApi) + '\n'; } }); } @@ -100,9 +107,9 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module if (moduleEntity.interfaceDeclarations.length > 0) { moduleEntity.interfaceDeclarations.forEach(value => { if (value.exportModifiers.length > 0) { - outBody += generateInterfaceDeclaration(moduleName, value, sourceFile, false, moduleEntity.interfaceDeclarations) + ';\n'; + outBody += generateInterfaceDeclaration(moduleName, value, sourceFile, false, mockApi, moduleEntity.interfaceDeclarations) + ';\n'; } else { - moduleBody += '\t' + generateInterfaceDeclaration(moduleName, value, sourceFile, false, moduleEntity.interfaceDeclarations) + ';\n'; + moduleBody += '\t' + generateInterfaceDeclaration(moduleName, value, sourceFile, false, mockApi, moduleEntity.interfaceDeclarations) + ';\n'; } }); } @@ -117,16 +124,10 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module }); } - if (moduleEntity.moduleDeclarations.length > 0) { - moduleEntity.moduleDeclarations.forEach(value => { - moduleBody += generateInnerModule(value, sourceFile) + '\n'; - }); - } - let functionBody = ''; if (moduleEntity.functionDeclarations.size > 0) { moduleEntity.functionDeclarations.forEach(value => { - functionBody += '\t' + generateCommonFunction(moduleName, value, sourceFile) + '\n'; + functionBody += '\t' + generateCommonFunction(moduleName, value, sourceFile, mockApi) + '\n'; }); } @@ -134,7 +135,7 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module if (moduleEntity.variableStatements.length > 0) { moduleEntity.variableStatements.forEach(value => { value.forEach(val => { - moduleBody += generateVariableStatementDelcatation(val) + '\n'; + moduleBody += generateVariableStatementDelcatation(val, false) + '\n'; }); }); } @@ -143,7 +144,7 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module let sourceFileFunctionBody = ''; if (sourceFileFunctions.size > 0) { sourceFileFunctions.forEach(value => { - sourceFileFunctionBody += generateCommonFunction(moduleName, value, sourceFile); + sourceFileFunctionBody += generateCommonFunction(moduleName, value, sourceFile, mockApi); }); } @@ -152,7 +153,7 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module if (sourceFileVariableStatements.length > 0) { sourceFileVariableStatements.forEach(value => { value.forEach(val => { - sourceFileStatementBody += generateVariableStatementDelcatation(val); + sourceFileStatementBody += generateVariableStatementDelcatation(val, false); }); }); } @@ -176,19 +177,42 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module return moduleBody; } +/** + * generate inner module for declare module + * @param moduleEntity + * @returns + */ +function generateInnerDeclareModule(moduleEntity: ModuleBlockEntity): string { + let moduleName = '$' + moduleEntity.moduleName.replace(/["']/g, ''); + let module = `\n\texport const ${moduleName} = `; + if (moduleEntity.exportDeclarations.length > 0) { + moduleEntity.exportDeclarations.forEach(value => { + module += value.match(/{[^{}]*}/g)[0] + '\n'; + }); + } + return module; +} + /** * generate inner module * @param moduleEntity * @param sourceFile + * @param extraImport * @returns */ -function generateInnerModule(moduleEntity: ModuleBlockEntity, sourceFile: SourceFile): string { +function generateInnerModule(moduleEntity: ModuleBlockEntity, sourceFile: SourceFile, extraImport: string[]): string { const moduleName = moduleEntity.moduleName; - let innerModuleBody = `const ${moduleName} = {`; + let innerModuleBody = `const ${moduleName} = (()=> {`; + + if (moduleEntity.enumDeclarations.length > 0) { + moduleEntity.enumDeclarations.forEach(value => { + innerModuleBody += generateEnumDeclaration(moduleName, value) + '\n'; + }); + } if (moduleEntity.typeAliasDeclarations.length > 0) { moduleEntity.typeAliasDeclarations.forEach(value => { - innerModuleBody += generateTypeAliasDeclaration(value, true) + '\n'; + innerModuleBody += generateTypeAliasDeclaration(value, true, sourceFile, extraImport) + '\n'; }); } @@ -200,27 +224,21 @@ function generateInnerModule(moduleEntity: ModuleBlockEntity, sourceFile: Source if (moduleEntity.interfaceDeclarations.length > 0) { moduleEntity.interfaceDeclarations.forEach(value => { - innerModuleBody += generateInterfaceDeclaration(moduleName, value, sourceFile, false, moduleEntity.interfaceDeclarations) + '\n'; - }); - } - - if (moduleEntity.enumDeclarations.length > 0) { - moduleEntity.enumDeclarations.forEach(value => { - innerModuleBody += generateEnumDeclaration(moduleName, value) + '\n'; + innerModuleBody += generateInterfaceDeclaration(moduleName, value, sourceFile, false, '', moduleEntity.interfaceDeclarations) + '\n'; }); } - let functionBody = ''; + let functionBody = 'return {'; if (moduleEntity.functionDeclarations.size > 0) { moduleEntity.functionDeclarations.forEach(value => { - functionBody += generateCommonFunction(moduleName, value, sourceFile) + '\n'; + functionBody += generateCommonFunction(moduleName, value, sourceFile, '') + '\n'; }); } if (moduleEntity.variableStatements.length > 0) { moduleEntity.variableStatements.forEach(value => { value.forEach(val => { - innerModuleBody += generateVariableStatementDelcatation(val) + '\n'; + innerModuleBody += generateVariableStatementDelcatation(val, true) + '\n'; }); }); } @@ -234,7 +252,7 @@ function generateInnerModule(moduleEntity: ModuleBlockEntity, sourceFile: Source if (exportString !== '') { innerModuleBody += '\t' + exportString; } - innerModuleBody += '\t};'; + innerModuleBody += '\t};})();'; return innerModuleBody; } @@ -245,6 +263,9 @@ function generateInnerModule(moduleEntity: ModuleBlockEntity, sourceFile: Source */ function getModuleExportElements(moduleEntity: ModuleBlockEntity): Array { const exportElements: Array = []; + if (moduleEntity.moduleName.startsWith('"') && moduleEntity.moduleName.endsWith('"')) { + return exportElements; + } if (moduleEntity.classDeclarations.length > 0) { moduleEntity.classDeclarations.forEach(value => { exportElements.push({ name: firstCharacterToUppercase(value.className), type: 'class' }); diff --git a/mock-generate/src/generate/generatePropertyDeclaration.ts b/mock-generate/src/generate/generatePropertyDeclaration.ts index 12e56923..8287fc69 100644 --- a/mock-generate/src/generate/generatePropertyDeclaration.ts +++ b/mock-generate/src/generate/generatePropertyDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,9 +13,10 @@ * limitations under the License. */ -import { SourceFile, SyntaxKind } from 'typescript'; +import { SyntaxKind } from 'typescript'; +import type { SourceFile } from 'typescript'; import { getClassNameSet } from '../common/commonUtils'; -import { PropertyEntity } from '../declaration-node/propertyDeclaration'; +import type { PropertyEntity } from '../declaration-node/propertyDeclaration'; import { getTheRealReferenceFromImport } from './generateCommonUtil'; /** @@ -47,7 +48,7 @@ export function generatePropertyDeclaration(rootName: string, propertyDeclaratio } else if (propertyDeclaration.kind === SyntaxKind.TypeReference) { propertyBody = `this.${propertyDeclaration.propertyName} = `; if (getClassNameSet().has(propertyDeclaration.propertyTypeName)) { - if (propertyDeclaration.propertyTypeName !== 'Want' && propertyDeclaration.propertyTypeName !== 'InputMethodExtensionContext') { + if (!['Want', 'InputMethodExtensionContext'].includes(propertyDeclaration.propertyTypeName)) { propertyBody += `new ${getTheRealReferenceFromImport(sourceFile, propertyDeclaration.propertyTypeName)}();`; } else { propertyBody += `${getTheRealReferenceFromImport(sourceFile, propertyDeclaration.propertyTypeName)};`; @@ -58,7 +59,7 @@ export function generatePropertyDeclaration(rootName: string, propertyDeclaratio } else if (propertyDeclaration.kind === SyntaxKind.NumericLiteral || propertyDeclaration.kind === SyntaxKind.StringLiteral) { propertyBody = `this.${propertyDeclaration.propertyName} = ${propertyDeclaration.propertyTypeName};`; } else { - propertyBody = `this.${propertyDeclaration.propertyName} = '[PC Previwe] unkonwn ${propertyDeclaration.propertyName}';`; + propertyBody = `this.${propertyDeclaration.propertyName} = '[PC Previwe] unknown ${propertyDeclaration.propertyName}';`; } } return propertyBody; diff --git a/mock-generate/src/generate/generatePropertySignatureDeclaration.ts b/mock-generate/src/generate/generatePropertySignatureDeclaration.ts index c69fefba..335e6181 100644 --- a/mock-generate/src/generate/generatePropertySignatureDeclaration.ts +++ b/mock-generate/src/generate/generatePropertySignatureDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,8 +13,9 @@ * limitations under the License. */ -import { SourceFile, SyntaxKind } from 'typescript'; -import { PropertySignatureEntity } from '../declaration-node/propertySignatureDeclaration'; +import { SyntaxKind } from 'typescript'; +import type { SourceFile } from 'typescript'; +import type { PropertySignatureEntity } from '../declaration-node/propertySignatureDeclaration'; import { checkIsGenericSymbol, getCallbackStatement, getTheRealReferenceFromImport, getWarnConsole, propertyTypeWhiteList @@ -27,12 +28,12 @@ import { * @param sourceFile * @returns */ -export function generatePropertySignatureDeclaration(rootName: string, propertySignature: PropertySignatureEntity, sourceFile: SourceFile): string { +export function generatePropertySignatureDeclaration(rootName: string, propertySignature: PropertySignatureEntity, sourceFile: SourceFile, mockApi: string): string { let propertySignatureBody = ''; if (propertySignature.kind === SyntaxKind.FunctionType) { propertySignatureBody += `${propertySignature.propertyName}: function(...args) {`; propertySignatureBody += getWarnConsole(rootName, propertySignature.propertyName); - propertySignatureBody += getCallbackStatement(); + propertySignatureBody += getCallbackStatement(mockApi); propertySignatureBody += '},\n'; } else { if (propertySignature.propertyTypeName.startsWith('{')) { @@ -44,12 +45,16 @@ export function generatePropertySignatureDeclaration(rootName: string, propertyS propertySignatureBody = `${propertySignature.propertyName}: {key: {}},`; } else if (propertySignature.propertyTypeName === 'string' || checkIsGenericSymbol(propertySignature.propertyTypeName) || propertySignature.propertyTypeName === 'bool' || propertySignature.propertyTypeName === 'Data') { - propertySignatureBody = `${propertySignature.propertyName}: '[PC Preview] unkonwn ${propertySignature.propertyName}',`; + propertySignatureBody = `${propertySignature.propertyName}: '[PC Preview] unknown ${propertySignature.propertyName}',`; } else { if (propertySignature.propertyTypeName.includes('<')) { - const preSplit = propertySignature.propertyTypeName.split('<'); - const genericArg = preSplit[preSplit.length - 1].split('>')[0]; - propertySignatureBody = `${propertySignature.propertyName}: ${genericArg},`; + if (propertySignature.propertyTypeName.startsWith('AsyncCallback')) { + propertySignatureBody = `${propertySignature.propertyName}: ()=>{},`; + } else { + const preSplit = propertySignature.propertyTypeName.split('<'); + const genericArg = preSplit[preSplit.length - 1].split('>')[0]; + propertySignatureBody = `${propertySignature.propertyName}: ${genericArg},`; + } } else { if (propertyTypeWhiteList(propertySignature.propertyTypeName) === propertySignature.propertyTypeName) { propertySignatureBody = `${propertySignature.propertyName}: ${getTheRealReferenceFromImport(sourceFile, propertySignature.propertyTypeName)},`; @@ -61,15 +66,18 @@ export function generatePropertySignatureDeclaration(rootName: string, propertyS } else if (propertySignature.kind === SyntaxKind.NumberKeyword) { propertySignatureBody = `${propertySignature.propertyName}: 0,`; } else if (propertySignature.kind === SyntaxKind.StringKeyword) { - propertySignatureBody = `${propertySignature.propertyName}: '[PC Preview] unkonwn ${propertySignature.propertyName}',`; + propertySignatureBody = `${propertySignature.propertyName}: '[PC Preview] unknown ${propertySignature.propertyName}',`; } else if (propertySignature.kind === SyntaxKind.BooleanKeyword) { propertySignatureBody = `${propertySignature.propertyName}: true,`; } else if (propertySignature.kind === SyntaxKind.UnionType) { - const unionFirstElement = propertySignature.propertyTypeName.split('|')[0].trimStart().trimEnd(); - if (unionFirstElement.startsWith('"')) { + let unionFirstElement = propertySignature.propertyTypeName.split('|')[0].trimStart().trimEnd(); + if (unionFirstElement.includes('[]')) { + unionFirstElement = '[]'; + } + if (unionFirstElement.startsWith('"') || unionFirstElement.startsWith("'")) { propertySignatureBody = `${propertySignature.propertyName}: ${unionFirstElement},`; } else if (unionFirstElement === 'string') { - propertySignatureBody = `${propertySignature.propertyName}: '[PC Preview] unkonwn ${propertySignature.propertyName}',`; + propertySignatureBody = `${propertySignature.propertyName}: '[PC Preview] unknown ${propertySignature.propertyName}',`; } else if (unionFirstElement === 'number') { propertySignatureBody = `${propertySignature.propertyName}: 0,`; } else if (unionFirstElement === 'boolean') { @@ -79,18 +87,20 @@ export function generatePropertySignatureDeclaration(rootName: string, propertyS } else { let element = unionFirstElement; if (element === 'HTMLCanvasElement') { - element = `'[PC Preview] unkonwn ${propertySignature.propertyName}'`; + element = `'[PC Preview] unknown ${propertySignature.propertyName}'`; } else if (element === 'WebGLActiveInfo') { - element = `{size: '[PC Preview] unkonwn GLint', type: 0, name: '[PC Preview] unkonwn name'}`; - } else if (element === 'accessibility.EventType') { - element = `mockAccessibility().EventType`; + element = '{size: \'[PC Preview] unknown GLint\', type: 0, name: \'[PC Preview] unknown name\'}'; + } else if (element.startsWith('Array')) { + element = '[]'; + } else if (propertyTypeWhiteList(unionFirstElement) === unionFirstElement) { + element = getTheRealReferenceFromImport(sourceFile, unionFirstElement); } propertySignatureBody = `${propertySignature.propertyName}: ${element},`; } } else if (propertySignature.kind === SyntaxKind.ArrayType) { propertySignatureBody = `${propertySignature.propertyName}: [],`; } else { - propertySignatureBody = `${propertySignature.propertyName}: '[PC Preview] unkonwn ${propertySignature.propertyName}',`; + propertySignatureBody = `${propertySignature.propertyName}: '[PC Preview] unknown ${propertySignature.propertyName}',`; } } return propertySignatureBody; diff --git a/mock-generate/src/generate/generateStaticFunction.ts b/mock-generate/src/generate/generateStaticFunction.ts index fda79e06..0668da3c 100644 --- a/mock-generate/src/generate/generateStaticFunction.ts +++ b/mock-generate/src/generate/generateStaticFunction.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,9 +13,10 @@ * limitations under the License. */ -import { SourceFile, SyntaxKind } from 'typescript'; +import { SyntaxKind } from 'typescript'; +import type { SourceFile } from 'typescript'; import { firstCharacterToUppercase } from '../common/commonUtils'; -import { StaticMethodEntity } from '../declaration-node/methodDeclaration'; +import type { StaticMethodEntity } from '../declaration-node/methodDeclaration'; import { generateSymbolIterator, getCallbackStatement, getReturnStatement, getWarnConsole } from './generateCommonUtil'; /** @@ -25,7 +26,7 @@ import { generateSymbolIterator, getCallbackStatement, getReturnStatement, getWa * @param sourceFile * @returns */ -export function generateStaticFunction(staticMethod: StaticMethodEntity, isSystem: boolean, sourceFile: SourceFile): string { +export function generateStaticFunction(staticMethod: StaticMethodEntity, isSystem: boolean, sourceFile: SourceFile, mockApi: string): string { let methodBody = ''; const rootName = staticMethod.className; const methodEntity = staticMethod.methodEntity; @@ -45,7 +46,7 @@ export function generateStaticFunction(staticMethod: StaticMethodEntity, isSyste const args = methodEntity.args; const len = args.length; if (args.length > 0 && args[len - 1].paramName === 'callback') { - methodBody += getCallbackStatement(); + methodBody += getCallbackStatement(mockApi, args[len - 1]?.paramTypeString); } if (methodEntity.returnType.returnKind !== SyntaxKind.VoidKeyword) { diff --git a/mock-generate/src/generate/generateSystemIndex.ts b/mock-generate/src/generate/generateSystemIndex.ts index b1c2b90d..386f00f4 100644 --- a/mock-generate/src/generate/generateSystemIndex.ts +++ b/mock-generate/src/generate/generateSystemIndex.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at diff --git a/mock-generate/src/generate/generateTypeAlias.ts b/mock-generate/src/generate/generateTypeAlias.ts index 96c987c7..5836ebe8 100644 --- a/mock-generate/src/generate/generateTypeAlias.ts +++ b/mock-generate/src/generate/generateTypeAlias.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,22 +13,133 @@ * limitations under the License. */ -import { TypeAliasEntity } from '../declaration-node/typeAliasDeclaration'; +import type { TypeAliasEntity, TypeAliasTypeEntity } from '../declaration-node/typeAliasDeclaration'; +import { firstCharacterToUppercase, getOhosInterfacesDir } from '../common/commonUtils'; +import path from 'path'; +import fs from 'fs'; +import type { SourceFile } from 'typescript'; + +const interceptIndex = 2; /** * generate type alias * @param typeAliasEntity * @param isInner + * @param sourceFile + * @param extraImport * @returns */ -export function generateTypeAliasDeclaration(typeAliasEntity: TypeAliasEntity, isInner: boolean): string { +export function generateTypeAliasDeclaration( + typeAliasEntity: TypeAliasEntity, isInner: boolean, sourceFile: SourceFile, extraImport: string[] +): string { let typeAliasName = ''; if (!isInner) { typeAliasName += `export const ${typeAliasEntity.typeAliasName} = `; } else { typeAliasName += `const ${typeAliasEntity.typeAliasName} = `; } + let typeAliasValue = ''; - typeAliasValue += `'[PC Preview] unkonwn ${typeAliasEntity.typeAliasName}'`; + + const typeAliasTypeElements = typeAliasEntity.typeAliasTypeElements; + + if (typeAliasTypeElements) { + typeAliasValue += parseImportExpression(typeAliasTypeElements, sourceFile, extraImport); + } + + if (!typeAliasValue) { + typeAliasValue += `'[PC Preview] unknown ${typeAliasEntity.typeAliasName}'`; + } return typeAliasName + typeAliasValue + ';'; } + +function getImportFileFullPath(typeName: string): string { + const importRelatePathTmp = typeName.match(/\('[^'()]+'\)/); + if (!importRelatePathTmp) { + return ''; + } + const importRelatePath = importRelatePathTmp[0].substring(interceptIndex, importRelatePathTmp[0].length - interceptIndex); + const tmpRealPath = getOhosInterfacesDir() + importRelatePath.replace('../api', '').replace(/\//g, path.sep); + if (fs.existsSync(tmpRealPath + '.d.ts')) { + return tmpRealPath + '.d.ts'; + } + + if (fs.existsSync(tmpRealPath + '.d.ets')) { + return tmpRealPath + '.d.ets'; + } + console.warn(`Can not find import \'${importRelatePath}\'`); + return ''; +} + +function pathToImportPath(currentFilePath: string, importFilePath: string): string { + const currentFilePathSteps = currentFilePath.replace(/.d.e?ts/, '').split('/'); + const importFilePathSteps = importFilePath.replace(/.d.e?ts/, '').split(path.sep); + const importFilePathStepsLength = importFilePathSteps.length; + importFilePathSteps[importFilePathStepsLength - 1] = importFilePathSteps[importFilePathStepsLength - 1] + .replace('@', '').replace(/\./g, '_'); + let differStepIndex: number; + for (differStepIndex = 0; differStepIndex < currentFilePathSteps.length; differStepIndex++) { + if (currentFilePathSteps[differStepIndex] !== importFilePathSteps[differStepIndex]) { + break; + } + } + const currentFileDifferPathSteps = currentFilePathSteps.slice(differStepIndex); + const importFileDifferPathSteps = importFilePathSteps.slice(differStepIndex); + if (currentFileDifferPathSteps.length === importFileDifferPathSteps.length + && currentFileDifferPathSteps.length === 1) { + return `./${path.basename(importFilePath)}`; + } else { + const steps = []; + for (let i = 0; i < currentFileDifferPathSteps.length - 1; i++) { + steps.push('..'); + } + const fullSteps = steps.concat(importFileDifferPathSteps); + return fullSteps.join('/'); + } +} + +function parseImportExpression( + typeAliasTypeElements: TypeAliasTypeEntity[], sourceFile: SourceFile, extraImport: string[] +): string { + for (let i = 0; i < typeAliasTypeElements.length; i++) { + const typeAliasTypeElement = typeAliasTypeElements[i]; + const typeName = typeAliasTypeElement.typeName; + if (!typeName?.trim().startsWith('import(')) { + continue; + } + const splitTypeName = typeName.split(')'); + const propertiesIndex = 1; + const properties = splitTypeName[propertiesIndex]; + const importPath = getImportFileFullPath(typeName); + const realImportPath = pathToImportPath(sourceFile.fileName, importPath); + if (!importPath) { + continue; + } + const importFileContent = fs.readFileSync(importPath, 'utf-8'); + if (properties.startsWith('.default')) { + let result = importFileContent.match(/export\sdefault\sclass\s[a-zA-Z]+/); + if (result) { + const defaultModuleName = '_' + result[0].replace(/export\sdefault\sclass\s/, ''); + const importStr = `import ${defaultModuleName} from '${realImportPath}';\n`; + !extraImport.includes(importStr) && extraImport.push(importStr); + return `${defaultModuleName}${properties.replace('.default', '')}`; + } + result = importFileContent.match(/export\sdefault\s[a-zA-Z]+;/); + if (result) { + const moduleName = result[0] + .replace(/export\sdefault\s/, '') + .replace(';', ''); + const mockFunctionName = `mock${firstCharacterToUppercase(moduleName)}`; + const importStr = `import {${mockFunctionName}} from '${realImportPath}';\n`; + !extraImport.includes(importStr) && extraImport.push(importStr); + return `${mockFunctionName}()${properties.replace('.default', '')}`; + } + } else { + const moduleName = properties.replace('.', '').split('.')[0]; + const importStr = `import {${moduleName} as _${moduleName}} from '${realImportPath}';\n`; + !extraImport.includes(importStr) && extraImport.push(importStr); + return `_${properties.replace('.', '')}`; + } + } + return ''; +} diff --git a/mock-generate/src/generate/generateVariableStatementDeclaration.ts b/mock-generate/src/generate/generateVariableStatementDeclaration.ts index 9c0db497..b39de52e 100644 --- a/mock-generate/src/generate/generateVariableStatementDeclaration.ts +++ b/mock-generate/src/generate/generateVariableStatementDeclaration.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -15,18 +15,23 @@ import { SyntaxKind } from 'typescript'; import { getClassNameSet } from '../common/commonUtils'; -import { StatementEntity } from '../declaration-node/variableStatementResolve'; +import type { StatementEntity } from '../declaration-node/variableStatementResolve'; /** * generate const variable statement * @param statementEntity * @returns */ -export function generateVariableStatementDelcatation(statementEntity: StatementEntity): string { - let statementBody = `${statementEntity.statementName}: `; +export function generateVariableStatementDelcatation(statementEntity: StatementEntity, isInnerModule: boolean): string { + let statementBody = ''; + if (isInnerModule) { + statementBody = `const ${statementEntity.statementName} = `; + } else { + statementBody = `${statementEntity.statementName}: `; + } let statementValue; if (statementEntity.typeKind === SyntaxKind.StringKeyword) { - statementValue = `''`; + statementValue = '\'\''; } else if (statementEntity.typeKind === SyntaxKind.LiteralType || statementEntity.typeKind === SyntaxKind.StringLiteral || statementEntity.typeKind === SyntaxKind.NumericLiteral) { if (statementEntity.initializer === '') { @@ -61,6 +66,10 @@ export function generateVariableStatementDelcatation(statementEntity: StatementE statementValue = `'[PC Preivew] unknown ${statementEntity.statementName}'`; } statementBody += statementValue; - statementBody += ','; + if (isInnerModule) { + statementBody += ';'; + } else { + statementBody += ','; + } return statementBody; } diff --git a/mock-generate/src/main.ts b/mock-generate/src/main.ts index 14a9fc71..3e97abe5 100644 --- a/mock-generate/src/main.ts +++ b/mock-generate/src/main.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -17,15 +17,13 @@ import fs from 'fs'; import path from 'path'; import os from 'os'; import { createSourceFile, ScriptTarget } from 'typescript'; -import { collectAllFileName, getAllClassDeclaration } from './common/commonUtils'; +import { collectAllFileName, getAllClassDeclaration, dtsFileList, getOhosInterfacesDir, getApiInputPath } from './common/commonUtils'; import { getSourceFileAssembly } from './declaration-node/sourceFileElementsAssemply'; import { generateEntry } from './generate/generateEntry'; import { generateIndex } from './generate/generateIndex'; import { generateSourceFileElements } from './generate/generateMockJsFile'; import { generateSystemIndex } from './generate/generateSystemIndex'; -const dtsFileList: Array = []; - /** * get all api .d.ts file path * @param dir @@ -33,7 +31,7 @@ const dtsFileList: Array = []; */ function getAllDtsFile(dir: string): Array { const arr = fs.readdirSync(dir); - if (!dir.toString().includes('node_modules') && !dir.toString().includes('/@internal/component/')) { + if (!dir.toString().includes('node_modules') && !dir.toString().includes(path.join('@internal', 'component'))) { arr.forEach(value => { const fullPath = path.join(dir, value); const stats = fs.statSync(fullPath); @@ -51,7 +49,7 @@ function getAllDtsFile(dir: string): Array { * delete the old mock file befor generate new mock file * @param outDir */ - function deleteOldMockJsFile(outDir: string) { +function deleteOldMockJsFile(outDir: string): void { const arr = fs.readdirSync(outDir); arr.forEach(value => { const currPath = path.join(outDir, value); @@ -73,7 +71,7 @@ function getAllDtsFile(dir: string): Array { * @param dirname * @returns */ -function mkdirsSync(dirname) { +function mkdirsSync(dirname): boolean { if (fs.existsSync(dirname)) { return true; } else { @@ -82,60 +80,70 @@ function mkdirsSync(dirname) { return true; } } + return false; } -function main() { - let interfaceRootDir = ''; - if (os.platform() === 'linux' || os.platform() === 'darwin') { - interfaceRootDir = __dirname.split('/out')[0]; - } else { - interfaceRootDir = __dirname.split('\\out')[0]; - } - const dtsDir = path.join(interfaceRootDir, './interface/sdk-js/api'); +function main(): void { + const dtsDir = getApiInputPath(); const outMockJsFileDir = path.join(__dirname, '../../runtime/main/extend/systemplugin'); - deleteOldMockJsFile(outMockJsFileDir); + // deleteOldMockJsFile(outMockJsFileDir); getAllDtsFile(dtsDir); dtsFileList.forEach(value => { collectAllFileName(value); - if (value.endsWith('.d.ts')) { + if (value.endsWith('.d.ts') || value.endsWith('.d.ets')) { const code = fs.readFileSync(value); - const sourceFile = createSourceFile('', code.toString(), ScriptTarget.Latest); + const sourceFile = createSourceFile(value, code.toString(), ScriptTarget.Latest); getAllClassDeclaration(sourceFile); } }); - dtsFileList.forEach(value => { + let index = 0; + while (index < dtsFileList.length) { + const value = dtsFileList[index]; + index++; + + if (!value.endsWith('.d.ts') && !value.endsWith('.d.ets')) { + continue; + } + + const code = fs.readFileSync(value); + const sourceFile = createSourceFile(value, code.toString(), ScriptTarget.Latest); + let fileName: string; if (value.endsWith('.d.ts')) { - const code = fs.readFileSync(value); - const sourceFile = createSourceFile('', code.toString(), ScriptTarget.Latest); - const fileName = path.basename(value).split('.d.ts')[0]; - let outputFileName = ''; - if (fileName.includes('@')) { - outputFileName = fileName.split('@')[1].replace(/\./g, '_'); - } else { - outputFileName = fileName; - } + fileName = path.basename(value, '.d.ts'); + } else if (value.endsWith('.d.ets')) { + fileName = path.basename(value, '.d.ets'); + } else { + continue; + } + let outputFileName = ''; + if (fileName.includes('@')) { + outputFileName = fileName.split('@')[1].replace(/\./g, '_'); + } else { + outputFileName = fileName; + } - let tmpOutputMockJsFileDir = outMockJsFileDir; - if (!outputFileName.startsWith('system_')) { - tmpOutputMockJsFileDir = path.join(outMockJsFileDir, 'napi'); - } - let dirName = ''; - if (os.platform() === 'linux' || os.platform() === 'darwin') { - dirName = path.join(tmpOutputMockJsFileDir, path.dirname(value).split('/api')[1]); - } else { - dirName = path.join(tmpOutputMockJsFileDir, path.dirname(value).split('\\api')[1]); - } - if (!fs.existsSync(dirName)) { - mkdirsSync(dirName); - } - const sourceFileEntity = getSourceFileAssembly(sourceFile, fileName); - const filePath = path.join(dirName, outputFileName + '.js'); - fs.writeFileSync(filePath, ''); - fs.appendFileSync(path.join(filePath), generateSourceFileElements('', sourceFileEntity, sourceFile, outputFileName)); + let tmpOutputMockJsFileDir = outMockJsFileDir; + if (!outputFileName.startsWith('system_')) { + tmpOutputMockJsFileDir = path.join(outMockJsFileDir, 'napi'); } - }); + + if (value.startsWith(getOhosInterfacesDir()) && !dtsDir.startsWith(getOhosInterfacesDir())) { + tmpOutputMockJsFileDir = path.join(tmpOutputMockJsFileDir, '@ohos'); + } + + let dirName = ''; + dirName = path.join(tmpOutputMockJsFileDir, path.dirname(value).split(`${path.sep}api`)[1]); + if (!fs.existsSync(dirName)) { + mkdirsSync(dirName); + } + const sourceFileEntity = getSourceFileAssembly(sourceFile, fileName); + const filePath = path.join(dirName, outputFileName + '.js'); + fs.writeFileSync(filePath, ''); + fs.appendFileSync(path.join(filePath), generateSourceFileElements('', sourceFileEntity, sourceFile, outputFileName)); + } + if (!fs.existsSync(path.join(outMockJsFileDir, 'napi'))) { mkdirsSync(path.join(outMockJsFileDir, 'napi')); } -- Gitee From 610e0eea95d9424728fa78a1293854b45f134910 Mon Sep 17 00:00:00 2001 From: yy8545 <854551495@qq.com> Date: Mon, 20 Nov 2023 20:50:45 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=B8=BB=E5=B9=B2=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=90=88=E5=85=A53.2-release=E5=88=86=E6=94=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yy8545 <854551495@qq.com> --- .../sourceFileElementsAssemply.ts | 18 ++- .../src/generate/generateCommonFunction.ts | 71 ++++++--- .../src/generate/generateCommonMethod.ts | 47 +++--- .../generate/generateCommonMethodSignature.ts | 48 ++++-- .../src/generate/generateCommonUtil.ts | 132 ++++++++++++++-- .../src/generate/generateExportFunction.ts | 12 +- mock-generate/src/generate/generateIndex.ts | 1 + .../src/generate/generateMockJsFile.ts | 24 ++- .../src/generate/generateModuleDeclaration.ts | 142 ++++++++++++++++-- .../generatePropertySignatureDeclaration.ts | 8 +- .../src/generate/generateSystemIndex.ts | 2 +- .../src/generate/generateTypeAlias.ts | 2 +- 12 files changed, 403 insertions(+), 104 deletions(-) diff --git a/mock-generate/src/declaration-node/sourceFileElementsAssemply.ts b/mock-generate/src/declaration-node/sourceFileElementsAssemply.ts index 30568e5b..c2e733d0 100644 --- a/mock-generate/src/declaration-node/sourceFileElementsAssemply.ts +++ b/mock-generate/src/declaration-node/sourceFileElementsAssemply.ts @@ -53,7 +53,7 @@ export function getSourceFileAssembly(sourceFile: SourceFile, fileName: string): let exportAssignment: Array = []; const staticMethods: Array> = []; const exportDeclarations: Array = []; - const functionDeclarations: Array = []; + const functionDeclarations: Map> = new Map>(); sourceFile.forEachChild(node => { if (isImportDeclaration(node)) { @@ -86,10 +86,16 @@ export function getSourceFileAssembly(sourceFile: SourceFile, fileName: string): enumDeclarations.push(getEnumDeclaration(node, sourceFile)); } else if (isExportDeclaration(node)) { exportDeclarations.push(sourceFile.text.substring(node.pos, node.end).trimStart().trimEnd()); - } else if (isFunctionDeclaration(node)){ - functionDeclarations.push(getFunctionDeclaration(node, sourceFile)); - } - else { + } else if (isFunctionDeclaration(node)) { + const functionEntity = getFunctionDeclaration(node, sourceFile); + if (functionDeclarations.get(functionEntity.functionName) !== undefined) { + functionDeclarations.get(functionEntity.functionName)?.push(functionEntity); + } else { + const functionArray: Array = []; + functionArray.push(functionEntity); + functionDeclarations.set(functionEntity.functionName, functionArray); + } + } else { if (node.kind !== SyntaxKind.EndOfFileToken && !isFunctionDeclaration(node) && !isVariableStatement(node)) { console.log('--------------------------- uncaught sourceFile type start -----------------------'); console.log('fileName: ' + fileName); @@ -175,5 +181,5 @@ export interface SourceFileEntity { exportAssignment: Array, staticMethods: Array>, exportDeclarations: Array, - functionDeclarations: Array + functionDeclarations: Map> } diff --git a/mock-generate/src/generate/generateCommonFunction.ts b/mock-generate/src/generate/generateCommonFunction.ts index 3f7f485b..b55f23f0 100644 --- a/mock-generate/src/generate/generateCommonFunction.ts +++ b/mock-generate/src/generate/generateCommonFunction.ts @@ -16,26 +16,39 @@ import type { SourceFile } from 'typescript'; import { SyntaxKind } from 'typescript'; import type { FunctionEntity } from '../declaration-node/functionDeclaration'; -import { getCallbackStatement, getReturnStatement, getWarnConsole, getReturnData } from './generateCommonUtil'; +import { + getCallbackStatement, + getReturnStatement, + getWarnConsole, + getReturnData, + getOverloadedFunctionCallbackStatement, + overloadedFunctionArr +} from './generateCommonUtil'; /** * generate function * @param rootName * @param functionArray * @param sourceFile + * @param mockApi + * @param isRoot * @returns */ -export function generateCommonFunction(rootName: string, functionArray: Array, sourceFile: SourceFile, mockApi: string): string { +export function generateCommonFunction( + rootName: string, + functionArray: Array, + sourceFile: SourceFile, + mockApi: string, + isRoot: boolean +): string { let functionBody = ''; const functionEntity = functionArray[0]; - functionBody = `${functionEntity.functionName}: function(...args) {`; - functionBody += getWarnConsole(rootName, functionEntity.functionName); - - // The callback function cannot be executed immediately, otherwise an error will be reported - if (sourceFile.fileName.includes('@ohos.events.emitter.d.ts')) { - functionBody += '},'; - return functionBody; + if (isRoot) { + functionBody = `const ${functionEntity.functionName} = function(...args) {`; + } else { + functionBody = `${functionEntity.functionName}: function(...args) {`; } + functionBody += getWarnConsole(rootName, functionEntity.functionName); if (functionArray.length === 1) { const args = functionEntity.args; @@ -57,6 +70,7 @@ export function generateCommonFunction(rootName: string, functionArray: Array = new Set(); let isCallBack = false; + let needOverloaded = false; functionArray.forEach(value => { returnSet.add(value.returnType.returnKindName); value.args.forEach(arg => { @@ -67,10 +81,20 @@ export function generateCommonFunction(rootName: string, functionArray: Array { - resolve('[PC Preview] unknow boolean'); - }) - }`; - } else { - functionBody += ` - return new Promise((resolve, reject) => { - resolve('[PC Preview] unknow boolean'); - }) - `; - } + functionBody += ` + return new Promise((resolve, reject) => { + resolve('[PC Preview] unknow boolean'); + }) + `; } } else if (otherReturnValue) { let returnType = null; @@ -119,6 +135,13 @@ export function generateCommonFunction(rootName: string, functionArray: Array, sourceFile: SourceFile, mockApi: string): string { +export function generateCommonMethod( + rootName: string, + methodArray: Array, + sourceFile: SourceFile, + mockApi: string +): string { let methodBody = ''; const methodEntity = methodArray[0]; if (methodEntity.functionName.name === 'Symbol.iterator') { @@ -60,6 +70,7 @@ export function generateCommonMethod(rootName: string, methodArray: Array = new Set(); let isCallBack = false; + let needOverloaded = false; methodArray.forEach(value => { returnSet.add(value.returnType.returnKindName); value.args.forEach(arg => { @@ -70,10 +81,20 @@ export function generateCommonMethod(rootName: string, methodArray: Array { - resolve('[PC Preview] unknow boolean'); - }) - }`; - } else { - methodBody += ` - return new Promise((resolve, reject) => { - resolve('[PC Preview] unknow boolean'); - }) - `; - } + methodBody += ` + return new Promise((resolve, reject) => { + resolve('[PC Preview] unknow boolean'); + }) + `; } } else if (otherReturnValue) { let returnType = null; diff --git a/mock-generate/src/generate/generateCommonMethodSignature.ts b/mock-generate/src/generate/generateCommonMethodSignature.ts index 115116c0..829a97ea 100644 --- a/mock-generate/src/generate/generateCommonMethodSignature.ts +++ b/mock-generate/src/generate/generateCommonMethodSignature.ts @@ -16,7 +16,14 @@ import type { SourceFile } from 'typescript'; import { SyntaxKind } from 'typescript'; import type { MethodSignatureEntity } from '../declaration-node/methodSignatureDeclaration'; -import { getCallbackStatement, getReturnStatement, getWarnConsole, getReturnData } from './generateCommonUtil'; +import { + getCallbackStatement, + getReturnStatement, + getWarnConsole, + getReturnData, + getOverloadedFunctionCallbackStatement, + overloadedFunctionArr +} from './generateCommonUtil'; /** * generate interface signature method @@ -25,7 +32,13 @@ import { getCallbackStatement, getReturnStatement, getWarnConsole, getReturnData * @param sourceFile * @returns */ -export function generateCommonMethodSignature(rootName: string, methodSignatureArray: Array, sourceFile: SourceFile, mockApi: string): string { +export function generateCommonMethodSignature( + rootName: string, + methodSignatureArray: + Array, + sourceFile: SourceFile, + mockApi: string +): string { let methodSignatureBody = ''; const methodEntity = methodSignatureArray[0]; methodSignatureBody += `${methodEntity.functionName}: function(...args) {`; @@ -48,6 +61,7 @@ export function generateCommonMethodSignature(rootName: string, methodSignatureA let argParamsSet: string = ''; const returnSet: Set = new Set(); let isCallBack = false; + let needOverloaded = false; methodSignatureArray.forEach(value => { returnSet.add(value.returnType.returnKindName); value.args.forEach(arg => { @@ -58,10 +72,20 @@ export function generateCommonMethodSignature(rootName: string, methodSignatureA argParamsSet = arg.paramTypeString; } } + if ( + arg.paramTypeString.startsWith("'") && arg.paramTypeString.endsWith("'") || + arg.paramTypeString.startsWith('"') && arg.paramTypeString.endsWith('"') + ) { + needOverloaded = true; + } }); }); if (isCallBack) { - methodSignatureBody += getCallbackStatement(mockApi, argParamsSet); + if (overloadedFunctionArr.includes(methodEntity.functionName) && needOverloaded) { + methodSignatureBody += getOverloadedFunctionCallbackStatement(methodSignatureArray, sourceFile, mockApi); + } else { + methodSignatureBody += getCallbackStatement(mockApi, argParamsSet); + } } let isReturnPromise = false; let promiseReturnValue = ''; @@ -86,19 +110,11 @@ export function generateCommonMethodSignature(rootName: string, methodSignatureA }); methodSignatureBody += getReturnData(isCallBack, isReturnPromise, returnType, sourceFile, mockApi); } else { - if (isCallBack) { - methodSignatureBody += `else { - return new Promise((resolve, reject) => { - resolve('[PC Preview] unknow boolean'); - }) - }`; - } else { - methodSignatureBody += ` - return new Promise((resolve, reject) => { - resolve('[PC Preview] unknow boolean'); - }) - `; - } + methodSignatureBody += ` + return new Promise((resolve, reject) => { + resolve('[PC Preview] unknow boolean'); + }) + `; } } else if (otherReturnValue) { let returnType = null; diff --git a/mock-generate/src/generate/generateCommonUtil.ts b/mock-generate/src/generate/generateCommonUtil.ts index 66308381..37aabee6 100644 --- a/mock-generate/src/generate/generateCommonUtil.ts +++ b/mock-generate/src/generate/generateCommonUtil.ts @@ -20,6 +20,8 @@ import type { ReturnTypeEntity } from '../common/commonUtils'; import { getImportDeclarationArray } from '../declaration-node/importAndExportDeclaration'; import type { ImportElementEntity } from '../declaration-node/importAndExportDeclaration'; import type { MethodEntity } from '../declaration-node/methodDeclaration'; +import type { FunctionEntity } from '../declaration-node/functionDeclaration'; +import type { MethodSignatureEntity } from '../declaration-node/methodSignatureDeclaration'; /** * get warn console template @@ -31,6 +33,22 @@ export function getWarnConsole(interfaceNameOrClassName: string, functionNameOrP return `console.warn('The ${interfaceNameOrClassName}.${functionNameOrPropertyName} interface in the Previewer is a mocked implementation and may behave differently than on a real device.');\n`; } +function handlePromiseParams(returnType: ReturnTypeEntity): string { + const returnKindName = returnType.returnKindName.slice(0, returnType.returnKindName.length - 1).slice(8).trim(); + let returnName = `return new Promise((resolve, reject) => { + resolve('[PC Preview] unknown type'); + })`; + Object.keys(paramsTypeStart).forEach(key => { + if (returnKindName.startsWith(key)) { + const data = paramsTypeStart[key] === '[PC Preview] unknown type' ? `'${paramsTypeStart[key]}'` : `${paramsTypeStart[key]}`; + returnName = `return new Promise((resolve, reject) => { + resolve(${data}); + })`; + } + }); + return returnName; +} + /** * generate return statement; * @param returnType @@ -40,13 +58,19 @@ export function getWarnConsole(interfaceNameOrClassName: string, functionNameOrP export function getReturnStatement(returnType: ReturnTypeEntity, sourceFile: SourceFile): string { if (returnType.returnKind === SyntaxKind.TypeReference) { if (returnType.returnKindName.startsWith('Promise')) { - return `return new Promise((resolve, reject) => { - resolve('[PC Preview] unknown type'); - })`; + return handlePromiseParams(returnType); } else if (returnType.returnKindName === 'T') { return 'return \'[PC Preview] unknown type\''; - } else if (returnType.returnKindName === 'String') { + } else if (returnType.returnKindName === 'object' || returnType.returnKindName === 'Object') { + return 'return {}'; + } else if (returnType.returnKindName === 'Function') { + return 'return \'[PC Preview] unknown type\''; + } else if (returnType.returnKindName === 'String' || returnType.returnKindName === 'string') { return `return ${returnType.returnKindName}(...args)`; + } else if (returnType.returnKindName === 'number' || returnType.returnKindName === 'Number') { + return 'return 0'; + } else if (returnType.returnKindName === 'boolean' || returnType.returnKindName === 'Boolean') { + return 'return false'; } else if (returnType.returnKindName === 'ArrayBuffer') { return `return new ${returnType.returnKindName}(0)`; } else if (returnType.returnKindName.startsWith('Array')) { @@ -147,7 +171,23 @@ export function getReturnStatement(returnType: ReturnTypeEntity, sourceFile: Sou return `return ${getBaseReturnValue(returnName.trimStart().trimEnd())}`; } } else { - return 'return \'[PC Preview] unknown type\''; + let returnName = returnType.returnKindName.trim(); + let temp = true; + if (returnName.endsWith(']')) { + returnName = '[]'; + temp = false; + } else { + Object.keys(paramsTypeStart).forEach(key => { + if (returnType.returnKindName.startsWith(key)) { + returnName = paramsTypeStart[key]; + temp = false; + } + }); + } + if (temp) { + return 'return \'[PC Preview] unknown type\''; + } + return `return ${returnName};`; } return 'return \'[PC Preview] unknown type\''; } @@ -300,10 +340,14 @@ const paramsTypeStart = { 'void': '[PC Preview] unknown type', 'Array': '[]', 'Object': '{}', + 'object': '{}', '{': '{}', 'string': '""', + 'String': '""', 'number': 0, + 'Number': 0, 'boolean': false, + 'Boolean': false, 'ArrayBuffer': 'new ArrayBuffer(0)', 'Uint8Array': 'new Uint8Array()', 'unknown': '[PC Preview] unknown type' @@ -434,6 +478,70 @@ export function getCallbackStatement(mockApi: string, paramTypeString?: string): return outPut; } +/** + * get callback statement + * @returns callback statement + */ +export function getOverloadedFunctionCallbackStatement( + entityArray: Array | Array | Array, + sourceFile: SourceFile, + mockApi: string +): string { + let overloadedCallbackBody = ''; + entityArray.forEach(functionBody => { + let content = ''; + let firstParamContent = ''; + let callbackParamContent = ''; + functionBody.args.forEach(arg => { + if ( + arg.paramTypeString.startsWith("'") && arg.paramTypeString.endsWith("'") || + arg.paramTypeString.startsWith('"') && arg.paramTypeString.endsWith('"') + ) { + const paramTypeStringArr = arg.paramTypeString.split('|'); + firstParamContent += `if (args && [${paramTypeStringArr}].includes(args[0])) {\n`; + } + if (['callback', 'observercallback', 'listener', 'synccallback'].includes(arg.paramName.toLowerCase())) { + callbackParamContent += getCallbackBody(mockApi, arg.paramTypeString); + } + }); + if (firstParamContent) { + content = `${firstParamContent}${callbackParamContent}\n}` + content; + } else { + content += callbackParamContent; + } + overloadedCallbackBody += content; + }); + overloadedCallbackBody += '\n'; + return overloadedCallbackBody; +} + +/** + * get callback statement + * @returns callback statement + */ +function getCallbackBody(mockApi: string, paramString: string): string { + let bodyInfo = `if (args && typeof args[args.length - 1] === 'function') { + args[args.length - 1].call(this,`; + const callbackError = "{'code': '','data': '','name': '','message': '','stack': ''}"; + if (paramString === 'ErrorCallback') { + bodyInfo += callbackError + ');\n}'; + return bodyInfo; + } + let callbackDataParams = { + type: '', + data: '[PC Preview] unknown type' + }; + if (paramString) { + callbackDataParams = setCallbackData(mockApi, paramString); + } + if (callbackDataParams?.type === 'AsyncCallback') { + bodyInfo += ` ${callbackError},`; + } + bodyInfo += callbackDataParams.data === '[PC Preview] unknown type' ? ` '${callbackDataParams.data}');\n` : ` ${callbackDataParams.data});\n`; + bodyInfo += '}'; + return bodyInfo; +} + /** * get iterator template string * @param methodEntity @@ -614,19 +722,11 @@ export function getReturnData(isCallBack: boolean, isReturnPromise: boolean, ret } const data = typeof returnData === 'string' && returnData.startsWith('[PC Preview] unknown') ? `'${returnData}'` : `${returnData}`; if (isReturnPromise) { - if (isCallBack) { - return `else { - return new Promise((resolve, reject) => { - resolve(${data}); - }) - }`; - } else { - return ` + return ` return new Promise((resolve, reject) => { resolve(${data}); }) `; - } } else { return `return ${data}`; } @@ -674,3 +774,7 @@ function getSeparatorParam(returnPromiseParams: string): string { } return otherValue; } + +export const overloadedFunctionArr = ['on', 'off']; + +export const needToAddBrace = ['ViewData', 'AutoFillType']; diff --git a/mock-generate/src/generate/generateExportFunction.ts b/mock-generate/src/generate/generateExportFunction.ts index d45972fb..3925221a 100644 --- a/mock-generate/src/generate/generateExportFunction.ts +++ b/mock-generate/src/generate/generateExportFunction.ts @@ -27,11 +27,11 @@ import { getCallbackStatement, getReturnStatement } from './generateCommonUtil'; * @returns */ export function generateExportFunction(functionEntity: FunctionEntity, sourceFile: SourceFile, mockApi: string): string { - if (functionEntity.functionName !== 'getContext') { + let functionBody = ''; + functionBody = `const ${functionEntity.functionName} = function (...args) {`; + if (mockApi.includes(functionBody)) { return ''; } - let functionBody = ''; - functionBody = `global.${functionEntity.functionName} = function (...args) {`; functionBody += `console.warn('The ${functionEntity.functionName} interface in the Previewer is a mocked implementation and may behave differently than on a real device.');\n`; const args = functionEntity.args; @@ -43,5 +43,11 @@ export function generateExportFunction(functionEntity: FunctionEntity, sourceFil functionBody += getReturnStatement(functionEntity.returnType, sourceFile); } functionBody += '}'; + functionBody += ` + if (!global.${functionEntity.functionName}) { + global.${functionEntity.functionName} = ${functionEntity.functionName} + } + `; return functionBody; } + diff --git a/mock-generate/src/generate/generateIndex.ts b/mock-generate/src/generate/generateIndex.ts index 1df5b3a8..0d88820e 100644 --- a/mock-generate/src/generate/generateIndex.ts +++ b/mock-generate/src/generate/generateIndex.ts @@ -35,6 +35,7 @@ export function getIndexArray(): Array { export function generateIndex(): string { let indexBody = 'import * as common from \'./@internal/component/ets/common\';\n'; let caseBody = ''; + indexBody += 'import * as etsglobal from \'./@internal/ets/global\';\n'; const filterSet: Set = new Set(); indexArray.forEach(value => { diff --git a/mock-generate/src/generate/generateMockJsFile.ts b/mock-generate/src/generate/generateMockJsFile.ts index 7df4e79e..ecc04f43 100644 --- a/mock-generate/src/generate/generateMockJsFile.ts +++ b/mock-generate/src/generate/generateMockJsFile.ts @@ -29,7 +29,8 @@ import { generateModuleDeclaration } from './generateModuleDeclaration'; import { generateStaticFunction } from './generateStaticFunction'; import { addToSystemIndexArray } from './generateSystemIndex'; import { generateTypeAliasDeclaration } from './generateTypeAlias'; -import { generateExportFunction } from './generateExportFunction'; +import { generateCommonFunction } from './generateCommonFunction'; +import { needToAddBrace } from './generateCommonUtil'; /** * generate mock file string @@ -40,7 +41,7 @@ import { generateExportFunction } from './generateExportFunction'; * @returns */ export function generateSourceFileElements(rootName: string, sourceFileEntity: SourceFileEntity, sourceFile: SourceFile, fileName: string): string { - + let mockApi = ''; const mockFunctionElements: Array = []; const dependsSourceFileList = collectReferenceFiles(sourceFile); @@ -55,7 +56,7 @@ export function generateSourceFileElements(rootName: string, sourceFileEntity: S if (sourceFileEntity.moduleDeclarations.length > 0) { sourceFileEntity.moduleDeclarations.forEach(value => { - mockApi += generateModuleDeclaration('', value, sourceFile, fileName, mockApi, extraImport) + '\n'; + mockApi += generateModuleDeclaration('', value, sourceFile, fileName, mockApi, extraImport, sourceFileEntity.importDeclarations) + '\n'; }); } @@ -85,14 +86,14 @@ export function generateSourceFileElements(rootName: string, sourceFileEntity: S if (sourceFileEntity.typeAliasDeclarations.length > 0) { sourceFileEntity.typeAliasDeclarations.forEach(value => { - mockApi += generateTypeAliasDeclaration(value, false, sourceFile, extraImport) + '\n'; + mockApi += generateTypeAliasDeclaration(value, false, sourceFile, extraImport, mockApi) + '\n'; mockFunctionElements.push({ elementName: value.typeAliasName, type: 'typeAlias' }); }); } - if (sourceFileEntity.functionDeclarations.length > 0) { - sourceFileEntity.functionDeclarations.forEach(value => { - mockApi += generateExportFunction(value, sourceFile, mockApi) + '\n'; + if (sourceFileEntity.functionDeclarations.size > 0) { + Array.from(sourceFileEntity.functionDeclarations.keys()).forEach(key => { + mockApi += generateCommonFunction(key, sourceFileEntity.functionDeclarations.get(key), sourceFile, mockApi, true) + '\n'; }); } @@ -207,6 +208,9 @@ export function generateImportDeclaration( sourceFileName === 'Context' && tmpImportPath === './ApplicationContext') { return ''; } + if (!importElements.includes('{') && !importElements.includes('}') && needToAddBrace.includes(importElements)) { + importElements = `{ ${importElements} }`; + } collectAllLegalImports(importElements); return `import ${importElements} from ${importPath}\n`; } @@ -327,7 +331,11 @@ function generateImportElements(importEntity: ImportElementEntity, heritageClaus let importElements = importEntity.importElements; if (!importElements.includes('{') && !importElements.includes('* as') && !heritageClausesArray.includes(importElements) && importEntity.importPath.includes('@ohos')) { const tmpArr = importEntity.importPath.split('.'); - importElements = `{ mock${firstCharacterToUppercase(tmpArr[tmpArr.length - 1].replace('"', '').replace('\'', ''))} }`; + const mockModuleName = firstCharacterToUppercase(tmpArr[tmpArr.length - 1].replace('"', '').replace('\'', '')); + if (importElements === 'observer' && importEntity.importPath.includes('@ohos.arkui.observer')) { + return `{ mockUIObserver as ${importElements}}`; + } + importElements = `{ mock${mockModuleName} }`; } else { // adapt no rules .d.ts if (importElements.trimRight().trimEnd() === 'AccessibilityExtensionContext, { AccessibilityElement }') { diff --git a/mock-generate/src/generate/generateModuleDeclaration.ts b/mock-generate/src/generate/generateModuleDeclaration.ts index 4967044b..6f75a349 100644 --- a/mock-generate/src/generate/generateModuleDeclaration.ts +++ b/mock-generate/src/generate/generateModuleDeclaration.ts @@ -32,6 +32,7 @@ import { generateStaticFunction } from './generateStaticFunction'; import { addToSystemIndexArray } from './generateSystemIndex'; import { generateTypeAliasDeclaration } from './generateTypeAlias'; import { generateVariableStatementDelcatation } from './generateVariableStatementDeclaration'; +import type { ImportElementEntity } from '../declaration-node/importAndExportDeclaration'; /** * generate declare @@ -43,9 +44,11 @@ import { generateVariableStatementDelcatation } from './generateVariableStatemen * @returns */ export function generateModuleDeclaration(rootName: string, moduleEntity: ModuleBlockEntity, sourceFile: SourceFile, - filename: string, mockApi: string, extraImport: string[]): string { - let moduleName = moduleEntity.moduleName.replace(/["']/g, ''); + filename: string, mockApi: string, extraImport: string[], importDeclarations: ImportElementEntity[]): string { + let innerModuleBody = ''; + const moduleName = moduleEntity.moduleName.replace(/["']/g, ''); let moduleBody = `export function mock${firstCharacterToUppercase(moduleName)}() {\n`; + let enumBody = ''; if (!(moduleEntity.exportModifiers.includes(SyntaxKind.DeclareKeyword) && (moduleEntity.moduleName.startsWith('"') || moduleEntity.moduleName.startsWith('\''))) && path.basename(sourceFile.fileName).startsWith('@ohos') @@ -84,7 +87,7 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module if (moduleEntity.typeAliasDeclarations.length > 0) { moduleEntity.typeAliasDeclarations.forEach(value => { - outBody += generateTypeAliasDeclaration(value, true, sourceFile, extraImport) + '\n'; + outBody += generateTypeAliasDeclaration(value, true, sourceFile, extraImport, mockApi) + '\n'; }); } @@ -107,9 +110,9 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module if (moduleEntity.interfaceDeclarations.length > 0) { moduleEntity.interfaceDeclarations.forEach(value => { if (value.exportModifiers.length > 0) { - outBody += generateInterfaceDeclaration(moduleName, value, sourceFile, false, mockApi, moduleEntity.interfaceDeclarations) + ';\n'; + outBody += generateInterfaceDeclaration(moduleName, value, sourceFile, false, mockApi, moduleEntity.interfaceDeclarations, importDeclarations, extraImport) + ';\n'; } else { - moduleBody += '\t' + generateInterfaceDeclaration(moduleName, value, sourceFile, false, mockApi, moduleEntity.interfaceDeclarations) + ';\n'; + moduleBody += '\t' + generateInterfaceDeclaration(moduleName, value, sourceFile, false, mockApi, moduleEntity.interfaceDeclarations, importDeclarations, extraImport) + ';\n'; } }); } @@ -119,7 +122,7 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module if (value.exportModifiers.length > 0) { outBody += generateEnumDeclaration(moduleName, value) + '\n'; } else { - moduleBody += '\t' + generateEnumDeclaration(moduleName, value) + '\n'; + enumBody += generateEnumDeclaration(moduleName, value); } }); } @@ -127,10 +130,21 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module let functionBody = ''; if (moduleEntity.functionDeclarations.size > 0) { moduleEntity.functionDeclarations.forEach(value => { - functionBody += '\t' + generateCommonFunction(moduleName, value, sourceFile, mockApi) + '\n'; + functionBody += '\t' + generateCommonFunction(moduleName, value, sourceFile, mockApi, false) + '\n'; }); } + if (moduleEntity.moduleDeclarations.length > 0) { + moduleEntity.moduleDeclarations.forEach(value => { + if (!value.moduleName.startsWith("'") && !value.moduleName.startsWith('"')) { + innerModuleBody += generateInnerModuleDeclaration(value, sourceFile, filename, mockApi, extraImport, importDeclarations); + } + }); + } + if (innerModuleBody) { + moduleBody += innerModuleBody + '\n'; + } + moduleBody += '\t' + `const ${moduleName} = {`; if (moduleEntity.variableStatements.length > 0) { moduleEntity.variableStatements.forEach(value => { @@ -144,7 +158,7 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module let sourceFileFunctionBody = ''; if (sourceFileFunctions.size > 0) { sourceFileFunctions.forEach(value => { - sourceFileFunctionBody += generateCommonFunction(moduleName, value, sourceFile, mockApi); + sourceFileFunctionBody += '\n' + generateCommonFunction(moduleName, value, sourceFile, mockApi, false); }); } @@ -153,7 +167,7 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module if (sourceFileVariableStatements.length > 0) { sourceFileVariableStatements.forEach(value => { value.forEach(val => { - sourceFileStatementBody += generateVariableStatementDelcatation(val, false); + sourceFileStatementBody += '\n' + generateVariableStatementDelcatation(val, false); }); }); } @@ -165,7 +179,11 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module const exports = getModuleExportElements(moduleEntity); let exportString = ''; exports.forEach(value => { - exportString += `${value.name}: ${value.name},\n`; + if (value.type === 'module' && !value.name.startsWith("'") && !value.name.startsWith('"')) { + exportString += `${value.name}: mock${value.name}(),\n`; + } else { + exportString += `${value.name}: ${value.name},\n`; + } }); if (exportString !== '') { moduleBody += '\t' + exportString; @@ -174,6 +192,104 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module moduleBody += '\t};'; moduleBody += `\n\treturn ${moduleName};}\n`; moduleBody += outBody; + moduleBody = enumBody + moduleBody; + return moduleBody; +} + +function generateInnerModuleDeclaration(moduleEntity: ModuleBlockEntity, sourceFile: SourceFile, + filename: string, mockApi: string, extraImport: string[], importDeclarations: ImportElementEntity[]): string { + let innerModuleBody = ''; + const innerModuleName = moduleEntity.moduleName.replace(/["']/g, ''); + let moduleBody = `function mock${innerModuleName}() {\n`; + let innerOutBody = ''; + let innerFunctionBody = ''; + + if (moduleEntity.typeAliasDeclarations.length) { + moduleEntity.typeAliasDeclarations.forEach(value => { + innerOutBody += generateTypeAliasDeclaration(value, true, sourceFile, extraImport, mockApi) + '\n'; + }); + } + + if (moduleEntity.moduleImportEquaqls.length) { + moduleEntity.moduleImportEquaqls.forEach(value => { + innerOutBody += generateImportEqual(value) + '\n'; + }); + } + + if (moduleEntity.classDeclarations.length) { + moduleEntity.classDeclarations.forEach(value => { + if (value.exportModifiers.length && value.exportModifiers.includes(SyntaxKind.ExportKeyword)) { + innerOutBody += generateClassDeclaration(innerModuleName, value, false, '', '', sourceFile, false, mockApi) + '\n'; + } else { + moduleBody += '\t' + generateClassDeclaration(innerModuleName, value, false, '', '', sourceFile, true, mockApi) + '\n'; + } + }); + } + + if (moduleEntity.interfaceDeclarations.length) { + moduleEntity.interfaceDeclarations.forEach(value => { + if (value.exportModifiers.length) { + innerOutBody += generateInterfaceDeclaration(innerModuleName, value, sourceFile, false, mockApi, moduleEntity.interfaceDeclarations, importDeclarations, extraImport) + ';\n'; + } else { + moduleBody += '\t' + generateInterfaceDeclaration(innerModuleName, value, sourceFile, false, mockApi, moduleEntity.interfaceDeclarations, importDeclarations, extraImport) + ';\n'; + } + }); + } + + if (moduleEntity.enumDeclarations.length) { + moduleEntity.enumDeclarations.forEach(value => { + if (value.exportModifiers.length) { + innerOutBody += generateEnumDeclaration(innerModuleName, value) + '\n'; + } else { + moduleBody += generateEnumDeclaration(innerModuleName, value); + } + }); + } + + if (moduleEntity.functionDeclarations.size) { + moduleEntity.functionDeclarations.forEach(value => { + innerFunctionBody += '\n' + generateCommonFunction(innerModuleName, value, sourceFile, mockApi, false) + '\n'; + }); + } + + if (moduleEntity.moduleDeclarations.length) { + moduleEntity.moduleDeclarations.forEach(value => { + if (!value.moduleName.startsWith("'") && !value.moduleName.startsWith('"')) { + innerModuleBody += generateInnerModuleDeclaration(value, sourceFile, filename, mockApi, extraImport, importDeclarations); + } + }); + } + if (innerModuleBody) { + moduleBody += innerModuleBody + '\n'; + } + + moduleBody += `const ${innerModuleName} = {\n`; + if (moduleEntity.variableStatements.length) { + moduleEntity.variableStatements.forEach(value => { + value.forEach(val => { + moduleBody += generateVariableStatementDelcatation(val, false) + '\n'; + }); + }); + } + + moduleBody += innerFunctionBody + '\n'; + + const exportArr = getModuleExportElements(moduleEntity); + let innerExportString = ''; + exportArr.forEach(value => { + if (value.type === 'module' && !value.name.startsWith("'") && !value.name.startsWith('"')) { + innerExportString += `${value.name}: mock${value.name}(),\n`; + } else { + innerExportString += `${value.name}: ${value.name},\n`; + } + }); + if (innerExportString !== '') { + moduleBody += '\t' + innerExportString; + } + + moduleBody += '\t};'; + moduleBody += `\n\treturn ${innerModuleName};}\n`; + moduleBody += innerOutBody; return moduleBody; } @@ -200,7 +316,7 @@ function generateInnerDeclareModule(moduleEntity: ModuleBlockEntity): string { * @param extraImport * @returns */ -function generateInnerModule(moduleEntity: ModuleBlockEntity, sourceFile: SourceFile, extraImport: string[]): string { +function generateInnerModule(moduleEntity: ModuleBlockEntity, sourceFile: SourceFile, extraImport: string[], mockApi: string): string { const moduleName = moduleEntity.moduleName; let innerModuleBody = `const ${moduleName} = (()=> {`; @@ -212,7 +328,7 @@ function generateInnerModule(moduleEntity: ModuleBlockEntity, sourceFile: Source if (moduleEntity.typeAliasDeclarations.length > 0) { moduleEntity.typeAliasDeclarations.forEach(value => { - innerModuleBody += generateTypeAliasDeclaration(value, true, sourceFile, extraImport) + '\n'; + innerModuleBody += generateTypeAliasDeclaration(value, true, sourceFile, extraImport, mockApi) + '\n'; }); } @@ -231,7 +347,7 @@ function generateInnerModule(moduleEntity: ModuleBlockEntity, sourceFile: Source let functionBody = 'return {'; if (moduleEntity.functionDeclarations.size > 0) { moduleEntity.functionDeclarations.forEach(value => { - functionBody += generateCommonFunction(moduleName, value, sourceFile, '') + '\n'; + functionBody += generateCommonFunction(moduleName, value, sourceFile, '', false) + '\n'; }); } diff --git a/mock-generate/src/generate/generatePropertySignatureDeclaration.ts b/mock-generate/src/generate/generatePropertySignatureDeclaration.ts index 335e6181..6dddcd65 100644 --- a/mock-generate/src/generate/generatePropertySignatureDeclaration.ts +++ b/mock-generate/src/generate/generatePropertySignatureDeclaration.ts @@ -36,7 +36,13 @@ export function generatePropertySignatureDeclaration(rootName: string, propertyS propertySignatureBody += getCallbackStatement(mockApi); propertySignatureBody += '},\n'; } else { - if (propertySignature.propertyTypeName.startsWith('{')) { + if ( + (propertySignature.propertyTypeName.startsWith('{') || + propertySignature.propertyTypeName.startsWith('Record<') || + propertySignature.propertyTypeName.startsWith('Object') || + propertySignature.propertyTypeName.startsWith('object')) && + !propertySignature.propertyTypeName.endsWith(']') + ) { propertySignatureBody = `${propertySignature.propertyName}: {},`; } else if (propertySignature.kind === SyntaxKind.TypeReference) { if (propertySignature.propertyTypeName.startsWith('Array')) { diff --git a/mock-generate/src/generate/generateSystemIndex.ts b/mock-generate/src/generate/generateSystemIndex.ts index 386f00f4..1c7c488f 100644 --- a/mock-generate/src/generate/generateSystemIndex.ts +++ b/mock-generate/src/generate/generateSystemIndex.ts @@ -17,7 +17,7 @@ const systemIndexArray: Array = []; const systemNoMockArray = ['system.app', 'system.configuration', 'system.device', 'system.mediaquery', 'system.prompt', 'system.router']; -export function addToSystemIndexArray(systemIndexEntity: SystemIndexEntity) { +export function addToSystemIndexArray(systemIndexEntity: SystemIndexEntity): void { systemIndexArray.push(systemIndexEntity); } diff --git a/mock-generate/src/generate/generateTypeAlias.ts b/mock-generate/src/generate/generateTypeAlias.ts index 5836ebe8..156be4bd 100644 --- a/mock-generate/src/generate/generateTypeAlias.ts +++ b/mock-generate/src/generate/generateTypeAlias.ts @@ -30,7 +30,7 @@ const interceptIndex = 2; * @returns */ export function generateTypeAliasDeclaration( - typeAliasEntity: TypeAliasEntity, isInner: boolean, sourceFile: SourceFile, extraImport: string[] + typeAliasEntity: TypeAliasEntity, isInner: boolean, sourceFile: SourceFile, extraImport: string[], mockApi: string ): string { let typeAliasName = ''; if (!isInner) { -- Gitee