@nativescript/windows 0.1.0-alpha.51 → 0.1.0-alpha.53

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.
@@ -10,6 +10,13 @@ internal readonly struct HandleRef(int id)
10
10
  public readonly int Id = id;
11
11
  }
12
12
 
13
+ // Carries a raw IUnknown/IInspectable pointer from a WinRT proxy (tag 0x0A).
14
+ // CoerceBin calls Marshal.GetObjectForIUnknown to create a managed RCW.
15
+ internal readonly struct WinRtRef(long ptr)
16
+ {
17
+ public readonly long Ptr = ptr;
18
+ }
19
+
13
20
  internal ref struct BinReader(ReadOnlySpan<byte> buf)
14
21
  {
15
22
  private readonly ReadOnlySpan<byte> _buf = buf;
@@ -24,6 +31,13 @@ internal ref struct BinReader(ReadOnlySpan<byte> buf)
24
31
  return v;
25
32
  }
26
33
 
34
+ public long ReadI64()
35
+ {
36
+ var v = BinaryPrimitives.ReadInt64LittleEndian(_buf[_pos..]);
37
+ _pos += 8;
38
+ return v;
39
+ }
40
+
27
41
  public ushort ReadU16()
28
42
  {
29
43
  var v = BinaryPrimitives.ReadUInt16LittleEndian(_buf[_pos..]);
@@ -65,6 +79,7 @@ internal ref struct BinReader(ReadOnlySpan<byte> buf)
65
79
  0x04 => (object)ReadF64(),
66
80
  0x05 => (object)ReadString16(),
67
81
  0x06 => (object)new HandleRef(ReadI32()),
82
+ 0x0A => (object)new WinRtRef(ReadI64()),
68
83
  _ => null,
69
84
  };
70
85
  }
@@ -158,6 +158,13 @@ public static partial class Bridge
158
158
  s_handles.TryGetValue(hr.Id, out var obj);
159
159
  return obj;
160
160
  }
161
+ if (value is WinRtRef wr && wr.Ptr != 0)
162
+ {
163
+ // Marshal.GetObjectForIUnknown calls AddRef internally; the RCW will
164
+ // Release when GC'd.
165
+ try { return Marshal.GetObjectForIUnknown(new IntPtr(wr.Ptr)); }
166
+ catch { return null; }
167
+ }
161
168
  if (value.GetType() == targetType) return value;
162
169
  try { return Convert.ChangeType(value, targetType); }
163
170
  catch { return value; }
@@ -86,8 +86,6 @@ public static partial class Bridge
86
86
  finally { if (builtArgs.Length > 0) ReturnArgs(builtArgs); }
87
87
  }
88
88
 
89
- // ── compiled dispatch cache ───────────────────────────────────────────────
90
-
91
89
  private static DispatchEntry GetCachedMethod(Type type, string name, int argCount, BindingFlags flags)
92
90
  => s_methodCache.GetOrAdd(
93
91
  new MethodKey(type, name, argCount, flags),
@@ -148,8 +146,6 @@ public static partial class Bridge
148
146
  new PropKey(type, method[prefixLen..], flags),
149
147
  static k => k.Type.GetProperty(k.Name, k.Flags));
150
148
 
151
- // ── argument coercion ─────────────────────────────────────────────────────
152
-
153
149
  // Pooled: rented array passed to the compiled delegate (which accesses by index,
154
150
  // not by Length). Caller must return via ReturnArgs immediately after invoke.
155
151
  private static object?[] BuildArgs(JsonElement[] elements, ParameterInfo[] parameters)
@@ -186,8 +182,6 @@ public static partial class Bridge
186
182
  return el.Deserialize(targetType, s_coerceOpts);
187
183
  }
188
184
 
189
- // ── async unwrapping ──────────────────────────────────────────────────────
190
-
191
185
  private static object? AwaitIfTask(object? value)
192
186
  {
193
187
  if (value is null) return null;
@@ -216,8 +210,6 @@ public static partial class Bridge
216
210
  return value;
217
211
  }
218
212
 
219
- // ── result boxing ─────────────────────────────────────────────────────────
220
-
221
213
  private static DispatchResult Box(object? value)
222
214
  {
223
215
  if (value is null) return DispatchResult.Void;
@@ -239,17 +231,24 @@ public static partial class Bridge
239
231
  return DispatchResult.Handle(id, t.FullName ?? t.Name);
240
232
  }
241
233
 
242
- // ── type/member resolution ────────────────────────────────────────────────
243
-
244
234
  internal static DispatchResult BuildMembersResult(Type t)
245
235
  {
246
236
  const BindingFlags inst = BindingFlags.Public | BindingFlags.Instance;
247
237
  const BindingFlags stat = BindingFlags.Public | BindingFlags.Static;
238
+
239
+ var instProps = t.GetProperties(inst);
240
+ var statProps = t.GetProperties(stat);
241
+
248
242
  return DispatchResult.Members(
249
- t.GetMethods(inst).Where(m => !m.IsSpecialName).Select(m => m.Name).Distinct().ToArray(),
250
- t.GetProperties(inst).Select(p => p.Name).Distinct().ToArray(),
251
- t.GetMethods(stat).Where(m => !m.IsSpecialName).Select(m => m.Name).Distinct().ToArray(),
252
- t.GetProperties(stat).Select(p => p.Name).Distinct().ToArray());
243
+ methods: t.GetMethods(inst).Where(m => !m.IsSpecialName).Select(m => m.Name).Distinct().ToArray(),
244
+ props: instProps.Where(p => p.GetGetMethod() != null).Select(p => p.Name).Distinct().ToArray(),
245
+ staticMethods: t.GetMethods(stat).Where(m => !m.IsSpecialName).Select(m => m.Name).Distinct().ToArray(),
246
+ staticProps: statProps.Where(p => p.GetGetMethod() != null).Select(p => p.Name).Distinct().ToArray(),
247
+ readonlyProps: instProps.Where(p => p.GetGetMethod() != null && p.GetSetMethod() == null).Select(p => p.Name).Distinct().ToArray(),
248
+ readonlyStaticProps: statProps.Where(p => p.GetGetMethod() != null && p.GetSetMethod() == null).Select(p => p.Name).Distinct().ToArray(),
249
+ writeonlyProps: instProps.Where(p => p.GetGetMethod() == null && p.GetSetMethod() != null).Select(p => p.Name).Distinct().ToArray(),
250
+ writeonlyStaticProps: statProps.Where(p => p.GetGetMethod() == null && p.GetSetMethod() != null).Select(p => p.Name).Distinct().ToArray()
251
+ );
253
252
  }
254
253
 
255
254
  internal static Type? ResolveType(string? assemblyName, string? typeName)
@@ -288,12 +287,14 @@ public static partial class Bridge
288
287
  // we catch and continue.
289
288
  foreach (var ty in asm.GetTypes())
290
289
  {
291
- if (string.Equals(ty.FullName, typeName, StringComparison.Ordinal)
292
- || string.Equals(ty.Name, shortName, StringComparison.Ordinal)
293
- || (lastDot < 0 && ty.Namespace != null && ty.Namespace == typeName))
294
- {
290
+ if (string.Equals(ty.FullName, typeName, StringComparison.Ordinal))
291
+ return ty;
292
+ // Short-name match only when input has no namespace prefix (e.g. "Stopwatch").
293
+ // Guarding on lastDot < 0 prevents matching unrelated types in other namespaces
294
+ // (e.g. "NativeScript.Widgets.FlexboxLayout" must not match a different
295
+ // FlexboxLayout that happens to live in another namespace).
296
+ if (lastDot < 0 && string.Equals(ty.Name, shortName, StringComparison.Ordinal))
295
297
  return ty;
296
- }
297
298
  }
298
299
  }
299
300
  catch (ReflectionTypeLoadException) { }
@@ -315,12 +316,10 @@ public static partial class Bridge
315
316
  {
316
317
  foreach (var ty in asm.GetTypes())
317
318
  {
318
- if (string.Equals(ty.FullName, typeName, StringComparison.Ordinal)
319
- || string.Equals(ty.Name, shortName, StringComparison.Ordinal)
320
- || (lastDot < 0 && ty.Namespace != null && ty.Namespace == typeName))
321
- {
319
+ if (string.Equals(ty.FullName, typeName, StringComparison.Ordinal))
320
+ return ty;
321
+ if (lastDot < 0 && string.Equals(ty.Name, shortName, StringComparison.Ordinal))
322
322
  return ty;
323
- }
324
323
  }
325
324
  }
326
325
  catch (ReflectionTypeLoadException) { }
@@ -342,7 +341,6 @@ public static partial class Bridge
342
341
  internal static Exception Unwrap(Exception ex) =>
343
342
  ex is TargetInvocationException { InnerException: { } inner } ? Unwrap(inner) : ex;
344
343
 
345
- // ── full-pipeline helpers (parse + dispatch + serialise) ──────────────────
346
344
  // Used by benchmarks to give a fair end-to-end comparison of protocols.
347
345
 
348
346
  internal static byte[] PipelineJson(ReadOnlySpan<byte> jsonRequest)
@@ -368,8 +366,6 @@ public static partial class Bridge
368
366
  return buf.WrittenSpan.ToArray();
369
367
  }
370
368
 
371
- // ── JSON response writers ─────────────────────────────────────────────────
372
-
373
369
  private static unsafe void WriteResult(DispatchResult res, byte** outPtr, int* outLen)
374
370
  {
375
371
  var buf = new ArrayBufferWriter<byte>(256);
@@ -10,8 +10,6 @@ namespace NativeScriptBridge;
10
10
 
11
11
  public static partial class Bridge
12
12
  {
13
- // ── JS delegate creation ──────────────────────────────────────────────────
14
- //
15
13
  // opcode 0x09: given a delegate type name (or "" for System.Action) and a
16
14
  // JS callback id, compile a .NET delegate that serialises its parameters as
17
15
  // binary and calls back into V8 via the s_jsInvoker function pointer.
@@ -51,8 +49,6 @@ public static partial class Bridge
51
49
  return Box(del);
52
50
  }
53
51
 
54
- // ── Callback invocation helper ────────────────────────────────────────────
55
-
56
52
  internal static unsafe void CallJsCallback(int id, object?[] args)
57
53
  {
58
54
  if (s_jsInvoker == null) return;
@@ -51,24 +51,13 @@ public static partial class Bridge
51
51
 
52
52
  // Returns a JSON object mapping top-level namespace roots (e.g. "NativeScript")
53
53
  // to the assembly simple-name that most likely contains that namespace's types.
54
- // This probes the application base directory and libs/ for assemblies and
55
- // inspects exported types. The result is safe-to-call and tolerant of
56
- // non-.NET DLLs.
54
+ // Reuses s_assemblySearchDirs so plugin and NuGet assemblies are included.
57
55
  public static string GetNamespaceAssemblyMapJson()
58
56
  {
59
57
  var map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
60
58
  try
61
59
  {
62
- var baseDir = AppContext.BaseDirectory ?? AppDomain.CurrentDomain.BaseDirectory;
63
- var dirs = new List<string> { baseDir };
64
- var libs = Path.Combine(baseDir, "libs");
65
- if (Directory.Exists(libs))
66
- {
67
- dirs.Add(libs);
68
- try { dirs.AddRange(Directory.GetDirectories(libs, "*", SearchOption.AllDirectories)); } catch { }
69
- }
70
-
71
- foreach (var dir in dirs.Where(d => !string.IsNullOrEmpty(d) && Directory.Exists(d)))
60
+ foreach (var dir in s_assemblySearchDirs.Where(Directory.Exists))
72
61
  {
73
62
  try
74
63
  {
@@ -108,19 +97,46 @@ public static partial class Bridge
108
97
  try { return JsonSerializer.Serialize(map); } catch { return "{}"; }
109
98
  }
110
99
 
111
- // Static ctor: initialize assembly search directories and register resolver.
112
100
  static Bridge()
113
101
  {
114
102
  try
115
103
  {
116
104
  var baseDir = AppContext.BaseDirectory ?? AppDomain.CurrentDomain.BaseDirectory;
117
105
  var dirs = new List<string> { baseDir };
106
+
107
+ // libs/ subtree relative to the bridge's own directory.
118
108
  var libs = Path.Combine(baseDir, "libs");
119
109
  if (Directory.Exists(libs))
120
110
  {
121
111
  dirs.Add(libs);
122
112
  try { dirs.AddRange(Directory.GetDirectories(libs, "*", SearchOption.AllDirectories)); } catch { }
123
113
  }
114
+
115
+ // The bridge DLL lives at dotnet-bridge/publish/ inside the app output root.
116
+ // Plugin assemblies (added via plugin.props) land at plugins/**/*.dll and NuGet
117
+ // assemblies land at the app output root itself — both outside the bridge subtree.
118
+ // Use the host process directory to reach them.
119
+ try
120
+ {
121
+ var processDir = Path.GetDirectoryName(
122
+ System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName);
123
+ if (!string.IsNullOrEmpty(processDir))
124
+ {
125
+ dirs.Add(processDir);
126
+
127
+ // plugins/ subtree: CLI-managed plugin DLLs live here.
128
+ var pluginsDir = Path.Combine(processDir, "plugins");
129
+ if (Directory.Exists(pluginsDir))
130
+ try { dirs.AddRange(Directory.GetDirectories(pluginsDir, "*", SearchOption.AllDirectories)); } catch { }
131
+
132
+ // libs/ relative to the app root (alternative convention).
133
+ var processLibs = Path.Combine(processDir, "libs");
134
+ if (Directory.Exists(processLibs))
135
+ try { dirs.AddRange(Directory.GetDirectories(processLibs, "*", SearchOption.AllDirectories)); } catch { }
136
+ }
137
+ }
138
+ catch { }
139
+
124
140
  s_assemblySearchDirs = dirs.Where(d => !string.IsNullOrEmpty(d)).Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
125
141
  AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
126
142
  }
@@ -12,14 +12,10 @@ using System.Threading.Tasks;
12
12
 
13
13
  namespace NativeScriptBridge;
14
14
 
15
- // ── JSON source-gen context ───────────────────────────────────────────────────
16
-
17
15
  [JsonSerializable(typeof(InvokeRequest))]
18
16
  [JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
19
17
  internal partial class BridgeJsonContext : JsonSerializerContext { }
20
18
 
21
- // ── JSON wire type ────────────────────────────────────────────────────────────
22
-
23
19
  internal sealed record InvokeRequest(
24
20
  string? Assembly,
25
21
  string? TypeName,
@@ -28,7 +24,6 @@ internal sealed record InvokeRequest(
28
24
  JsonElement[]? Args
29
25
  );
30
26
 
31
- // ── cache key structs ─────────────────────────────────────────────────────────
32
27
  //
33
28
  // Using Type as the key field (rather than Type.FullName) is correct and faster:
34
29
  // Type instances are singletons within an AssemblyLoadContext, so reference
@@ -38,8 +33,6 @@ internal readonly record struct MethodKey(Type Type, string Name, int ArgCount,
38
33
  internal readonly record struct PropKey(Type Type, string Name, BindingFlags Flags);
39
34
  internal readonly record struct CtorKey(Type Type, int ArgCount);
40
35
 
41
- // ── cache value types ─────────────────────────────────────────────────────────
42
-
43
36
  internal readonly struct DispatchEntry(Func<object?, object?[], object?>? invoke, ParameterInfo[] parameters)
44
37
  {
45
38
  public readonly Func<object?, object?[], object?>? Invoke = invoke;
@@ -53,8 +46,6 @@ internal readonly struct CtorEntry(ConstructorInfo? ctor, ParameterInfo[] parame
53
46
  public readonly ParameterInfo[] Parameters = parameters;
54
47
  }
55
48
 
56
- // ── dispatch result ───────────────────────────────────────────────────────────
57
-
58
49
  internal enum DispatchKind : byte { Void, Primitive, Handle, Collection, Members }
59
50
 
60
51
  internal readonly struct DispatchResult
@@ -71,14 +62,22 @@ internal readonly struct DispatchResult
71
62
  private readonly string[]? _properties;
72
63
  private readonly string[]? _staticMethods;
73
64
  private readonly string[]? _staticProperties;
65
+ private readonly string[]? _readonlyProperties;
66
+ private readonly string[]? _readonlyStaticProperties;
67
+ private readonly string[]? _writeonlyProperties;
68
+ private readonly string[]? _writeonlyStaticProperties;
74
69
 
75
70
  private DispatchResult(DispatchKind kind, object? value, Type? type, int handle,
76
71
  string? typeName, string[]? methods, string[]? props,
77
- string[]? staticMethods, string[]? staticProps)
72
+ string[]? staticMethods, string[]? staticProps,
73
+ string[]? readonlyProps = null, string[]? readonlyStaticProps = null,
74
+ string[]? writeonlyProps = null, string[]? writeonlyStaticProps = null)
78
75
  {
79
76
  _kind = kind; _value = value; _type = type; _handle = handle;
80
77
  _typeName = typeName; _methods = methods; _properties = props;
81
78
  _staticMethods = staticMethods; _staticProperties = staticProps;
79
+ _readonlyProperties = readonlyProps; _readonlyStaticProperties = readonlyStaticProps;
80
+ _writeonlyProperties = writeonlyProps; _writeonlyStaticProperties = writeonlyStaticProps;
82
81
  }
83
82
 
84
83
  public static DispatchResult Primitive(object value, Type type)
@@ -91,13 +90,15 @@ internal readonly struct DispatchResult
91
90
  => new(DispatchKind.Collection, items, null, 0, null, null, null, null, null);
92
91
 
93
92
  public static DispatchResult Members(
94
- string[] methods, string[] props, string[] staticMethods, string[] staticProps)
95
- => new(DispatchKind.Members, null, null, 0, null, methods, props, staticMethods, staticProps);
93
+ string[] methods, string[] props, string[] staticMethods, string[] staticProps,
94
+ string[] readonlyProps, string[] readonlyStaticProps,
95
+ string[] writeonlyProps, string[] writeonlyStaticProps)
96
+ => new(DispatchKind.Members, null, null, 0, null,
97
+ methods, props, staticMethods, staticProps,
98
+ readonlyProps, readonlyStaticProps, writeonlyProps, writeonlyStaticProps);
96
99
 
97
100
  internal int HandleId() => _handle;
98
101
 
99
- // ── JSON serialisation ────────────────────────────────────────────────────
100
-
101
102
  public void WriteTo(Utf8JsonWriter w, JsonSerializerOptions opts)
102
103
  {
103
104
  switch (_kind)
@@ -126,10 +127,14 @@ internal readonly struct DispatchResult
126
127
 
127
128
  case DispatchKind.Members:
128
129
  w.WriteStartObject();
129
- WriteStringArray(w, "methods"u8, _methods!);
130
- WriteStringArray(w, "properties"u8, _properties!);
131
- WriteStringArray(w, "staticMethods"u8, _staticMethods!);
132
- WriteStringArray(w, "staticProperties"u8, _staticProperties!);
130
+ WriteStringArray(w, "methods"u8, _methods!);
131
+ WriteStringArray(w, "properties"u8, _properties!);
132
+ WriteStringArray(w, "staticMethods"u8, _staticMethods!);
133
+ WriteStringArray(w, "staticProperties"u8, _staticProperties!);
134
+ WriteStringArray(w, "readonlyProperties"u8, _readonlyProperties!);
135
+ WriteStringArray(w, "readonlyStaticProperties"u8, _readonlyStaticProperties!);
136
+ WriteStringArray(w, "writeonlyProperties"u8, _writeonlyProperties!);
137
+ WriteStringArray(w, "writeonlyStaticProperties"u8,_writeonlyStaticProperties!);
133
138
  w.WriteEndObject();
134
139
  break;
135
140
  }
@@ -142,7 +147,6 @@ internal readonly struct DispatchResult
142
147
  w.WriteEndArray();
143
148
  }
144
149
 
145
- // ── binary serialisation ──────────────────────────────────────────────────
146
150
  //
147
151
  // Response tags:
148
152
  // 0x00 = null 0x01 = false 0x02 = true
@@ -185,6 +189,10 @@ internal readonly struct DispatchResult
185
189
  WriteStringArrayBin(ref w, _properties!);
186
190
  WriteStringArrayBin(ref w, _staticMethods!);
187
191
  WriteStringArrayBin(ref w, _staticProperties!);
192
+ WriteStringArrayBin(ref w, _readonlyProperties!);
193
+ WriteStringArrayBin(ref w, _readonlyStaticProperties!);
194
+ WriteStringArrayBin(ref w, _writeonlyProperties!);
195
+ WriteStringArrayBin(ref w, _writeonlyStaticProperties!);
188
196
  break;
189
197
  }
190
198
  }
@@ -242,8 +250,6 @@ internal readonly struct DispatchResult
242
250
  }
243
251
  }
244
252
 
245
- // ── async result helpers ──────────────────────────────────────────────────────
246
-
247
253
  internal static class TaskResultCache
248
254
  {
249
255
  private static readonly ConcurrentDictionary<Type, Func<Task, object?>> s_cache = new();
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nativescript/windows",
3
- "version": "0.1.0-alpha.51",
3
+ "version": "0.1.0-alpha.53",
4
4
  "description": "NativeScript for using Windows v8",
5
5
  "repository": {
6
6
  "type": "git",