@thelacanians/vue-native-cli 0.4.3 → 0.4.4

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.
Files changed (172) hide show
  1. package/dist/cli.js +34 -17
  2. package/native/android/README.md +205 -0
  3. package/native/android/VueNativeCore/build.gradle.kts +100 -0
  4. package/native/android/VueNativeCore/consumer-rules.pro +12 -0
  5. package/native/android/VueNativeCore/proguard-rules.pro +33 -0
  6. package/native/android/VueNativeCore/src/main/AndroidManifest.xml +17 -0
  7. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/ErrorOverlayView.kt +94 -0
  8. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/HotReloadManager.kt +105 -0
  9. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/JSPolyfills.kt +652 -0
  10. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/JSRuntime.kt +207 -0
  11. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/NativeBridge.kt +417 -0
  12. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/ComponentRegistry.kt +76 -0
  13. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VActionSheetFactory.kt +78 -0
  14. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VActivityIndicatorFactory.kt +46 -0
  15. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VAlertDialogFactory.kt +84 -0
  16. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VButtonFactory.kt +73 -0
  17. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VCheckboxFactory.kt +93 -0
  18. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VDropdownFactory.kt +125 -0
  19. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VImageFactory.kt +75 -0
  20. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VInputFactory.kt +210 -0
  21. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VKeyboardAvoidingFactory.kt +31 -0
  22. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VListFactory.kt +183 -0
  23. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VModalFactory.kt +105 -0
  24. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VPickerFactory.kt +57 -0
  25. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VPressableFactory.kt +109 -0
  26. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VProgressBarFactory.kt +43 -0
  27. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRadioFactory.kt +103 -0
  28. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRefreshControlFactory.kt +73 -0
  29. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRootFactory.kt +39 -0
  30. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSafeAreaFactory.kt +48 -0
  31. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VScrollViewFactory.kt +105 -0
  32. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSectionListFactory.kt +144 -0
  33. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSegmentedControlFactory.kt +77 -0
  34. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSliderFactory.kt +74 -0
  35. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VStatusBarFactory.kt +52 -0
  36. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSwitchFactory.kt +62 -0
  37. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VTextFactory.kt +53 -0
  38. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VVideoFactory.kt +191 -0
  39. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VViewFactory.kt +48 -0
  40. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VWebViewFactory.kt +90 -0
  41. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/NativeComponentFactory.kt +40 -0
  42. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/VTextNodeView.kt +23 -0
  43. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/GestureHelper.kt +16 -0
  44. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/TouchableView.kt +105 -0
  45. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AnimationModule.kt +292 -0
  46. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AppStateModule.kt +41 -0
  47. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AsyncStorageModule.kt +59 -0
  48. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AudioModule.kt +331 -0
  49. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BackgroundTaskModule.kt +166 -0
  50. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BiometryModule.kt +56 -0
  51. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BluetoothModule.kt +302 -0
  52. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/CalendarModule.kt +198 -0
  53. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/CameraModule.kt +64 -0
  54. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ClipboardModule.kt +36 -0
  55. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ContactsModule.kt +288 -0
  56. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/DatabaseModule.kt +229 -0
  57. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/DeviceInfoModule.kt +39 -0
  58. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/FileSystemModule.kt +193 -0
  59. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/GeolocationModule.kt +68 -0
  60. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/HapticsModule.kt +61 -0
  61. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/HttpModule.kt +111 -0
  62. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/IAPModule.kt +302 -0
  63. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/KeyboardModule.kt +26 -0
  64. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/LinkingModule.kt +43 -0
  65. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModule.kt +27 -0
  66. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModuleRegistry.kt +92 -0
  67. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NetworkModule.kt +75 -0
  68. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NotificationsModule.kt +181 -0
  69. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/OTAModule.kt +255 -0
  70. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/PerformanceModule.kt +147 -0
  71. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/PermissionsModule.kt +126 -0
  72. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SecureStorageModule.kt +51 -0
  73. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SensorsModule.kt +134 -0
  74. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ShareModule.kt +36 -0
  75. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SocialAuthModule.kt +160 -0
  76. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/WebSocketModule.kt +155 -0
  77. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Styling/StyleEngine.kt +802 -0
  78. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Tags.kt +43 -0
  79. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/VueNativeActivity.kt +169 -0
  80. package/native/android/VueNativeCore/src/main/res/values/ids.xml +8 -0
  81. package/native/android/app/build.gradle.kts +45 -0
  82. package/native/android/app/proguard-rules.pro +5 -0
  83. package/native/android/app/src/main/AndroidManifest.xml +25 -0
  84. package/native/android/app/src/main/assets/.gitkeep +0 -0
  85. package/native/android/app/src/main/kotlin/com/vuenative/example/counter/MainActivity.kt +14 -0
  86. package/native/android/app/src/main/res/layout/activity_main.xml +6 -0
  87. package/native/android/app/src/main/res/values/strings.xml +3 -0
  88. package/native/android/app/src/main/res/values/themes.xml +9 -0
  89. package/native/android/app/src/main/res/xml/network_security_config.xml +8 -0
  90. package/native/android/build.gradle.kts +6 -0
  91. package/native/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  92. package/native/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  93. package/native/android/gradle.properties +4 -0
  94. package/native/android/gradlew +87 -0
  95. package/native/android/gradlew.bat +48 -0
  96. package/native/android/settings.gradle.kts +20 -0
  97. package/native/ios/VueNativeCore/Package.resolved +23 -0
  98. package/native/ios/VueNativeCore/Package.swift +32 -0
  99. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/CertificatePinning.swift +132 -0
  100. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/ErrorOverlayView.swift +92 -0
  101. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/HotReloadManager.swift +147 -0
  102. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/JSPolyfills.swift +711 -0
  103. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/JSRuntime.swift +421 -0
  104. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/NativeBridge.swift +891 -0
  105. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/VueNativeViewController.swift +88 -0
  106. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/ComponentRegistry.swift +193 -0
  107. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VActionSheetFactory.swift +91 -0
  108. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VActivityIndicatorFactory.swift +74 -0
  109. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VAlertDialogFactory.swift +150 -0
  110. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VButtonFactory.swift +93 -0
  111. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VCheckboxFactory.swift +114 -0
  112. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VDropdownFactory.swift +112 -0
  113. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VImageFactory.swift +172 -0
  114. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VInputFactory.swift +357 -0
  115. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VKeyboardAvoidingFactory.swift +99 -0
  116. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VListFactory.swift +250 -0
  117. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VModalFactory.swift +112 -0
  118. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VPickerFactory.swift +96 -0
  119. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VPressableFactory.swift +168 -0
  120. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VProgressBarFactory.swift +39 -0
  121. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VRadioFactory.swift +167 -0
  122. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VRefreshControlFactory.swift +153 -0
  123. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSafeAreaFactory.swift +56 -0
  124. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VScrollViewFactory.swift +240 -0
  125. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSectionListFactory.swift +248 -0
  126. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSegmentedControlFactory.swift +73 -0
  127. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSliderFactory.swift +63 -0
  128. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VStatusBarFactory.swift +50 -0
  129. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSwitchFactory.swift +108 -0
  130. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VTextFactory.swift +290 -0
  131. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VVideoFactory.swift +246 -0
  132. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VViewFactory.swift +157 -0
  133. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VWebViewFactory.swift +172 -0
  134. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/NativeComponentFactory.swift +53 -0
  135. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/GestureWrapper.swift +107 -0
  136. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/TouchableView.swift +136 -0
  137. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/UIColor+Hex.swift +80 -0
  138. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AnimationModule.swift +291 -0
  139. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AppStateModule.swift +65 -0
  140. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AsyncStorageModule.swift +68 -0
  141. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AudioModule.swift +366 -0
  142. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BackgroundTaskModule.swift +135 -0
  143. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BiometryModule.swift +61 -0
  144. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BluetoothModule.swift +387 -0
  145. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CalendarModule.swift +161 -0
  146. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CameraModule.swift +318 -0
  147. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ClipboardModule.swift +33 -0
  148. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ContactsModule.swift +173 -0
  149. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DatabaseModule.swift +259 -0
  150. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DeviceInfoModule.swift +34 -0
  151. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/FileSystemModule.swift +233 -0
  152. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/GeolocationModule.swift +147 -0
  153. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/HapticsModule.swift +50 -0
  154. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/IAPModule.swift +194 -0
  155. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/KeyboardModule.swift +31 -0
  156. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/LinkingModule.swift +42 -0
  157. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModule.swift +28 -0
  158. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModuleRegistry.swift +78 -0
  159. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NetworkModule.swift +62 -0
  160. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NotificationsModule.swift +215 -0
  161. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/OTAModule.swift +281 -0
  162. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PerformanceModule.swift +138 -0
  163. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PermissionsModule.swift +190 -0
  164. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SecureStorageModule.swift +118 -0
  165. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SensorsModule.swift +103 -0
  166. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ShareModule.swift +49 -0
  167. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SocialAuthModule.swift +240 -0
  168. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/WebSocketModule.swift +213 -0
  169. package/native/ios/VueNativeCore/Sources/VueNativeCore/Resources/vue-native-placeholder.js +8 -0
  170. package/native/ios/VueNativeCore/Sources/VueNativeCore/Styling/StyleEngine.swift +885 -0
  171. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/JSRuntimeTests.swift +362 -0
  172. package/package.json +3 -2
@@ -0,0 +1,421 @@
1
+ #if canImport(UIKit)
2
+ import JavaScriptCore
3
+ import Foundation
4
+
5
+ // MARK: - Bundle Source
6
+
7
+ /// Describes where to load the JS application bundle from.
8
+ public enum BundleSource {
9
+ /// Load from an embedded resource in the app bundle.
10
+ case embedded(name: String)
11
+ /// Load from a development server URL (for live reload).
12
+ case devServer(url: URL)
13
+ }
14
+
15
+ // MARK: - JSRuntime
16
+
17
+ /// Core JavaScript runtime manager. Wraps JSContext on a dedicated serial DispatchQueue.
18
+ /// All JS operations are guaranteed to execute on the JS queue. UIKit operations
19
+ /// are never performed on this queue.
20
+ ///
21
+ /// Thread safety contract:
22
+ /// - All JSContext access happens exclusively on `jsQueue`
23
+ /// - Never pass JSValue across threads — extract primitives first
24
+ /// - All closures registered with JSContext use [weak self]
25
+ public final class JSRuntime: @unchecked Sendable {
26
+
27
+ // MARK: - Singleton
28
+
29
+ public static let shared = JSRuntime()
30
+
31
+ // MARK: - Properties
32
+
33
+ /// Dedicated serial queue for all JavaScript execution.
34
+ /// QoS is userInteractive because JS drives the UI pipeline.
35
+ public let jsQueue = DispatchQueue(label: "com.vuenative.js", qos: .userInteractive)
36
+
37
+ /// The underlying JavaScriptCore context. Only access on jsQueue.
38
+ public private(set) var context: JSContext!
39
+
40
+ /// Whether the runtime has been initialized.
41
+ public private(set) var isInitialized = false
42
+
43
+ /// Startup time reference for performance.now()
44
+ public let startTime: CFAbsoluteTime = CFAbsoluteTimeGetCurrent()
45
+
46
+ // MARK: - Initialization
47
+
48
+ private init() {}
49
+
50
+ /// Initialize the JS runtime. Creates the JSContext on the JS queue,
51
+ /// configures exception handling, and registers polyfills.
52
+ /// Must be called before any other method.
53
+ public func initialize(completion: (() -> Void)? = nil) {
54
+ jsQueue.async { [weak self] in
55
+ guard let self = self else { return }
56
+ guard !self.isInitialized else {
57
+ completion?()
58
+ return
59
+ }
60
+
61
+ // Create the JSContext
62
+ self.context = JSContext()
63
+
64
+ // Configure exception handler
65
+ self.context.exceptionHandler = { [weak self] context, exception in
66
+ guard let exception = exception else { return }
67
+ let message = exception.toString() ?? "Unknown JS error"
68
+ let line = exception.objectForKeyedSubscript("line")?.toInt32() ?? 0
69
+ let column = exception.objectForKeyedSubscript("column")?.toInt32() ?? 0
70
+ let stack = exception.objectForKeyedSubscript("stack")?.toString() ?? ""
71
+ NSLog("[VueNative JS Error] \(message) at line \(line):\(column)")
72
+ if !stack.isEmpty {
73
+ NSLog("[VueNative JS Stack] \(stack)")
74
+ }
75
+ #if DEBUG
76
+ let fullMessage = stack.isEmpty ? message : "\(message)\n\n\(stack)"
77
+ ErrorOverlayView.show(error: fullMessage)
78
+ #endif
79
+ _ = self // prevent unused warning
80
+ }
81
+
82
+ // Set globalThis = global object
83
+ self.context.evaluateScript("var globalThis = this;")
84
+
85
+ // Register polyfills
86
+ JSPolyfills.register(in: self)
87
+
88
+ self.isInitialized = true
89
+ completion?()
90
+ }
91
+ }
92
+
93
+ // MARK: - Script Evaluation
94
+
95
+ /// Evaluate a JavaScript string on the JS queue.
96
+ /// The completion handler is called on the JS queue with the result.
97
+ public func evaluateScript(_ script: String, sourceURL: String? = nil, completion: ((JSValue?) -> Void)? = nil) {
98
+ jsQueue.async { [weak self] in
99
+ guard let self = self, let context = self.context else {
100
+ completion?(nil)
101
+ return
102
+ }
103
+
104
+ let result: JSValue?
105
+ if let sourceURL = sourceURL, let url = URL(string: sourceURL) {
106
+ result = context.evaluateScript(script, withSourceURL: url)
107
+ } else {
108
+ result = context.evaluateScript(script)
109
+ }
110
+
111
+ // Force microtask drain after evaluation.
112
+ // JSC may not automatically drain microtasks after evaluateScript returns.
113
+ // This ensures Vue's Promise-based scheduler flushes.
114
+ context.evaluateScript("void 0;")
115
+
116
+ completion?(result)
117
+ }
118
+ }
119
+
120
+ /// Evaluate a script synchronously. MUST only be called from the JS queue.
121
+ /// Returns the JSValue result directly.
122
+ @discardableResult
123
+ public func evaluateScriptSync(_ script: String, sourceURL: String? = nil) -> JSValue? {
124
+ dispatchPrecondition(condition: .onQueue(jsQueue))
125
+ guard let context = context else { return nil }
126
+
127
+ let result: JSValue?
128
+ if let sourceURL = sourceURL, let url = URL(string: sourceURL) {
129
+ result = context.evaluateScript(script, withSourceURL: url)
130
+ } else {
131
+ result = context.evaluateScript(script)
132
+ }
133
+
134
+ // Force microtask drain
135
+ context.evaluateScript("void 0;")
136
+ return result
137
+ }
138
+
139
+ // MARK: - Function Calls
140
+
141
+ /// Call a global JS function by name with arguments. Runs on the JS queue.
142
+ /// Uses objectForKeyedSubscript().call() for performance (avoids re-parsing).
143
+ public func callFunction(_ name: String, withArguments args: [Any], completion: ((JSValue?) -> Void)? = nil) {
144
+ jsQueue.async { [weak self] in
145
+ guard let self = self, let context = self.context else {
146
+ completion?(nil)
147
+ return
148
+ }
149
+
150
+ let function = context.objectForKeyedSubscript(name)
151
+ guard let fn = function, !fn.isUndefined else {
152
+ NSLog("[VueNative] Warning: JS function '\(name)' not found")
153
+ completion?(nil)
154
+ return
155
+ }
156
+
157
+ let result = fn.call(withArguments: args)
158
+
159
+ // Force microtask drain
160
+ context.evaluateScript("void 0;")
161
+
162
+ completion?(result)
163
+ }
164
+ }
165
+
166
+ /// Call a global JS function synchronously. MUST only be called from the JS queue.
167
+ @discardableResult
168
+ public func callFunctionSync(_ name: String, withArguments args: [Any]) -> JSValue? {
169
+ dispatchPrecondition(condition: .onQueue(jsQueue))
170
+ guard let context = context else { return nil }
171
+
172
+ let function = context.objectForKeyedSubscript(name)
173
+ guard let fn = function, !fn.isUndefined else {
174
+ NSLog("[VueNative] Warning: JS function '\(name)' not found")
175
+ return nil
176
+ }
177
+
178
+ let result = fn.call(withArguments: args)
179
+
180
+ // Force microtask drain
181
+ context.evaluateScript("void 0;")
182
+ return result
183
+ }
184
+
185
+ // MARK: - Function Registration
186
+
187
+ /// Register a Swift function as a global JS function.
188
+ /// The block receives a single JSValue argument (use .toArray() etc. to extract args).
189
+ /// IMPORTANT: The block executes on the JS queue.
190
+ public func registerFunction(_ name: String, block: @escaping @convention(block) (JSValue) -> Void) {
191
+ jsQueue.async { [weak self] in
192
+ guard let self = self, let context = self.context else { return }
193
+ let wrappedBlock: @convention(block) (JSValue) -> Void = { [weak self] value in
194
+ _ = self // prevent retain cycle through closure capture
195
+ block(value)
196
+ }
197
+ context.setObject(wrappedBlock, forKeyedSubscript: name as NSString)
198
+ }
199
+ }
200
+
201
+ /// Register a Swift function with multiple arguments.
202
+ public func registerFunctionMultiArg(_ name: String, argCount: Int, block: @escaping ([JSValue]) -> Void) {
203
+ jsQueue.async { [weak self] in
204
+ guard let self = self, let context = self.context else { return }
205
+
206
+ switch argCount {
207
+ case 0:
208
+ let wrapped: @convention(block) () -> Void = { [weak self] in
209
+ _ = self
210
+ block([])
211
+ }
212
+ context.setObject(wrapped, forKeyedSubscript: name as NSString)
213
+ case 1:
214
+ let wrapped: @convention(block) (JSValue) -> Void = { [weak self] a in
215
+ _ = self
216
+ block([a])
217
+ }
218
+ context.setObject(wrapped, forKeyedSubscript: name as NSString)
219
+ case 2:
220
+ let wrapped: @convention(block) (JSValue, JSValue) -> Void = { [weak self] a, b in
221
+ _ = self
222
+ block([a, b])
223
+ }
224
+ context.setObject(wrapped, forKeyedSubscript: name as NSString)
225
+ case 3:
226
+ let wrapped: @convention(block) (JSValue, JSValue, JSValue) -> Void = { [weak self] a, b, c in
227
+ _ = self
228
+ block([a, b, c])
229
+ }
230
+ context.setObject(wrapped, forKeyedSubscript: name as NSString)
231
+ default:
232
+ // For 4+ args, use the single-arg version and extract from JSValue
233
+ let wrapped: @convention(block) (JSValue) -> Void = { [weak self] value in
234
+ _ = self
235
+ block([value])
236
+ }
237
+ context.setObject(wrapped, forKeyedSubscript: name as NSString)
238
+ }
239
+ }
240
+ }
241
+
242
+ // MARK: - Bundle Loading
243
+
244
+ /// Load a JS application bundle from the given source.
245
+ /// Polyfills are already registered during initialize().
246
+ public func loadBundle(source: BundleSource, completion: ((Bool) -> Void)? = nil) {
247
+ jsQueue.async { [weak self] in
248
+ guard let self = self, self.context != nil else {
249
+ completion?(false)
250
+ return
251
+ }
252
+
253
+ switch source {
254
+ case .embedded(let name):
255
+ self.loadEmbeddedBundle(name: name, completion: completion)
256
+
257
+ case .devServer(let url):
258
+ self.loadDevServerBundle(url: url, completion: completion)
259
+ }
260
+ }
261
+ }
262
+
263
+ // MARK: - Private: Bundle Loading
264
+
265
+ private func loadEmbeddedBundle(name: String, completion: ((Bool) -> Void)?) {
266
+ // Try to find the bundle in the main app bundle
267
+ let bundleName: String
268
+ let bundleExtension: String
269
+
270
+ if name.contains(".") {
271
+ let parts = name.split(separator: ".", maxSplits: 1)
272
+ bundleName = String(parts[0])
273
+ bundleExtension = String(parts[1])
274
+ } else {
275
+ bundleName = name
276
+ bundleExtension = "js"
277
+ }
278
+
279
+ // Search in main bundle and SPM resource bundle
280
+ var scriptURL: URL?
281
+
282
+ if let url = Bundle.main.url(forResource: bundleName, withExtension: bundleExtension) {
283
+ scriptURL = url
284
+ } else {
285
+ // Try the module bundle (SPM resources)
286
+ #if SWIFT_PACKAGE
287
+ if let url = Bundle.module.url(forResource: bundleName, withExtension: bundleExtension) {
288
+ scriptURL = url
289
+ }
290
+ #endif
291
+ }
292
+
293
+ guard let url = scriptURL else {
294
+ NSLog("[VueNative] Error: Bundle '\(name)' not found in app resources")
295
+ completion?(false)
296
+ return
297
+ }
298
+
299
+ do {
300
+ let script = try String(contentsOf: url, encoding: .utf8)
301
+ NSLog("[VueNative] Loading bundle: \(name) (\(script.count) bytes)")
302
+ self.context.evaluateScript(script, withSourceURL: url)
303
+ // Force microtask drain after bundle load
304
+ self.context.evaluateScript("void 0;")
305
+ NSLog("[VueNative] Bundle loaded successfully")
306
+ completion?(true)
307
+ } catch {
308
+ NSLog("[VueNative] Error loading bundle '\(name)': \(error.localizedDescription)")
309
+ completion?(false)
310
+ }
311
+ }
312
+
313
+ private func loadDevServerBundle(url: URL, completion: ((Bool) -> Void)?) {
314
+ // Fetch from dev server on a background queue, then evaluate on JS queue
315
+ let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
316
+ guard let self = self else {
317
+ completion?(false)
318
+ return
319
+ }
320
+
321
+ self.jsQueue.async { [weak self] in
322
+ guard let self = self, self.context != nil else {
323
+ completion?(false)
324
+ return
325
+ }
326
+
327
+ if let error = error {
328
+ NSLog("[VueNative] Dev server error: \(error.localizedDescription)")
329
+ completion?(false)
330
+ return
331
+ }
332
+
333
+ guard let data = data, let script = String(data: data, encoding: .utf8) else {
334
+ NSLog("[VueNative] Dev server returned invalid data")
335
+ completion?(false)
336
+ return
337
+ }
338
+
339
+ NSLog("[VueNative] Loading dev bundle from \(url) (\(script.count) bytes)")
340
+ self.context.evaluateScript(script, withSourceURL: url)
341
+ // Force microtask drain
342
+ self.context.evaluateScript("void 0;")
343
+ NSLog("[VueNative] Dev bundle loaded successfully")
344
+ completion?(true)
345
+ }
346
+ }
347
+ task.resume()
348
+ }
349
+
350
+ // MARK: - Hot Reload
351
+
352
+ /// Reload the runtime with a new JavaScript bundle string.
353
+ /// Creates a fresh JSContext, re-registers polyfills, and evaluates the bundle.
354
+ /// Calls completion on the JS queue with success/failure.
355
+ public func reload(bundle: String, completion: ((Bool) -> Void)? = nil) {
356
+ jsQueue.async { [weak self] in
357
+ guard let self = self else {
358
+ completion?(false)
359
+ return
360
+ }
361
+
362
+ NSLog("[VueNative] Hot reload: tearing down old context...")
363
+
364
+ // Tear down old Vue app gracefully
365
+ if let teardown = self.context?.objectForKeyedSubscript("__VN_teardown"),
366
+ !teardown.isUndefined {
367
+ teardown.call(withArguments: [])
368
+ self.context?.evaluateScript("void 0;")
369
+ }
370
+
371
+ // Reset polyfill state (timers, RAF, display link) before creating new context
372
+ JSPolyfills.reset()
373
+
374
+ // Create fresh context
375
+ self.context = JSContext()
376
+ self.context.exceptionHandler = { [weak self] _, exception in
377
+ guard let exception = exception else { return }
378
+ let message = exception.toString() ?? "Unknown JS error"
379
+ let line = exception.objectForKeyedSubscript("line")?.toInt32() ?? 0
380
+ let stack = exception.objectForKeyedSubscript("stack")?.toString() ?? ""
381
+ NSLog("[VueNative JS Error] \(message) at line \(line)")
382
+ #if DEBUG
383
+ let fullMessage = stack.isEmpty ? message : "\(message)\n\n\(stack)"
384
+ ErrorOverlayView.show(error: fullMessage)
385
+ #endif
386
+ _ = self
387
+ }
388
+
389
+ // Re-register globalThis and polyfills
390
+ self.context.evaluateScript("var globalThis = this;")
391
+ JSPolyfills.register(in: self)
392
+
393
+ NSLog("[VueNative] Hot reload: evaluating new bundle (\(bundle.count) bytes)...")
394
+ self.context.evaluateScript(bundle)
395
+ if let exception = self.context.exception {
396
+ NSLog("[VueNative] Hot reload bundle error: %@", exception.toString() ?? "unknown")
397
+ self.context.exception = nil
398
+ completion?(false)
399
+ return
400
+ }
401
+ self.context.evaluateScript("void 0;")
402
+ NSLog("[VueNative] Hot reload: complete")
403
+
404
+ completion?(true)
405
+ }
406
+ }
407
+
408
+ // MARK: - Teardown
409
+
410
+ /// Invalidate the runtime and release resources.
411
+ /// After calling this, the runtime cannot be used again.
412
+ public func invalidate() {
413
+ jsQueue.async { [weak self] in
414
+ guard let self = self else { return }
415
+ self.context = nil
416
+ self.isInitialized = false
417
+ NSLog("[VueNative] JS runtime invalidated")
418
+ }
419
+ }
420
+ }
421
+ #endif