@@ -26,12 +26,25 @@ import * as yargs from 'yargs';
26
26
import camelCase = require ( 'lodash.camelcase' ) ;
27
27
import { loadProtosWithOptions , addCommonProtos } from '../src/util' ;
28
28
29
+ const templateStr = "%s" ;
30
+ const useNameFmter = ( { outputTemplate, inputTemplate} : GeneratorOptions ) => {
31
+ if ( outputTemplate === inputTemplate ) {
32
+ throw new Error ( 'inputTemplate and outputTemplate must differ' )
33
+ }
34
+ return {
35
+ outputName : ( n : string ) => outputTemplate . replace ( templateStr , n ) ,
36
+ inputName : ( n : string ) => inputTemplate . replace ( templateStr , n )
37
+ } ;
38
+ }
39
+
29
40
type GeneratorOptions = Protobuf . IParseOptions & Protobuf . IConversionOptions & {
30
41
includeDirs ?: string [ ] ;
31
42
grpcLib : string ;
32
43
outDir : string ;
33
44
verbose ?: boolean ;
34
45
includeComments ?: boolean ;
46
+ inputTemplate : string ;
47
+ outputTemplate : string ;
35
48
}
36
49
37
50
class TextFormatter {
@@ -114,15 +127,16 @@ function getTypeInterfaceName(type: Protobuf.Type | Protobuf.Enum | Protobuf.Ser
114
127
return type . fullName . replace ( / \. / g, '_' ) ;
115
128
}
116
129
117
- function getImportLine ( dependency : Protobuf . Type | Protobuf . Enum | Protobuf . Service , from ? : Protobuf . Type | Protobuf . Service ) {
130
+ function getImportLine ( dependency : Protobuf . Type | Protobuf . Enum | Protobuf . Service , from : Protobuf . Type | Protobuf . Service | undefined , options : GeneratorOptions ) {
118
131
const filePath = from === undefined ? './' + getImportPath ( dependency ) : getRelativeImportPath ( from , dependency ) ;
132
+ const { outputName , inputName } = useNameFmter ( options ) ;
119
133
const typeInterfaceName = getTypeInterfaceName ( dependency ) ;
120
134
let importedTypes : string ;
121
135
/* If the dependency is defined within a message, it will be generated in that
122
136
* message's file and exported using its typeInterfaceName. */
123
137
if ( dependency . parent instanceof Protobuf . Type ) {
124
138
if ( dependency instanceof Protobuf . Type ) {
125
- importedTypes = `${typeInterfaceName } , ${typeInterfaceName } __Output `;
139
+ importedTypes = `${ inputName ( typeInterfaceName ) } , ${ outputName ( typeInterfaceName ) } ` ;
126
140
} else if ( dependency instanceof Protobuf . Enum ) {
127
141
importedTypes = `${ typeInterfaceName } ` ;
128
142
} else if ( dependency instanceof Protobuf . Service ) {
@@ -132,7 +146,7 @@ function getImportLine(dependency: Protobuf.Type | Protobuf.Enum | Protobuf.Serv
132
146
}
133
147
} else {
134
148
if ( dependency instanceof Protobuf . Type ) {
135
- importedTypes = `${dependency . name } as ${typeInterfaceName } , $ { dependency . name } __Output as ${typeInterfaceName } __Output `;
149
+ importedTypes = `${ inputName ( dependency . name ) } as ${ inputName ( typeInterfaceName ) } , ${ outputName ( dependency . name ) } as ${ outputName ( typeInterfaceName ) } ` ;
136
150
} else if ( dependency instanceof Protobuf . Enum ) {
137
151
importedTypes = `${ dependency . name } as ${ typeInterfaceName } ` ;
138
152
} else if ( dependency instanceof Protobuf . Service ) {
@@ -170,7 +184,8 @@ function formatComment(formatter: TextFormatter, comment?: string | null) {
170
184
171
185
// GENERATOR FUNCTIONS
172
186
173
- function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | Protobuf.Enum | null, repeated: boolean, map: boolean): string {
187
+ function getTypeNamePermissive ( fieldType : string , resolvedType : Protobuf . Type | Protobuf . Enum | null , repeated : boolean , map : boolean , options : GeneratorOptions ) : string {
188
+ const { inputName} = useNameFmter ( options ) ;
174
189
switch ( fieldType ) {
175
190
case 'double' :
176
191
case 'float' :
@@ -200,18 +215,18 @@ function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type |
200
215
const typeInterfaceName = getTypeInterfaceName ( resolvedType ) ;
201
216
if ( resolvedType instanceof Protobuf . Type ) {
202
217
if ( repeated || map ) {
203
- return typeInterfaceName;
218
+ return inputName ( typeInterfaceName ) ;
204
219
} else {
205
- return ` $ { typeInterfaceName } | null `;
220
+ return `${ inputName ( typeInterfaceName ) } | null` ;
206
221
}
207
222
} else {
208
223
return `${ typeInterfaceName } | keyof typeof ${ typeInterfaceName } ` ;
209
224
}
210
225
}
211
226
}
212
227
213
- function getFieldTypePermissive(field: Protobuf.FieldBase): string {
214
- const valueType = getTypeNamePermissive(field.type, field.resolvedType, field.repeated, field.map);
228
+ function getFieldTypePermissive ( field : Protobuf . FieldBase , options : GeneratorOptions ) : string {
229
+ const valueType = getTypeNamePermissive ( field . type , field . resolvedType , field . repeated , field . map , options ) ;
215
230
if ( field instanceof Protobuf . MapField ) {
216
231
const keyType = field . keyType === 'string' ? 'string' : 'number' ;
217
232
return `{ [ key : ${keyType } ] : ${valueType } } `;
@@ -221,23 +236,24 @@ function getFieldTypePermissive(field: Protobuf.FieldBase): string {
221
236
}
222
237
223
238
function generatePermissiveMessageInterface ( formatter : TextFormatter , messageType : Protobuf . Type , options : GeneratorOptions , nameOverride ? : string ) {
239
+ const { inputName } = useNameFmter ( options ) ;
224
240
if ( options . includeComments ) {
225
241
formatComment ( formatter , messageType . comment ) ;
226
242
}
227
243
if ( messageType . fullName === '.google.protobuf.Any' ) {
228
244
/* This describes the behavior of the Protobuf.js Any wrapper fromObject
229
245
* replacement function */
230
- formatter.writeLine(' export type Any = AnyExtension | {' );
246
+ formatter . writeLine ( ` export type ${ inputName ( ' Any' ) } = AnyExtension | {` ) ;
231
247
formatter . writeLine ( ' type_url: string;' ) ;
232
248
formatter . writeLine ( ' value: Buffer | Uint8Array | string;' ) ;
233
249
formatter . writeLine ( '}' ) ;
234
250
return ;
235
251
}
236
- formatter.writeLine(` export interface ${nameOverride ?? messageType . name } { `);
252
+ formatter . writeLine ( `export interface ${ inputName ( nameOverride ?? messageType . name ) } {` ) ;
237
253
formatter . indent ( ) ;
238
254
for ( const field of messageType . fieldsArray ) {
239
255
const repeatedString = field . repeated ? '[]' : '' ;
240
- const type: string = getFieldTypePermissive(field);
256
+ const type : string = getFieldTypePermissive ( field , options ) ;
241
257
if ( options . includeComments ) {
242
258
formatComment ( formatter , field . comment ) ;
243
259
}
@@ -255,6 +271,7 @@ function generatePermissiveMessageInterface(formatter: TextFormatter, messageTyp
255
271
}
256
272
257
273
function getTypeNameRestricted ( fieldType : string , resolvedType : Protobuf . Type | Protobuf . Enum | null , repeated : boolean , map : boolean , options : GeneratorOptions ) : string {
274
+ const { outputName } = useNameFmter ( options ) ;
258
275
switch ( fieldType ) {
259
276
case 'double ':
260
277
case 'float ':
@@ -302,9 +319,9 @@ function getTypeNameRestricted(fieldType: string, resolvedType: Protobuf.Type |
302
319
/* null is only used to represent absent message values if the defaults
303
320
* option is set, and only for non-repeated, non-map fields. */
304
321
if ( options . defaults && ! repeated && ! map ) {
305
- return ` $ { typeInterfaceName } __Output | null `;
322
+ return `${outputName ( typeInterfaceName ) } | null `;
306
323
} else {
307
- return ` $ { typeInterfaceName } __Output `;
324
+ return ` $ { outputName ( typeInterfaceName ) } `;
308
325
}
309
326
} else {
310
327
if ( options . enums == String ) {
@@ -327,20 +344,21 @@ function getFieldTypeRestricted(field: Protobuf.FieldBase, options: GeneratorOpt
327
344
}
328
345
329
346
function generateRestrictedMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: GeneratorOptions, nameOverride?: string) {
347
+ const {outputName} = useNameFmter(options);
330
348
if (options.includeComments) {
331
349
formatComment(formatter, messageType.comment);
332
350
}
333
351
if (messageType.fullName === '.google.protobuf.Any' && options.json) {
334
352
/* This describes the behavior of the Protobuf.js Any wrapper toObject
335
353
* replacement function */
336
354
let optionalString = options.defaults ? '' : '?';
337
- formatter.writeLine(' export type Any__Output = AnyExtension | {' );
355
+ formatter.writeLine(` export type ${ outputName ( 'Any' ) } = AnyExtension | { ` );
338
356
formatter.writeLine(` type_url$ { optionalString } : string ; `) ;
339
357
formatter . writeLine ( ` value${ optionalString } : ${ getTypeNameRestricted ( 'bytes' , null , false , false , options ) } ;` ) ;
340
358
formatter . writeLine ( '}' ) ;
341
359
return ;
342
360
}
343
- formatter.writeLine(` export interface ${nameOverride ?? messageType . name } __Output { `);
361
+ formatter . writeLine ( `export interface ${ outputName ( nameOverride ?? messageType . name ) } {` ) ;
344
362
formatter . indent ( ) ;
345
363
for ( const field of messageType . fieldsArray ) {
346
364
let fieldGuaranteed : boolean ;
@@ -389,7 +407,7 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob
389
407
continue ;
390
408
}
391
409
seenDeps . add ( dependency . fullName ) ;
392
- formatter . writeLine ( getImportLine ( dependency , messageType ) ) ;
410
+ formatter . writeLine ( getImportLine ( dependency , messageType , options ) ) ;
393
411
}
394
412
if ( field . type . indexOf ( '64' ) >= 0 ) {
395
413
usesLong = true ;
@@ -404,7 +422,7 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob
404
422
continue ;
405
423
}
406
424
seenDeps . add ( dependency . fullName ) ;
407
- formatter . writeLine ( getImportLine ( dependency , messageType ) ) ;
425
+ formatter . writeLine ( getImportLine ( dependency , messageType , options ) ) ;
408
426
}
409
427
if ( field . type . indexOf ( '64' ) >= 0 ) {
410
428
usesLong = true ;
@@ -487,6 +505,7 @@ const CLIENT_RESERVED_METHOD_NAMES = new Set([
487
505
] ) ;
488
506
489
507
function generateServiceClientInterface ( formatter : TextFormatter , serviceType : Protobuf . Service , options : GeneratorOptions ) {
508
+ const { outputName , inputName } = useNameFmter ( options ) ;
490
509
if ( options . includeComments ) {
491
510
formatComment ( formatter , serviceType . comment ) ;
492
511
}
@@ -501,8 +520,8 @@ function generateServiceClientInterface(formatter: TextFormatter, serviceType: P
501
520
if ( options . includeComments ) {
502
521
formatComment ( formatter , method . comment ) ;
503
522
}
504
- const requestType = getTypeInterfaceName ( method . resolvedRequestType ! ) ;
505
- const responseType = getTypeInterfaceName ( method . resolvedResponseType ! ) + '__Output' ;
523
+ const requestType = inputName ( getTypeInterfaceName ( method . resolvedRequestType ! ) ) ;
524
+ const responseType = outputName ( getTypeInterfaceName ( method . resolvedResponseType ! ) ) ;
506
525
const callbackType = `grpc . requestCallback < $ { responseType } > `;
507
526
if (method.requestStream) {
508
527
if (method.responseStream) {
@@ -541,6 +560,7 @@ function generateServiceClientInterface(formatter: TextFormatter, serviceType: P
541
560
}
542
561
543
562
function generateServiceHandlerInterface ( formatter : TextFormatter , serviceType : Protobuf . Service , options : GeneratorOptions ) {
563
+ const { inputName , outputName } = useNameFmter ( options ) ;
544
564
if ( options . includeComments ) {
545
565
formatComment ( formatter , serviceType . comment ) ;
546
566
}
@@ -551,8 +571,8 @@ function generateServiceHandlerInterface(formatter: TextFormatter, serviceType:
551
571
if ( options . includeComments ) {
552
572
formatComment ( formatter , method . comment ) ;
553
573
}
554
- const requestType = getTypeInterfaceName ( method . resolvedRequestType ! ) + '__Output' ;
555
- const responseType = getTypeInterfaceName ( method . resolvedResponseType ! ) ;
574
+ const requestType = outputName ( getTypeInterfaceName ( method . resolvedRequestType ! ) ) ;
575
+ const responseType = inputName ( getTypeInterfaceName ( method . resolvedResponseType ! ) ) ;
556
576
if ( method . requestStream ) {
557
577
if ( method . responseStream ) {
558
578
// Bidi streaming
@@ -576,14 +596,15 @@ function generateServiceHandlerInterface(formatter: TextFormatter, serviceType:
576
596
formatter . writeLine ( '}' ) ;
577
597
}
578
598
579
- function generateServiceDefinitionInterface ( formatter : TextFormatter , serviceType : Protobuf . Service ) {
599
+ function generateServiceDefinitionInterface ( formatter : TextFormatter , serviceType : Protobuf . Service , options : GeneratorOptions ) {
600
+ const { inputName , outputName } = useNameFmter ( options ) ;
580
601
formatter . writeLine ( `export interface ${ serviceType . name } Definition extends grpc.ServiceDefinition {` ) ;
581
602
formatter . indent ( ) ;
582
603
for ( const methodName of Object . keys ( serviceType . methods ) . sort ( ) ) {
583
604
const method = serviceType . methods [ methodName ] ;
584
605
const requestType = getTypeInterfaceName ( method . resolvedRequestType ! ) ;
585
606
const responseType = getTypeInterfaceName ( method . resolvedResponseType ! ) ;
586
- formatter . writeLine ( `${ methodName } : MethodDefinition<${ requestType } , ${ responseType } , ${ requestType } __Output , ${ responseType } __Output >` ) ;
607
+ formatter . writeLine ( `${ methodName } : MethodDefinition<${ inputName ( requestType ) } , ${ inputName ( responseType ) } , ${ outputName ( requestType ) } , ${ outputName ( responseType ) } >` ) ;
587
608
}
588
609
formatter . unindent ( ) ;
589
610
formatter . writeLine ( '}' )
@@ -601,7 +622,7 @@ function generateServiceInterfaces(formatter: TextFormatter, serviceType: Protob
601
622
dependencies . add ( method . resolvedResponseType ! ) ;
602
623
}
603
624
for (const dep of Array.from(dependencies.values()).sort(compareName)) {
604
- formatter . writeLine ( getImportLine ( dep , serviceType ) ) ;
625
+ formatter . writeLine ( getImportLine ( dep , serviceType , options ) ) ;
605
626
}
606
627
formatter.writeLine('');
607
628
@@ -611,7 +632,7 @@ function generateServiceInterfaces(formatter: TextFormatter, serviceType: Protob
611
632
generateServiceHandlerInterface(formatter, serviceType, options);
612
633
formatter.writeLine('');
613
634
614
- generateServiceDefinitionInterface(formatter, serviceType);
635
+ generateServiceDefinitionInterface(formatter, serviceType, options );
615
636
}
616
637
617
638
function containsDefinition ( definitionType : typeof Protobuf . Type | typeof Protobuf . Enum , namespace : Protobuf . NamespaceBase ) : boolean {
@@ -645,7 +666,7 @@ function generateDefinitionImports(formatter: TextFormatter, namespace: Protobuf
645
666
function generateServiceImports ( formatter : TextFormatter , namespace : Protobuf . NamespaceBase , options : GeneratorOptions ) {
646
667
for ( const nested of namespace . nestedArray . sort ( compareName ) ) {
647
668
if ( nested instanceof Protobuf . Service ) {
648
- formatter . writeLine ( getImportLine ( nested ) ) ;
669
+ formatter . writeLine ( getImportLine ( nested , undefined , options ) ) ;
649
670
} else if (isNamespaceBase(nested) && ! ( nested instanceof Protobuf . Type ) && ! ( nested instanceof Protobuf . Enum ) ) {
650
671
generateServiceImports ( formatter , nested , options ) ;
651
672
}
@@ -776,7 +797,7 @@ async function runScript() {
776
797
. normalize ( [ 'includeDirs' , 'outDir' ] )
777
798
. array ( 'includeDirs' )
778
799
. boolean ( [ 'keepCase' , 'defaults' , 'arrays' , 'objects' , 'oneofs' , 'json' , 'verbose' , 'includeComments' ] )
779
- . string ( [ 'longs' , 'enums' , 'bytes' ] )
800
+ . string ( [ 'longs' , 'enums' , 'bytes' , 'inputTemplate' , 'outputTemplate' ] )
780
801
. default ( 'keepCase' , false )
781
802
. default ( 'defaults' , false )
782
803
. default ( 'arrays' , false )
@@ -787,6 +808,8 @@ async function runScript() {
787
808
. default ( 'longs' , 'Long' )
788
809
. default ( 'enums' , 'number' )
789
810
. default ( 'bytes' , 'Buffer' )
811
+ . default ( 'inputTemplate' , `${ templateStr } ` )
812
+ . default ( 'outputTemplate' , `${ templateStr } __Output` )
790
813
. coerce ( 'longs' , value => {
791
814
switch ( value ) {
792
815
case 'String' : return String ;
@@ -805,7 +828,8 @@ async function runScript() {
805
828
case 'String' : return String ;
806
829
default : return undefined ;
807
830
}
808
- } ) . alias ( {
831
+ } )
832
+ . alias ( {
809
833
includeDirs : 'I' ,
810
834
outDir : 'O' ,
811
835
verbose : 'v'
@@ -822,7 +846,9 @@ async function runScript() {
822
846
includeComments : 'Generate doc comments from comments in the original files' ,
823
847
includeDirs : 'Directories to search for included files' ,
824
848
outDir : 'Directory in which to output files' ,
825
- grpcLib : 'The gRPC implementation library that these types will be used with'
849
+ grpcLib : 'The gRPC implementation library that these types will be used with' ,
850
+ inputTemplate : 'Template for mapping input or "permissive" type names' ,
851
+ outputTemplate : 'Template for mapping output or "restricted" type names' ,
826
852
} ) . demandOption ( [ 'outDir' , 'grpcLib' ] )
827
853
. demand ( 1 )
828
854
. usage ( '$0 [options] filenames...' )
0 commit comments