@abide/abide 0.28.0

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 (562) hide show
  1. package/CHANGELOG.md +607 -0
  2. package/LICENSE +21 -0
  3. package/README.md +154 -0
  4. package/bin/abide.ts +212 -0
  5. package/package.json +155 -0
  6. package/src/abideLsp.ts +211 -0
  7. package/src/abideModules.d.ts +8 -0
  8. package/src/abideResolverPlugin.ts +923 -0
  9. package/src/appEntry.ts +151 -0
  10. package/src/assets/app.html +12 -0
  11. package/src/build.ts +143 -0
  12. package/src/buildCli.ts +127 -0
  13. package/src/buildDisconnected.ts +118 -0
  14. package/src/bundleApp.ts +147 -0
  15. package/src/bundleDisconnectedEntry.ts +14 -0
  16. package/src/checkAbide.ts +77 -0
  17. package/src/cliEntry.ts +25 -0
  18. package/src/clientBuildPlugins.ts +33 -0
  19. package/src/clientEntry.ts +17 -0
  20. package/src/compile.ts +63 -0
  21. package/src/controlServerWorker.ts +426 -0
  22. package/src/devEntry.ts +250 -0
  23. package/src/discoveryEntry.ts +81 -0
  24. package/src/lib/bundle/BundleMenu.ts +12 -0
  25. package/src/lib/bundle/BundleMenuItem.ts +25 -0
  26. package/src/lib/bundle/BundleWindow.ts +37 -0
  27. package/src/lib/bundle/WEBVIEW_BUILD_REVISION.ts +9 -0
  28. package/src/lib/bundle/WEBVIEW_VERSION.ts +7 -0
  29. package/src/lib/bundle/bindConnectedFlag.ts +29 -0
  30. package/src/lib/bundle/bindRequestNavigate.ts +34 -0
  31. package/src/lib/bundle/buildWebviewLib.ts +111 -0
  32. package/src/lib/bundle/bundled.ts +35 -0
  33. package/src/lib/bundle/disconnected.abide +236 -0
  34. package/src/lib/bundle/disconnected.css +9 -0
  35. package/src/lib/bundle/ensureWebviewLib.ts +20 -0
  36. package/src/lib/bundle/exitWithParent.ts +28 -0
  37. package/src/lib/bundle/infoPlist.ts +46 -0
  38. package/src/lib/bundle/installDownloads.ts +24 -0
  39. package/src/lib/bundle/installMacMenu.ts +39 -0
  40. package/src/lib/bundle/listenLocalControlServer.ts +19 -0
  41. package/src/lib/bundle/native/abideMenu.mm +422 -0
  42. package/src/lib/bundle/native/webview.h +4557 -0
  43. package/src/lib/bundle/onMenu.ts +42 -0
  44. package/src/lib/bundle/openWebview.ts +104 -0
  45. package/src/lib/bundle/pngToIcns.ts +47 -0
  46. package/src/lib/bundle/probeAbideServer.ts +57 -0
  47. package/src/lib/bundle/resolveServerBinary.ts +12 -0
  48. package/src/lib/bundle/resolveWebviewLib.ts +53 -0
  49. package/src/lib/bundle/serverBinaryFilename.ts +8 -0
  50. package/src/lib/bundle/signMacApp.ts +37 -0
  51. package/src/lib/bundle/spawnEmbeddedServer.ts +64 -0
  52. package/src/lib/bundle/stableLocalPort.ts +19 -0
  53. package/src/lib/bundle/waitForServer.ts +23 -0
  54. package/src/lib/bundle/webviewCachePath.ts +23 -0
  55. package/src/lib/bundle/webviewLibName.ts +11 -0
  56. package/src/lib/cli/connectToServer.ts +23 -0
  57. package/src/lib/cli/createClient.ts +108 -0
  58. package/src/lib/cli/dispatchCommand.ts +71 -0
  59. package/src/lib/cli/loadEnvFromBinaryDir.ts +15 -0
  60. package/src/lib/cli/parseArgvForRpc.ts +100 -0
  61. package/src/lib/cli/printHelp.ts +119 -0
  62. package/src/lib/cli/printSessionHelp.ts +27 -0
  63. package/src/lib/cli/printSessionStatus.ts +21 -0
  64. package/src/lib/cli/printTrimmed.ts +8 -0
  65. package/src/lib/cli/printValue.ts +10 -0
  66. package/src/lib/cli/resolveCliTarget.ts +48 -0
  67. package/src/lib/cli/runCli.ts +176 -0
  68. package/src/lib/cli/runSession.ts +108 -0
  69. package/src/lib/cli/startLocalInstance.ts +14 -0
  70. package/src/lib/cli/tokenizeLine.ts +51 -0
  71. package/src/lib/cli/types/CliManifest.ts +9 -0
  72. package/src/lib/cli/types/CliManifestEntry.ts +17 -0
  73. package/src/lib/cli/types/CliTarget.ts +13 -0
  74. package/src/lib/mcp/annotationsForMethod.ts +29 -0
  75. package/src/lib/mcp/createMcpResourceServer.ts +102 -0
  76. package/src/lib/mcp/createMcpServer.ts +48 -0
  77. package/src/lib/mcp/dispatchMcpRequest.ts +138 -0
  78. package/src/lib/mcp/mcpResourceServerSlot.ts +18 -0
  79. package/src/lib/mcp/mcpSurface.ts +295 -0
  80. package/src/lib/mcp/toolResultFromResponse.ts +66 -0
  81. package/src/lib/mcp/types/JsonRpcRequest.ts +12 -0
  82. package/src/lib/mcp/types/JsonRpcResponse.ts +20 -0
  83. package/src/lib/mcp/types/McpResourceContents.ts +10 -0
  84. package/src/lib/mcp/types/McpResourceDescriptor.ts +6 -0
  85. package/src/lib/mcp/types/McpResourceServer.ts +12 -0
  86. package/src/lib/mcp/types/McpServer.ts +9 -0
  87. package/src/lib/mcp/types/McpServerOptions.ts +16 -0
  88. package/src/lib/server/AppModule.ts +47 -0
  89. package/src/lib/server/DELETE.ts +10 -0
  90. package/src/lib/server/GET.ts +10 -0
  91. package/src/lib/server/HEAD.ts +10 -0
  92. package/src/lib/server/PATCH.ts +10 -0
  93. package/src/lib/server/POST.ts +10 -0
  94. package/src/lib/server/PUT.ts +10 -0
  95. package/src/lib/server/agent.ts +86 -0
  96. package/src/lib/server/appDataDir.ts +16 -0
  97. package/src/lib/server/cli/buildEnvContent.ts +19 -0
  98. package/src/lib/server/cli/createTarGz.ts +77 -0
  99. package/src/lib/server/cli/handleCliDownload.ts +150 -0
  100. package/src/lib/server/cli/handleCliInstall.ts +37 -0
  101. package/src/lib/server/cli/installScript.ts +31 -0
  102. package/src/lib/server/cli/maxSourceMtime.ts +26 -0
  103. package/src/lib/server/cookies.ts +30 -0
  104. package/src/lib/server/env.ts +51 -0
  105. package/src/lib/server/error.ts +73 -0
  106. package/src/lib/server/json.ts +42 -0
  107. package/src/lib/server/jsonl.ts +47 -0
  108. package/src/lib/server/prompts/definePrompt.ts +21 -0
  109. package/src/lib/server/prompts/promptRegistry.ts +9 -0
  110. package/src/lib/server/prompts/registerPrompt.ts +6 -0
  111. package/src/lib/server/prompts/renderPromptTemplate.ts +17 -0
  112. package/src/lib/server/prompts/types/Prompt.ts +13 -0
  113. package/src/lib/server/prompts/types/PromptOptions.ts +12 -0
  114. package/src/lib/server/prompts/types/PromptRegistryEntry.ts +13 -0
  115. package/src/lib/server/prompts/types/PromptRoutes.ts +10 -0
  116. package/src/lib/server/reachable.ts +45 -0
  117. package/src/lib/server/redirect.ts +43 -0
  118. package/src/lib/server/request.ts +19 -0
  119. package/src/lib/server/rpc/defineVerb.ts +210 -0
  120. package/src/lib/server/rpc/dispatchVerbInProcess.ts +46 -0
  121. package/src/lib/server/rpc/findVerbByCommandName.ts +18 -0
  122. package/src/lib/server/rpc/parseArgs.ts +127 -0
  123. package/src/lib/server/rpc/readBodyWithinLimit.ts +44 -0
  124. package/src/lib/server/rpc/registerVerb.ts +6 -0
  125. package/src/lib/server/rpc/runWithVerbTimeout.ts +49 -0
  126. package/src/lib/server/rpc/types/RemoteHandler.ts +27 -0
  127. package/src/lib/server/rpc/types/RemoteRoutes.ts +13 -0
  128. package/src/lib/server/rpc/types/TypedResponse.ts +18 -0
  129. package/src/lib/server/rpc/types/VerbHelper.ts +87 -0
  130. package/src/lib/server/rpc/types/VerbRegistryEntry.ts +35 -0
  131. package/src/lib/server/rpc/unprocessed.ts +14 -0
  132. package/src/lib/server/rpc/verbRegistry.ts +11 -0
  133. package/src/lib/server/runtime/DEFAULT_PORT.ts +6 -0
  134. package/src/lib/server/runtime/DEV_READY_MESSAGE.ts +6 -0
  135. package/src/lib/server/runtime/DEV_REBUILD_MESSAGE.ts +4 -0
  136. package/src/lib/server/runtime/DEV_RELOAD_CLIENT_SCRIPT.ts +107 -0
  137. package/src/lib/server/runtime/SSR_SWAP_SCRIPT.ts +16 -0
  138. package/src/lib/server/runtime/acceptsGzip.ts +24 -0
  139. package/src/lib/server/runtime/buildCacheSnapshot.ts +61 -0
  140. package/src/lib/server/runtime/buildHealthPayload.ts +34 -0
  141. package/src/lib/server/runtime/buildInspectorSurface.ts +37 -0
  142. package/src/lib/server/runtime/buildOpenApiSpec.ts +106 -0
  143. package/src/lib/server/runtime/cacheControlForAsset.ts +22 -0
  144. package/src/lib/server/runtime/containsTraversal.ts +37 -0
  145. package/src/lib/server/runtime/createAppAssetServer.ts +76 -0
  146. package/src/lib/server/runtime/createAssetHeaderCache.ts +31 -0
  147. package/src/lib/server/runtime/createPublicAssetServer.ts +67 -0
  148. package/src/lib/server/runtime/createReachable.ts +109 -0
  149. package/src/lib/server/runtime/createRouteDispatcher.ts +127 -0
  150. package/src/lib/server/runtime/createServer.ts +674 -0
  151. package/src/lib/server/runtime/createUiPageRenderer.ts +181 -0
  152. package/src/lib/server/runtime/crossOriginForbidden.ts +17 -0
  153. package/src/lib/server/runtime/crossOriginGate.ts +29 -0
  154. package/src/lib/server/runtime/devClientFingerprint.ts +117 -0
  155. package/src/lib/server/runtime/devHotModuleResponse.ts +40 -0
  156. package/src/lib/server/runtime/devReloadResponse.ts +41 -0
  157. package/src/lib/server/runtime/disableIdleTimeoutForStream.ts +27 -0
  158. package/src/lib/server/runtime/envSchemaStore.ts +15 -0
  159. package/src/lib/server/runtime/findOpenPort.ts +21 -0
  160. package/src/lib/server/runtime/getActiveServer.ts +6 -0
  161. package/src/lib/server/runtime/globToPathSet.ts +29 -0
  162. package/src/lib/server/runtime/gzipResponse.ts +46 -0
  163. package/src/lib/server/runtime/inProcessServer.ts +20 -0
  164. package/src/lib/server/runtime/internalErrorResponse.ts +25 -0
  165. package/src/lib/server/runtime/isCrossOriginRequest.ts +23 -0
  166. package/src/lib/server/runtime/listenOnOpenPort.ts +36 -0
  167. package/src/lib/server/runtime/logExposedSurfaces.ts +156 -0
  168. package/src/lib/server/runtime/maybeMountInspector.ts +97 -0
  169. package/src/lib/server/runtime/mimeForExtension.ts +14 -0
  170. package/src/lib/server/runtime/pageUrlFromStore.ts +15 -0
  171. package/src/lib/server/runtime/parseIdleTimeout.ts +10 -0
  172. package/src/lib/server/runtime/parsePort.ts +11 -0
  173. package/src/lib/server/runtime/registryManifests.ts +66 -0
  174. package/src/lib/server/runtime/requestContext.ts +5 -0
  175. package/src/lib/server/runtime/resolvePageSnapshot.ts +25 -0
  176. package/src/lib/server/runtime/respondWithEmbeddedAsset.ts +18 -0
  177. package/src/lib/server/runtime/runWithRequestScope.ts +150 -0
  178. package/src/lib/server/runtime/safeJsonForScript.ts +17 -0
  179. package/src/lib/server/runtime/serializeCacheSnapshot.ts +45 -0
  180. package/src/lib/server/runtime/serverSlot.ts +13 -0
  181. package/src/lib/server/runtime/setActiveServer.ts +6 -0
  182. package/src/lib/server/runtime/snapshotEntryFromCache.ts +83 -0
  183. package/src/lib/server/runtime/streamCacheResolutions.ts +37 -0
  184. package/src/lib/server/runtime/streamFromIterator.ts +86 -0
  185. package/src/lib/server/runtime/types/Assets.ts +6 -0
  186. package/src/lib/server/runtime/types/DevReloadStamp.ts +18 -0
  187. package/src/lib/server/runtime/types/InspectorCacheEntry.ts +24 -0
  188. package/src/lib/server/runtime/types/InspectorCacheSnapshot.ts +11 -0
  189. package/src/lib/server/runtime/types/InspectorContext.ts +30 -0
  190. package/src/lib/server/runtime/types/InspectorSocket.ts +17 -0
  191. package/src/lib/server/runtime/types/InspectorSurface.ts +13 -0
  192. package/src/lib/server/runtime/types/InspectorVerb.ts +27 -0
  193. package/src/lib/server/runtime/types/RequestStore.ts +55 -0
  194. package/src/lib/server/runtime/warnUnguardedMcp.ts +32 -0
  195. package/src/lib/server/runtime/withResponseDefaults.ts +24 -0
  196. package/src/lib/server/server.ts +33 -0
  197. package/src/lib/server/socket.ts +32 -0
  198. package/src/lib/server/sockets/createSocketDispatcher.ts +337 -0
  199. package/src/lib/server/sockets/defineSocket.ts +179 -0
  200. package/src/lib/server/sockets/lookupSocket.ts +6 -0
  201. package/src/lib/server/sockets/registerSocket.ts +6 -0
  202. package/src/lib/server/sockets/socketOperations.ts +36 -0
  203. package/src/lib/server/sockets/socketRegistry.ts +9 -0
  204. package/src/lib/server/sockets/types/Socket.ts +23 -0
  205. package/src/lib/server/sockets/types/SocketClientFrame.ts +19 -0
  206. package/src/lib/server/sockets/types/SocketOperation.ts +22 -0
  207. package/src/lib/server/sockets/types/SocketOptions.ts +26 -0
  208. package/src/lib/server/sockets/types/SocketRegistryEntry.ts +19 -0
  209. package/src/lib/server/sockets/types/SocketRoutes.ts +10 -0
  210. package/src/lib/server/sockets/types/SocketServerFrame.ts +24 -0
  211. package/src/lib/server/sse.ts +54 -0
  212. package/src/lib/shared/ABIDE_PACKAGE_NAME.ts +7 -0
  213. package/src/lib/shared/ABIDE_VERSION.ts +9 -0
  214. package/src/lib/shared/CACHE_CONTROL_VALUES.ts +16 -0
  215. package/src/lib/shared/CACHE_WRAPPED.ts +8 -0
  216. package/src/lib/shared/CLI_PATH.ts +7 -0
  217. package/src/lib/shared/DEV_HOT_PREFIX.ts +7 -0
  218. package/src/lib/shared/DEV_RELOAD_PATH.ts +6 -0
  219. package/src/lib/shared/HEALTH_PATH.ts +7 -0
  220. package/src/lib/shared/HttpError.ts +20 -0
  221. package/src/lib/shared/IDENTITY_PATH.ts +6 -0
  222. package/src/lib/shared/INSPECTOR_PATH.ts +7 -0
  223. package/src/lib/shared/NAV_HEADER.ts +8 -0
  224. package/src/lib/shared/OFFLINE_HEADER.ts +8 -0
  225. package/src/lib/shared/REMOTE_FUNCTION.ts +8 -0
  226. package/src/lib/shared/REPLAYABLE_METHODS.ts +12 -0
  227. package/src/lib/shared/SOCKETS_PATH.ts +7 -0
  228. package/src/lib/shared/STREAMING_CONTENT_TYPES.ts +11 -0
  229. package/src/lib/shared/SocketDisconnectedError.ts +13 -0
  230. package/src/lib/shared/TEXT_PLAIN.ts +7 -0
  231. package/src/lib/shared/abideImportName.ts +44 -0
  232. package/src/lib/shared/abideLog.ts +38 -0
  233. package/src/lib/shared/activeCacheStore.ts +20 -0
  234. package/src/lib/shared/activePage.ts +25 -0
  235. package/src/lib/shared/appDataDir.ts +34 -0
  236. package/src/lib/shared/appNameSlot.ts +10 -0
  237. package/src/lib/shared/basePath.ts +10 -0
  238. package/src/lib/shared/basePathFromAppUrl.ts +20 -0
  239. package/src/lib/shared/baseSlot.ts +14 -0
  240. package/src/lib/shared/binaryDirEnvPath.ts +12 -0
  241. package/src/lib/shared/browserClientFlags.ts +10 -0
  242. package/src/lib/shared/buildRpcProxy.ts +39 -0
  243. package/src/lib/shared/buildRpcRequest.ts +70 -0
  244. package/src/lib/shared/buildSocketOverChannel.ts +58 -0
  245. package/src/lib/shared/bundleLayout.ts +36 -0
  246. package/src/lib/shared/cache.ts +951 -0
  247. package/src/lib/shared/cacheEntryFromSnapshot.ts +59 -0
  248. package/src/lib/shared/cacheStoreSlot.ts +16 -0
  249. package/src/lib/shared/cacheStores.ts +10 -0
  250. package/src/lib/shared/canonicalJson.ts +63 -0
  251. package/src/lib/shared/carriesBodyArgs.ts +13 -0
  252. package/src/lib/shared/clearLastConnection.ts +7 -0
  253. package/src/lib/shared/commandNameForUrl.ts +17 -0
  254. package/src/lib/shared/createCacheStore.ts +104 -0
  255. package/src/lib/shared/createChannelLog.ts +122 -0
  256. package/src/lib/shared/createLifecycleChannel.ts +56 -0
  257. package/src/lib/shared/createLivenessWatch.ts +118 -0
  258. package/src/lib/shared/createPushIterator.ts +127 -0
  259. package/src/lib/shared/createRemoteFunction.ts +122 -0
  260. package/src/lib/shared/createSubscriber.ts +55 -0
  261. package/src/lib/shared/createTraceContext.ts +21 -0
  262. package/src/lib/shared/dataDirEnvPath.ts +12 -0
  263. package/src/lib/shared/decodeResponse.ts +47 -0
  264. package/src/lib/shared/detectTarget.ts +27 -0
  265. package/src/lib/shared/detectVerbMethod.ts +17 -0
  266. package/src/lib/shared/emitLogRecord.ts +190 -0
  267. package/src/lib/shared/exeSuffix.ts +9 -0
  268. package/src/lib/shared/exitOnBuildFailure.ts +17 -0
  269. package/src/lib/shared/extraForwardHeaders.ts +16 -0
  270. package/src/lib/shared/fileStem.ts +9 -0
  271. package/src/lib/shared/findExportCallSite.ts +476 -0
  272. package/src/lib/shared/formatTraceparent.ts +6 -0
  273. package/src/lib/shared/forwardHeaders.ts +44 -0
  274. package/src/lib/shared/getRemoteMeta.ts +5 -0
  275. package/src/lib/shared/globalCacheStore.ts +15 -0
  276. package/src/lib/shared/globalCacheStoreSlot.ts +14 -0
  277. package/src/lib/shared/health.ts +179 -0
  278. package/src/lib/shared/healthReadSlot.ts +11 -0
  279. package/src/lib/shared/healthSeedSlot.ts +12 -0
  280. package/src/lib/shared/html.ts +38 -0
  281. package/src/lib/shared/importNamesToStrip.ts +13 -0
  282. package/src/lib/shared/invalidateEvent.ts +11 -0
  283. package/src/lib/shared/invalidateTripwire.ts +40 -0
  284. package/src/lib/shared/isAbideHealthPayload.ts +11 -0
  285. package/src/lib/shared/isCompileTarget.ts +15 -0
  286. package/src/lib/shared/isDebugEnabled.ts +26 -0
  287. package/src/lib/shared/isDebugNegated.ts +19 -0
  288. package/src/lib/shared/isModuleNotFound.ts +16 -0
  289. package/src/lib/shared/isReadOnlyMethod.ts +14 -0
  290. package/src/lib/shared/isReplayableMethod.ts +7 -0
  291. package/src/lib/shared/isStreamingResponse.ts +11 -0
  292. package/src/lib/shared/isSubscribable.ts +15 -0
  293. package/src/lib/shared/jsonSchemaForPromptArguments.ts +29 -0
  294. package/src/lib/shared/jsonSchemaForSchema.ts +39 -0
  295. package/src/lib/shared/jsonlErrorFrame.ts +24 -0
  296. package/src/lib/shared/keyForRemoteCall.ts +29 -0
  297. package/src/lib/shared/keyMatchesPrefix.ts +9 -0
  298. package/src/lib/shared/lastConnectionPath.ts +7 -0
  299. package/src/lib/shared/layoutChainForRoute.ts +22 -0
  300. package/src/lib/shared/loadEnvFile.ts +17 -0
  301. package/src/lib/shared/loadEnvFromDataDir.ts +14 -0
  302. package/src/lib/shared/log.ts +24 -0
  303. package/src/lib/shared/logClosingRecord.ts +28 -0
  304. package/src/lib/shared/logTapSlot.ts +13 -0
  305. package/src/lib/shared/manifestModule.ts +39 -0
  306. package/src/lib/shared/matchesDebugPattern.ts +16 -0
  307. package/src/lib/shared/memoizeByKey.ts +32 -0
  308. package/src/lib/shared/normalizeTarget.ts +10 -0
  309. package/src/lib/shared/online.ts +51 -0
  310. package/src/lib/shared/page.ts +30 -0
  311. package/src/lib/shared/pageSlot.ts +17 -0
  312. package/src/lib/shared/pageUrlForFile.ts +14 -0
  313. package/src/lib/shared/parseBoundedEnvInt.ts +20 -0
  314. package/src/lib/shared/parseDebugPatterns.ts +21 -0
  315. package/src/lib/shared/parseEnv.ts +30 -0
  316. package/src/lib/shared/parsePromptMarkdown.ts +35 -0
  317. package/src/lib/shared/parseRouteSegments.ts +22 -0
  318. package/src/lib/shared/parseTraceparent.ts +26 -0
  319. package/src/lib/shared/pending.ts +30 -0
  320. package/src/lib/shared/prepareRpcModule.ts +59 -0
  321. package/src/lib/shared/prepareSocketModule.ts +49 -0
  322. package/src/lib/shared/probeRegistries.ts +68 -0
  323. package/src/lib/shared/producerKey.ts +32 -0
  324. package/src/lib/shared/programNameForPackage.ts +14 -0
  325. package/src/lib/shared/promptNameForFile.ts +10 -0
  326. package/src/lib/shared/queryStringFromArgs.ts +27 -0
  327. package/src/lib/shared/randomHexId.ts +14 -0
  328. package/src/lib/shared/readEnvFile.ts +15 -0
  329. package/src/lib/shared/readLastConnection.ts +18 -0
  330. package/src/lib/shared/readPackageJson.ts +9 -0
  331. package/src/lib/shared/recordRemoteMeta.ts +5 -0
  332. package/src/lib/shared/refreshing.ts +31 -0
  333. package/src/lib/shared/remoteMetaStore.ts +16 -0
  334. package/src/lib/shared/requestScopeSlot.ts +15 -0
  335. package/src/lib/shared/resolveClientFlags.ts +20 -0
  336. package/src/lib/shared/responseErrorText.ts +9 -0
  337. package/src/lib/shared/rpcTimeoutSlot.ts +9 -0
  338. package/src/lib/shared/rpcUrlForFile.ts +19 -0
  339. package/src/lib/shared/runningAsStandaloneBinary.ts +13 -0
  340. package/src/lib/shared/selectorMatcher.ts +68 -0
  341. package/src/lib/shared/selectorPrefix.ts +39 -0
  342. package/src/lib/shared/serializeEnv.ts +18 -0
  343. package/src/lib/shared/setAppName.ts +5 -0
  344. package/src/lib/shared/setBaseResolver.ts +6 -0
  345. package/src/lib/shared/setCacheStoreResolver.ts +6 -0
  346. package/src/lib/shared/setGlobalCacheStoreResolver.ts +6 -0
  347. package/src/lib/shared/setPageResolver.ts +7 -0
  348. package/src/lib/shared/setRequestScopeResolver.ts +6 -0
  349. package/src/lib/shared/snippet.ts +25 -0
  350. package/src/lib/shared/socketNameForFile.ts +11 -0
  351. package/src/lib/shared/socketTapSlot.ts +12 -0
  352. package/src/lib/shared/sseErrorFrame.ts +29 -0
  353. package/src/lib/shared/streamResponse.ts +169 -0
  354. package/src/lib/shared/stripImport.ts +27 -0
  355. package/src/lib/shared/subscribableFromResponse.ts +51 -0
  356. package/src/lib/shared/tailProbeSlot.ts +16 -0
  357. package/src/lib/shared/toBunRoutePattern.ts +28 -0
  358. package/src/lib/shared/toScopeSet.ts +4 -0
  359. package/src/lib/shared/trace.ts +16 -0
  360. package/src/lib/shared/types/CacheEntry.ts +84 -0
  361. package/src/lib/shared/types/CacheInvalidation.ts +9 -0
  362. package/src/lib/shared/types/CacheOnContext.ts +25 -0
  363. package/src/lib/shared/types/CacheOptions.ts +39 -0
  364. package/src/lib/shared/types/CacheSelector.ts +17 -0
  365. package/src/lib/shared/types/CacheSnapshot.ts +16 -0
  366. package/src/lib/shared/types/CacheSnapshotEntry.ts +17 -0
  367. package/src/lib/shared/types/CacheStats.ts +13 -0
  368. package/src/lib/shared/types/CacheStore.ts +39 -0
  369. package/src/lib/shared/types/ChannelLog.ts +13 -0
  370. package/src/lib/shared/types/ClientFlags.ts +11 -0
  371. package/src/lib/shared/types/CompileTarget.ts +6 -0
  372. package/src/lib/shared/types/FrameworkLog.ts +13 -0
  373. package/src/lib/shared/types/HttpVerb.ts +1 -0
  374. package/src/lib/shared/types/LastConnection.ts +9 -0
  375. package/src/lib/shared/types/Log.ts +13 -0
  376. package/src/lib/shared/types/LogRecord.ts +42 -0
  377. package/src/lib/shared/types/LogVoice.ts +7 -0
  378. package/src/lib/shared/types/PageSnapshot.ts +14 -0
  379. package/src/lib/shared/types/PromptArgument.ts +12 -0
  380. package/src/lib/shared/types/RawRemoteFunction.ts +14 -0
  381. package/src/lib/shared/types/RemoteCallable.ts +12 -0
  382. package/src/lib/shared/types/RemoteFunction.ts +47 -0
  383. package/src/lib/shared/types/ReplayableMethod.ts +7 -0
  384. package/src/lib/shared/types/RequestScopeInfo.ts +16 -0
  385. package/src/lib/shared/types/RpcInvoker.ts +6 -0
  386. package/src/lib/shared/types/SocketChannel.ts +17 -0
  387. package/src/lib/shared/types/SocketSubCallbacks.ts +13 -0
  388. package/src/lib/shared/types/StandardSchemaV1.ts +56 -0
  389. package/src/lib/shared/types/StreamedResolution.ts +10 -0
  390. package/src/lib/shared/types/Subscribable.ts +26 -0
  391. package/src/lib/shared/types/TailHooks.ts +12 -0
  392. package/src/lib/shared/types/TailOptions.ts +10 -0
  393. package/src/lib/shared/types/TraceContext.ts +17 -0
  394. package/src/lib/shared/url.ts +118 -0
  395. package/src/lib/shared/withBase.ts +11 -0
  396. package/src/lib/shared/withBaseUrl.ts +17 -0
  397. package/src/lib/shared/withJsonSchema.ts +21 -0
  398. package/src/lib/shared/writeDts.ts +12 -0
  399. package/src/lib/shared/writeHealthDts.ts +36 -0
  400. package/src/lib/shared/writeLastConnection.ts +13 -0
  401. package/src/lib/shared/writePublicAssetsDts.ts +31 -0
  402. package/src/lib/shared/writeRoutesDts.ts +73 -0
  403. package/src/lib/shared/writeRpcDts.ts +49 -0
  404. package/src/lib/shared/writeTestRpcDts.ts +45 -0
  405. package/src/lib/shared/writeTestSocketsDts.ts +34 -0
  406. package/src/lib/test/assertAgentFrameConformance.ts +73 -0
  407. package/src/lib/test/createScriptedSurface.ts +45 -0
  408. package/src/lib/test/createTestApp.ts +203 -0
  409. package/src/lib/test/createTestSocketChannel.ts +142 -0
  410. package/src/lib/ui/README.md +86 -0
  411. package/src/lib/ui/compile/SSR_ESCAPE.ts +25 -0
  412. package/src/lib/ui/compile/UI_RUNTIME_IMPORTS.ts +36 -0
  413. package/src/lib/ui/compile/VOID_TAGS.ts +21 -0
  414. package/src/lib/ui/compile/abideUiPlugin.ts +65 -0
  415. package/src/lib/ui/compile/analyzeComponent.ts +117 -0
  416. package/src/lib/ui/compile/assetModulesFile.ts +32 -0
  417. package/src/lib/ui/compile/branchElements.ts +50 -0
  418. package/src/lib/ui/compile/collectAbideDiagnostics.ts +59 -0
  419. package/src/lib/ui/compile/compileComponent.ts +20 -0
  420. package/src/lib/ui/compile/compileModule.ts +116 -0
  421. package/src/lib/ui/compile/compileSSR.ts +36 -0
  422. package/src/lib/ui/compile/compileShadow.ts +352 -0
  423. package/src/lib/ui/compile/createShadowLanguageService.ts +197 -0
  424. package/src/lib/ui/compile/createShadowProgram.ts +96 -0
  425. package/src/lib/ui/compile/decodeHtmlEntities.ts +49 -0
  426. package/src/lib/ui/compile/desugarSignals.ts +133 -0
  427. package/src/lib/ui/compile/escapeHtml.ts +15 -0
  428. package/src/lib/ui/compile/generateBuild.ts +638 -0
  429. package/src/lib/ui/compile/generateSSR.ts +380 -0
  430. package/src/lib/ui/compile/groupBindParts.ts +28 -0
  431. package/src/lib/ui/compile/hoistCells.ts +120 -0
  432. package/src/lib/ui/compile/loadShadowTsConfig.ts +31 -0
  433. package/src/lib/ui/compile/lowerDocAccess.ts +202 -0
  434. package/src/lib/ui/compile/nearestProjectRoot.ts +16 -0
  435. package/src/lib/ui/compile/parseTemplate.ts +396 -0
  436. package/src/lib/ui/compile/partitionSlots.ts +36 -0
  437. package/src/lib/ui/compile/prepareNestedScript.ts +42 -0
  438. package/src/lib/ui/compile/remapShadowDiagnostic.ts +30 -0
  439. package/src/lib/ui/compile/renameSignalRefs.ts +85 -0
  440. package/src/lib/ui/compile/resolveAbideImports.ts +29 -0
  441. package/src/lib/ui/compile/scopeCss.ts +115 -0
  442. package/src/lib/ui/compile/shadowNaming.ts +11 -0
  443. package/src/lib/ui/compile/sourceToShadowOffset.ts +24 -0
  444. package/src/lib/ui/compile/staticAttrValue.ts +13 -0
  445. package/src/lib/ui/compile/stripEffects.ts +32 -0
  446. package/src/lib/ui/compile/types/AbideDiagnostic.ts +14 -0
  447. package/src/lib/ui/compile/types/AnalyzedComponent.ts +25 -0
  448. package/src/lib/ui/compile/types/CompiledShadow.ts +15 -0
  449. package/src/lib/ui/compile/types/TemplateAttr.ts +16 -0
  450. package/src/lib/ui/compile/types/TemplateNode.ts +78 -0
  451. package/src/lib/ui/compile/types/TextPart.ts +8 -0
  452. package/src/lib/ui/derived.ts +28 -0
  453. package/src/lib/ui/doc.ts +15 -0
  454. package/src/lib/ui/dom/appendSnippet.ts +34 -0
  455. package/src/lib/ui/dom/appendStatic.ts +27 -0
  456. package/src/lib/ui/dom/appendText.ts +114 -0
  457. package/src/lib/ui/dom/applyResolved.ts +72 -0
  458. package/src/lib/ui/dom/attach.ts +20 -0
  459. package/src/lib/ui/dom/attr.ts +19 -0
  460. package/src/lib/ui/dom/awaitBlock.ts +224 -0
  461. package/src/lib/ui/dom/cloneStatic.ts +52 -0
  462. package/src/lib/ui/dom/each.ts +115 -0
  463. package/src/lib/ui/dom/eachAsync.ts +153 -0
  464. package/src/lib/ui/dom/hydrate.ts +35 -0
  465. package/src/lib/ui/dom/mount.ts +29 -0
  466. package/src/lib/ui/dom/mountChild.ts +33 -0
  467. package/src/lib/ui/dom/on.ts +15 -0
  468. package/src/lib/ui/dom/openChild.ts +22 -0
  469. package/src/lib/ui/dom/openRoot.ts +20 -0
  470. package/src/lib/ui/dom/switchBlock.ts +75 -0
  471. package/src/lib/ui/dom/text.ts +20 -0
  472. package/src/lib/ui/dom/tryBlock.ts +112 -0
  473. package/src/lib/ui/dom/types/EachRow.ts +3 -0
  474. package/src/lib/ui/dom/types/SwitchCase.ts +6 -0
  475. package/src/lib/ui/dom/when.ts +73 -0
  476. package/src/lib/ui/effect.ts +16 -0
  477. package/src/lib/ui/installHotBridge.ts +73 -0
  478. package/src/lib/ui/matchRoute.ts +89 -0
  479. package/src/lib/ui/navigate.ts +17 -0
  480. package/src/lib/ui/probeNavigation.ts +33 -0
  481. package/src/lib/ui/remoteProxy.ts +97 -0
  482. package/src/lib/ui/renderChain.ts +50 -0
  483. package/src/lib/ui/renderToStream.ts +104 -0
  484. package/src/lib/ui/router.ts +286 -0
  485. package/src/lib/ui/runtime/OUTLET_TAG.ts +8 -0
  486. package/src/lib/ui/runtime/OWNER.ts +8 -0
  487. package/src/lib/ui/runtime/REACTIVE_CONTEXT.ts +14 -0
  488. package/src/lib/ui/runtime/RENDER.ts +23 -0
  489. package/src/lib/ui/runtime/RESUME.ts +16 -0
  490. package/src/lib/ui/runtime/applyPatchToTree.ts +41 -0
  491. package/src/lib/ui/runtime/claimChild.ts +10 -0
  492. package/src/lib/ui/runtime/clientPage.ts +16 -0
  493. package/src/lib/ui/runtime/createComputedNode.ts +16 -0
  494. package/src/lib/ui/runtime/createDoc.ts +177 -0
  495. package/src/lib/ui/runtime/createEffectNode.ts +58 -0
  496. package/src/lib/ui/runtime/createSignalNode.ts +16 -0
  497. package/src/lib/ui/runtime/detachLink.ts +21 -0
  498. package/src/lib/ui/runtime/endTracking.ts +24 -0
  499. package/src/lib/ui/runtime/enterRenderPass.ts +12 -0
  500. package/src/lib/ui/runtime/exitRenderPass.ts +7 -0
  501. package/src/lib/ui/runtime/firstOutlet.ts +22 -0
  502. package/src/lib/ui/runtime/flushEffects.ts +17 -0
  503. package/src/lib/ui/runtime/hotInstances.ts +10 -0
  504. package/src/lib/ui/runtime/hotReloadEnabled.ts +8 -0
  505. package/src/lib/ui/runtime/hotReplace.ts +25 -0
  506. package/src/lib/ui/runtime/nextBlockId.ts +11 -0
  507. package/src/lib/ui/runtime/pathExists.ts +23 -0
  508. package/src/lib/ui/runtime/readNode.ts +17 -0
  509. package/src/lib/ui/runtime/registerHotInstance.ts +23 -0
  510. package/src/lib/ui/runtime/runNode.ts +28 -0
  511. package/src/lib/ui/runtime/runtimePath.ts +9 -0
  512. package/src/lib/ui/runtime/scope.ts +24 -0
  513. package/src/lib/ui/runtime/toTeardown.ts +26 -0
  514. package/src/lib/ui/runtime/track.ts +58 -0
  515. package/src/lib/ui/runtime/trigger.ts +44 -0
  516. package/src/lib/ui/runtime/types/Cell.ts +5 -0
  517. package/src/lib/ui/runtime/types/Derived.ts +3 -0
  518. package/src/lib/ui/runtime/types/Doc.ts +19 -0
  519. package/src/lib/ui/runtime/types/EffectResult.ts +10 -0
  520. package/src/lib/ui/runtime/types/HotInstance.ts +14 -0
  521. package/src/lib/ui/runtime/types/NavVerdict.ts +9 -0
  522. package/src/lib/ui/runtime/types/Patch.ts +11 -0
  523. package/src/lib/ui/runtime/types/ReactiveLink.ts +21 -0
  524. package/src/lib/ui/runtime/types/ReactiveNode.ts +25 -0
  525. package/src/lib/ui/runtime/types/Route.ts +8 -0
  526. package/src/lib/ui/runtime/types/RouteLoader.ts +7 -0
  527. package/src/lib/ui/runtime/types/SsrRender.ts +22 -0
  528. package/src/lib/ui/runtime/types/State.ts +3 -0
  529. package/src/lib/ui/runtime/types/Teardown.ts +5 -0
  530. package/src/lib/ui/runtime/types/UiComponent.ts +16 -0
  531. package/src/lib/ui/runtime/types/UiProps.ts +15 -0
  532. package/src/lib/ui/runtime/unlinkDeps.ts +20 -0
  533. package/src/lib/ui/runtime/untrack.ts +20 -0
  534. package/src/lib/ui/runtime/valueAtPath.ts +18 -0
  535. package/src/lib/ui/runtime/writeNode.ts +16 -0
  536. package/src/lib/ui/socketChannel.ts +227 -0
  537. package/src/lib/ui/socketProxy.ts +25 -0
  538. package/src/lib/ui/startClient.ts +58 -0
  539. package/src/lib/ui/state.ts +25 -0
  540. package/src/lib/ui/tail.ts +324 -0
  541. package/src/lib/ui/types/Layouts.ts +9 -0
  542. package/src/lib/ui/types/Pages.ts +8 -0
  543. package/src/preload.ts +19 -0
  544. package/src/scaffold.ts +153 -0
  545. package/src/serverBuildPlugins.ts +19 -0
  546. package/src/serverEntry.ts +95 -0
  547. package/template/bunfig.toml +4 -0
  548. package/template/package.json +18 -0
  549. package/template/src/app.ts +28 -0
  550. package/template/src/bundle/icon.png +0 -0
  551. package/template/src/cli/banner.txt +3 -0
  552. package/template/src/cli/footer.txt +1 -0
  553. package/template/src/server/config.ts +17 -0
  554. package/template/src/server/rpc/getHello.ts +36 -0
  555. package/template/src/ui/Layout.abide +19 -0
  556. package/template/src/ui/app.css +21 -0
  557. package/template/src/ui/app.html +24 -0
  558. package/template/src/ui/pages/about/page.abide +9 -0
  559. package/template/src/ui/pages/page.abide +22 -0
  560. package/template/test/app.test.ts +30 -0
  561. package/template/tsconfig.json +18 -0
  562. package/tsconfig.app.json +17 -0
@@ -0,0 +1,638 @@
1
+ import { OUTLET_TAG } from '../runtime/OUTLET_TAG.ts'
2
+ import { branchElements } from './branchElements.ts'
3
+ import { escapeHtml } from './escapeHtml.ts'
4
+ import { groupBindParts } from './groupBindParts.ts'
5
+ import { lowerDocAccess } from './lowerDocAccess.ts'
6
+ import { partitionSlots } from './partitionSlots.ts'
7
+ import { nestedBindingNames } from './prepareNestedScript.ts'
8
+ import { renameSignalRefs } from './renameSignalRefs.ts'
9
+ import { staticAttrValue } from './staticAttrValue.ts'
10
+ import type { TemplateNode } from './types/TemplateNode.ts'
11
+ import { VOID_TAGS } from './VOID_TAGS.ts'
12
+
13
+ /*
14
+ Generates the build statements for a parsed template: element creation, static
15
+ attributes, reactive `attr`/`text` bindings, `on` listeners, keyed `each`, and
16
+ conditional `when`. Every embedded expression is first rewritten from the signal
17
+ surface (`count` → `model.count`) and then lowered to the doc patch/read API
18
+ (cell-hoisting runs over the whole result afterwards). The output operates on
19
+ `hostVar` and expects the dom bindings, `doc`, `effect`, and the component's
20
+ `model` in scope — the body the component compiler wraps and hoists cells into.
21
+ */
22
+ export function generateBuild(
23
+ nodes: TemplateNode[],
24
+ hostVar: string,
25
+ stateNames: ReadonlySet<string>,
26
+ derivedNames: ReadonlySet<string>,
27
+ isLayout = false,
28
+ ): string {
29
+ let counter = 0
30
+ const nextVar = (prefix: string): string => `${prefix}${counter++}`
31
+
32
+ /* Branch-scoped signal bindings (from nested `<script>`s) — they deref to
33
+ `.value` like a `derived`. Pushed while a branch's script + markup compile,
34
+ popped after, so they shadow only within that subtree. */
35
+ const localDerived = new Set<string>()
36
+ const derefScope = (): ReadonlySet<string> =>
37
+ localDerived.size === 0 ? derivedNames : new Set([...derivedNames, ...localDerived])
38
+
39
+ /* Rewrites signal refs, then lowers a single expression (no trailing `;`). */
40
+ function lowerExpression(code: string): string {
41
+ const renamed = renameSignalRefs(code, stateNames, derefScope())
42
+ return lowerDocAccess(renamed, 'model').trim().replace(/;$/, '')
43
+ }
44
+
45
+ /* As above but keeps the trailing `;` for a handler body. */
46
+ function lowerStatement(code: string): string {
47
+ const renamed = renameSignalRefs(code, stateNames, derefScope())
48
+ return lowerDocAccess(renamed, 'model').trim()
49
+ }
50
+
51
+ /* Builds an element and its children; returns the build code and its var.
52
+ `varExpr` is how the element is obtained — `openChild(parent, tag)` for a
53
+ child (create-or-claim), or `document.createElement(tag)` for a returned
54
+ root (rows/branches, which are create-only). */
55
+ function generateElement(
56
+ node: Extract<TemplateNode, { kind: 'element' }>,
57
+ varExpr: string,
58
+ ): { code: string; varName: string } {
59
+ const varName = nextVar('el')
60
+ let code = `const ${varName} = ${varExpr};\n`
61
+ /* Stamp the scope attribute of every `<style>` active at this element (its own
62
+ sibling list plus every ancestor's), so the bundled CSS matches it. */
63
+ for (const scope of node.scopes ?? []) {
64
+ code += `${varName}.setAttribute(${JSON.stringify(scope)}, "");\n`
65
+ }
66
+ for (const attr of node.attrs) {
67
+ if (attr.kind === 'static') {
68
+ code += `${varName}.setAttribute(${JSON.stringify(attr.name)}, ${JSON.stringify(attr.value)});\n`
69
+ } else if (attr.kind === 'expression') {
70
+ code += `attr(${varName}, ${JSON.stringify(attr.name)}, () => (${lowerExpression(attr.code)}));\n`
71
+ } else if (attr.kind === 'event') {
72
+ code += `on(${varName}, ${JSON.stringify(attr.event)}, (${lowerExpression(attr.code)}));\n`
73
+ } else if (attr.kind === 'attach') {
74
+ code += `attach(${varName}, (${lowerExpression(attr.code)}));\n`
75
+ } else if (attr.kind === 'bind' && attr.property === 'group') {
76
+ /* Grouped two-way: radio binds the path to the single checked
77
+ `value`; checkbox treats the path as an array, adding/removing
78
+ `value` on toggle. Membership reads the array via the lowered
79
+ path and calls native `.includes`/`.indexOf` (the doc API has no
80
+ array search); mutations go through `push`/`delete`, which lower
81
+ to `add`/`remove` patches that the doc reindexes. */
82
+ const { valueCode, isRadio } = groupBindParts(node)
83
+ const value = lowerExpression(valueCode)
84
+ if (isRadio) {
85
+ code += `effect(() => { ${varName}.checked = (${lowerExpression(attr.code)}) === (${value}); });\n`
86
+ code += `on(${varName}, "change", () => { if (${varName}.checked) { ${lowerStatement(`${attr.code} = ${valueCode}`)} } });\n`
87
+ } else {
88
+ code += `effect(() => { ${varName}.checked = (${lowerExpression(attr.code)}).includes(${value}); });\n`
89
+ code += `on(${varName}, "change", () => { const $groupValue = ${value}; if (${varName}.checked) { if (!(${lowerExpression(attr.code)}).includes($groupValue)) { ${lowerStatement(`${attr.code}.push($groupValue)`)} } } else { const $groupIndex = (${lowerExpression(attr.code)}).indexOf($groupValue); if ($groupIndex !== -1) { ${lowerStatement(`delete ${attr.code}[$groupIndex]`)} } } });\n`
90
+ }
91
+ } else {
92
+ /* Two-way: drive the property from the path, and write the path
93
+ back on input. The path is an lvalue, so the write is lowered
94
+ as an assignment statement. */
95
+ code += `effect(() => { ${varName}.${attr.property} = ${lowerExpression(attr.code)}; });\n`
96
+ code += `on(${varName}, "input", () => { ${lowerStatement(`${attr.code} = ${varName}.${attr.property}`)} });\n`
97
+ }
98
+ }
99
+ /* A `<script>` among the children scopes its bindings to this element's
100
+ subtree (its later siblings auto-deref them); pop after. */
101
+ const added = scopeNestedScripts(node.children)
102
+ code += generateChildren(node.children, varName)
103
+ for (const name of added) {
104
+ localDerived.delete(name)
105
+ }
106
+ return { code, varName }
107
+ }
108
+
109
+ /* Adds the binding names of any `<script>` children to the deref scope, returning
110
+ the names it added (for the caller to pop). */
111
+ function scopeNestedScripts(children: TemplateNode[]): string[] {
112
+ const added: string[] = []
113
+ for (const child of children) {
114
+ if (child.kind === 'script') {
115
+ for (const name of nestedBindingNames(child.code)) {
116
+ if (!localDerived.has(name)) {
117
+ localDerived.add(name)
118
+ added.push(name)
119
+ }
120
+ }
121
+ }
122
+ }
123
+ return added
124
+ }
125
+
126
+ /* Emits code appending `node` to `parentVar`. */
127
+ function generateChild(node: TemplateNode, parentVar: string): string {
128
+ if (node.kind === 'script') {
129
+ return `${lowerStatement(node.code)}\n`
130
+ }
131
+ /* A `<style>` emits no DOM — its CSS is bundled and its scope attribute is
132
+ already stamped onto the elements it covers (see `generateElement`). */
133
+ if (node.kind === 'style') {
134
+ return ''
135
+ }
136
+ if (node.kind === 'text') {
137
+ /* The non-whitespace parts share one merged SSR text node, so on hydrate
138
+ each must split off its own portion. Every consumer but the last passes
139
+ `splitAlways` so it leaves a node behind even on an exact-length consume
140
+ (e.g. an interpolation that renders empty) — the last keeps the cheaper
141
+ split-only-when-shorter path. */
142
+ const consumers = node.parts.filter(
143
+ (part) => part.kind !== 'static' || part.value.trim() !== '',
144
+ )
145
+ return consumers
146
+ .map((part, index) => {
147
+ const splitAlways = index < consumers.length - 1 ? ', true' : ''
148
+ return part.kind === 'static'
149
+ ? `appendStatic(${parentVar}, ${JSON.stringify(part.value)}${splitAlways});\n`
150
+ : `appendText(${parentVar}, () => (${lowerExpression(part.code)})${splitAlways});\n`
151
+ })
152
+ .join('')
153
+ }
154
+ if (node.kind === 'element' && node.tag === 'slot') {
155
+ /* In a layout, the unnamed `<slot/>` is the router's page outlet: a bare
156
+ structural element the router mounts the next chain layer into. Created
157
+ empty (no scope attr, no children) so it matches the SSR placeholder. */
158
+ if (isLayout && staticAttrValue(node, 'name') === undefined) {
159
+ return `openChild(${parentVar}, ${JSON.stringify(OUTLET_TAG)});\n`
160
+ }
161
+ return generateSlot(node, parentVar)
162
+ }
163
+ if (node.kind === 'element') {
164
+ /* openChild appends (create) or claims (hydrate) — no separate append. */
165
+ return generateElement(node, `openChild(${parentVar}, ${JSON.stringify(node.tag)})`)
166
+ .code
167
+ }
168
+ if (node.kind === 'if') {
169
+ return generateIf(node, parentVar)
170
+ }
171
+ if (node.kind === 'await') {
172
+ return generateAwait(node, parentVar)
173
+ }
174
+ if (node.kind === 'try') {
175
+ return generateTry(node, parentVar)
176
+ }
177
+ if (node.kind === 'branch') {
178
+ return '' // branches are consumed by their await block, never standalone
179
+ }
180
+ if (node.kind === 'component') {
181
+ return generateComponent(node, parentVar)
182
+ }
183
+ if (node.kind === 'switch') {
184
+ return generateSwitch(node, parentVar)
185
+ }
186
+ if (node.kind === 'case') {
187
+ return '' // cases are consumed by their switch/if, never standalone
188
+ }
189
+ if (node.kind === 'snippet') {
190
+ return generateSnippet(node)
191
+ }
192
+ return generateEach(node, parentVar)
193
+ }
194
+
195
+ /* Builds a sibling list, coalescing maximal runs of fully-static element subtrees
196
+ into one `cloneStatic` clone (a single cloneNode in place of the N create/append
197
+ calls the imperative path would emit). Whitespace-only text is transparent — it
198
+ neither breaks a run nor adds markup, matching both back-ends dropping it. Every
199
+ other child flushes the pending run and builds imperatively, preserving order. */
200
+ function generateChildren(children: TemplateNode[], parentVar: string): string {
201
+ let code = ''
202
+ let runHtml = ''
203
+ const flush = (): void => {
204
+ if (runHtml !== '') {
205
+ code += `cloneStatic(${parentVar}, ${JSON.stringify(runHtml)});\n`
206
+ runHtml = ''
207
+ }
208
+ }
209
+ for (const child of children) {
210
+ if (isStaticCloneableElement(child)) {
211
+ runHtml += staticHtml(child)
212
+ } else if (!isWhitespaceText(child)) {
213
+ flush()
214
+ code += generateChild(child, parentVar)
215
+ }
216
+ }
217
+ flush()
218
+ return code
219
+ }
220
+
221
+ /* A snippet declaration: a hoisted function returning a `snippet`-branded builder
222
+ that appends its body into the host it is mounted on. The function closes over
223
+ the component scope (its `model`/cells); `args` are plain parameters bound by
224
+ the call. Appends nothing at the declaration site — `{name(args)}` mounts it. */
225
+ function generateSnippet(node: Extract<TemplateNode, { kind: 'snippet' }>): string {
226
+ const body = node.children.map((child) => generateChild(child, '$host')).join('')
227
+ return `function ${node.name}(${node.params ?? ''}) {\nreturn snippet(($host) => {\n${body}});\n}\n`
228
+ }
229
+
230
+ /* A switch: each `case` is `{ match: () => value, render }`, the default is
231
+ `{ match: undefined, render }`. */
232
+ function generateSwitch(
233
+ node: Extract<TemplateNode, { kind: 'switch' }>,
234
+ parentVar: string,
235
+ ): string {
236
+ const cases = node.children
237
+ .filter(
238
+ (child): child is Extract<TemplateNode, { kind: 'case' }> => child.kind === 'case',
239
+ )
240
+ .map((branch) => {
241
+ const param = nextVar('p')
242
+ const roots = elementRoots(branch.children, '<template case>', param)
243
+ const match =
244
+ branch.match === undefined
245
+ ? 'undefined'
246
+ : `() => (${lowerExpression(branch.match)})`
247
+ return `{ match: ${match}, render: (${param}) => {\n${roots.code}return ${roots.expr};\n} }`
248
+ })
249
+ .join(', ')
250
+ return `switchBlock(${parentVar}, () => (${lowerExpression(node.subject)}), [${cases}]);\n`
251
+ }
252
+
253
+ /* A `<slot>` outlet: render the parent-provided content for this slot (default
254
+ via `$children`, named via `$slots[name]`), falling back to the slot's own
255
+ children when the parent supplied none. */
256
+ function generateSlot(
257
+ node: Extract<TemplateNode, { kind: 'element' }>,
258
+ parentVar: string,
259
+ ): string {
260
+ const name = staticAttrValue(node, 'name')
261
+ const guard =
262
+ name === undefined
263
+ ? '$props && $props.$children'
264
+ : `$props && $props.$slots && $props.$slots[${JSON.stringify(name)}]`
265
+ const invoke =
266
+ name === undefined
267
+ ? `$props.$children(${parentVar})`
268
+ : `$props.$slots[${JSON.stringify(name)}](${parentVar})`
269
+ const fallback = node.children.map((child) => generateChild(child, parentVar)).join('')
270
+ if (fallback.trim() === '') {
271
+ return `if (${guard}) { ${invoke}; }\n`
272
+ }
273
+ return `if (${guard}) { ${invoke}; } else {\n${fallback}}\n`
274
+ }
275
+
276
+ /* Mounts a child component into a wrapper element, passing each prop as a
277
+ reactive thunk so the child re-reads when the parent expression changes. */
278
+ function generateComponent(
279
+ node: Extract<TemplateNode, { kind: 'component' }>,
280
+ parentVar: string,
281
+ ): string {
282
+ const wrapper = nextVar('cmp')
283
+ const parts = node.props.map(
284
+ (prop) => `${JSON.stringify(prop.name)}: () => (${lowerExpression(prop.code)})`,
285
+ )
286
+ /* Slot content compiles to builders the child mounts into the host it passes
287
+ from each <slot> position: the default markup as `$children`, and each
288
+ `slot="name"` group as `$slots[name]`. */
289
+ const groups = partitionSlots(node.children)
290
+ const slotCode = groups.default.map((child) => generateChild(child, '$slot')).join('')
291
+ if (slotCode.trim() !== '') {
292
+ parts.push(`"$children": ($slot) => {\n${slotCode}}`)
293
+ }
294
+ if (groups.named.length > 0) {
295
+ const entries = groups.named
296
+ .map((group) => {
297
+ const code = group.nodes.map((child) => generateChild(child, '$slot')).join('')
298
+ return `${JSON.stringify(group.name)}: ($slot) => {\n${code}}`
299
+ })
300
+ .join(', ')
301
+ parts.push(`"$slots": { ${entries} }`)
302
+ }
303
+ /* openChild appends (create) or claims the SSR wrapper (hydrate); since
304
+ hydration is still active, the child's own build then adopts its server
305
+ markup inside the wrapper. */
306
+ return (
307
+ `const ${wrapper} = openChild(${parentVar}, ${JSON.stringify(node.name.toLowerCase())});\n` +
308
+ `mountChild(${wrapper}, ${node.name}, { ${parts.join(', ')} });\n`
309
+ )
310
+ }
311
+
312
+ /* An await block: pending → resolved(value) / error branches. Each branch is a
313
+ single-element root; a render thunk returns its node. */
314
+ function generateAwait(
315
+ node: Extract<TemplateNode, { kind: 'await' }>,
316
+ parentVar: string,
317
+ ): string {
318
+ const isBranch = (which: 'then' | 'catch' | 'finally') => (child: TemplateNode) =>
319
+ child.kind === 'branch' && child.branch === which
320
+ const catchBranch = node.children.find(isBranch('catch'))
321
+ const finallyChildren = branchChildren(node.children.find(isBranch('finally')))
322
+ /* Blocking: no pending, the children are the resolved branch bound to `node.as`.
323
+ Streaming: pending is the non-branch children, resolved is the `then` child. */
324
+ const pending = node.blocking
325
+ ? []
326
+ : node.children.filter((child) => child.kind !== 'branch')
327
+ const thenThunk = node.blocking
328
+ ? renderRangeThunk(
329
+ node.children.filter((child) => child.kind !== 'branch'),
330
+ node.as ?? '_value',
331
+ '<template await then>',
332
+ finallyChildren,
333
+ )
334
+ : renderSettledThunk(
335
+ node.children.find(isBranch('then')),
336
+ '_value',
337
+ '<template then>',
338
+ finallyChildren,
339
+ )
340
+ /* Neither catch nor finally → pass `undefined` so awaitBlock re-throws the
341
+ rejection (surfacing it) instead of rendering an empty branch. A finally-only
342
+ block keeps a catch thunk that renders just finally. */
343
+ const catchThunk =
344
+ catchBranch === undefined && finallyChildren.length === 0
345
+ ? 'undefined'
346
+ : renderSettledThunk(catchBranch, '_error', '<template catch>', finallyChildren)
347
+ return (
348
+ `awaitBlock(${parentVar}, nextBlockId(), () => (${lowerExpression(node.promise)}), ` +
349
+ `${renderThunk(pending, undefined, '<template await> pending')}, ` +
350
+ `${thenThunk}, ` +
351
+ `${catchThunk});\n`
352
+ )
353
+ }
354
+
355
+ /* Children of a branch node (then/catch), or [] when the branch is absent. */
356
+ function branchChildren(branch: TemplateNode | undefined): TemplateNode[] {
357
+ return branch !== undefined && branch.kind === 'branch' ? branch.children : []
358
+ }
359
+
360
+ /* The value/error variable name a branch binds, if any. */
361
+ function branchVar(branch: TemplateNode | undefined): string | undefined {
362
+ return branch !== undefined && branch.kind === 'branch' ? branch.as : undefined
363
+ }
364
+
365
+ /* Builds the element roots of a branch into `parentVar` (each via openRoot, so
366
+ detached on create / claimed on hydrate), returning the code plus an array
367
+ expression of the root nodes the block tracks as a range. */
368
+ function elementRoots(
369
+ children: TemplateNode[],
370
+ context: string,
371
+ parentVar: string,
372
+ allowEmpty = false,
373
+ ): { code: string; expr: string } {
374
+ /* Nested `<script>`s: add their bindings to the deref scope (so the script
375
+ body + this branch's markup auto-deref them), emit the lowered script
376
+ bodies first, then build the element roots — all within the scope, which
377
+ we pop afterward. The scripts run when the branch mounts, owned by its
378
+ scope. */
379
+ const added: string[] = []
380
+ for (const child of children) {
381
+ if (child.kind === 'script') {
382
+ for (const name of nestedBindingNames(child.code)) {
383
+ if (!localDerived.has(name)) {
384
+ localDerived.add(name)
385
+ added.push(name)
386
+ }
387
+ }
388
+ }
389
+ }
390
+ const scriptCode = children
391
+ .filter(
392
+ (child): child is Extract<TemplateNode, { kind: 'script' }> =>
393
+ child.kind === 'script',
394
+ )
395
+ .map((child) => `${lowerStatement(child.code)}\n`)
396
+ .join('')
397
+ const built = branchElements(children, context, allowEmpty).map((element) =>
398
+ generateElement(element, `openRoot(${parentVar}, ${JSON.stringify(element.tag)})`),
399
+ )
400
+ for (const name of added) {
401
+ localDerived.delete(name)
402
+ }
403
+ return {
404
+ code: scriptCode + built.map((part) => part.code).join(''),
405
+ expr: `[${built.map((part) => part.varName).join(', ')}]`,
406
+ }
407
+ }
408
+
409
+ /* A `(parent[, value]) => Node[]` thunk over a branch's element roots, or
410
+ `undefined` when empty (a `<template await>` with no pending branch).
411
+ `paramName`/`fallback` name the resolved/error value the branch binds. */
412
+ function renderThunk(
413
+ children: TemplateNode[],
414
+ paramName: string | undefined,
415
+ context: string,
416
+ fallback?: string,
417
+ ): string {
418
+ const hasElement = children.some((child) => child.kind === 'element')
419
+ const parentParam = nextVar('p')
420
+ if (!hasElement) {
421
+ const value = fallback === undefined ? '' : `, ${paramName ?? fallback}`
422
+ return fallback === undefined ? 'undefined' : `(${parentParam}${value}) => []`
423
+ }
424
+ const roots = elementRoots(children, context, parentParam)
425
+ const value = fallback === undefined ? '' : `, ${paramName ?? fallback}`
426
+ return `(${parentParam}${value}) => {\n${roots.code}return ${roots.expr};\n}`
427
+ }
428
+
429
+ /* A thunk over a node range: `children`'s roots concatenated with the `finally`
430
+ roots, both possibly empty. `param` names a bound value (the resolved/error
431
+ value, or the caught error); undefined for a value-less branch (try/pending). */
432
+ function renderRangeThunk(
433
+ children: TemplateNode[],
434
+ param: string | undefined,
435
+ context: string,
436
+ finallyChildren: TemplateNode[],
437
+ ): string {
438
+ const parentParam = nextVar('p')
439
+ const head = param === undefined ? `(${parentParam})` : `(${parentParam}, ${param})`
440
+ const roots = elementRoots(children, context, parentParam, true)
441
+ const finallyRoots = elementRoots(finallyChildren, '<template finally>', parentParam, true)
442
+ return `${head} => {\n${roots.code}${finallyRoots.code}return [...${roots.expr}, ...${finallyRoots.expr}];\n}`
443
+ }
444
+
445
+ /* A settled (then/catch) thunk: the outcome branch's roots ++ `finally`. */
446
+ function renderSettledThunk(
447
+ branch: TemplateNode | undefined,
448
+ fallback: string,
449
+ context: string,
450
+ finallyChildren: TemplateNode[],
451
+ ): string {
452
+ return renderRangeThunk(
453
+ branchChildren(branch),
454
+ branchVar(branch) ?? fallback,
455
+ context,
456
+ finallyChildren,
457
+ )
458
+ }
459
+
460
+ /* The branch child of a control block matching `which` (then/catch/finally). */
461
+ function findBranch(
462
+ children: TemplateNode[],
463
+ which: 'then' | 'catch' | 'finally',
464
+ ): Extract<TemplateNode, { kind: 'branch' }> | undefined {
465
+ return children.find(
466
+ (child): child is Extract<TemplateNode, { kind: 'branch' }> =>
467
+ child.kind === 'branch' && child.branch === which,
468
+ )
469
+ }
470
+
471
+ /* A sync error boundary: build the guarded subtree (++ finally); a throw while
472
+ building swaps to the catch branch (++ finally). No catch → `undefined`, which
473
+ makes the runtime re-throw to the nearest enclosing boundary. */
474
+ function generateTry(node: Extract<TemplateNode, { kind: 'try' }>, parentVar: string): string {
475
+ const catchBranch = findBranch(node.children, 'catch')
476
+ const finallyChildren = branchChildren(findBranch(node.children, 'finally'))
477
+ const guarded = node.children.filter((child) => child.kind !== 'branch')
478
+ const tryThunk = renderRangeThunk(guarded, undefined, '<template try>', finallyChildren)
479
+ const catchThunk =
480
+ catchBranch === undefined
481
+ ? 'undefined'
482
+ : renderRangeThunk(
483
+ branchChildren(catchBranch),
484
+ branchVar(catchBranch) ?? '_error',
485
+ '<template catch>',
486
+ finallyChildren,
487
+ )
488
+ return `tryBlock(${parentVar}, nextBlockId(), ${tryThunk}, ${catchThunk});\n`
489
+ }
490
+
491
+ /* A conditional with an optional nested `<template else>` (a `case` child).
492
+ Both branches are single-element roots. */
493
+ function generateIf(node: Extract<TemplateNode, { kind: 'if' }>, parentVar: string): string {
494
+ const elseBranch = node.children.find(
495
+ (child): child is Extract<TemplateNode, { kind: 'case' }> => child.kind === 'case',
496
+ )
497
+ const thenChildren = node.children.filter((child) => child.kind !== 'case')
498
+ const thenParam = nextVar('p')
499
+ const thenRoots = elementRoots(thenChildren, '<template if>', thenParam)
500
+ const thenThunk = `(${thenParam}) => {\n${thenRoots.code}return ${thenRoots.expr};\n}`
501
+ if (elseBranch === undefined) {
502
+ return `when(${parentVar}, () => (${lowerExpression(node.condition)}), ${thenThunk});\n`
503
+ }
504
+ const elseParam = nextVar('p')
505
+ const elseRoots = elementRoots(elseBranch.children, '<template else>', elseParam)
506
+ const elseThunk = `(${elseParam}) => {\n${elseRoots.code}return ${elseRoots.expr};\n}`
507
+ return `when(${parentVar}, () => (${lowerExpression(node.condition)}), ${thenThunk}, ${elseThunk});\n`
508
+ }
509
+
510
+ /* A keyed each. The row must have a single element root (it returns one node). */
511
+ function generateEach(
512
+ node: Extract<TemplateNode, { kind: 'each' }>,
513
+ parentVar: string,
514
+ ): string {
515
+ const rowParam = nextVar('p')
516
+ /* A `<script>` in the row body declares per-row local signals (seeded from
517
+ the row item), scoped to this row's render thunk. */
518
+ const added = scopeNestedScripts(node.children)
519
+ const scriptCode = node.children
520
+ .filter(
521
+ (child): child is Extract<TemplateNode, { kind: 'script' }> =>
522
+ child.kind === 'script',
523
+ )
524
+ .map((child) => `${lowerStatement(child.code)}\n`)
525
+ .join('')
526
+ const row = singleElementRoot(
527
+ node.children,
528
+ '<template each> must contain a single element row',
529
+ rowParam,
530
+ )
531
+ for (const name of added) {
532
+ localDerived.delete(name)
533
+ }
534
+ const keyExpression = node.key === undefined ? node.as : lowerExpression(node.key)
535
+ /* `await` → the AsyncIterable runtime, drained row-by-row on the client, with an
536
+ optional `<template catch>` branch rendered (after the streamed rows) when the
537
+ iterator rejects. Absent → `undefined`, so the rejection surfaces instead. */
538
+ const fn = node.async ? 'eachAsync' : 'each'
539
+ const catchBranch = node.children.find(
540
+ (child) => child.kind === 'branch' && child.branch === 'catch',
541
+ )
542
+ const catchArg = node.async
543
+ ? `, ${catchBranch === undefined ? 'undefined' : renderSettledThunk(catchBranch, '_error', '<template catch>', [])}`
544
+ : ''
545
+ return (
546
+ `${fn}(${parentVar}, () => (${lowerExpression(node.items)}), ` +
547
+ `(${node.as}) => (${keyExpression}), (${rowParam}, ${node.as}) => {\n${scriptCode}${row.code}return ${row.varName};\n}${catchArg});\n`
548
+ )
549
+ }
550
+
551
+ /* Builds the lone element child of a control-flow block (each/if return one
552
+ node), erroring if the block isn't a single element. The root is opened
553
+ with `openRoot(parentVar, tag)` so it's detached on create and claimed on
554
+ hydrate — `parentVar` is the render thunk's parent parameter. */
555
+ function singleElementRoot(
556
+ children: TemplateNode[],
557
+ message: string,
558
+ parentVar: string,
559
+ ): { code: string; varName: string } {
560
+ const root = children.find((child) => child.kind === 'element')
561
+ if (root === undefined || root.kind !== 'element') {
562
+ throw new Error(`[abide] ${message}`)
563
+ }
564
+ return generateElement(root, `openRoot(${parentVar}, ${JSON.stringify(root.tag)})`)
565
+ }
566
+
567
+ return generateChildren(nodes, hostVar)
568
+ }
569
+
570
+ /* A text node that is purely whitespace (no interpolation, only blank static
571
+ parts). Both back-ends drop it, so it neither contributes markup nor breaks a
572
+ static clone run — it stays transparent so `<a/>\n<b/>` still coalesces. */
573
+ function isWhitespaceText(node: TemplateNode): boolean {
574
+ return (
575
+ node.kind === 'text' &&
576
+ node.parts.every((part) => part.kind === 'static' && part.value.trim() === '')
577
+ )
578
+ }
579
+
580
+ /*
581
+ Whether an element subtree is fully static — no reactive/event/bind attributes,
582
+ no nested `<script>`, and every descendant likewise static (static text, static
583
+ child elements, or scope-only `<style>`). Such a subtree builds to fixed DOM with
584
+ no per-instance wiring, so it can be cloned from a template instead of built call
585
+ by call. Only ELEMENTS qualify as run members: a static element never merges with
586
+ an adjacent dynamic text node, whereas a bare static text sibling shares one
587
+ merged SSR text node with its neighbour (the `splitAlways` hazard) — those stay
588
+ imperative. Static text and elements nested INSIDE a qualifying element are fine,
589
+ enclosed by its tags.
590
+ */
591
+ function isStaticCloneableElement(node: TemplateNode): boolean {
592
+ if (node.kind !== 'element' || node.tag === 'slot') {
593
+ return false
594
+ }
595
+ if (node.attrs.some((attr) => attr.kind !== 'static')) {
596
+ return false
597
+ }
598
+ return node.children.every(
599
+ (child) =>
600
+ child.kind === 'style' ||
601
+ (child.kind === 'text' && child.parts.every((part) => part.kind === 'static')) ||
602
+ isStaticCloneableElement(child),
603
+ )
604
+ }
605
+
606
+ /*
607
+ Renders a fully-static node to its constant HTML, byte-identical to the SSR
608
+ back-end's output for the same node (same scope-attr order, same escaping, same
609
+ void-tag handling, same whitespace-only-text dropping) — so the client clone
610
+ template and the server markup parse to the same DOM. Only handles the shapes
611
+ `isStaticCloneableElement` admits.
612
+ */
613
+ function staticHtml(node: TemplateNode): string {
614
+ if (node.kind === 'text') {
615
+ return node.parts
616
+ .map((part) =>
617
+ part.kind === 'static' && part.value.trim() !== '' ? escapeHtml(part.value) : '',
618
+ )
619
+ .join('')
620
+ }
621
+ if (node.kind !== 'element') {
622
+ return '' // <style> and any non-element emit no markup
623
+ }
624
+ let html = `<${node.tag}`
625
+ for (const scope of node.scopes ?? []) {
626
+ html += ` ${scope}=""`
627
+ }
628
+ for (const attr of node.attrs) {
629
+ if (attr.kind === 'static') {
630
+ html += ` ${attr.name}="${escapeHtml(attr.value)}"`
631
+ }
632
+ }
633
+ html += '>'
634
+ if (VOID_TAGS.has(node.tag)) {
635
+ return html
636
+ }
637
+ return `${html}${node.children.map(staticHtml).join('')}</${node.tag}>`
638
+ }