@nativescript/windows 0.1.0-alpha.50 → 0.1.0-alpha.52

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.
@@ -245,11 +245,20 @@ public static partial class Bridge
245
245
  {
246
246
  const BindingFlags inst = BindingFlags.Public | BindingFlags.Instance;
247
247
  const BindingFlags stat = BindingFlags.Public | BindingFlags.Static;
248
+
249
+ var instProps = t.GetProperties(inst);
250
+ var statProps = t.GetProperties(stat);
251
+
248
252
  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());
253
+ methods: t.GetMethods(inst).Where(m => !m.IsSpecialName).Select(m => m.Name).Distinct().ToArray(),
254
+ props: instProps.Where(p => p.GetGetMethod() != null).Select(p => p.Name).Distinct().ToArray(),
255
+ staticMethods: t.GetMethods(stat).Where(m => !m.IsSpecialName).Select(m => m.Name).Distinct().ToArray(),
256
+ staticProps: statProps.Where(p => p.GetGetMethod() != null).Select(p => p.Name).Distinct().ToArray(),
257
+ readonlyProps: instProps.Where(p => p.GetGetMethod() != null && p.GetSetMethod() == null).Select(p => p.Name).Distinct().ToArray(),
258
+ readonlyStaticProps: statProps.Where(p => p.GetGetMethod() != null && p.GetSetMethod() == null).Select(p => p.Name).Distinct().ToArray(),
259
+ writeonlyProps: instProps.Where(p => p.GetGetMethod() == null && p.GetSetMethod() != null).Select(p => p.Name).Distinct().ToArray(),
260
+ writeonlyStaticProps: statProps.Where(p => p.GetGetMethod() == null && p.GetSetMethod() != null).Select(p => p.Name).Distinct().ToArray()
261
+ );
253
262
  }
254
263
 
255
264
  internal static Type? ResolveType(string? assemblyName, string? typeName)
@@ -288,12 +297,14 @@ public static partial class Bridge
288
297
  // we catch and continue.
289
298
  foreach (var ty in asm.GetTypes())
290
299
  {
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
- {
300
+ if (string.Equals(ty.FullName, typeName, StringComparison.Ordinal))
301
+ return ty;
302
+ // Short-name match only when input has no namespace prefix (e.g. "Stopwatch").
303
+ // Guarding on lastDot < 0 prevents matching unrelated types in other namespaces
304
+ // (e.g. "NativeScript.Widgets.FlexboxLayout" must not match a different
305
+ // FlexboxLayout that happens to live in another namespace).
306
+ if (lastDot < 0 && string.Equals(ty.Name, shortName, StringComparison.Ordinal))
295
307
  return ty;
296
- }
297
308
  }
298
309
  }
299
310
  catch (ReflectionTypeLoadException) { }
@@ -315,12 +326,10 @@ public static partial class Bridge
315
326
  {
316
327
  foreach (var ty in asm.GetTypes())
317
328
  {
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
- {
329
+ if (string.Equals(ty.FullName, typeName, StringComparison.Ordinal))
330
+ return ty;
331
+ if (lastDot < 0 && string.Equals(ty.Name, shortName, StringComparison.Ordinal))
322
332
  return ty;
323
- }
324
333
  }
325
334
  }
326
335
  catch (ReflectionTypeLoadException) { }
@@ -1,7 +1,11 @@
1
1
  using System;
2
2
  using System.Collections.Concurrent;
3
+ using System.Collections.Generic;
4
+ using System.IO;
5
+ using System.Linq;
3
6
  using System.Reflection;
4
7
  using System.Runtime.InteropServices;
8
+ using System.Runtime.Loader;
5
9
  using System.Text.Json;
6
10
 
7
11
  [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("DotNetBridgeTests")]
@@ -24,6 +28,11 @@ public static partial class Bridge
24
28
  private static readonly ConcurrentDictionary<MethodKey, DispatchEntry> s_methodCache = new();
25
29
  private static readonly ConcurrentDictionary<PropKey, PropertyInfo?> s_propCache = new();
26
30
  private static readonly ConcurrentDictionary<CtorKey, CtorEntry> s_ctorCache = new();
31
+ // Cache of attempted assembly loads (simple name -> Assembly or null if not found).
32
+ private static readonly ConcurrentDictionary<string, Assembly?> s_assemblyLoadCache
33
+ = new(StringComparer.OrdinalIgnoreCase);
34
+ // Directories to search for assemblies (initialized once in static ctor).
35
+ private static readonly string[] s_assemblySearchDirs;
27
36
 
28
37
  private static readonly JsonSerializerOptions s_coerceOpts = new()
29
38
  {
@@ -40,6 +49,148 @@ public static partial class Bridge
40
49
  s_nextHandle = 0;
41
50
  }
42
51
 
52
+ // Returns a JSON object mapping top-level namespace roots (e.g. "NativeScript")
53
+ // to the assembly simple-name that most likely contains that namespace's types.
54
+ // Reuses s_assemblySearchDirs so plugin and NuGet assemblies are included.
55
+ public static string GetNamespaceAssemblyMapJson()
56
+ {
57
+ var map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
58
+ try
59
+ {
60
+ foreach (var dir in s_assemblySearchDirs.Where(Directory.Exists))
61
+ {
62
+ try
63
+ {
64
+ foreach (var file in Directory.EnumerateFiles(dir, "*.dll", SearchOption.TopDirectoryOnly))
65
+ {
66
+ try
67
+ {
68
+ var simple = Path.GetFileNameWithoutExtension(file);
69
+ if (string.IsNullOrEmpty(simple)) continue;
70
+
71
+ Assembly asm = AppDomain.CurrentDomain.GetAssemblies()
72
+ .FirstOrDefault(a => string.Equals(a.GetName().Name, simple, StringComparison.OrdinalIgnoreCase));
73
+ if (asm is null)
74
+ {
75
+ try { asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(file); }
76
+ catch { continue; }
77
+ }
78
+
79
+ Type[] types;
80
+ try { types = asm.GetExportedTypes(); }
81
+ catch { types = Array.Empty<Type>(); }
82
+
83
+ foreach (var t in types)
84
+ {
85
+ if (string.IsNullOrEmpty(t.Namespace)) continue;
86
+ var root = t.Namespace.Split('.')[0];
87
+ if (!map.ContainsKey(root)) map[root] = asm.GetName().Name;
88
+ }
89
+ }
90
+ catch { }
91
+ }
92
+ }
93
+ catch { }
94
+ }
95
+ }
96
+ catch { }
97
+ try { return JsonSerializer.Serialize(map); } catch { return "{}"; }
98
+ }
99
+
100
+ // Static ctor: initialize assembly search directories and register resolver.
101
+ static Bridge()
102
+ {
103
+ try
104
+ {
105
+ var baseDir = AppContext.BaseDirectory ?? AppDomain.CurrentDomain.BaseDirectory;
106
+ var dirs = new List<string> { baseDir };
107
+
108
+ // libs/ subtree relative to the bridge's own directory.
109
+ var libs = Path.Combine(baseDir, "libs");
110
+ if (Directory.Exists(libs))
111
+ {
112
+ dirs.Add(libs);
113
+ try { dirs.AddRange(Directory.GetDirectories(libs, "*", SearchOption.AllDirectories)); } catch { }
114
+ }
115
+
116
+ // The bridge DLL lives at dotnet-bridge/publish/ inside the app output root.
117
+ // Plugin assemblies (added via plugin.props) land at plugins/**/*.dll and NuGet
118
+ // assemblies land at the app output root itself — both outside the bridge subtree.
119
+ // Use the host process directory to reach them.
120
+ try
121
+ {
122
+ var processDir = Path.GetDirectoryName(
123
+ System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName);
124
+ if (!string.IsNullOrEmpty(processDir))
125
+ {
126
+ dirs.Add(processDir);
127
+
128
+ // plugins/ subtree: CLI-managed plugin DLLs live here.
129
+ var pluginsDir = Path.Combine(processDir, "plugins");
130
+ if (Directory.Exists(pluginsDir))
131
+ try { dirs.AddRange(Directory.GetDirectories(pluginsDir, "*", SearchOption.AllDirectories)); } catch { }
132
+
133
+ // libs/ relative to the app root (alternative convention).
134
+ var processLibs = Path.Combine(processDir, "libs");
135
+ if (Directory.Exists(processLibs))
136
+ try { dirs.AddRange(Directory.GetDirectories(processLibs, "*", SearchOption.AllDirectories)); } catch { }
137
+ }
138
+ }
139
+ catch { }
140
+
141
+ s_assemblySearchDirs = dirs.Where(d => !string.IsNullOrEmpty(d)).Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
142
+ AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
143
+ }
144
+ catch
145
+ {
146
+ s_assemblySearchDirs = Array.Empty<string>();
147
+ }
148
+ }
149
+
150
+ private static Assembly? OnAssemblyResolve(object? sender, ResolveEventArgs args)
151
+ {
152
+ try
153
+ {
154
+ var requested = new AssemblyName(args.Name).Name;
155
+ if (string.IsNullOrEmpty(requested)) return null;
156
+
157
+ if (s_assemblyLoadCache.TryGetValue(requested, out var cached)) return cached;
158
+
159
+ // Check already-loaded assemblies first (avoid recursive Assembly.Load).
160
+ var loadedAsm = AppDomain.CurrentDomain.GetAssemblies()
161
+ .FirstOrDefault(a => string.Equals(a.GetName().Name, requested, StringComparison.OrdinalIgnoreCase));
162
+ if (loadedAsm is not null)
163
+ {
164
+ s_assemblyLoadCache[requested] = loadedAsm;
165
+ return loadedAsm;
166
+ }
167
+
168
+ // Try to locate a matching dll in known search directories.
169
+ foreach (var dir in s_assemblySearchDirs)
170
+ {
171
+ try
172
+ {
173
+ var candidate = Path.Combine(dir, requested + ".dll");
174
+ if (File.Exists(candidate))
175
+ {
176
+ try
177
+ {
178
+ var asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(candidate);
179
+ s_assemblyLoadCache[requested] = asm;
180
+ return asm;
181
+ }
182
+ catch { }
183
+ }
184
+ }
185
+ catch { }
186
+ }
187
+
188
+ s_assemblyLoadCache[requested] = null;
189
+ }
190
+ catch { }
191
+ return null;
192
+ }
193
+
43
194
  [UnmanagedCallersOnly(EntryPoint = "RegisterJsCallback",
44
195
  CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])]
45
196
  public static unsafe int RegisterJsCallback(
@@ -71,14 +71,22 @@ internal readonly struct DispatchResult
71
71
  private readonly string[]? _properties;
72
72
  private readonly string[]? _staticMethods;
73
73
  private readonly string[]? _staticProperties;
74
+ private readonly string[]? _readonlyProperties;
75
+ private readonly string[]? _readonlyStaticProperties;
76
+ private readonly string[]? _writeonlyProperties;
77
+ private readonly string[]? _writeonlyStaticProperties;
74
78
 
75
79
  private DispatchResult(DispatchKind kind, object? value, Type? type, int handle,
76
80
  string? typeName, string[]? methods, string[]? props,
77
- string[]? staticMethods, string[]? staticProps)
81
+ string[]? staticMethods, string[]? staticProps,
82
+ string[]? readonlyProps = null, string[]? readonlyStaticProps = null,
83
+ string[]? writeonlyProps = null, string[]? writeonlyStaticProps = null)
78
84
  {
79
85
  _kind = kind; _value = value; _type = type; _handle = handle;
80
86
  _typeName = typeName; _methods = methods; _properties = props;
81
87
  _staticMethods = staticMethods; _staticProperties = staticProps;
88
+ _readonlyProperties = readonlyProps; _readonlyStaticProperties = readonlyStaticProps;
89
+ _writeonlyProperties = writeonlyProps; _writeonlyStaticProperties = writeonlyStaticProps;
82
90
  }
83
91
 
84
92
  public static DispatchResult Primitive(object value, Type type)
@@ -91,8 +99,12 @@ internal readonly struct DispatchResult
91
99
  => new(DispatchKind.Collection, items, null, 0, null, null, null, null, null);
92
100
 
93
101
  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);
102
+ string[] methods, string[] props, string[] staticMethods, string[] staticProps,
103
+ string[] readonlyProps, string[] readonlyStaticProps,
104
+ string[] writeonlyProps, string[] writeonlyStaticProps)
105
+ => new(DispatchKind.Members, null, null, 0, null,
106
+ methods, props, staticMethods, staticProps,
107
+ readonlyProps, readonlyStaticProps, writeonlyProps, writeonlyStaticProps);
96
108
 
97
109
  internal int HandleId() => _handle;
98
110
 
@@ -126,10 +138,14 @@ internal readonly struct DispatchResult
126
138
 
127
139
  case DispatchKind.Members:
128
140
  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!);
141
+ WriteStringArray(w, "methods"u8, _methods!);
142
+ WriteStringArray(w, "properties"u8, _properties!);
143
+ WriteStringArray(w, "staticMethods"u8, _staticMethods!);
144
+ WriteStringArray(w, "staticProperties"u8, _staticProperties!);
145
+ WriteStringArray(w, "readonlyProperties"u8, _readonlyProperties!);
146
+ WriteStringArray(w, "readonlyStaticProperties"u8, _readonlyStaticProperties!);
147
+ WriteStringArray(w, "writeonlyProperties"u8, _writeonlyProperties!);
148
+ WriteStringArray(w, "writeonlyStaticProperties"u8,_writeonlyStaticProperties!);
133
149
  w.WriteEndObject();
134
150
  break;
135
151
  }
@@ -185,6 +201,10 @@ internal readonly struct DispatchResult
185
201
  WriteStringArrayBin(ref w, _properties!);
186
202
  WriteStringArrayBin(ref w, _staticMethods!);
187
203
  WriteStringArrayBin(ref w, _staticProperties!);
204
+ WriteStringArrayBin(ref w, _readonlyProperties!);
205
+ WriteStringArrayBin(ref w, _readonlyStaticProperties!);
206
+ WriteStringArrayBin(ref w, _writeonlyProperties!);
207
+ WriteStringArrayBin(ref w, _writeonlyStaticProperties!);
188
208
  break;
189
209
  }
190
210
  }
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nativescript/windows",
3
- "version": "0.1.0-alpha.50",
3
+ "version": "0.1.0-alpha.52",
4
4
  "description": "NativeScript for using Windows v8",
5
5
  "repository": {
6
6
  "type": "git",