【重构】【cfg】 略微重构 typescript语言生成代码,多态类的构造函数名由 deserialize改为 constructorFrom,语义更清楚

【修复】【cfg】 修复  typescript 生成代码能编译但未能正确导出定义类的bug
【特性】【proto】 对于使用puerts框架的unity项目,支持生成 typescript的消息代码。测试通过。
main
walon 2021-05-01 22:36:59 +08:00
parent 5868f9bd0a
commit ca8104aa33
20 changed files with 766 additions and 161 deletions

View File

@ -57,6 +57,11 @@ namespace Luban.Common.Utils
return string.Join("", module.Split('.').Select(n => $"{n}_")) + ueName;
}
public static string MakeTypescriptNamespaceBegin(string module)
{
return string.Join("", module.Split('.').Select(n => $"export namespace {n} {{"));
}
public static string MakeFullName(string module, string name)
{
if (string.IsNullOrEmpty(module))

View File

@ -98,9 +98,14 @@ namespace Luban.Job.Cfg.Defs
}
public static string TsDeserialize(string fieldName, string jsonFieldName, TType type)
public static string TsJsonConstructor(string fieldName, string jsonFieldName, TType type)
{
return type.Apply(TypescriptDeserializeVisitor.Ins, $"{jsonFieldName}", fieldName);
return type.Apply(TypescriptJsonConstructorVisitor.Ins, $"{jsonFieldName}", fieldName);
}
public static string TsBinConstructor(string fieldName, string byteBufName, TType type)
{
return type.Apply(TypescriptBinConstructorVisitor.Ins, $"{byteBufName}", fieldName);
}
public static string TsRecursiveResolve(DefField field, string tables)
@ -124,11 +129,6 @@ namespace Luban.Job.Cfg.Defs
}
}
public static string TsDeserializeBin(string fieldName, string byteBufName, TType type)
{
return type.Apply(TypescriptDeserializeBinVisitor.Ins, byteBufName, fieldName);
}
public static string Py3Deserialize(string fieldName, string jsonFieldName, TType type)
{
return type.Apply(PyDeserializeVisitor.Py3Ins, $"{jsonFieldName}", fieldName);

View File

@ -1,14 +1,23 @@
using Luban.Job.Cfg.Defs;
using Luban.Job.Common.Defs;
using Luban.Job.Common.Utils;
using Scriban;
using System;
using System.Collections.Generic;
namespace Luban.Job.Cfg.Generate
{
class TypeScriptBinCodeRender : TypescriptCodeRenderBase
class TypeScriptBinCodeRender : CodeRenderBase
{
public override string Render(DefConst c)
{
return RenderUtil.RenderTypescriptConstClass(c);
}
public override string Render(DefEnum e)
{
return RenderUtil.RenderTypescriptEnumClass(e);
}
[ThreadStatic]
private static Template t_beanRender;
@ -23,11 +32,11 @@ namespace Luban.Job.Cfg.Generate
hierarchy_export_fields = x.hierarchy_export_fields
}}
namespace {{x.namespace}} {
{{x.typescript_namespace_begin}}
export {{if x.is_abstract_type}} abstract {{end}} class {{name}} {{if parent_def_type}} extends {{x.parent}}{{end}} {
{{~if x.is_abstract_type~}}
static deserialize(_buf_ : Bright.Serialization.ByteBuf) : {{name}} {
static constructorFrom(_buf_ : Bright.Serialization.ByteBuf) : {{name}} {
switch (_buf_.ReadInt())
{
case 0 : return null;
@ -44,7 +53,7 @@ export {{if x.is_abstract_type}} abstract {{end}} class {{name}} {{if parent_def
super(_buf_);
{{~end~}}
{{~ for field in export_fields ~}}
{{ts_deserialize_bin ('this.' + field.ts_style_name) '_buf_' field.ctype}}
{{ts_bin_constructor ('this.' + field.ts_style_name) '_buf_' field.ctype}}
{{~end~}}
}
@ -69,7 +78,7 @@ export {{if x.is_abstract_type}} abstract {{end}} class {{name}} {{if parent_def
}
}
}
{{x.typescript_namespace_end}}
");
var result = template.RenderCode(b);
@ -88,7 +97,7 @@ export {{if x.is_abstract_type}} abstract {{end}} class {{name}} {{if parent_def
key_type2 = x.key_ttype2
value_type = x.value_ttype
}}
namespace {{x.namespace}} {
{{x.typescript_namespace_begin}}
export class {{name}}{
{{~ if x.is_two_key_map_table ~}}
private _dataListMap : Map<{{ts_define_type key_type1}}, {{ts_define_type value_type}}[]>;
@ -102,7 +111,7 @@ export class {{name}}{
for(let n = _buf_.ReadInt(); n > 0 ; n--) {
let _v : {{ts_define_type value_type}};
{{ts_deserialize_bin '_v' '_buf_' value_type}}
{{ts_bin_constructor '_v' '_buf_' value_type}}
this._dataList.push(_v);
var _key = _v.{{x.index_field1.ts_style_name}};
let list : {{ts_define_type value_type}}[] = this._dataListMap.get(_key);
@ -142,7 +151,7 @@ export class {{name}}{
for(let n = _buf_.ReadInt() ; n > 0 ; n--) {
let _v : {{ts_define_type value_type}};
{{ts_deserialize_bin '_v' '_buf_' value_type}}
{{ts_bin_constructor '_v' '_buf_' value_type}}
this._dataList.push(_v);
this._dataMap.set(_v.{{x.index_field.ts_style_name}}, _v);
}
@ -165,7 +174,7 @@ export class {{name}}{
constructor(_buf_ : Bright.Serialization.ByteBuf) {
if (_buf_.ReadInt() != 1) throw new Error('table mode=one, but size != 1');
{{ts_deserialize_bin 'this._data' '_buf_' value_type}}
{{ts_bin_constructor 'this._data' '_buf_' value_type}}
}
getData() : {{ts_define_type value_type}} { return this._data; }
@ -180,7 +189,7 @@ export class {{name}}{
{{end}}
}
}
{{x.typescript_namespace_end}}
");
var result = template.RenderCode(p);

View File

@ -1,13 +1,24 @@
using Luban.Job.Cfg.Defs;
using Luban.Job.Common.Defs;
using Luban.Job.Common.Utils;
using Scriban;
using System;
using System.Collections.Generic;
namespace Luban.Job.Cfg.Generate
{
class TypeScriptJsonCodeRender : TypescriptCodeRenderBase
class TypeScriptJsonCodeRender : CodeRenderBase
{
public override string Render(DefConst c)
{
return RenderUtil.RenderTypescriptConstClass(c);
}
public override string Render(DefEnum e)
{
return RenderUtil.RenderTypescriptEnumClass(e);
}
[ThreadStatic]
private static Template t_beanRender;
public override string Render(DefBean b)
@ -21,11 +32,11 @@ namespace Luban.Job.Cfg.Generate
hierarchy_export_fields = x.hierarchy_export_fields
}}
namespace {{x.namespace}} {
{{x.typescript_namespace_begin}}
export {{if x.is_abstract_type}} abstract {{end}} class {{name}} {{if parent_def_type}} extends {{x.parent}}{{end}} {
{{~if x.is_abstract_type~}}
static deserialize(_json_ : any) : {{name}} {
static constructorFrom(_json_ : any) : {{name}} {
switch (_json_.__type__) {
case null : return null;
{{~ for child in x.hierarchy_not_abstract_children~}}
@ -44,7 +55,7 @@ export {{if x.is_abstract_type}} abstract {{end}} class {{name}} {{if parent_def
{{~if !field.ctype.is_nullable~}}
if (_json_.{{field.name}} == null) { throw new Error(); }
{{~end~}}
{{ts_deserialize ('this.' + field.ts_style_name) ( '_json_.' + field.name) field.ctype}}
{{ts_json_constructor ('this.' + field.ts_style_name) ( '_json_.' + field.name) field.ctype}}
{{~end~}}
}
@ -69,7 +80,7 @@ export {{if x.is_abstract_type}} abstract {{end}} class {{name}} {{if parent_def
}
}
}
{{x.typescript_namespace_end}}
");
var result = template.RenderCode(b);
@ -88,7 +99,7 @@ export {{if x.is_abstract_type}} abstract {{end}} class {{name}} {{if parent_def
key_type2 = x.key_ttype2
value_type = x.value_ttype
}}
namespace {{x.namespace}} {
{{x.typescript_namespace_begin}}
export class {{name}}{
{{~ if x.is_two_key_map_table ~}}
private _dataListMap : Map<{{ts_define_type key_type1}}, {{ts_define_type value_type}}[]>;
@ -102,7 +113,7 @@ export class {{name}}{
for(var _json2_ of _json_) {
let _v : {{ts_define_type value_type}};
{{ts_deserialize '_v' '_json2_' value_type}}
{{ts_json_constructor '_v' '_json2_' value_type}}
this._dataList.push(_v);
var _key = _v.{{x.index_field1.ts_style_name}};
let list : {{ts_define_type value_type}}[] = this._dataListMap.get(_key);
@ -142,7 +153,7 @@ export class {{name}}{
for(var _json2_ of _json_) {
let _v : {{ts_define_type value_type}};
{{ts_deserialize '_v' '_json2_' value_type}}
{{ts_json_constructor '_v' '_json2_' value_type}}
this._dataList.push(_v);
this._dataMap.set(_v.{{x.index_field.ts_style_name}}, _v);
}
@ -165,7 +176,7 @@ export class {{name}}{
constructor(_json_ : any) {
if (_json_.length != 1) throw new Error('table mode=one, but size != 1');
{{ts_deserialize 'this._data' '_json_[0]' value_type}}
{{ts_json_constructor 'this._data' '_json_[0]' value_type}}
}
getData() : {{ts_define_type value_type}} { return this._data; }
@ -180,7 +191,7 @@ export class {{name}}{
{{end}}
}
}
{{x.typescript_namespace_end}}
");
var result = template.RenderCode(p);

View File

@ -1,59 +0,0 @@
using Luban.Job.Common.Defs;
using Scriban;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Luban.Job.Cfg.Generate
{
abstract class TypescriptCodeRenderBase : CodeRenderBase
{
[ThreadStatic]
private static Template t_tsConstRender;
public override string Render(DefConst c)
{
var ctx = new TemplateContext();
var env = new TTypeTemplateCommonExtends
{
["x"] = c
};
ctx.PushGlobal(env);
var template = t_tsConstRender ??= Template.Parse(@"
namespace {{x.namespace}} {
export class {{x.name}} {
{{~ for item in x.items ~}}
static {{item.name}} = {{ts_const_value item.ctype item.value}};
{{~end~}}
}
}
");
var result = template.Render(ctx);
return result;
}
[ThreadStatic]
private static Template t_tsEnumRender;
public override string Render(DefEnum e)
{
var template = t_tsEnumRender ??= Template.Parse(@"
namespace {{namespace}} {
export enum {{name}} {
{{- for item in items }}
{{item.name}} = {{item.value}},
{{-end}}
}
}
");
var result = template.Render(e);
return result;
}
}
}

View File

@ -0,0 +1,30 @@
using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors;
namespace Luban.Job.Common.TypeVisitors
{
class TypescriptBinConstructorVisitor : DecoratorFuncVisitor<string, string, string>
{
public static TypescriptBinConstructorVisitor Ins { get; } = new TypescriptBinConstructorVisitor();
public override string DoAccept(TType type, string byteBufName, string fieldName)
{
if (type.IsNullable)
{
return $"if({byteBufName}.ReadBool()) {{ {type.Apply(TypescriptBinUnderingConstructorVisitor.Ins, byteBufName, fieldName)} }} else {{ {fieldName} = null; }}";
}
else
{
return type.Apply(TypescriptBinUnderingConstructorVisitor.Ins, byteBufName, fieldName);
}
}
// TODO 设计需要简化现在造成多态bean的可空与其他字段类型不一样而需要单独处理
// 多态bean不浪费一个字段直接用typeid==0表示空
// 因此不跟普通字段一样,需要 ReadBool()来区别是否为空
public override string Accept(TBean type, string bufName, string fieldName)
{
return type.Apply(TypescriptBinUnderingConstructorVisitor.Ins, bufName, fieldName);
}
}
}

View File

@ -0,0 +1,22 @@
using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors;
namespace Luban.Job.Common.TypeVisitors
{
class TypescriptBinUnderingConstructorVisitor : TypescriptBinUnderingDeserializeVisitorBase
{
public static TypescriptBinUnderingConstructorVisitor Ins { get; } = new TypescriptBinUnderingConstructorVisitor();
public override string Accept(TBean type, string bufVarName, string fieldName)
{
if (type.Bean.IsAbstractType)
{
return $"{fieldName} = {type.Bean.FullName}.constructorFrom({bufVarName});";
}
else
{
return $"{fieldName} = new {type.Bean.FullName}({bufVarName});";
}
}
}
}

View File

@ -1,27 +0,0 @@
using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors;
namespace Luban.Job.Cfg.TypeVisitors
{
class TypescriptDeserializeVisitor : DecoratorFuncVisitor<string, string, string>
{
public static TypescriptDeserializeVisitor Ins { get; } = new TypescriptDeserializeVisitor();
public override string DoAccept(TType type, string jsonFieldName, string fieldName)
{
if (type.IsNullable)
{
return $"if({jsonFieldName} != null) {{ {type.Apply(TypescriptUnderingDeserializeVisitor.Ins, jsonFieldName, fieldName)} }} else {{ {fieldName} = null; }}";
}
else
{
return type.Apply(TypescriptUnderingDeserializeVisitor.Ins, jsonFieldName, fieldName);
}
}
public override string Accept(TBean type, string bufName, string fieldName)
{
return type.Apply(TypescriptUnderingDeserializeVisitor.Ins, bufName, fieldName);
}
}
}

View File

@ -0,0 +1,27 @@
using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors;
namespace Luban.Job.Cfg.TypeVisitors
{
class TypescriptJsonConstructorVisitor : DecoratorFuncVisitor<string, string, string>
{
public static TypescriptJsonConstructorVisitor Ins { get; } = new TypescriptJsonConstructorVisitor();
public override string DoAccept(TType type, string jsonFieldName, string fieldName)
{
if (type.IsNullable)
{
return $"if({jsonFieldName} != null) {{ {type.Apply(TypescriptJsonUnderingConstructorVisitor.Ins, jsonFieldName, fieldName)} }} else {{ {fieldName} = null; }}";
}
else
{
return type.Apply(TypescriptJsonUnderingConstructorVisitor.Ins, jsonFieldName, fieldName);
}
}
//public override string Accept(TBean type, string bytebufName, string fieldName)
//{
// return type.Apply(TypescriptJsonUnderingConstructorVisitor.Ins, bytebufName, fieldName);
//}
}
}

View File

@ -3,9 +3,9 @@ using Luban.Job.Common.TypeVisitors;
namespace Luban.Job.Cfg.TypeVisitors
{
class TypescriptUnderingDeserializeVisitor : ITypeFuncVisitor<string, string, string>
class TypescriptJsonUnderingConstructorVisitor : ITypeFuncVisitor<string, string, string>
{
public static TypescriptUnderingDeserializeVisitor Ins { get; } = new TypescriptUnderingDeserializeVisitor();
public static TypescriptJsonUnderingConstructorVisitor Ins { get; } = new TypescriptJsonUnderingConstructorVisitor();
public string Accept(TBool type, string jsonVarName, string fieldName)
{
@ -81,7 +81,7 @@ namespace Luban.Job.Cfg.TypeVisitors
{
if (type.Bean.IsAbstractType)
{
return $"{fieldName} = {type.Bean.FullName}.deserialize({jsonVarName});";
return $"{fieldName} = {type.Bean.FullName}.constructorFrom({jsonVarName});";
}
else
{

View File

@ -33,6 +33,9 @@ namespace Luban.Job.Common.Defs
public string CppFullNameWithTopModule => TypeUtil.MakeCppFullName(AssemblyBase.TopModule, FullName);
public string TypescriptNamespaceBegin => TypeUtil.MakeTypescriptNamespaceBegin(Namespace);
public string TypescriptNamespaceEnd => TypeUtil.MakeCppNamespaceEnd(Namespace);
public string CppFullName => TypeUtil.MakeCppFullName(Namespace, Name);

View File

@ -138,6 +138,16 @@ namespace Luban.Job.Common.Defs
return type.Apply(LuaConstValueVisitor.Ins, value);
}
public static string TsBinSerialize(string fieldName, string byteBufName, TType type)
{
return type.Apply(TypescriptBinSerializeVisitor.Ins, byteBufName, fieldName);
}
public static string TsBinDeserialize(string fieldName, string byteBufName, TType type)
{
return type.Apply(TypescriptBinDeserializeVisitor.Ins, byteBufName, fieldName);
}
public static string PyDefineType(TType type)
{
return type.Apply(PyDefineTypeName.Ins);

View File

@ -1,27 +1,27 @@
using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors;
namespace Luban.Job.Cfg.TypeVisitors
namespace Luban.Job.Common.TypeVisitors
{
class TypescriptDeserializeBinVisitor : DecoratorFuncVisitor<string, string, string>
class TypescriptBinDeserializeVisitor : DecoratorFuncVisitor<string, string, string>
{
public static TypescriptDeserializeBinVisitor Ins { get; } = new TypescriptDeserializeBinVisitor();
public static TypescriptBinDeserializeVisitor Ins { get; } = new TypescriptBinDeserializeVisitor();
public override string DoAccept(TType type, string byteBufName, string fieldName)
{
if (type.IsNullable)
{
return $"if({byteBufName}.ReadBool()) {{ {type.Apply(TypescriptUnderingDeserializeBinVisitor.Ins, byteBufName, fieldName)} }} else {{ {fieldName} = null; }}";
return $"if({byteBufName}.ReadBool()) {{ {type.Apply(TypescriptBinUnderingDeserializeVisitor.Ins, byteBufName, fieldName)} }} else {{ {fieldName} = null; }}";
}
else
{
return type.Apply(TypescriptUnderingDeserializeBinVisitor.Ins, byteBufName, fieldName);
return type.Apply(TypescriptBinUnderingDeserializeVisitor.Ins, byteBufName, fieldName);
}
}
public override string Accept(TBean type, string bufName, string fieldName)
{
return type.Apply(TypescriptUnderingDeserializeBinVisitor.Ins, bufName, fieldName);
return type.Apply(TypescriptBinUnderingDeserializeVisitor.Ins, bufName, fieldName);
}
}
}

View File

@ -0,0 +1,31 @@
using Luban.Job.Common.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Luban.Job.Common.TypeVisitors
{
class TypescriptBinSerializeVisitor : DecoratorFuncVisitor<string, string, string>
{
public static TypescriptBinSerializeVisitor Ins { get; } = new TypescriptBinSerializeVisitor();
public override string DoAccept(TType type, string bytebufName, string fieldName)
{
if (type.IsNullable)
{
return $"if({bytebufName}.ReadBool()) {{{type.Apply(TypescriptBinUnderingSerializeVisitor.Ins, bytebufName, fieldName)} }} else {{ {fieldName} = null; }}";
}
else
{
return type.Apply(TypescriptBinUnderingSerializeVisitor.Ins, bytebufName, fieldName);
}
}
public override string Accept(TBean type, string bufName, string fieldName)
{
return type.Apply(TypescriptBinUnderingSerializeVisitor.Ins, bufName, fieldName);
}
}
}

View File

@ -0,0 +1,22 @@
using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors;
namespace Luban.Job.Common.TypeVisitors
{
public class TypescriptBinUnderingDeserializeVisitor : TypescriptBinUnderingDeserializeVisitorBase
{
public static TypescriptBinUnderingDeserializeVisitor Ins { get; } = new TypescriptBinUnderingDeserializeVisitor();
public override string Accept(TBean type, string bufVarName, string fieldName)
{
if (type.Bean.IsAbstractType)
{
return $"{fieldName} = {type.Bean.FullName}.deserializeFrom({bufVarName});";
}
else
{
return $"{fieldName} = new {type.Bean.FullName}(); {fieldName}.deserialize({bufVarName});";
}
}
}
}

View File

@ -1,12 +1,10 @@
using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors;
namespace Luban.Job.Cfg.TypeVisitors
namespace Luban.Job.Common.TypeVisitors
{
class TypescriptUnderingDeserializeBinVisitor : ITypeFuncVisitor<string, string, string>
public abstract class TypescriptBinUnderingDeserializeVisitorBase : ITypeFuncVisitor<string, string, string>
{
public static TypescriptUnderingDeserializeBinVisitor Ins { get; } = new TypescriptUnderingDeserializeBinVisitor();
public string Accept(TBool type, string bufName, string fieldName)
{
return $"{fieldName} = {bufName}.ReadBool();";
@ -69,7 +67,7 @@ namespace Luban.Job.Cfg.TypeVisitors
public string Accept(TBytes type, string bufName, string fieldName)
{
return $"{fieldName} = {bufName}.ReadArrayBuf();";
return $"{fieldName} = new Uint8Array({bufName}.ReadArrayBuffer());";
}
public string Accept(TText type, string bufName, string fieldName)
@ -77,17 +75,17 @@ namespace Luban.Job.Cfg.TypeVisitors
return $"{fieldName} = {bufName}.ReadString();";
}
public string Accept(TBean type, string bufVarName, string fieldName)
{
if (type.Bean.IsAbstractType)
{
return $"{fieldName} = {type.Bean.FullName}.deserialize({bufVarName});";
}
else
{
return $"{fieldName} = new {type.Bean.FullName}({bufVarName});";
}
}
public abstract string Accept(TBean type, string bufVarName, string fieldName);
//{
// if (type.Bean.IsAbstractType)
// {
// return $"{fieldName} = {type.Bean.FullName}.deserialize({bufVarName});";
// }
// else
// {
// return $"{fieldName} = new {type.Bean.FullName}({bufVarName});";
// }
//}
private string GetNewArray(TArray arrayType, string size)
{

View File

@ -0,0 +1,171 @@
using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Luban.Job.Common.TypeVisitors
{
class TypescriptBinUnderingSerializeVisitor : ITypeFuncVisitor<string, string, string>
{
public static TypescriptBinUnderingSerializeVisitor Ins { get; } = new TypescriptBinUnderingSerializeVisitor();
public string Accept(TBool type, string bufName, string fieldName)
{
return $"{bufName}.WriteBool({fieldName});";
}
public string Accept(TByte type, string bufName, string fieldName)
{
return $"{bufName}.WriteByte({fieldName});";
}
public string Accept(TShort type, string bufName, string fieldName)
{
return $"{bufName}.WriteShort({fieldName});";
}
public string Accept(TFshort type, string bufName, string fieldName)
{
return $"{bufName}.WriteFshort({fieldName});";
}
public string Accept(TInt type, string bufName, string fieldName)
{
return $"{bufName}.WriteInt({fieldName});";
}
public string Accept(TFint type, string bufName, string fieldName)
{
return $"{bufName}.WriteFint({fieldName});";
}
public string Accept(TLong type, string bufName, string fieldName)
{
return $"{bufName}.WriteLong({fieldName});";
}
public string Accept(TFlong type, string bufName, string fieldName)
{
return $"{bufName}.WriteFlong({fieldName});";
}
public string Accept(TFloat type, string bufName, string fieldName)
{
return $"{bufName}.WriteFloat({fieldName});";
}
public string Accept(TDouble type, string bufName, string fieldName)
{
return $"{bufName}.WriteDouble({fieldName});";
}
public string Accept(TEnum type, string bufName, string fieldName)
{
return $"{bufName}.WriteInt({fieldName});";
}
public string Accept(TString type, string bufName, string fieldName)
{
return $"{bufName}.WriteString({fieldName});";
}
public string Accept(TBytes type, string bufName, string fieldName)
{
return $"{bufName}.WriteArrayBuffer({fieldName}.buffer);";
}
public string Accept(TText type, string bufName, string fieldName)
{
return $"{bufName}.WriteString({fieldName});";
}
public string Accept(TVector2 type, string bufVarName, string fieldName)
{
return $"{fieldName}.to({bufVarName})";
}
public string Accept(TVector3 type, string bufVarName, string fieldName)
{
return $"{fieldName}.to({bufVarName})";
}
public string Accept(TVector4 type, string bufVarName, string fieldName)
{
return $"{fieldName}.to({bufVarName})";
}
public string Accept(TDateTime type, string bufVarName, string fieldName)
{
return $"{bufVarName}.WriteInt({fieldName});";
}
public string Accept(TBean type, string bufVarName, string fieldName)
{
if (type.Bean.IsAbstractType)
{
return $"{type.Bean.FullName}.serializeTo({bufVarName}, {fieldName});";
}
else
{
return $"{fieldName}.serialize({bufVarName});";
}
}
private static string GetNewArray(TArray arrayType, string size)
{
switch (arrayType.ElementType)
{
case TByte _: return $"new Uint8Array({size})";
case TShort _:
case TFshort _: return $"new Int16Array({size})";
case TInt _:
case TFint _: return $"new Int32Array({size})";
case TLong _:
case TFlong _: return $"new Int64Array({size})";
case TFloat _: return $"new Float32Array({size})";
case TDouble _: return $"new Float64Array({size})";
default: return "[]";
}
}
private static bool IsRawArrayElementType(TType elementType)
{
switch (elementType)
{
case TByte _:
case TShort _:
case TFshort _:
case TInt _:
case TFint _:
case TLong _:
case TFlong _:
case TFloat _:
case TDouble _: return true;
default: return false;
}
}
public string Accept(TArray type, string bufVarName, string fieldName)
{
return $"{{ {bufVarName}.WriteSize({fieldName}.length); for(let _e of {fieldName}) {{ {type.ElementType.Apply(this, bufVarName, "_e")} }} }}";
}
public string Accept(TList type, string bufVarName, string fieldName)
{
return $"{{ {bufVarName}.WriteSize({fieldName}.length); for(let _e of {fieldName}) {{ {type.ElementType.Apply(this, bufVarName, "_e")} }} }}";
}
public string Accept(TSet type, string bufVarName, string fieldName)
{
return $"{{ {bufVarName}.WriteSize({fieldName}.size); for(let _e of {fieldName}) {{ {type.ElementType.Apply(this, bufVarName, "_e")} }} }}";
}
public string Accept(TMap type, string bufVarName, string fieldName)
{
return $"{{ {bufVarName}.WriteSize({fieldName}.size); for(let [_k, _v] of {fieldName}) {{ {type.KeyType.Apply(this, bufVarName, "_k")} {type.ValueType.Apply(this, bufVarName, "_v")} }} }}";
}
}
}

View File

@ -177,11 +177,9 @@ enum class {{name}}
}
[ThreadStatic]
private static Template t_tsConstRender;
public static string RenderTsConstClass(DefConst c)
public static string RenderTypescriptConstClass(DefConst c)
{
var ctx = new TemplateContext();
var env = new TTypeTemplateCommonExtends
@ -192,15 +190,14 @@ enum class {{name}}
var template = t_tsConstRender ??= Template.Parse(@"
namespace {{x.namespace_with_top_module}}
{
export class {{x.name}}
{
{{typescript_namespace_begin}}
export class {{x.name}} {
{{~ for item in x.items ~}}
static {{item.name}} : {{ts_define_type item.ctype}} = {{ts_const_value item.ctype item.value}};
static {{item.name}} = {{ts_const_value item.ctype item.value}};
{{~end~}}
}
}
{{typescript_namespace_end}}
");
var result = template.Render(ctx);
@ -210,20 +207,17 @@ namespace {{x.namespace_with_top_module}}
[ThreadStatic]
private static Template t_tsEnumRender;
public static string RenderTsEnumClass(DefEnum e)
public static string RenderTypescriptEnumClass(DefEnum e)
{
var template = t_tsEnumRender ??= Template.Parse(@"
namespace {{namespace_with_top_module}}
{
export enum {{name}}
{
{{typescript_namespace_begin}}
export enum {{name}} {
{{- for item in items }}
{{item.name}} = {{item.value}},
{{-end}}
}
}
{{typescript_namespace_end}}
");
var result = template.Render(e);

View File

@ -0,0 +1,231 @@
using Luban.Job.Common.Defs;
using Luban.Job.Common.Utils;
using Luban.Job.Proto.Defs;
using Scriban;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Luban.Job.Proto.Generate
{
class TypescriptRender
{
public string RenderAny(object o)
{
switch (o)
{
case DefConst c: return Render(c);
case DefEnum e: return Render(e);
case DefBean b: return Render(b);
case DefProto p: return Render(p);
case DefRpc r: return Render(r);
default: throw new Exception($"unknown render type:{o}");
}
}
private string Render(DefConst c)
{
return RenderUtil.RenderTypescriptConstClass(c);
}
private string Render(DefEnum e)
{
return RenderUtil.RenderTypescriptEnumClass(e);
}
[ThreadStatic]
private static Template t_beanRender;
private string Render(DefBean b)
{
var template = t_beanRender ??= Template.Parse(@"
{{
is_value_type = x.is_value_type
is_abstract_type = x.is_abstract_type
name = x.name
full_name = x.full_name
parent_def_type = x.parent_def_type
parent = x.parent
fields = x.fields
hierarchy_fields = x.hierarchy_fields
}}
{{x.typescript_namespace_begin}}
export {{if x.is_abstract_type}} abstract {{end}} class {{name}} extends {{if parent_def_type}}{{x.parent}}{{else}}BeanBase{{end}} {
{{~if x.is_abstract_type~}}
static serializeTo(_buf_ : Bright.Serialization.ByteBuf, _bean_ : {{name}}) : void {
if (_bean_ == null) {
_buf_.WriteInt(0)
return
}
_buf_.WriteInt(_bean_.getTypeId())
_bean_.serialize(_buf_)
}
static deserializeFrom(_buf_ : Bright.Serialization.ByteBuf) : {{name}} {
let _bean_ :{{name}}
switch (_buf_.ReadInt()) {
case 0 : return null;
{{~ for child in x.hierarchy_not_abstract_children~}}
case {{child.id}}: _bean_ = new {{child.full_name}}(_buf_); break;
{{~end~}}
default: throw new Error();
}
_bean_.deserialize(_buf_)
return _bean_
}
{{else}}
static readonly ID = {{x.id}}
getTypeId() { return {{name}}.ID }
{{~end~}}
{{~ for field in fields ~}}
{{field.ts_style_name}}{{if field.is_nullable}}?{{end}} : {{ts_define_type field.ctype}};
{{~end~}}
serialize(_buf_ : Bright.Serialization.ByteBuf) {
{{~if parent_def_type~}}
super.serialize(_buf_);
{{~end~}}
{{~ for field in fields ~}}
{{ts_bin_serialize ('this.' + field.ts_style_name) '_buf_' field.ctype}}
{{~end~}}
}
deserialize(_buf_ : Bright.Serialization.ByteBuf) {
{{~if parent_def_type~}}
super.deserialize(_buf_);
{{~end~}}
{{~ for field in fields ~}}
{{ts_bin_deserialize ('this.' + field.ts_style_name) '_buf_' field.ctype}}
{{~end~}}
}
toString(): string {
return ""{{full_name}}{ ""
{{~ for field in hierarchy_fields ~}}
+ ""{{field.ts_style_name}}:"" + this.{{field.ts_style_name}} + "",""
{{~end~}}
+ ""}"";
}
}
{{x.typescript_namespace_end}}
");
var result = template.RenderCode(b);
return result;
}
[ThreadStatic]
private static Template t_protoRender;
private string Render(DefProto p)
{
var template = t_protoRender ??= Template.Parse(@"
{{
name = x.name
full_name = x.full_name
parent = x.parent
fields = x.fields
}}
{{x.typescript_namespace_begin}}
export class {{name}} extends Protocol {
static readonly ID = {{x.id}}
getTypeId() { return {{name}}.ID }
{{~ for field in fields ~}}
{{field.ts_style_name}}{{if field.is_nullable}}?{{end}} : {{ts_define_type field.ctype}};
{{~end~}}
serialize(_buf_ : Bright.Serialization.ByteBuf) {
{{~ for field in fields ~}}
{{ts_bin_serialize ('this.' + field.ts_style_name) '_buf_' field.ctype}}
{{~end~}}
}
deserialize(_buf_ : Bright.Serialization.ByteBuf) {
{{~ for field in fields ~}}
{{ts_bin_deserialize ('this.' + field.ts_style_name) '_buf_' field.ctype}}
{{~end~}}
}
toString(): string {
return ""{{full_name}}{ ""
{{~ for field in fields ~}}
+ ""{{field.ts_style_name}}:"" + this.{{field.ts_style_name}} + "",""
{{~end~}}
+ ""}"";
}
}
{{x.typescript_namespace_end}}
");
var result = template.RenderCode(p);
return result;
}
[ThreadStatic]
private static Template t_rpcRender;
private string Render(DefRpc r)
{
var template = t_rpcRender ??= Template.Parse(@"
{{
name = x.name
full_name = x.full_name
parent = x.parent
fields = x.fields
targ_type = x.targ_type
tres_type = x.tres_type
}}
// TODO {{full_name}}
");
var result = template.RenderCode(r);
return result;
}
[ThreadStatic]
private static Template t_stubRender;
public string RenderStubs(string name, string module, List<DefTypeBase> protos, List<DefTypeBase> rpcs)
{
var template = t_stubRender ??= Template.Parse(@"
type ProtocolFactory = () => Protocol
export class {{name}} {
static readonly Factories = new Map<number, ProtocolFactory>([
{{~ for proto in protos ~}}
[{{proto.full_name}}.ID, () => new {{proto.full_name}}()],
{{~end~}}
{{~ for rpc in rpcs ~}}
// TODO RPC .. [{{rpc.full_name}}.ID] = () => new {{rpc.full_name}}(),
{{~end~}}
])
}
");
var result = template.Render(new
{
Name = name,
Namespace = module,
Protos = protos,
Rpcs = rpcs,
});
return result;
}
}
}

View File

@ -1,6 +1,7 @@
using CommandLine;
using Luban.Common.Protos;
using Luban.Common.Utils;
using Luban.Job.Common;
using Luban.Job.Common.Defs;
using Luban.Job.Common.Utils;
using Luban.Job.Proto.Defs;
@ -30,7 +31,7 @@ namespace Luban.Job.Proto
[Option('c', "output_code_dir", Required = true, HelpText = "output code directory")]
public string OutputCodeDir { get; set; }
[Option('g', "gen_type", Required = true, HelpText = "cs,lua,java,cpp")]
[Option('g', "gen_type", Required = true, HelpText = "cs,lua,java,cpp,ts")]
public string GenType { get; set; }
[Option('s', "service", Required = true, HelpText = "service")]
@ -145,6 +146,132 @@ namespace Luban.Job.Proto
}));
break;
}
case "ts":
{
var render = new TypescriptRender();
tasks.Add(Task.Run(() =>
{
var fileContent = new List<string>
{
@$"
import {{Bright}} from 'csharp'
export namespace {ass.TopModule} {{
",
@"
export interface ISerializable {
serialize(_buf_: Bright.Serialization.ByteBuf) : void
deserialize(_buf_: Bright.Serialization.ByteBuf) : void
}
export abstract class BeanBase implements ISerializable {
abstract getTypeId() : number
abstract serialize(_buf_: Bright.Serialization.ByteBuf): void
abstract deserialize(_buf_: Bright.Serialization.ByteBuf): void
}
export abstract class Protocol implements ISerializable {
abstract getTypeId() : number
abstract serialize(_buf_: Bright.Serialization.ByteBuf): void
abstract deserialize(_buf_: Bright.Serialization.ByteBuf): void
}
export class Vector2 {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
to(_buf_: Bright.Serialization.ByteBuf) {
_buf_.WriteFloat(this.x)
_buf_.WriteFloat(this.y)
}
static from(_buf_: Bright.Serialization.ByteBuf): Vector2 {
let x = _buf_.ReadFloat();
let y = _buf_.ReadFloat();
return new Vector2(x, y);
}
}
export class Vector3 {
x: number;
y: number;
z: number;
constructor(x: number, y: number, z: number) {
this.x = x;
this.y = y;
this.z = z;
}
to(_buf_: Bright.Serialization.ByteBuf) {
_buf_.WriteFloat(this.x)
_buf_.WriteFloat(this.y)
_buf_.WriteFloat(this.z)
}
static from(_buf_: Bright.Serialization.ByteBuf): Vector3 {
let x = _buf_.ReadFloat();
let y = _buf_.ReadFloat();
let z = _buf_.ReadFloat();
return new Vector3(x, y, z);
}
}
export class Vector4 {
x: number;
y: number;
z: number;
w: number;
constructor(x: number, y: number, z: number, w: number) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
to(_buf_: Bright.Serialization.ByteBuf) {
_buf_.WriteFloat(this.x)
_buf_.WriteFloat(this.y)
_buf_.WriteFloat(this.z)
_buf_.WriteFloat(this.w)
}
static from(_buf_: Bright.Serialization.ByteBuf): Vector4 {
let x = _buf_.ReadFloat();
let y = _buf_.ReadFloat();
let z = _buf_.ReadFloat();
let w = _buf_.ReadFloat();
return new Vector4(x, y, z, w);
}
}
"
};
foreach (var type in exportTypes)
{
fileContent.Add(render.RenderAny(type));
}
fileContent.Add(render.RenderStubs("ProtocolStub", ass.TopModule, ass.Types.Values.Where(t => t is DefProto).ToList(),
ass.Types.Values.Where(t => t is DefRpc).ToList()));
fileContent.Add("}"); // end of topmodule
var content = FileHeaderUtil.ConcatAutoGenerationHeader(string.Join('\n', fileContent), ELanguage.TYPESCRIPT);
var file = "Types.ts";
var md5 = CacheFileUtil.GenMd5AndAddCache(file, content);
genCodeFiles.Add(new FileInfo() { FilePath = file, MD5 = md5 });
}));
break;
}
default:
{
throw new NotSupportedException($"not support gen type:{genType}");