@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,202 @@
1
+ import ts from 'typescript'
2
+
3
+ /*
4
+ The linchpin compiler pass. Rewrites idiomatic data access on a reactive document
5
+ binding into the document's patch/read API, so an author writes plain property
6
+ syntax and the runtime gets addressed change — the thing that makes a real
7
+ component hit the fast path instead of building path strings by hand:
8
+
9
+ model.note = 'x' → model.replace("note", 'x')
10
+ model.count += 1 → model.replace("count", model.read("count") + 1)
11
+ model.lines.push(v) → model.add("lines/-", v)
12
+ delete model.byId[key] → model.remove(`byId/${key}`)
13
+ model.lines[0].sku → model.read("lines/0/sku")
14
+ model.lines[i].sku → model.read(`lines/${i}/sku`)
15
+
16
+ A member/element-access chain rooted at `docName` becomes a `/`-joined path:
17
+ literal keys and numeric indices fold into one string literal; a non-literal
18
+ index makes the path a template (a dynamic segment). Reads are lowered to
19
+ `read(path)`; a later pass hoists static-path reads to a `cell` bound once at
20
+ component init (the string-free hot path the bench measured). Index expressions
21
+ are themselves visited, so a read used as an index lowers too.
22
+ */
23
+ export function lowerDocAccess(code: string, docName: string): string {
24
+ const source = ts.createSourceFile('component.ts', code, ts.ScriptTarget.Latest, true)
25
+ const result = ts.transform(source, [docAccessTransformer(docName)])
26
+ const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed })
27
+ const output = printer.printFile(result.transformed[0] as ts.SourceFile)
28
+ result.dispose()
29
+ return output
30
+ }
31
+
32
+ /* A path segment is either a literal key or a runtime expression (a dynamic index). */
33
+ type Segment = { kind: 'literal'; value: string } | { kind: 'expression'; node: ts.Expression }
34
+
35
+ /* Maps a compound-assignment operator to its plain binary counterpart. */
36
+ const COMPOUND_OPERATORS = new Map<ts.SyntaxKind, ts.BinaryOperator>([
37
+ [ts.SyntaxKind.PlusEqualsToken, ts.SyntaxKind.PlusToken],
38
+ [ts.SyntaxKind.MinusEqualsToken, ts.SyntaxKind.MinusToken],
39
+ [ts.SyntaxKind.AsteriskEqualsToken, ts.SyntaxKind.AsteriskToken],
40
+ [ts.SyntaxKind.SlashEqualsToken, ts.SyntaxKind.SlashToken],
41
+ ])
42
+
43
+ function docAccessTransformer(docName: string): ts.TransformerFactory<ts.SourceFile> {
44
+ return (context) => (root) => {
45
+ /* Collects the path of an access chain rooted at `docName`, visiting any
46
+ dynamic index so reads inside it lower too. undefined if not our doc. */
47
+ function pathSegments(node: ts.Expression): Segment[] | undefined {
48
+ const segments: Segment[] = []
49
+ let current: ts.Expression = node
50
+ while (true) {
51
+ if (ts.isPropertyAccessExpression(current)) {
52
+ segments.unshift({ kind: 'literal', value: current.name.text })
53
+ current = current.expression
54
+ } else if (ts.isElementAccessExpression(current)) {
55
+ const argument = current.argumentExpression
56
+ if (ts.isStringLiteral(argument) || ts.isNumericLiteral(argument)) {
57
+ segments.unshift({ kind: 'literal', value: argument.text })
58
+ } else {
59
+ segments.unshift({
60
+ kind: 'expression',
61
+ node: ts.visitNode(argument, visit) as ts.Expression,
62
+ })
63
+ }
64
+ current = current.expression
65
+ } else {
66
+ break
67
+ }
68
+ }
69
+ if (ts.isIdentifier(current) && current.text === docName && segments.length > 0) {
70
+ return segments
71
+ }
72
+ return undefined
73
+ }
74
+
75
+ function visit(node: ts.Node): ts.Node {
76
+ /* Assignment (plain or compound) to a doc path → replace patch. */
77
+ if (ts.isBinaryExpression(node)) {
78
+ const segments = pathSegments(node.left as ts.Expression)
79
+ if (segments) {
80
+ const operator = node.operatorToken.kind
81
+ if (operator === ts.SyntaxKind.EqualsToken) {
82
+ return docCall(docName, 'replace', [
83
+ buildPath(segments),
84
+ ts.visitNode(node.right, visit) as ts.Expression,
85
+ ])
86
+ }
87
+ const binary = COMPOUND_OPERATORS.get(operator)
88
+ if (binary) {
89
+ const next = ts.factory.createBinaryExpression(
90
+ docCall(docName, 'read', [buildPath(segments)]),
91
+ binary,
92
+ ts.visitNode(node.right, visit) as ts.Expression,
93
+ )
94
+ return docCall(docName, 'replace', [buildPath(segments), next])
95
+ }
96
+ }
97
+ }
98
+ /* doc array `.push(x)` → add patch at the array's `-` slot. */
99
+ if (
100
+ ts.isCallExpression(node) &&
101
+ ts.isPropertyAccessExpression(node.expression) &&
102
+ node.expression.name.text === 'push'
103
+ ) {
104
+ const segments = pathSegments(node.expression.expression)
105
+ const pushed = node.arguments[0]
106
+ if (segments && pushed !== undefined) {
107
+ return docCall(docName, 'add', [
108
+ buildPath([...segments, { kind: 'literal', value: '-' }]),
109
+ ts.visitNode(pushed, visit) as ts.Expression,
110
+ ])
111
+ }
112
+ }
113
+ /* A called member on a doc chain is a method on the read value, not a
114
+ deeper path: `model.draft.trim()` → `model.read("draft").trim()`,
115
+ `model.items.map(f)` → `model.read("items").map(f)`. (Array `.push`
116
+ above is the exception — it lowers to an `add` patch.) */
117
+ if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
118
+ const segments = pathSegments(node.expression.expression)
119
+ if (segments) {
120
+ return ts.factory.createCallExpression(
121
+ ts.factory.createPropertyAccessExpression(
122
+ docCall(docName, 'read', [buildPath(segments)]),
123
+ node.expression.name.text,
124
+ ),
125
+ node.typeArguments,
126
+ node.arguments.map((arg) => ts.visitNode(arg, visit) as ts.Expression),
127
+ )
128
+ }
129
+ }
130
+ /* delete doc.path → remove patch. */
131
+ if (ts.isDeleteExpression(node)) {
132
+ const segments = pathSegments(node.expression)
133
+ if (segments) {
134
+ return docCall(docName, 'remove', [buildPath(segments)])
135
+ }
136
+ }
137
+ /* Any remaining doc access chain is a read. */
138
+ if (ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node)) {
139
+ const segments = pathSegments(node)
140
+ if (segments) {
141
+ return docCall(docName, 'read', [buildPath(segments)])
142
+ }
143
+ }
144
+ return ts.visitEachChild(node, visit, context)
145
+ }
146
+
147
+ return ts.visitNode(root, visit) as ts.SourceFile
148
+ }
149
+ }
150
+
151
+ /* Builds `docName.method(...args)`. */
152
+ function docCall(docName: string, method: string, args: ts.Expression[]): ts.CallExpression {
153
+ return ts.factory.createCallExpression(
154
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(docName), method),
155
+ undefined,
156
+ args,
157
+ )
158
+ }
159
+
160
+ /*
161
+ Turns segments into a path expression: an all-literal path is one string literal
162
+ (`"lines/0/sku"`); a path with a dynamic segment is a string-concatenation that
163
+ evaluates to the path at runtime (`"lines/" + i + "/sku"`), kept string-typed by
164
+ leading with a literal.
165
+ */
166
+ function buildPath(segments: Segment[]): ts.Expression {
167
+ if (segments.every((segment) => segment.kind === 'literal')) {
168
+ return ts.factory.createStringLiteral(
169
+ segments.map((segment) => (segment as { value: string }).value).join('/'),
170
+ )
171
+ }
172
+ const fragments: ts.Expression[] = []
173
+ /* Append text to the trailing string fragment when there is one, so a `/`
174
+ separator folds into the preceding literal (`"lines/" + i`) rather than
175
+ printing as its own term (`"lines" + "/" + i`). */
176
+ const appendText = (text: string): void => {
177
+ const last = fragments[fragments.length - 1]
178
+ if (last !== undefined && ts.isStringLiteral(last)) {
179
+ fragments[fragments.length - 1] = ts.factory.createStringLiteral(last.text + text)
180
+ } else {
181
+ fragments.push(ts.factory.createStringLiteral(text))
182
+ }
183
+ }
184
+ segments.forEach((segment, index) => {
185
+ const separator = index === 0 ? '' : '/'
186
+ if (segment.kind === 'literal') {
187
+ appendText(separator + segment.value)
188
+ } else {
189
+ if (separator !== '') {
190
+ appendText(separator)
191
+ }
192
+ fragments.push(segment.node)
193
+ }
194
+ })
195
+ const head = fragments[0]
196
+ if (head === undefined || !ts.isStringLiteral(head)) {
197
+ fragments.unshift(ts.factory.createStringLiteral(''))
198
+ }
199
+ return fragments.reduce((left, right) =>
200
+ ts.factory.createBinaryExpression(left, ts.SyntaxKind.PlusToken, right),
201
+ )
202
+ }
@@ -0,0 +1,16 @@
1
+ import { dirname } from 'node:path'
2
+ import ts from 'typescript'
3
+
4
+ /*
5
+ The project root governing a `.abide` file: the directory of the nearest
6
+ `tsconfig.json` at or above it, or `fallback` when none is found. The LSP routes
7
+ each document to a shadow service rooted here, so a file is type-checked against
8
+ its own project's `paths`/`baseUrl`/strictness — the same tsconfig `abide check`
9
+ uses when run from that package. Without this, every file in a monorepo opened at
10
+ its root would be checked against the root tsconfig, and project-local path
11
+ aliases (`$server/*`, `$ui/*`) would fail to resolve.
12
+ */
13
+ export function nearestProjectRoot(filePath: string, fallback: string): string {
14
+ const configPath = ts.findConfigFile(dirname(filePath), ts.sys.fileExists, 'tsconfig.json')
15
+ return configPath === undefined ? fallback : dirname(configPath)
16
+ }
@@ -0,0 +1,396 @@
1
+ import { decodeHtmlEntities } from './decodeHtmlEntities.ts'
2
+ import type { TemplateAttr } from './types/TemplateAttr.ts'
3
+ import type { TemplateNode } from './types/TemplateNode.ts'
4
+ import type { TextPart } from './types/TextPart.ts'
5
+
6
+ /*
7
+ A minimal compile-time parser for the abide template subset: elements, text with
8
+ `{expr}` interpolation, static/`{expr}`/`on<event>={expr}` attributes, and
9
+ `<template each as key>` control flow. Not a full HTML parser — it covers what
10
+ components need and reads brace expressions with quote/nesting awareness so an
11
+ expression containing `<`, `>`, or `}` parses intact. Void elements self-close.
12
+ `<!-- … -->` comments are dropped (no node emitted) so they leave no trace in the
13
+ SSR/client output or hydration cursor.
14
+
15
+ A `<style>` becomes a `style` node IN PLACE (not hoisted): its CSS body is read
16
+ structurally (not via a raw-source regex) so a `<style>` sitting inside a `{expr}`
17
+ or attribute — e.g. one quoted in a code sample — is read as that expression's
18
+ text, never mistaken for a real style. Keeping it in the tree lets the front-end
19
+ scope it to its sibling subtree (`analyzeComponent`); the node emits no DOM/markup.
20
+ */
21
+
22
+ const VOID_TAGS = new Set([
23
+ 'area',
24
+ 'base',
25
+ 'br',
26
+ 'col',
27
+ 'embed',
28
+ 'hr',
29
+ 'img',
30
+ 'input',
31
+ 'link',
32
+ 'meta',
33
+ 'param',
34
+ 'source',
35
+ 'track',
36
+ 'wbr',
37
+ ])
38
+
39
+ /* A braced template expression with the absolute source offset of its first
40
+ (post-trim) character, so the type-checking shadow can map a diagnostic back. */
41
+ type Braced = { code: string; loc: number }
42
+
43
+ export function parseTemplate(source: string, baseOffset = 0): { nodes: TemplateNode[] } {
44
+ let cursor = 0
45
+
46
+ /* Reads a `{...}` expression starting at `cursor` (on the `{`), tracking
47
+ string literals and nested braces so the matching `}` is found. `loc` is the
48
+ absolute offset (baseOffset-relative) of the trimmed code's first char. */
49
+ function readBracedExpression(): Braced {
50
+ cursor += 1 // past '{'
51
+ const start = cursor
52
+ let depth = 1
53
+ while (cursor < source.length && depth > 0) {
54
+ const char = source.charAt(cursor)
55
+ if (char === '"' || char === "'" || char === '`') {
56
+ cursor += 1
57
+ while (cursor < source.length && source.charAt(cursor) !== char) {
58
+ if (source.charAt(cursor) === '\\') {
59
+ cursor += 1
60
+ }
61
+ cursor += 1
62
+ }
63
+ } else if (char === '{') {
64
+ depth += 1
65
+ } else if (char === '}') {
66
+ depth -= 1
67
+ }
68
+ cursor += 1
69
+ }
70
+ const raw = source.slice(start, cursor - 1)
71
+ const leading = raw.length - raw.trimStart().length
72
+ return { code: raw.trim(), loc: baseOffset + start + leading }
73
+ }
74
+
75
+ /* Skips an HTML comment starting at `cursor` (on `<!--`), advancing past its
76
+ `-->`; an unterminated comment runs to the end of source. Emits no node. */
77
+ function skipComment(): void {
78
+ const close = source.indexOf('-->', cursor)
79
+ cursor = close === -1 ? source.length : close + '-->'.length
80
+ }
81
+
82
+ /* True when `cursor` is on a `<style>` open tag — read raw (`readStyle`) so its
83
+ CSS braces never misparse as `{expr}` interpolations. */
84
+ function atStyleTag(): boolean {
85
+ return source.startsWith('<style', cursor) && /[\s>]/.test(source.charAt(cursor + 6))
86
+ }
87
+
88
+ /* Reads a `<style>…</style>` block into a `style` node carrying its CSS body; an
89
+ unterminated block runs to end. The body is read raw (not parsed as markup) so
90
+ CSS braces never misparse as `{expr}`. */
91
+ function readStyle(): TemplateNode {
92
+ const openEnd = source.indexOf('>', cursor)
93
+ const close = source.indexOf('</style>', cursor)
94
+ const css =
95
+ openEnd !== -1 && (close === -1 || openEnd < close)
96
+ ? source.slice(openEnd + 1, close === -1 ? source.length : close).trim()
97
+ : ''
98
+ cursor = close === -1 ? source.length : close + '</style>'.length
99
+ return { kind: 'style', css }
100
+ }
101
+
102
+ function readText(): TemplateNode {
103
+ const parts: TextPart[] = []
104
+ let literal = ''
105
+ while (cursor < source.length && source.charAt(cursor) !== '<') {
106
+ if (source.charAt(cursor) === '{') {
107
+ if (literal !== '') {
108
+ parts.push({ kind: 'static', value: decodeHtmlEntities(literal) })
109
+ literal = ''
110
+ }
111
+ const { code, loc } = readBracedExpression()
112
+ parts.push({ kind: 'expression', code, loc })
113
+ } else {
114
+ literal += source.charAt(cursor)
115
+ cursor += 1
116
+ }
117
+ }
118
+ if (literal !== '') {
119
+ parts.push({ kind: 'static', value: decodeHtmlEntities(literal) })
120
+ }
121
+ return { kind: 'text', parts }
122
+ }
123
+
124
+ function readAttributes(): TemplateAttr[] {
125
+ const attrs: TemplateAttr[] = []
126
+ while (cursor < source.length) {
127
+ while (/\s/.test(source.charAt(cursor))) {
128
+ cursor += 1
129
+ }
130
+ const char = source.charAt(cursor)
131
+ if (char === '>' || char === '/' || char === undefined) {
132
+ break
133
+ }
134
+ let name = ''
135
+ while (cursor < source.length && !/[\s=>/]/.test(source.charAt(cursor))) {
136
+ name += source.charAt(cursor)
137
+ cursor += 1
138
+ }
139
+ while (/\s/.test(source.charAt(cursor))) {
140
+ cursor += 1
141
+ }
142
+ if (source.charAt(cursor) !== '=') {
143
+ attrs.push({ kind: 'static', name, value: '' }) // boolean attribute
144
+ continue
145
+ }
146
+ cursor += 1 // past '='
147
+ while (/\s/.test(source.charAt(cursor))) {
148
+ cursor += 1
149
+ }
150
+ if (source.charAt(cursor) === '{') {
151
+ const { code, loc } = readBracedExpression()
152
+ if (name.startsWith('on')) {
153
+ attrs.push({ kind: 'event', event: name.slice(2), code, loc })
154
+ } else if (name.startsWith('bind:')) {
155
+ attrs.push({ kind: 'bind', property: name.slice(5), code, loc })
156
+ } else if (name === 'attach') {
157
+ attrs.push({ kind: 'attach', code, loc })
158
+ } else {
159
+ attrs.push({ kind: 'expression', name, code, loc })
160
+ }
161
+ } else {
162
+ const quote = source.charAt(cursor)
163
+ cursor += 1
164
+ let value = ''
165
+ while (cursor < source.length && source.charAt(cursor) !== quote) {
166
+ value += source.charAt(cursor)
167
+ cursor += 1
168
+ }
169
+ cursor += 1 // past closing quote
170
+ attrs.push({ kind: 'static', name, value })
171
+ }
172
+ }
173
+ return attrs
174
+ }
175
+
176
+ function readElement(): TemplateNode {
177
+ cursor += 1 // past '<'
178
+ let tag = ''
179
+ while (cursor < source.length && !/[\s>/]/.test(source.charAt(cursor))) {
180
+ tag += source.charAt(cursor)
181
+ cursor += 1
182
+ }
183
+ const attrs = readAttributes()
184
+ let selfClosing = false
185
+ if (source.charAt(cursor) === '/') {
186
+ selfClosing = true
187
+ cursor += 1
188
+ }
189
+ cursor += 1 // past '>'
190
+ /* A nested `<script>` is a scoped reactive block: its body is raw JS read
191
+ verbatim to its `</script>` (not parsed as markup), scoped by the
192
+ containing branch when compiled. */
193
+ if (tag === 'script' && !selfClosing) {
194
+ const close = source.indexOf('</script>', cursor)
195
+ const end = close === -1 ? source.length : close
196
+ const code = source.slice(cursor, end)
197
+ cursor = close === -1 ? source.length : end + '</script>'.length
198
+ return { kind: 'script', code }
199
+ }
200
+ /* A capitalised tag is a child component; its attributes become props and
201
+ its children become slot content (rendered where the child puts <slot>). */
202
+ if (/^[A-Z]/.test(tag)) {
203
+ const slotted = selfClosing ? [] : readChildren(tag)
204
+ return { kind: 'component', name: tag, props: toProps(attrs), children: slotted }
205
+ }
206
+ const children = selfClosing || VOID_TAGS.has(tag) ? [] : readChildren(tag)
207
+ if (tag === 'template') {
208
+ return toControlFlow(attrs, children)
209
+ }
210
+ return { kind: 'element', tag, attrs, children }
211
+ }
212
+
213
+ function readChildren(closeTag: string): TemplateNode[] {
214
+ const nodes: TemplateNode[] = []
215
+ while (cursor < source.length) {
216
+ if (source.startsWith(`</${closeTag}`, cursor)) {
217
+ cursor = source.indexOf('>', cursor) + 1
218
+ break
219
+ }
220
+ if (source.startsWith('<!--', cursor)) {
221
+ skipComment()
222
+ } else if (atStyleTag()) {
223
+ nodes.push(readStyle())
224
+ } else if (source.charAt(cursor) === '<') {
225
+ nodes.push(readElement())
226
+ } else {
227
+ nodes.push(readText())
228
+ }
229
+ }
230
+ return nodes
231
+ }
232
+
233
+ const roots: TemplateNode[] = []
234
+ while (cursor < source.length) {
235
+ if (source.startsWith('<!--', cursor)) {
236
+ skipComment()
237
+ } else if (atStyleTag()) {
238
+ roots.push(readStyle())
239
+ } else if (source.charAt(cursor) === '<') {
240
+ roots.push(readElement())
241
+ } else {
242
+ roots.push(readText())
243
+ }
244
+ }
245
+ return { nodes: roots }
246
+ }
247
+
248
+ /* Turns a component's attributes into props: a static value becomes a string
249
+ literal, an expression keeps its code (event/bind on components ignored). */
250
+ function toProps(attrs: TemplateAttr[]): { name: string; code: string; loc?: number }[] {
251
+ const props: { name: string; code: string; loc?: number }[] = []
252
+ for (const attr of attrs) {
253
+ if (attr.kind === 'static') {
254
+ props.push({ name: attr.name, code: JSON.stringify(attr.value) })
255
+ } else if (attr.kind === 'expression') {
256
+ props.push({ name: attr.name, code: attr.code, loc: attr.loc })
257
+ }
258
+ }
259
+ return props
260
+ }
261
+
262
+ /* The literal text of an attribute (a static value or an expression's code);
263
+ undefined for event/bind attributes, which a directive never is. */
264
+ function attrText(attr: TemplateAttr): string | undefined {
265
+ if (attr.kind === 'static') {
266
+ return attr.value
267
+ }
268
+ if (attr.kind === 'expression') {
269
+ return attr.code
270
+ }
271
+ return undefined
272
+ }
273
+
274
+ /* The source offset of an attribute expression's code (see TextPart.loc); only
275
+ expression attributes carry one — a static value isn't a checkable expression. */
276
+ function attrLoc(attr: TemplateAttr | undefined): number | undefined {
277
+ return attr !== undefined && attr.kind === 'expression' ? attr.loc : undefined
278
+ }
279
+
280
+ /* The attribute's source name (`on<event>`/`bind:<property>` reconstructed). */
281
+ function attrName(attr: TemplateAttr): string {
282
+ if (attr.kind === 'event') {
283
+ return `on${attr.event}`
284
+ }
285
+ if (attr.kind === 'bind') {
286
+ return `bind:${attr.property}`
287
+ }
288
+ if (attr.kind === 'attach') {
289
+ return 'attach'
290
+ }
291
+ return attr.name
292
+ }
293
+
294
+ /* Turns a `<template>` directive into a control node (if/each/await + then/catch). */
295
+ function toControlFlow(attrs: TemplateAttr[], children: TemplateNode[]): TemplateNode {
296
+ const find = (name: string) => attrs.find((attr) => attrName(attr) === name)
297
+ /* `<template name="row" args={item}>` declares a snippet — a named builder, not
298
+ a control branch. `args` (its parameter list) rides the `{…}` expression slot. */
299
+ const snippet = find('name')
300
+ if (snippet !== undefined) {
301
+ const name = attrText(snippet)
302
+ if (name === undefined || name === '') {
303
+ throw new Error('[abide] <template name> requires a snippet name')
304
+ }
305
+ const params = find('args')
306
+ return {
307
+ kind: 'snippet',
308
+ name,
309
+ params: params === undefined ? undefined : attrText(params),
310
+ children,
311
+ loc: attrLoc(params),
312
+ }
313
+ }
314
+ /* `<template try>` is a synchronous error boundary: its children are the guarded
315
+ subtree; `catch`/`finally` branches handle a throw while building them. */
316
+ if (find('try') !== undefined) {
317
+ return { kind: 'try', children }
318
+ }
319
+ /* `await` alongside `each` is the async-list switch (handled in the each branch
320
+ below), not an await block. */
321
+ const promise = find('await')
322
+ if (promise !== undefined && find('each') === undefined) {
323
+ const promiseCode = attrText(promise)
324
+ if (promiseCode === undefined) {
325
+ throw new Error('[abide] <template await> requires a promise expression')
326
+ }
327
+ /* A `then` attribute ON the await tag is the blocking switch: children become
328
+ the resolved content bound to its value (a `then` *child* is a streaming
329
+ branch, handled separately below when its own tag is parsed). */
330
+ const boundThen = find('then')
331
+ return {
332
+ kind: 'await',
333
+ promise: promiseCode,
334
+ blocking: boundThen !== undefined,
335
+ as: boundThen === undefined ? undefined : attrText(boundThen) || undefined,
336
+ children,
337
+ loc: attrLoc(promise),
338
+ }
339
+ }
340
+ const thenAttr = find('then')
341
+ if (thenAttr !== undefined) {
342
+ return { kind: 'branch', branch: 'then', as: attrText(thenAttr) || undefined, children }
343
+ }
344
+ const catchAttr = find('catch')
345
+ if (catchAttr !== undefined) {
346
+ return { kind: 'branch', branch: 'catch', as: attrText(catchAttr) || undefined, children }
347
+ }
348
+ /* `<template finally>` renders after settle on BOTH outcomes — outcome-agnostic,
349
+ so it binds no value. */
350
+ if (find('finally') !== undefined) {
351
+ return { kind: 'branch', branch: 'finally', as: undefined, children }
352
+ }
353
+ const subject = find('switch')
354
+ if (subject !== undefined) {
355
+ const subjectCode = attrText(subject)
356
+ if (subjectCode === undefined) {
357
+ throw new Error('[abide] <template switch> requires a subject expression')
358
+ }
359
+ return { kind: 'switch', subject: subjectCode, children, loc: attrLoc(subject) }
360
+ }
361
+ const caseAttr = find('case')
362
+ if (caseAttr !== undefined) {
363
+ const matchCode = attrText(caseAttr)
364
+ if (matchCode === undefined) {
365
+ throw new Error('[abide] <template case> requires a value expression')
366
+ }
367
+ return { kind: 'case', match: matchCode, children, loc: attrLoc(caseAttr) }
368
+ }
369
+ if (find('default') !== undefined || find('else') !== undefined) {
370
+ return { kind: 'case', match: undefined, children } // default (switch) / else (if)
371
+ }
372
+ const condition = find('if')
373
+ if (condition !== undefined) {
374
+ const conditionCode = attrText(condition)
375
+ if (conditionCode === undefined) {
376
+ throw new Error('[abide] <template if> requires a condition expression')
377
+ }
378
+ return { kind: 'if', condition: conditionCode, children, loc: attrLoc(condition) }
379
+ }
380
+ const items = find('each')
381
+ const itemsCode = items === undefined ? undefined : attrText(items)
382
+ if (itemsCode === undefined) {
383
+ throw new Error('[abide] <template> without a supported directive (if/each)')
384
+ }
385
+ const as = find('as')
386
+ const key = find('key')
387
+ return {
388
+ kind: 'each',
389
+ items: itemsCode,
390
+ as: (as === undefined ? undefined : attrText(as)) ?? '_item',
391
+ key: key === undefined ? undefined : attrText(key),
392
+ async: find('await') !== undefined, // `<template each await>` over an AsyncIterable
393
+ children,
394
+ loc: attrLoc(items),
395
+ }
396
+ }
@@ -0,0 +1,36 @@
1
+ import { staticAttrValue } from './staticAttrValue.ts'
2
+ import type { TemplateNode } from './types/TemplateNode.ts'
3
+
4
+ /* A component's slotted children split by destination slot. */
5
+ export type SlotGroups = {
6
+ default: TemplateNode[]
7
+ named: { name: string; nodes: TemplateNode[] }[]
8
+ }
9
+
10
+ /*
11
+ Partitions a component's children by their `slot="name"` attribute: an element
12
+ carrying one goes to that named group (with the directive attr stripped so it
13
+ never renders as a real attribute), everything else forms the default slot. Both
14
+ back-ends partition identically, so SSR and client agree on which markup lands in
15
+ which `<slot>`.
16
+ */
17
+ export function partitionSlots(children: TemplateNode[]): SlotGroups {
18
+ const defaults: TemplateNode[] = []
19
+ const named = new Map<string, TemplateNode[]>()
20
+ for (const child of children) {
21
+ const name = child.kind === 'element' ? staticAttrValue(child, 'slot') : undefined
22
+ if (child.kind !== 'element' || name === undefined) {
23
+ defaults.push(child)
24
+ continue
25
+ }
26
+ const stripped = {
27
+ ...child,
28
+ attrs: child.attrs.filter((attr) => !(attr.kind === 'static' && attr.name === 'slot')),
29
+ }
30
+ named.set(name, [...(named.get(name) ?? []), stripped])
31
+ }
32
+ return {
33
+ default: defaults,
34
+ named: [...named].map(([name, nodes]) => ({ name, nodes })),
35
+ }
36
+ }