diff --git a/.gitignore b/.gitignore index 1d71de0..f988373 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,9 @@ ui_* /cmake-build-debug/ .idea .vscode/ +automock/.babelrc +automock/.eslintrc +automock/dist/ +automock/package.json +automock/runtime/ +automock/tsconfig.json diff --git a/automock/mock-generate/src/common/commonUtils.ts b/automock/mock-generate/src/common/commonUtils.ts index 7470d15..9d50d91 100644 --- a/automock/mock-generate/src/common/commonUtils.ts +++ b/automock/mock-generate/src/common/commonUtils.ts @@ -22,6 +22,8 @@ import { import fs from 'fs'; import { ImportElementEntity } from '../declaration-node/importAndExportDeclaration'; + +const paramIndex = 2; const allLegalImports = new Set(); const fileNameList = new Set(); const allClassSet = new Set(); @@ -226,23 +228,23 @@ export interface ReturnTypeEntity { } /** - * - * return project dir + * Get OpenHarmony project dir + * @return project dir */ export function getProjectDir(): string { - const apiInputPath = process.argv[2]; + const apiInputPath = process.argv[paramIndex]; 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 apiInputPath.replace(`${path.sep}${privateInterface}`, ''); } } /** - * return ohos interface dir + * return interface api dir in OpenHarmony */ export function getOhosInterfacesDir(): string { return path.join(getProjectDir(), 'interface', 'sdk-js', 'api'); @@ -252,8 +254,8 @@ export function getOhosInterfacesDir(): string { * return interface api root path * @returns apiInputPath */ -export function getApiInputPath () { - return process.argv[2]; +export function getApiInputPath(): string { + return process.argv[paramIndex]; } /** @@ -268,7 +270,8 @@ export function findOhosDependFile(importPath: string, sourceFile: SourceFile): const sourceFileDir = path.dirname(sourceFile.fileName); let dependsFilePath: string; if (tmpImportPath.startsWith('./')) { - dependsFilePath = path.join(sourceFileDir, tmpImportPath.substring(2)); + const subIndex = 2; + dependsFilePath = path.join(sourceFileDir, tmpImportPath.substring(subIndex)); } else if (tmpImportPath.startsWith('../')) { const backSymbolList = tmpImportPath.split('/').filter(step => step === '..'); dependsFilePath = [ @@ -279,11 +282,11 @@ export function findOhosDependFile(importPath: string, sourceFile: SourceFile): 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')){ + if (fs.existsSync(tmpInterFaceDir + '.d.ts')) { return tmpInterFaceDir + '.d.ts'; } - if (fs.existsSync(tmpInterFaceDir + '.d.ets')){ + if (fs.existsSync(tmpInterFaceDir + '.d.ets')) { return tmpInterFaceDir + '.d.ets'; } } @@ -291,13 +294,16 @@ export function findOhosDependFile(importPath: string, sourceFile: SourceFile): dependsFilePath = path.join(getOhosInterfacesDir(), tmpImportPath); } - if (fs.existsSync(dependsFilePath + '.d.ts')){ + if (fs.existsSync(dependsFilePath + '.d.ts')) { return dependsFilePath + '.d.ts'; } - if (fs.existsSync(dependsFilePath + '.d.ets')){ + if (fs.existsSync(dependsFilePath + '.d.ets')) { return dependsFilePath + '.d.ets'; } + + console.warn(`Cannot find module '${importPath}'`); + return; } /** @@ -314,11 +320,17 @@ export function isOhosInterface(path: string): boolean { * @returns */ export function getJsSdkDir(): string { - let sdkJsDir = process.argv[2].split(path.sep).slice(0, -1).join(path.sep); - sdkJsDir += sdkJsDir.endsWith(path.sep) ? '' : path.sep + 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; @@ -329,6 +341,11 @@ export function hasBeenImported(importDeclarations: ImportElementEntity[], typeN 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; diff --git a/automock/mock-generate/src/generate/generateClassDeclaration.ts b/automock/mock-generate/src/generate/generateClassDeclaration.ts index 801f679..9093e72 100644 --- a/automock/mock-generate/src/generate/generateClassDeclaration.ts +++ b/automock/mock-generate/src/generate/generateClassDeclaration.ts @@ -78,12 +78,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();\n`; + classBody += 'super();\n'; } classBody += getWarnConsole(className, 'constructor'); } diff --git a/automock/mock-generate/src/generate/generateMockJsFile.ts b/automock/mock-generate/src/generate/generateMockJsFile.ts index 5cebd8a..2c92b6f 100644 --- a/automock/mock-generate/src/generate/generateMockJsFile.ts +++ b/automock/mock-generate/src/generate/generateMockJsFile.ts @@ -15,10 +15,12 @@ import fs from 'fs'; import path from 'path'; -import { ScriptTarget, SourceFile, SyntaxKind, createSourceFile } from 'typescript'; +import { ScriptTarget, SyntaxKind, createSourceFile } from 'typescript'; +import type { SourceFile } from 'typescript'; import { collectAllLegalImports, dtsFileList, firstCharacterToUppercase, getAllFileNameList, getApiInputPath } from '../common/commonUtils'; import { ImportElementEntity } from '../declaration-node/importAndExportDeclaration'; -import { getDefaultExportClassDeclaration, SourceFileEntity } from '../declaration-node/sourceFileElementsAssemply'; +import { getDefaultExportClassDeclaration } from '../declaration-node/sourceFileElementsAssemply'; +import type { SourceFileEntity } from '../declaration-node/sourceFileElementsAssemply'; import { generateClassDeclaration } from './generateClassDeclaration'; import { generateEnumDeclaration } from './generateEnumDeclaration'; import { addToIndexArray } from './generateIndex'; @@ -161,76 +163,39 @@ export function generateImportDeclaration( sourceFileName: string, heritageClausesArray: string[], currentFilePath: string, - dependsSourceFileList?: SourceFile[] - ): string { - if (dependsSourceFileList.length) { - if (!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`; - } - } - } - } - - let importPathName = ''; - const importPathSplit = importEntity.importPath.split('/'); - let fileName = importPathSplit[importPathSplit.length - 1]; - if (fileName.endsWith('.d.ts') || fileName.endsWith('.d.ets')) { - fileName = fileName.split('.d.')[0]; - } - if (fileName.includes('@')) { - importPathName = fileName.replace('@', '').replace(/\./g, '_'); - } else { - importPathName = fileName.replace(/\./g, '_'); - } - let importPath = ''; - for (let i = 0; i < importPathSplit.length - 1; i++) { - importPath += importPathSplit[i] + '/'; - } - 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('\'', ''))} }`; - } + dependsSourceFileList: SourceFile[]): string { + const importDeclaration = referenctImport2ModuleImport(importEntity, currentFilePath, dependsSourceFileList); + if (importDeclaration){ + return importDeclaration; } - const testPath = importPath.replace(/"/g, '').replace(/'/g, '').split('/'); - if (getAllFileNameList().has(testPath[testPath.length - 1]) || testPath[testPath.length - 1] === 'ohos_application_want') { - let tmpImportPath = importPath.replace(/'/g, '').replace(/"/g, ''); - if (!tmpImportPath.startsWith('./') && !tmpImportPath.startsWith('../')) { - importPath = `'./${tmpImportPath}'`; - } - tmpImportPath = importPath.replace(/'/g, '').replace(/"/g, ''); - if (sourceFileName === 'tagSession' && tmpImportPath === './basic' || sourceFileName === 'notificationContent' && - tmpImportPath === './ohos_multimedia_image') { - importPath = `'.${importPath.replace(/'/g, '')}'`; - } + const importPathSplit = importEntity.importPath.split('/'); - // adapt no rules .d.ts - if (importElements.trimRight().trimEnd() === 'AccessibilityExtensionContext, { AccessibilityElement }') { - importElements = '{ AccessibilityExtensionContext, AccessibilityElement }'; - } - if (importElements.trimRight().trimEnd() === '{ image }') { - importElements = '{ mockImage as image }'; - } - tmpImportPath = importPath.replace(/'/g, '').replace(/"/g, ''); - if (sourceFileName === 'AbilityContext' && tmpImportPath === '../ohos_application_Ability' || - sourceFileName === 'Context' && tmpImportPath === './ApplicationContext') { - return ''; - } - collectAllLegalImports(importElements); - return `import ${importElements} from ${importPath}\n`; - } else { + let importPath = importPathSplit.slice(0, -1).join('/') + '/'; + importPath += getImportPathName(importPathSplit); + + const importElements = generateImportElements(importEntity, heritageClausesArray); + + const testPath = importPath.replace(/"/g, '').replace(/'/g, '').split('/'); + if (!getAllFileNameList().has(testPath[testPath.length - 1]) && testPath[testPath.length - 1] !== 'ohos_application_want') { return ''; } + + let tmpImportPath = importPath.replace(/'/g, '').replace(/"/g, ''); + if (!tmpImportPath.startsWith('./') && !tmpImportPath.startsWith('../')) { + importPath = `'./${tmpImportPath}'`; + } + if (sourceFileName === 'tagSession' && tmpImportPath === './basic' || sourceFileName === 'notificationContent' && + tmpImportPath === './ohos_multimedia_image') { + importPath = `'.${importPath.replace(/'/g, '')}'`; + } + + if (sourceFileName === 'AbilityContext' && tmpImportPath === '../ohos_application_Ability' || + sourceFileName === 'Context' && tmpImportPath === './ApplicationContext') { + return ''; + } + collectAllLegalImports(importElements); + return `import ${importElements} from ${importPath}\n`; } /** @@ -309,11 +274,58 @@ function contentRelatePath2RealRelatePath(currentFilePath: string, contentRefere realReferenceFilePath = currentFilePath.replace(baseFileNameTemplate, referenceFileName).replace(/\//g, path.sep); } else { console.error(`Can not find reference ${contentReferenceRelatePath} from ${currentFilePath}`); - return; + return undefined; } - return realReferenceFilePath + return realReferenceFilePath; } +export function referenctImport2ModuleImport(importEntity: ImportElementEntity, currentFilePath: string, dependsSourceFileList: SourceFile[]): string | undefined { + 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/automock/mock-generate/src/generate/generatePropertySignatureDeclaration.ts b/automock/mock-generate/src/generate/generatePropertySignatureDeclaration.ts index 7e2d4ac..4934b30 100644 --- a/automock/mock-generate/src/generate/generatePropertySignatureDeclaration.ts +++ b/automock/mock-generate/src/generate/generatePropertySignatureDeclaration.ts @@ -71,7 +71,7 @@ export function generatePropertySignatureDeclaration(rootName: string, propertyS } else if (propertySignature.kind === SyntaxKind.UnionType) { let unionFirstElement = propertySignature.propertyTypeName.split('|')[0].trimStart().trimEnd(); if (unionFirstElement.includes('[]')) { - unionFirstElement = '[]' + unionFirstElement = '[]'; } if (unionFirstElement.startsWith('"') || unionFirstElement.startsWith("'")) { propertySignatureBody = `${propertySignature.propertyName}: ${unionFirstElement},`; diff --git a/automock/mock-generate/src/main.ts b/automock/mock-generate/src/main.ts index 81122a6..c9d21f9 100644 --- a/automock/mock-generate/src/main.ts +++ b/automock/mock-generate/src/main.ts @@ -104,7 +104,7 @@ function main(apiInputPath) { }); let index = 0; - while (index < dtsFileList.length){ + while (index < dtsFileList.length) { const value = dtsFileList[index]; index ++; @@ -157,5 +157,6 @@ function main(apiInputPath) { fs.writeFileSync(path.join(outMockJsFileDir, 'entry.js'), generateEntry()); } -const apiInputPath = process.argv[2]; +const paramIndex = 2; +const apiInputPath = process.argv[paramIndex]; main(apiInputPath); \ No newline at end of file