@@ -33,6 +33,7 @@ import {
33
33
import {
34
34
indent
35
35
} from "./util" ;
36
+ import { Source , NodeKind , ImportStatement , DeclarationStatement , ExportStatement } from "./ast" ;
36
37
37
38
/** Walker base class. */
38
39
abstract class ExportsWalker {
@@ -140,6 +141,9 @@ export class NEARBindingsBuilder extends ExportsWalker {
140
141
private sb : string [ ] = [ ] ;
141
142
private generatedEncodeFunctions = new Set < string > ( ) ;
142
143
private generatedDecodeFunctions = new Set < string > ( ) ;
144
+ private exportedClasses : Class [ ] = [ ] ;
145
+ private exportedFunctions : Function [ ] = [ ] ;
146
+ private filesByImport = new Map < string , string > ( ) ;
143
147
144
148
static build ( program : Program ) : string {
145
149
return new NEARBindingsBuilder ( program ) . build ( ) ;
@@ -154,14 +158,33 @@ export class NEARBindingsBuilder extends ExportsWalker {
154
158
}
155
159
156
160
visitClass ( element : Class ) : void {
157
- // Do nothing
161
+ if ( ! element . is ( CommonFlags . EXPORT ) ) {
162
+ return ;
163
+ }
164
+ this . exportedClasses . push ( element ) ;
158
165
}
159
166
160
167
visitFunction ( element : Function ) : void {
168
+ if ( ! element . is ( CommonFlags . EXPORT ) ) {
169
+ return ;
170
+ }
171
+ this . exportedFunctions . push ( element ) ;
161
172
this . generateArgsParser ( element ) ;
162
173
this . generateWrapperFunction ( element ) ;
163
174
}
164
175
176
+ visitInterface ( element : Interface ) : void {
177
+ // Do nothing
178
+ }
179
+
180
+ visitField ( element : Field ) : void {
181
+ throw new Error ( "Shouldn't be called" ) ;
182
+ }
183
+
184
+ visitNamespace ( element : Element ) : void {
185
+ // Do nothing
186
+ }
187
+
165
188
private generateArgsParser ( element : Function ) {
166
189
let signature = element . signature ;
167
190
let fields = signature . parameterNames ? signature . parameterNames . map ( ( paramName , i ) => {
@@ -175,7 +198,7 @@ export class NEARBindingsBuilder extends ExportsWalker {
175
198
` ) ;
176
199
if ( signature . parameterNames ) {
177
200
fields . forEach ( ( field ) => {
178
- this . sb . push ( `__near_param_${ field . simpleName } : ${ field . type } ;` ) ;
201
+ this . sb . push ( `__near_param_${ field . simpleName } : ${ this . wrappedTypeName ( field . type ) } ;` ) ;
179
202
} ) ;
180
203
this . generateHandlerMethods ( "this.__near_param_" , fields ) ;
181
204
} else {
@@ -196,9 +219,9 @@ export class NEARBindingsBuilder extends ExportsWalker {
196
219
handler.decoder = new JSONDecoder<__near_ArgsParser_${ element . simpleName } >(handler);
197
220
handler.decoder.deserialize(json);` ) ;
198
221
if ( returnType . toString ( ) != "void" ) {
199
- this . sb . push ( `let result = ${ element . simpleName } (` ) ;
222
+ this . sb . push ( `let result = wrapped_ ${ element . simpleName } (` ) ;
200
223
} else {
201
- this . sb . push ( `${ element . simpleName } (` ) ;
224
+ this . sb . push ( `wrapped_ ${ element . simpleName } (` ) ;
202
225
}
203
226
if ( signature . parameterNames ) {
204
227
this . sb . push ( signature . parameterNames . map ( paramName => `handler.__near_param_${ paramName } ` ) . join ( "," ) ) ;
@@ -238,7 +261,7 @@ export class NEARBindingsBuilder extends ExportsWalker {
238
261
this . sb . push ( "setNull(name: string): void {" ) ;
239
262
fields . forEach ( ( field ) => {
240
263
this . sb . push ( `if (name == "${ field . simpleName } ") {
241
- ${ valuePrefix } ${ field . simpleName } = <${ field . type . toString ( ) } >null;
264
+ ${ valuePrefix } ${ field . simpleName } = <${ this . wrappedTypeName ( field . type ) } >null;
242
265
return;
243
266
}` ) ;
244
267
} ) ;
@@ -272,7 +295,7 @@ export class NEARBindingsBuilder extends ExportsWalker {
272
295
fields . forEach ( ( field ) => {
273
296
if ( ! ( field . type . toString ( ) in this . typeMapping ) ) {
274
297
this . sb . push ( `if (name == "${ field . simpleName } ") {
275
- ${ valuePrefix } ${ field . simpleName } = __near_decode_${ this . encodeType ( field . type ) } (this.buffer, this.decoder.state);
298
+ ${ valuePrefix } ${ field . simpleName } = < ${ field . type } > __near_decode_${ this . encodeType ( field . type ) } (this.buffer, this.decoder.state);
276
299
return false;
277
300
}` ) ;
278
301
}
@@ -295,7 +318,7 @@ export class NEARBindingsBuilder extends ExportsWalker {
295
318
}` ) ;
296
319
} else {
297
320
this . sb . push ( `pushObject(name: string): bool {
298
- ${ valuePrefix } .push(__near_decode_${ this . encodeType ( fieldType ) } (this.buffer, this.decoder.state));
321
+ ${ valuePrefix } .push(< ${ fieldType } > __near_decode_${ this . encodeType ( fieldType ) } (this.buffer, this.decoder.state));
299
322
return false;
300
323
}
301
324
pushArray(name: string): bool {
@@ -304,12 +327,13 @@ export class NEARBindingsBuilder extends ExportsWalker {
304
327
this.handledRoot = true;
305
328
return true;
306
329
}
307
- ${ valuePrefix } .push(__near_decode_${ this . encodeType ( fieldType ) } (this.buffer, this.decoder.state));
330
+ ${ valuePrefix } .push(< ${ fieldType } > __near_decode_${ this . encodeType ( fieldType ) } (this.buffer, this.decoder.state));
308
331
return false;
309
332
}` ) ;
310
333
}
311
334
}
312
335
336
+
313
337
private generateEncodeFunction ( type : Type ) {
314
338
if ( ! type . classReference ) {
315
339
return ;
@@ -321,12 +345,17 @@ export class NEARBindingsBuilder extends ExportsWalker {
321
345
}
322
346
this . generatedEncodeFunctions . add ( typeName ) ;
323
347
348
+ let methodName = `__near_encode_${ typeName } ` ;
349
+ if ( this . tryUsingImport ( type , methodName ) ) {
350
+ return ;
351
+ }
352
+
324
353
if ( this . isArrayType ( type ) ) {
325
354
// Array
326
355
this . generateEncodeFunction ( type . classReference . typeArguments ! [ 0 ] ) ;
327
356
328
357
this . sb . push ( `export function __near_encode_${ typeName } (
329
- value: ${ type . toString ( ) } ,
358
+ value: ${ this . wrappedTypeName ( type ) } ,
330
359
encoder: JSONEncoder): void {` ) ;
331
360
this . sb . push ( `for (let i = 0; i < value.length; i++) {` ) ;
332
361
this . generateFieldEncoder ( type . classReference . typeArguments ! [ 0 ] , "null" , "value[i]" ) ;
@@ -339,7 +368,7 @@ export class NEARBindingsBuilder extends ExportsWalker {
339
368
} ) ;
340
369
341
370
this . sb . push ( `export function __near_encode_${ typeName } (
342
- value: ${ type . toString ( ) } ,
371
+ value: ${ this . wrappedTypeName ( type ) } ,
343
372
encoder: JSONEncoder): void {` ) ;
344
373
this . getFields ( type . classReference ) . forEach ( ( field ) => {
345
374
let fieldType = field . type ;
@@ -352,13 +381,31 @@ export class NEARBindingsBuilder extends ExportsWalker {
352
381
this . sb . push ( "}" ) ;
353
382
}
354
383
384
+ private tryUsingImport ( type : Type , methodName : string ) : bool {
385
+ let importedFile = this . filesByImport . get ( type . classReference ! . simpleName ) ;
386
+ if ( importedFile ) {
387
+ if ( this . hasExport ( importedFile , methodName ) ) {
388
+ this . sb . push ( `import { ${ methodName } } from "${ importedFile } ";` ) ;
389
+ return true ;
390
+ }
391
+ }
392
+ return false ;
393
+ }
394
+
395
+ private hasExport ( importedFile : string , name : string ) : bool {
396
+ let importedSource = this . program . sources . filter (
397
+ s => "./" + s . normalizedPath == importedFile + ".ts" ) [ 0 ] ;
398
+
399
+ return this . getExports ( importedSource ) . filter ( d => d . name . text == name ) . length > 0 ;
400
+ }
401
+
355
402
private generateHandler ( type : Type ) {
356
403
let typeName = this . encodeType ( type ) ;
357
404
this . sb . push ( `export class __near_JSONHandler_${ typeName } extends ThrowingJSONHandler {
358
405
buffer: Uint8Array;
359
406
decoder: JSONDecoder<__near_JSONHandler_${ typeName } >;
360
407
handledRoot: boolean = false;
361
- value: ${ type } = new ${ type } ();` ) ;
408
+ value: ${ this . wrappedTypeName ( type ) } = new ${ this . wrappedTypeName ( type ) } ();` ) ;
362
409
if ( this . isArrayType ( type ) ) {
363
410
this . generateArrayHandlerMethods ( "this.value" , type . classReference ! . typeArguments ! [ 0 ] ) ;
364
411
} else {
@@ -367,6 +414,22 @@ export class NEARBindingsBuilder extends ExportsWalker {
367
414
this . sb . push ( "}\n" ) ;
368
415
}
369
416
417
+ private wrappedTypeName ( type : Type ) : string {
418
+ if ( ! type . classReference ) {
419
+ return type . toString ( ) ;
420
+ }
421
+ let cls = type . classReference ;
422
+ if ( this . exportedClasses . indexOf ( cls ) != - 1 ) {
423
+ return "wrapped_" + cls . simpleName ;
424
+ }
425
+ if ( cls . typeArguments && cls . typeArguments . length > 0 ) {
426
+ return cls . prototype . simpleName + "<" +
427
+ cls . typeArguments . map ( argType => this . wrappedTypeName ( argType ) ) . join ( ", " ) +
428
+ ">"
429
+ }
430
+ return cls . simpleName ;
431
+ }
432
+
370
433
private generateDecodeFunction ( type : Type ) {
371
434
if ( ! type . classReference ) {
372
435
return ;
@@ -378,6 +441,11 @@ export class NEARBindingsBuilder extends ExportsWalker {
378
441
}
379
442
this . generatedDecodeFunctions . add ( typeName ) ;
380
443
444
+ let methodName = `__near_decode_${ typeName } ` ;
445
+ if ( this . tryUsingImport ( type , methodName ) ) {
446
+ return ;
447
+ }
448
+
381
449
this . generateHandler ( type ) ;
382
450
if ( this . isArrayType ( type ) ) {
383
451
// Array
@@ -390,7 +458,7 @@ export class NEARBindingsBuilder extends ExportsWalker {
390
458
}
391
459
392
460
this . sb . push ( `export function __near_decode_${ typeName } (
393
- buffer: Uint8Array, state: DecoderState): ${ type } {
461
+ buffer: Uint8Array, state: DecoderState):${ this . wrappedTypeName ( type ) } {
394
462
let handler = new __near_JSONHandler_${ typeName } ();
395
463
handler.buffer = buffer;
396
464
handler.decoder = new JSONDecoder<__near_JSONHandler_${ typeName } >(handler);
@@ -406,7 +474,7 @@ export class NEARBindingsBuilder extends ExportsWalker {
406
474
let pushType = this . isArrayType ( fieldType ) ? "Array" : "Object" ;
407
475
this . sb . push ( `if (${ sourceExpr } != null) {
408
476
encoder.push${ pushType } (${ fieldExpr } );
409
- __near_encode_${ this . encodeType ( fieldType ) } (${ sourceExpr } , encoder);
477
+ __near_encode_${ this . encodeType ( fieldType ) } (< ${ fieldType } > ${ sourceExpr } , encoder);
410
478
encoder.pop${ pushType } ();
411
479
} else {
412
480
encoder.setNull(${ fieldExpr } );
@@ -444,23 +512,25 @@ export class NEARBindingsBuilder extends ExportsWalker {
444
512
return < Field [ ] > [ ...element . members . values ( ) ] . filter ( member => member instanceof Field ) ;
445
513
}
446
514
447
- visitInterface ( element : Interface ) : void {
448
- // Do nothing
449
- }
515
+ build ( ) : string {
516
+ let mainSource = this . program . sources
517
+ . filter ( s => s . normalizedPath . indexOf ( "~lib" ) != 0 ) [ 0 ] ;
518
+ this . copyImports ( mainSource ) ;
450
519
451
- visitField ( element : Field ) : void {
452
- throw new Error ( "Shouldn't be called" ) ;
453
- }
520
+ this . walk ( ) ;
454
521
455
- visitNamespace ( element : Element ) : void {
456
- // Do nothing
457
- }
522
+ this . exportedClasses . forEach ( c => {
523
+ this . generateEncodeFunction ( c . type ) ;
524
+ this . generateDecodeFunction ( c . type ) ;
525
+ } ) ;
458
526
459
- build ( ) : string {
460
- this . sb . push ( `
527
+ let allExported = ( < Element [ ] > this . exportedClasses ) . concat ( < Element [ ] > this . exportedFunctions ) ;
528
+ let allImportsStr = allExported . map ( c => `${ c . simpleName } as wrapped_${ c . simpleName } ` ) . join ( ", " ) ;
529
+ this . sb = [ `
461
530
import { near } from "./near";
462
531
import { JSONEncoder} from "./json/encoder"
463
532
import { JSONDecoder, ThrowingJSONHandler, DecoderState } from "./json/decoder"
533
+ import {${ allImportsStr } } from "./${ mainSource . normalizedPath . replace ( ".ts" , "" ) } ";
464
534
465
535
// Runtime functions
466
536
@external("env", "return_value")
@@ -469,13 +539,51 @@ export class NEARBindingsBuilder extends ExportsWalker {
469
539
declare function input_read_len(): u32;
470
540
@external("env", "input_read_into")
471
541
declare function input_read_into(ptr: usize): void;
472
- ` ) ;
473
- let mainSource = this . program . sources
474
- . filter ( s => s . normalizedPath . indexOf ( "~lib" ) != 0 ) [ 0 ] ;
475
- this . sb . push ( mainSource . text ) ;
476
- this . walk ( ) ;
542
+ ` ] . concat ( this . sb ) ;
543
+ this . exportedClasses . forEach ( c => {
544
+ this . sb . push ( `export class ${ c . simpleName } extends ${ this . wrappedTypeName ( c . type ) } {
545
+ static decode(json: Uint8Array): ${ c . simpleName } {
546
+ return <${ c . simpleName } >__near_decode_${ this . encodeType ( c . type ) } (json, null);
547
+ }
548
+
549
+ encode(): Uint8Array {
550
+ let encoder: JSONEncoder = new JSONEncoder();
551
+ encoder.pushObject(null);
552
+ __near_encode_${ this . encodeType ( c . type ) } (<${ c . simpleName } >this, encoder);
553
+ encoder.popObject();
554
+ return encoder.serialize();
555
+ }
556
+ }` ) ;
557
+ } )
477
558
return this . sb . join ( "\n" ) ;
478
559
}
560
+
561
+ private copyImports ( mainSource : Source ) : any {
562
+ this . getImports ( mainSource ) . forEach ( statement => {
563
+ if ( statement . declarations ) {
564
+ let declarationsStr = statement . declarations !
565
+ . map ( declaration => `${ declaration . externalName . text } as ${ declaration . name . text } ` )
566
+ . join ( "," ) ;
567
+ this . sb . push ( `import {${ declarationsStr } } from "${ statement . path . value } ";` ) ;
568
+ statement . declarations . forEach ( d => {
569
+ this . filesByImport . set ( d . name . text , statement . path . value ) ;
570
+ } ) ;
571
+ }
572
+ } ) ;
573
+ }
574
+
575
+ private getImports ( source : Source ) : ImportStatement [ ] {
576
+ return < ImportStatement [ ] > source . statements
577
+ . filter ( statement => statement . kind == NodeKind . IMPORT ) ;
578
+ }
579
+
580
+ private getExports ( source : Source ) : DeclarationStatement [ ] {
581
+ let declarations = < DeclarationStatement [ ] > source . statements
582
+ . filter ( statement =>
583
+ statement . kind == NodeKind . FUNCTIONDECLARATION ||
584
+ statement . kind == NodeKind . CLASSDECLARATION ) ;
585
+ return declarations . filter ( d => d . isTopLevelExport ) ;
586
+ }
479
587
}
480
588
481
589
/** A WebIDL definitions builder. */
0 commit comments