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("// arpack \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") fmt.Fprintf(b, " const msg = new %s();\n", msg.Name) 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) fmt.Fprintf(b, "%spos += 1;\n", indent) } 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) fmt.Fprintf(b, "%spos += 1;\n", indent) 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) fmt.Fprintf(b, "%spos += 2;\n", indent) 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) fmt.Fprintf(b, "%spos += 4;\n", indent) case parser.KindFloat64: fmt.Fprintf(b, "%sview.setFloat64(pos, %s, true);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 8;\n", indent) case parser.KindInt8: fmt.Fprintf(b, "%sview.setInt8(pos, %s);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 1;\n", indent) case parser.KindUint8: fmt.Fprintf(b, "%sview.setUint8(pos, %s);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 1;\n", indent) case parser.KindBool: fmt.Fprintf(b, "%sview.setUint8(pos, %s ? 1 : 0);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 1;\n", indent) case parser.KindInt16: fmt.Fprintf(b, "%sview.setInt16(pos, %s, true);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 2;\n", indent) case parser.KindUint16: fmt.Fprintf(b, "%sview.setUint16(pos, %s, true);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 2;\n", indent) case parser.KindInt32: fmt.Fprintf(b, "%sview.setInt32(pos, %s, true);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 4;\n", indent) case parser.KindUint32: fmt.Fprintf(b, "%sview.setUint32(pos, %s, true);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 4;\n", indent) case parser.KindInt64: fmt.Fprintf(b, "%sview.setBigInt64(pos, %s, true);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 8;\n", indent) case parser.KindUint64: fmt.Fprintf(b, "%sview.setBigUint64(pos, %s, true);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 8;\n", indent) 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) fmt.Fprintf(b, "%spos += 2;\n", indent) 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) fmt.Fprintf(b, "%spos += 4;\n", indent) case parser.KindFloat64: fmt.Fprintf(b, "%sview.setFloat64(pos, %s, true);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 8;\n", indent) case parser.KindInt8: fmt.Fprintf(b, "%sview.setInt8(pos, %s);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 1;\n", indent) case parser.KindUint8: fmt.Fprintf(b, "%sview.setUint8(pos, %s);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 1;\n", indent) case parser.KindBool: fmt.Fprintf(b, "%sview.setUint8(pos, %s ? 1 : 0);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 1;\n", indent) case parser.KindInt16: fmt.Fprintf(b, "%sview.setInt16(pos, %s, true);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 2;\n", indent) case parser.KindUint16: fmt.Fprintf(b, "%sview.setUint16(pos, %s, true);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 2;\n", indent) case parser.KindInt32: fmt.Fprintf(b, "%sview.setInt32(pos, %s, true);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 4;\n", indent) case parser.KindUint32: fmt.Fprintf(b, "%sview.setUint32(pos, %s, true);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 4;\n", indent) case parser.KindInt64: fmt.Fprintf(b, "%sview.setBigInt64(pos, %s, true);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 8;\n", indent) case parser.KindUint64: fmt.Fprintf(b, "%sview.setBigUint64(pos, %s, true);\n", indent, valueExpr) fmt.Fprintf(b, "%spos += 8;\n", indent) 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) fmt.Fprintf(b, "%spos += 2;\n", indent) 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) fmt.Fprintf(b, "%spos += 1;\n", indent) } 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) fmt.Fprintf(b, "%spos += 2;\n", indent) } 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) fmt.Fprintf(b, "%spos += 1;\n", indent) } 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) fmt.Fprintf(b, "%spos += 2;\n", indent) } 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) fmt.Fprintf(b, "%spos += 2;\n", indent) 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: expr := "view.getFloat32(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 4;\n", indent) case parser.KindFloat64: expr := "view.getFloat64(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 8;\n", indent) case parser.KindInt8: expr := "view.getInt8(pos)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 1;\n", indent) case parser.KindUint8: expr := "view.getUint8(pos)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 1;\n", indent) case parser.KindBool: expr := "view.getUint8(pos) !== 0" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 1;\n", indent) case parser.KindInt16: expr := "view.getInt16(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 2;\n", indent) case parser.KindUint16: expr := "view.getUint16(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 2;\n", indent) case parser.KindInt32: expr := "view.getInt32(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 4;\n", indent) case parser.KindUint32: expr := "view.getUint32(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 4;\n", indent) case parser.KindInt64: expr := "view.getBigInt64(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 8;\n", indent) case parser.KindUint64: expr := "view.getBigUint64(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 8;\n", indent) case parser.KindString: lenVar := "_slen" + sanitizeVarName(access) fmt.Fprintf(b, "%sconst %s = view.getUint16(pos, true);\n", indent, lenVar) fmt.Fprintf(b, "%spos += 2;\n", indent) 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: expr := "view.getFloat32(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 4;\n", indent) case parser.KindFloat64: expr := "view.getFloat64(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 8;\n", indent) case parser.KindInt8: expr := "view.getInt8(pos)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 1;\n", indent) case parser.KindUint8: expr := "view.getUint8(pos)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 1;\n", indent) case parser.KindBool: expr := "view.getUint8(pos) !== 0" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 1;\n", indent) case parser.KindInt16: expr := "view.getInt16(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 2;\n", indent) case parser.KindUint16: expr := "view.getUint16(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 2;\n", indent) case parser.KindInt32: expr := "view.getInt32(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 4;\n", indent) case parser.KindUint32: expr := "view.getUint32(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 4;\n", indent) case parser.KindInt64: expr := "view.getBigInt64(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 8;\n", indent) case parser.KindUint64: expr := "view.getBigUint64(pos, true)" fmt.Fprintf(b, "%s%s = %s;\n", indent, access, tsDeserializeValueExpr(expr, f, enumNames)) fmt.Fprintf(b, "%spos += 8;\n", indent) case parser.KindString: lenVar := "_slen" + sanitizeVarName(access) fmt.Fprintf(b, "%sconst %s = view.getUint16(pos, true);\n", indent, lenVar) fmt.Fprintf(b, "%spos += 2;\n", indent) 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) fmt.Fprintf(b, "%spos += 1;\n", indent) 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) fmt.Fprintf(b, "%spos += 2;\n", indent) 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) fmt.Fprintf(b, "%spos += 1;\n", indent) 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) fmt.Fprintf(b, "%spos += 2;\n", indent) 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 }