@wuapi/generator
Version:
417 lines (413 loc) • 16.4 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const essential_1 = require("@wuapi/essential");
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const ncp_1 = __importDefault(require("ncp"));
const lodash_1 = __importDefault(require("lodash"));
const brace_1 = require("./brace");
const plugin_base_1 = require("./plugin_base");
const dedent_1 = __importDefault(require("dedent"));
/**
* Java code plugin.
*/
class JavaPlugin extends plugin_base_1.BasePlugin {
/**
* Returns the description of this plugin.
*/
getDescription() {
return {
name: "java",
abbreviation: "j",
version: "1.0.0",
description: "Generate Java code.",
arguments: [
{
tag: "getter",
withValue: false,
description: "Generate getter/setters of properties",
},
{
tag: "gradle",
withValue: false,
description: "Generate gradle project",
},
{
tag: "inc",
withValue: false,
description: "Increamental, NOT overriding old files (only work with 'gradle' mode)",
},
],
};
}
/**
* Process gradle project.
*/
processGradle(project, outputDir, skip, next) {
if (skip) {
next();
return;
}
const srcDir = [__dirname, "..", "template", this.getName()].join(path_1.default.sep);
const dstDir = [outputDir, this.getName()].join(path_1.default.sep);
(0, ncp_1.default)(srcDir, dstDir, (error) => {
if (error) {
return console.error(error);
}
const map = {
"{{project_name}}": project.name,
"{{project_version}}": project.version,
"{{project_package}}": project.targetPackage,
};
this.rewriteFile([srcDir, "settings.gradle"].join(path_1.default.sep), [dstDir, "settings.gradle"].join(path_1.default.sep), map);
this.rewriteFile([srcDir, "library", "build.gradle"].join(path_1.default.sep), [dstDir, "library", "build.gradle"].join(path_1.default.sep), map);
next();
});
}
/**
* Start process the project, and generate code.
*/
process(project, outputDir, args) {
if (args["gradle"] != undefined) {
const javaDir = [outputDir, this.getName(), "library", "src", "main"].join(path_1.default.sep);
fs_1.default.mkdirSync(javaDir, { recursive: true });
this.processGradle(project, outputDir, args["inc"] != undefined, () => {
new JavaPlugin().process(project, javaDir, lodash_1.default.omit(args, ["gradle", "inc"]));
});
return;
}
new JavaProcessor(this, project, outputDir, args).process();
}
}
exports.default = JavaPlugin;
/**
* The Java project processor
*/
class JavaProcessor extends plugin_base_1.ProjectProcessor {
get useGetter() { return this.config['getter'] != undefined; }
constructor(plugin, project, outputDir, config) {
super(plugin, project, outputDir, config);
this.packageDir = lodash_1.default.concat([this.rootDir], this.project.targetPackage.split('.')).join(path_1.default.sep);
}
/**
* Write text into java file.
* @param name The name of this file (without extension).
* @param text The content of the file
*/
writeJavaFile(name, text) {
const filePath = this.packageDir + path_1.default.sep + name + ".java";
const file = fs_1.default.openSync(filePath, 'w');
fs_1.default.writeFileSync(file, (0, dedent_1.default) `
package ${this.project.targetPackage};
import java.util.*; `
+ '\n\n' + text);
}
/**
* Write an entity.
* @param pth The path to the entity.
* @param entity The entity
*/
writeEntity(pth, entity) {
const self = this;
//
function genericTypeName(type) {
switch (type.type) {
case "TBoolean": return "Boolean";
case "TInteger": return "Integer";
case "TLong": return "Long";
case "TID": return "Long";
case "TDouble": return "Double";
case "TString": return "String";
case "TURL": return "String";
case "TDateTime": return "Long";
case "TSSMap": return "HashMap<String, String>";
case "TEnum": return type.enu.name;
case "TObject": return type.entity.name;
case "TUnknown": return type.unknown;
//case "TList" : return memberTypeName(type as $TList)
case "TList": return `List<${genericTypeName(type.member)}>`;
default: throw new Error(`Unknown generic type "${type.type}" in "${pth.module}/${pth.name}"`);
}
}
//
function generateFixedValue(name, f) {
let value = "";
const prefix = self.useGetter ? "private" : "public";
switch (f.type.type) {
case "TBoolean":
value = `${f.fixedValue}`;
break;
case "TInteger":
value = `${f.fixedValue}`;
break;
case "TLong":
value = `${f.fixedValue}L`;
break;
case "TID":
value = `${f.fixedValue}L`;
break;
case "TDouble":
value = `${f.fixedValue}`;
break;
case "TString":
value = `"${f.fixedValue}"`;
break;
case "TURL":
value = `"${f.fixedValue}"`;
break;
case "TDateTime":
value = `${f.fixedValue}`;
break;
default: throw Error(`Type "${f.type.type}" of Field "${name}" in "${pth.module}/${pth.name}" can NOT have fixed value!`);
}
return `${prefix} final ${genericTypeName(f.type)} ${name} = ${value};`;
}
//
function generateOptionalValue(name, f) {
const prefix = self.useGetter ? "private" : "public";
return `${prefix} ${genericTypeName(f.type)} ${name} = null;`;
}
//
function generateDefaultValue(name, f) {
let value = "";
const prefix = self.useGetter ? "private" : "public";
switch (f.type.type) {
case "TBoolean":
value = "";
break;
case "TInteger":
value = "";
break;
case "TLong":
value = "";
break;
case "TID":
value = "";
break;
case "TDouble":
value = "";
break;
case "TString":
value = "= \"\"";
break;
case "TURL":
value = "= \"\"";
break;
case "TDateTime":
value = "";
break;
case "TSSMap":
value = "= new HashMap<>()";
break;
case "TObject":
value = "= null";
break;
case "TUnknown":
value = "= null";
break;
case "TList":
value = "= new LinkedList<>()";
break;
case "TEnum": {
let fe = f.type;
value = `= ${fe.enu.name}.${fe.enu.asEnumOf(self.project).firstName()}`;
break;
}
default: throw Error(`Type "${f.type.type}" of Field "${name}" in "${pth.module}/${pth.name}" is invalid.`);
}
return `${prefix} ${genericTypeName(f.type)} ${name} ${value};`;
}
//
function calcSuffix(extra) {
let unsolved = entity.getGenericUnsolved(self.project);
if (extra) {
unsolved = lodash_1.default.concat(unsolved, [extra]);
}
return (unsolved.length > 0) ? `<${unsolved.join(", ")}>` : "";
}
//
function calcExtSuffix(extra) {
let punsolved = entity.parent?.asEntityOf(self.project)?.getGenericUnsolved(self.project) ?? [];
let unsolved = [];
punsolved.forEach((name) => {
let solved = entity.genericMap[name];
let item = (solved) ? genericTypeName(solved.type) : name;
unsolved.push(item);
});
if (extra) {
unsolved = lodash_1.default.concat(unsolved, [extra]);
}
return (unsolved.length > 0) ? `<${unsolved.join(", ")}>` : "";
}
//
function generateField(b, name, f) {
if (f.realname) {
b(`@SerializedName("${f.realname}")`);
}
if (f.fixedValue) {
b(generateFixedValue(name, f));
}
else if (f.isOptional) {
b(generateOptionalValue(name, f));
}
else {
b(generateDefaultValue(name, f));
}
}
//
function generateGetterSetter(b, name, f) {
const _name = lodash_1.default.camelCase(name);
b.bra(`public ${genericTypeName(f.type)} get${_name}()`).add((b) => {
b(`return ${name};`);
});
b.bra(`public void set${_name}(${genericTypeName(f.type)} value)`).add((b) => {
b(`${name} = value;`);
});
}
this.writeJavaFile(pth.name, (0, brace_1.flatBra)("").add((b) => {
// b(toBlockComment(entity))
const prefix = (entity.isAbstract) ? "abstract" : "";
switch (entity.type) {
////////////////////
// REQUEST
////////////////////
case essential_1.$EntityType.REQUEST: {
let resName = entity.response?.name;
let pname = entity.parent?.name ?? "AbsReq";
let suffix = calcSuffix((entity.isAbstract) ? "R extends AbsRes" : undefined);
let extSuf = calcExtSuffix((entity.isAbstract) ? "R" : (resName ?? undefined));
b.bra(`public ${prefix} class ${pth.name}${suffix} extends ${pname}${extSuf}`).add((b) => {
if (!entity.isAbstract) {
b((0, dedent_1.default) `
@Override
public String obtainPath() {
return "${entity.path}";
}
@Override
public String obtainMethod() {
return ${entity.method ? `"${entity.method}"` : "null"};
}
@Override
public Class<? extends ${resName}> obtainResClass() {
return ${resName}.class;
}
`);
}
//
lodash_1.default.forIn(entity.fieldsLocal, (f, name) => {
generateField(b, name, f);
});
b("");
if (this.useGetter) {
lodash_1.default.forIn(entity.fieldsLocal, (f, name) => {
generateGetterSetter(b, name, f);
});
}
});
break;
}
////////////////////
// RESPONSE
////////////////////
case essential_1.$EntityType.RESPONSE: {
let pname = entity.parent?.name ?? "AbsRes";
let suffix = calcSuffix();
let extSuf = calcExtSuffix();
b.bra(`public ${prefix} class ${pth.name}${suffix} extends ${pname}${extSuf}`).add((b) => {
//
lodash_1.default.forIn(entity.fieldsLocal, (f, name) => {
generateField(b, name, f);
});
b("");
if (this.useGetter) {
lodash_1.default.forIn(entity.fieldsLocal, (f, name) => {
generateGetterSetter(b, name, f);
});
}
});
break;
}
////////////////////
// OBJECT
////////////////////
case essential_1.$EntityType.OBJECT: {
let extendString = (entity.parent) ? `extends ${entity.parent.name}` : "";
let suffix = calcSuffix();
let extSuf = calcExtSuffix();
b.bra(`public ${prefix} class ${pth.name}${suffix} ${extendString}${extSuf}`).add((b) => {
//
lodash_1.default.forIn(entity.fieldsLocal, (f, name) => {
generateField(b, name, f);
});
b("");
if (this.useGetter) {
lodash_1.default.forIn(entity.fieldsLocal, (f, name) => {
generateGetterSetter(b, name, f);
});
}
});
break;
}
}
}).toString());
}
/**
* Write an enumeration
* @param pth The path to the enumeration
* @param enu The enumeration.
*/
writeEnum(pth, enu) {
this.writeJavaFile(pth.name, (0, brace_1.flatBra)("").add((b) => {
// b(toBlockComment(enu))
b.bra(`public enum ${pth.name}`).add((b) => {
enu.flat().forEach(({ name, item }) => {
// b(toLineComment(item))
b(`${name}(${item.value}),`);
});
b((0, dedent_1.default) `
;
private int value;
private ${pth.name}(int value) {
this.value = value;
}
public int getValue() {
return value;
}
`);
b.bra(`public static ${pth.name} find(int value)`).add((b) => {
b.bra("switch(value)").add((b) => {
enu.flat().forEach(({ name, item }) => {
b(`case ${item.value}: return ${name};`);
});
b("default: return null;");
});
});
});
}).toString());
}
/**
* Process the project.
*/
process() {
fs_1.default.rmSync(this.rootDir, { recursive: true, force: true });
fs_1.default.mkdirSync(this.packageDir, { recursive: true });
this.writeJavaFile("AbsReq", (0, dedent_1.default) `
public abstract class AbsReq<R extends AbsRes> {
public abstract String obtainPath();
public abstract String obtainMethod();
public abstract Class<? extends R> obtainResClass();
}`);
this.writeJavaFile("AbsRes", (0, dedent_1.default) `
public abstract class AbsRes {
}`);
this.project.flatEntities().forEach(({ path, entity }) => {
this.writeEntity(path, entity);
});
this.project.flatEnums().forEach(({ path, enu }) => {
this.writeEnum(path, enu);
});
}
}