Files
arpack/generator/ts.go
T

636 lines
24 KiB
Go
Raw Normal View History

2026-03-23 16:04:31 +03:00
package generator
import (
"fmt"
"strings"
"github.com/edmand46/arpack/parser"
)
// GenerateTypeScript generates TypeScript code for the given messages
func GenerateTypeScript(messages []parser.Message, namespace string) ([]byte, error) {
return GenerateTypeScriptSchema(parser.Schema{Messages: messages}, namespace)
}
// GenerateTypeScriptSchema generates TypeScript code from a schema
func GenerateTypeScriptSchema(schema parser.Schema, namespace string) ([]byte, error) {
messages := schema.Messages
var b strings.Builder
b.WriteString("// <auto-generated> arpack </auto-generated>\n")
b.WriteString("// Code generated by arpack. DO NOT EDIT.\n\n")
enumNames := make(map[string]struct{}, len(schema.Enums))
for _, enum := range schema.Enums {
enumNames[enum.Name] = struct{}{}
}
// Generate enums
for _, enum := range schema.Enums {
writeTSEnum(&b, enum)
b.WriteString("\n")
}
// Generate messages
for i, msg := range messages {
if err := writeTSMessage(&b, msg, enumNames); err != nil {
return nil, fmt.Errorf("message %s: %w", msg.Name, err)
}
if i < len(messages)-1 {
b.WriteString("\n")
}
}
return []byte(b.String()), nil
}
func writeTSEnum(b *strings.Builder, enum parser.Enum) {
fmt.Fprintf(b, "export enum %s {\n", enum.Name)
for i, value := range enum.Values {
fmt.Fprintf(b, " %s = %s", value.Name, value.Value)
if i < len(enum.Values)-1 {
b.WriteString(",")
}
b.WriteString("\n")
}
b.WriteString("}\n")
}
func writeTSMessage(b *strings.Builder, msg parser.Message, enumNames map[string]struct{}) error {
segs := segmentFields(msg.Fields)
fmt.Fprintf(b, "export class %s {\n", msg.Name)
// Field declarations with defaults
for _, f := range msg.Fields {
defaultValue := tsDefaultValue(f)
fmt.Fprintf(b, " %s: %s = %s;\n", toCamelCase(f.Name), tsTypeName(f, enumNames), defaultValue)
}
b.WriteString("\n")
// Serialize method
b.WriteString(" serialize(view: DataView, offset: number): number {\n")
b.WriteString(" let pos = offset;\n")
for i, seg := range segs {
if seg.single != nil {
if err := writeTSSerializeField(b, "this", *seg.single, " ", enumNames); err != nil {
return err
}
} else {
writeTSBoolGroupSerialize(b, "this", seg.bools, i, " ")
}
}
b.WriteString(" return pos - offset;\n")
b.WriteString(" }\n\n")
// Deserialize method
fmt.Fprintf(b, " static deserialize(view: DataView, offset: number): [%s, number] {\n", msg.Name)
b.WriteString(" let pos = offset;\n")
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, " const msg = new %s();\n", msg.Name)
2026-03-23 16:04:31 +03:00
for i, seg := range segs {
if seg.single != nil {
if err := writeTSDeserializeField(b, "msg", *seg.single, " ", enumNames); err != nil {
return err
}
} else {
writeTSBoolGroupDeserialize(b, "msg", seg.bools, i, " ")
}
}
b.WriteString(" return [msg, pos - offset];\n")
b.WriteString(" }\n")
b.WriteString("}\n")
return nil
}
func writeTSBoolGroupSerialize(b *strings.Builder, recv string, bools []parser.Field, groupIdx int, indent string) {
varName := fmt.Sprintf("_boolByte%d", groupIdx)
fmt.Fprintf(b, "%slet %s = 0;\n", indent, varName)
for bit, f := range bools {
fmt.Fprintf(b, "%sif (%s.%s) %s |= 1 << %d;\n", indent, recv, toCamelCase(f.Name), varName, bit)
}
fmt.Fprintf(b, "%sview.setUint8(pos, %s);\n", indent, varName)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
}
func writeTSBoolGroupDeserialize(b *strings.Builder, recv string, bools []parser.Field, groupIdx int, indent string) {
varName := fmt.Sprintf("_boolByte%d", groupIdx)
fmt.Fprintf(b, "%sconst %s = view.getUint8(pos);\n", indent, varName)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
for bit, f := range bools {
fmt.Fprintf(b, "%s%s.%s = (%s & (1 << %d)) !== 0;\n", indent, recv, toCamelCase(f.Name), varName, bit)
}
}
func writeTSSerializeField(b *strings.Builder, recv string, f parser.Field, indent string, enumNames map[string]struct{}) error {
access := recv + "." + toCamelCase(f.Name)
switch f.Kind {
case parser.KindPrimitive:
return writeTSSerializePrimitive(b, access, f, indent, enumNames)
case parser.KindNested:
fmt.Fprintf(b, "%spos += %s.serialize(view, pos);\n", indent, access)
case parser.KindFixedArray:
iVar := "_i" + f.Name
fmt.Fprintf(b, "%sfor (let %s = 0; %s < %d; %s++) {\n",
indent, iVar, iVar, f.FixedLen, iVar)
elemField := parser.Field{
Name: f.Name + "[" + iVar + "]",
Kind: f.Elem.Kind,
Primitive: f.Elem.Primitive,
NamedType: f.Elem.NamedType,
Quant: f.Elem.Quant,
TypeName: f.Elem.TypeName,
Elem: f.Elem.Elem,
FixedLen: f.Elem.FixedLen,
}
if err := writeTSSerializeField(b, recv, elemField, indent+" ", enumNames); err != nil {
return err
}
fmt.Fprintf(b, "%s}\n", indent)
case parser.KindSlice:
fmt.Fprintf(b, "%sview.setUint16(pos, %s.length, true);\n", indent, access)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
iVar := "_i" + f.Name
fmt.Fprintf(b, "%sfor (const %s of %s) {\n", indent, iVar, access)
elemField := parser.Field{
Name: iVar,
Kind: f.Elem.Kind,
Primitive: f.Elem.Primitive,
NamedType: f.Elem.NamedType,
Quant: f.Elem.Quant,
TypeName: f.Elem.TypeName,
Elem: f.Elem.Elem,
FixedLen: f.Elem.FixedLen,
}
if err := writeTSSerializeFieldElement(b, iVar, elemField, indent+" ", enumNames); err != nil {
return err
}
fmt.Fprintf(b, "%s}\n", indent)
}
return nil
}
func writeTSSerializeFieldElement(b *strings.Builder, access string, f parser.Field, indent string, enumNames map[string]struct{}) error {
switch f.Kind {
case parser.KindPrimitive:
return writeTSSerializePrimitiveElement(b, access, f, indent, enumNames)
case parser.KindNested:
fmt.Fprintf(b, "%spos += %s.serialize(view, pos);\n", indent, access)
}
return nil
}
func writeTSSerializePrimitiveElement(b *strings.Builder, access string, f parser.Field, indent string, enumNames map[string]struct{}) error {
if f.Quant != nil {
return writeTSSerializeQuantElement(b, access, f, indent)
}
valueExpr := tsSerializeValueExpr(access, f, enumNames)
switch f.Primitive {
case parser.KindFloat32:
fmt.Fprintf(b, "%sview.setFloat32(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 4;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindFloat64:
fmt.Fprintf(b, "%sview.setFloat64(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 8;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt8:
fmt.Fprintf(b, "%sview.setInt8(pos, %s);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint8:
fmt.Fprintf(b, "%sview.setUint8(pos, %s);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindBool:
fmt.Fprintf(b, "%sview.setUint8(pos, %s ? 1 : 0);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt16:
fmt.Fprintf(b, "%sview.setInt16(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint16:
fmt.Fprintf(b, "%sview.setUint16(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt32:
fmt.Fprintf(b, "%sview.setInt32(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 4;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint32:
fmt.Fprintf(b, "%sview.setUint32(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 4;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt64:
fmt.Fprintf(b, "%sview.setBigInt64(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 8;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint64:
fmt.Fprintf(b, "%sview.setBigUint64(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 8;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindString:
lenVar := "_slen" + sanitizeVarName(access)
fmt.Fprintf(b, "%sconst %s = new TextEncoder().encode(%s);\n", indent, lenVar, valueExpr)
fmt.Fprintf(b, "%sview.setUint16(pos, %s.length, true);\n", indent, lenVar)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%snew Uint8Array(view.buffer, pos, %s.length).set(%s);\n", indent, lenVar, lenVar)
fmt.Fprintf(b, "%spos += %s.length;\n", indent, lenVar)
}
return nil
}
func writeTSSerializePrimitive(b *strings.Builder, access string, f parser.Field, indent string, enumNames map[string]struct{}) error {
if f.Quant != nil {
return writeTSSerializeQuant(b, access, f, indent)
}
valueExpr := tsSerializeValueExpr(access, f, enumNames)
switch f.Primitive {
case parser.KindFloat32:
fmt.Fprintf(b, "%sview.setFloat32(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 4;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindFloat64:
fmt.Fprintf(b, "%sview.setFloat64(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 8;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt8:
fmt.Fprintf(b, "%sview.setInt8(pos, %s);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint8:
fmt.Fprintf(b, "%sview.setUint8(pos, %s);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindBool:
fmt.Fprintf(b, "%sview.setUint8(pos, %s ? 1 : 0);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt16:
fmt.Fprintf(b, "%sview.setInt16(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint16:
fmt.Fprintf(b, "%sview.setUint16(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt32:
fmt.Fprintf(b, "%sview.setInt32(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 4;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint32:
fmt.Fprintf(b, "%sview.setUint32(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 4;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt64:
fmt.Fprintf(b, "%sview.setBigInt64(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 8;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint64:
fmt.Fprintf(b, "%sview.setBigUint64(pos, %s, true);\n", indent, valueExpr)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 8;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindString:
lenVar := "_slen" + sanitizeVarName(access)
fmt.Fprintf(b, "%sconst %s = new TextEncoder().encode(%s);\n", indent, lenVar, valueExpr)
fmt.Fprintf(b, "%sview.setUint16(pos, %s.length, true);\n", indent, lenVar)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%snew Uint8Array(view.buffer, pos, %s.length).set(%s);\n", indent, lenVar, lenVar)
fmt.Fprintf(b, "%spos += %s.length;\n", indent, lenVar)
}
return nil
}
func writeTSSerializeQuant(b *strings.Builder, access string, f parser.Field, indent string) error {
q := f.Quant
maxUint := q.MaxUint()
varName := "_q" + sanitizeVarName(access)
if q.Bits == 8 {
fmt.Fprintf(b, "%sconst %s = Math.round((%s - (%g)) / (%g - (%g)) * %g);\n",
indent, varName, access, q.Min, q.Max, q.Min, maxUint)
fmt.Fprintf(b, "%sview.setUint8(pos, %s);\n", indent, varName)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
} else {
fmt.Fprintf(b, "%sconst %s = Math.round((%s - (%g)) / (%g - (%g)) * %g);\n",
indent, varName, access, q.Min, q.Max, q.Min, maxUint)
fmt.Fprintf(b, "%sview.setUint16(pos, %s, true);\n", indent, varName)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
}
return nil
}
func writeTSSerializeQuantElement(b *strings.Builder, access string, f parser.Field, indent string) error {
q := f.Quant
maxUint := q.MaxUint()
varName := "_q" + sanitizeVarName(access)
if q.Bits == 8 {
fmt.Fprintf(b, "%sconst %s = Math.round((%s - (%g)) / (%g - (%g)) * %g);\n",
indent, varName, access, q.Min, q.Max, q.Min, maxUint)
fmt.Fprintf(b, "%sview.setUint8(pos, %s);\n", indent, varName)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
} else {
fmt.Fprintf(b, "%sconst %s = Math.round((%s - (%g)) / (%g - (%g)) * %g);\n",
indent, varName, access, q.Min, q.Max, q.Min, maxUint)
fmt.Fprintf(b, "%sview.setUint16(pos, %s, true);\n", indent, varName)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
}
return nil
}
func writeTSDeserializeField(b *strings.Builder, recv string, f parser.Field, indent string, enumNames map[string]struct{}) error {
access := recv + "." + toCamelCase(f.Name)
switch f.Kind {
case parser.KindPrimitive:
return writeTSDeserializePrimitive(b, access, f, indent, enumNames)
case parser.KindNested:
fmt.Fprintf(b, "%sconst [_%s, _n%s] = %s.deserialize(view, pos);\n", indent, f.Name, f.Name, f.TypeName)
fmt.Fprintf(b, "%s%s = _%s;\n", indent, access, f.Name)
fmt.Fprintf(b, "%spos += _n%s;\n", indent, f.Name)
case parser.KindFixedArray:
iVar := "_i" + f.Name
fmt.Fprintf(b, "%s%s = new Array(%d);\n", indent, access, f.FixedLen)
fmt.Fprintf(b, "%sfor (let %s = 0; %s < %d; %s++) {\n",
indent, iVar, iVar, f.FixedLen, iVar)
elemField := parser.Field{
Name: f.Name + "[" + iVar + "]",
Kind: f.Elem.Kind,
Primitive: f.Elem.Primitive,
NamedType: f.Elem.NamedType,
Quant: f.Elem.Quant,
TypeName: f.Elem.TypeName,
Elem: f.Elem.Elem,
FixedLen: f.Elem.FixedLen,
}
if err := writeTSDeserializeField(b, recv, elemField, indent+" ", enumNames); err != nil {
return err
}
fmt.Fprintf(b, "%s}\n", indent)
case parser.KindSlice:
lenVar := "_len" + f.Name
fmt.Fprintf(b, "%sconst %s = view.getUint16(pos, true);\n", indent, lenVar)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = new Array(%s);\n", indent, access, lenVar)
iVar := "_i" + f.Name
fmt.Fprintf(b, "%sfor (let %s = 0; %s < %s; %s++) {\n", indent, iVar, iVar, lenVar, iVar)
elemField := parser.Field{
Name: f.Name + "[" + iVar + "]",
Kind: f.Elem.Kind,
Primitive: f.Elem.Primitive,
NamedType: f.Elem.NamedType,
Quant: f.Elem.Quant,
TypeName: f.Elem.TypeName,
Elem: f.Elem.Elem,
FixedLen: f.Elem.FixedLen,
}
if err := writeTSDeserializeFieldElement(b, recv, elemField, indent+" ", enumNames); err != nil {
return err
}
fmt.Fprintf(b, "%s}\n", indent)
}
return nil
}
func writeTSDeserializeFieldElement(b *strings.Builder, recv string, f parser.Field, indent string, enumNames map[string]struct{}) error {
access := recv + "." + toCamelCase(f.Name)
switch f.Kind {
case parser.KindPrimitive:
return writeTSDeserializePrimitiveElement(b, access, f, indent, enumNames)
case parser.KindNested:
fmt.Fprintf(b, "%sconst [_elem, _nElem] = %s.deserialize(view, pos);\n", indent, f.TypeName)
fmt.Fprintf(b, "%s%s = _elem;\n", indent, access)
fmt.Fprintf(b, "%spos += _nElem;\n", indent)
}
return nil
}
func writeTSDeserializePrimitiveElement(b *strings.Builder, access string, f parser.Field, indent string, enumNames map[string]struct{}) error {
if f.Quant != nil {
return writeTSDeserializeQuantElement(b, access, f, indent)
}
switch f.Primitive {
case parser.KindFloat32:
2026-03-23 16:19:17 +03:00
expr := "view.getFloat32(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 4;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindFloat64:
2026-03-23 16:19:17 +03:00
expr := "view.getFloat64(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 8;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt8:
2026-03-23 16:19:17 +03:00
expr := "view.getInt8(pos)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint8:
2026-03-23 16:19:17 +03:00
expr := "view.getUint8(pos)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindBool:
2026-03-23 16:19:17 +03:00
expr := "view.getUint8(pos) !== 0"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt16:
2026-03-23 16:19:17 +03:00
expr := "view.getInt16(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint16:
2026-03-23 16:19:17 +03:00
expr := "view.getUint16(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt32:
2026-03-23 16:19:17 +03:00
expr := "view.getInt32(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 4;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint32:
2026-03-23 16:19:17 +03:00
expr := "view.getUint32(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 4;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt64:
2026-03-23 16:19:17 +03:00
expr := "view.getBigInt64(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 8;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint64:
2026-03-23 16:19:17 +03:00
expr := "view.getBigUint64(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 8;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindString:
lenVar := "_slen" + sanitizeVarName(access)
fmt.Fprintf(b, "%sconst %s = view.getUint16(pos, true);\n", indent, lenVar)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
expr := fmt.Sprintf("new TextDecoder().decode(new Uint8Array(view.buffer, pos, %s))", lenVar)
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
fmt.Fprintf(b, "%spos += %s;\n", indent, lenVar)
}
return nil
}
func writeTSDeserializePrimitive(b *strings.Builder, access string, f parser.Field, indent string, enumNames map[string]struct{}) error {
if f.Quant != nil {
return writeTSDeserializeQuant(b, access, f, indent)
}
switch f.Primitive {
case parser.KindFloat32:
2026-03-23 16:19:17 +03:00
expr := "view.getFloat32(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 4;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindFloat64:
2026-03-23 16:19:17 +03:00
expr := "view.getFloat64(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 8;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt8:
2026-03-23 16:19:17 +03:00
expr := "view.getInt8(pos)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint8:
2026-03-23 16:19:17 +03:00
expr := "view.getUint8(pos)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindBool:
2026-03-23 16:19:17 +03:00
expr := "view.getUint8(pos) !== 0"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt16:
2026-03-23 16:19:17 +03:00
expr := "view.getInt16(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint16:
2026-03-23 16:19:17 +03:00
expr := "view.getUint16(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt32:
2026-03-23 16:19:17 +03:00
expr := "view.getInt32(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 4;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint32:
2026-03-23 16:19:17 +03:00
expr := "view.getUint32(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 4;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindInt64:
2026-03-23 16:19:17 +03:00
expr := "view.getBigInt64(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 8;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindUint64:
2026-03-23 16:19:17 +03:00
expr := "view.getBigUint64(pos, true)"
2026-03-23 16:04:31 +03:00
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 8;\n", indent)
2026-03-23 16:04:31 +03:00
case parser.KindString:
lenVar := "_slen" + sanitizeVarName(access)
fmt.Fprintf(b, "%sconst %s = view.getUint16(pos, true);\n", indent, lenVar)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
expr := fmt.Sprintf("new TextDecoder().decode(new Uint8Array(view.buffer, pos, %s))", lenVar)
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames))
fmt.Fprintf(b, "%spos += %s;\n", indent, lenVar)
}
return nil
}
func writeTSDeserializeQuant(b *strings.Builder, access string, f parser.Field, indent string) error {
q := f.Quant
maxUint := q.MaxUint()
varName := "_q" + sanitizeVarName(access)
if q.Bits == 8 {
fmt.Fprintf(b, "%sconst %s = view.getUint8(pos);\n", indent, varName)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
expr := fmt.Sprintf("%s / %g * (%g - (%g)) + (%g)", varName, maxUint, q.Max, q.Min, q.Min)
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, nil))
} else {
fmt.Fprintf(b, "%sconst %s = view.getUint16(pos, true);\n", indent, varName)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
expr := fmt.Sprintf("%s / %g * (%g - (%g)) + (%g)", varName, maxUint, q.Max, q.Min, q.Min)
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, nil))
}
return nil
}
func writeTSDeserializeQuantElement(b *strings.Builder, access string, f parser.Field, indent string) error {
q := f.Quant
maxUint := q.MaxUint()
varName := "_q" + sanitizeVarName(access)
if q.Bits == 8 {
fmt.Fprintf(b, "%sconst %s = view.getUint8(pos);\n", indent, varName)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 1;\n", indent)
2026-03-23 16:04:31 +03:00
expr := fmt.Sprintf("%s / %g * (%g - (%g)) + (%g)", varName, maxUint, q.Max, q.Min, q.Min)
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, nil))
} else {
fmt.Fprintf(b, "%sconst %s = view.getUint16(pos, true);\n", indent, varName)
2026-03-23 16:19:17 +03:00
fmt.Fprintf(b, "%spos += 2;\n", indent)
2026-03-23 16:04:31 +03:00
expr := fmt.Sprintf("%s / %g * (%g - (%g)) + (%g)", varName, maxUint, q.Max, q.Min, q.Min)
fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, nil))
}
return nil
}
func tsTypeName(f parser.Field, enumNames map[string]struct{}) string {
switch f.Kind {
case parser.KindPrimitive:
if tsIsEnumType(f, enumNames) {
return f.NamedType
}
return tsPrimitiveTypeName(f.Primitive)
case parser.KindNested:
return f.TypeName
case parser.KindFixedArray, parser.KindSlice:
return tsTypeName(*f.Elem, enumNames) + "[]"
}
return "unknown"
}
func tsPrimitiveTypeName(k parser.PrimitiveKind) string {
switch k {
case parser.KindFloat32, parser.KindFloat64:
return "number"
case parser.KindInt8, parser.KindInt16, parser.KindInt32, parser.KindUint8, parser.KindUint16, parser.KindUint32:
return "number"
case parser.KindInt64, parser.KindUint64:
return "bigint"
case parser.KindBool:
return "boolean"
case parser.KindString:
return "string"
}
return "unknown"
}
func tsDefaultValue(f parser.Field) string {
switch f.Kind {
case parser.KindPrimitive:
if tsIsEnumType(f, nil) {
return "0"
}
switch f.Primitive {
case parser.KindFloat32, parser.KindFloat64, parser.KindInt8, parser.KindInt16, parser.KindInt32,
parser.KindUint8, parser.KindUint16, parser.KindUint32:
return "0"
case parser.KindInt64, parser.KindUint64:
return "0n"
case parser.KindBool:
return "false"
case parser.KindString:
return `""`
}
case parser.KindNested:
return fmt.Sprintf("new %s()", f.TypeName)
case parser.KindFixedArray:
elemDefault := tsDefaultValue(*f.Elem)
elemType := tsTypeName(*f.Elem, nil)
return fmt.Sprintf("new Array<%s>(%d).fill(%s)", elemType, f.FixedLen, elemDefault)
case parser.KindSlice:
return "[]"
}
return "undefined"
}
func tsSerializeValueExpr(access string, f parser.Field, enumNames map[string]struct{}) string {
if !tsIsEnumType(f, enumNames) {
return access
}
return access + " as " + tsPrimitiveTypeName(f.Primitive)
}
func tsDeserializeValueExpr(expr string, f parser.Field, enumNames map[string]struct{}) string {
if !tsIsEnumType(f, enumNames) {
return expr
}
return "(" + expr + " as " + f.NamedType + ")"
}
func tsIsEnumType(f parser.Field, enumNames map[string]struct{}) bool {
if f.NamedType == "" || enumNames == nil {
return false
}
_, ok := enumNames[f.NamedType]
return ok
}
// toCamelCase converts PascalCase to camelCase (e.g., EntityID -> entityID)
func toCamelCase(s string) string {
if s == "" {
return ""
}
// First character to lowercase
result := strings.ToLower(s[:1]) + s[1:]
return result
}