@abide/abide 0.49.0 → 0.50.1

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 (325) hide show
  1. package/AGENTS.md +564 -437
  2. package/CHANGELOG.md +183 -0
  3. package/README.md +165 -202
  4. package/package.json +14 -5
  5. package/src/abideLsp.ts +5 -6
  6. package/src/abideResolverPlugin.ts +197 -169
  7. package/src/build.ts +79 -56
  8. package/src/buildDisconnected.ts +0 -2
  9. package/src/checkAbide.ts +12 -2
  10. package/src/devEntry.ts +113 -28
  11. package/src/discoveryEntry.ts +3 -2
  12. package/src/lib/bundle/disconnected.abide +69 -73
  13. package/src/lib/bundle/infoPlist.ts +13 -7
  14. package/src/lib/bundle/spawnEmbeddedServer.ts +13 -4
  15. package/src/lib/bundle/waitForServer.ts +6 -1
  16. package/src/lib/mcp/mcpTools.ts +15 -6
  17. package/src/lib/server/error.ts +6 -6
  18. package/src/lib/server/json.ts +17 -3
  19. package/src/lib/server/rpc/defineRpc.ts +58 -24
  20. package/src/lib/server/rpc/parseArgs.ts +98 -13
  21. package/src/lib/server/rpc/resolveRpcJsonSchema.ts +28 -0
  22. package/src/lib/server/rpc/types/RpcHelper.ts +75 -105
  23. package/src/lib/server/rpc/types/RpcRegistryEntry.ts +24 -9
  24. package/src/lib/server/rpc/validationError.ts +1 -1
  25. package/src/lib/server/runtime/DEV_RELOAD_CLIENT_SCRIPT.ts +0 -15
  26. package/src/lib/server/runtime/buildCacheSnapshot.ts +10 -9
  27. package/src/lib/server/runtime/buildInspectorSurface.ts +6 -4
  28. package/src/lib/server/runtime/buildOpenApiSpec.ts +55 -11
  29. package/src/lib/server/runtime/buildPreloadManifest.ts +12 -10
  30. package/src/lib/server/runtime/createAppAssetServer.ts +18 -15
  31. package/src/lib/server/runtime/createAppRouteResolver.ts +145 -0
  32. package/src/lib/server/runtime/createPlumbingRouter.ts +212 -0
  33. package/src/lib/server/runtime/createRouteDispatcher.ts +4 -10
  34. package/src/lib/server/runtime/createServer.ts +120 -324
  35. package/src/lib/server/runtime/createUiPageRenderer.ts +137 -26
  36. package/src/lib/server/runtime/devClientFingerprint.ts +19 -34
  37. package/src/lib/server/runtime/installAmbientScopeStore.ts +30 -9
  38. package/src/lib/server/runtime/logExposedSurfaces.ts +8 -7
  39. package/src/lib/server/runtime/pathStore.ts +15 -0
  40. package/src/lib/server/runtime/registryManifests.ts +1 -1
  41. package/src/lib/server/runtime/renderCellBarrierStore.ts +15 -0
  42. package/src/lib/server/runtime/runWithRequestScope.ts +3 -0
  43. package/src/lib/server/runtime/serializeCacheSnapshot.ts +6 -4
  44. package/src/lib/server/runtime/snapshotEntryFromCache.ts +14 -14
  45. package/src/lib/server/runtime/streamCacheResolutions.ts +14 -7
  46. package/src/lib/server/runtime/streamFromIterator.ts +30 -2
  47. package/src/lib/server/runtime/textResponse.ts +23 -0
  48. package/src/lib/server/runtime/types/DevReloadStamp.ts +6 -10
  49. package/src/lib/server/runtime/types/InspectorCacheEntry.ts +1 -1
  50. package/src/lib/server/runtime/types/RequestStore.ts +27 -0
  51. package/src/lib/server/runtime/warnUnguardedMcp.ts +15 -5
  52. package/src/lib/server/sockets/createSocketDispatcher.ts +9 -11
  53. package/src/lib/server/sockets/defineSocket.ts +5 -4
  54. package/src/lib/server/sse.ts +5 -1
  55. package/src/lib/shared/ASYNC_CELL.ts +5 -0
  56. package/src/lib/shared/DEV_REBUILD_PATH.ts +6 -0
  57. package/src/lib/shared/HTTP_METHODS.ts +6 -0
  58. package/src/lib/shared/HttpError.ts +1 -5
  59. package/src/lib/shared/MCP_PATH.ts +6 -0
  60. package/src/lib/shared/PROXIED_SERVER_SUBDIRS.ts +15 -0
  61. package/src/lib/shared/REF_JSON_TAGS.ts +13 -1
  62. package/src/lib/shared/RPC_SHIM_GLOBALS.ts +9 -0
  63. package/src/lib/shared/activeCacheStore.ts +1 -0
  64. package/src/lib/shared/activePage.ts +1 -0
  65. package/src/lib/shared/buildArtifact.ts +4 -1
  66. package/src/lib/shared/buildSocketOverChannel.ts +4 -3
  67. package/src/lib/shared/bundleGraphFromMetafile.ts +68 -0
  68. package/src/lib/shared/cache.ts +156 -131
  69. package/src/lib/shared/changeAffectsClient.ts +12 -7
  70. package/src/lib/shared/createCacheStore.ts +31 -8
  71. package/src/lib/shared/createLifecycleChannel.ts +7 -1
  72. package/src/lib/shared/createReachable.ts +47 -78
  73. package/src/lib/shared/createRemoteFunction.ts +52 -30
  74. package/src/lib/shared/createRpcServerProgram.ts +820 -0
  75. package/src/lib/shared/decodeRefJson.ts +4 -4
  76. package/src/lib/shared/decodeResponse.ts +2 -2
  77. package/src/lib/shared/decodeWireBody.ts +35 -0
  78. package/src/lib/shared/detectRpcMethod.ts +8 -1
  79. package/src/lib/shared/done.ts +8 -2
  80. package/src/lib/shared/encodeRefJson.ts +4 -4
  81. package/src/lib/shared/encodeWireBody.ts +18 -0
  82. package/src/lib/{server/rpc → shared}/fieldErrorsFromIssues.ts +5 -1
  83. package/src/lib/shared/generateDeclarations.ts +72 -0
  84. package/src/lib/shared/hasSeedableRequest.ts +25 -0
  85. package/src/lib/shared/hydrationWindow.ts +53 -0
  86. package/src/lib/shared/isAsyncCell.ts +11 -0
  87. package/src/lib/shared/isAsyncIterable.ts +8 -0
  88. package/src/lib/shared/isSubscribable.ts +3 -3
  89. package/src/lib/shared/isThenable.ts +9 -0
  90. package/src/lib/shared/jsonSchemaForType.ts +258 -0
  91. package/src/lib/shared/lenientDecode.ts +15 -0
  92. package/src/lib/shared/loadProjectTsConfig.ts +28 -0
  93. package/src/lib/shared/markFrameworkSourcesIgnored.ts +1 -1
  94. package/src/lib/shared/matchRoute.ts +4 -14
  95. package/src/lib/shared/peek.ts +14 -0
  96. package/src/lib/shared/pending.ts +9 -6
  97. package/src/lib/shared/pendingAsyncCellsSlot.ts +13 -0
  98. package/src/lib/shared/prepareRpcModule.ts +91 -93
  99. package/src/lib/shared/prepareSocketModule.ts +3 -2
  100. package/src/lib/shared/probeRegistries.ts +5 -18
  101. package/src/lib/shared/reachable.ts +7 -10
  102. package/src/lib/shared/refresh.ts +12 -2
  103. package/src/lib/shared/refreshing.ts +8 -2
  104. package/src/lib/shared/resolvedCellsSlot.ts +13 -0
  105. package/src/lib/shared/reviveWireField.ts +49 -0
  106. package/src/lib/shared/reviveWireOutput.ts +36 -0
  107. package/src/lib/shared/rpcServerForRoot.ts +25 -0
  108. package/src/lib/shared/scanPages.ts +25 -0
  109. package/src/lib/shared/snapshotShippable.ts +8 -7
  110. package/src/lib/shared/streamedCellsSlot.ts +14 -0
  111. package/src/lib/shared/subscribableFromResponse.ts +4 -4
  112. package/src/lib/shared/subscribableProbes.ts +1 -1
  113. package/src/lib/shared/tailProbeSlot.ts +1 -1
  114. package/src/lib/shared/types/AsyncComputed.ts +20 -0
  115. package/src/lib/shared/types/AsyncState.ts +13 -0
  116. package/src/lib/shared/types/CacheEntry.ts +7 -7
  117. package/src/lib/shared/types/CacheOptions.ts +23 -37
  118. package/src/lib/shared/types/CachePolicy.ts +25 -0
  119. package/src/lib/shared/types/CacheSnapshotEntry.ts +6 -5
  120. package/src/lib/shared/types/ErrorJsonSchemas.ts +8 -0
  121. package/src/lib/shared/types/HttpMethod.ts +3 -1
  122. package/src/lib/shared/types/InputCoercion.ts +17 -0
  123. package/src/lib/shared/types/{Subscribable.ts → NamedAsyncIterable.ts} +1 -1
  124. package/src/lib/shared/types/OutputWirePlan.ts +17 -0
  125. package/src/lib/shared/types/PagesScan.ts +7 -0
  126. package/src/lib/shared/types/PendingAsyncCells.ts +10 -0
  127. package/src/lib/shared/types/RawRemoteFunction.ts +6 -0
  128. package/src/lib/shared/types/RemoteCallable.ts +8 -7
  129. package/src/lib/shared/types/RemoteFunction.ts +16 -15
  130. package/src/lib/shared/types/ResolvedCells.ts +11 -0
  131. package/src/lib/shared/types/ReturnBody.ts +15 -0
  132. package/src/lib/shared/types/RpcBuildStamps.ts +23 -0
  133. package/src/lib/shared/types/RpcErrorGuard.ts +3 -8
  134. package/src/lib/shared/types/Socket.ts +4 -4
  135. package/src/lib/shared/types/SsrPayload.ts +5 -1
  136. package/src/lib/shared/types/StreamPolicy.ts +11 -0
  137. package/src/lib/shared/types/StreamedCells.ts +19 -0
  138. package/src/lib/shared/types/StreamedResolution.ts +24 -6
  139. package/src/lib/shared/types/TailHooks.ts +1 -1
  140. package/src/lib/shared/types/WireKind.ts +11 -0
  141. package/src/lib/shared/validationHttpError.ts +33 -0
  142. package/src/lib/shared/warmSeedKey.ts +16 -0
  143. package/src/lib/shared/wireJsonReplacer.ts +30 -0
  144. package/src/lib/shared/writeRpcDts.ts +11 -1
  145. package/src/lib/shared/writeTestSocketsDts.ts +1 -1
  146. package/src/lib/test/createTestApp.ts +19 -1
  147. package/src/lib/ui/README.md +1 -1
  148. package/src/lib/ui/activePendingCells.ts +14 -0
  149. package/src/lib/ui/compile/BLOCK_KEYWORDS.ts +21 -0
  150. package/src/lib/ui/compile/SSR_ESCAPE.ts +4 -1
  151. package/src/lib/ui/compile/UI_RUNTIME_IMPORTS.ts +35 -8
  152. package/src/lib/ui/compile/abideUiPlugin.ts +19 -2
  153. package/src/lib/ui/compile/analyzeComponent.ts +89 -6
  154. package/src/lib/ui/compile/assignmentTargetNames.ts +54 -0
  155. package/src/lib/ui/compile/asyncInterpolationFields.ts +152 -0
  156. package/src/lib/ui/compile/asyncValuePositionError.ts +21 -0
  157. package/src/lib/ui/compile/asyncValuePositionInterpolations.ts +64 -0
  158. package/src/lib/ui/compile/attrLiftPosition.ts +18 -0
  159. package/src/lib/ui/compile/cachedSourceFile.ts +40 -0
  160. package/src/lib/ui/compile/catchBinding.ts +7 -5
  161. package/src/lib/ui/compile/classifyInterpolationType.ts +46 -0
  162. package/src/lib/ui/compile/collectAbideDiagnostics.ts +96 -0
  163. package/src/lib/ui/compile/compileComponent.ts +19 -3
  164. package/src/lib/ui/compile/compileModule.ts +27 -58
  165. package/src/lib/ui/compile/compileSSR.ts +51 -12
  166. package/src/lib/ui/compile/compileShadow.ts +145 -18
  167. package/src/lib/ui/compile/composeProps.ts +12 -2
  168. package/src/lib/ui/compile/createShadowLanguageService.ts +116 -68
  169. package/src/lib/ui/compile/createShadowProgram.ts +35 -6
  170. package/src/lib/ui/compile/declaredNames.ts +36 -0
  171. package/src/lib/ui/compile/desugarSignals.ts +418 -36
  172. package/src/lib/ui/compile/expressionIsPrefixEvaluable.ts +19 -0
  173. package/src/lib/ui/compile/generateBuild.ts +52 -9
  174. package/src/lib/ui/compile/generateSSR.ts +242 -43
  175. package/src/lib/ui/compile/hoistableAwaits.ts +193 -0
  176. package/src/lib/ui/compile/hoistableChildRenders.ts +112 -0
  177. package/src/lib/ui/compile/interpolatedTemplateLiteral.ts +3 -1
  178. package/src/lib/ui/compile/interpolationClassifierForRoot.ts +37 -0
  179. package/src/lib/ui/compile/isSpuriousAsyncReadDiagnostic.ts +174 -0
  180. package/src/lib/ui/compile/liftAsyncSubExpressions.ts +166 -0
  181. package/src/lib/ui/compile/lowerAsyncInterpolations.ts +92 -0
  182. package/src/lib/ui/compile/lowerContext.ts +10 -0
  183. package/src/lib/ui/compile/lowerDocAccess.ts +26 -23
  184. package/src/lib/ui/compile/lowerScript.ts +40 -4
  185. package/src/lib/ui/compile/nodeAtShadowOffset.ts +28 -0
  186. package/src/lib/ui/compile/parseTemplate.ts +18 -1092
  187. package/src/lib/ui/compile/parseTemplateRecovering.ts +1385 -0
  188. package/src/lib/ui/compile/referencedIdentifiers.ts +35 -0
  189. package/src/lib/ui/compile/renameSignalRefs.ts +21 -22
  190. package/src/lib/ui/compile/seedTypeClassifierForRoot.ts +65 -0
  191. package/src/lib/ui/compile/shadowInterpolationClassifier.ts +47 -0
  192. package/src/lib/ui/compile/sourceFileOptionsSignature.ts +20 -0
  193. package/src/lib/ui/compile/structuralHeadTokens.ts +107 -0
  194. package/src/lib/ui/compile/templateSemanticTokens.ts +21 -0
  195. package/src/lib/ui/compile/templateStartOffset.ts +15 -0
  196. package/src/lib/ui/compile/tryPlan.ts +4 -3
  197. package/src/lib/ui/compile/types/AnalyzedComponent.ts +4 -0
  198. package/src/lib/ui/compile/types/AsyncInterpolationField.ts +19 -0
  199. package/src/lib/ui/compile/types/InterpolationClassifier.ts +12 -0
  200. package/src/lib/ui/compile/types/InterpolationKind.ts +7 -0
  201. package/src/lib/ui/compile/types/ParseDiagnostic.ts +8 -0
  202. package/src/lib/ui/compile/types/SeedTypeClassifier.ts +15 -0
  203. package/src/lib/ui/compile/types/TemplateNode.ts +36 -4
  204. package/src/lib/ui/compile/types/ValuePositionInterpolation.ts +13 -0
  205. package/src/lib/ui/compile/writtenTemplateNames.ts +84 -0
  206. package/src/lib/ui/computed.ts +28 -1
  207. package/src/lib/ui/createScope.ts +35 -68
  208. package/src/lib/ui/dom/anchoredBranch.ts +142 -0
  209. package/src/lib/ui/dom/appendText.ts +8 -3
  210. package/src/lib/ui/dom/awaitBlock.ts +43 -94
  211. package/src/lib/ui/dom/bindProp.ts +22 -0
  212. package/src/lib/ui/dom/bindableProp.ts +47 -0
  213. package/src/lib/ui/dom/cellPending.ts +24 -0
  214. package/src/lib/ui/dom/disposeRange.ts +2 -1
  215. package/src/lib/ui/dom/each.ts +26 -4
  216. package/src/lib/ui/dom/eachAsync.ts +39 -3
  217. package/src/lib/ui/dom/fillBoundary.ts +2 -3
  218. package/src/lib/ui/dom/fillRange.ts +4 -4
  219. package/src/lib/ui/dom/hydrate.ts +6 -12
  220. package/src/lib/ui/dom/isComment.ts +1 -1
  221. package/src/lib/ui/dom/matchingRangeClose.ts +29 -0
  222. package/src/lib/ui/dom/mount.ts +1 -2
  223. package/src/lib/ui/dom/mountChild.ts +9 -40
  224. package/src/lib/ui/dom/mountRange.ts +2 -3
  225. package/src/lib/ui/dom/mountStreamedChild.ts +84 -0
  226. package/src/lib/ui/dom/mountSwappableRange.ts +46 -4
  227. package/src/lib/ui/dom/mutateDocContainer.ts +65 -0
  228. package/src/lib/ui/dom/on.ts +2 -2
  229. package/src/lib/ui/dom/readCell.ts +40 -0
  230. package/src/lib/ui/dom/switchBlock.ts +30 -7
  231. package/src/lib/ui/dom/tryBlock.ts +230 -66
  232. package/src/lib/ui/dom/types/SwitchCase.ts +5 -1
  233. package/src/lib/ui/dom/when.ts +12 -2
  234. package/src/lib/ui/dom/withScope.ts +2 -2
  235. package/src/lib/ui/finalizeStreamedChildren.ts +89 -0
  236. package/src/lib/ui/flight.ts +56 -0
  237. package/src/lib/ui/html.ts +12 -1
  238. package/src/lib/ui/isolateCellBarrier.ts +17 -0
  239. package/src/lib/ui/linked.ts +48 -2
  240. package/src/lib/ui/remoteProxy.ts +84 -159
  241. package/src/lib/ui/renderChain.ts +49 -13
  242. package/src/lib/ui/renderToStream.ts +22 -18
  243. package/src/lib/ui/resumeSeedScript.ts +1 -1
  244. package/src/lib/ui/router.ts +63 -36
  245. package/src/lib/ui/runtime/AsyncCellError.ts +20 -0
  246. package/src/lib/ui/runtime/CELL_SEED.ts +14 -0
  247. package/src/lib/ui/runtime/CURRENT_BOUNDARY.ts +11 -0
  248. package/src/lib/ui/runtime/CURRENT_PATH.ts +29 -0
  249. package/src/lib/ui/runtime/RENDER.ts +10 -7
  250. package/src/lib/ui/runtime/RESUME.ts +4 -4
  251. package/src/lib/ui/runtime/STREAMED_CELLS.ts +57 -0
  252. package/src/lib/ui/runtime/ambientPathBacking.ts +32 -0
  253. package/src/lib/ui/runtime/applyPatchToTree.ts +1 -1
  254. package/src/lib/ui/runtime/blockId.ts +31 -0
  255. package/src/lib/ui/runtime/boundaryFor.ts +11 -0
  256. package/src/lib/ui/runtime/cellBarrierBacking.ts +30 -0
  257. package/src/lib/ui/runtime/createAsyncCell.ts +300 -0
  258. package/src/lib/ui/runtime/createDoc.ts +3 -42
  259. package/src/lib/ui/runtime/createEffectNode.ts +9 -0
  260. package/src/lib/ui/runtime/enterRenderPass.ts +5 -4
  261. package/src/lib/ui/runtime/flushEffects.ts +16 -6
  262. package/src/lib/ui/runtime/isAsyncFunction.ts +14 -0
  263. package/src/lib/ui/runtime/nextBlockId.ts +8 -7
  264. package/src/lib/ui/runtime/renderPath.ts +16 -0
  265. package/src/lib/ui/runtime/types/Boundary.ts +9 -0
  266. package/src/lib/ui/runtime/types/RenderContext.ts +9 -7
  267. package/src/lib/ui/runtime/types/SsrRender.ts +9 -2
  268. package/src/lib/ui/runtime/types/UiComponent.ts +1 -5
  269. package/src/lib/ui/runtime/withOptionalPath.ts +8 -0
  270. package/src/lib/ui/runtime/withPath.ts +16 -0
  271. package/src/lib/ui/runtime/withPathFrom.ts +20 -0
  272. package/src/lib/ui/seedStreamedResolution.ts +31 -6
  273. package/src/lib/ui/settleAsyncCells.ts +24 -0
  274. package/src/lib/ui/socketProxy.ts +1 -1
  275. package/src/lib/ui/startClient.ts +16 -31
  276. package/src/lib/ui/trackedComputed.ts +68 -0
  277. package/src/lib/ui/types/Scope.ts +8 -24
  278. package/src/lib/ui/watch.ts +3 -3
  279. package/src/serverEntry.ts +14 -0
  280. package/template/src/server/rpc/getHello.ts +15 -13
  281. package/template/test/app.test.ts +1 -1
  282. package/src/lib/server/runtime/devHotModuleResponse.ts +0 -41
  283. package/src/lib/shared/DEV_HOT_PREFIX.ts +0 -7
  284. package/src/lib/shared/UNREACHABLE_STATUSES.ts +0 -13
  285. package/src/lib/shared/hasReplayableRequest.ts +0 -17
  286. package/src/lib/shared/hydratingSlot.ts +0 -12
  287. package/src/lib/shared/outboxProbeSlot.ts +0 -20
  288. package/src/lib/shared/types/Outbox.ts +0 -9
  289. package/src/lib/shared/types/OutboxEntry.ts +0 -27
  290. package/src/lib/shared/types/SmartReadOptions.ts +0 -36
  291. package/src/lib/shared/wakeHydrationPeeks.ts +0 -20
  292. package/src/lib/ui/COMPONENT_WRAPPER_PREFIX.ts +0 -5
  293. package/src/lib/ui/compile/REACTIVE_CALLEES.ts +0 -11
  294. package/src/lib/ui/compile/assertRuntimeHelpersBound.ts +0 -80
  295. package/src/lib/ui/compile/markupTokens.ts +0 -313
  296. package/src/lib/ui/compile/structuralBlockTokens.ts +0 -100
  297. package/src/lib/ui/dom/applyResolved.ts +0 -87
  298. package/src/lib/ui/dom/mutateDocArray.ts +0 -38
  299. package/src/lib/ui/dom/scopeLabel.ts +0 -21
  300. package/src/lib/ui/dom/text.ts +0 -20
  301. package/src/lib/ui/history.ts +0 -108
  302. package/src/lib/ui/installHotBridge.ts +0 -95
  303. package/src/lib/ui/installInspectorBridge.ts +0 -140
  304. package/src/lib/ui/outbox.ts +0 -35
  305. package/src/lib/ui/persist.ts +0 -115
  306. package/src/lib/ui/rpcOutbox/createOutboxQueue.ts +0 -281
  307. package/src/lib/ui/rpcOutbox/outboxRegistry.ts +0 -69
  308. package/src/lib/ui/runtime/PATCH_BUS.ts +0 -28
  309. package/src/lib/ui/runtime/captureModelDoc.ts +0 -43
  310. package/src/lib/ui/runtime/hotInstances.ts +0 -10
  311. package/src/lib/ui/runtime/hotReloadEnabled.ts +0 -8
  312. package/src/lib/ui/runtime/hotReplace.ts +0 -38
  313. package/src/lib/ui/runtime/liveScopes.ts +0 -15
  314. package/src/lib/ui/runtime/localStoragePersistence.ts +0 -47
  315. package/src/lib/ui/runtime/registerHotInstance.ts +0 -23
  316. package/src/lib/ui/runtime/seedModelDoc.ts +0 -26
  317. package/src/lib/ui/runtime/types/HotInstance.ts +0 -22
  318. package/src/lib/ui/runtime/types/PatchEvent.ts +0 -16
  319. package/src/lib/ui/seedResolved.ts +0 -28
  320. package/src/lib/ui/sync.ts +0 -48
  321. package/src/lib/ui/types/History.ts +0 -14
  322. package/src/lib/ui/types/PersistHandle.ts +0 -11
  323. package/src/lib/ui/types/PersistenceStore.ts +0 -12
  324. package/src/lib/ui/types/ResolvedFrame.ts +0 -15
  325. package/src/lib/ui/types/SyncTransport.ts +0 -13
@@ -1,7 +1,16 @@
1
1
  import ts from 'typescript'
2
+ import { asyncValuePositionError } from './asyncValuePositionError.ts'
3
+ import { asyncValuePositionInterpolations } from './asyncValuePositionInterpolations.ts'
4
+ import { classifyInterpolationType } from './classifyInterpolationType.ts'
2
5
  import type { ShadowProgram } from './createShadowProgram.ts'
6
+ import { isSpuriousAsyncReadDiagnostic } from './isSpuriousAsyncReadDiagnostic.ts'
7
+ import { nodeAtShadowOffset } from './nodeAtShadowOffset.ts'
8
+ import { parseTemplateRecovering } from './parseTemplateRecovering.ts'
3
9
  import { remapShadowDiagnostic } from './remapShadowDiagnostic.ts'
10
+ import { sourceToShadowOffset } from './sourceToShadowOffset.ts'
11
+ import { templateStartOffset } from './templateStartOffset.ts'
4
12
  import type { AbideDiagnostic } from './types/AbideDiagnostic.ts'
13
+ import type { ShadowMapping } from './types/CompiledShadow.ts'
5
14
 
6
15
  /*
7
16
  Runs the shadow program's type-checker over every `.abide` shadow and relocates
@@ -12,6 +21,7 @@ Shared by `abide check` (one-shot render) and the LSP (per-file publish).
12
21
  */
13
22
  export function collectAbideDiagnostics(shadow: ShadowProgram): AbideDiagnostic[] {
14
23
  const { program, shadows, parseErrors, abidePaths } = shadow
24
+ const checker = program.getTypeChecker()
15
25
  const diagnostics: AbideDiagnostic[] = []
16
26
  for (const abidePath of abidePaths) {
17
27
  const parseError = parseErrors.get(abidePath)
@@ -41,6 +51,15 @@ export function collectAbideDiagnostics(shadow: ShadowProgram): AbideDiagnostic[
41
51
  if (sourceFile === undefined || mappings === undefined) {
42
52
  continue
43
53
  }
54
+ /* The template boundary: a diagnostic mapping at/after it is a template expression, so
55
+ eligible for the ADR-0032 bare-async-read suppression; anything before it is `<script>`
56
+ code, where a forgotten `await` must still surface. If the source can't be read, DON'T
57
+ fall back to 0 — that treats the whole file (including `<script>`) as template and would
58
+ silently suppress a genuine forgotten-await error. Use +Infinity so nothing is eligible
59
+ for suppression and every real diagnostic surfaces (fail toward reporting). */
60
+ const abideSource = ts.sys.readFile(abidePath)
61
+ const templateStart =
62
+ abideSource === undefined ? Number.POSITIVE_INFINITY : templateStartOffset(abideSource)
44
63
  const raw = [
45
64
  ...program.getSyntacticDiagnostics(sourceFile),
46
65
  ...program.getSemanticDiagnostics(sourceFile),
@@ -57,6 +76,21 @@ export function collectAbideDiagnostics(shadow: ShadowProgram): AbideDiagnostic[
57
76
  if (located === undefined) {
58
77
  continue
59
78
  }
79
+ /* Drop the diagnostics a bare async read (ADR-0032) provokes spuriously: the runtime
80
+ peeks the resolved value (`undefined` while pending), so a `?.` read of a real member
81
+ and an `{#if}` on the promise are valid — the raw-`Promise` shadow can't see that. */
82
+ if (
83
+ located.start >= templateStart &&
84
+ isSpuriousAsyncReadDiagnostic(
85
+ sourceFile,
86
+ checker,
87
+ diagnostic.code,
88
+ diagnostic.start,
89
+ diagnostic.length ?? 0,
90
+ )
91
+ ) {
92
+ continue
93
+ }
60
94
  diagnostics.push({
61
95
  file: abidePath,
62
96
  start: located.start,
@@ -65,6 +99,68 @@ export function collectAbideDiagnostics(shadow: ShadowProgram): AbideDiagnostic[
65
99
  category: diagnostic.category,
66
100
  })
67
101
  }
102
+ /* Stage E parity (ADR-0019): the build front-end (`lowerAsyncInterpolations`) throws on a
103
+ promise/asyncIterable in a NON-content value position; mirror it here as a diagnostic so
104
+ `abide check`/the LSP surface the same error. The shadow already type-checks these
105
+ spans, so their offsets map through the same `mappings`; classify each against the
106
+ checker and emit an Error for any async value the guard rejects. */
107
+ collectValuePositionDiagnostics(abidePath, sourceFile, mappings, checker, diagnostics)
68
108
  }
69
109
  return diagnostics
70
110
  }
111
+
112
+ /* Parses the component template, walks its value-position interpolations, and pushes a diagnostic
113
+ for any promise/asyncIterable the Stage E guard rejects. Classifies via the shadow: map the
114
+ expression's source offset into shadow coordinates, find its emitted expression node, read its
115
+ checker type. Fail-open — an unparseable template or unmappable span contributes nothing, so a
116
+ type hiccup degrades to no extra diagnostic instead of throwing. */
117
+ function collectValuePositionDiagnostics(
118
+ abidePath: string,
119
+ shadowFile: ts.SourceFile,
120
+ mappings: ShadowMapping[],
121
+ checker: ts.TypeChecker,
122
+ diagnostics: AbideDiagnostic[],
123
+ ): void {
124
+ const source = ts.sys.readFile(abidePath)
125
+ if (source === undefined) {
126
+ return
127
+ }
128
+ /* The template starts just past the leading `<script>` — the SAME base `compileShadow` parses
129
+ from, so each interpolation's `loc` lines up with the shadow's source→shadow `mappings`. */
130
+ const templateStart = templateStartOffset(source)
131
+ /* The recovering core never throws — it returns best-effort `nodes` PLUS every parse
132
+ diagnostic. Surface each with the `file` + `category` the parser can't know, so the LSP
133
+ reports parse errors from mid-edit source instead of fail-opening on the first throw. */
134
+ const parsed = parseTemplateRecovering(source.slice(templateStart), templateStart)
135
+ const nodes = parsed.nodes
136
+ for (const parseDiagnostic of parsed.diagnostics) {
137
+ diagnostics.push({
138
+ file: abidePath,
139
+ start: parseDiagnostic.start,
140
+ length: parseDiagnostic.length,
141
+ message: parseDiagnostic.message,
142
+ category: ts.DiagnosticCategory.Error,
143
+ })
144
+ }
145
+ for (const interpolation of asyncValuePositionInterpolations(nodes)) {
146
+ const shadowOffset = sourceToShadowOffset(mappings, interpolation.loc)
147
+ if (shadowOffset === undefined) {
148
+ continue
149
+ }
150
+ const node = nodeAtShadowOffset(shadowFile, shadowOffset, interpolation.code.length)
151
+ if (node === undefined) {
152
+ continue
153
+ }
154
+ const kind = classifyInterpolationType(checker.getTypeAtLocation(node), node, checker)
155
+ const message = asyncValuePositionError(kind, interpolation.position)
156
+ if (message !== undefined) {
157
+ diagnostics.push({
158
+ file: abidePath,
159
+ start: interpolation.loc,
160
+ length: interpolation.code.length,
161
+ message,
162
+ category: ts.DiagnosticCategory.Error,
163
+ })
164
+ }
165
+ }
166
+ }
@@ -2,6 +2,8 @@ import { analyzeComponent } from './analyzeComponent.ts'
2
2
  import { generateBuild } from './generateBuild.ts'
3
3
  import { hoistCells } from './hoistCells.ts'
4
4
  import type { AnalyzedComponent } from './types/AnalyzedComponent.ts'
5
+ import type { InterpolationClassifier } from './types/InterpolationClassifier.ts'
6
+ import type { SeedTypeClassifier } from './types/SeedTypeClassifier.ts'
5
7
 
6
8
  /*
7
9
  Compiles a single-file abide component into the body of a client build function.
@@ -19,10 +21,24 @@ export function compileComponent(
19
21
  source: string,
20
22
  isLayout = false,
21
23
  scopeSeed?: string,
22
- analyzed: AnalyzedComponent = analyzeComponent(source, scopeSeed),
24
+ analyzed?: AnalyzedComponent,
25
+ classify?: InterpolationClassifier,
26
+ seedClassify?: SeedTypeClassifier,
23
27
  ): string {
24
- const { script, stateNames, derivedNames, computedNames, nodes } = analyzed
25
- const build = generateBuild(nodes, 'host', stateNames, derivedNames, computedNames, isLayout)
28
+ /* `analyzed` is shared by `compileModule` (analyzed once, classifiers already applied);
29
+ a direct caller (tests) omits it and the front-end runs here — threading `classify` and
30
+ `seedClassify` so type-directed interpolation + cell lowering happen on this path too. */
31
+ const resolved = analyzed ?? analyzeComponent(source, scopeSeed, classify, seedClassify)
32
+ const { script, stateNames, derivedNames, computedNames, cellReadNames, nodes } = resolved
33
+ const build = generateBuild(
34
+ nodes,
35
+ 'host',
36
+ stateNames,
37
+ derivedNames,
38
+ computedNames,
39
+ isLayout,
40
+ cellReadNames,
41
+ )
26
42
  /* The scoped CSS is bundled into the entry stylesheet (see `abideUiPlugin`), not
27
43
  injected at runtime; the build only needs the `data-a-…` scope attributes on
28
44
  elements, which `generateBuild` reads from each node's annotated `scopes`. */
@@ -1,11 +1,12 @@
1
1
  import ts from 'typescript'
2
2
  import { ABIDE_PACKAGE_NAME } from '../../shared/ABIDE_PACKAGE_NAME.ts'
3
3
  import { analyzeComponent } from './analyzeComponent.ts'
4
- import { assertRuntimeHelpersBound } from './assertRuntimeHelpersBound.ts'
5
4
  import { assertTranspiles } from './assertTranspiles.ts'
6
5
  import { compileComponent } from './compileComponent.ts'
7
6
  import { compileSSR } from './compileSSR.ts'
8
7
  import type { AnalyzedComponent } from './types/AnalyzedComponent.ts'
8
+ import type { InterpolationClassifier } from './types/InterpolationClassifier.ts'
9
+ import type { SeedTypeClassifier } from './types/SeedTypeClassifier.ts'
9
10
  import { UI_RUNTIME_IMPORTS } from './UI_RUNTIME_IMPORTS.ts'
10
11
 
11
12
  /*
@@ -26,52 +27,34 @@ what the `.abide` bundler loader emits.
26
27
  */
27
28
  export function compileModule(
28
29
  source: string,
29
- options: { isLayout?: boolean; moduleId?: string; hot?: boolean } = {},
30
+ options: {
31
+ isLayout?: boolean
32
+ moduleId?: string
33
+ /* Type-directed interpolation lowering (ADR-0019): the warm shadow classifier the
34
+ bundler plugin builds per `.abide`. Optional and fail-open — absent, the module
35
+ compiles exactly as before (every interpolation binds as a plain value). */
36
+ classify?: InterpolationClassifier
37
+ /* Type-directed cell lowering (ADR-0023): the seed classifier the plugin builds over
38
+ the SAME warm shadow program. Optional and fail-open — absent, a no-marker
39
+ `computed(seed)` routes by the `isBareCallComputed` syntax heuristic (today's behavior). */
40
+ seedClassify?: SeedTypeClassifier
41
+ } = {},
30
42
  ): { code: string; styles: AnalyzedComponent['styles'] } {
31
43
  const isLayout = options.isLayout ?? false
32
44
  /* Run the shared front-end once and feed it to both back-ends — the analysis is
33
45
  pure over (source, moduleId), so the client and SSR builds reuse one parse
34
46
  instead of re-running it. `imports` (hoisted child-component imports) and the
35
- per-element scopes both come from this single pass. */
36
- const analyzed = analyzeComponent(source, options.moduleId)
47
+ per-element scopes both come from this single pass. The classifier (when present)
48
+ lowers promise-typed interpolations here, so both back-ends see one lowered tree. */
49
+ const analyzed = analyzeComponent(
50
+ source,
51
+ options.moduleId,
52
+ options.classify,
53
+ options.seedClassify,
54
+ )
37
55
  const userImports = analyzed.imports
38
56
  const body = indent(compileComponent(source, isLayout, options.moduleId, analyzed))
39
57
 
40
- /* Hot module (dev component HMR): the same client build, but its runtime comes
41
- from the live bundle via `window.__abide` — so it shares the one reactive graph
42
- and instance registry, not fresh copies — and on load it hands the new factory
43
- to `hotReplace`, which disposes + re-runs every live instance in place. No SSR /
44
- hydrate / export: it is imported only to replace, never mounted fresh. Supports
45
- leaf components today; one importing children falls back to a reload (the dev
46
- layer decides what to hot-swap). */
47
- if (options.hot) {
48
- /* Bridge keys are the bare source names; bind each to its emitted local (`$$`
49
- alias when set), so the hot body's `$$mountChild(...)` resolves. */
50
- const names = UI_RUNTIME_IMPORTS.map((entry) =>
51
- entry.alias === undefined || entry.alias === entry.name
52
- ? entry.name
53
- : `${entry.name}: ${entry.alias}`,
54
- ).join(', ')
55
- const id = JSON.stringify(options.moduleId)
56
- /* Hot mode never imports the scoped CSS (it reuses the live bundle's sheet), so
57
- styles are empty here regardless of the analyzed blocks. */
58
- return {
59
- code: `const { ${names}, hotReplace } = window.__abide
60
- ${userImports}
61
- function build(host, $props) {
62
- ${body}
63
- }
64
- function component(host, $props) {
65
- return $$mount(host, build, $props)
66
- }
67
- component.build = build
68
- component.__abideId = ${id}
69
- if (!hotReplace(${id}, component)) location.reload()
70
- `,
71
- styles: [],
72
- }
73
- }
74
-
75
58
  const ssrBody = indent(compileSSR(source, isLayout, options.moduleId, analyzed))
76
59
  const moduleBody = `function build(host, $props) {
77
60
  ${body}
@@ -95,7 +78,7 @@ component.hydrate = hydrateInto
95
78
  /* The bare build, so a parent can range-mount this as a nested child (no wrapper). */
96
79
  component.build = build
97
80
  component.hydratable = ${analyzed.hydratable}
98
- ${options.moduleId === undefined ? '' : `component.__abideId = ${JSON.stringify(options.moduleId)}\n`}`
81
+ `
99
82
  /* Per-component dead-import elimination: emit only the runtime helpers this module
100
83
  references. A component using no `each`/`await`/`html` shouldn't drag those modules
101
84
  into its chunk, and the package isn't globally side-effect-free (the dev/runtime
@@ -107,13 +90,10 @@ ${options.moduleId === undefined ? '' : `component.__abideId = ${JSON.stringify(
107
90
  string/comment/HTML literal (e.g. an `on`-attribute in static markup) no longer
108
91
  forces a spurious import, so no per-surface scoping is needed: a client-only helper
109
92
  simply doesn't appear as an identifier in the SSR body. */
110
- /* Parse the generated bodies ONCE and feed the single tree to both AST passes: the
111
- dead-import filter (`collectIdentifiers`) and the binding backstop
112
- (`assertRuntimeHelpersBound`). The import block isn't in this tree yet — it is derived
113
- from the filter's result so the backstop is told the names that block will bind
114
- (`importedHelpers`), which is exactly what it would have read from the prepended imports
115
- had it re-parsed the whole module. `setParentNodes` is required by the backstop's
116
- `getStart`/line lookups. */
93
+ /* Parse the generated bodies ONCE and feed the tree to the dead-import filter
94
+ (`collectIdentifiers`) and the reactive-import backstop below. The import block isn't in
95
+ this tree yet — it is derived from the filter's result. `setParentNodes` lets
96
+ `collectValueReferences` distinguish a value use from a property name. */
117
97
  const bodySource = ts.createSourceFile(
118
98
  'module.ts',
119
99
  `${userImports}\n${moduleBody}`,
@@ -161,17 +141,6 @@ ${moduleBody}`
161
141
  template shape no test exercises) otherwise ships as a broken bundle; this surfaces
162
142
  it as a located compile error for every component. */
163
143
  assertTranspiles(module, 'component module generation')
164
- /* `assertTranspiles` only proves the output PARSES — a call to an un-imported helper is
165
- valid syntax, so it slips through. This second guard proves the output is BOUND: every
166
- runtime helper it calls is actually imported (an independent check of the dead-import
167
- filter above), turning a runtime `ReferenceError` into a located compile error. It walks
168
- the SAME tree the filter just parsed, with the kept helper imports supplied as the bound
169
- set the prepended import block provides. */
170
- assertRuntimeHelpersBound(
171
- bodySource,
172
- new Set(keptImports.map((entry) => entry.alias ?? entry.name)),
173
- 'component module generation',
174
- )
175
144
  return { code: module, styles: analyzed.styles }
176
145
  }
177
146
 
@@ -2,6 +2,8 @@ import { analyzeComponent } from './analyzeComponent.ts'
2
2
  import { generateSSR } from './generateSSR.ts'
3
3
  import { SSR_ESCAPE } from './SSR_ESCAPE.ts'
4
4
  import type { AnalyzedComponent } from './types/AnalyzedComponent.ts'
5
+ import type { InterpolationClassifier } from './types/InterpolationClassifier.ts'
6
+ import type { SeedTypeClassifier } from './types/SeedTypeClassifier.ts'
5
7
 
6
8
  /*
7
9
  Compiles a component into the body of a server render function. Runs the shared
@@ -18,12 +20,12 @@ Effects are stripped — they are client lifecycle and emit no HTML, so the serv
18
20
  render is a snapshot of the markup before any effect runs.
19
21
 
20
22
  Defines `$$model` via the lowered script; the reactive scope is entered via `$$enterScope`
21
- and exited in a `finally` block. The block-id counter is
22
- the request-local `$ctx` (threaded into child renders), not a module global — a blocking
23
- `await` block awaits its promise at its structural position and renders inline, so ids
24
- allocate depth-first like the client; render yields at that `await`, and a shared global
25
- counter would interleave across concurrent requests. `$ctx` defaults to a fresh counter
26
- when a caller (a test, a top-level render) omits it.
23
+ and exited in a `finally` block. The block-id counter is the request-local `$ctx` — a
24
+ per-render-path `Map` (ADR-0037), threaded into child renders not a module global. Each
25
+ `await`/`try` block draws `$$blockId($ctx)` = `${render-path}:${n}`, counting per path in
26
+ document order; namespacing by path (rather than one flat counter) keeps ids congruent with
27
+ the client even when sibling child renders run concurrently, and isolates concurrent requests.
28
+ `$ctx` defaults to a fresh `Map` when a caller (a test, a top-level render) omits it.
27
29
 
28
30
  The body is wrapped in an ASYNC IIFE (returns `Promise<SsrRender>`) ONLY when it contains
29
31
  an inline `await` — a blocking `{#await … then}` block, a child-component render, a `<slot>`
@@ -43,17 +45,54 @@ export function compileSSR(
43
45
  source: string,
44
46
  isLayout = false,
45
47
  scopeSeed?: string,
46
- analyzed: AnalyzedComponent = analyzeComponent(source, scopeSeed),
48
+ analyzed?: AnalyzedComponent,
49
+ classify?: InterpolationClassifier,
50
+ seedClassify?: SeedTypeClassifier,
47
51
  ): string {
48
- const { ssrScript: lowered, stateNames, derivedNames, computedNames, nodes } = analyzed
49
- const ssr = generateSSR(nodes, stateNames, derivedNames, computedNames, isLayout)
52
+ /* `analyzed` is shared by `compileModule` (analyzed once, classifiers already applied);
53
+ a direct caller (tests) omits it and the front-end runs here — threading `classify` and
54
+ `seedClassify` so type-directed interpolation + cell lowering happen on this path too. */
55
+ const resolved = analyzed ?? analyzeComponent(source, scopeSeed, classify, seedClassify)
56
+ const {
57
+ ssrScript: lowered,
58
+ stateNames,
59
+ derivedNames,
60
+ computedNames,
61
+ cellReadNames,
62
+ nodes,
63
+ } = resolved
64
+ const {
65
+ body: ssr,
66
+ flightDecls,
67
+ hasStagedChildren,
68
+ } = generateSSR(nodes, stateNames, derivedNames, computedNames, isLayout, cellReadNames)
69
+ /* ADR-0039: a component with hoistable children declares `$childSlots` (the body walk reserves an
70
+ output slot per child) and, after the walk, awaits `$$finalizeStreamedChildren` — which fills
71
+ each slot inline (settled child, byte-identical to the old inline await) or with a streaming
72
+ boundary (still-pending child). Empty for a component with no hoistable child, which stays
73
+ synchronous. */
74
+ const childSlotsDecl = hasStagedChildren ? 'const $childSlots = [];\n' : ''
75
+ const finalizeChildren = hasStagedChildren
76
+ ? 'await $$finalizeStreamedChildren($childSlots, $awaits, $resume);\n'
77
+ : ''
78
+ /* The Tier-2 await-barrier (ADR-0019): between the lowered cell declarations and the
79
+ template, drain + await every async cell's in-flight promise so the template's
80
+ `$$readCell(name)` peeks the RESOLVED value and it bakes into the first-pass HTML —
81
+ single render pass, no client refetch. Emitted whenever the component declares a cell
82
+ (`cellReadNames`: every `linked` / async or bare-call `computed`); the barrier only
83
+ awaits promises a cell actually registered server-side (a sync/stream cell registers
84
+ none), so it is a cheap no-op for a component whose cells all settled synchronously. */
85
+ const barrier = cellReadNames.size > 0 ? 'await $$settleAsyncCells();\n' : ''
50
86
  /* No `<style>` in the markup — the scoped CSS is bundled into the entry stylesheet
51
87
  the shell links (see `abideUiPlugin`), so SSR output is styled by that sheet. The
52
88
  elements still carry their `data-a-…` scopes via `generateSSR`. */
53
89
  /* `typeof model` guards a component with no reactive state (a pure-async or
54
90
  static component declares no `model`); its snapshot is then empty. */
91
+ /* ADR-0034 flight declarations sit AFTER the lowered script (so their promises can read the
92
+ component's signals) and BEFORE the barrier (so a hoisted flight is already in-flight while
93
+ the barrier awaits any unrelated blocking cell). Empty when nothing hoisted. */
55
94
  const body =
56
- `const $scope = $$enterScope();\ntry {\n${lowered}\n${SSR_ESCAPE}\nconst $out = [];\nconst $awaits = [];\nconst $resume = {};\n${ssr}` +
95
+ `const $scope = $$enterScope();\ntry {\n${lowered}\n${flightDecls}${SSR_ESCAPE}\nconst $out = [];\nconst $awaits = [];\n${childSlotsDecl}const $resume = {};\n${barrier}${ssr}${finalizeChildren}` +
57
96
  `return { html: $out.join(''), state: (typeof $$model !== 'undefined' ? $$model.snapshot() : {}), awaits: $awaits, resume: $resume };\n` +
58
97
  `} finally { $$exitScope($scope); }`
59
98
  /* An inline `await` — a blocking await block, a child render, a slot read, or a
@@ -63,6 +102,6 @@ export function compileSSR(
63
102
  top-level `await` in a non-async function (a SyntaxError). `(?!:)` excludes the
64
103
  `<!--abide:await:N-->` boundary-marker strings; `\b` excludes `$awaits`. A false
65
104
  positive (the token in author text) only costs a needless async wrapper, never a crash. */
66
- const needsAsync = /\bawait\b(?!:)/.test(`${lowered}${ssr}`)
67
- return `var $ctx = $ctx || { next: 0 };\n${needsAsync ? `return (async () => {\n${body}\n})();` : body}`
105
+ const needsAsync = hasStagedChildren || /\bawait\b(?!:)/.test(`${lowered}${ssr}${barrier}`)
106
+ return `var $ctx = $ctx || new Map();\n${needsAsync ? `return (async () => {\n${body}\n})();` : body}`
68
107
  }