fix problem context undefined

Signed-off-by: sambaby <1337922982@qq.com>
This commit is contained in:
sambaby
2023-09-13 14:42:46 +08:00
parent e09a7b15f0
commit 425180b22d
6 changed files with 185 additions and 14 deletions
@@ -53,6 +53,7 @@ export function getSourceFileAssembly(sourceFile: SourceFile, fileName: string):
let exportAssignment: Array<string> = [];
const staticMethods: Array<Array<StaticMethodEntity>> = [];
const exportDeclarations: Array<string> = [];
const functionDeclarations: Array<FunctionEntity> = [];
sourceFile.forEachChild(node => {
if (isImportDeclaration(node)) {
@@ -85,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);
@@ -104,7 +108,8 @@ export function getSourceFileAssembly(sourceFile: SourceFile, fileName: string):
enumDeclarations: enumDeclarations,
exportAssignment: exportAssignment,
staticMethods: staticMethods,
exportDeclarations: exportDeclarations
exportDeclarations: exportDeclarations,
functionDeclarations: functionDeclarations,
};
}
@@ -169,5 +174,6 @@ export interface SourceFileEntity {
enumDeclarations: Array<EnumEntity>,
exportAssignment: Array<string>,
staticMethods: Array<Array<StaticMethodEntity>>,
exportDeclarations: Array<string>
exportDeclarations: Array<string>,
functionDeclarations: Array<FunctionEntity>
}
@@ -261,7 +261,7 @@ function getImportTypeAliasNameFromImportElements(importElementEntity: ImportEle
if (typeName === 'Want') {
typeName = 'mockWant().Want';
} else if (typeName === 'InputMethodExtensionContext') {
typeName = 'mockInputmethodextensioncontext().InputMethodExtensionContext';
typeName = 'mockInputMethodExtensionContext().InputMethodExtensionContext';
}
return typeName;
}
@@ -0,0 +1,44 @@
/*
* 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 {
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;
}
@@ -29,6 +29,7 @@ import { generateModuleDeclaration } from './generateModuleDeclaration';
import { generateStaticFunction } from './generateStaticFunction';
import { addToSystemIndexArray } from './generateSystemIndex';
import { generateTypeAliasDeclaration } from './generateTypeAlias';
import { generateExportFunction } from './generateExportFunction';
/**
* generate mock file string
@@ -54,7 +55,7 @@ export function generateSourceFileElements(rootName: string, sourceFileEntity: S
if (sourceFileEntity.moduleDeclarations.length > 0) {
sourceFileEntity.moduleDeclarations.forEach(value => {
mockApi += generateModuleDeclaration('', value, sourceFile, fileName, mockApi) + '\n';
mockApi += generateModuleDeclaration('', value, sourceFile, fileName, mockApi, extraImport) + '\n';
});
}
@@ -84,11 +85,17 @@ 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];
@@ -157,6 +164,9 @@ export function generateSourceFileElements(rootName: string, sourceFileEntity: S
* generate import definition
* @param importEntity
* @param sourceFileName
* @param heritageClausesArray
* @param currentFilePath
* @param dependsSourceFileList
* @returns
*/
export function generateImportDeclaration(
@@ -39,9 +39,11 @@ import { generateVariableStatementDelcatation } from './generateVariableStatemen
* @param moduleEntity
* @param sourceFile
* @param filename
* @param extraImport
* @returns
*/
export function generateModuleDeclaration(rootName: string, moduleEntity: ModuleBlockEntity, sourceFile: SourceFile, filename: string, mockApi: string): string {
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) &&
@@ -82,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';
});
}
@@ -178,7 +180,6 @@ export function generateModuleDeclaration(rootName: string, moduleEntity: Module
/**
* generate inner module for declare module
* @param moduleEntity
* @param sourceFile
* @returns
*/
function generateInnerDeclareModule(moduleEntity: ModuleBlockEntity): string {
@@ -196,9 +197,10 @@ function generateInnerDeclareModule(moduleEntity: ModuleBlockEntity): string {
* 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} = (()=> {`;
@@ -210,7 +212,7 @@ function generateInnerModule(moduleEntity: ModuleBlockEntity, sourceFile: Source
if (moduleEntity.typeAliasDeclarations.length > 0) {
moduleEntity.typeAliasDeclarations.forEach(value => {
innerModuleBody += generateTypeAliasDeclaration(value, true) + '\n';
innerModuleBody += generateTypeAliasDeclaration(value, true, sourceFile, extraImport) + '\n';
});
}
@@ -13,22 +13,131 @@
* limitations under the License.
*/
import type { 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';
/**
* 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] unknown ${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(2, importRelatePathTmp[0].length - 2);
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 '';
}