@tsonic/emitter 0.0.64 → 0.0.66
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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/core/semantic/imports.d.ts.map +1 -1
- package/dist/core/semantic/imports.js +42 -22
- package/dist/core/semantic/imports.js.map +1 -1
- package/dist/core/semantic/imports.test.js +94 -0
- package/dist/core/semantic/imports.test.js.map +1 -1
- package/dist/core/semantic/type-resolution.d.ts +10 -1
- package/dist/core/semantic/type-resolution.d.ts.map +1 -1
- package/dist/core/semantic/type-resolution.js +14 -6
- package/dist/core/semantic/type-resolution.js.map +1 -1
- package/dist/emitter-types/core.d.ts +1 -1
- package/dist/emitter-types/core.d.ts.map +1 -1
- package/dist/expressions/access.d.ts.map +1 -1
- package/dist/expressions/access.js +107 -22
- package/dist/expressions/access.js.map +1 -1
- package/dist/expressions/calls/call-emitter.d.ts.map +1 -1
- package/dist/expressions/calls/call-emitter.js +30 -126
- package/dist/expressions/calls/call-emitter.js.map +1 -1
- package/dist/expressions/index.test.js +304 -129
- package/dist/expressions/index.test.js.map +1 -1
- package/dist/json-aot-generic.test.js +2 -0
- package/dist/json-aot-generic.test.js.map +1 -1
- package/dist/statements/blocks.d.ts.map +1 -1
- package/dist/statements/blocks.js +44 -17
- package/dist/statements/blocks.js.map +1 -1
- package/dist/statements/index.test.js +225 -0
- package/dist/statements/index.test.js.map +1 -1
- package/dist/types/references.d.ts.map +1 -1
- package/dist/types/references.js +27 -5
- package/dist/types/references.js.map +1 -1
- package/dist/types/references.test.js +122 -1
- package/dist/types/references.test.js.map +1 -1
- package/package.json +2 -2
|
@@ -217,6 +217,7 @@ describe("Expression Emission", () => {
|
|
|
217
217
|
isOptional: false,
|
|
218
218
|
// Hierarchical member binding from manifest
|
|
219
219
|
memberBinding: {
|
|
220
|
+
kind: "method",
|
|
220
221
|
assembly: "System.Linq",
|
|
221
222
|
type: "System.Linq.Enumerable",
|
|
222
223
|
member: "SelectMany",
|
|
@@ -237,6 +238,54 @@ describe("Expression Emission", () => {
|
|
|
237
238
|
// No using statements
|
|
238
239
|
expect(result).not.to.include("using System.Linq");
|
|
239
240
|
});
|
|
241
|
+
it("should emit global static calls through member binding type for surface globals", () => {
|
|
242
|
+
const module = {
|
|
243
|
+
kind: "module",
|
|
244
|
+
filePath: "/src/test.ts",
|
|
245
|
+
namespace: "MyApp",
|
|
246
|
+
className: "test",
|
|
247
|
+
isStaticContainer: true,
|
|
248
|
+
imports: [],
|
|
249
|
+
body: [
|
|
250
|
+
{
|
|
251
|
+
kind: "expressionStatement",
|
|
252
|
+
expression: {
|
|
253
|
+
kind: "call",
|
|
254
|
+
callee: {
|
|
255
|
+
kind: "memberAccess",
|
|
256
|
+
object: {
|
|
257
|
+
kind: "identifier",
|
|
258
|
+
name: "Array",
|
|
259
|
+
inferredType: {
|
|
260
|
+
kind: "referenceType",
|
|
261
|
+
name: "ArrayConstructor",
|
|
262
|
+
},
|
|
263
|
+
resolvedClrType: "Tsonic.JSRuntime.JSArray`1",
|
|
264
|
+
resolvedAssembly: "Tsonic.JSRuntime",
|
|
265
|
+
csharpName: "JSArray",
|
|
266
|
+
},
|
|
267
|
+
property: "from",
|
|
268
|
+
isComputed: false,
|
|
269
|
+
isOptional: false,
|
|
270
|
+
memberBinding: {
|
|
271
|
+
kind: "method",
|
|
272
|
+
assembly: "Tsonic.JSRuntime",
|
|
273
|
+
type: "Tsonic.JSRuntime.JSArrayStatics",
|
|
274
|
+
member: "from",
|
|
275
|
+
isExtensionMethod: false,
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
arguments: [{ kind: "literal", value: "abc" }],
|
|
279
|
+
isOptional: false,
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
],
|
|
283
|
+
exports: [],
|
|
284
|
+
};
|
|
285
|
+
const result = emitModule(module);
|
|
286
|
+
expect(result).to.include('global::Tsonic.JSRuntime.JSArrayStatics.from("abc")');
|
|
287
|
+
expect(result).not.to.include("global::Tsonic.JSRuntime.JSArray.from");
|
|
288
|
+
});
|
|
240
289
|
it("should escape C# keywords in hierarchical member bindings", () => {
|
|
241
290
|
const module = {
|
|
242
291
|
kind: "module",
|
|
@@ -263,6 +312,7 @@ describe("Expression Emission", () => {
|
|
|
263
312
|
isComputed: false,
|
|
264
313
|
isOptional: false,
|
|
265
314
|
memberBinding: {
|
|
315
|
+
kind: "method",
|
|
266
316
|
assembly: "express",
|
|
267
317
|
type: "Express.Express",
|
|
268
318
|
member: "static",
|
|
@@ -290,6 +340,7 @@ describe("Expression Emission", () => {
|
|
|
290
340
|
isComputed: false,
|
|
291
341
|
isOptional: false,
|
|
292
342
|
memberBinding: {
|
|
343
|
+
kind: "property",
|
|
293
344
|
assembly: "express",
|
|
294
345
|
type: "Express.Request",
|
|
295
346
|
member: "params",
|
|
@@ -332,6 +383,7 @@ describe("Expression Emission", () => {
|
|
|
332
383
|
isComputed: false,
|
|
333
384
|
isOptional: false,
|
|
334
385
|
memberBinding: {
|
|
386
|
+
kind: "method",
|
|
335
387
|
assembly: "Tsonic.JSRuntime",
|
|
336
388
|
type: "Tsonic.JSRuntime.String",
|
|
337
389
|
member: "split",
|
|
@@ -349,7 +401,7 @@ describe("Expression Emission", () => {
|
|
|
349
401
|
expect(result).to.include('global::Tsonic.JSRuntime.String.split(path, "/")');
|
|
350
402
|
expect(result).not.to.include("path.split");
|
|
351
403
|
});
|
|
352
|
-
it("should
|
|
404
|
+
it("should lower numeric wrapper extension methods through surface bindings", () => {
|
|
353
405
|
const module = {
|
|
354
406
|
kind: "module",
|
|
355
407
|
filePath: "/src/test.ts",
|
|
@@ -366,95 +418,19 @@ describe("Expression Emission", () => {
|
|
|
366
418
|
kind: "memberAccess",
|
|
367
419
|
object: {
|
|
368
420
|
kind: "identifier",
|
|
369
|
-
name: "
|
|
370
|
-
inferredType: {
|
|
371
|
-
kind: "arrayType",
|
|
372
|
-
elementType: { kind: "primitiveType", name: "int" },
|
|
373
|
-
},
|
|
421
|
+
name: "value",
|
|
422
|
+
inferredType: { kind: "primitiveType", name: "number" },
|
|
374
423
|
},
|
|
375
|
-
property: "
|
|
376
|
-
isComputed: false,
|
|
377
|
-
isOptional: false,
|
|
378
|
-
},
|
|
379
|
-
arguments: [{ kind: "identifier", name: "doubleIt" }],
|
|
380
|
-
isOptional: false,
|
|
381
|
-
inferredType: {
|
|
382
|
-
kind: "arrayType",
|
|
383
|
-
elementType: { kind: "primitiveType", name: "int" },
|
|
384
|
-
},
|
|
385
|
-
},
|
|
386
|
-
},
|
|
387
|
-
],
|
|
388
|
-
exports: [],
|
|
389
|
-
};
|
|
390
|
-
const result = emitModule(module, { surface: "js" });
|
|
391
|
-
expect(result).to.include("global::System.Linq.Enumerable.Select(nums, doubleIt)");
|
|
392
|
-
expect(result).to.include("global::System.Linq.Enumerable.ToArray(");
|
|
393
|
-
expect(result).not.to.include("new global::Tsonic.JSRuntime.JSArray");
|
|
394
|
-
});
|
|
395
|
-
it("should rewrite js-surface reduce/reduceRight/join via deterministic CLR calls", () => {
|
|
396
|
-
const numsExpr = {
|
|
397
|
-
kind: "identifier",
|
|
398
|
-
name: "nums",
|
|
399
|
-
inferredType: {
|
|
400
|
-
kind: "arrayType",
|
|
401
|
-
elementType: { kind: "primitiveType", name: "int" },
|
|
402
|
-
},
|
|
403
|
-
};
|
|
404
|
-
const module = {
|
|
405
|
-
kind: "module",
|
|
406
|
-
filePath: "/src/test.ts",
|
|
407
|
-
namespace: "MyApp",
|
|
408
|
-
className: "test",
|
|
409
|
-
isStaticContainer: true,
|
|
410
|
-
imports: [],
|
|
411
|
-
body: [
|
|
412
|
-
{
|
|
413
|
-
kind: "expressionStatement",
|
|
414
|
-
expression: {
|
|
415
|
-
kind: "call",
|
|
416
|
-
callee: {
|
|
417
|
-
kind: "memberAccess",
|
|
418
|
-
object: numsExpr,
|
|
419
|
-
property: "reduce",
|
|
420
|
-
isComputed: false,
|
|
421
|
-
isOptional: false,
|
|
422
|
-
},
|
|
423
|
-
arguments: [
|
|
424
|
-
{ kind: "identifier", name: "sum" },
|
|
425
|
-
{ kind: "literal", value: 0 },
|
|
426
|
-
],
|
|
427
|
-
isOptional: false,
|
|
428
|
-
},
|
|
429
|
-
},
|
|
430
|
-
{
|
|
431
|
-
kind: "expressionStatement",
|
|
432
|
-
expression: {
|
|
433
|
-
kind: "call",
|
|
434
|
-
callee: {
|
|
435
|
-
kind: "memberAccess",
|
|
436
|
-
object: numsExpr,
|
|
437
|
-
property: "reduceRight",
|
|
438
|
-
isComputed: false,
|
|
439
|
-
isOptional: false,
|
|
440
|
-
},
|
|
441
|
-
arguments: [
|
|
442
|
-
{ kind: "identifier", name: "sum" },
|
|
443
|
-
{ kind: "literal", value: 0 },
|
|
444
|
-
],
|
|
445
|
-
isOptional: false,
|
|
446
|
-
},
|
|
447
|
-
},
|
|
448
|
-
{
|
|
449
|
-
kind: "expressionStatement",
|
|
450
|
-
expression: {
|
|
451
|
-
kind: "call",
|
|
452
|
-
callee: {
|
|
453
|
-
kind: "memberAccess",
|
|
454
|
-
object: numsExpr,
|
|
455
|
-
property: "join",
|
|
424
|
+
property: "toString",
|
|
456
425
|
isComputed: false,
|
|
457
426
|
isOptional: false,
|
|
427
|
+
memberBinding: {
|
|
428
|
+
kind: "method",
|
|
429
|
+
assembly: "Tsonic.JSRuntime",
|
|
430
|
+
type: "Tsonic.JSRuntime.Number",
|
|
431
|
+
member: "toString",
|
|
432
|
+
isExtensionMethod: true,
|
|
433
|
+
},
|
|
458
434
|
},
|
|
459
435
|
arguments: [],
|
|
460
436
|
isOptional: false,
|
|
@@ -463,11 +439,9 @@ describe("Expression Emission", () => {
|
|
|
463
439
|
],
|
|
464
440
|
exports: [],
|
|
465
441
|
};
|
|
466
|
-
const result = emitModule(module
|
|
467
|
-
expect(result).to.include("global::
|
|
468
|
-
expect(result).to.include("
|
|
469
|
-
expect(result).to.include('global::System.String.Join(",", nums)');
|
|
470
|
-
expect(result).not.to.include("new global::Tsonic.JSRuntime.JSArray");
|
|
442
|
+
const result = emitModule(module);
|
|
443
|
+
expect(result).to.include("global::Tsonic.JSRuntime.Number.toString(value)");
|
|
444
|
+
expect(result).not.to.include("value.toString()");
|
|
471
445
|
});
|
|
472
446
|
it("should emit fluent LINQ extension method calls (required for EF query precompilation)", () => {
|
|
473
447
|
const module = {
|
|
@@ -493,6 +467,7 @@ describe("Expression Emission", () => {
|
|
|
493
467
|
isComputed: false,
|
|
494
468
|
isOptional: false,
|
|
495
469
|
memberBinding: {
|
|
470
|
+
kind: "method",
|
|
496
471
|
assembly: "System.Linq",
|
|
497
472
|
type: "System.Linq.Queryable",
|
|
498
473
|
member: "Count",
|
|
@@ -542,6 +517,7 @@ describe("Expression Emission", () => {
|
|
|
542
517
|
isComputed: false,
|
|
543
518
|
isOptional: false,
|
|
544
519
|
memberBinding: {
|
|
520
|
+
kind: "method",
|
|
545
521
|
assembly: "System.Linq",
|
|
546
522
|
type: "System.Linq.Queryable",
|
|
547
523
|
member: m.member,
|
|
@@ -586,6 +562,7 @@ describe("Expression Emission", () => {
|
|
|
586
562
|
isComputed: false,
|
|
587
563
|
isOptional: false,
|
|
588
564
|
memberBinding: {
|
|
565
|
+
kind: "method",
|
|
589
566
|
assembly: "System.Linq",
|
|
590
567
|
type: "System.Linq.Enumerable",
|
|
591
568
|
member: "ToArray",
|
|
@@ -611,6 +588,7 @@ describe("Expression Emission", () => {
|
|
|
611
588
|
isComputed: false,
|
|
612
589
|
isOptional: false,
|
|
613
590
|
memberBinding: {
|
|
591
|
+
kind: "method",
|
|
614
592
|
assembly: "System.Linq",
|
|
615
593
|
type: "System.Linq.Enumerable",
|
|
616
594
|
member: "ToList",
|
|
@@ -637,6 +615,7 @@ describe("Expression Emission", () => {
|
|
|
637
615
|
isComputed: false,
|
|
638
616
|
isOptional: false,
|
|
639
617
|
memberBinding: {
|
|
618
|
+
kind: "method",
|
|
640
619
|
assembly: "System.Linq",
|
|
641
620
|
type: "System.Linq.Enumerable",
|
|
642
621
|
member: "Where",
|
|
@@ -683,6 +662,7 @@ describe("Expression Emission", () => {
|
|
|
683
662
|
isComputed: false,
|
|
684
663
|
isOptional: false,
|
|
685
664
|
memberBinding: {
|
|
665
|
+
kind: "method",
|
|
686
666
|
assembly: "Microsoft.EntityFrameworkCore",
|
|
687
667
|
type: "Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions",
|
|
688
668
|
member: "AsNoTracking",
|
|
@@ -729,6 +709,7 @@ describe("Expression Emission", () => {
|
|
|
729
709
|
isComputed: false,
|
|
730
710
|
isOptional: false,
|
|
731
711
|
memberBinding: {
|
|
712
|
+
kind: "method",
|
|
732
713
|
assembly: "System.Linq",
|
|
733
714
|
type: "System.Linq.Enumerable",
|
|
734
715
|
member: "ToList",
|
|
@@ -742,6 +723,7 @@ describe("Expression Emission", () => {
|
|
|
742
723
|
isComputed: false,
|
|
743
724
|
isOptional: false,
|
|
744
725
|
memberBinding: {
|
|
726
|
+
kind: "method",
|
|
745
727
|
assembly: "System.Linq",
|
|
746
728
|
type: "System.Linq.Enumerable",
|
|
747
729
|
member: "ToArray",
|
|
@@ -1033,6 +1015,7 @@ describe("Expression Emission", () => {
|
|
|
1033
1015
|
isComputed: false,
|
|
1034
1016
|
isOptional: false,
|
|
1035
1017
|
memberBinding: {
|
|
1018
|
+
kind: "method",
|
|
1036
1019
|
assembly: "MyLib",
|
|
1037
1020
|
type: "MyLib.Math",
|
|
1038
1021
|
member: "Add",
|
|
@@ -1085,7 +1068,7 @@ describe("Expression Emission", () => {
|
|
|
1085
1068
|
// Should emit regular property access
|
|
1086
1069
|
expect(result).to.include("obj.property");
|
|
1087
1070
|
});
|
|
1088
|
-
it("should emit
|
|
1071
|
+
it("should emit member-binding CLR name exactly (no surface rewrite)", () => {
|
|
1089
1072
|
const module = {
|
|
1090
1073
|
kind: "module",
|
|
1091
1074
|
filePath: "/src/test.ts",
|
|
@@ -1100,33 +1083,187 @@ describe("Expression Emission", () => {
|
|
|
1100
1083
|
kind: "memberAccess",
|
|
1101
1084
|
object: {
|
|
1102
1085
|
kind: "identifier",
|
|
1103
|
-
name: "
|
|
1086
|
+
name: "value",
|
|
1087
|
+
inferredType: { kind: "primitiveType", name: "string" },
|
|
1088
|
+
},
|
|
1089
|
+
property: "length",
|
|
1090
|
+
isComputed: false,
|
|
1091
|
+
isOptional: false,
|
|
1092
|
+
memberBinding: {
|
|
1093
|
+
kind: "property",
|
|
1094
|
+
assembly: "System.Private.CoreLib",
|
|
1095
|
+
type: "System.String",
|
|
1096
|
+
member: "Length",
|
|
1097
|
+
},
|
|
1098
|
+
},
|
|
1099
|
+
},
|
|
1100
|
+
],
|
|
1101
|
+
exports: [],
|
|
1102
|
+
};
|
|
1103
|
+
const result = emitModule(module);
|
|
1104
|
+
expect(result).to.include("value.Length");
|
|
1105
|
+
expect(result).not.to.include("value.length");
|
|
1106
|
+
});
|
|
1107
|
+
it("should emit global simple-binding member access as static CLR access", () => {
|
|
1108
|
+
const module = {
|
|
1109
|
+
kind: "module",
|
|
1110
|
+
filePath: "/src/test.ts",
|
|
1111
|
+
namespace: "MyApp",
|
|
1112
|
+
className: "test",
|
|
1113
|
+
isStaticContainer: true,
|
|
1114
|
+
imports: [],
|
|
1115
|
+
body: [
|
|
1116
|
+
{
|
|
1117
|
+
kind: "expressionStatement",
|
|
1118
|
+
expression: {
|
|
1119
|
+
kind: "memberAccess",
|
|
1120
|
+
object: {
|
|
1121
|
+
kind: "identifier",
|
|
1122
|
+
name: "console",
|
|
1123
|
+
inferredType: { kind: "referenceType", name: "Console" },
|
|
1124
|
+
},
|
|
1125
|
+
property: "log",
|
|
1126
|
+
isComputed: false,
|
|
1127
|
+
isOptional: false,
|
|
1128
|
+
memberBinding: {
|
|
1129
|
+
kind: "method",
|
|
1130
|
+
assembly: "Tsonic.JSRuntime",
|
|
1131
|
+
type: "Tsonic.JSRuntime.console",
|
|
1132
|
+
member: "log",
|
|
1133
|
+
},
|
|
1134
|
+
},
|
|
1135
|
+
},
|
|
1136
|
+
],
|
|
1137
|
+
exports: [],
|
|
1138
|
+
};
|
|
1139
|
+
const result = emitModule(module);
|
|
1140
|
+
expect(result).to.include("global::Tsonic.JSRuntime.console.log");
|
|
1141
|
+
});
|
|
1142
|
+
it("should keep local member access when identifier case differs from CLR type leaf", () => {
|
|
1143
|
+
const module = {
|
|
1144
|
+
kind: "module",
|
|
1145
|
+
filePath: "/src/test.ts",
|
|
1146
|
+
namespace: "MyApp",
|
|
1147
|
+
className: "test",
|
|
1148
|
+
isStaticContainer: true,
|
|
1149
|
+
imports: [],
|
|
1150
|
+
body: [
|
|
1151
|
+
{
|
|
1152
|
+
kind: "expressionStatement",
|
|
1153
|
+
expression: {
|
|
1154
|
+
kind: "memberAccess",
|
|
1155
|
+
object: {
|
|
1156
|
+
kind: "identifier",
|
|
1157
|
+
name: "entity",
|
|
1104
1158
|
inferredType: {
|
|
1105
|
-
kind: "
|
|
1106
|
-
|
|
1159
|
+
kind: "referenceType",
|
|
1160
|
+
name: "Entity",
|
|
1161
|
+
resolvedClrType: "Acme.Core.Entity",
|
|
1107
1162
|
},
|
|
1108
1163
|
},
|
|
1164
|
+
property: "Maybe",
|
|
1165
|
+
isComputed: false,
|
|
1166
|
+
isOptional: false,
|
|
1167
|
+
memberBinding: {
|
|
1168
|
+
kind: "property",
|
|
1169
|
+
assembly: "Acme.Core",
|
|
1170
|
+
type: "Acme.Core.Entity",
|
|
1171
|
+
member: "Maybe",
|
|
1172
|
+
},
|
|
1173
|
+
},
|
|
1174
|
+
},
|
|
1175
|
+
],
|
|
1176
|
+
exports: [],
|
|
1177
|
+
};
|
|
1178
|
+
const result = emitModule(module);
|
|
1179
|
+
expect(result).to.include("entity.Maybe");
|
|
1180
|
+
expect(result).not.to.include("global::Acme.Core.Entity.Maybe");
|
|
1181
|
+
});
|
|
1182
|
+
it("should emit extension member value access as static invocation", () => {
|
|
1183
|
+
const module = {
|
|
1184
|
+
kind: "module",
|
|
1185
|
+
filePath: "/src/test.ts",
|
|
1186
|
+
namespace: "MyApp",
|
|
1187
|
+
className: "test",
|
|
1188
|
+
isStaticContainer: true,
|
|
1189
|
+
imports: [],
|
|
1190
|
+
body: [
|
|
1191
|
+
{
|
|
1192
|
+
kind: "expressionStatement",
|
|
1193
|
+
expression: {
|
|
1194
|
+
kind: "memberAccess",
|
|
1195
|
+
object: {
|
|
1196
|
+
kind: "identifier",
|
|
1197
|
+
name: "value",
|
|
1198
|
+
inferredType: { kind: "primitiveType", name: "string" },
|
|
1199
|
+
},
|
|
1109
1200
|
property: "length",
|
|
1110
1201
|
isComputed: false,
|
|
1111
1202
|
isOptional: false,
|
|
1112
1203
|
memberBinding: {
|
|
1204
|
+
kind: "method",
|
|
1113
1205
|
assembly: "Tsonic.JSRuntime",
|
|
1114
|
-
type: "Tsonic.JSRuntime.
|
|
1206
|
+
type: "Tsonic.JSRuntime.String",
|
|
1115
1207
|
member: "length",
|
|
1208
|
+
isExtensionMethod: true,
|
|
1116
1209
|
},
|
|
1117
1210
|
},
|
|
1118
1211
|
},
|
|
1119
1212
|
],
|
|
1120
1213
|
exports: [],
|
|
1121
1214
|
};
|
|
1122
|
-
const
|
|
1123
|
-
expect(
|
|
1124
|
-
expect(
|
|
1125
|
-
const nodeResult = emitModule(module, { surface: "nodejs" });
|
|
1126
|
-
expect(nodeResult).to.include("nums.Length");
|
|
1127
|
-
expect(nodeResult).not.to.include("nums.length");
|
|
1215
|
+
const result = emitModule(module);
|
|
1216
|
+
expect(result).to.include("global::Tsonic.JSRuntime.String.length(value)");
|
|
1217
|
+
expect(result).not.to.include("value.length");
|
|
1128
1218
|
});
|
|
1129
|
-
it("should emit array
|
|
1219
|
+
it("should emit array wrapper call for non-System.Array member bindings", () => {
|
|
1220
|
+
const module = {
|
|
1221
|
+
kind: "module",
|
|
1222
|
+
filePath: "/src/test.ts",
|
|
1223
|
+
namespace: "MyApp",
|
|
1224
|
+
className: "test",
|
|
1225
|
+
isStaticContainer: true,
|
|
1226
|
+
imports: [],
|
|
1227
|
+
body: [
|
|
1228
|
+
{
|
|
1229
|
+
kind: "expressionStatement",
|
|
1230
|
+
expression: {
|
|
1231
|
+
kind: "call",
|
|
1232
|
+
callee: {
|
|
1233
|
+
kind: "memberAccess",
|
|
1234
|
+
object: {
|
|
1235
|
+
kind: "identifier",
|
|
1236
|
+
name: "nums",
|
|
1237
|
+
inferredType: {
|
|
1238
|
+
kind: "arrayType",
|
|
1239
|
+
elementType: { kind: "primitiveType", name: "int" },
|
|
1240
|
+
},
|
|
1241
|
+
},
|
|
1242
|
+
property: "map",
|
|
1243
|
+
isComputed: false,
|
|
1244
|
+
isOptional: false,
|
|
1245
|
+
memberBinding: {
|
|
1246
|
+
kind: "method",
|
|
1247
|
+
assembly: "Tsonic.JSRuntime",
|
|
1248
|
+
type: "Tsonic.JSRuntime.JSArray`1",
|
|
1249
|
+
member: "map",
|
|
1250
|
+
},
|
|
1251
|
+
},
|
|
1252
|
+
arguments: [{ kind: "identifier", name: "project" }],
|
|
1253
|
+
isOptional: false,
|
|
1254
|
+
inferredType: {
|
|
1255
|
+
kind: "arrayType",
|
|
1256
|
+
elementType: { kind: "primitiveType", name: "int" },
|
|
1257
|
+
},
|
|
1258
|
+
},
|
|
1259
|
+
},
|
|
1260
|
+
],
|
|
1261
|
+
exports: [],
|
|
1262
|
+
};
|
|
1263
|
+
const result = emitModule(module);
|
|
1264
|
+
expect(result).to.include("new global::Tsonic.JSRuntime.JSArray<int>(nums).map(project).toArray()");
|
|
1265
|
+
});
|
|
1266
|
+
it("should emit array wrapper property access for non-System.Array member bindings", () => {
|
|
1130
1267
|
const module = {
|
|
1131
1268
|
kind: "module",
|
|
1132
1269
|
filePath: "/src/test.ts",
|
|
@@ -1150,19 +1287,21 @@ describe("Expression Emission", () => {
|
|
|
1150
1287
|
property: "length",
|
|
1151
1288
|
isComputed: false,
|
|
1152
1289
|
isOptional: false,
|
|
1290
|
+
memberBinding: {
|
|
1291
|
+
kind: "property",
|
|
1292
|
+
assembly: "Tsonic.JSRuntime",
|
|
1293
|
+
type: "Tsonic.JSRuntime.JSArray`1",
|
|
1294
|
+
member: "length",
|
|
1295
|
+
},
|
|
1153
1296
|
},
|
|
1154
1297
|
},
|
|
1155
1298
|
],
|
|
1156
1299
|
exports: [],
|
|
1157
1300
|
};
|
|
1158
|
-
const
|
|
1159
|
-
expect(
|
|
1160
|
-
expect(jsResult).not.to.include("nums.length");
|
|
1161
|
-
const nodeResult = emitModule(module, { surface: "nodejs" });
|
|
1162
|
-
expect(nodeResult).to.include("nums.Length");
|
|
1163
|
-
expect(nodeResult).not.to.include("nums.length");
|
|
1301
|
+
const result = emitModule(module);
|
|
1302
|
+
expect(result).to.include("new global::Tsonic.JSRuntime.JSArray<int>(nums).length");
|
|
1164
1303
|
});
|
|
1165
|
-
it("should emit array
|
|
1304
|
+
it("should emit array wrapper property access for nullable array receivers", () => {
|
|
1166
1305
|
const module = {
|
|
1167
1306
|
kind: "module",
|
|
1168
1307
|
filePath: "/src/test.ts",
|
|
@@ -1177,29 +1316,36 @@ describe("Expression Emission", () => {
|
|
|
1177
1316
|
kind: "memberAccess",
|
|
1178
1317
|
object: {
|
|
1179
1318
|
kind: "identifier",
|
|
1180
|
-
name: "
|
|
1319
|
+
name: "maybeNums",
|
|
1181
1320
|
inferredType: {
|
|
1182
|
-
kind: "
|
|
1183
|
-
|
|
1184
|
-
|
|
1321
|
+
kind: "unionType",
|
|
1322
|
+
types: [
|
|
1323
|
+
{
|
|
1324
|
+
kind: "arrayType",
|
|
1325
|
+
elementType: { kind: "primitiveType", name: "int" },
|
|
1326
|
+
},
|
|
1327
|
+
{ kind: "primitiveType", name: "undefined" },
|
|
1328
|
+
],
|
|
1185
1329
|
},
|
|
1186
1330
|
},
|
|
1187
1331
|
property: "length",
|
|
1188
1332
|
isComputed: false,
|
|
1189
1333
|
isOptional: false,
|
|
1334
|
+
memberBinding: {
|
|
1335
|
+
kind: "property",
|
|
1336
|
+
assembly: "Tsonic.JSRuntime",
|
|
1337
|
+
type: "Tsonic.JSRuntime.JSArray`1",
|
|
1338
|
+
member: "length",
|
|
1339
|
+
},
|
|
1190
1340
|
},
|
|
1191
1341
|
},
|
|
1192
1342
|
],
|
|
1193
1343
|
exports: [],
|
|
1194
1344
|
};
|
|
1195
|
-
const
|
|
1196
|
-
expect(
|
|
1197
|
-
expect(jsResult).not.to.include("nums.length");
|
|
1198
|
-
const nodeResult = emitModule(module, { surface: "nodejs" });
|
|
1199
|
-
expect(nodeResult).to.include("nums.Length");
|
|
1200
|
-
expect(nodeResult).not.to.include("nums.length");
|
|
1345
|
+
const result = emitModule(module);
|
|
1346
|
+
expect(result).to.include("new global::Tsonic.JSRuntime.JSArray<int>(maybeNums).length");
|
|
1201
1347
|
});
|
|
1202
|
-
it("should emit array
|
|
1348
|
+
it("should emit array wrapper property access for ReadonlyArray receivers", () => {
|
|
1203
1349
|
const module = {
|
|
1204
1350
|
kind: "module",
|
|
1205
1351
|
filePath: "/src/test.ts",
|
|
@@ -1225,8 +1371,9 @@ describe("Expression Emission", () => {
|
|
|
1225
1371
|
isComputed: false,
|
|
1226
1372
|
isOptional: false,
|
|
1227
1373
|
memberBinding: {
|
|
1374
|
+
kind: "property",
|
|
1228
1375
|
assembly: "Tsonic.JSRuntime",
|
|
1229
|
-
type: "Tsonic.JSRuntime.JSArray",
|
|
1376
|
+
type: "Tsonic.JSRuntime.JSArray`1",
|
|
1230
1377
|
member: "length",
|
|
1231
1378
|
},
|
|
1232
1379
|
},
|
|
@@ -1234,12 +1381,37 @@ describe("Expression Emission", () => {
|
|
|
1234
1381
|
],
|
|
1235
1382
|
exports: [],
|
|
1236
1383
|
};
|
|
1237
|
-
const
|
|
1238
|
-
expect(
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1384
|
+
const result = emitModule(module);
|
|
1385
|
+
expect(result).to.include("new global::Tsonic.JSRuntime.JSArray<int>(nums).length");
|
|
1386
|
+
});
|
|
1387
|
+
it("should preserve source member name when no CLR member binding exists", () => {
|
|
1388
|
+
const module = {
|
|
1389
|
+
kind: "module",
|
|
1390
|
+
filePath: "/src/test.ts",
|
|
1391
|
+
namespace: "MyApp",
|
|
1392
|
+
className: "test",
|
|
1393
|
+
isStaticContainer: true,
|
|
1394
|
+
imports: [],
|
|
1395
|
+
body: [
|
|
1396
|
+
{
|
|
1397
|
+
kind: "expressionStatement",
|
|
1398
|
+
expression: {
|
|
1399
|
+
kind: "memberAccess",
|
|
1400
|
+
object: {
|
|
1401
|
+
kind: "identifier",
|
|
1402
|
+
name: "value",
|
|
1403
|
+
inferredType: { kind: "primitiveType", name: "string" },
|
|
1404
|
+
},
|
|
1405
|
+
property: "length",
|
|
1406
|
+
isComputed: false,
|
|
1407
|
+
isOptional: false,
|
|
1408
|
+
},
|
|
1409
|
+
},
|
|
1410
|
+
],
|
|
1411
|
+
exports: [],
|
|
1412
|
+
};
|
|
1413
|
+
const result = emitModule(module);
|
|
1414
|
+
expect(result).to.include("value.length");
|
|
1243
1415
|
});
|
|
1244
1416
|
it("should project CLR Union_n member access deterministically", () => {
|
|
1245
1417
|
const unionReference = {
|
|
@@ -1323,6 +1495,7 @@ describe("Expression Emission", () => {
|
|
|
1323
1495
|
isComputed: false,
|
|
1324
1496
|
isOptional: false,
|
|
1325
1497
|
memberBinding: {
|
|
1498
|
+
kind: "property",
|
|
1326
1499
|
assembly: "MyApp",
|
|
1327
1500
|
type: "MyApp.Ok",
|
|
1328
1501
|
member: "success",
|
|
@@ -1342,6 +1515,7 @@ describe("Expression Emission", () => {
|
|
|
1342
1515
|
isComputed: false,
|
|
1343
1516
|
isOptional: false,
|
|
1344
1517
|
memberBinding: {
|
|
1518
|
+
kind: "property",
|
|
1345
1519
|
assembly: "MyApp",
|
|
1346
1520
|
type: "MyApp.Err",
|
|
1347
1521
|
member: "error",
|
|
@@ -1361,6 +1535,7 @@ describe("Expression Emission", () => {
|
|
|
1361
1535
|
isComputed: false,
|
|
1362
1536
|
isOptional: false,
|
|
1363
1537
|
memberBinding: {
|
|
1538
|
+
kind: "property",
|
|
1364
1539
|
assembly: "MyApp",
|
|
1365
1540
|
type: "MyApp.Ok",
|
|
1366
1541
|
member: "data",
|