struct-frame 0.0.29__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env python3
2
+ # Simple GraphQL schema generator for struct-frame
3
+
4
+ from struct_frame import version, pascalCase, CamelToSnakeCase
5
+ import time
6
+
7
+ # Mapping from proto primitive types to GraphQL scalar types
8
+ gql_types = {
9
+ "uint8": "Int",
10
+ "int8": "Int",
11
+ "uint16": "Int",
12
+ "int16": "Int",
13
+ "uint32": "Int",
14
+ "int32": "Int",
15
+ "uint64": "Int", # Could be custom scalar if needed
16
+ "int64": "Int", # Could be custom scalar if needed
17
+ "bool": "Boolean",
18
+ "float": "Float",
19
+ "double": "Float",
20
+ "string": "String",
21
+ }
22
+
23
+
24
+ def _gql_enum_value_name(name: str) -> str:
25
+ # If already in ALL_CAPS (possibly with underscores) keep as is
26
+ if name.replace('_', '').isupper():
27
+ return name
28
+ return CamelToSnakeCase(name).upper()
29
+
30
+
31
+ def _clean_comment_line(c: str) -> str:
32
+ c = c.strip()
33
+ if c.startswith('#'):
34
+ c = c[1:].strip()
35
+ # Remove leading // once or twice
36
+ if c.startswith('//'):
37
+ c = c[2:].strip()
38
+ # If parser already kept leading markers inside line, remove repeated
39
+ if c.startswith('//'):
40
+ c = c[2:].strip()
41
+ return c
42
+
43
+
44
+ def _triple_quote_block(lines):
45
+ cleaned = [_clean_comment_line(l) for l in lines if _clean_comment_line(l)]
46
+ if not cleaned:
47
+ return None
48
+ return '"""\n' + '\n'.join(cleaned) + '\n"""'
49
+
50
+
51
+ def _single_quote_line(lines):
52
+ cleaned = [_clean_comment_line(l) for l in lines if _clean_comment_line(l)]
53
+ if not cleaned:
54
+ return None
55
+ # Join multi-line into one sentence for single-line description
56
+ return '"' + ' '.join(cleaned) + '"'
57
+
58
+
59
+ class EnumGqlGen:
60
+ @staticmethod
61
+ def generate(enum):
62
+ lines = []
63
+ if enum.comments:
64
+ desc = _triple_quote_block(enum.comments)
65
+ if desc:
66
+ lines.append(desc)
67
+ enum_name = f"{pascalCase(enum.package)}{enum.name}"
68
+ lines.append(f"enum {enum_name} {{")
69
+ for key, value in enum.data.items():
70
+ if value[1]:
71
+ desc = _single_quote_line(value[1])
72
+ if desc:
73
+ lines.append(f" {desc}")
74
+ lines.append(f" {_gql_enum_value_name(key)}")
75
+ lines.append("}\n")
76
+ return '\n'.join(lines)
77
+
78
+
79
+ class FieldGqlGen:
80
+ @staticmethod
81
+ def type_name(field):
82
+ t = field.fieldType
83
+ base_type = gql_types.get(t, f"{pascalCase(field.package)}{t}")
84
+
85
+ # Handle arrays
86
+ if getattr(field, 'is_array', False):
87
+ # Arrays in GraphQL are represented as [Type!]! for non-null arrays of non-null elements
88
+ # or [Type] for nullable arrays, etc. We'll use [Type!]! as the standard
89
+ return f"[{base_type}!]!"
90
+
91
+ return base_type
92
+
93
+ @staticmethod
94
+ def generate(field, name_override=None):
95
+ lines = []
96
+
97
+ # Generate clean comments with size information, preferring our generated descriptions over proto comments
98
+ if getattr(field, 'is_array', False):
99
+ # Array field - use our size descriptions
100
+ if getattr(field, 'size_option', None) is not None:
101
+ # Fixed array
102
+ if field.fieldType == "string":
103
+ comment_lines = [
104
+ f"Fixed string array: {field.size_option} strings, each {getattr(field, 'element_size', 'N/A')} chars"]
105
+ else:
106
+ comment_lines = [
107
+ f"Fixed array: always {field.size_option} elements"]
108
+ else:
109
+ # Variable array
110
+ if field.fieldType == "string":
111
+ comment_lines = [
112
+ f"Variable string array: up to {getattr(field, 'max_size', 'N/A')} strings, each max {getattr(field, 'element_size', 'N/A')} chars"]
113
+ else:
114
+ comment_lines = [
115
+ f"Variable array: up to {getattr(field, 'max_size', 'N/A')} elements"]
116
+ elif field.fieldType == "string":
117
+ # Non-array string field
118
+ if getattr(field, 'size_option', None) is not None:
119
+ comment_lines = [
120
+ f"Fixed string: exactly {field.size_option} characters"]
121
+ elif getattr(field, 'max_size', None) is not None:
122
+ comment_lines = [
123
+ f"Variable string: up to {field.max_size} characters"]
124
+ else:
125
+ comment_lines = field.comments[:] if field.comments else []
126
+ else:
127
+ # Regular field - use original comments
128
+ comment_lines = field.comments[:] if field.comments else []
129
+
130
+ if comment_lines:
131
+ desc = _single_quote_line(comment_lines)
132
+ if desc:
133
+ lines.append(f" {desc}")
134
+
135
+ fname = name_override if name_override else field.name
136
+ lines.append(f" {fname}: {FieldGqlGen.type_name(field)}")
137
+ return '\n'.join(lines)
138
+
139
+ @staticmethod
140
+ def generate_flattened_children(field, package, parent_msg):
141
+ # Expand a message-typed field into its child fields.
142
+ # If a child field name collides, raise an error and fail generation.
143
+ t = field.fieldType
144
+ child_msg = package.messages.get(t)
145
+ if not child_msg:
146
+ # Fallback to normal generation if unknown
147
+ return [FieldGqlGen.generate(field)]
148
+
149
+ out_lines = []
150
+ for ck, cf in child_msg.fields.items():
151
+ out_lines.append(FieldGqlGen.generate(cf, name_override=ck))
152
+ return out_lines
153
+
154
+
155
+ class MessageGqlGen:
156
+ @staticmethod
157
+ def generate(package, msg):
158
+ lines = []
159
+ if msg.comments:
160
+ desc = _triple_quote_block(msg.comments)
161
+ if desc:
162
+ lines.append(desc)
163
+ type_name = f"{pascalCase(msg.package)}{msg.name}"
164
+ lines.append(f"type {type_name} {{")
165
+ if not msg.fields:
166
+ lines.append(" _empty: Boolean")
167
+ else:
168
+ for key, f in msg.fields.items():
169
+ if getattr(f, 'flatten', False) and f.fieldType not in gql_types:
170
+ lines.extend(
171
+ FieldGqlGen.generate_flattened_children(f, package, msg))
172
+ else:
173
+ lines.append(FieldGqlGen.generate(f))
174
+ lines.append("}\n")
175
+ return '\n'.join(lines)
176
+
177
+
178
+ class FileGqlGen:
179
+ @staticmethod
180
+ def generate(package):
181
+ # Multiline triple-quoted header block
182
+ yield f"# Automatically generated GraphQL schema\n# Generated by struct-frame {version} at {time.asctime()}\n\n"
183
+
184
+ first_block = True
185
+ # Enums
186
+ for _, enum in package.enums.items():
187
+ if not first_block:
188
+ yield '\n'
189
+ first_block = False
190
+ yield EnumGqlGen.generate(enum).rstrip() + '\n'
191
+
192
+ # Messages (object types)
193
+ for _, msg in package.sortedMessages().items():
194
+ if not first_block:
195
+ yield '\n'
196
+ first_block = False
197
+ yield MessageGqlGen.generate(package, msg).rstrip() + '\n'
198
+
199
+ # Root Query type
200
+ if package.messages:
201
+ if not first_block:
202
+ yield '\n'
203
+ yield 'type Query {\n'
204
+ for _, msg in package.sortedMessages().items():
205
+ type_name = f"{pascalCase(msg.package)}{msg.name}"
206
+ yield f" {msg.name}: {type_name}\n"
207
+ yield '}\n'
struct_frame/py_gen.py ADDED
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env python3
2
+ # kate: replace-tabs on; indent-width 4;
3
+
4
+ from struct_frame import version, NamingStyleC, CamelToSnakeCase, pascalCase
5
+ import time
6
+
7
+ StyleC = NamingStyleC()
8
+
9
+ py_types = {"uint8": "uint8",
10
+ "int8": "int8",
11
+ "uint16": "uint16",
12
+ "int16": "int16",
13
+ "uint32": "uint32",
14
+ "int32": "int32",
15
+ "bool": "bool8",
16
+ "float": "float32",
17
+ "double": "float64",
18
+ "uint64": 'uint64',
19
+ "int64": 'int64',
20
+ "string": "str", # Add string type support
21
+ }
22
+
23
+
24
+ class EnumPyGen():
25
+ @staticmethod
26
+ def generate(field):
27
+ leading_comment = field.comments
28
+
29
+ result = ''
30
+ if leading_comment:
31
+ for c in leading_comment:
32
+ result = '#%s\n' % c
33
+
34
+ enumName = '%s%s' % (pascalCase(field.package), field.name)
35
+ result += 'class %s(Enum):\n' % (enumName)
36
+
37
+ enum_length = len(field.data)
38
+ enum_values = []
39
+ for index, (d) in enumerate(field.data):
40
+ leading_comment = field.data[d][1]
41
+
42
+ if leading_comment:
43
+ for c in leading_comment:
44
+ enum_values.append("#" + c)
45
+
46
+ enum_value = " %s_%s = %d" % (CamelToSnakeCase(
47
+ field.name).upper(), StyleC.enum_entry(d), field.data[d][0])
48
+
49
+ enum_values.append(enum_value)
50
+
51
+ result += '\n'.join(enum_values)
52
+ return result
53
+
54
+
55
+ class FieldPyGen():
56
+ @staticmethod
57
+ def generate(field):
58
+ result = ''
59
+
60
+ var_name = field.name
61
+ type_name = field.fieldType
62
+
63
+ # Handle basic type resolution
64
+ if type_name in py_types:
65
+ base_type = py_types[type_name]
66
+ else:
67
+ if field.isEnum:
68
+ # For enums, use the full enum class name for better type safety
69
+ base_type = '%s%s' % (pascalCase(field.package), type_name)
70
+ else:
71
+ base_type = '%s%s' % (pascalCase(field.package), type_name)
72
+
73
+ # Handle arrays
74
+ if field.is_array:
75
+ if field.fieldType == "string":
76
+ # String arrays require both array size and individual element size
77
+ if field.size_option is not None:
78
+ type_annotation = f"list[{base_type}] # Fixed string array size={field.size_option}, each max {field.element_size} chars"
79
+ elif field.max_size is not None:
80
+ type_annotation = f"list[{base_type}] # Bounded string array max_size={field.max_size}, each max {field.element_size} chars"
81
+ else:
82
+ type_annotation = f"list[{base_type}] # String array"
83
+ else:
84
+ # Non-string arrays
85
+ if field.size_option is not None:
86
+ type_annotation = f"list[{base_type}] # Fixed array size={field.size_option}"
87
+ elif field.max_size is not None:
88
+ type_annotation = f"list[{base_type}] # Bounded array max_size={field.max_size}"
89
+ else:
90
+ type_annotation = f"list[{base_type}] # Array"
91
+ # Handle strings with size info
92
+ elif field.fieldType == "string":
93
+ if field.size_option is not None:
94
+ # Fixed string - exact length
95
+ type_annotation = f"str # Fixed string size={field.size_option}"
96
+ elif field.max_size is not None:
97
+ # Variable string - up to max length
98
+ type_annotation = f"str # Variable string max_size={field.max_size}"
99
+ else:
100
+ # Fallback (shouldn't happen with validation)
101
+ type_annotation = "str # String"
102
+ else:
103
+ # Regular field
104
+ type_annotation = base_type
105
+
106
+ result += ' %s: %s' % (var_name, type_annotation)
107
+
108
+ leading_comment = field.comments
109
+ if leading_comment:
110
+ for c in leading_comment:
111
+ result = "#" + c + "\n" + result
112
+
113
+ return result
114
+
115
+
116
+ class MessagePyGen():
117
+ @staticmethod
118
+ def generate(msg):
119
+ leading_comment = msg.comments
120
+
121
+ result = ''
122
+ if leading_comment:
123
+ for c in msg.comments:
124
+ result = '#%s\n' % c
125
+
126
+ structName = '%s%s' % (pascalCase(msg.package), msg.name)
127
+ result += 'class %s(Structured, byte_order=ByteOrder.LE, byte_order_mode=ByteOrderMode.OVERRIDE):\n' % structName
128
+ result += ' msg_size = %s\n' % msg.size
129
+ if msg.id != None:
130
+ result += ' msg_id = %s\n' % msg.id
131
+
132
+ result += '\n'.join([FieldPyGen.generate(f)
133
+ for key, f in msg.fields.items()])
134
+
135
+ result += '\n\n def __str__(self):\n'
136
+ result += f' out = "{msg.name} Msg, ID {msg.id}, Size {msg.size} \\n"\n'
137
+ for key, f in msg.fields.items():
138
+ result += f' out += f"{key} = '
139
+ result += '{self.' + key + '}\\n"\n'
140
+ result += f' out += "\\n"\n'
141
+ result += f' return out'
142
+
143
+ result += '\n\n def to_dict(self, include_name = True, include_id = True):\n'
144
+ result += ' out = {}\n'
145
+ # Handle all field types including arrays
146
+ for key, f in msg.fields.items():
147
+ if f.is_array:
148
+ if f.isDefaultType or f.isEnum or f.fieldType == "string":
149
+ # Array of primitives, enums, or strings
150
+ result += f' out["{key}"] = self.{key}\n'
151
+ else:
152
+ # Array of nested messages - convert each element
153
+ result += f' out["{key}"] = [item.to_dict(False, False) for item in self.{key}]\n'
154
+ elif f.isDefaultType or f.isEnum or f.fieldType == "string":
155
+ # Regular primitive, enum, or string field
156
+ result += f' out["{key}"] = self.{key}\n'
157
+ else:
158
+ # Nested message field
159
+ if getattr(f, 'flatten', False):
160
+ # Merge nested dict into parent
161
+ result += f' out.update(self.{key}.to_dict(False, False))\n'
162
+ else:
163
+ result += f' out["{key}"] = self.{key}.to_dict(False, False)\n'
164
+ result += ' if include_name:\n'
165
+ result += f' out["name"] = "{msg.name}"\n'
166
+ result += ' if include_id:\n'
167
+ result += f' out["msg_id"] = "{msg.id}"\n'
168
+ result += ' return out\n'
169
+
170
+ return result
171
+
172
+ @staticmethod
173
+ def get_initializer(msg, null_init):
174
+ if not msg.fields:
175
+ return '{0}'
176
+
177
+ parts = []
178
+ for field in msg.fields:
179
+ parts.append(field.get_initializer(null_init))
180
+ return '{' + ', '.join(parts) + '}'
181
+
182
+
183
+ class FilePyGen():
184
+ @staticmethod
185
+ def generate(package):
186
+ yield '# Automatically generated struct frame header \n'
187
+ yield '# Generated by %s at %s. \n\n' % (version, time.asctime())
188
+
189
+ yield 'from structured import *\n'
190
+ yield 'from enum import Enum\n\n'
191
+
192
+ if package.enums:
193
+ yield '# Enum definitions\n'
194
+ for key, enum in package.enums.items():
195
+ yield EnumPyGen.generate(enum) + '\n\n'
196
+
197
+ if package.messages:
198
+ yield '# Struct definitions \n'
199
+ # Need to sort messages to make sure dependecies are properly met
200
+
201
+ for key, msg in package.sortedMessages().items():
202
+ yield MessagePyGen.generate(msg) + '\n'
203
+ yield '\n'
204
+
205
+ if package.messages:
206
+
207
+ yield '%s_definitions = {\n' % package.name
208
+ for key, msg in package.sortedMessages().items():
209
+ if msg.id != None:
210
+ structName = '%s%s' % (pascalCase(msg.package), msg.name)
211
+ yield ' %s: %s,\n' % (msg.id, structName)
212
+
213
+ yield '}\n'
struct_frame/ts_gen.py ADDED
@@ -0,0 +1,260 @@
1
+ #!/usr/bin/env python3
2
+ # kate: replace-tabs on; indent-width 4;
3
+
4
+ from struct_frame import version, NamingStyleC
5
+ import time
6
+
7
+ StyleC = NamingStyleC()
8
+
9
+ ts_types = {
10
+ "int8": 'Int8',
11
+ "uint8": 'UInt8',
12
+ "int16": 'Int16LE',
13
+ "uint16": 'UInt16LE',
14
+ "bool": 'Boolean8',
15
+ "double": 'Float64LE',
16
+ "float": 'Float32LE',
17
+ "int32": 'Int32LE',
18
+ "uint32": 'UInt32LE',
19
+ "uint64": 'BigInt64LE',
20
+ "int64": 'BigUInt64LE',
21
+ "string": 'String',
22
+ }
23
+
24
+ # TypeScript type mappings for array declarations
25
+ ts_array_types = {
26
+ "int8": 'number',
27
+ "uint8": 'number',
28
+ "int16": 'number',
29
+ "uint16": 'number',
30
+ "bool": 'boolean',
31
+ "double": 'number',
32
+ "float": 'number',
33
+ "int32": 'number',
34
+ "uint32": 'number',
35
+ "uint64": 'bigint',
36
+ "int64": 'bigint',
37
+ "string": 'string',
38
+ }
39
+
40
+
41
+ class EnumTsGen():
42
+ @staticmethod
43
+ def generate(field, packageName):
44
+ leading_comment = field.comments
45
+ result = ''
46
+ if leading_comment:
47
+ for c in leading_comment:
48
+ result = '%s\n' % c
49
+
50
+ result += 'export enum %s%s' % (packageName,
51
+ StyleC.enum_name(field.name))
52
+
53
+ result += ' {\n'
54
+
55
+ enum_length = len(field.data)
56
+ enum_values = []
57
+ for index, (d) in enumerate(field.data):
58
+ leading_comment = field.data[d][1]
59
+
60
+ if leading_comment:
61
+ for c in leading_comment:
62
+ enum_values.append(c)
63
+
64
+ comma = ","
65
+ if index == enum_length - 1:
66
+ # last enum member should not end with a comma
67
+ comma = ""
68
+
69
+ enum_value = " %s = %d%s" % (
70
+ StyleC.enum_entry(d), field.data[d][0], comma)
71
+
72
+ enum_values.append(enum_value)
73
+
74
+ result += '\n'.join(enum_values)
75
+ result += '\n}'
76
+
77
+ return result
78
+
79
+
80
+ class FieldTsGen():
81
+ @staticmethod
82
+ def generate(field, packageName):
83
+ result = ''
84
+ isEnum = False
85
+ var_name = StyleC.var_name(field.name)
86
+ type_name = field.fieldType
87
+
88
+ # Handle arrays
89
+ if field.is_array:
90
+ if field.fieldType == "string":
91
+ if field.size_option is not None: # Fixed size array [size=X]
92
+ # Fixed string array: string[size] -> Array<string> with fixed length
93
+ result += f' // Fixed string array: {field.size_option} strings, each exactly {field.element_size} chars\n'
94
+ result += f' .Array(\'{var_name}\', \'String\', {field.size_option})'
95
+ else: # Variable size array [max_size=X]
96
+ # Variable string array: string[max_size=X, element_size=Y] -> Array<string> with count
97
+ result += f' // Variable string array: up to {field.max_size} strings, each max {field.element_size} chars\n'
98
+ result += f' .UInt8(\'{var_name}_count\')\n'
99
+ result += f' .Array(\'{var_name}_data\', \'String\', {field.max_size})'
100
+ else:
101
+ # Regular type arrays
102
+ if type_name in ts_types:
103
+ base_type = ts_types[type_name]
104
+ else:
105
+ base_type = f'{packageName.lower()}_{StyleC.struct_name(type_name).lower()}'
106
+
107
+ if field.size_option is not None: # Fixed size array [size=X]
108
+ # Fixed array: type[size] -> Array<type> with fixed length
109
+ # For fixed arrays, size_option contains the exact size
110
+ array_size = field.size_option
111
+ result += f' // Fixed array: always {array_size} elements\n'
112
+ result += f' .Array(\'{var_name}\', \'{base_type}\', {array_size})'
113
+ else: # Variable size array [max_size=X]
114
+ # Variable array: type[max_size=X] -> count + Array<type>
115
+ max_count = field.max_size # For variable arrays, max_size is the maximum count
116
+ result += f' // Variable array: up to {max_count} elements\n'
117
+ result += f' .UInt8(\'{var_name}_count\')\n'
118
+ result += f' .Array(\'{var_name}_data\', \'{base_type}\', {max_count})'
119
+ else:
120
+ # Non-array fields (existing logic)
121
+ if field.fieldType == "string":
122
+ if hasattr(field, 'size_option') and field.size_option is not None:
123
+ # Fixed string: string[size] -> fixed length string
124
+ result += f' // Fixed string: exactly {field.size_option} chars\n'
125
+ result += f' .String(\'{var_name}\', {field.size_option})'
126
+ elif hasattr(field, 'max_size') and field.max_size is not None:
127
+ # Variable string: string[max_size=X] -> length + data
128
+ result += f' // Variable string: up to {field.max_size} chars\n'
129
+ result += f' .UInt8(\'{var_name}_length\')\n'
130
+ result += f' .String(\'{var_name}_data\', {field.max_size})'
131
+ else:
132
+ # Default string handling (should not occur with new parser)
133
+ result += f' .String(\'{var_name}\')'
134
+ else:
135
+ # Regular types
136
+ if type_name in ts_types:
137
+ type_name = ts_types[type_name]
138
+ else:
139
+ type_name = f'{packageName}_{StyleC.struct_name(type_name)}'
140
+
141
+ if isEnum:
142
+ result += f' .UInt8(\'{var_name}\', typed<{type_name}>())'
143
+ else:
144
+ result += f' .{type_name}(\'{var_name}\')'
145
+
146
+ leading_comment = field.comments
147
+ if leading_comment:
148
+ for c in leading_comment:
149
+ result = c + "\n" + result
150
+
151
+ return result
152
+
153
+
154
+ # ---------------------------------------------------------------------------
155
+ # Generation of messages (structures)
156
+ # ---------------------------------------------------------------------------
157
+
158
+
159
+ class MessageTsGen():
160
+ @staticmethod
161
+ def generate(msg, packageName):
162
+ leading_comment = msg.comments
163
+
164
+ result = ''
165
+ if leading_comment:
166
+ for c in msg.comments:
167
+ result = '%s\n' % c
168
+
169
+ package_msg_name = '%s_%s' % (packageName, msg.name)
170
+
171
+ result += 'export const %s = new typed_struct.Struct(\'%s\') ' % (
172
+ package_msg_name, package_msg_name)
173
+
174
+ result += '\n'
175
+
176
+ size = 1
177
+ if not msg.fields:
178
+ # Empty structs are not allowed in C standard.
179
+ # Therefore add a dummy field if an empty message occurs.
180
+ result += ' .UInt8(\'dummy_field\');'
181
+ else:
182
+ size = msg.size
183
+
184
+ result += '\n'.join([FieldTsGen.generate(f, packageName)
185
+ for key, f in msg.fields.items()])
186
+ result += '\n .compile();\n\n'
187
+
188
+ result += 'export const %s_max_size = %d;\n' % (package_msg_name, size)
189
+
190
+ if msg.id:
191
+ result += 'export const %s_msgid = %d\n' % (
192
+ package_msg_name, msg.id)
193
+
194
+ result += 'export function %s_encode(buffer: struct_frame_buffer, msg: any) {\n' % (
195
+ package_msg_name)
196
+ result += ' msg_encode(buffer, msg, %s_msgid)\n}\n' % (package_msg_name)
197
+
198
+ result += 'export function %s_reserve(buffer: struct_frame_buffer) {\n' % (
199
+ package_msg_name)
200
+ result += ' const msg_buffer = msg_reserve(buffer, %s_msgid, %s_max_size);\n' % (
201
+ package_msg_name, package_msg_name)
202
+ result += ' if (msg_buffer){\n'
203
+ result += ' return new %s(msg_buffer)\n }\n return;\n}\n' % (
204
+ package_msg_name)
205
+
206
+ result += 'export function %s_finish(buffer: struct_frame_buffer) {\n' % (
207
+ package_msg_name)
208
+ result += ' msg_finish(buffer);\n}\n'
209
+ return result + '\n'
210
+
211
+ @staticmethod
212
+ def get_initializer(msg, null_init):
213
+ if not msg.fields:
214
+ return '{0}'
215
+
216
+ parts = []
217
+ for field in msg.fields:
218
+ parts.append(field.get_initializer(null_init))
219
+ return '{' + ', '.join(parts) + '}'
220
+
221
+
222
+ class FileTsGen():
223
+ @staticmethod
224
+ def generate(package):
225
+ yield '/* Automatically generated struct frame header */\n'
226
+ yield '/* Generated by %s at %s. */\n\n' % (version, time.asctime())
227
+
228
+ yield 'const typed_struct = require(\'typed-struct\')\n'
229
+ yield 'const ExtractType = typeof typed_struct.ExtractType;\n'
230
+ yield 'const type = typeof typed_struct.ExtractType;\n\n'
231
+
232
+ yield "import { struct_frame_buffer } from './struct_frame_types';\n"
233
+
234
+ yield "import { msg_encode, msg_reserve, msg_finish } from './struct_frame';\n\n"
235
+
236
+ # include additional header files here if available in the future
237
+
238
+ if package.enums:
239
+ yield '/* Enum definitions */\n'
240
+ for key, enum in package.enums.items():
241
+ yield EnumTsGen.generate(enum, package.name) + '\n\n'
242
+
243
+ if package.messages:
244
+ yield '/* Struct definitions */\n'
245
+ for key, msg in package.sortedMessages().items():
246
+ yield MessageTsGen.generate(msg, package.name) + '\n'
247
+ yield '\n'
248
+
249
+ if package.messages:
250
+ # Only generate get_message_length if there are messages with IDs
251
+ messages_with_id = [
252
+ msg for key, msg in package.sortedMessages().items() if msg.id]
253
+ if messages_with_id:
254
+ yield 'export function get_message_length(msg_id : number){\n switch (msg_id)\n {\n'
255
+ for msg in messages_with_id:
256
+ package_msg_name = '%s_%s' % (package.name, msg.name)
257
+ yield ' case %s_msgid: return %s_max_size;\n' % (package_msg_name, package_msg_name)
258
+
259
+ yield ' default: break;\n } return 0;\n}'
260
+ yield '\n'