lib/common_generator.js (1,077 lines of code) (raw):
/* eslint-disable max-len */
'use strict';
const Emitter = require('@darabonba/emitter');
const assert = require('assert');
const DSL = require('@darabonba/parser');
const Annotation = require('@darabonba/annotation-parser');
const REQUEST = '_request';
const RESPONSE = '_response';
const { _name, _string, _type, _lowerFirst, _subModelName, _upperFirst, avoidReserveName, collectionType, SSE, md2Html } = require('./util');
class Generator extends Emitter {
constructor(ast, ctx) {
super(' ');
this.ast = ast;
this.ctx = ctx;
this.ctx.predefined = this.ast.predefined;
}
emitNumber(ast, level) {
this.emit(ast.value.value, level);
if (ast.value.type === 'long') {
this.emit('L');
}
if (ast.value.type === 'double') {
this.emit('D');
}
if (ast.value.type === 'float') {
this.emit('F');
}
}
visitArray(ast, level) {
assert.equal(ast.type, 'array');
if (ast.items.length === 0) {
this.emit('new java.util.ArrayList<>()');
return;
}
this.emit('java.util.Arrays.asList(\n');
for (let i = 0; i < ast.items.length; i++) {
const item = ast.items[i];
var comments = DSL.comment.getFrontComments(this.ctx.comments, item.tokenRange[0]);
this.visitComments(comments, level + 1);
this.emit('', level + 1);
this.visitExpr(item, level + 1);
if (i < ast.items.length - 1) {
this.emit(',');
}
this.emit('\n');
}
this.emit(')', level);
}
visitIf(ast, isAsync, level) {
assert.equal(ast.type, 'if');
this.emit('if (', level);
this.visitExpr(ast.condition, level + 1);
this.emit(') {\n');
this.visitStmts(ast.stmts, isAsync, level + 1);
this.emit('}', level);
if (ast.elseIfs) {
for (let i = 0; i < ast.elseIfs.length; i++) {
const branch = ast.elseIfs[i];
this.emit(' else if (');
this.visitExpr(branch.condition, level + 1);
this.emit(') {\n');
this.visitStmts(branch.stmts, isAsync, level + 1);
this.emit('}', level);
}
}
if (ast.elseStmts) {
this.emit(' else {\n');
for (let i = 0; i < ast.elseStmts.stmts.length; i++) {
this.visitStmt(ast.elseStmts.stmts[i], isAsync, level + 1);
}
this.emit('}', level);
}
this.emit('\n');
this.emit('\n');
}
visitAssign(ast, level) {
var isCollection = false;
var isBuilder = false;
if (ast.left.type === 'id') {
this.emit(`${_name(ast.left.id)}`, level);
} else if (ast.left.type === 'property_assign' || ast.left.type === 'property') {
var id = _name(ast.left.id);
if (id === '__request') {
id = 'request_';
}
this.emit(`${id}`, level);
for (var i = 0; i < ast.left.propertyPath.length; i++) {
if ((i === ast.left.propertyPath.length - 1 && ast.left.propertyPathTypes[i - 1] && ast.left.propertyPathTypes[i - 1].type === 'map') ||
(ast.left.id.inferred && ast.left.id.inferred.type === 'map')) {
this.emit(`.put("${_name(ast.left.propertyPath[i])}", `);
isCollection = true;
} else {
this.emit(` = ${id}.toBuilder().${_name(ast.left.propertyPath[i])}(`);
isBuilder = true;
}
}
} else if (ast.left.type === 'virtualVariable') {
this.emit(`this.${_name(ast.left.vid).substr(1)}`, level);
} else if (ast.left.type === 'variable') {
this.emit(`${_name(ast.left.id)}`, level);
} else if (ast.left.type === 'map_access') {
isCollection = true;
this.visitMapAccess(ast.left, false, level);
} else if (ast.left.type === 'array_access') {
isCollection = true;
this.visitArrayAccess(ast.left, false, level);
} else {
throw new Error('unimpelemented');
}
if (!isCollection && !isBuilder) {
this.emit(' = ');
}
this.visitExpr(ast.expr, level);
if (isCollection) {
this.emit(')');
}
if (isBuilder) {
this.emit(').build()');
}
if (ast.expr.type === 'call' && ast.expr.isAsync) {
this.emit(`.join()`);
}
this.emit(';\n');
}
visitExpr(ast, level) {
if (ast.type === 'boolean') {
this.emit(`${ast.value}`);
} else if (ast.type === 'property_access') {
this.visitPropertyAccess(ast, level);
} else if (ast.type === 'string') {
this.emit(`"${_string(ast.value)}"`);
} else if (ast.type === 'null') {
this.emit('null');
} else if (ast.type === 'number') {
this.emitNumber(ast);
} else if (ast.type === 'object') {
this.visitObject(ast, level);
} else if (ast.type === 'variable') {
var id = _name(ast.id);
if (id === '__response') {
this.emit(RESPONSE);
} else if (id === '__request') {
this.emit(REQUEST);
} else if (ast.inferred && ast.inferred.name === 'class') {
this.emit(avoidReserveName(id) + '.class');
} else {
this.emit(avoidReserveName(id));
}
} else if (ast.type === 'virtualVariable') {
const vid = `${_lowerFirst(_name(ast.vid).substr(1))}`;
this.emit(`${vid}`);
} else if (ast.type === 'template_string') {
for (let i = 0; i < ast.elements.length; i++) {
var item = ast.elements[i];
if (item.type === 'element') {
this.emit('"');
this.emit(_string(item.value));
this.emit('"');
} else if (item.type === 'expr') {
if (item.expr.type === 'property_access' && _name(item.expr.id) === '__module') {
var value = this.__module;
for (let i = 0; i < item.expr.propertyPath.length; i++) {
value = value[_name(item.expr.propertyPath[i])];
}
this.emit('"');
this.emit(value);
this.emit('"');
} else {
this.visitExpr(item.expr, level);
}
} else {
throw new Error('unimpelemented');
}
if (i < ast.elements.length - 1) {
this.emit(' + ');
}
}
} else if (ast.type === 'call') {
this.visitCall(ast, level);
} else if (ast.type === 'construct') {
this.visitConstruct(ast, level);
} else if (ast.type === 'array') {
this.visitArray(ast, level);
} else if (ast.type === 'and') {
this.visitExpr(ast.left, level);
this.emit(' && ');
this.visitExpr(ast.right, level);
} else if (ast.type === 'or') {
this.visitExpr(ast.left, level);
this.emit(' || ');
this.visitExpr(ast.right, level);
} else if (ast.type === 'null') {
this.emit('null');
} else if (ast.type === 'not') {
this.emit('!');
this.visitExpr(ast.expr, level);
} else if (ast.type === 'construct_model') {
this.visitConstructModel(ast, level);
} else if (ast.type === 'super') {
this.emit('super(');
if (ast.args) {
for (let i = 0; i < ast.args.length; i++) {
if (i > 0) {
this.emit(', ');
}
this.visitExpr(ast.args[i], level);
}
}
this.emit(')');
} else if (ast.type === 'map_access') {
this.visitMapAccess(ast, true);
} else if (ast.type === 'array_access') {
this.visitArrayAccess(ast, true);
} else {
throw new Error('unimpelemented');
}
}
visitCall(ast, level) {
assert.equal(ast.type, 'call');
if (ast.left.type === 'method_call') {
this.visitMethodCall(ast, level);
} else if (ast.left.type === 'instance_call') {
this.visitInstanceCall(ast, level);
} else if (ast.left.type === 'static_call') {
this.visitStaticCall(ast, level);
} else {
throw new Error('unimplemented');
}
}
visitStaticCall(ast, level) {
assert.equal(ast.left.type, 'static_call');
var className = this.ctx.imports[ast.left.id.lexeme].className || 'DefaultAsyncClient';
this.emit(`${this.ctx.imports[ast.left.id.lexeme].package}.${className}.${_name(ast.left.propertyPath[0])}(`);
for (let i = 0; i < ast.args.length; i++) {
const expr = ast.args[i];
if (expr.needCast) {
this.emit('TeaModel.buildMap(');
}
this.visitExpr(expr, level);
if (expr.needCast) {
this.emit(')');
}
if (i !== ast.args.length - 1) {
this.emit(', ');
}
}
this.emit(')');
}
visitInstanceCall(ast, level) {
assert.equal(ast.left.type, 'instance_call');
const method = ast.left.propertyPath[0];
var id = _name(ast.left.id);
if (id.indexOf('@') > -1) {
id = `this.${id.substr(1)}`;
}
this.emit(`${id}.${_name(method)}(`);
for (let i = 0; i < ast.args.length; i++) {
const expr = ast.args[i];
this.visitExpr(expr, level);
if (i !== ast.args.length - 1) {
this.emit(', ');
}
}
this.emit(')');
}
visitMethodCall(ast, level) {
assert.equal(ast.left.type, 'method_call');
if (ast.isStatic) {
var className = this.ctx.className || 'DefaultAsyncClient';
this.emit(`${className}.${_name(ast.left.id)}(`);
} else {
this.emit(`this.${_name(ast.left.id)}(`);
}
for (let i = 0; i < ast.args.length; i++) {
const expr = ast.args[i];
if (expr.needCast) {
this.emit('TeaModel.buildMap(');
}
this.visitExpr(expr, level);
if (expr.needCast) {
this.emit(')');
}
if (i !== ast.args.length - 1) {
this.emit(', ');
}
}
this.emit(')');
}
visitDeclare(ast, level) {
var id = _name(ast.id);
this.emit(``, level);
if (ast.expr.type === 'call' && ast.expr.isAsync) {
this.emit(`CompletableFuture<`);
}
this.visitType(ast.expr.inferred);
if (ast.expr.type === 'call' && ast.expr.isAsync) {
this.emit(`> ${id}Future = `);
} else {
this.emit(` ${id} = `);
}
this.visitExpr(ast.expr, level);
this.emit(';\n');
if (ast.expr.type === 'call' && ast.expr.isAsync) {
this.emit(``, level);
this.visitType(ast.expr.inferred);
this.emit(` ${id} = ${id}Future.join();\n`);
}
}
visitComments(comments, level) {
comments.forEach(comment => {
this.emit(`${comment.value}`, level);
this.emit(`\n`);
});
}
visitStmts(ast, isAsync, level) {
assert.equal(ast.type, 'stmts');
let node;
for (var i = 0; i < ast.stmts.length; i++) {
node = ast.stmts[i];
this.visitStmt(node, isAsync, level);
}
if (node) {
//find the last node's back comment
let comments = DSL.comment.getBackComments(this.ctx.comments, node.tokenRange[1]);
this.visitComments(comments, level);
}
if (ast.stmts.length === 0) {
//empty block's comment
let comments = DSL.comment.getBetweenComments(this.ctx.comments, ast.tokenRange[0], ast.tokenRange[1]);
this.visitComments(comments, level);
}
}
visitConstruct(ast, level) {
assert.equal(ast.type, 'construct');
this.emit('new ');
let className = this.ctx.imports[ast.inferred.name].className;
let pathName = this.ctx.imports[ast.inferred.name].package;
if (this.ctx.conflictModels.get(className) && this.ctx.conflictModels.get(className) !== pathName) {
this.emit(`${pathName}.${className}`);
} else {
if (!this.ctx.conflictModels.get(className)) {
this.ctx.conflictModels.set(className, pathName);
}
this.emit(className);
}
this.visitArgs(ast.args, level);
}
visitConstructModel(ast, level) {
assert.equal(ast.type, 'construct_model');
this.visitType(ast.inferred);
this.emit(`.builder()`);
if (ast.object && ast.object.fields && ast.object.fields.length > 0) {
this.visitBuilderMethod(ast.object, level);
}
this.emit(`\n`);
this.emit(`.build()`, level + 2);
}
visitArgs(args, level) {
this.emit('(');
for (let i = 0; i < args.length; i++) {
const expr = args[i];
this.visitExpr(expr, level);
if (i !== args.length - 1) {
this.emit(', ');
}
}
this.emit(')');
}
visitArrayAccess(ast, isExpr, level) {
assert.equal(ast.type, 'array_access');
let expr = _name(ast.id);
if (expr.indexOf('@') > -1) {
expr = `this.${expr.substr(1)}`;
}
if (ast.propertyPath && ast.propertyPath.length) {
var current = ast.id.inferred;
for (var i = 0; i < ast.propertyPath.length; i++) {
var name = _name(ast.propertyPath[i]);
if (current.type === 'model') {
expr += `.get${_upperFirst(name)}()`;
} else {
expr += `.get("${name}")`;
}
current = ast.propertyPathTypes[i];
}
}
if (isExpr) {
this.emit(`${expr}.get(`);
this.visitExpr(ast.accessKey);
this.emit(`)`);
} else {
this.emit(`${expr}.set(`, level);
this.visitExpr(ast.accessKey);
this.emit(', ');
}
}
visitMapAccess(ast, isExpr, level) {
assert.equal(ast.type, 'map_access');
let expr = _name(ast.id);
if (expr.indexOf('@') > -1) {
expr = `this.${expr.substr(1)}`;
}
if (ast.propertyPath && ast.propertyPath.length) {
var current = ast.id.inferred;
for (var i = 0; i < ast.propertyPath.length; i++) {
var name = _name(ast.propertyPath[i]);
if (current.type === 'model') {
expr += `.get${_upperFirst(name)}()`;
} else {
expr += `.get("${name}")`;
}
current = ast.propertyPathTypes[i];
}
}
if (isExpr) {
this.emit(`${expr}.get(`);
this.visitExpr(ast.accessKey);
this.emit(`)`);
} else {
this.emit(`${expr}.put(`, level);
this.visitExpr(ast.accessKey);
this.emit(`, `);
}
}
visitPropertyAccess(ast) {
assert.equal(ast.type, 'property_access');
var id = _name(ast.id);
var expr = '';
if (id === '__response') {
expr += RESPONSE;
} else if (id === '__request') {
expr += REQUEST;
} else {
expr += avoidReserveName(id);
}
var current = ast.id.inferred;
for (var i = 0; i < ast.propertyPath.length; i++) {
var name = _name(ast.propertyPath[i]);
if (current.type === 'model') {
expr += `.get${_upperFirst(name)}()`;
} else {
expr += `.get("${name}")`;
}
current = ast.propertyPathTypes[i];
}
this.emit(expr);
}
visitBuilderMethod(ast, level) {
let classFieldName = '';
for (let i = 0; i < ast.fields.length; i++) {
classFieldName = _name(ast.fields[i].fieldName);
this.emit('\n');
let comments = DSL.comment.getFrontComments(this.ctx.comments, ast.fields[i].tokenRange[0]);
this.visitComments(comments, level + 2);
this.emit('', level + 2);
this.emit(`.${classFieldName}(`);
this.visitObjectFieldValue(ast.fields[i].expr, level + 2);
this.emit(')');
}
}
visitStmt(ast, isAsync, level) {
let comments = DSL.comment.getFrontComments(this.ctx.comments, ast.tokenRange[0]);
this.visitComments(comments, level);
if (ast.type === 'return') {
this.visitReturn(ast, isAsync, level);
} else if (ast.type === 'if') {
this.visitIf(ast, isAsync, level);
} else if (ast.type === 'throw') {
this.visitThrow(ast, level);
} else if (ast.type === 'assign') {
this.visitAssign(ast, level);
} else if (ast.type === 'retry') {
this.visitRetry(ast, level);
} else if (ast.type === 'break') {
this.emit(`break;\n`, level);
} else if (ast.type === 'declare') {
this.visitDeclare(ast, level);
} else if (ast.type === 'while') {
this.visitWhile(ast, isAsync, level);
} else if (ast.type === 'for') {
this.visitFor(ast, isAsync, level);
} else if (ast.type === 'try') {
this.visitTry(ast, isAsync, level);
} else if (ast.type === 'yield') {
this.visitYield(ast, level);
} else {
this.emit(``, level);
this.visitExpr(ast, level);
this.emit(';\n');
}
}
visitReturn(ast, isAsync, level) {
assert.equal(ast.type, 'return');
let property = '';
if (ast.expr && ast.expr.left && ast.expr.left.propertyPath) {
property = ast.expr.left.propertyPath.pop();
}
if (ast.needCast &&
(_name(property) === '_do' || _name(property) === 'doAsyncRequestBody'
|| _name(property) === 'doRequestBody' || _name(property) === 'doResponseHandler')) {
const args = ast.expr.args;
this.emit(`TeaRequest teaRequest = REQUEST.copy()`, level);
this.emit('.setStyle(RequestStyle.');
this.emit(`${_string(args[0].value).toUpperCase()}`);
this.emit(').setAction("');
this.emit(`${_string(args[1].value)}`);
this.emit('").setMethod(HttpMethod.');
this.emit(`${_string(args[2].value).toUpperCase()}`);
this.emit(').setPathRegex("');
this.emit(`${_string(args[3].value)}`);
this.emit('").setBodyType(BodyType.');
this.emit(`${_string(args[4].value).toUpperCase()}`);
this.emit(').setBodyIsForm(');
this.emit(`${args[5].value}`);
if (typeof args[6].value.string !== 'undefined' && args[6].value.string !== '') {
this.emit(').setReqBodyType(BodyType.');
this.emit(`${_string(args[6].value).toUpperCase()}`);
}
this.emitln(`).formModel(${_name(args[7].id)});`);
if (args[8] && _name(args[8].id) === 'requestBody') {
this.emit(`ClientExecutionParams params = new ClientExecutionParams().withInput(${_name(args[7].id)}).withRequest(teaRequest).withRequestBody(${_name(args[8].id)}).withOutput(`, level);
} else if (args[8] && _name(args[8].id) === 'responseHandler') {
this.emit(`ClientExecutionParams params = new ClientExecutionParams().withInput(${_name(args[7].id)}).withRequest(teaRequest).withResponseHandler(${_name(args[8].id)}).withOutput(`, level);
} else {
this.emit(`ClientExecutionParams params = new ClientExecutionParams().withInput(${_name(args[7].id)}).withRequest(teaRequest).withOutput(`, level);
}
this.visitType(ast.expectedType);
this.emitln('.create());');
this.emit('return ', level);
var id = _name(ast.expr.left.id);
if (id.indexOf('@') > -1) {
id = `this.${id.substr(1)}`;
}
if (_name(property) === 'doResponseHandler') {
this.emitln(`${id}.execute(params)`);
this.emit(' .thenCompose((output) -> CompletableFuture.completedFuture(responseHandler.transform((', level);
this.visitType(ast.expectedType);
this.emit(')output)))');
} else {
this.emit(`${id}.execute(params)`);
}
if (!isAsync) {
this.emit(`.join()`);
}
this.emit(`;\n`);
return;
}
this.emit('return ', level);
if (!ast.expr) {
this.emit(';\n');
return;
}
this.visitExpr(ast.expr, level);
this.emit(';\n');
}
visitYield(ast, level) {
assert.equal(ast.type, 'yield');
let property = '';
if (ast.expr && ast.expr.left && ast.expr.left.propertyPath) {
property = ast.expr.left.propertyPath.pop();
}
if (_name(property) === 'doSSERequest') {
const args = ast.expr.args;
this.emit(`TeaRequest teaRequest = REQUEST.copy()`, level);
this.emit('.setStyle(RequestStyle.');
this.emit(`${_string(args[0].value).toUpperCase()}`);
this.emit(').setAction("');
this.emit(`${_string(args[1].value)}`);
this.emit('").setMethod(HttpMethod.');
this.emit(`${_string(args[2].value).toUpperCase()}`);
this.emit(').setPathRegex("');
this.emit(`${_string(args[3].value)}`);
this.emit('").setBodyType(BodyType.');
this.emit(`${_string(args[4].value).toUpperCase()}`);
this.emit(').setBodyIsForm(');
this.emit(`${args[5].value}`);
if (typeof args[6].value.string !== 'undefined' && args[6].value.string !== '') {
this.emit(').setReqBodyType(BodyType.');
this.emit(`${_string(args[6].value).toUpperCase()}`);
}
this.emitln(`).formModel(${_name(args[7].id)});`);
let modelName = _name(ast.expectedType);
this.emitln(`${modelName}Iterator iterator = ${modelName}Iterator.create();`, level);
this.ctx.iterators.push({
iteratorType: ast.expectedType,
iteratorStyle: SSE,
});
this.emitln(`ClientExecutionParams params = new ClientExecutionParams().withInput(${_name(args[7].id)}).withRequest(teaRequest).withHttpResponseHandler(new SSEHttpResponseHandler(iterator));`, level);
var id = _name(ast.expr.left.id);
if (id.indexOf('@') > -1) {
id = `this.${id.substr(1)}`;
}
this.emitln(`${id}.execute(params);`, level);
this.emitln('return new ResponseIterable<>(iterator);', level);
return;
}
this.emit('return ', level);
if (!ast.expr) {
this.emit(';\n');
return;
}
this.visitExpr(ast.expr, level);
this.emit(';\n');
}
visitWhile(ast, isAsync, level) {
assert.equal(ast.type, 'while');
this.emit('\n');
this.emit('while (', level);
this.visitExpr(ast.condition, level + 1);
this.emit(') {\n');
this.visitStmts(ast.stmts, isAsync, level + 1);
this.emit('}\n', level);
}
visitFor(ast, isAsync, level) {
assert.equal(ast.type, 'for');
this.emit(`for (`, level);
this.visitType(ast.list.inferred.itemType || ast.list.inferred.valueType);
this.emit(` ${_name(ast.id)} : `);
this.visitExpr(ast.list, level + 1);
this.emit(') {\n');
this.visitStmts(ast.stmts, isAsync, level + 1);
this.emit('}\n', level);
}
visitTry(ast, isAsync, level) {
this.emit('try {\n', level);
this.visitStmts(ast.tryBlock, isAsync, level + 1);
this.emit('}', level);
if (ast.catchBlock && ast.catchBlock.stmts.length > 0) {
let errorName = _name(ast.catchId);
this.emit(` catch (TeaException ${errorName}) {\n`);
this.visitStmts(ast.catchBlock, isAsync, level + 1);
this.emit(`} catch (Exception _${errorName}) {`, level);
this.emit('\n');
this.emit(`TeaException ${errorName} = new TeaException(_${errorName}.getMessage(), _${errorName});\n`, level + 1);
this.visitStmts(ast.catchBlock, isAsync, level + 1);
this.emit('}', level);
}
if (ast.finallyBlock && ast.finallyBlock.stmts.length > 0) {
this.emit(' finally {\n');
this.visitStmts(ast.finallyBlock, isAsync, level + 1);
this.emit('}', level);
}
this.emit('\n', level);
}
visitParams(ast) {
assert.equal(ast.type, 'params');
this.emit('(');
for (var i = 0; i < ast.params.length; i++) {
if (i !== 0) {
this.emit(', ');
}
const node = ast.params[i];
assert.equal(node.type, 'param');
this.visitType(node.paramType);
this.emit(` ${avoidReserveName(_name(node.paramName))}`);
}
this.emit(')');
}
visitPureParams(ast) {
assert.equal(ast.type, 'params');
for (var i = 0; i < ast.params.length; i++) {
if (i !== 0) {
this.emit(', ');
}
const node = ast.params[i];
assert.equal(node.type, 'param');
this.visitType(node.paramType);
this.emit(` ${avoidReserveName(_name(node.paramName))}`);
}
}
getSubFieldClassName(className, hasModel) {
if (className.indexOf('.') > 0) {
var names = className.split('.');
var name = '';
if (hasModel) {
name = names[0] + '.';
}
name += _subModelName(className, this.ctx.conflictModelNameMap, this.ctx.allModleNameMap);
return name;
}
return className;
}
getSubModelClassName(names, index, currentName) {
if (index < names.length) {
names[index] = currentName + _upperFirst(names[index]);
return this.getSubModelClassName(names, index + 1, names[index]);
}
return names.join('.');
}
visitAnnotation(annotation, level) {
if (!annotation || !annotation.value) {
if (this.ast.modelName) {
const modelName = _name(this.ast.modelName);
this.emitln(`/**`, level);
this.emitln(` * `, level);
this.emitln(` * {@link ${this.ast.title ? this.ast.title : modelName}} extends {@link ${this.ctx.isRequestModel ? 'RequestModel' : 'TeaModel'}}`, level);
this.emitln(` *`, level);
this.emitln(` * <p>${this.ast.title ? this.ast.title : modelName}</p>`, level);
this.emitln(` */`, level);
}
return;
}
let comments = DSL.comment.getFrontComments(this.ctx.comments, annotation.index);
this.visitComments(comments, level);
var node = Annotation.parse(annotation.value);
var description = node.items.find((item) => {
return item.type === 'description';
});
var summary = node.items.find((item) => {
return item.type === 'summary';
});
var _return = node.items.find((item) => {
return item.type === 'return';
});
var deprecated = node.items.find((item) => {
return item.type === 'deprecated';
});
var params = node.items.filter((item) => {
return item.type === 'param';
}).map((item) => {
return {
name: item.name.id,
text: item.text.text.trimEnd()
};
});
var throws = node.items.filter((item) => {
return item.type === 'throws';
}).map((item) => {
return item.text.text.trimEnd();
});
let hasNextSection = false;
this.emitln(`/**`, level);
const descriptionText = description ? description.text.text : '';
const summaryText = summary ? summary.text.text : '';
const returnText = _return ? _return.text.text.trimEnd() : '';
if (summaryText !== '') {
if (hasNextSection) {
this.emitln(` * `, level);
}
this.emitln(` * <b>summary</b> : `, level);
const summaryTexts = md2Html(summaryText).trimEnd();
summaryTexts.split('\n').forEach((line) => {
this.emitln(` * ${line}`, level);
});
hasNextSection = true;
}
if (descriptionText !== '') {
this.emitln(` * <b>description</b> :`, level);
const descriptionTexts = md2Html(descriptionText).trimEnd();
descriptionTexts.split('\n').forEach((line) => {
this.emitln(` * ${line}`, level);
});
hasNextSection = true;
}
if (deprecated) {
if (hasNextSection) {
this.emitln(` * `, level);
}
const deprecatedText = deprecated.text.text.trimEnd();
this.emit(` * @deprecated `, level);
deprecatedText.split('\n').forEach((line, index) => {
if (index === 0) {
this.emitln(`${line}`);
} else {
this.emitln(` * ${line}`, level);
}
});
hasNextSection = true;
}
if (params.length > 0) {
if (hasNextSection) {
this.emitln(` * `, level);
}
params.forEach((item) => {
this.emit(` * @param ${item.name} `, level);
const items = item.text.trimEnd().split('\n');
items.forEach((line, index) => {
if (index === 0) {
this.emitln(`${line}`);
} else {
this.emitln(` * ${line}`, level);
}
});
});
hasNextSection = true;
}
if (returnText !== '') {
this.emit(` * @return `, level);
const returns = returnText.split('\n');
returns.forEach((line, index) => {
if (index === 0) {
this.emitln(`${line}`);
} else {
this.emitln(` * ${line}`, level);
}
});
hasNextSection = true;
}
if (throws.length > 0) {
if (hasNextSection) {
this.emitln(` * `, level);
}
throws.forEach((item) => {
this.emit(` * @throws `, level);
const items = item.trimEnd().split('\n');
items.forEach((line, index) => {
if (index === 0) {
this.emitln(`${line}`);
} else {
this.emitln(` * ${line}`, level);
}
});
});
}
if (this.ast.modelName) {
const modelName = _name(this.ast.modelName);
this.emitln(` * `, level);
this.emitln(` * {@link ${this.ast.title ? this.ast.title : modelName}} extends {@link ${this.ctx.isRequestModel ? 'RequestModel' : 'TeaModel'}}`, level);
this.emitln(` *`, level);
this.emitln(` * <p>${this.ast.title ? this.ast.title : modelName}</p>`, level);
}
this.emitln(` */`, level);
if (deprecated) {
this.emitln(`@Deprecated`, level);
}
}
visitObjectFieldValue(ast, level) {
this.visitExpr(ast, level);
}
visitObjectField(ast, level) {
let comments = DSL.comment.getFrontComments(this.ctx.comments, ast.tokenRange[0]);
this.visitComments(comments, level);
if (ast.type === 'objectField') {
if (typeof ast.fieldName.string !== 'undefined') {
this.emit(`new TeaPair("${_string(ast.fieldName)}", `, level);
} else {
this.emit(`new TeaPair("${_name(ast.fieldName)}", `, level);
}
this.visitObjectFieldValue(ast.expr, level);
} else {
throw new Error('unimpelemented');
}
this.emit(')');
}
visitObject(ast, level) {
assert.equal(ast.type, 'object');
if (ast.fields.length === 0) {
this.emit('new java.util.HashMap<>()');
return;
}
var hasExpandField = false;
var hasNotExpandField = false;
for (let i = 0; i < ast.fields.length; i++) {
const field = ast.fields[i];
if (field.type === 'expandField') {
hasExpandField = true;
break;
} else {
hasNotExpandField = true;
}
}
if (!hasExpandField) {
this.emit('CommonUtil.buildMap(\n');
for (let i = 0; i < ast.fields.length; i++) {
this.visitObjectField(ast.fields[i], level + 1);
if (i < ast.fields.length - 1) {
this.emit(',');
}
this.emit('\n');
}
this.emit(')', level);
return;
}
var all = [];
// 分段
var current = [];
for (let i = 0; i < ast.fields.length; i++) {
const field = ast.fields[i];
if (field.type === 'objectField') {
current.push(field);
} else {
if (current.length > 0) {
all.push(current);
}
all.push(field);
current = [];
}
}
if (current.length > 0) {
all.push(current);
}
this.emit('CommonUtil.merge(');
if (ast.inferred && ast.inferred.valueType.name === 'string') {
this.emit('String.class');
} else {
this.emit('Object.class');
}
var hasExpandFieldBuildMap = false;
if (hasExpandField && hasNotExpandField) {
hasExpandFieldBuildMap = true;
this.emit(',\n');
this.emit('CommonUtil.buildMap(\n', level + 1);
} else {
this.emit(',\n');
}
for (let i = 0; i < all.length; i++) {
const item = all[i];
if (Array.isArray(item)) {
for (var j = 0; j < item.length; j++) {
this.visitObjectField(item[j], level + 2);
if (item[j + 1]) {
this.emit(',\n');
} else {
this.emit('\n');
}
}
} else {
this.emit('', level + 1);
this.visitExpr(item.expr, level);
if (all[i + 1]) {
this.emit(',');
}
this.emit('\n');
}
if (hasExpandFieldBuildMap) {
this.emit(')', level + 1);
if (all[i + 1]) {
this.emit(',\n');
} else {
this.emit('\n');
}
hasExpandFieldBuildMap = false;
}
}
this.emit(')', level);
}
visitFieldType(value, node, modelName, useEnum) {
if (value.fieldType === 'array') {
// basic type
this.emit(`java.util.List < `);
if (value.fieldItemType.tag === 8) {
this.emit(`${collectionType(_type(value.fieldItemType.lexeme))} `);
} else if (value.fieldItemType.type === 'map') {
this.visitType(value.fieldItemType);
} else if (value.fieldItemType.fieldType === 'array') {
this.visitFieldType(value.fieldItemType, node, modelName);
} else {
if (node.fieldValue.itemType) {
this.emit(_subModelName(node.fieldValue.itemType, this.ctx.conflictModelNameMap, this.ctx.allModleNameMap));
} else {
this.emit(`${_name(node.fieldValue.fieldItemType)} `);
}
}
this.emit(`> `);
} else if (value.fieldType === 'map') {
this.emit(`java.util.Map < ${collectionType(_type(value.keyType.lexeme))}, `);
if (value.valueType.type) {
this.visitType(value.valueType);
} else {
this.emit(`${collectionType(_type(value.valueType.lexeme))} `);
}
this.emit('> ');
} else if (typeof value.fieldType === 'string') {
this.emit(`${_type(value.fieldType)} `);
} else if (value.fieldType) {
if (value.fieldType.idType && value.fieldType.idType === 'module') {
var className = this.ctx.imports[`${_type(value.fieldType.lexeme)}`].className || 'DefaultAsyncClient';
this.emit(this.ctx.imports[`${_type(value.fieldType.lexeme)}`].package);
this.emit(`.${className} `);
} else if (value.fieldType.type && value.fieldType.type === 'moduleModel') {
this.emit(this.ctx.imports[_name(value.fieldType.path[0])].package);
this.emit(`.models.${_name(value.fieldType.path[1])} `);
} else if (value.fieldType.idType && value.fieldType.idType === 'enum') {
if (useEnum) {
this.emit(`${_type(value.fieldType.lexeme)} `);
} else {
this.emit(`${_type(this.ctx.enumMap[value.fieldType.lexeme])} `);
}
} else {
this.emit(`${_type(value.fieldType.lexeme)} `);
}
} else {
this.emit(_subModelName([modelName, _name(node.fieldName)].join('.'), this.ctx.conflictModelNameMap, this.ctx.allModleNameMap));
this.emit(' ');
}
}
visitType(ast, isSubType = false) {
if (ast.type === 'map') {
this.emit(`java.util.Map<`);
this.visitType(ast.keyType, true);
this.emit(`, `);
this.visitType(ast.valueType, true);
this.emit(`>`);
} else if (ast.type === 'array') {
this.emit(`java.util.List<`);
this.visitType(ast.subType || ast.itemType, true);
this.emit(`>`);
} else if (ast.type === 'model') {
if (ast.moduleName) {
const modelMap = `${ast.moduleName}:${_name(ast)}`;
if (this.ctx.conflictModels.get(modelMap)) {
this.emit(`${this.ctx.imports[ast.moduleName].package}.models.`);
}
} else {
const modelMap = `${_name(ast)}`;
if (this.ctx.conflictModels.get(modelMap)) {
this.emit(`${this.ctx.package}.models.`);
}
}
this.emit(`${_type(this.getSubFieldClassName(ast.name, true))}`);
} else if (ast.type === 'subModel') {
let className = '';
for (let i = 0; i < ast.path.length; i++) {
const item = ast.path[i];
if (i > 0) {
className += '.';
}
className += item.lexeme;
}
let resultName = this.getSubModelClassName(className.split('.'), 0, '');
this.emit(resultName);
} else if (ast.type === 'moduleModel') {
const [moduleId, ...rest] = ast.path;
let pathName = rest.map((item) => {
return item.lexeme;
}).join('.');
let subModelName = '';
if (rest.length > 1) {
subModelName = `.${_subModelName(pathName, this.ctx.conflictModelNameMap, this.ctx.allModleNameMap)}`;
}
var modelName = rest[0].lexeme;
var moduleName = moduleId.lexeme;
var packageName = `${this.ctx.imports[moduleName].package}.models.`;
const checkModel = moduleName + ':' + pathName;
if (this.ctx.conflictModels.get(checkModel)) {
this.emit(packageName + modelName + subModelName);
} else {
this.emit(modelName + subModelName);
}
} else if (ast.type === 'basic') {
this.emit(_type(ast.name));
} else if (this.ctx.predefined && this.ctx.predefined[`module:${_name(ast)}`]) {
var className = this.ctx.imports[ast.lexeme || ast.name].className || 'DefaultAsyncClient';
this.emit(`${this.ctx.imports[_name(ast)]}.${className}`);
} else if (ast.idType === 'module') {
let className = this.ctx.imports[ast.lexeme || ast.name].className;
if (this.ctx.conflictModels.get(className) && this.ctx.conflictModels.get(className) !== this.ctx.imports[ast.lexeme].package) {
this.emit(`${this.ctx.imports[ast.lexeme || ast.name].package}.${className}`);
} else {
if (!this.ctx.conflictModels.get(className)) {
this.ctx.conflictModels.set(className, this.ctx.imports[ast.lexeme || ast.name].package);
}
this.emit(className);
}
} else if (ast.idType === 'model') {
const modelMap = `${_name(ast)}`;
if (this.ctx.conflictModels.get(modelMap)) {
this.emit(`${this.ctx.package}.models.`);
}
this.emit(modelMap);
} else if (ast.type === 'module_instance') {
let className = this.ctx.imports[ast.lexeme || ast.name].className;
if (this.ctx.conflictModels.get(className) && this.ctx.conflictModels.get(className) !== this.ctx.imports[ast.lexeme].package) {
this.emit(`${this.ctx.imports[ast.lexeme || ast.name].package}.${className}`);
} else {
if (!this.ctx.conflictModels.get(className)) {
this.ctx.conflictModels.set(className, this.ctx.imports[ast.lexeme || ast.name].package);
}
this.emit(className);
}
} else if (ast.type === 'iterator') {
this.emit(`ResponseIterable<${_type(ast.valueType.lexeme || ast.valueType.name)}>`);
} else {
if (isSubType) {
this.emit(collectionType(_type(ast.lexeme || ast.name)));
} else {
this.emit(_type(ast.lexeme || ast.name));
}
}
}
}
module.exports = Generator;