protons 7.7.0 → 8.0.0

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.
Files changed (60) hide show
  1. package/README.md +5 -5
  2. package/dist/bin/protons.js +1 -1
  3. package/dist/src/fields/array-field.d.ts +18 -0
  4. package/dist/src/fields/array-field.d.ts.map +1 -0
  5. package/dist/src/fields/array-field.js +83 -0
  6. package/dist/src/fields/array-field.js.map +1 -0
  7. package/dist/src/fields/enum-field.d.ts +9 -0
  8. package/dist/src/fields/enum-field.d.ts.map +1 -0
  9. package/dist/src/fields/enum-field.js +21 -0
  10. package/dist/src/fields/enum-field.js.map +1 -0
  11. package/dist/src/fields/field.d.ts +45 -0
  12. package/dist/src/fields/field.d.ts.map +1 -0
  13. package/dist/src/fields/field.js +147 -0
  14. package/dist/src/fields/field.js.map +1 -0
  15. package/dist/src/fields/map-field.d.ts +22 -0
  16. package/dist/src/fields/map-field.d.ts.map +1 -0
  17. package/dist/src/fields/map-field.js +83 -0
  18. package/dist/src/fields/map-field.js.map +1 -0
  19. package/dist/src/fields/message-field.d.ts +9 -0
  20. package/dist/src/fields/message-field.d.ts.map +1 -0
  21. package/dist/src/fields/message-field.js +23 -0
  22. package/dist/src/fields/message-field.js.map +1 -0
  23. package/dist/src/index.d.ts +190 -16
  24. package/dist/src/index.d.ts.map +1 -1
  25. package/dist/src/index.js +5 -963
  26. package/dist/src/index.js.map +1 -1
  27. package/dist/src/types/enum.d.ts +21 -0
  28. package/dist/src/types/enum.d.ts.map +1 -0
  29. package/dist/src/types/enum.js +87 -0
  30. package/dist/src/types/enum.js.map +1 -0
  31. package/dist/src/types/index.d.ts +20 -0
  32. package/dist/src/types/index.d.ts.map +1 -0
  33. package/dist/src/types/index.js +2 -0
  34. package/dist/src/types/index.js.map +1 -0
  35. package/dist/src/types/message.d.ts +49 -0
  36. package/dist/src/types/message.d.ts.map +1 -0
  37. package/dist/src/types/message.js +478 -0
  38. package/dist/src/types/message.js.map +1 -0
  39. package/dist/src/types/module.d.ts +30 -0
  40. package/dist/src/types/module.d.ts.map +1 -0
  41. package/dist/src/types/module.js +184 -0
  42. package/dist/src/types/module.js.map +1 -0
  43. package/dist/src/types/primitive.d.ts +13 -0
  44. package/dist/src/types/primitive.d.ts.map +1 -0
  45. package/dist/src/types/primitive.js +174 -0
  46. package/dist/src/types/primitive.js.map +1 -0
  47. package/dist/typedoc-urls.json +2 -4
  48. package/package.json +102 -15
  49. package/src/fields/array-field.ts +109 -0
  50. package/src/fields/enum-field.ts +30 -0
  51. package/src/fields/field.ts +201 -0
  52. package/src/fields/map-field.ts +107 -0
  53. package/src/fields/message-field.ts +29 -0
  54. package/src/index.ts +6 -1202
  55. package/src/types/enum.ts +112 -0
  56. package/src/types/index.ts +21 -0
  57. package/src/types/message.ts +558 -0
  58. package/src/types/module.ts +234 -0
  59. package/src/types/primitive.ts +215 -0
  60. package/LICENSE +0 -4
@@ -0,0 +1,112 @@
1
+ import { ParseError } from 'protons-runtime'
2
+ import type { Parent, Type } from './index.ts'
3
+ import type { Field } from '../fields/field.ts'
4
+
5
+ export interface EnumDef {
6
+ values: Record<string, number>
7
+ }
8
+
9
+ export function isEnumDef (obj?: any): obj is EnumDef {
10
+ return obj?.values != null
11
+ }
12
+
13
+ export class Enum implements Type {
14
+ public pbType: string
15
+ public jsType: string
16
+ public values: Map<string, number>
17
+ public lowestValue: number
18
+ public lowestValueName: string
19
+
20
+ constructor (pbType: string, jsType: string, def: EnumDef) {
21
+ this.pbType = pbType
22
+ this.jsType = jsType
23
+ this.values = new Map(Object.entries(def.values))
24
+
25
+ // select lowest-value enum - should be 0 but it's not guaranteed
26
+ const lowestValue = [...this.values.entries()]
27
+ .sort((a, b) => {
28
+ if (a[1] < b[1]) {
29
+ return 1
30
+ }
31
+
32
+ if (a[1] > b[1]) {
33
+ return -1
34
+ }
35
+
36
+ return 0
37
+ })
38
+ .pop()
39
+
40
+ if (lowestValue == null) {
41
+ throw new Error(`Could not find lowest enum value for ${pbType}`)
42
+ }
43
+
44
+ this.lowestValue = lowestValue[1]
45
+ this.lowestValueName = lowestValue[0]
46
+ }
47
+
48
+ init (): void {
49
+
50
+ }
51
+
52
+ getDecoder (field: Field): string {
53
+ return `${this.jsType}.codec().decode(reader)`
54
+ }
55
+
56
+ getStreamingDecoder (field: Field): string {
57
+ return `${this.jsType}.codec().stream(reader)`
58
+ }
59
+
60
+ getEncoder (field: Field, accessor: string): string {
61
+ return `${this.jsType}.codec().encode(${accessor}, w)`
62
+ }
63
+
64
+ getValueTest (field: Field, accessor: string): string {
65
+ if (field.proto2Required) {
66
+ return 'true'
67
+ }
68
+
69
+ const valueTest = `${accessor} != null`
70
+
71
+ // singular enums default to 0, but enums can be defined without a 0
72
+ // value which is against the proto3 spec but is tolerated
73
+ if (field.optional || field.proto2Required) {
74
+ return valueTest
75
+ }
76
+
77
+ return `${valueTest} && __${field.type}Values[${accessor}] !== 0`
78
+ }
79
+
80
+ public compile (parent: Parent): string {
81
+ // import required modules
82
+ parent.addImport('protons-runtime', 'enumeration')
83
+
84
+ // check that the enum def values start from 0
85
+ if ([...this.values.values()][0] !== 0) {
86
+ const message = `enum ${this.pbType} does not contain a value that maps to zero as the first element, this is required in proto3 - see https://protobuf.dev/programming-guides/proto3/#enum`
87
+
88
+ if (parent.flags.strict === true) {
89
+ throw new ParseError(message)
90
+ } else {
91
+ // eslint-disable-next-line no-console
92
+ console.info(`[WARN] ${message}`)
93
+ }
94
+ }
95
+
96
+ return `
97
+ export enum ${this.pbType} {
98
+ ${[...this.values.keys()].map(key => `${key} = '${key}'`).join(',\n ')}
99
+ }
100
+
101
+ enum __${this.pbType}Values {
102
+ ${[...this.values.entries()].map(([key, value]) => `${key} = ${value}`).join(',\n ')}
103
+ }
104
+
105
+ export namespace ${this.pbType} {
106
+ export const codec = (): Codec<${this.pbType}> => {
107
+ return enumeration<${this.pbType}>(__${this.pbType}Values)
108
+ }
109
+ }
110
+ `.trimStart()
111
+ }
112
+ }
@@ -0,0 +1,21 @@
1
+ import type { Field } from '../fields/field.ts'
2
+ import type { Flags } from '../index.ts'
3
+ import type { Module } from './module.ts'
4
+
5
+ export interface Type {
6
+ jsType: string
7
+ pbType: string
8
+ init(module: Module): void
9
+ getDecoder(field: Field, indent?: string): string
10
+ getStreamingDecoder(field: Field, prefix: string, indent?: string): string
11
+ getEncoder(field: Field, accessor: string): string
12
+ getValueTest(field: Field, accessor: string): string
13
+ }
14
+
15
+ export interface Parent {
16
+ flags: Flags
17
+ findType (type: string, jsOverride?: 'string' | 'number'): Type
18
+ addImport (module: string, symbol: string, alias?: string): void
19
+ addTypeImport (module: string, symbol: string, alias?: string): void
20
+ addEslintIgnore (rule: string): void
21
+ }
@@ -0,0 +1,558 @@
1
+ import { ArrayField, isArrayFieldDef } from '../fields/array-field.ts'
2
+ import { EnumField } from '../fields/enum-field.ts'
3
+ import { Field } from '../fields/field.ts'
4
+ import { isMapFieldDef, MapField } from '../fields/map-field.ts'
5
+ import { MessageField } from '../fields/message-field.ts'
6
+ import { Enum } from './enum.ts'
7
+ import { Primitive } from './primitive.ts'
8
+ import type { EnumDef } from './enum.ts'
9
+ import type { Parent, Type } from './index.ts'
10
+ import type { FieldDef } from '../fields/field.ts'
11
+ import type { Flags } from '../index.ts'
12
+
13
+ interface StreamEvent {
14
+ name: string
15
+ fields: string[]
16
+ type: 'field'
17
+ | 'collection-primitive-member'
18
+ | 'collection-message-member-field'
19
+ | 'sub-message-field'
20
+ | 'sub-message-collection-primitive-member'
21
+ | 'sub-message-collection-message-member-field'
22
+ }
23
+
24
+ function camelize (input: string): string {
25
+ return `${input.substring(0, 1).toUpperCase()}${input.substring(1)}`
26
+ }
27
+
28
+ export interface MessageDef {
29
+ fields?: Record<string, FieldDef>
30
+ oneofs?: Record<string, { oneof: string[] }>
31
+ nested?: Record<string, MessageDef | EnumDef>
32
+ }
33
+
34
+ export function isMessageDef (obj?: any): obj is MessageDef {
35
+ return obj?.fields != null
36
+ }
37
+
38
+ export class Message implements Type {
39
+ public pbType: string
40
+ public jsType: string
41
+ public fields: Field[]
42
+ public oneOfs: string[][]
43
+ public nested: Record<string, Message | Enum>
44
+ private def: MessageDef
45
+ private parent: Parent
46
+
47
+ constructor (pbType: string, jsType: string, def: MessageDef, parent: Parent) {
48
+ this.pbType = pbType
49
+ this.jsType = jsType
50
+ this.oneOfs = []
51
+ this.nested = {}
52
+ this.fields = []
53
+ this.def = def
54
+ this.parent = parent
55
+
56
+ def.fields ??= {}
57
+ def.nested ??= {}
58
+ def.oneofs ??= {}
59
+
60
+ // create extra message types for map type backwards compatibility
61
+ // https://developers.google.com/protocol-buffers/docs/proto3#backwards
62
+ for (const [fieldName, fieldDef] of Object.entries<any>(def.fields)) {
63
+ if (fieldDef.keyType == null) {
64
+ continue
65
+ }
66
+
67
+ const mapEntryType = `${this.pbType}$${fieldName}Entry`
68
+
69
+ def.nested[mapEntryType] = {
70
+ fields: {
71
+ key: {
72
+ type: fieldDef.keyType,
73
+ id: 1
74
+ },
75
+ value: {
76
+ type: fieldDef.type,
77
+ id: 2
78
+ }
79
+ }
80
+ }
81
+
82
+ fieldDef.valueType = fieldDef.type
83
+ fieldDef.type = mapEntryType
84
+ fieldDef.rule = 'repeated'
85
+ }
86
+
87
+ Object.entries(def.nested ?? {}).forEach(([name, def]) => {
88
+ const fullName = `${this.jsType}.${name}`
89
+
90
+ if (isMessageDef(def)) {
91
+ this.nested[name] = new Message(name, fullName, def, this)
92
+ } else {
93
+ this.nested[name] = new Enum(name, fullName, def)
94
+ }
95
+ })
96
+
97
+ for (const [, { oneof: fields }] of Object.entries(def.oneofs)) {
98
+ for (const field of fields) {
99
+ if (def.fields[field] == null) {
100
+ continue
101
+ }
102
+
103
+ def.fields[field].options ??= {}
104
+ def.fields[field].options.proto3_optional = true
105
+ def.fields[field].oneof = fields
106
+ }
107
+ }
108
+
109
+ // reverse order of oneofs as spec says last field overwrites all others
110
+ this.oneOfs = Object.values(def.oneofs).map(({ oneof }) => oneof.reverse())
111
+ }
112
+
113
+ init (): void {
114
+ for (const [name, fieldDef] of Object.entries(this.def.fields ?? {})) {
115
+ if (isMapFieldDef(fieldDef)) {
116
+ this.fields.push(new MapField(name, fieldDef, this))
117
+ } else if (isArrayFieldDef(fieldDef)) {
118
+ this.fields.push(new ArrayField(name, fieldDef, this))
119
+ } else {
120
+ const type = this.findType(fieldDef.type)
121
+
122
+ if (type instanceof Enum) {
123
+ this.fields.push(new EnumField(name, fieldDef, this))
124
+ } else if (type instanceof Primitive) {
125
+ this.fields.push(new Field(name, fieldDef, this))
126
+ } else {
127
+ this.fields.push(new MessageField(name, fieldDef, this))
128
+ }
129
+ }
130
+ }
131
+
132
+ Object.values(this.nested).forEach(type => type.init())
133
+ }
134
+
135
+ findType (jsType: string, override?: 'string' | 'number'): Type {
136
+ const type = this.nested[override ?? jsType]
137
+
138
+ if (type == null) {
139
+ return this.parent.findType(jsType, override)
140
+ }
141
+
142
+ return type
143
+ }
144
+
145
+ addImport (module: string, symbol: string, alias?: string): void {
146
+ this.parent.addImport(module, symbol, alias)
147
+ }
148
+
149
+ addTypeImport (module: string, symbol: string, alias?: string): void {
150
+ this.parent.addTypeImport(module, symbol, alias)
151
+ }
152
+
153
+ addEslintIgnore (rule: string): void {
154
+ this.parent.addEslintIgnore(rule)
155
+ }
156
+
157
+ get flags (): Flags {
158
+ return this.parent.flags
159
+ }
160
+
161
+ getDecoder (field: Field, indent = ''): string {
162
+ let opts = ''
163
+
164
+ if (field instanceof MessageField) {
165
+ opts = `, {
166
+ ${indent} limits: opts.limits?.${field.name}
167
+ ${indent} }`
168
+ } else if (field instanceof ArrayField) {
169
+ opts = `, {
170
+ ${indent} limits: opts.limits?.${field.name}$
171
+ ${indent} }`
172
+ } else if (field instanceof MapField) {
173
+ opts = `, {
174
+ ${indent} limits: {
175
+ ${indent} value: opts.limits?.${field.name}$value
176
+ }
177
+ ${indent} }`
178
+ }
179
+
180
+ return `${this.jsType}.codec().decode(reader, reader.uint32()${opts})`
181
+ }
182
+
183
+ getStreamingDecoder (field: Field, prefix: string, indent = ''): string {
184
+ let opts = ''
185
+
186
+ if (field instanceof MessageField) {
187
+ opts = `, {
188
+ ${indent} limits: opts.limits?.${field.name}
189
+ ${indent} }`
190
+ } else if (field instanceof ArrayField) {
191
+ opts = `, {
192
+ ${indent} limits: opts.limits?.${field.name}$
193
+ ${indent} }`
194
+
195
+ return `for (const evt of ${this.jsType}.codec().stream(reader, reader.uint32(), ${prefix}${opts})) {
196
+ yield {
197
+ ...evt,
198
+ index: obj.${field.name}
199
+ }
200
+ }`
201
+ } else if (field instanceof MapField) {
202
+ opts = `, {
203
+ ${indent} limits: {
204
+ ${indent} value: opts.limits?.${field.name}$value
205
+ }
206
+ ${indent} }`
207
+ }
208
+
209
+ return `yield * ${this.jsType}.codec().stream(reader, reader.uint32(), ${prefix}${opts})`
210
+ }
211
+
212
+ getEncoder (field: Field, accessor: string): string {
213
+ if (field instanceof ArrayField) {
214
+ // message fields are only written if they have values. But if a message
215
+ // is part of a repeated field, and consists of only default values it
216
+ // won't be written, so write a zero-length buffer if that's the case
217
+ // writeField = (): string => `w.uint32(${id})
218
+ // ${type.jsType}.codec().encode(${valueVar}, w)`
219
+ }
220
+
221
+ return `${this.jsType}.codec().encode(${accessor}, w)`
222
+ }
223
+
224
+ getValueTest (field: Field): string {
225
+ return `obj.${field.name} != null`
226
+ }
227
+
228
+ public compile (parent: Parent, indent: string = ''): string {
229
+ // import required modules
230
+ parent.addImport('protons-runtime', 'encodeMessage')
231
+ parent.addImport('protons-runtime', 'decodeMessage')
232
+ parent.addImport('protons-runtime', 'streamMessage')
233
+ parent.addImport('protons-runtime', 'message')
234
+ parent.addTypeImport('protons-runtime', 'Codec')
235
+ parent.addTypeImport('protons-runtime', 'DecodeOptions')
236
+ parent.addTypeImport('uint8arraylist', 'Uint8ArrayList')
237
+
238
+ let nested = ''
239
+
240
+ if (this.nested != null && [...Object.values(this.nested)].length > 0) {
241
+ nested += Object.values(this.nested)
242
+ .map(def => def.compile(this, `${indent} `).trim())
243
+ .join('\n\n')
244
+ nested = nested.split('\n').join('\n ')
245
+ nested = `
246
+ ${nested}
247
+ `
248
+ }
249
+
250
+ const interfaceFields = this.fields.map(field => field.getInterfaceField(this))
251
+ .join('\n ')
252
+ .trim()
253
+
254
+ let interfaceDef = ''
255
+ let interfaceCodecDef = ''
256
+
257
+ if (interfaceFields === '') {
258
+ interfaceDef = `
259
+ export interface ${this.pbType} {}`
260
+ } else {
261
+ interfaceDef = `
262
+ export interface ${this.pbType} {
263
+ ${interfaceFields}
264
+ }`
265
+ }
266
+
267
+ const enforceOneOfEncoding = this.createOneOfEncoding()
268
+ const enforceOneOfDecoding = this.createOneOfDecoding()
269
+ const streamEvents = this.getStreamEvents()
270
+
271
+ const encodeFields = this.fields.map(field => field.getEncoder(this))
272
+ const decodeFields = this.fields.map(field => field.getDecoder(this))
273
+ const streamFields = this.fields.map(field => field.getStreamingDecoder(this))
274
+
275
+ const streamGeneratorEvents = streamEvents.map(evt => evt.name)
276
+
277
+ if (streamGeneratorEvents.length === 0) {
278
+ this.addEslintIgnore('require-yield')
279
+ streamGeneratorEvents.push('{}')
280
+ }
281
+
282
+ interfaceCodecDef = `
283
+ let _codec: Codec<${this.pbType}>
284
+
285
+ export const codec = (): Codec<${this.pbType}> => {
286
+ if (_codec == null) {
287
+ _codec = message<${this.pbType}>((obj, w, opts = {}) => {
288
+ if (opts.lengthDelimited !== false) {
289
+ w.fork()
290
+ }${enforceOneOfEncoding}${this.formatFields(encodeFields)}
291
+
292
+ if (opts.lengthDelimited !== false) {
293
+ w.ldelim()
294
+ }
295
+ }, (reader, length, opts = {}) => {
296
+ const obj: any = {${this.createDefaultObject()}}
297
+
298
+ const end = length == null ? reader.len : reader.pos + length
299
+
300
+ while (reader.pos < end) {
301
+ const tag = reader.uint32()
302
+
303
+ switch (tag >>> 3) {${this.formatFields(decodeFields, '\n ')}
304
+ default: {
305
+ reader.skipType(tag & 7)
306
+ break
307
+ }
308
+ }
309
+ }
310
+ ${enforceOneOfDecoding === '' ? '' : `${enforceOneOfDecoding}\n`}
311
+ return obj
312
+ }, function * (reader, length, prefix, opts = {}) {
313
+ ${this.createLimitObject()}const end = length == null ? reader.len : reader.pos + length
314
+
315
+ while (reader.pos < end) {
316
+ const tag = reader.uint32()
317
+
318
+ switch (tag >>> 3) {${this.formatFields(streamFields, '\n ')}
319
+ default: {
320
+ reader.skipType(tag & 7)
321
+ break
322
+ }
323
+ }
324
+ }
325
+ })
326
+ }
327
+
328
+ return _codec
329
+ }${this.formatStreamEvents(streamEvents)}
330
+
331
+ export function encode (obj: Partial<${this.pbType}>): Uint8Array {
332
+ return encodeMessage(obj, ${this.pbType}.codec())
333
+ }
334
+
335
+ export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<${this.pbType}>): ${this.pbType} {
336
+ return decodeMessage(buf, ${this.pbType}.codec(), opts)
337
+ }
338
+
339
+ export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<${this.pbType}>): Generator<${streamGeneratorEvents.join(' | ')}> {
340
+ return streamMessage(buf, ${this.pbType}.codec(), opts)
341
+ }`
342
+
343
+ return `
344
+ ${interfaceDef}
345
+
346
+ export namespace ${this.pbType} {${nested}${interfaceCodecDef.trimEnd()}
347
+ }
348
+ `.trimStart()
349
+ }
350
+
351
+ private createOneOfEncoding (): string {
352
+ let oneOfs = this.oneOfs.map(fields => {
353
+ if (fields.length < 2) {
354
+ return ''
355
+ }
356
+
357
+ let oneOf = ''
358
+
359
+ for (const name of fields) {
360
+ oneOf += `
361
+ if (obj.${name} != null) {
362
+ ${fields
363
+ .filter(field => field !== name)
364
+ .map(name => ` obj.${name} = undefined`).join('\n')}
365
+ }
366
+ `
367
+ }
368
+
369
+ return oneOf.trimEnd()
370
+ }).join('\n').trimEnd()
371
+
372
+ if (oneOfs !== '') {
373
+ oneOfs = `
374
+
375
+ obj = { ...obj }
376
+ ${oneOfs}`
377
+ }
378
+
379
+ return oneOfs
380
+ }
381
+
382
+ private createOneOfDecoding (): string {
383
+ return this.oneOfs.map(fields => {
384
+ if (fields.length < 2) {
385
+ return ''
386
+ }
387
+
388
+ let oneOf = ''
389
+
390
+ for (const name of fields) {
391
+ oneOf += `
392
+ if (obj.${name} != null) {
393
+ ${fields
394
+ .filter(field => field !== name)
395
+ .map(name => ` delete obj.${name}`).join('\n')}
396
+ }
397
+ `
398
+ }
399
+
400
+ return oneOf.trimEnd()
401
+ }).join('\n').trimEnd()
402
+ }
403
+
404
+ createDefaultObject (indent = ''): string {
405
+ const output = this.fields
406
+ .map((field) => field.getDefaultField(this))
407
+ .filter(Boolean)
408
+ .join(`,\n ${indent}`)
409
+
410
+ if (output !== '') {
411
+ return `
412
+ ${indent}${output}
413
+ ${indent}`
414
+ }
415
+
416
+ return ''
417
+ }
418
+
419
+ createLimitObject (): string {
420
+ const output = this.fields.map(field => field.getLimitField())
421
+ .filter(Boolean)
422
+ .join(',\n ')
423
+
424
+ if (output !== '') {
425
+ return `const obj = {
426
+ ${output}
427
+ }
428
+
429
+ `
430
+ }
431
+
432
+ return ''
433
+ }
434
+
435
+ formatStreamEvents (streamEvents: StreamEvent[]): string {
436
+ if (streamEvents.length === 0) {
437
+ return ''
438
+ }
439
+
440
+ return `
441
+
442
+ ${streamEvents.map(evt => `export interface ${evt.name} {
443
+ ${evt.fields.join('\n ')}
444
+ }`).join('\n\n ')}`
445
+ }
446
+
447
+ formatFields (fields: string[], delimiter = '\n'): string {
448
+ if (fields.length === 0) {
449
+ return ''
450
+ }
451
+
452
+ return `
453
+ ${fields.join(delimiter)}`
454
+ }
455
+
456
+ getStreamEvents (fieldPrefix = '$.'): StreamEvent[] {
457
+ const streamEvents: StreamEvent[] = []
458
+
459
+ const addMessageFields = (field: Field, message: Message, extraFields: string[]): void => {
460
+ let fieldSuffix = '.'
461
+
462
+ if (field instanceof ArrayField) {
463
+ fieldSuffix = '[].'
464
+ } else if (field instanceof MapField) {
465
+ fieldSuffix = '{}.'
466
+ }
467
+
468
+ // include sub messages
469
+ streamEvents.push(...message.getStreamEvents(`${fieldPrefix}${field.name}${fieldSuffix}`).map(evt => {
470
+ let type = evt.type
471
+
472
+ if (evt.type === 'field') {
473
+ type = (field instanceof MapField || field instanceof ArrayField) ? 'collection-message-member-field' : 'sub-message-field'
474
+ } else if (evt.type === 'collection-primitive-member') {
475
+ type = 'sub-message-collection-primitive-member'
476
+ } else if (evt.type === 'collection-message-member-field') {
477
+ type = 'sub-message-collection-message-member-field'
478
+ }
479
+
480
+ const fields = new Map<string, string>()
481
+ evt.fields.forEach(field => {
482
+ const [key, value] = field.split(':')
483
+ fields.set(key.trim(), value.trim())
484
+ })
485
+ extraFields.forEach(field => {
486
+ const [key, value] = field.split(':')
487
+ fields.set(key.trim(), value.trim())
488
+ })
489
+
490
+ return {
491
+ ...evt,
492
+ name: `${fieldPrefix === '$.' ? this.pbType : ''}${camelize(field.name)}${evt.name}`,
493
+ type,
494
+ fields: [...fields.entries()].map(([key, value]) => `${key}: ${value}`)
495
+ }
496
+ }))
497
+ }
498
+
499
+ this.fields.forEach(field => {
500
+ if (field instanceof MapField) {
501
+ const keyType = this.findType(field.keyType)
502
+ const valueType = this.findType(field.valueType)
503
+
504
+ if (valueType instanceof Primitive || valueType instanceof Enum) {
505
+ streamEvents.push({
506
+ name: `${fieldPrefix === '$.' ? this.pbType : ''}${camelize(field.name)}FieldEvent`,
507
+ fields: [
508
+ `field: '${fieldPrefix}${field.name}{}'`,
509
+ `key: ${keyType.jsType}`,
510
+ `value: ${valueType.jsType}`
511
+ ],
512
+ type: 'collection-primitive-member'
513
+ })
514
+ } else if (valueType instanceof Message) {
515
+ addMessageFields(field, valueType, [
516
+ `key: ${keyType.jsType}`,
517
+ `value: ${valueType.jsType}`
518
+ ])
519
+ }
520
+ } else if (field instanceof ArrayField) {
521
+ const type = this.findType(field.type)
522
+
523
+ if (type instanceof Primitive || type instanceof Enum) {
524
+ streamEvents.push({
525
+ name: `${fieldPrefix === '$.' ? this.pbType : ''}${camelize(field.name)}FieldEvent`,
526
+ fields: [
527
+ `field: '${fieldPrefix}${field.name}[]'`,
528
+ 'index: number',
529
+ `value: ${type.jsType}`
530
+ ],
531
+ type: 'collection-primitive-member'
532
+ })
533
+ } else if (type instanceof Message) {
534
+ addMessageFields(field, type, [
535
+ 'index: number'
536
+ ])
537
+ }
538
+ } else {
539
+ const type = this.findType(field.type)
540
+
541
+ if (type instanceof Primitive || type instanceof Enum) {
542
+ streamEvents.push({
543
+ name: `${fieldPrefix === '$.' ? this.pbType : ''}${camelize(field.name)}FieldEvent`,
544
+ fields: [
545
+ `field: '${fieldPrefix}${field.name}'`,
546
+ `value: ${type.jsType}`
547
+ ],
548
+ type: 'field'
549
+ })
550
+ } else if (type instanceof Message) {
551
+ addMessageFields(field, type, [])
552
+ }
553
+ }
554
+ })
555
+
556
+ return streamEvents
557
+ }
558
+ }