Skip to content

Commit 6459564

Browse files
committed
feat: Add ability to configure if marhsal and/or unmarshal method should be generated when using TSMessageAttribute + generated TS messages are now in the same namespace as where they are declared in C#
1 parent aa3e6e9 commit 6459564

File tree

50 files changed

+1013
-907
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1013
-907
lines changed

src/SourceGenerators/Uno.UI.SourceGenerators/Helpers/SymbolExtensions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,5 +568,17 @@ public static string GetFullyQualifiedType(this ITypeSymbol type)
568568

569569
return type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
570570
}
571+
572+
public static TypedConstant? FindNamedArg(this AttributeData attribute, string argName)
573+
=> attribute.NamedArguments is { IsDefaultOrEmpty: false } args
574+
&& args.FirstOrDefault(arg => arg.Key == argName) is { Key: not null } arg
575+
? arg.Value
576+
: null;
577+
578+
public static T? GetNamedValue<T>(this AttributeData attribute, string argName)
579+
where T : Enum
580+
=> attribute.FindNamedArg(argName) is { IsNull: false, Kind: TypedConstantKind.Enum } arg && arg.Type!.Name == typeof(T).Name
581+
? (T)arg.Value!
582+
: default(T?);
571583
}
572584
}

src/SourceGenerators/Uno.UI.SourceGenerators/TSBindings/TSBindingsGenerator.cs

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics;
34
using System.IO;
45
using System.Linq;
56
using System.Reflection;
67
using System.Runtime.InteropServices;
78
using Microsoft.CodeAnalysis;
89
using Uno.Extensions;
10+
using Uno.Foundation.Interop;
911
using Uno.UI.SourceGenerators.Helpers;
1012
using Uno.Roslyn;
1113

@@ -32,7 +34,6 @@ public void Initialize(GeneratorInitializationContext context)
3234

3335
public void Execute(GeneratorExecutionContext context)
3436
{
35-
3637
if (!DesignTimeHelper.IsDesignTime(context))
3738
{
3839
_bindingsPaths = context.GetMSBuildPropertyValue("TSBindingsPath")?.ToString();
@@ -59,52 +60,69 @@ from module in sym.Modules
5960

6061
internal void GenerateTSMarshallingLayouts(IEnumerable<IModuleSymbol> modules)
6162
{
62-
var messageTypes = from module in modules
63-
from type in GetNamespaceTypes(module)
64-
where (
65-
type.FindAttributeFlattened(_interopMessageSymbol) != null
66-
&& type.TypeKind == TypeKind.Struct
67-
)
68-
select type;
63+
var messages = from module in modules
64+
from type in GetNamespaceTypes(module)
65+
let attr = type.FindAttributeFlattened(_interopMessageSymbol)
66+
where attr is not null && type.TypeKind is TypeKind.Struct
67+
select (type, attr);
6968

70-
messageTypes = messageTypes.ToArray();
69+
messages = messages.ToArray();
7170

72-
foreach (var messageType in messageTypes)
71+
foreach (var message in messages)
7372
{
74-
var packValue = GetStructPack(messageType);
73+
var packValue = GetStructPack(message.type);
7574

7675
var sb = new IndentedStringBuilder();
7776

7877
sb.AppendLineInvariant($"/* {nameof(TSBindingsGenerator)} Generated code -- this code is regenerated on each build */");
7978

80-
using (sb.BlockInvariant($"class {messageType.Name}"))
79+
var ns = message.type.ContainingNamespace.ToDisplayString();
80+
if (message.type.ContainingType?.Name?.Contains("WindowManagerInterop", StringComparison.OrdinalIgnoreCase) ?? false)
8181
{
82-
sb.AppendLineInvariant($"/* Pack={packValue} */");
82+
// For backward compatibility, we include the namespace only for types that are not part of the WindowsManagerInterop.
83+
// We should include the namespace for all messages, but it would require to update all usages.
84+
ns = null;
85+
}
8386

84-
foreach (var field in messageType.GetFields())
87+
using (ns is null ? null : sb.BlockInvariant($"namespace {ns}"))
88+
{
89+
using (sb.BlockInvariant($"{(ns is null ? "": "export ")}class {message.type.Name}"))
8590
{
86-
sb.AppendLineInvariant($"public {field.Name} : {GetTSFieldType(field.Type)};");
87-
}
91+
sb.AppendLineInvariant($"/* Pack={packValue} */");
8892

89-
if (messageType.Name.EndsWith("Params") || messageType.Name.EndsWith("EventArgs"))
90-
{
91-
GenerateUnmarshaler(messageType, sb, packValue);
92-
}
93+
foreach (var field in message.type.GetFields())
94+
{
95+
sb.AppendLineInvariant($"public {field.Name} : {GetTSFieldType(field.Type)};");
96+
}
9397

94-
if (messageType.Name.EndsWith("Return") || messageType.Name.EndsWith("EventArgs"))
95-
{
96-
GenerateMarshaler(messageType, sb, packValue);
98+
if (message.attr.GetNamedValue<CodeGeneration>(nameof(TSInteropMessageAttribute.UnMarshaller)) switch
99+
{
100+
CodeGeneration.Enabled => true,
101+
CodeGeneration.Disabled => false,
102+
_ => message.type.Name.EndsWith("Params") || message.type.Name.EndsWith("EventArgs"),
103+
})
104+
{
105+
GenerateUnmarshaler(message.type, sb, packValue);
106+
}
107+
108+
if (message.attr.GetNamedValue<CodeGeneration>(nameof(TSInteropMessageAttribute.Marshaller)) switch
109+
{
110+
CodeGeneration.Enabled => true,
111+
CodeGeneration.Disabled => false,
112+
_ => message.type.Name.EndsWith("Return") || message.type.Name.EndsWith("EventArgs"),
113+
})
114+
{
115+
GenerateMarshaler(message.type, sb, packValue);
116+
}
97117
}
98118
}
99119

100-
var outputPath = Path.Combine(_bindingsPaths, $"{messageType.Name}.ts");
120+
var outputPath = Path.Combine(_bindingsPaths, $"{(ns is null ? "" : ns.Replace('.', '_') + "_")}{message.type.Name}.ts");
101121

102122
var fileExists = File.Exists(outputPath);
103123
var output = sb.ToString();
104124

105-
if (
106-
(fileExists && File.ReadAllText(outputPath) != output)
107-
|| !fileExists)
125+
if (!fileExists || File.ReadAllText(outputPath) != output)
108126
{
109127
File.WriteAllText(outputPath, output);
110128
}
@@ -361,6 +379,7 @@ field.Type.SpecialType is SpecialType.System_UInt32 ||
361379
SymbolEqualityComparer.Default.Equals(field.Type, _intPtrSymbol) ||
362380
field.Type.SpecialType is SpecialType.System_Single ||
363381
field.Type.SpecialType is SpecialType.System_Boolean ||
382+
field.Type.SpecialType is SpecialType.System_Byte ||
364383
field.Type is IArrayTypeSymbol
365384
)
366385
{

src/SourceGenerators/Uno.UI.SourceGenerators/Uno.UI.SourceGenerators.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@
9595
<Compile Include="..\..\Uno.UI\UI\Xaml\XamlFilePathHelper.shared.cs">
9696
<Link>Helpers\XamlFilePathHelper.shared.cs</Link>
9797
</Compile>
98+
<Compile Include="..\..\Uno.Foundation.Runtime.WebAssembly\Interop\TSInteropMessageAttribute.wasm.cs">
99+
<Link>TSBindings\TSInteropMessageAttribute.cs</Link>
100+
</Compile>
98101
</ItemGroup>
99102

100103
<Import Project="..\..\Uno.Foundation\Uno.Core.Extensions\Uno.Core.Extensions.props" />

src/Uno.Foundation.Runtime.WebAssembly/Interop/TSInteropMessageAttribute.wasm.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ namespace Uno.Foundation.Interop
99
/// </summary>
1010
[AttributeUsage(AttributeTargets.Struct, AllowMultiple = false)]
1111
public class TSInteropMessageAttribute : Attribute
12+
{
13+
public CodeGeneration Marshaller { get; set; }
14+
15+
public CodeGeneration UnMarshaller { get; set; }
16+
}
17+
18+
public enum CodeGeneration
1219
{
20+
Auto = 0,
21+
Enabled = 1,
22+
Disabled = 256,
1323
}
1424
}

src/Uno.UI.Wasm.Tests/WasmScripts/UnitTests.d.ts

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,35 @@ declare class TSBindingsTests {
1212
When_NullArrayOfStrings(pParams: number, pReturn: number): boolean;
1313
When_ArrayOfNullStrings(pParams: number, pReturn: number): boolean;
1414
}
15-
declare class GenericReturn {
16-
Value: string;
17-
marshal(pData: number): void;
15+
declare namespace SamplesApp.UnitTests.TSBindings {
16+
class GenericReturn {
17+
Value: string;
18+
marshal(pData: number): void;
19+
}
1820
}
19-
declare class When_ArrayOfIntParams {
20-
MyArray_Length: number;
21-
MyArray: Array<number>;
22-
static unmarshal(pData: number): When_ArrayOfIntParams;
21+
declare namespace SamplesApp.UnitTests.TSBindings {
22+
class When_ArrayOfIntParams {
23+
MyArray_Length: number;
24+
MyArray: Array<number>;
25+
static unmarshal(pData: number): When_ArrayOfIntParams;
26+
}
2327
}
24-
declare class When_ArrayOfStringParams {
25-
MyArray_Length: number;
26-
MyArray: Array<string>;
27-
static unmarshal(pData: number): When_ArrayOfStringParams;
28+
declare namespace SamplesApp.UnitTests.TSBindings {
29+
class When_ArrayOfStringsParams {
30+
MyArray_Length: number;
31+
MyArray: Array<string>;
32+
static unmarshal(pData: number): When_ArrayOfStringsParams;
33+
}
2834
}
29-
declare class When_ArrayOfStringsParams {
30-
MyArray_Length: number;
31-
MyArray: Array<string>;
32-
static unmarshal(pData: number): When_ArrayOfStringsParams;
35+
declare namespace SamplesApp.UnitTests.TSBindings {
36+
class When_IntPtrParams {
37+
Id: number;
38+
static unmarshal(pData: number): When_IntPtrParams;
39+
}
3340
}
34-
declare class When_IntPtrParams {
35-
Id: number;
36-
static unmarshal(pData: number): When_IntPtrParams;
37-
}
38-
declare class When_SingleStringParams {
39-
MyString: string;
40-
static unmarshal(pData: number): When_SingleStringParams;
41+
declare namespace SamplesApp.UnitTests.TSBindings {
42+
class When_SingleStringParams {
43+
MyString: string;
44+
static unmarshal(pData: number): When_SingleStringParams;
45+
}
4146
}

0 commit comments

Comments
 (0)