@nativescript/vite 8.0.0-alpha.3 → 8.0.0-alpha.30

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 (295) hide show
  1. package/README.md +51 -11
  2. package/configuration/angular.d.ts +34 -1
  3. package/configuration/angular.js +369 -159
  4. package/configuration/angular.js.map +1 -1
  5. package/configuration/base.js +184 -14
  6. package/configuration/base.js.map +1 -1
  7. package/configuration/javascript.js +5 -72
  8. package/configuration/javascript.js.map +1 -1
  9. package/configuration/solid.js +27 -1
  10. package/configuration/solid.js.map +1 -1
  11. package/configuration/typescript.js +5 -75
  12. package/configuration/typescript.js.map +1 -1
  13. package/helpers/angular/angular-linker.d.ts +5 -6
  14. package/helpers/angular/angular-linker.js +36 -121
  15. package/helpers/angular/angular-linker.js.map +1 -1
  16. package/helpers/angular/inject-component-hmr-registration.d.ts +112 -0
  17. package/helpers/angular/inject-component-hmr-registration.js +291 -0
  18. package/helpers/angular/inject-component-hmr-registration.js.map +1 -0
  19. package/helpers/angular/inject-hmr-vite-ignore.d.ts +75 -0
  20. package/helpers/angular/inject-hmr-vite-ignore.js +221 -0
  21. package/helpers/angular/inject-hmr-vite-ignore.js.map +1 -0
  22. package/helpers/angular/inline-decorator-component-templates.js +1 -170
  23. package/helpers/angular/inline-decorator-component-templates.js.map +1 -1
  24. package/helpers/angular/js-lexer.d.ts +4 -0
  25. package/helpers/angular/js-lexer.js +182 -0
  26. package/helpers/angular/js-lexer.js.map +1 -0
  27. package/helpers/angular/shared-linker.d.ts +31 -3
  28. package/helpers/angular/shared-linker.js +67 -14
  29. package/helpers/angular/shared-linker.js.map +1 -1
  30. package/helpers/angular/synthesize-decorator-ctor-parameters.js +2 -170
  31. package/helpers/angular/synthesize-decorator-ctor-parameters.js.map +1 -1
  32. package/helpers/angular/synthesize-injectable-factories.js +1 -174
  33. package/helpers/angular/synthesize-injectable-factories.js.map +1 -1
  34. package/helpers/angular/util.d.ts +1 -0
  35. package/helpers/angular/util.js +88 -0
  36. package/helpers/angular/util.js.map +1 -1
  37. package/helpers/app-components.d.ts +2 -1
  38. package/helpers/app-components.js.map +1 -1
  39. package/helpers/app-css-state.d.ts +8 -0
  40. package/helpers/app-css-state.js +8 -0
  41. package/helpers/app-css-state.js.map +1 -0
  42. package/helpers/bundler-context.d.ts +11 -0
  43. package/helpers/bundler-context.js +71 -0
  44. package/helpers/bundler-context.js.map +1 -0
  45. package/helpers/config-as-json.js +10 -0
  46. package/helpers/config-as-json.js.map +1 -1
  47. package/helpers/dev-host.d.ts +341 -0
  48. package/helpers/dev-host.js +617 -0
  49. package/helpers/dev-host.js.map +1 -0
  50. package/helpers/esbuild-platform-resolver.js +4 -1
  51. package/helpers/esbuild-platform-resolver.js.map +1 -1
  52. package/helpers/global-defines.d.ts +51 -0
  53. package/helpers/global-defines.js +77 -0
  54. package/helpers/global-defines.js.map +1 -1
  55. package/helpers/hmr-scope.d.ts +26 -0
  56. package/helpers/hmr-scope.js +67 -0
  57. package/helpers/hmr-scope.js.map +1 -0
  58. package/helpers/init.js +0 -18
  59. package/helpers/init.js.map +1 -1
  60. package/helpers/logging.d.ts +1 -0
  61. package/helpers/logging.js +63 -3
  62. package/helpers/logging.js.map +1 -1
  63. package/helpers/main-entry.d.ts +2 -1
  64. package/helpers/main-entry.js +430 -47
  65. package/helpers/main-entry.js.map +1 -1
  66. package/helpers/nativeclass-esbuild-plugin.d.ts +2 -1
  67. package/helpers/nativeclass-esbuild-plugin.js.map +1 -1
  68. package/helpers/nativeclass-transform.js.map +1 -1
  69. package/helpers/nativeclass-transformer-plugin.d.ts +9 -2
  70. package/helpers/nativeclass-transformer-plugin.js +157 -14
  71. package/helpers/nativeclass-transformer-plugin.js.map +1 -1
  72. package/helpers/nativescript-package-resolver.js +8 -3
  73. package/helpers/nativescript-package-resolver.js.map +1 -1
  74. package/helpers/normalize-id.d.ts +42 -0
  75. package/helpers/normalize-id.js +60 -0
  76. package/helpers/normalize-id.js.map +1 -0
  77. package/helpers/ns-core-url.d.ts +88 -0
  78. package/helpers/ns-core-url.js +191 -0
  79. package/helpers/ns-core-url.js.map +1 -0
  80. package/helpers/package-platform-aliases.js +4 -3
  81. package/helpers/package-platform-aliases.js.map +1 -1
  82. package/helpers/platform-types.d.ts +2 -0
  83. package/helpers/platform-types.js +2 -0
  84. package/helpers/platform-types.js.map +1 -0
  85. package/helpers/prelink-angular.js +12 -33
  86. package/helpers/prelink-angular.js.map +1 -1
  87. package/helpers/project.d.ts +35 -0
  88. package/helpers/project.js +120 -2
  89. package/helpers/project.js.map +1 -1
  90. package/helpers/resolver.js +17 -2
  91. package/helpers/resolver.js.map +1 -1
  92. package/helpers/solid-jsx-deps.d.ts +15 -0
  93. package/helpers/solid-jsx-deps.js +178 -0
  94. package/helpers/solid-jsx-deps.js.map +1 -0
  95. package/helpers/ts-config-paths.d.ts +14 -0
  96. package/helpers/ts-config-paths.js +89 -8
  97. package/helpers/ts-config-paths.js.map +1 -1
  98. package/helpers/typescript-check.d.ts +2 -1
  99. package/helpers/typescript-check.js.map +1 -1
  100. package/helpers/workers.d.ts +20 -19
  101. package/helpers/workers.js +624 -4
  102. package/helpers/workers.js.map +1 -1
  103. package/hmr/client/css-handler.d.ts +1 -0
  104. package/hmr/client/css-handler.js +33 -20
  105. package/hmr/client/css-handler.js.map +1 -1
  106. package/hmr/client/css-update-overlay.d.ts +18 -0
  107. package/hmr/client/css-update-overlay.js +27 -0
  108. package/hmr/client/css-update-overlay.js.map +1 -0
  109. package/hmr/client/hmr-pending-overlay.d.ts +27 -0
  110. package/hmr/client/hmr-pending-overlay.js +50 -0
  111. package/hmr/client/hmr-pending-overlay.js.map +1 -0
  112. package/hmr/client/index.js +419 -15
  113. package/hmr/client/index.js.map +1 -1
  114. package/hmr/client/utils.d.ts +6 -1
  115. package/hmr/client/utils.js +184 -8
  116. package/hmr/client/utils.js.map +1 -1
  117. package/hmr/client/vue-sfc-update-overlay.d.ts +82 -0
  118. package/hmr/client/vue-sfc-update-overlay.js +133 -0
  119. package/hmr/client/vue-sfc-update-overlay.js.map +1 -0
  120. package/hmr/entry-runtime.d.ts +2 -1
  121. package/hmr/entry-runtime.js +252 -65
  122. package/hmr/entry-runtime.js.map +1 -1
  123. package/hmr/frameworks/angular/client/index.d.ts +1 -0
  124. package/hmr/frameworks/angular/client/index.js +778 -20
  125. package/hmr/frameworks/angular/client/index.js.map +1 -1
  126. package/hmr/frameworks/angular/server/linker.js +1 -4
  127. package/hmr/frameworks/angular/server/linker.js.map +1 -1
  128. package/hmr/frameworks/angular/server/strategy.js +13 -15
  129. package/hmr/frameworks/angular/server/strategy.js.map +1 -1
  130. package/hmr/frameworks/solid/server/strategy.js +3 -18
  131. package/hmr/frameworks/solid/server/strategy.js.map +1 -1
  132. package/hmr/frameworks/typescript/server/strategy.js +2 -15
  133. package/hmr/frameworks/typescript/server/strategy.js.map +1 -1
  134. package/hmr/frameworks/vue/client/index.js +30 -199
  135. package/hmr/frameworks/vue/client/index.js.map +1 -1
  136. package/hmr/helpers/ast-normalizer.js +52 -5
  137. package/hmr/helpers/ast-normalizer.js.map +1 -1
  138. package/hmr/helpers/cjs-named-exports.d.ts +23 -0
  139. package/hmr/helpers/cjs-named-exports.js +152 -0
  140. package/hmr/helpers/cjs-named-exports.js.map +1 -0
  141. package/hmr/helpers/package-exports.d.ts +16 -0
  142. package/hmr/helpers/package-exports.js +396 -0
  143. package/hmr/helpers/package-exports.js.map +1 -0
  144. package/hmr/server/angular-root-component.d.ts +79 -0
  145. package/hmr/server/angular-root-component.js +149 -0
  146. package/hmr/server/angular-root-component.js.map +1 -0
  147. package/hmr/server/constants.js +13 -4
  148. package/hmr/server/constants.js.map +1 -1
  149. package/hmr/server/core-sanitize.d.ts +90 -7
  150. package/hmr/server/core-sanitize.js +211 -56
  151. package/hmr/server/core-sanitize.js.map +1 -1
  152. package/hmr/server/framework-strategy.d.ts +9 -19
  153. package/hmr/server/hmr-module-graph.d.ts +37 -0
  154. package/hmr/server/hmr-module-graph.js +214 -0
  155. package/hmr/server/hmr-module-graph.js.map +1 -0
  156. package/hmr/server/import-map.js +60 -8
  157. package/hmr/server/import-map.js.map +1 -1
  158. package/hmr/server/index.js +1 -0
  159. package/hmr/server/index.js.map +1 -1
  160. package/hmr/server/ns-core-cjs-shape.d.ts +204 -0
  161. package/hmr/server/ns-core-cjs-shape.js +271 -0
  162. package/hmr/server/ns-core-cjs-shape.js.map +1 -0
  163. package/hmr/server/ns-rt-bridge.d.ts +51 -0
  164. package/hmr/server/ns-rt-bridge.js +131 -0
  165. package/hmr/server/ns-rt-bridge.js.map +1 -0
  166. package/hmr/server/ns-rt-route.d.ts +5 -0
  167. package/hmr/server/ns-rt-route.js +35 -0
  168. package/hmr/server/ns-rt-route.js.map +1 -0
  169. package/hmr/server/perf-instrumentation.d.ts +114 -0
  170. package/hmr/server/perf-instrumentation.js +195 -0
  171. package/hmr/server/perf-instrumentation.js.map +1 -0
  172. package/hmr/server/require-guard.d.ts +1 -0
  173. package/hmr/server/require-guard.js +12 -0
  174. package/hmr/server/require-guard.js.map +1 -0
  175. package/hmr/server/route-helpers.d.ts +7 -0
  176. package/hmr/server/route-helpers.js +13 -0
  177. package/hmr/server/route-helpers.js.map +1 -0
  178. package/hmr/server/server-origin.d.ts +12 -0
  179. package/hmr/server/server-origin.js +66 -0
  180. package/hmr/server/server-origin.js.map +1 -0
  181. package/hmr/server/shared-transform-request.js +12 -5
  182. package/hmr/server/shared-transform-request.js.map +1 -1
  183. package/hmr/server/vendor-bare-module-shims.d.ts +4 -0
  184. package/hmr/server/vendor-bare-module-shims.js +80 -0
  185. package/hmr/server/vendor-bare-module-shims.js.map +1 -0
  186. package/hmr/server/vite-plugin.js +60 -42
  187. package/hmr/server/vite-plugin.js.map +1 -1
  188. package/hmr/server/websocket-angular-entry.js +1 -1
  189. package/hmr/server/websocket-angular-entry.js.map +1 -1
  190. package/hmr/server/websocket-angular-hot-update.d.ts +17 -0
  191. package/hmr/server/websocket-angular-hot-update.js +176 -2
  192. package/hmr/server/websocket-angular-hot-update.js.map +1 -1
  193. package/hmr/server/websocket-core-bridge.d.ts +41 -6
  194. package/hmr/server/websocket-core-bridge.js +72 -75
  195. package/hmr/server/websocket-core-bridge.js.map +1 -1
  196. package/hmr/server/websocket-css-hot-update.d.ts +33 -0
  197. package/hmr/server/websocket-css-hot-update.js +65 -0
  198. package/hmr/server/websocket-css-hot-update.js.map +1 -0
  199. package/hmr/server/websocket-device-transform.d.ts +21 -0
  200. package/hmr/server/websocket-device-transform.js +1570 -0
  201. package/hmr/server/websocket-device-transform.js.map +1 -0
  202. package/hmr/server/websocket-graph-upsert.d.ts +15 -0
  203. package/hmr/server/websocket-graph-upsert.js +20 -0
  204. package/hmr/server/websocket-graph-upsert.js.map +1 -1
  205. package/hmr/server/websocket-hmr-pending.d.ts +43 -0
  206. package/hmr/server/websocket-hmr-pending.js +55 -0
  207. package/hmr/server/websocket-hmr-pending.js.map +1 -0
  208. package/hmr/server/websocket-hot-update.d.ts +51 -0
  209. package/hmr/server/websocket-hot-update.js +1160 -0
  210. package/hmr/server/websocket-hot-update.js.map +1 -0
  211. package/hmr/server/websocket-import-map-route.d.ts +15 -0
  212. package/hmr/server/websocket-import-map-route.js +44 -0
  213. package/hmr/server/websocket-import-map-route.js.map +1 -0
  214. package/hmr/server/websocket-module-bindings.js +3 -3
  215. package/hmr/server/websocket-module-bindings.js.map +1 -1
  216. package/hmr/server/websocket-module-specifiers.d.ts +66 -2
  217. package/hmr/server/websocket-module-specifiers.js +202 -19
  218. package/hmr/server/websocket-module-specifiers.js.map +1 -1
  219. package/hmr/server/websocket-ns-core.d.ts +21 -0
  220. package/hmr/server/websocket-ns-core.js +305 -0
  221. package/hmr/server/websocket-ns-core.js.map +1 -0
  222. package/hmr/server/websocket-ns-entry.d.ts +22 -0
  223. package/hmr/server/websocket-ns-entry.js +150 -0
  224. package/hmr/server/websocket-ns-entry.js.map +1 -0
  225. package/hmr/server/websocket-ns-m-paths.d.ts +3 -0
  226. package/hmr/server/websocket-ns-m-paths.js +92 -0
  227. package/hmr/server/websocket-ns-m-paths.js.map +1 -0
  228. package/hmr/server/websocket-ns-m-request.d.ts +45 -0
  229. package/hmr/server/websocket-ns-m-request.js +196 -0
  230. package/hmr/server/websocket-ns-m-request.js.map +1 -0
  231. package/hmr/server/websocket-ns-m.d.ts +34 -0
  232. package/hmr/server/websocket-ns-m.js +853 -0
  233. package/hmr/server/websocket-ns-m.js.map +1 -0
  234. package/hmr/server/websocket-served-module-helpers.d.ts +39 -0
  235. package/hmr/server/websocket-served-module-helpers.js +654 -0
  236. package/hmr/server/websocket-served-module-helpers.js.map +1 -0
  237. package/hmr/server/websocket-sfc.d.ts +24 -0
  238. package/hmr/server/websocket-sfc.js +1223 -0
  239. package/hmr/server/websocket-sfc.js.map +1 -0
  240. package/hmr/server/websocket-txn.d.ts +6 -0
  241. package/hmr/server/websocket-txn.js +39 -0
  242. package/hmr/server/websocket-txn.js.map +1 -0
  243. package/hmr/server/websocket-vendor-unifier.d.ts +10 -0
  244. package/hmr/server/websocket-vendor-unifier.js +45 -0
  245. package/hmr/server/websocket-vendor-unifier.js.map +1 -0
  246. package/hmr/server/websocket.d.ts +0 -30
  247. package/hmr/server/websocket.js +599 -6038
  248. package/hmr/server/websocket.js.map +1 -1
  249. package/hmr/shared/runtime/boot-placeholder-ui.d.ts +69 -0
  250. package/hmr/shared/runtime/boot-placeholder-ui.js +101 -0
  251. package/hmr/shared/runtime/boot-placeholder-ui.js.map +1 -0
  252. package/hmr/shared/runtime/boot-progress.d.ts +40 -0
  253. package/hmr/shared/runtime/boot-progress.js +128 -0
  254. package/hmr/shared/runtime/boot-progress.js.map +1 -0
  255. package/hmr/shared/runtime/boot-timeline.d.ts +18 -0
  256. package/hmr/shared/runtime/boot-timeline.js +52 -0
  257. package/hmr/shared/runtime/boot-timeline.js.map +1 -0
  258. package/hmr/shared/runtime/dev-overlay-snapshots.d.ts +31 -0
  259. package/hmr/shared/runtime/dev-overlay-snapshots.js +324 -0
  260. package/hmr/shared/runtime/dev-overlay-snapshots.js.map +1 -0
  261. package/hmr/shared/runtime/dev-overlay.d.ts +75 -26
  262. package/hmr/shared/runtime/dev-overlay.js +990 -260
  263. package/hmr/shared/runtime/dev-overlay.js.map +1 -1
  264. package/hmr/shared/runtime/module-provenance.js +1 -4
  265. package/hmr/shared/runtime/module-provenance.js.map +1 -1
  266. package/hmr/shared/runtime/root-placeholder-view.d.ts +19 -0
  267. package/hmr/shared/runtime/root-placeholder-view.js +310 -0
  268. package/hmr/shared/runtime/root-placeholder-view.js.map +1 -0
  269. package/hmr/shared/runtime/root-placeholder.js +352 -194
  270. package/hmr/shared/runtime/root-placeholder.js.map +1 -1
  271. package/hmr/shared/runtime/session-bootstrap.js +164 -1
  272. package/hmr/shared/runtime/session-bootstrap.js.map +1 -1
  273. package/hmr/shared/runtime/vendor-bootstrap.js +1 -9
  274. package/hmr/shared/runtime/vendor-bootstrap.js.map +1 -1
  275. package/hmr/shared/vendor/manifest-collect.d.ts +32 -0
  276. package/hmr/shared/vendor/manifest-collect.js +512 -0
  277. package/hmr/shared/vendor/manifest-collect.js.map +1 -0
  278. package/hmr/shared/vendor/manifest-loader.d.ts +2 -1
  279. package/hmr/shared/vendor/manifest-loader.js +3 -2
  280. package/hmr/shared/vendor/manifest-loader.js.map +1 -1
  281. package/hmr/shared/vendor/manifest.d.ts +1 -5
  282. package/hmr/shared/vendor/manifest.js +102 -739
  283. package/hmr/shared/vendor/manifest.js.map +1 -1
  284. package/hmr/shared/vendor/vendor-device-shim.d.ts +1 -0
  285. package/hmr/shared/vendor/vendor-device-shim.js +208 -0
  286. package/hmr/shared/vendor/vendor-device-shim.js.map +1 -0
  287. package/hmr/shared/vendor/vendor-esbuild-plugins.d.ts +16 -0
  288. package/hmr/shared/vendor/vendor-esbuild-plugins.js +203 -0
  289. package/hmr/shared/vendor/vendor-esbuild-plugins.js.map +1 -0
  290. package/index.d.ts +1 -0
  291. package/index.js +5 -0
  292. package/index.js.map +1 -1
  293. package/package.json +55 -11
  294. package/runtime/core-aliases-early.js +17 -41
  295. package/runtime/core-aliases-early.js.map +1 -1
@@ -0,0 +1,1570 @@
1
+ // Device code-transform subsystem: rewrites a served module's imports + source
2
+ // for the on-device ESM runtime (the HMR plugin's hot path). Extracted verbatim
3
+ // from `websocket.ts`, which imports these back for the plugin closure; specs
4
+ // import them directly from this module. Pure functions only — no plugin/server
5
+ // state beyond the project-derived `APP_ROOT_DIR` and the CLI-env snapshot below.
6
+ import { sanitizeStrayCoreReferences, isDeepCoreSubpath } from './core-sanitize.js';
7
+ import { existsSync, readFileSync } from 'fs';
8
+ import { astNormalizeModuleImportsAndHelpers, astVerifyAndAnnotateDuplicates } from '../helpers/ast-normalizer.js';
9
+ import { stripDanglingViteCjsImports } from '../helpers/sanitize.js';
10
+ import * as path from 'path';
11
+ import * as PAT from './constants.js';
12
+ import { getVendorManifest, resolveVendorSpecifier } from '../shared/vendor/registry.js';
13
+ import { getMonorepoWorkspaceRoot, getProjectRootPath } from '../../helpers/project.js';
14
+ import { createProcessSfcCode } from '../frameworks/vue/server/sfc-transforms.js';
15
+ import { getProjectAppPath } from '../../helpers/utils.js';
16
+ import { getCliFlags } from '../../helpers/cli-flags.js';
17
+ import { buildCoreUrl, buildCoreUrlPath } from '../../helpers/ns-core-url.js';
18
+ import { resolveAngularCoreHmrImportSource, rewriteAngularEntryRegisterOnly } from './websocket-angular-entry.js';
19
+ import { linkAngularPartialsIfNeeded } from '../frameworks/angular/server/linker.js';
20
+ import { isCoreGlobalsReference, isLikelyNativeScriptRuntimePluginSpecifier, isNativeScriptCoreModule, isNativeScriptPluginModule, normalizeNativeScriptCoreSpecifier, normalizeNodeModulesSpecifier, resolveNodeModulesPackageBoundary, resolveVendorFromCandidate, resolveVendorRouting, rewriteFsAbsoluteToNsM, shouldPreserveBareRuntimePluginSubpathImport, viteDepsPathToBareSpecifier } from './websocket-module-specifiers.js';
21
+ import { ensureNativeScriptModuleBindings, getProcessCodeResolvedSpecifierOverrides } from './websocket-module-bindings.js';
22
+ import { collectTopLevelImportRecords, deduplicateLinkerImports, ensureDestructureRtImports, ensureDynamicHmrImportHelper, ensureVariableDynamicImportHelper, hoistTopLevelStaticImports, repairImportEqualsAssignments, stripCoreGlobalsImports, stripViteDynamicImportVirtual } from './websocket-served-module-helpers.js';
23
+ const APP_ROOT_DIR = getProjectAppPath();
24
+ // Build a serialized process.env object from CLI --env.* flags.
25
+ // This is injected into every HTTP-served module so app code referencing
26
+ // process.env.TEST_ENV (etc.) works on device in HMR dev mode.
27
+ const __processEnvEntries = { NODE_ENV: 'development' };
28
+ try {
29
+ const flags = getCliFlags();
30
+ for (const [k, v] of Object.entries(flags || {})) {
31
+ // Skip internal NativeScript build flags
32
+ if (['ios', 'android', 'visionos', 'platform', 'hmr', 'verbose'].includes(k))
33
+ continue;
34
+ __processEnvEntries[k] = String(v);
35
+ }
36
+ }
37
+ catch { }
38
+ const __processEnvJson = JSON.stringify(__processEnvEntries);
39
+ export function prepareAngularEntryForDevice(code, importerPath, sfcFileMap, depFileMap, projectRoot, verbose = false, outputDirOverrideRel, httpOrigin, resolveVendorAsHttp = false) {
40
+ const rewrittenCode = rewriteImports(code, importerPath, sfcFileMap, depFileMap, projectRoot, verbose, outputDirOverrideRel, httpOrigin, resolveVendorAsHttp);
41
+ return rewriteAngularEntryRegisterOnly(rewrittenCode, resolveAngularCoreHmrImportSource(rewrittenCode, httpOrigin));
42
+ }
43
+ const processSfcCode = createProcessSfcCode(processCodeForDevice);
44
+ // Bare specifiers and special skip patterns (virtual, data:, etc.)
45
+ const VENDOR_PACKAGES = /^[A-Za-z@][^:\/\s]*$/;
46
+ const SKIP_PATTERNS = /^(?:data:|blob:|node:|virtual:|vite:|\0|\/@@?id|\/__vite|__vite|__x00__)/;
47
+ function rewriteVitePrebundleImportsForDevice(code, preserveVendorImports) {
48
+ const imports = collectTopLevelImportRecords(code);
49
+ if (!imports.length) {
50
+ return code;
51
+ }
52
+ const edits = [];
53
+ for (const imp of imports) {
54
+ const source = imp.source;
55
+ const depMatch = source.match(/(?:^|\/)node_modules\/\.vite\/deps\/(.+)$/);
56
+ const depPath = depMatch?.[1] || (source.startsWith('.vite/deps/') ? source.slice('.vite/deps/'.length) : null);
57
+ if (!depPath) {
58
+ continue;
59
+ }
60
+ let replacement = '';
61
+ if (preserveVendorImports) {
62
+ const canonical = resolveVendorFromCandidate(`.vite/deps/${depPath}`);
63
+ const bareSpecifier = canonical || viteDepsPathToBareSpecifier(depPath);
64
+ if (bareSpecifier) {
65
+ replacement = imp.text.replace(source, bareSpecifier);
66
+ }
67
+ }
68
+ edits.push({
69
+ start: imp.start,
70
+ end: imp.end,
71
+ text: replacement,
72
+ });
73
+ }
74
+ if (!edits.length) {
75
+ return code;
76
+ }
77
+ let next = code;
78
+ for (const edit of edits.sort((left, right) => right.start - left.start)) {
79
+ next = next.slice(0, edit.start) + edit.text + next.slice(edit.end);
80
+ }
81
+ return next;
82
+ }
83
+ function buildNodeModuleProvenancePrelude(sourceId) {
84
+ if (!sourceId) {
85
+ return '';
86
+ }
87
+ const cleaned = sourceId.replace(PAT.QUERY_PATTERN, '');
88
+ let normalized = normalizeNodeModulesSpecifier(cleaned);
89
+ if (!normalized) {
90
+ const viteDepsMatch = cleaned.match(/(?:^|\/)node_modules\/\.vite\/deps\/([^?#]+)/);
91
+ if (viteDepsMatch?.[1]) {
92
+ normalized = `.vite/deps/${viteDepsMatch[1]}`;
93
+ }
94
+ }
95
+ if (!normalized) {
96
+ return '';
97
+ }
98
+ let packageSpecifier = normalized;
99
+ let via = 'node_modules';
100
+ if (normalized.startsWith('.vite/deps/')) {
101
+ via = 'vite-deps';
102
+ packageSpecifier = viteDepsPathToBareSpecifier(normalized.slice('.vite/deps/'.length)) || normalized;
103
+ }
104
+ const rootPackage = resolveNodeModulesPackageBoundary(packageSpecifier, getProjectRootPath()).packageName;
105
+ if (!rootPackage) {
106
+ return '';
107
+ }
108
+ return `try { const __nsRecord = globalThis.__NS_RECORD_MODULE_PROVENANCE__; if (typeof __nsRecord === 'function') { __nsRecord(${JSON.stringify(rootPackage)}, ${JSON.stringify({ kind: 'http-esm', specifier: packageSpecifier, url: sourceId, via })}); } } catch {}\n`;
109
+ }
110
+ function shouldRemapImport(spec) {
111
+ if (!spec || typeof spec !== 'string')
112
+ return false;
113
+ if (VENDOR_PACKAGES.test(spec))
114
+ return false;
115
+ if (isNativeScriptCoreModule(spec))
116
+ return false;
117
+ if (isNativeScriptPluginModule(spec))
118
+ return false;
119
+ if (resolveVendorFromCandidate(spec))
120
+ return false;
121
+ if (spec.startsWith('~/'))
122
+ return false;
123
+ if (SKIP_PATTERNS.test(spec))
124
+ return false;
125
+ if (!spec.startsWith('/') && !spec.startsWith('./') && !spec.startsWith('../')) {
126
+ return false;
127
+ }
128
+ return true;
129
+ }
130
+ function removeNamedImports(code, names) {
131
+ const regex = /^(\s*import\s*\{)([^}]*)(\}\s*from\s*['"][^'"]+['"];?)/gm;
132
+ return code.replace(regex, (_m, p1, specList, p3) => {
133
+ const srcMatch = /from\s*['"]\s*([^'"\s]+)\s*['"]/i.exec(_m);
134
+ const src = (srcMatch?.[1] || '').toLowerCase();
135
+ const isVueSource = /^(?:vue|nativescript-vue)(?:\b|\/)/i.test(src);
136
+ if (!isVueSource) {
137
+ return _m;
138
+ }
139
+ const remaining = specList
140
+ .split(',')
141
+ .map((s) => s.trim())
142
+ .filter(Boolean)
143
+ .filter((entry) => {
144
+ const base = entry.split(/\s+as\s+/i)[0].trim();
145
+ return !names.includes(base);
146
+ });
147
+ if (!remaining.length)
148
+ return '';
149
+ return `${p1} ${remaining.join(', ')} ${p3}`;
150
+ });
151
+ }
152
+ function normalizeImportPath(spec, importerDir) {
153
+ if (!spec)
154
+ return null;
155
+ let key;
156
+ if (spec.startsWith('/')) {
157
+ key = spec;
158
+ }
159
+ else if (spec.startsWith('./') || spec.startsWith('../')) {
160
+ key = path.posix.normalize(path.posix.join(importerDir, spec));
161
+ if (!key.startsWith('/')) {
162
+ key = `/${key}`;
163
+ }
164
+ }
165
+ else {
166
+ key = spec;
167
+ }
168
+ return key.replace(PAT.QUERY_PATTERN, '');
169
+ }
170
+ function findDependencyFileName(depFileMap, key) {
171
+ const variants = new Set();
172
+ const base = key.replace(PAT.QUERY_PATTERN, '');
173
+ variants.add(base);
174
+ const normalized = path.posix.normalize(base);
175
+ variants.add(normalized);
176
+ const withSlash = normalized.startsWith('/') ? normalized : `/${normalized}`;
177
+ variants.add(withSlash);
178
+ for (const variant of Array.from(variants)) {
179
+ if (variant.endsWith('.js')) {
180
+ variants.add(variant.replace(/\.js$/i, '.mjs'));
181
+ }
182
+ else if (variant.endsWith('.mjs')) {
183
+ variants.add(variant.replace(/\.mjs$/i, '.js'));
184
+ }
185
+ }
186
+ for (const variant of variants) {
187
+ const value = depFileMap.get(variant);
188
+ if (value) {
189
+ return value;
190
+ }
191
+ }
192
+ return undefined;
193
+ }
194
+ function isRuntimePluginRootEntrySpecifier(specifier, projectRoot) {
195
+ if (!specifier) {
196
+ return false;
197
+ }
198
+ const cleaned = specifier.replace(PAT.QUERY_PATTERN, '');
199
+ const normalized = normalizeNodeModulesSpecifier(cleaned) || cleaned.replace(/^\/+/, '');
200
+ if (!normalized) {
201
+ return false;
202
+ }
203
+ const { packageName, subpath } = resolveNodeModulesPackageBoundary(normalized, projectRoot);
204
+ if (!packageName || !isLikelyNativeScriptRuntimePluginSpecifier(packageName, projectRoot)) {
205
+ return false;
206
+ }
207
+ if (!subpath) {
208
+ return true;
209
+ }
210
+ if (subpath.includes('/')) {
211
+ return false;
212
+ }
213
+ const pkgBaseName = packageName.split('/').pop() || '';
214
+ const withoutExt = /(?:\.(?:ios|android|visionos))?\.(?:ts|tsx|js|jsx|mjs|mts|cts)$/i.test(subpath) ? subpath.replace(/\.[^.]+$/, '') : subpath;
215
+ const withoutPlatform = withoutExt.replace(/\.(ios|android|visionos)$/i, '');
216
+ return withoutPlatform === 'index' || withoutPlatform === pkgBaseName;
217
+ }
218
+ function collectMixedRuntimePluginHttpRootPackages(code, projectRoot) {
219
+ const nonRootSubpathPackages = new Set();
220
+ const rootEntryPackages = new Set();
221
+ const visitSpecifier = (rawSpecifier) => {
222
+ if (!rawSpecifier) {
223
+ return;
224
+ }
225
+ const specifier = normalizeNativeScriptCoreSpecifier(rawSpecifier).replace(PAT.QUERY_PATTERN, '');
226
+ if (!specifier) {
227
+ return;
228
+ }
229
+ if (/^https?:\/\//.test(specifier) || specifier.startsWith('/ns/')) {
230
+ return;
231
+ }
232
+ if (/^(?:\.|\/)/.test(specifier) && !specifier.includes('/node_modules/')) {
233
+ return;
234
+ }
235
+ const normalized = normalizeNodeModulesSpecifier(specifier) || specifier.replace(/^\/+/, '');
236
+ if (!normalized) {
237
+ return;
238
+ }
239
+ const { packageName } = resolveNodeModulesPackageBoundary(normalized, projectRoot);
240
+ if (!packageName || !isLikelyNativeScriptRuntimePluginSpecifier(packageName, projectRoot)) {
241
+ return;
242
+ }
243
+ if (isRuntimePluginRootEntrySpecifier(normalized, projectRoot)) {
244
+ rootEntryPackages.add(packageName);
245
+ return;
246
+ }
247
+ nonRootSubpathPackages.add(packageName);
248
+ };
249
+ for (const pattern of [PAT.IMPORT_PATTERN_1, PAT.IMPORT_PATTERN_2, PAT.IMPORT_PATTERN_3, PAT.IMPORT_PATTERN_SIDE_EFFECT]) {
250
+ pattern.lastIndex = 0;
251
+ let match;
252
+ while ((match = pattern.exec(code)) !== null) {
253
+ visitSpecifier(match[2]);
254
+ }
255
+ }
256
+ return new Set(Array.from(nonRootSubpathPackages).filter((packageName) => rootEntryPackages.has(packageName)));
257
+ }
258
+ function collectImportDependencies(code, importerPath) {
259
+ const importerDir = path.posix.dirname(importerPath);
260
+ const deps = new Set();
261
+ const patterns = [PAT.IMPORT_PATTERN_1, PAT.IMPORT_PATTERN_2, PAT.EXPORT_PATTERN, PAT.IMPORT_PATTERN_3];
262
+ for (const pattern of patterns) {
263
+ pattern.lastIndex = 0;
264
+ let match;
265
+ while ((match = pattern.exec(code)) !== null) {
266
+ const rawSpec = match[2];
267
+ const spec = normalizeNativeScriptCoreSpecifier(rawSpec);
268
+ if (!spec || !shouldRemapImport(spec)) {
269
+ continue;
270
+ }
271
+ if (resolveVendorFromCandidate(spec)) {
272
+ continue;
273
+ }
274
+ // Manifest-aware vendor spec detection
275
+ try {
276
+ if (resolveVendorSpecifier && resolveVendorSpecifier(spec)) {
277
+ continue;
278
+ }
279
+ }
280
+ catch { }
281
+ const normalized = normalizeImportPath(spec, importerDir);
282
+ if (normalized) {
283
+ if (resolveVendorFromCandidate(normalized)) {
284
+ continue;
285
+ }
286
+ try {
287
+ if (resolveVendorSpecifier && resolveVendorSpecifier(normalized)) {
288
+ continue;
289
+ }
290
+ }
291
+ catch { }
292
+ if (isCoreGlobalsReference(normalized)) {
293
+ continue;
294
+ }
295
+ if (isNativeScriptCoreModule(normalized)) {
296
+ continue;
297
+ }
298
+ if (isNativeScriptPluginModule(normalized)) {
299
+ continue;
300
+ }
301
+ deps.add(normalized);
302
+ }
303
+ }
304
+ }
305
+ return deps;
306
+ }
307
+ /**
308
+ * Clean code: remove Vite/Vue noise, rewrite to vendor
309
+ */
310
+ function cleanCode(code, strategy) {
311
+ let result = code;
312
+ // Remove Vite client and hot module noise
313
+ result = result.replace(PAT.VITE_CLIENT_IMPORT, '');
314
+ result = result.replace(PAT.IMPORT_META_HOT_ASSIGNMENT, '');
315
+ // Keep import.meta.hot call sites; runtime now provides a stable import.meta.hot.
316
+ result = strategy.preClean?.(result) ?? result;
317
+ result = strategy.rewriteFrameworkImports?.(result) ?? result;
318
+ // Vendor manifest-driven import rewrites
319
+ // NOTE: Static and side-effect vendor imports are intentionally NOT rewritten here.
320
+ // They are left as import statements so that ensureNativeScriptModuleBindings()
321
+ // (called later in processCodeForDevice) can transform them using the robust
322
+ // __nsVendorRequire + __nsPick pattern that works on device.
323
+ // Only dynamic imports are handled here since ensureNativeScriptModuleBindings
324
+ // does not process dynamic import() calls.
325
+ try {
326
+ const manifest = getVendorManifest();
327
+ if (manifest) {
328
+ // Dynamic import rewrites: import('pkg') -> Promise.resolve(__nsVendor('id'))
329
+ const dynImportRE = /(import\(\s*["'])([^"']+)(["']\s*\))/g;
330
+ result = result.replace(dynImportRE, (full, pre, spec, post) => {
331
+ if (isNativeScriptCoreModule(spec))
332
+ return full;
333
+ const resolved = resolveVendorSpecifier(spec);
334
+ if (!resolved || /^@nativescript\/core(\b|\/)/i.test(resolved))
335
+ return full;
336
+ return `Promise.resolve(__nsVendor(${JSON.stringify(resolved)}))`;
337
+ });
338
+ }
339
+ }
340
+ catch (e) {
341
+ // Non-fatal; fallback to original code if manifest logic fails
342
+ }
343
+ result = result.replace(PAT.VITE_CLIENT_IMPORT, '').replace(PAT.IMPORT_META_HOT_ASSIGNMENT, '');
344
+ // Clean up HMR noise
345
+ result = strategy.postClean?.(result) ?? result;
346
+ result = stripCoreGlobalsImports(result);
347
+ return result;
348
+ }
349
+ // Application import helpers
350
+ /**
351
+ * Check if a path is an application module (not node_modules, not vendor, not relative)
352
+ * This is generic and works for ANY project structure.
353
+ *
354
+ * Examples of application imports: /core/v4/store.ts, /src/utils/helper.ts, /custom/module.ts
355
+ * Examples of NON-application imports: node_modules/..., ~/vendor.mjs, ./relative.ts, ../parent.ts
356
+ */
357
+ function isApplicationImport(importPath) {
358
+ if (!importPath.startsWith('/')) {
359
+ return false; // Relative paths (./..., ../...) are not application imports
360
+ }
361
+ // Exclude node_modules and special paths
362
+ if (importPath.includes('node_modules') || importPath.startsWith('/@') || importPath.startsWith('~/')) {
363
+ return false;
364
+ }
365
+ return true;
366
+ }
367
+ function stripToProjectRelative(importPath, projectRoot) {
368
+ if (!importPath) {
369
+ return '';
370
+ }
371
+ let normalized = importPath.replace(/\\/g, '/');
372
+ normalized = normalized.replace(/^\/?@fs\//, '/');
373
+ if (normalized.startsWith('file://')) {
374
+ normalized = normalized.replace(/^file:\/\//, '/');
375
+ }
376
+ const documentsMarker = '/Documents/';
377
+ const documentsIndex = normalized.indexOf(documentsMarker);
378
+ if (documentsIndex !== -1) {
379
+ return normalized.substring(documentsIndex + documentsMarker.length);
380
+ }
381
+ if (projectRoot) {
382
+ const normalizedRoot = projectRoot.replace(/\\/g, '/').replace(/\/+$/, '');
383
+ const rootIndex = normalized.indexOf(normalizedRoot);
384
+ if (rootIndex !== -1) {
385
+ const sliced = normalized.substring(rootIndex + normalizedRoot.length);
386
+ return sliced.replace(/^\/+/, '');
387
+ }
388
+ }
389
+ return normalized.replace(/^\/+/, '');
390
+ }
391
+ /**
392
+ * Convert absolute application import to relative .mjs path for Documents folder
393
+ * /core/v4/store.ts → ./core/v4/store.mjs
394
+ */
395
+ function getProjectRelativeImportPath(importPath, projectRoot) {
396
+ if (!importPath) {
397
+ return null;
398
+ }
399
+ let normalized = importPath.replace(PAT.QUERY_PATTERN, '');
400
+ normalized = normalized.replace(/\\/g, '/');
401
+ if (normalized.startsWith('file://')) {
402
+ normalized = normalized.replace(/^file:\/\//, '/');
403
+ }
404
+ const documentsMarker = '/Documents/';
405
+ const documentsIndex = normalized.indexOf(documentsMarker);
406
+ if (documentsIndex !== -1) {
407
+ normalized = normalized.substring(documentsIndex + documentsMarker.length);
408
+ }
409
+ else if (projectRoot) {
410
+ const normalizedRoot = projectRoot.replace(/\\/g, '/').replace(/\/+$/, '');
411
+ const rootIndex = normalized.indexOf(normalizedRoot);
412
+ if (rootIndex !== -1) {
413
+ normalized = normalized.substring(rootIndex + normalizedRoot.length);
414
+ }
415
+ }
416
+ normalized = normalized.replace(/^\/+/, '');
417
+ if (!normalized) {
418
+ return null;
419
+ }
420
+ if (normalized.startsWith('dep-')) {
421
+ return null;
422
+ }
423
+ if (normalized.startsWith('sfc-')) {
424
+ return null;
425
+ }
426
+ normalized = path.posix.normalize(normalized);
427
+ if (!normalized) {
428
+ return null;
429
+ }
430
+ normalized = normalized.replace(/\.(ts|js|tsx|jsx|mjs|mts|cts)$/i, '.mjs');
431
+ if (!normalized.endsWith('.mjs')) {
432
+ normalized = `${normalized}.mjs`;
433
+ }
434
+ return normalized.replace(/^\/+/, '');
435
+ }
436
+ function toAppModuleBaseId(importPath, projectRoot) {
437
+ const projectRelative = getProjectRelativeImportPath(importPath, projectRoot);
438
+ if (!projectRelative) {
439
+ return null;
440
+ }
441
+ const base = projectRelative.replace(/\.mjs$/i, '');
442
+ return `/${base}`;
443
+ }
444
+ function toNodeModulesHttpModuleId(importPath) {
445
+ const nodeModulesSpecifier = normalizeNodeModulesSpecifier(importPath);
446
+ if (!nodeModulesSpecifier) {
447
+ return null;
448
+ }
449
+ return `/ns/m/node_modules/${nodeModulesSpecifier}`;
450
+ }
451
+ /**
452
+ * Process code for device: inject globals, remove framework imports
453
+ */
454
+ function processCodeForDevice(code, isVitePreBundled, preserveVendorImports = false, isNodeModule = false, sourceId, options) {
455
+ let result = code;
456
+ const resolvedSpecifierOverrides = options?.resolvedSpecifierOverrides || getProcessCodeResolvedSpecifierOverrides(sourceId, getProjectRootPath());
457
+ const bindingOptions = {
458
+ preserveNonPluginVendorImports: preserveVendorImports,
459
+ resolvedSpecifierOverrides,
460
+ };
461
+ // Ensure Angular partial declarations are linked before any sanitizers run so runtime never hits the JIT path.
462
+ result = linkAngularPartialsIfNeeded(result);
463
+ // Post-linker: deduplicate/resolve imports the Angular linker injected with bare specifiers
464
+ result = deduplicateLinkerImports(result);
465
+ // First: aggressively strip any lingering virtual dynamic-import-helper before anything else.
466
+ // Doing this up-front prevents downstream dependency collection from seeing the virtual id.
467
+ result = stripViteDynamicImportVirtual(result);
468
+ // Skip reactive injection for Vite pre-bundled deps (they have Vue bundled already)
469
+ if (isVitePreBundled) {
470
+ return result;
471
+ }
472
+ // Inject ALL NativeScript/build globals at the top (matching global-defines.ts)
473
+ // This ensures any code using __DEV__, __ANDROID__, __IOS__, etc. works correctly
474
+ const allGlobals = [
475
+ // Minimal process shim — populated with CLI --env.* flags at module load time.
476
+ // In production builds, Vite/Rollup replaces process.env.* statically.
477
+ // In HMR dev mode the code runs as-is on device, so we need the shim.
478
+ //
479
+ // IMPORTANT: every check goes through `globalThis.process` (a member
480
+ // expression), NEVER bare `typeof process` (an identifier reference).
481
+ // bare identifier resolution
482
+ // against runtime-added global object properties is not reliable in
483
+ // V8 module scope. `globalThis.process` is unambiguous: it always
484
+ // reads the `process` property off the (single) global object.
485
+ //
486
+ // The shim is also strictly additive — it only initializes
487
+ // `globalThis.process` and `globalThis.process.env` if they are
488
+ // missing. App code that pre-populates `process.env` (e.g. an Azure
489
+ // App Configuration boot module) is preserved; we never overwrite a
490
+ // populated env with the bare `{ NODE_ENV: 'development' }` stub.
491
+ `if (typeof globalThis.process === "undefined" || globalThis.process === null) { globalThis.process = { env: ${__processEnvJson} }; } else if (!globalThis.process.env) { globalThis.process.env = ${__processEnvJson}; }`,
492
+ 'const __ANDROID__ = globalThis.__ANDROID__ !== undefined ? globalThis.__ANDROID__ : false;',
493
+ 'const __IOS__ = globalThis.__IOS__ !== undefined ? globalThis.__IOS__ : false;',
494
+ 'const __VISIONOS__ = globalThis.__VISIONOS__ !== undefined ? globalThis.__VISIONOS__ : false;',
495
+ 'const __APPLE__ = globalThis.__APPLE__ !== undefined ? globalThis.__APPLE__ : (__IOS__ || __VISIONOS__);',
496
+ 'const __DEV__ = globalThis.__DEV__ !== undefined ? globalThis.__DEV__ : false;',
497
+ 'const __COMMONJS__ = globalThis.__COMMONJS__ !== undefined ? globalThis.__COMMONJS__ : false;',
498
+ 'const __NS_WEBPACK__ = globalThis.__NS_WEBPACK__ !== undefined ? globalThis.__NS_WEBPACK__ : false;',
499
+ 'const __NS_ENV_VERBOSE__ = globalThis.__NS_ENV_VERBOSE__ !== undefined ? !!globalThis.__NS_ENV_VERBOSE__ : false;',
500
+ "const __CSS_PARSER__ = globalThis.__CSS_PARSER__ !== undefined ? globalThis.__CSS_PARSER__ : 'css-tree';",
501
+ 'const __UI_USE_XML_PARSER__ = globalThis.__UI_USE_XML_PARSER__ !== undefined ? globalThis.__UI_USE_XML_PARSER__ : true;',
502
+ 'const __UI_USE_EXTERNAL_RENDERER__ = globalThis.__UI_USE_EXTERNAL_RENDERER__ !== undefined ? globalThis.__UI_USE_EXTERNAL_RENDERER__ : false;',
503
+ 'const __TEST__ = globalThis.__TEST__ !== undefined ? globalThis.__TEST__ : false;',
504
+ ];
505
+ result = allGlobals.join('\n') + '\n' + result;
506
+ const nodeModuleProvenancePrelude = buildNodeModuleProvenancePrelude(sourceId);
507
+ if (nodeModuleProvenancePrelude) {
508
+ result = nodeModuleProvenancePrelude + result;
509
+ }
510
+ // AST normalization: inject /ns/rt helper aliases for underscore-prefixed identifiers.
511
+ // ONLY for app source files — library code in node_modules should be served as-is.
512
+ // Running the normalizer on libraries like tslib injects harmful destructures
513
+ // (e.g., `const { SuppressedError } = __ns_rt_ns_1`) that shadow globals.
514
+ if (!isNodeModule) {
515
+ // CRITICAL ORDERING: canonicalise any bare `@nativescript/core[/sub]`
516
+ // specifiers to `/ns/core[/sub]` BEFORE the AST normaliser sees them.
517
+ // `astNormalizeModuleImportsAndHelpers` defensively rewrites bare
518
+ // `@nativescript/core` imports and emits a one-shot
519
+ // `[ast-normalizer] unexpected @nativescript/core spec` warning —
520
+ // the warning means the upstream rewriter regressed. For Vue SFC
521
+ // `<script>` blocks the bare specifier flows through Vite's
522
+ // transform pipeline without a per-statement source-string rewrite
523
+ // (Vite's resolver only edits the module graph, not the emitted
524
+ // code), so the only upstream rewriter that can canonicalise these
525
+ // in dev mode is this regex sweep. Running it here keeps the AST
526
+ // normaliser purely a tripwire instead of an active rewriter.
527
+ try {
528
+ result = sanitizeStrayCoreReferences(result);
529
+ }
530
+ catch { }
531
+ try {
532
+ result = astNormalizeModuleImportsAndHelpers(result);
533
+ }
534
+ catch { }
535
+ // Verify there are no duplicate top-level const/let bindings after AST normalization
536
+ try {
537
+ result = astVerifyAndAnnotateDuplicates(result);
538
+ }
539
+ catch { }
540
+ }
541
+ // If AST marker present OR this is a node_modules file, skip regex-based helper
542
+ // alias injection. Library code should NOT get /ns/rt destructures injected —
543
+ // underscore-prefixed identifiers in libraries are internal variables, not NS helpers.
544
+ if (!isNodeModule && !/^\s*(?:\/\/|\/\*) \[ast-normalized\]/m.test(result)) {
545
+ try {
546
+ const underscored = new Set();
547
+ const re = /(^|[^.\w$])_([A-Za-z]\w*)\b/g;
548
+ let m;
549
+ while ((m = re.exec(result))) {
550
+ const name = m[2];
551
+ if (name === 'ctx' || name === 'cache')
552
+ continue;
553
+ if (name.startsWith('hoisted_'))
554
+ continue;
555
+ if (name.startsWith('component_'))
556
+ continue;
557
+ if (name.startsWith('directive_'))
558
+ continue;
559
+ if (name === 'sfc_main')
560
+ continue;
561
+ if (name === 'ns_sfc__' || name.startsWith('ns_sfc'))
562
+ continue;
563
+ if (name.startsWith('sfc'))
564
+ continue;
565
+ try {
566
+ const declRE = new RegExp(`(^|\\n)\\s*(?:const|let|var)\\s+_${name}\\b`);
567
+ if (declRE.test(result))
568
+ continue;
569
+ }
570
+ catch { }
571
+ underscored.add(name);
572
+ }
573
+ if (underscored.size) {
574
+ const needed = [];
575
+ for (const n of underscored) {
576
+ const aliasNeedle = new RegExp(`\\b${n}\\s+as\\s+_${n}\\b`);
577
+ if (!aliasNeedle.test(result))
578
+ needed.push(n);
579
+ }
580
+ if (needed.length) {
581
+ const importLine = `import { ${needed.map((n) => `${n} as _${n}`).join(', ')} } from "/ns/rt";\n`;
582
+ result = importLine + result;
583
+ }
584
+ }
585
+ }
586
+ catch { }
587
+ }
588
+ // In strict dev mode, proactively surface duplicate-binding diagnostics to avoid "already declared" runtime errors
589
+ try {
590
+ if (/^\s*\/\/ \[ast-verify\]\[duplicate-bindings\]/m.test(result)) {
591
+ const diagnosticLine = (result.match(/^\s*\/\/ \[ast-verify\]\[duplicate-bindings\][^\n]*/m) || [])[0] || '// [ast-verify][duplicate-bindings]';
592
+ const brief = diagnosticLine.replace(/^[^:]*:?\s?/, '');
593
+ const escaped = brief.replace(/["\\]/g, '\\$&');
594
+ const thrower = `throw new Error("[nsv-hmr] Duplicate top-level bindings detected: ${escaped}");`;
595
+ result = `${thrower}\n` + result;
596
+ }
597
+ }
598
+ catch { }
599
+ // Remove Vite internal imports (dynamic-import-helper, etc.)
600
+ // This handles both standalone lines and concatenated imports on the same line
601
+ result = result.replace(/import\s+[^;]+\s+from\s+["']\/@id\/[^"']*["'];?\s*/g, '');
602
+ // Also remove side-effect only virtual id imports like: import "/@id/__x00__vite/dynamic-import-helper.js";
603
+ // These can slip through and cause the NativeScript runtime to attempt resolving
604
+ // a non-existent physical file (e.g. /@id/__x00__vite/dynamic-import-helper.js) leading to
605
+ // module not found crashes during HMR evaluation.
606
+ if (/^[\t ]*import\s+["']\/@id\/[^"']+["'];?\s*$/m.test(result)) {
607
+ result = result.replace(/^[\t ]*import\s+["']\/@id\/[^"']+["'];?\s*$/gm, '');
608
+ // Inject a lightweight marker comment (harmless if left in output) so devs can confirm rewrite took place when viewing streamed artifact.
609
+ result = `// [hmr-sanitize] stripped virtual /@id/ side-effect imports\n${result}`;
610
+ }
611
+ // IMPORTANT: Perform vendor-module binding injection BEFORE stripping Vite prebundle imports.
612
+ // This allows the rewriter to see and canonicalize '/node_modules/.vite/deps/*' specifiers back
613
+ // to their package ids (e.g., '@nativescript/firebase-core') and generate require-based bindings
614
+ // so named imports like `{ firebase }` are preserved as const bindings.
615
+ //
616
+ // Some upstream transforms can emit a multiline form:
617
+ // import { x } from
618
+ // "/node_modules/.vite/deps/...";
619
+ // If we don't normalize it, later stripping of naked string-only lines can leave
620
+ // an invalid `import ... from` statement.
621
+ try {
622
+ result = result.replace(/(^|\n)([\t ]*import\s+[^;]*?\s+from)\s*\n\s*("\/?node_modules\/\.vite\/deps\/[^"\n]+"\s*;?\s*)/gm, (_m, p1, p2, p3) => `${p1}${p2} ${p3}`);
623
+ }
624
+ catch { }
625
+ // When preserveVendorImports is true (HMR /ns/m/ endpoint), skip the
626
+ // __nsVendorRequire + __nsPick rewrite. Vendor imports stay as bare
627
+ // specifiers so the device-side import map resolves them via V8's native
628
+ // module system, which correctly handles export * re-exports.
629
+ result = ensureNativeScriptModuleBindings(result, bindingOptions);
630
+ // Repair any accidental "import ... = expr" assignments that may have slipped in.
631
+ try {
632
+ result = repairImportEqualsAssignments(result);
633
+ }
634
+ catch { }
635
+ // Strip Vite prebundle deps imports (both named and side-effect) and any malformed const string artifacts
636
+ // Example problematic line observed: const "/node_modules/.vite/deps/@nativescript_firebase-messaging.js?v=...";
637
+ if (/node_modules\/\.vite\/deps\//.test(result)) {
638
+ result = rewriteVitePrebundleImportsForDevice(result, preserveVendorImports);
639
+ // Malformed const string lines accidentally produced by upstream transforms
640
+ result = result.replace(/^[\t ]*const\s+["']\/?node_modules\/\.vite\/deps\/[^"']+["'];?\s*$/gm, '// [hmr-sanitize] stripped malformed const prebundle ref\n');
641
+ // Naked string-only lines pointing at prebundle deps
642
+ result = result.replace(/^[\t ]*["']\/?node_modules\/\.vite\/deps\/[^"']+["'];?\s*$/gm, '// [hmr-sanitize] stripped prebundle side-effect literal\n');
643
+ }
644
+ // Dynamic aliasing covers helper imports; no further static list handling needed.
645
+ // Handle navigation helpers (dev bridge): $navigateTo, $navigateBack
646
+ // Note: do NOT inject $showModal as a named import; AST normalizer/destructure covers it when imported,
647
+ // and free-uses are handled via AST injection. This avoids duplicate identifier redeclarations.
648
+ if (/\$(?:navigate(?:To|Back)|showModal)\b/.test(result)) {
649
+ const navHelpers = [];
650
+ // Only consider free uses (not property access like obj.$navigateTo)
651
+ const needTo = /(^|[^.\w$])\$navigateTo\b/.test(result);
652
+ const needBack = /(^|[^.\w$])\$navigateBack\b/.test(result);
653
+ if (needTo)
654
+ navHelpers.push('$navigateTo');
655
+ if (needBack)
656
+ navHelpers.push('$navigateBack');
657
+ // Intentionally exclude $showModal from navHelpers injection to prevent named import reinsertion
658
+ // Remove any direct imports/usages that might shadow globals
659
+ // 1) From 'vue' or 'nativescript-vue' sources
660
+ result = removeNamedImports(result, navHelpers);
661
+ // 2) From our runtime bridge '/ns/rt' (versioned or not)
662
+ try {
663
+ // Do NOT re-introduce named imports from /ns/rt for nav helpers; drop them entirely after removing nav helpers.
664
+ const rtNamedRE = /(^|\n)\s*import\s*\{([^}]+)\}\s*from\s*["'](?:https?:\/\/[^"']+)?\/ns\/rt(?:\/[\d]+)?["'];?\s*/gm;
665
+ // Also compute locally-declared helpers to drop regardless of free-use detection
666
+ const hasLocalToForDrop = /(^|[\n;])\s*(?:const|let|var|function)\s+\$navigateTo\b/.test(result);
667
+ const hasLocalBackForDrop = /(^|[\n;])\s*(?:const|let|var|function)\s+\$navigateBack\b/.test(result);
668
+ result = result.replace(rtNamedRE, (full, pfx, specList) => {
669
+ const drop = new Set(navHelpers);
670
+ if (hasLocalToForDrop)
671
+ drop.add('$navigateTo');
672
+ if (hasLocalBackForDrop)
673
+ drop.add('$navigateBack');
674
+ const remaining = String(specList)
675
+ .split(',')
676
+ .map((s) => s.trim())
677
+ .filter(Boolean)
678
+ .filter((entry) => {
679
+ const base = entry.split(/\s+as\s+/i)[0].trim();
680
+ return !drop.has(base);
681
+ });
682
+ if (!remaining.length)
683
+ return pfx || '';
684
+ // Preserve non-navigation named imports for later normalization
685
+ return `${pfx}import { ${remaining.join(', ')} } from "/ns/rt";`;
686
+ });
687
+ // Also strip $navigateTo/$navigateBack from any destructuring previously created from /ns/rt
688
+ // Also remove from destructures bound off any __ns_rt_ns temp (including _re)
689
+ const rtDestructureRE = /(^|[\n;])\s*const\s*\{([^}]+)\}\s*=\s*(__ns_rt_ns(?:\d+|_re))\s*;?\s*/gm;
690
+ result = result.replace(rtDestructureRE, (full, pfx, specList, varName) => {
691
+ const cleaned = String(specList)
692
+ .split(',')
693
+ .map((s) => s.trim())
694
+ .filter(Boolean)
695
+ .filter((seg) => {
696
+ const lhs = seg.split(':')[0].trim();
697
+ return !/^\$navigate(?:To|Back)$/.test(lhs);
698
+ });
699
+ if (!cleaned.length)
700
+ return pfx || '';
701
+ return `${pfx}const { ${cleaned.join(', ')} } = ${varName};`;
702
+ });
703
+ }
704
+ catch { }
705
+ // Inject named imports from /ns/rt to provide bindings without redeclaration collisions
706
+ const imports = [];
707
+ const hasImportTo = /(^|\n)\s*import\s*\{[^}]*\$navigateTo[^}]*\}\s*from\s*["'](?:https?:\/\/[^"']+)?\/ns\/rt(?:\/[\d]+)?["']/.test(result);
708
+ const hasImportBack = /(^|\n)\s*import\s*\{[^}]*\$navigateBack[^}]*\}\s*from\s*["'](?:https?:\/\/[^"']+)?\/ns\/rt(?:\/[\d]+)?["']/.test(result);
709
+ // Avoid adding named imports if a local binding already exists (e.g., wrapper const)
710
+ const hasLocalTo = /(^|[\n;])\s*(?:const|let|var|function)\s+\$navigateTo\b/.test(result);
711
+ const hasLocalBack = /(^|[\n;])\s*(?:const|let|var|function)\s+\$navigateBack\b/.test(result);
712
+ if (needTo && !hasImportTo && !hasLocalTo)
713
+ imports.push('$navigateTo');
714
+ if (needBack && !hasImportBack && !hasLocalBack)
715
+ imports.push('$navigateBack');
716
+ // Do not inject $showModal named import; avoid duplicates with destructures created upstream
717
+ if (imports.length) {
718
+ result = `import { ${imports.join(', ')} } from "/ns/rt";\n` + result;
719
+ }
720
+ }
721
+ // Ensure vendor bindings also apply after potential wrapper injections above
722
+ // (idempotent: second pass will be a no-op if imports already consumed).
723
+ result = ensureNativeScriptModuleBindings(result, bindingOptions);
724
+ try {
725
+ result = repairImportEqualsAssignments(result);
726
+ }
727
+ catch { }
728
+ // Rewrite any previously-injected vendor-based core access to the unified HTTP core bridge
729
+ try {
730
+ const vendorCoreRE1 = /globalThis\.__nsVendor\s*\(\s*["']@nativescript\/core["']\s*\)/g;
731
+ const vendorCoreRE2 = /__nsVendor\s*\(\s*["']@nativescript\/core["']\s*\)/g;
732
+ if (vendorCoreRE1.test(result) || vendorCoreRE2.test(result)) {
733
+ const hasImport = /import\s+__ns_core_bridge\s+from\s+["'][^"']*\/(?:\@ns|ns)\/core(?:\/[^"']+)?["']\s*;?/.test(result) || /(^|\n)\s*import\s+__ns_core_bridge\s+from\s+["']\/(?:\@ns|ns)\/core["']\s*;?/m.test(result);
734
+ if (!hasImport) {
735
+ result = `import __ns_core_bridge from "/ns/core";\n` + result;
736
+ }
737
+ result = result.replace(vendorCoreRE1, '__ns_core_bridge');
738
+ result = result.replace(vendorCoreRE2, '__ns_core_bridge');
739
+ }
740
+ }
741
+ catch { }
742
+ // Rewrite any explicit require('@nativescript/core[/sub]') calls to the unified core bridge
743
+ try {
744
+ const reqCoreRE1 = /(^|[^.\w$])require\(\s*["']@nativescript\/core([^"'\n]*)["']\s*\)/g;
745
+ const reqCoreRE2 = /(?:globalThis|window|self)\.require\(\s*["']@nativescript\/core([^"'\n]*)["']\s*\)/g;
746
+ if (reqCoreRE1.test(result) || reqCoreRE2.test(result)) {
747
+ const hasImport = /import\s+__ns_core_bridge\s+from\s+["'][^"']*\/(?:\@ns|ns)\/core(?:\/[^"']+)?["']\s*;?/.test(result) || /(^|\n)\s*import\s+__ns_core_bridge\s+from\s+["']\/(?:\@ns|ns)\/core["']\s*;?/m.test(result);
748
+ if (!hasImport) {
749
+ result = `import __ns_core_bridge from "/ns/core";\n` + result;
750
+ }
751
+ result = result.replace(reqCoreRE1, (_m, p1, _sub) => `${p1}__ns_core_bridge`);
752
+ result = result.replace(reqCoreRE2, '__ns_core_bridge');
753
+ }
754
+ }
755
+ catch { }
756
+ // Apply the three-pass safety net for stray @nativescript/core references
757
+ // (naked string literals, dangling `from` merges, lingering resolved-path
758
+ // references). Centralised in core-sanitize.sanitizeStrayCoreReferences so
759
+ // every NS-M emitter applies the same passes in the same order.
760
+ result = sanitizeStrayCoreReferences(result);
761
+ result = ensureVariableDynamicImportHelper(result);
762
+ // Normalize any lingering @nativescript/core imports to the /ns/core bridge (non-destructive best-effort)
763
+ try {
764
+ // Rewrite named imports from the /ns/core bridge into default import + destructuring.
765
+ // This makes `import { Frame } from '@nativescript/core'` work even if the bridge provides only a default export.
766
+ {
767
+ let __core_ns_seq = 0;
768
+ const toDestructureCore = (specList) => specList
769
+ .split(',')
770
+ .map((s) => s.trim())
771
+ .filter(Boolean)
772
+ .map((seg) => {
773
+ const m = seg.split(/\s+as\s+/i);
774
+ return m.length === 2 ? `${m[0].trim()}: ${m[1].trim()}` : seg;
775
+ })
776
+ .join(', ');
777
+ const reNamed = /(^|\n)\s*import\s*\{([^}]+)\}\s*from\s*["']((?:https?:\/\/[^"']+)?\/ns\/core(?:\/[^"']+)?)['"];?\s*/gm;
778
+ result = result.replace(reNamed, (_full, pfx, specList, src) => {
779
+ // Deep subpath URLs serve actual ESM with real named exports — skip.
780
+ if (isDeepCoreSubpath(src))
781
+ return _full;
782
+ __core_ns_seq++;
783
+ const tmp = `__ns_core_ns${__core_ns_seq}`;
784
+ const decl = `const { ${toDestructureCore(specList)} } = ${tmp};`;
785
+ return `${pfx}import ${tmp} from ${JSON.stringify(src)};\n${decl}\n`;
786
+ });
787
+ const reMixed = /(^|\n)\s*import\s+([A-Za-z_$][\w$]*)\s*,\s*\{([^}]+)\}\s*from\s*["']((?:https?:\/\/[^"']+)?\/ns\/core(?:\/[^"']+)?)['"];?\s*/gm;
788
+ result = result.replace(reMixed, (_full, pfx, defName, specList, src) => {
789
+ if (isDeepCoreSubpath(src))
790
+ return _full;
791
+ const decl = `const { ${toDestructureCore(specList)} } = ${defName};`;
792
+ return `${pfx}import ${defName} from ${JSON.stringify(src)};\n${decl}\n`;
793
+ });
794
+ }
795
+ }
796
+ catch { }
797
+ // Note: Removed legacy var-based underscore prelude to avoid const/var redeclaration conflicts.
798
+ // Normalize concatenated imports that may have ended up after a statement on the same line
799
+ try {
800
+ // Common concatenations
801
+ // Keep a single semicolon before the import to avoid generating ';;'
802
+ result = result.replace(/;\s*import\s+/g, ';\nimport ');
803
+ result = result.replace(/}\s*import\s+/g, '}\nimport ');
804
+ // Fallback: ensure any static import that isn't at start of line gets a newline before it.
805
+ //
806
+ // Only match after **structural** statement-ending characters: `;`, `}`, `)`, `]`. We
807
+ // deliberately do NOT include `'`, `"`, or `` ` `` here — those are string-literal
808
+ // terminators (and openers!), and including them caused the regex to fire inside
809
+ // example code embedded in error strings. Concrete failure observed:
810
+ // `@supabase/realtime-js` throws an Error whose message contains the literal
811
+ // `' import ws from "ws"\n' +`. With `'` in the delimiter class, the engine matched
812
+ // the opening `'` of that string literal as a "statement terminator" and rewrote the
813
+ // example to `'\nimport ws from "..."` — splitting the string across two lines and
814
+ // producing a SyntaxError on device. The structural delimiters below do not appear
815
+ // inside string-literal openers, so the rewrite is safe.
816
+ result = result.replace(/([;}\)\]])\s*(import\s+[^;\n]*\s+from\s*["'][^"']+["'])/g, '$1\n$2');
817
+ }
818
+ catch { }
819
+ // Collapse duplicate destructuring from the same temp namespace var (e.g., multiple const { x } = __ns_rt_ns1)
820
+ try {
821
+ const collapse = (code, prefix) => {
822
+ const re = new RegExp(`(^|\\n)\\s*const\\s*\\{([^}]+)\\}\\s*=\\s*(${prefix}\\d+)\\s*;?\\s*`, 'gm');
823
+ const byVar = {};
824
+ code.replace(re, (_full, _pfx, specList, varName) => {
825
+ const set = (byVar[varName] || (byVar[varName] = new Set()));
826
+ String(specList)
827
+ .split(',')
828
+ .map((s) => s.trim())
829
+ .filter(Boolean)
830
+ .forEach((seg) => set.add(seg));
831
+ return '';
832
+ });
833
+ if (Object.keys(byVar).length) {
834
+ // Remove all existing destructures first
835
+ code = code.replace(re, (full, pfx) => pfx || '');
836
+ // Re-emit one per var
837
+ const blocks = Object.entries(byVar).map(([varName, set]) => `const { ${Array.from(set).join(', ')} } = ${varName};`);
838
+ code = blocks.join('\n') + '\n' + code;
839
+ }
840
+ return code;
841
+ };
842
+ result = collapse(result, '__ns_rt_ns');
843
+ result = collapse(result, '__ns_core_ns');
844
+ }
845
+ catch { }
846
+ // After consolidating destructures, hoist static import declarations to the very top so imports
847
+ // always come before any statements that might reference their bindings. This ordering avoids
848
+ // device runtimes that are stricter about imports-first semantics during module instantiation.
849
+ try {
850
+ result = hoistTopLevelStaticImports(result);
851
+ }
852
+ catch { }
853
+ // Final safety: normalize any lingering named imports from /ns/rt into default+destructure
854
+ // Skip for node_modules (no /ns/rt helpers needed) and when AST marker present
855
+ try {
856
+ if (!isNodeModule && !/^\s*\/\* \[ast-normalized\] \*\//m.test(result)) {
857
+ result = ensureDestructureRtImports(result);
858
+ }
859
+ }
860
+ catch { }
861
+ // Post-pass: if both a destructure from __ns_rt_ns* and named imports from /ns/rt exist,
862
+ // remove overlapping named specifiers to avoid "Identifier has already been declared".
863
+ try {
864
+ // Collect all bindings destructured from any __ns_rt_ns* temp
865
+ const rtDestructureRE = /(^|\n)\s*const\s*\{([^}]+)\}\s*=\s*(__ns_rt_ns(?:\d+|_re))\s*;?\s*/gm;
866
+ const rtBound = new Set();
867
+ let m;
868
+ while ((m = rtDestructureRE.exec(result)) !== null) {
869
+ const specList = String(m[2] || '');
870
+ specList
871
+ .split(',')
872
+ .map((s) => s.trim())
873
+ .filter(Boolean)
874
+ .forEach((seg) => {
875
+ const bind = seg.includes(':') ? seg.split(':')[1].trim() : seg;
876
+ if (bind)
877
+ rtBound.add(bind);
878
+ });
879
+ }
880
+ if (rtBound.size) {
881
+ // Rewrite named imports from /ns/rt by removing any specifiers already provided via destructure
882
+ const rtNamedImportRE = /(^|\n)\s*import\s*\{([^}]+)\}\s*from\s*["']((?:https?:\/\/[^"']+)?\/ns\/rt(?:\/[\d]+)?)["'];?\s*/gm;
883
+ const edits = [];
884
+ while ((m = rtNamedImportRE.exec(result)) !== null) {
885
+ const full = m[0];
886
+ const pfx = m[1] || '';
887
+ const specList = String(m[2] || '');
888
+ const src = m[3];
889
+ const kept = [];
890
+ specList
891
+ .split(',')
892
+ .map((s) => s.trim())
893
+ .filter(Boolean)
894
+ .forEach((seg) => {
895
+ const name = seg.split(/\s+as\s+/i)[0].trim();
896
+ if (!rtBound.has(name))
897
+ kept.push(seg);
898
+ });
899
+ let replacement = '';
900
+ if (kept.length) {
901
+ replacement = `${pfx}import { ${kept.join(', ')} } from ${JSON.stringify(src)};`;
902
+ }
903
+ else {
904
+ // Drop the import entirely if nothing remains
905
+ replacement = pfx || '';
906
+ }
907
+ edits.push({
908
+ start: rtNamedImportRE.lastIndex - full.length,
909
+ end: rtNamedImportRE.lastIndex,
910
+ text: replacement,
911
+ });
912
+ }
913
+ if (edits.length) {
914
+ // Apply edits in reverse order
915
+ edits
916
+ .sort((a, b) => b.start - a.start)
917
+ .forEach((e) => {
918
+ result = result.slice(0, e.start) + e.text + result.slice(e.end);
919
+ });
920
+ }
921
+ }
922
+ }
923
+ catch { }
924
+ // Tidy-ups: remove stray lines that are only semicolons and collapse excessive blank lines
925
+ try {
926
+ // Remove lines that contain only an optional whitespace and a single ';'
927
+ result = result.replace(/^[ \t]*;[ \t]*$/gm, '');
928
+ // Collapse 3+ blank lines into at most 2 to keep output compact and consistent
929
+ result = result.replace(/\n{3,}/g, '\n\n');
930
+ }
931
+ catch { }
932
+ // De-duplicate destructured bindings across different temp vars to avoid 'Identifier has already been declared'
933
+ try {
934
+ const reDestructureAny = /(^|\n)\s*const\s*\{([^}]+)\}\s*=\s*(__ns_(?:rt|core)_[A-Za-z0-9_]+)\s*;?\s*/gm;
935
+ const seenBindings = new Set();
936
+ const edits = [];
937
+ let m;
938
+ while ((m = reDestructureAny.exec(result)) !== null) {
939
+ const full = m[0];
940
+ const pfx = m.index;
941
+ const specList = m[2];
942
+ const varName = m[3];
943
+ const entries = specList
944
+ .split(',')
945
+ .map((s) => s.trim())
946
+ .filter(Boolean);
947
+ const kept = [];
948
+ for (const seg of entries) {
949
+ const bind = seg.includes(':') ? seg.split(':')[1].trim() : seg;
950
+ if (seenBindings.has(bind))
951
+ continue;
952
+ seenBindings.add(bind);
953
+ kept.push(seg);
954
+ }
955
+ const replacement = kept.length ? `${m[1]}const { ${kept.join(', ')} } = ${varName};` : m[1] || '';
956
+ edits.push({ start: pfx, end: pfx + full.length, text: replacement });
957
+ }
958
+ if (edits.length) {
959
+ // Apply edits in reverse order to not mess up indices
960
+ edits
961
+ .sort((a, b) => b.start - a.start)
962
+ .forEach((e) => {
963
+ result = result.slice(0, e.start) + e.text + result.slice(e.end);
964
+ });
965
+ }
966
+ }
967
+ catch { }
968
+ // As a final safety net, neutralize any uses of Vite's CJS import helpers when the helper variable
969
+ // itself is not declared (e.g., stripped earlier during sanitation). This prevents runtime errors like
970
+ // "Cannot read properties of undefined (reading 'initNorrix')" on device when accessing
971
+ // __vite__cjsImportX__pkg["prop"].
972
+ try {
973
+ result = stripDanglingViteCjsImports(result);
974
+ }
975
+ catch { }
976
+ return result;
977
+ }
978
+ // Assert that sanitized code no longer contains any Vite optimized deps artifacts
979
+ // or virtual ids that could break the HTTP ESM loader on device. Throws with
980
+ // a helpful diagnostics message if any are found.
981
+ /**
982
+ * THE SINGLE REWRITE FUNCTION - used everywhere for consistency
983
+ */
984
+ export function rewriteImports(code, importerPath, sfcFileMap, depFileMap, projectRoot, verbose = false, outputDirOverrideRel, httpOrigin, resolveVendorAsHttp = false) {
985
+ let result = code;
986
+ // Pre-normalize concatenated imports onto their own lines.
987
+ //
988
+ // Babel's `genCode(ast, { retainLines: true })` in
989
+ // `astNormalizeModuleImportsAndHelpers` (which runs before us in the SFC
990
+ // asm pipeline, and in several other hot paths) can emit multiple
991
+ // statements on a single line, e.g.:
992
+ // `} = __ns_rt_ns_1;import { $goTo } from "../utils";import PageWrapper from ...;`
993
+ //
994
+ // IMPORT_PATTERN_1/_2/_3/SIDE_EFFECT all anchor on `(?:^|\n)\s*import`,
995
+ // so any import past the first one on a single line is silently dropped
996
+ // by the rewriter. Downstream that leaves bare relative specifiers like
997
+ // `../utils` to be resolved by the iOS HTTP ESM loader, which interprets
998
+ // them relative to the `/ns/asm/0?path=...` URL and 404s on the
999
+ // resulting `/ns/utils`. Splitting `;import` onto its own line makes the
1000
+ // existing patterns match every import, restoring the rewrite contract.
1001
+ //
1002
+ // Mirrors the same normalization already performed in
1003
+ // `core-sanitize.ts::normalizeStrayCoreStringLiterals` (`;\s*import` →
1004
+ // `;\nimport`) but applied universally at the rewriter entry point so
1005
+ // every caller benefits without having to opt in.
1006
+ result = result.replace(/;\s*import\s+/g, ';\nimport ');
1007
+ const httpOriginSafe = httpOrigin;
1008
+ const mixedRuntimePluginHttpRootPackages = collectMixedRuntimePluginHttpRootPackages(result, projectRoot);
1009
+ const isDynamicImportPrefix = (prefix) => /import\(\s*["']?$/.test(prefix.trimStart());
1010
+ const importerDir = path.posix.dirname(importerPath);
1011
+ // Resolved once per `rewriteImports` call so the per-import `/@fs/` rewriter
1012
+ // can convert workspace-lib paths back into our `/ns/m/` pipeline. Memoized
1013
+ // upstream — calling here is cheap and we reuse the value below.
1014
+ const monorepoWorkspaceRootForRewrite = getMonorepoWorkspaceRoot(projectRoot);
1015
+ // Determine importer output relative path (project-relative .mjs) to compute relative imports consistently
1016
+ const importerOutRel = outputDirOverrideRel || getProjectRelativeImportPath(importerPath, projectRoot) || stripToProjectRelative(importerPath, projectRoot).replace(/\.(ts|js|tsx|jsx|mjs|mts|cts)$/i, '.mjs');
1017
+ const importerOutDir = importerOutRel ? path.posix.dirname(importerOutRel) : '';
1018
+ const ensureRel = (p) => (p.startsWith('.') ? p : `./${p}`);
1019
+ const isNsSfcSpecifier = (spec) => /^(?:https?:\/\/[^/]+)?\/ns\/sfc(?:\/\d+)?(?:\/|$)/.test(spec.replace(PAT.QUERY_PATTERN, ''));
1020
+ // Normalize all @nativescript/core imports to the unified HTTP ESM core bridge to guarantee a single realm on device
1021
+ try {
1022
+ let coreAliasIdx = 0;
1023
+ const mkAlias = () => `__NSC${coreAliasIdx++}`;
1024
+ // Use the canonical PATH form `/ns/core/<sub>`. The iOS HTTP ESM
1025
+ // loader caches module records by URL string — every emitter
1026
+ // (`buildCoreUrl()` / `buildCoreUrlPath()`, the runtime import map,
1027
+ // vendor `require()` shims, app-side rewrites, the cold-boot
1028
+ // preload in `entry-runtime.ts`) MUST produce the same byte
1029
+ // string for the same logical core subpath. A divergence creates
1030
+ // two distinct V8 module records for the same source. Each gets
1031
+ // its own class
1032
+ // identities (TextBase, View, etc.), and side-effect patches
1033
+ // applied to one (e.g. @nativescript-community/text's
1034
+ // `TextBase.prototype.setTextDecorationAndTransform` override
1035
+ // installed when vendor.mjs evaluates `overrideSpanAndFormattedString()`
1036
+ // from `@nativescript-community/ui-label/index-common.js`) are
1037
+ // invisible to the other — manifesting as inconsistent line-height /
1038
+ // letter-spacing rendering between HMR and no-HMR.
1039
+ //
1040
+ // Mirrors `normalizeCoreSub()` (helpers/ns-core-url.ts) so the URL
1041
+ // produced here is byte-identical to what `buildCoreUrl()` produces
1042
+ // for the bundle entry, import map, and external-urls plugin.
1043
+ // Delegate to the ONE canonical URL builder so every emitter (this
1044
+ // rewriter, core-sanitize, the runtime import map, the ns-core-external-urls
1045
+ // build plugin, and main-entry) produces byte-identical URLs for
1046
+ // the same logical core module. Any drift here would re-introduce
1047
+ // the realm-split bug.
1048
+ const coreUrl = (sub) => (httpOriginSafe ? buildCoreUrl(httpOriginSafe, sub) : buildCoreUrlPath(sub));
1049
+ // Case 1: import { A, B } from '@nativescript/core[/sub]'
1050
+ result = result.replace(/(^|\n)\s*import\s*\{\s*([^}]+?)\s*\}\s*from\s+["']@nativescript\/core([^"'\n]*)["'];?/g, (_m, pfx, names, sub) => {
1051
+ const alias = mkAlias();
1052
+ const url = coreUrl(sub || '');
1053
+ const cleaned = names
1054
+ .split(',')
1055
+ .map((s) => s.trim())
1056
+ .filter(Boolean)
1057
+ .join(', ');
1058
+ return `${pfx}import * as ${alias} from ${JSON.stringify(url)};\nconst { ${cleaned} } = ${alias};`;
1059
+ });
1060
+ // Case 2: import Default, { A, B } from '@nativescript/core[/sub]'
1061
+ result = result.replace(/(^|\n)\s*import\s+([A-Za-z_$][\w$]*)\s*,\s*\{([^}]+?)\s*\}\s*from\s*["']@nativescript\/core([^"'\n]*)["'];?/g, (_m, pfx, defName, names, sub) => {
1062
+ const alias = mkAlias();
1063
+ const url = coreUrl(sub || '');
1064
+ const cleaned = names
1065
+ .split(',')
1066
+ .map((s) => s.trim())
1067
+ .filter(Boolean)
1068
+ .join(', ');
1069
+ return `${pfx}import * as ${alias} from ${JSON.stringify(url)};\nconst ${defName} = (${alias}.default || ${alias});\nconst { ${cleaned} } = ${alias};`;
1070
+ });
1071
+ // Case 3: import Default from '@nativescript/core[/sub]'
1072
+ result = result.replace(/(^|\n)\s*import\s+([A-Za-z_$][\w$]*)\s+from\s*["']@nativescript\/core([^"'\n]*)["'];?/g, (_m, pfx, defName, sub) => {
1073
+ const alias = mkAlias();
1074
+ const url = coreUrl(sub || '');
1075
+ return `${pfx}import * as ${alias} from ${JSON.stringify(url)};\nconst ${defName} = (${alias}.default || ${alias});`;
1076
+ });
1077
+ // Case 4: import * as NS from '@nativescript/core[/sub]'
1078
+ result = result.replace(/(^|\n)\s*import\s+\*\s+as\s+([A-Za-z_$][\w$]*)\s+from\s*["']@nativescript\/core([^"'\n]*)["'];?/g, (_m, pfx, nsName, sub) => {
1079
+ const url = coreUrl(sub || '');
1080
+ return `${pfx}import * as ${nsName} from ${JSON.stringify(url)};`;
1081
+ });
1082
+ // Case 5: side-effect import '@nativescript/core[/sub]'
1083
+ result = result.replace(/(^|\n)\s*import\s*["']@nativescript\/core([^"'\n]*)["'];?/g, (_m, pfx, sub) => {
1084
+ const url = coreUrl(sub || '');
1085
+ return `${pfx}import ${JSON.stringify(url)};`;
1086
+ });
1087
+ // Case 6: dynamic import('@nativescript/core[/sub]')
1088
+ result = result.replace(/import\(\s*["']@nativescript\/core([^"'\n]*)["']\s*\)/g, (_m, sub) => {
1089
+ const url = coreUrl(sub || '');
1090
+ return `import(${JSON.stringify(url)})`;
1091
+ });
1092
+ }
1093
+ catch { }
1094
+ // Inline JSON imports (package.json, config.json, etc.)
1095
+ // This must happen BEFORE other rewrites because JSON imports get a ?import query added by Vite
1096
+ result = result.replace(/import\s+(\w+)\s+from\s+["']([^"']+\.json(?:\?[^"']*)?)["'];?/g, (match, varName, jsonPath) => {
1097
+ try {
1098
+ // Remove query params like ?import
1099
+ const cleanPath = jsonPath.split('?')[0];
1100
+ // Resolve the JSON file path relative to the importer
1101
+ let fullPath;
1102
+ if (cleanPath.startsWith('/@fs/')) {
1103
+ // Vite filesystem URL: `/@fs/<abs-path>`. Strip the `/@fs` prefix
1104
+ // (4 chars, leaving the leading `/`) to recover the absolute
1105
+ // path. This matches `rewriteFsAbsoluteToNsM`'s convention and
1106
+ // covers both bare specifiers Vite pre-resolved out of the
1107
+ // project root (e.g. `emojibase-data/en/compact.json` →
1108
+ // `/@fs/.../node_modules/.../compact.json`) and tsconfig
1109
+ // path-alias targets that resolve outside the project root
1110
+ // (e.g. `~shared/...metadata.json` → `/@fs/.../tools/...json`).
1111
+ // Without this branch the next `else if` would `path.join` the
1112
+ // `/@fs/...` URL onto `projectRoot`, collapsing the leading `/`
1113
+ // and producing a malformed nested path that always misses on
1114
+ // `existsSync` and triggers a `ReferenceError` at runtime when
1115
+ // the JSON-import-failed comment leaves the binding undefined.
1116
+ fullPath = cleanPath.slice('/@fs'.length);
1117
+ }
1118
+ else if (cleanPath.startsWith('/')) {
1119
+ // Absolute from project root
1120
+ fullPath = path.join(projectRoot, cleanPath);
1121
+ }
1122
+ else if (cleanPath.startsWith('./') || cleanPath.startsWith('../')) {
1123
+ // Relative to importer - resolve from importer's location in project
1124
+ const importerFullPath = path.join(projectRoot, importerDir);
1125
+ fullPath = path.resolve(importerFullPath, cleanPath);
1126
+ }
1127
+ else {
1128
+ // Skip node_modules JSON imports
1129
+ return match;
1130
+ }
1131
+ if (existsSync(fullPath)) {
1132
+ const jsonContent = readFileSync(fullPath, 'utf-8');
1133
+ if (verbose) {
1134
+ console.log(`[rewrite] JSON inline: ${jsonPath} → const ${varName} = {...}`);
1135
+ }
1136
+ // Inline the JSON as a const declaration
1137
+ return `const ${varName} = ${jsonContent};`;
1138
+ }
1139
+ else {
1140
+ console.warn(`[rewrite] JSON file not found: ${fullPath} (specifier=${jsonPath})`);
1141
+ }
1142
+ }
1143
+ catch (error) {
1144
+ console.warn(`[rewrite] Could not inline JSON import: ${jsonPath}`, error);
1145
+ }
1146
+ // If we can't inline it, remove the import to prevent runtime errors
1147
+ // The code will fail with "varName is not defined" which is more debuggable
1148
+ return `/* JSON import failed: ${match} */`;
1149
+ });
1150
+ // Helper to resolve .vue file imports to absolute project paths
1151
+ const resolveVueKey = (spec) => {
1152
+ if (!spec || typeof spec !== 'string') {
1153
+ return null;
1154
+ }
1155
+ // Only process .vue files
1156
+ if (!PAT.VUE_FILE_PATTERN.test(spec)) {
1157
+ return null;
1158
+ }
1159
+ let key;
1160
+ if (spec.startsWith('/')) {
1161
+ key = spec;
1162
+ }
1163
+ else if (spec.startsWith('./') || spec.startsWith('../')) {
1164
+ key = path.posix.normalize(path.posix.join(importerDir, spec));
1165
+ if (!key.startsWith('/'))
1166
+ key = '/' + key;
1167
+ }
1168
+ else {
1169
+ return null;
1170
+ }
1171
+ // Strip query params
1172
+ key = key.replace(PAT.QUERY_PATTERN, '');
1173
+ return key;
1174
+ };
1175
+ // Replacement function for all imports
1176
+ const replaceVueImport = (_match, prefix, spec, suffix) => {
1177
+ // Safety check
1178
+ if (!spec || typeof spec !== 'string') {
1179
+ return `${prefix}${spec}${suffix}`;
1180
+ }
1181
+ // Guard 0: leave fully-qualified HTTP(S) URLs alone
1182
+ if (/^https?:\/\//.test(spec)) {
1183
+ return `${prefix}${spec}${suffix}`;
1184
+ }
1185
+ // Guard: anomalous bare '@' spec should be rewritten to a safe stub module.
1186
+ // This can surface from upstream alias mishaps; mapping it here avoids device-side
1187
+ // "instantiate failed @" errors.
1188
+ if (spec === '@') {
1189
+ const stub = `/ns/m/__invalid_at__.mjs`;
1190
+ if (verbose) {
1191
+ console.warn(`[rewrite] mapped bare '@' spec to stub: ${stub}`);
1192
+ }
1193
+ return `${prefix}${stub}${suffix}`;
1194
+ }
1195
+ spec = normalizeNativeScriptCoreSpecifier(spec);
1196
+ // Pull `/@fs/<abs-path>` URLs back into the `/ns/m/` pipeline so they
1197
+ // hit our CJS/UMD-wrapping handler. Vite emits `/@fs/...` for any
1198
+ // resolved id outside the configured `root` — including hoisted
1199
+ // `node_modules/<pkg>` entries and workspace libs in monorepos. Left
1200
+ // untouched, the device fetches them through Vite's standard
1201
+ // middleware which never invokes `wrapCommonJsModuleForDevice`, so a
1202
+ // UMD module like papaparse crashes on `(this).Papa = factory()`
1203
+ // because top-level `this` is `undefined` in ESM context.
1204
+ if (spec.startsWith('/@fs/')) {
1205
+ const rewritten = rewriteFsAbsoluteToNsM(spec, projectRoot, monorepoWorkspaceRootForRewrite);
1206
+ if (rewritten) {
1207
+ if (httpOriginSafe) {
1208
+ return `${prefix}${httpOriginSafe}${rewritten}${suffix}`;
1209
+ }
1210
+ return `${prefix}${rewritten}${suffix}`;
1211
+ }
1212
+ // Path resolves outside both roots — leave Vite's URL alone as a
1213
+ // last resort. The original behaviour was to fall through here
1214
+ // and let downstream branches (e.g. `normalizeNodeModulesSpecifier`)
1215
+ // handle paths whose abs form happens to contain `/node_modules/`,
1216
+ // so preserve that for the unrewritable case below.
1217
+ }
1218
+ // Route Vite virtual modules (/@solid-refresh, etc.) through /ns/m/ so their
1219
+ // internal imports (e.g. solid-js) get vendor-rewritten by our pipeline.
1220
+ // Skip known Vite internals (/@vite/, /@id/) which are handled elsewhere.
1221
+ // `/@fs/` is intentionally excluded above; if we ever reach here with a
1222
+ // `/@fs/` spec it means the rewrite-to-`/ns/m/` pass couldn't anchor it
1223
+ // under projectRoot or workspaceRoot, so we fall through and rely on the
1224
+ // `normalizeNodeModulesSpecifier` branch below for paths that still
1225
+ // contain a `/node_modules/<pkg>/` segment.
1226
+ if (spec.startsWith('/@') && !/^\/@(?:vite|id|fs)\//.test(spec)) {
1227
+ const out = `/ns/m${spec}`;
1228
+ if (httpOriginSafe) {
1229
+ return `${prefix}${httpOriginSafe}${out}${suffix}`;
1230
+ }
1231
+ return `${prefix}${out}${suffix}`;
1232
+ }
1233
+ // Route internal NS endpoints to absolute HTTP origin for device
1234
+ if (spec.startsWith('/ns/')) {
1235
+ if (httpOriginSafe) {
1236
+ return `${prefix}${httpOriginSafe}${spec}${suffix}`;
1237
+ }
1238
+ return `${prefix}${spec}${suffix}`;
1239
+ }
1240
+ if (isNativeScriptCoreModule(spec)) {
1241
+ return `${prefix}${spec}${suffix}`;
1242
+ }
1243
+ const nodeModulesSpecifier = normalizeNodeModulesSpecifier(spec);
1244
+ const normalizedRuntimePluginSpec = nodeModulesSpecifier || spec.replace(PAT.QUERY_PATTERN, '').replace(/^\/+/, '');
1245
+ if (normalizedRuntimePluginSpec && mixedRuntimePluginHttpRootPackages.size > 0) {
1246
+ const { packageName } = resolveNodeModulesPackageBoundary(normalizedRuntimePluginSpec, projectRoot);
1247
+ if (packageName && mixedRuntimePluginHttpRootPackages.has(packageName)) {
1248
+ const httpNodeModulesSpecifier = nodeModulesSpecifier || normalizedRuntimePluginSpec;
1249
+ const httpSpec = `/ns/m/node_modules/${httpNodeModulesSpecifier}`;
1250
+ if (httpOriginSafe) {
1251
+ return `${prefix}${httpOriginSafe}${httpSpec}${suffix}`;
1252
+ }
1253
+ return `${prefix}${httpSpec}${suffix}`;
1254
+ }
1255
+ }
1256
+ if (shouldPreserveBareRuntimePluginSubpathImport(spec, projectRoot)) {
1257
+ const httpSpec = `/ns/m/node_modules/${spec.replace(PAT.QUERY_PATTERN, '').replace(/^\/+/, '')}`;
1258
+ if (httpOriginSafe) {
1259
+ return `${prefix}${httpOriginSafe}${httpSpec}${suffix}`;
1260
+ }
1261
+ return `${prefix}${httpSpec}${suffix}`;
1262
+ }
1263
+ // ── Node modules routing ──────────────────────────────────────
1264
+ // Uses the package's own package.json exports field to determine
1265
+ // whether an import is the main entry (→ vendor bridge) or a
1266
+ // subpath entry (→ HTTP). This replaces the old heuristic-based
1267
+ // approach that tried to guess from file paths.
1268
+ if (nodeModulesSpecifier) {
1269
+ const vendorRouting = resolveVendorRouting(nodeModulesSpecifier, projectRoot);
1270
+ if (vendorRouting) {
1271
+ if (vendorRouting.route === 'vendor') {
1272
+ return `${prefix}${vendorRouting.bareSpec}${suffix}`;
1273
+ }
1274
+ // Vendor package but subpath/platform-specific → HTTP
1275
+ const httpSpec = `/ns/m/node_modules/${nodeModulesSpecifier}`;
1276
+ if (httpOriginSafe) {
1277
+ return `${prefix}${httpOriginSafe}${httpSpec}${suffix}`;
1278
+ }
1279
+ return `${prefix}${httpSpec}${suffix}`;
1280
+ }
1281
+ // Not a vendor package → serve via HTTP from Vite dev server
1282
+ const httpSpec = `/ns/m/node_modules/${nodeModulesSpecifier}`;
1283
+ if (httpOriginSafe) {
1284
+ return `${prefix}${httpOriginSafe}${httpSpec}${suffix}`;
1285
+ }
1286
+ return `${prefix}${httpSpec}${suffix}`;
1287
+ }
1288
+ // Handle .vue imports
1289
+ if (PAT.VUE_FILE_PATTERN.test(spec)) {
1290
+ // Case A: SFC submodule variant (template/script) must keep its query to avoid self-import cycles.
1291
+ const isVueVariant = /\bvue&type=/.test(spec);
1292
+ if (isVueVariant) {
1293
+ // Preserve the full ?vue&type=... query and route via /ns/sfc so sanitation applies
1294
+ const qIdx = spec.indexOf('?');
1295
+ const base = qIdx !== -1 ? spec.slice(0, qIdx) : spec;
1296
+ const query = qIdx !== -1 ? spec.slice(qIdx) : '';
1297
+ // Resolve to absolute project path if relative
1298
+ let abs = base;
1299
+ if (!abs.startsWith('/')) {
1300
+ const joined = path.posix.normalize(path.posix.join(importerDir, abs));
1301
+ abs = joined.startsWith('/') ? joined : `/${joined}`;
1302
+ }
1303
+ const out = `/ns/sfc${abs}${query}`;
1304
+ if (verbose) {
1305
+ console.log(`[rewrite] .vue variant routed (http): ${spec} → ${out}`);
1306
+ }
1307
+ return `${prefix}${out}${suffix}`;
1308
+ }
1309
+ // Case B: plain .vue module → rewrite to SFC endpoint or local artifact
1310
+ const vueKey = resolveVueKey(spec.replace(PAT.QUERY_PATTERN, '')) || '';
1311
+ if (vueKey) {
1312
+ if (true) {
1313
+ const absVue = vueKey.startsWith('/') ? vueKey : '/' + vueKey;
1314
+ const out = `/ns/sfc${absVue}`;
1315
+ if (verbose) {
1316
+ console.log(`[rewrite] .vue rewrite (http): ${spec} → ${out}`);
1317
+ }
1318
+ return `${prefix}${out}${suffix}`;
1319
+ }
1320
+ else {
1321
+ const vueFile = sfcFileMap.get(vueKey);
1322
+ if (vueFile) {
1323
+ const target = `_ns_hmr/${APP_ROOT_DIR}/sfc/${vueFile}`;
1324
+ const relPath = importerOutDir ? ensureRel(path.posix.relative(importerOutDir, target)) : ensureRel(target);
1325
+ if (verbose) {
1326
+ console.log(`[rewrite] .vue rewrite: ${spec} → ${relPath}`);
1327
+ }
1328
+ return `${prefix}${relPath}${suffix}`;
1329
+ }
1330
+ else if (verbose) {
1331
+ console.log(`[rewrite] .vue NOT in sfcFileMap: ${vueKey}`);
1332
+ }
1333
+ }
1334
+ }
1335
+ return `${prefix}${spec}${suffix}`;
1336
+ }
1337
+ // Rewrite relative application imports to HTTP for served modules
1338
+ if (spec.startsWith('./') || spec.startsWith('../')) {
1339
+ const absMaybe = normalizeImportPath(spec, importerDir);
1340
+ const nodeModulesHttpSpec = absMaybe ? toNodeModulesHttpModuleId(absMaybe) : null;
1341
+ if (nodeModulesHttpSpec) {
1342
+ if (isDynamicImportPrefix(prefix)) {
1343
+ if (verbose)
1344
+ console.log(`[rewrite][http] dynamic relative node_modules import → ${nodeModulesHttpSpec} (from ${spec})`);
1345
+ return `__nsDynamicHmrImport(${JSON.stringify(nodeModulesHttpSpec)})`;
1346
+ }
1347
+ if (verbose)
1348
+ console.log(`[rewrite][http] relative node_modules import → ${nodeModulesHttpSpec} (from ${spec})`);
1349
+ return `${prefix}${nodeModulesHttpSpec}${suffix}`;
1350
+ }
1351
+ const baseId = absMaybe ? toAppModuleBaseId(absMaybe, projectRoot) : null; // e.g. /src/foo.mjs
1352
+ if (baseId) {
1353
+ const httpSpec = `/ns/m${baseId}`;
1354
+ if (isDynamicImportPrefix(prefix)) {
1355
+ if (verbose)
1356
+ console.log(`[rewrite][http] dynamic relative app import → ${httpSpec} (from ${spec})`);
1357
+ return `__nsDynamicHmrImport(${JSON.stringify(httpSpec)})`;
1358
+ }
1359
+ if (verbose)
1360
+ console.log(`[rewrite][http] relative app import → ${httpSpec} (from ${spec})`);
1361
+ return `${prefix}${httpSpec}${suffix}`;
1362
+ }
1363
+ return `${prefix}${spec}${suffix}`;
1364
+ }
1365
+ // Note: Do NOT rewrite bare application specifiers (e.g. "core/foo").
1366
+ // These will be inlined during bundleDependenciesInline() to avoid static HTTP imports on device.
1367
+ if (isApplicationImport(spec)) {
1368
+ const baseId = toAppModuleBaseId(spec, projectRoot);
1369
+ if (baseId) {
1370
+ const httpSpec = `/ns/m${baseId}`;
1371
+ if (isDynamicImportPrefix(prefix)) {
1372
+ if (verbose)
1373
+ console.log(`[rewrite][http] dynamic app import → ${httpSpec} (from ${spec})`);
1374
+ return `__nsDynamicHmrImport(${JSON.stringify(httpSpec)})`;
1375
+ }
1376
+ if (verbose)
1377
+ console.log(`[rewrite][http] absolute app import → ${httpSpec} (from ${spec})`);
1378
+ return `${prefix}${httpSpec}${suffix}`;
1379
+ }
1380
+ return `${prefix}${spec}${suffix}`;
1381
+ }
1382
+ // In HTTP mode, avoid rewriting to dep-*.mjs; let imports resolve via server endpoints
1383
+ const depKey = normalizeImportPath(spec, importerDir);
1384
+ if (depKey && !httpOriginSafe) {
1385
+ if (isNativeScriptCoreModule(depKey)) {
1386
+ return `${prefix}${spec}${suffix}`;
1387
+ }
1388
+ if (isNativeScriptPluginModule(depKey)) {
1389
+ return `${prefix}${spec}${suffix}`;
1390
+ }
1391
+ const depFile = findDependencyFileName(depFileMap, depKey);
1392
+ if (depFile) {
1393
+ if (verbose) {
1394
+ console.log(`[rewrite] dep import: ${spec} → ./${depFile}`);
1395
+ }
1396
+ return `${prefix}./${depFile}${suffix}`;
1397
+ }
1398
+ }
1399
+ // ── Bare specifier vendor routing ────────────────────────────
1400
+ // Bare specifiers like `pinia`, `dayjs`, `lodash` never reach
1401
+ // the `nodeModulesSpecifier` branch above because
1402
+ // `normalizeNodeModulesSpecifier` keys on a literal
1403
+ // `/node_modules/` segment in the path. Without this check
1404
+ // they'd fall straight into the HTTP fallback below and get
1405
+ // rewritten to `/ns/m/node_modules/<spec>`, which serves the
1406
+ // package source over HTTP and bypasses the device-side import
1407
+ // map's `<pkg>` → `ns-vendor://<pkg>` entry. For CJS/UMD
1408
+ // packages (e.g. Pinia) the bare HTTP path doesn't expose the
1409
+ // full named-exports surface (only the default export round-
1410
+ // trips), so consumers like
1411
+ // `import { defineStore } from "pinia"` blow up at instantiate
1412
+ // time with `SyntaxError: ... does not provide an export named
1413
+ // 'defineStore'`. Preserving the bare spec lets the vendor
1414
+ // bridge serve it from the prebuilt `bundle.mjs`, which already
1415
+ // re-exports the full CJS surface. Subpath imports
1416
+ // (`pinia/plugins/foo`) intentionally fall through to the
1417
+ // HTTP fallback — `resolveVendorRouting` returns
1418
+ // `{ route: 'http' }` for non-main-entry subpaths even when the
1419
+ // root package is in the manifest, mirroring the
1420
+ // `nodeModulesSpecifier` branch.
1421
+ if (spec && !spec.startsWith('/') && !spec.startsWith('./') && !spec.startsWith('../') && !/^https?:\/\//i.test(spec) && !spec.startsWith('ns-vendor:') && !spec.startsWith('@nativescript/core')) {
1422
+ const bareNpmRe = /^(?:@[A-Za-z0-9][\w.-]*\/)?[A-Za-z0-9][\w.-]*(?:\/[\w.\-/]+)?$/;
1423
+ if (bareNpmRe.test(spec)) {
1424
+ const bareVendorRouting = resolveVendorRouting(spec, projectRoot);
1425
+ if (bareVendorRouting?.route === 'vendor') {
1426
+ if (verbose) {
1427
+ console.log(`[rewrite] bare vendor import: ${spec} → ${bareVendorRouting.bareSpec}`);
1428
+ }
1429
+ return `${prefix}${bareVendorRouting.bareSpec}${suffix}`;
1430
+ }
1431
+ }
1432
+ }
1433
+ // Bare npm package specifier fallback — route to /ns/m/node_modules/.
1434
+ // This catches specifiers like `source-map-js/lib/source-map-generator.js`
1435
+ // emitted by helpers such as the CommonJS compat transform, which Vite
1436
+ // would normally resolve to an absolute path but which pass through the
1437
+ // rewriter as bare strings here. Under HMR (core external) bundle.mjs
1438
+ // depends on these resolving over HTTP rather than via a filesystem
1439
+ // bare-specifier lookup, which iOS can't satisfy and which crashes with
1440
+ // "Module not found".
1441
+ if (spec && !spec.startsWith('/') && !spec.startsWith('./') && !spec.startsWith('../') && !/^https?:\/\//i.test(spec) && !spec.startsWith('ns-vendor:') && !spec.startsWith('@nativescript/core')) {
1442
+ // Only treat as a package spec if it looks like one — disallow
1443
+ // plain identifiers like `moment` unresolved (those are left alone
1444
+ // for existing vendor-routing paths to handle).
1445
+ const bareNpmRe = /^(?:@[A-Za-z0-9][\w.-]*\/)?[A-Za-z0-9][\w.-]*(?:\/[\w.\-/]+)?$/;
1446
+ if (bareNpmRe.test(spec)) {
1447
+ const httpSpec = `/ns/m/node_modules/${spec}`;
1448
+ if (httpOriginSafe) {
1449
+ return `${prefix}${httpOriginSafe}${httpSpec}${suffix}`;
1450
+ }
1451
+ return `${prefix}${httpSpec}${suffix}`;
1452
+ }
1453
+ }
1454
+ // Leave everything else unchanged (vendor imports, etc.)
1455
+ return `${prefix}${spec}${suffix}`;
1456
+ };
1457
+ // Apply to all import/export patterns (but only .vue files will be rewritten)
1458
+ result = result.replace(PAT.IMPORT_PATTERN_1, replaceVueImport);
1459
+ result = result.replace(PAT.IMPORT_PATTERN_2, replaceVueImport);
1460
+ result = result.replace(PAT.EXPORT_PATTERN, replaceVueImport);
1461
+ result = result.replace(PAT.IMPORT_PATTERN_3, replaceVueImport);
1462
+ // Side-effect imports (import "spec") — must run AFTER named-import patterns
1463
+ // since IMPORT_PATTERN_1 already handles `import ... from "spec"`.
1464
+ result = result.replace(PAT.IMPORT_PATTERN_SIDE_EFFECT, replaceVueImport);
1465
+ result = ensureDynamicHmrImportHelper(result);
1466
+ // Extra guard: map any lingering dynamic import('@') to a safe stub module path
1467
+ // to prevent device runtime normalization errors.
1468
+ // Example matched: import('@') or import("@") with optional whitespace before closing paren
1469
+ result = result.replace(/(import\(\s*['"])@(['"]\s*\))/g, (_m) => {
1470
+ const stubExpr = `import(new URL('/ns/m/__invalid_at__.mjs', import.meta.url).href)`;
1471
+ if (verbose) {
1472
+ console.warn(`[rewrite] mapped dynamic import('@') to /ns/m/__invalid_at__.mjs via import.meta.url`);
1473
+ }
1474
+ return stubExpr;
1475
+ });
1476
+ // Also guard static spec forms that could erroneously be '@'
1477
+ // 1) ESM: import { x } from '@'
1478
+ result = result.replace(/(from\s*['"])@(['"])/g, (_m, p1, p2) => {
1479
+ const stub = `/ns/m/__invalid_at__.mjs`;
1480
+ if (verbose) {
1481
+ console.warn(`[rewrite] mapped static from '@' to ${stub}`);
1482
+ }
1483
+ return `${p1}${stub}${p2}`;
1484
+ });
1485
+ // 2) ESM side-effect: import '@'
1486
+ result = result.replace(/(import\s*(?!\()\s*['"])@(['"])/g, (_m, p1, p2) => {
1487
+ const stub = `/ns/m/__invalid_at__.mjs`;
1488
+ if (verbose) {
1489
+ console.warn(`[rewrite] mapped side-effect import '@' to ${stub}`);
1490
+ }
1491
+ return `${p1}${stub}${p2}`;
1492
+ });
1493
+ // Handle .vue imports with queries
1494
+ // In HTTP mode, skip legacy local-path rewrite to avoid mixing module origins
1495
+ result = result.replace(PAT.VUE_FILE_IMPORT, (_m, p1, spec, p3) => {
1496
+ if (httpOrigin) {
1497
+ if (isNsSfcSpecifier(spec)) {
1498
+ if (verbose)
1499
+ console.log(`[rewrite] .vue already routed (VUE_FILE_IMPORT http): ${spec}`);
1500
+ return `${p1}${spec}${p3}`;
1501
+ }
1502
+ // Route via /ns/sfc with full query preserved
1503
+ try {
1504
+ let base = spec;
1505
+ const qIdx = base.indexOf('?');
1506
+ const query = qIdx !== -1 ? base.slice(qIdx) : '';
1507
+ base = qIdx !== -1 ? base.slice(0, qIdx) : base;
1508
+ // Resolve relative to importerDir
1509
+ let abs = base;
1510
+ if (!abs.startsWith('/')) {
1511
+ const joined = path.posix.normalize(path.posix.join(importerDir, abs));
1512
+ abs = joined.startsWith('/') ? joined : '/' + joined;
1513
+ }
1514
+ const out = `/ns/sfc${abs}${query}`;
1515
+ if (verbose)
1516
+ console.log(`[rewrite] .vue variant routed (VUE_FILE_IMPORT http): ${spec} → ${out}`);
1517
+ return `${p1}${out}${p3}`;
1518
+ }
1519
+ catch { }
1520
+ return `${p1}${spec}${p3}`;
1521
+ }
1522
+ const vueKey = resolveVueKey(spec);
1523
+ if (vueKey) {
1524
+ const vueFile = sfcFileMap.get(vueKey);
1525
+ if (vueFile) {
1526
+ const target = `_ns_hmr/${APP_ROOT_DIR}/sfc/${vueFile}`;
1527
+ const relPath = importerOutDir ? ensureRel(path.posix.relative(importerOutDir, target)) : ensureRel(target);
1528
+ if (verbose) {
1529
+ console.log(`[rewrite] .vue rewrite (VUE_FILE_IMPORT): ${spec} → ${relPath}`);
1530
+ }
1531
+ return `${p1}${relPath}${p3}`;
1532
+ }
1533
+ else if (verbose) {
1534
+ console.log(`[rewrite] .vue NOT in sfcFileMap (VUE_FILE_IMPORT): ${vueKey}`);
1535
+ }
1536
+ }
1537
+ return `${p1}${spec}${p3}`;
1538
+ });
1539
+ // Final safeguard: normalize any remaining absolute filesystem dynamic imports to HTTP origin spec
1540
+ const absoluteDynamicPattern = /(import\(\s*["'])([^"']+)(["']\s*\))/g;
1541
+ result = result.replace(absoluteDynamicPattern, (match, _prefix, spec, _suffix) => {
1542
+ if (!spec || !spec.startsWith('/'))
1543
+ return match;
1544
+ // Handle internal NS endpoints
1545
+ if (spec.startsWith('/ns/')) {
1546
+ const expr = `import(new URL('${spec}', import.meta.url).href)`;
1547
+ if (verbose)
1548
+ console.log(`[rewrite][http] internal ns import (dynamic) → ${spec} via import.meta.url`);
1549
+ return expr;
1550
+ }
1551
+ const nodeModulesHttpSpec = toNodeModulesHttpModuleId(spec);
1552
+ if (nodeModulesHttpSpec) {
1553
+ const expr = `import(new URL('${nodeModulesHttpSpec}', import.meta.url).href)`;
1554
+ if (verbose)
1555
+ console.log(`[rewrite][http] absolute dynamic node_modules import → ${nodeModulesHttpSpec} via import.meta.url (from ${spec})`);
1556
+ return expr;
1557
+ }
1558
+ const baseId = toAppModuleBaseId(spec, projectRoot);
1559
+ if (!baseId)
1560
+ return match;
1561
+ const expr = `import(new URL('/ns/m${baseId}', import.meta.url).href)`;
1562
+ if (verbose)
1563
+ console.log(`[rewrite][http] absolute dynamic import → /ns/m${baseId} via import.meta.url (from ${spec})`);
1564
+ return expr;
1565
+ });
1566
+ return result;
1567
+ }
1568
+ // Re-exports for the plugin closure + the spec suites that import from `./websocket.js`.
1569
+ export { processCodeForDevice, cleanCode, collectImportDependencies, shouldRemapImport, processSfcCode };
1570
+ //# sourceMappingURL=websocket-device-transform.js.map