blob: fdd17b14f578543342414628a1dbb9cfa9c9ce21 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 debug from 'debug';
import {ensureDir} from 'fs-extra';
import {join, parse} from 'path';
import {default as Ast, SourceFile} from 'ts-simple-ast';
import {Request} from './request';
import {toImport} from './transfer/to-import';
import {toTypescript} from './transfer/to-typescript';
import {IDependItem, IGetTypeInfo, IJClass, ITypeSearch} from './typings';
const log = debug('j2t:core:inteprethandle');
const ast = new Ast();
/**
* Translations for individual files
*/
export class IntepretHandle implements ITypeSearch {
constructor(classPath: string, interpreterRequest: Request) {
this.classPath = classPath;
this.request = interpreterRequest;
log(
'Start translating :%s, outputDir:%s',
classPath,
interpreterRequest.outputDir,
);
}
public classPath: string;
public request: Request;
public sourceFile: SourceFile;
private dependencies: IDependItem[] = [];
get to(): string {
return join(
this.request.outputDir,
this.classPath.split('.').join('/') + '.ts',
);
}
get astJava(): IJClass {
return this.request.getAst(this.classPath);
}
get providerSuffix(): string {
return this.request.providerSuffix;
}
public async work() {
await this.prepare();
await this.doItRecursively();
}
/**
*
* @returns {Promise<void>}
*/
private async prepare() {
ast.addSourceFileFromText(this.to, '//generate by dubbo-js');
this.sourceFile = ast.getSourceFile(this.to);
await ensureDir(parse(this.to).dir);
}
public hasAst = classPath => {
return this.request.hasAst(classPath);
};
public getTypeInfo: IGetTypeInfo = classPath => {
return this.request.getTypeInfo(classPath);
};
public isTypeParam = typeName => {
for (let typeParamItem of this.astJava.typeParams) {
if (typeParamItem.name === typeName) {
return true;
}
}
return false;
};
/**
* Adding dependencies
*
* @param classPath
* @param className
* @returns {Promise<void>}
*/
public async addDenpend(classPath: string): Promise<IDependItem> {
if (!(await this.request.hasAst(classPath))) {
log(`No class ast found:${classPath}`);
return;
}
if (classPath === this.classPath) {
log(`ignore self reference:${this.classPath}`);
let className = this.getTypeInfo(classPath).className;
return {
classPath,
name: className,
importName: className,
};
}
log(`Adding dependencies ${this.classPath}`);
let dependItem = this.getDependItem(classPath);
if (!dependItem) {
if (!this.request.isRecorded(classPath)) {
this.request.record(classPath);
try {
await new IntepretHandle(classPath, this.request).work();
} catch (err) {
console.error('Error in translating file::', classPath, err.stack);
throw err;
}
}
dependItem = this.createDependItem(classPath);
this.dependencies.push(dependItem);
try {
this.sourceFile.addImport(
toImport({
className:
dependItem.name != dependItem.importName
? `${dependItem.name} as ${dependItem.importName}`
: dependItem.name,
classPath,
packagePath: this.getTypeInfo(this.classPath).packagePath,
}),
);
} catch (err) {
console.error(
`Error in adding dependencies :add ${classPath} in ${this.classPath}`,
);
console.error(err);
}
return dependItem;
} else {
return dependItem;
}
}
private getDependItem(classPath: string): IDependItem | null {
for (let dependItem of this.dependencies) {
if (dependItem.classPath === classPath) {
return dependItem;
}
}
return null;
}
private createDependItem(classPath: string): IDependItem {
let name = this.getTypeInfo(classPath).className;
let importName = name;
let index = 0;
while (this.isDependNameExist(importName)) {
importName += index;
}
return {
classPath,
name,
importName: importName,
};
}
private isDependNameExist(importName) {
let isExist = false;
for (let dependItem of this.dependencies) {
if (dependItem.importName === importName) {
isExist = true;
}
}
return isExist;
}
/**
*
* @returns {Promise<void>}
*/
private async doItRecursively() {
await toTypescript(this);
await ast.saveUnsavedSourceFiles();
}
}