@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.
- package/CHANGELOG.md +607 -0
- package/LICENSE +21 -0
- package/README.md +154 -0
- package/bin/abide.ts +212 -0
- package/package.json +155 -0
- package/src/abideLsp.ts +211 -0
- package/src/abideModules.d.ts +8 -0
- package/src/abideResolverPlugin.ts +923 -0
- package/src/appEntry.ts +151 -0
- package/src/assets/app.html +12 -0
- package/src/build.ts +143 -0
- package/src/buildCli.ts +127 -0
- package/src/buildDisconnected.ts +118 -0
- package/src/bundleApp.ts +147 -0
- package/src/bundleDisconnectedEntry.ts +14 -0
- package/src/checkAbide.ts +77 -0
- package/src/cliEntry.ts +25 -0
- package/src/clientBuildPlugins.ts +33 -0
- package/src/clientEntry.ts +17 -0
- package/src/compile.ts +63 -0
- package/src/controlServerWorker.ts +426 -0
- package/src/devEntry.ts +250 -0
- package/src/discoveryEntry.ts +81 -0
- package/src/lib/bundle/BundleMenu.ts +12 -0
- package/src/lib/bundle/BundleMenuItem.ts +25 -0
- package/src/lib/bundle/BundleWindow.ts +37 -0
- package/src/lib/bundle/WEBVIEW_BUILD_REVISION.ts +9 -0
- package/src/lib/bundle/WEBVIEW_VERSION.ts +7 -0
- package/src/lib/bundle/bindConnectedFlag.ts +29 -0
- package/src/lib/bundle/bindRequestNavigate.ts +34 -0
- package/src/lib/bundle/buildWebviewLib.ts +111 -0
- package/src/lib/bundle/bundled.ts +35 -0
- package/src/lib/bundle/disconnected.abide +236 -0
- package/src/lib/bundle/disconnected.css +9 -0
- package/src/lib/bundle/ensureWebviewLib.ts +20 -0
- package/src/lib/bundle/exitWithParent.ts +28 -0
- package/src/lib/bundle/infoPlist.ts +46 -0
- package/src/lib/bundle/installDownloads.ts +24 -0
- package/src/lib/bundle/installMacMenu.ts +39 -0
- package/src/lib/bundle/listenLocalControlServer.ts +19 -0
- package/src/lib/bundle/native/abideMenu.mm +422 -0
- package/src/lib/bundle/native/webview.h +4557 -0
- package/src/lib/bundle/onMenu.ts +42 -0
- package/src/lib/bundle/openWebview.ts +104 -0
- package/src/lib/bundle/pngToIcns.ts +47 -0
- package/src/lib/bundle/probeAbideServer.ts +57 -0
- package/src/lib/bundle/resolveServerBinary.ts +12 -0
- package/src/lib/bundle/resolveWebviewLib.ts +53 -0
- package/src/lib/bundle/serverBinaryFilename.ts +8 -0
- package/src/lib/bundle/signMacApp.ts +37 -0
- package/src/lib/bundle/spawnEmbeddedServer.ts +64 -0
- package/src/lib/bundle/stableLocalPort.ts +19 -0
- package/src/lib/bundle/waitForServer.ts +23 -0
- package/src/lib/bundle/webviewCachePath.ts +23 -0
- package/src/lib/bundle/webviewLibName.ts +11 -0
- package/src/lib/cli/connectToServer.ts +23 -0
- package/src/lib/cli/createClient.ts +108 -0
- package/src/lib/cli/dispatchCommand.ts +71 -0
- package/src/lib/cli/loadEnvFromBinaryDir.ts +15 -0
- package/src/lib/cli/parseArgvForRpc.ts +100 -0
- package/src/lib/cli/printHelp.ts +119 -0
- package/src/lib/cli/printSessionHelp.ts +27 -0
- package/src/lib/cli/printSessionStatus.ts +21 -0
- package/src/lib/cli/printTrimmed.ts +8 -0
- package/src/lib/cli/printValue.ts +10 -0
- package/src/lib/cli/resolveCliTarget.ts +48 -0
- package/src/lib/cli/runCli.ts +176 -0
- package/src/lib/cli/runSession.ts +108 -0
- package/src/lib/cli/startLocalInstance.ts +14 -0
- package/src/lib/cli/tokenizeLine.ts +51 -0
- package/src/lib/cli/types/CliManifest.ts +9 -0
- package/src/lib/cli/types/CliManifestEntry.ts +17 -0
- package/src/lib/cli/types/CliTarget.ts +13 -0
- package/src/lib/mcp/annotationsForMethod.ts +29 -0
- package/src/lib/mcp/createMcpResourceServer.ts +102 -0
- package/src/lib/mcp/createMcpServer.ts +48 -0
- package/src/lib/mcp/dispatchMcpRequest.ts +138 -0
- package/src/lib/mcp/mcpResourceServerSlot.ts +18 -0
- package/src/lib/mcp/mcpSurface.ts +295 -0
- package/src/lib/mcp/toolResultFromResponse.ts +66 -0
- package/src/lib/mcp/types/JsonRpcRequest.ts +12 -0
- package/src/lib/mcp/types/JsonRpcResponse.ts +20 -0
- package/src/lib/mcp/types/McpResourceContents.ts +10 -0
- package/src/lib/mcp/types/McpResourceDescriptor.ts +6 -0
- package/src/lib/mcp/types/McpResourceServer.ts +12 -0
- package/src/lib/mcp/types/McpServer.ts +9 -0
- package/src/lib/mcp/types/McpServerOptions.ts +16 -0
- package/src/lib/server/AppModule.ts +47 -0
- package/src/lib/server/DELETE.ts +10 -0
- package/src/lib/server/GET.ts +10 -0
- package/src/lib/server/HEAD.ts +10 -0
- package/src/lib/server/PATCH.ts +10 -0
- package/src/lib/server/POST.ts +10 -0
- package/src/lib/server/PUT.ts +10 -0
- package/src/lib/server/agent.ts +86 -0
- package/src/lib/server/appDataDir.ts +16 -0
- package/src/lib/server/cli/buildEnvContent.ts +19 -0
- package/src/lib/server/cli/createTarGz.ts +77 -0
- package/src/lib/server/cli/handleCliDownload.ts +150 -0
- package/src/lib/server/cli/handleCliInstall.ts +37 -0
- package/src/lib/server/cli/installScript.ts +31 -0
- package/src/lib/server/cli/maxSourceMtime.ts +26 -0
- package/src/lib/server/cookies.ts +30 -0
- package/src/lib/server/env.ts +51 -0
- package/src/lib/server/error.ts +73 -0
- package/src/lib/server/json.ts +42 -0
- package/src/lib/server/jsonl.ts +47 -0
- package/src/lib/server/prompts/definePrompt.ts +21 -0
- package/src/lib/server/prompts/promptRegistry.ts +9 -0
- package/src/lib/server/prompts/registerPrompt.ts +6 -0
- package/src/lib/server/prompts/renderPromptTemplate.ts +17 -0
- package/src/lib/server/prompts/types/Prompt.ts +13 -0
- package/src/lib/server/prompts/types/PromptOptions.ts +12 -0
- package/src/lib/server/prompts/types/PromptRegistryEntry.ts +13 -0
- package/src/lib/server/prompts/types/PromptRoutes.ts +10 -0
- package/src/lib/server/reachable.ts +45 -0
- package/src/lib/server/redirect.ts +43 -0
- package/src/lib/server/request.ts +19 -0
- package/src/lib/server/rpc/defineVerb.ts +210 -0
- package/src/lib/server/rpc/dispatchVerbInProcess.ts +46 -0
- package/src/lib/server/rpc/findVerbByCommandName.ts +18 -0
- package/src/lib/server/rpc/parseArgs.ts +127 -0
- package/src/lib/server/rpc/readBodyWithinLimit.ts +44 -0
- package/src/lib/server/rpc/registerVerb.ts +6 -0
- package/src/lib/server/rpc/runWithVerbTimeout.ts +49 -0
- package/src/lib/server/rpc/types/RemoteHandler.ts +27 -0
- package/src/lib/server/rpc/types/RemoteRoutes.ts +13 -0
- package/src/lib/server/rpc/types/TypedResponse.ts +18 -0
- package/src/lib/server/rpc/types/VerbHelper.ts +87 -0
- package/src/lib/server/rpc/types/VerbRegistryEntry.ts +35 -0
- package/src/lib/server/rpc/unprocessed.ts +14 -0
- package/src/lib/server/rpc/verbRegistry.ts +11 -0
- package/src/lib/server/runtime/DEFAULT_PORT.ts +6 -0
- package/src/lib/server/runtime/DEV_READY_MESSAGE.ts +6 -0
- package/src/lib/server/runtime/DEV_REBUILD_MESSAGE.ts +4 -0
- package/src/lib/server/runtime/DEV_RELOAD_CLIENT_SCRIPT.ts +107 -0
- package/src/lib/server/runtime/SSR_SWAP_SCRIPT.ts +16 -0
- package/src/lib/server/runtime/acceptsGzip.ts +24 -0
- package/src/lib/server/runtime/buildCacheSnapshot.ts +61 -0
- package/src/lib/server/runtime/buildHealthPayload.ts +34 -0
- package/src/lib/server/runtime/buildInspectorSurface.ts +37 -0
- package/src/lib/server/runtime/buildOpenApiSpec.ts +106 -0
- package/src/lib/server/runtime/cacheControlForAsset.ts +22 -0
- package/src/lib/server/runtime/containsTraversal.ts +37 -0
- package/src/lib/server/runtime/createAppAssetServer.ts +76 -0
- package/src/lib/server/runtime/createAssetHeaderCache.ts +31 -0
- package/src/lib/server/runtime/createPublicAssetServer.ts +67 -0
- package/src/lib/server/runtime/createReachable.ts +109 -0
- package/src/lib/server/runtime/createRouteDispatcher.ts +127 -0
- package/src/lib/server/runtime/createServer.ts +674 -0
- package/src/lib/server/runtime/createUiPageRenderer.ts +181 -0
- package/src/lib/server/runtime/crossOriginForbidden.ts +17 -0
- package/src/lib/server/runtime/crossOriginGate.ts +29 -0
- package/src/lib/server/runtime/devClientFingerprint.ts +117 -0
- package/src/lib/server/runtime/devHotModuleResponse.ts +40 -0
- package/src/lib/server/runtime/devReloadResponse.ts +41 -0
- package/src/lib/server/runtime/disableIdleTimeoutForStream.ts +27 -0
- package/src/lib/server/runtime/envSchemaStore.ts +15 -0
- package/src/lib/server/runtime/findOpenPort.ts +21 -0
- package/src/lib/server/runtime/getActiveServer.ts +6 -0
- package/src/lib/server/runtime/globToPathSet.ts +29 -0
- package/src/lib/server/runtime/gzipResponse.ts +46 -0
- package/src/lib/server/runtime/inProcessServer.ts +20 -0
- package/src/lib/server/runtime/internalErrorResponse.ts +25 -0
- package/src/lib/server/runtime/isCrossOriginRequest.ts +23 -0
- package/src/lib/server/runtime/listenOnOpenPort.ts +36 -0
- package/src/lib/server/runtime/logExposedSurfaces.ts +156 -0
- package/src/lib/server/runtime/maybeMountInspector.ts +97 -0
- package/src/lib/server/runtime/mimeForExtension.ts +14 -0
- package/src/lib/server/runtime/pageUrlFromStore.ts +15 -0
- package/src/lib/server/runtime/parseIdleTimeout.ts +10 -0
- package/src/lib/server/runtime/parsePort.ts +11 -0
- package/src/lib/server/runtime/registryManifests.ts +66 -0
- package/src/lib/server/runtime/requestContext.ts +5 -0
- package/src/lib/server/runtime/resolvePageSnapshot.ts +25 -0
- package/src/lib/server/runtime/respondWithEmbeddedAsset.ts +18 -0
- package/src/lib/server/runtime/runWithRequestScope.ts +150 -0
- package/src/lib/server/runtime/safeJsonForScript.ts +17 -0
- package/src/lib/server/runtime/serializeCacheSnapshot.ts +45 -0
- package/src/lib/server/runtime/serverSlot.ts +13 -0
- package/src/lib/server/runtime/setActiveServer.ts +6 -0
- package/src/lib/server/runtime/snapshotEntryFromCache.ts +83 -0
- package/src/lib/server/runtime/streamCacheResolutions.ts +37 -0
- package/src/lib/server/runtime/streamFromIterator.ts +86 -0
- package/src/lib/server/runtime/types/Assets.ts +6 -0
- package/src/lib/server/runtime/types/DevReloadStamp.ts +18 -0
- package/src/lib/server/runtime/types/InspectorCacheEntry.ts +24 -0
- package/src/lib/server/runtime/types/InspectorCacheSnapshot.ts +11 -0
- package/src/lib/server/runtime/types/InspectorContext.ts +30 -0
- package/src/lib/server/runtime/types/InspectorSocket.ts +17 -0
- package/src/lib/server/runtime/types/InspectorSurface.ts +13 -0
- package/src/lib/server/runtime/types/InspectorVerb.ts +27 -0
- package/src/lib/server/runtime/types/RequestStore.ts +55 -0
- package/src/lib/server/runtime/warnUnguardedMcp.ts +32 -0
- package/src/lib/server/runtime/withResponseDefaults.ts +24 -0
- package/src/lib/server/server.ts +33 -0
- package/src/lib/server/socket.ts +32 -0
- package/src/lib/server/sockets/createSocketDispatcher.ts +337 -0
- package/src/lib/server/sockets/defineSocket.ts +179 -0
- package/src/lib/server/sockets/lookupSocket.ts +6 -0
- package/src/lib/server/sockets/registerSocket.ts +6 -0
- package/src/lib/server/sockets/socketOperations.ts +36 -0
- package/src/lib/server/sockets/socketRegistry.ts +9 -0
- package/src/lib/server/sockets/types/Socket.ts +23 -0
- package/src/lib/server/sockets/types/SocketClientFrame.ts +19 -0
- package/src/lib/server/sockets/types/SocketOperation.ts +22 -0
- package/src/lib/server/sockets/types/SocketOptions.ts +26 -0
- package/src/lib/server/sockets/types/SocketRegistryEntry.ts +19 -0
- package/src/lib/server/sockets/types/SocketRoutes.ts +10 -0
- package/src/lib/server/sockets/types/SocketServerFrame.ts +24 -0
- package/src/lib/server/sse.ts +54 -0
- package/src/lib/shared/ABIDE_PACKAGE_NAME.ts +7 -0
- package/src/lib/shared/ABIDE_VERSION.ts +9 -0
- package/src/lib/shared/CACHE_CONTROL_VALUES.ts +16 -0
- package/src/lib/shared/CACHE_WRAPPED.ts +8 -0
- package/src/lib/shared/CLI_PATH.ts +7 -0
- package/src/lib/shared/DEV_HOT_PREFIX.ts +7 -0
- package/src/lib/shared/DEV_RELOAD_PATH.ts +6 -0
- package/src/lib/shared/HEALTH_PATH.ts +7 -0
- package/src/lib/shared/HttpError.ts +20 -0
- package/src/lib/shared/IDENTITY_PATH.ts +6 -0
- package/src/lib/shared/INSPECTOR_PATH.ts +7 -0
- package/src/lib/shared/NAV_HEADER.ts +8 -0
- package/src/lib/shared/OFFLINE_HEADER.ts +8 -0
- package/src/lib/shared/REMOTE_FUNCTION.ts +8 -0
- package/src/lib/shared/REPLAYABLE_METHODS.ts +12 -0
- package/src/lib/shared/SOCKETS_PATH.ts +7 -0
- package/src/lib/shared/STREAMING_CONTENT_TYPES.ts +11 -0
- package/src/lib/shared/SocketDisconnectedError.ts +13 -0
- package/src/lib/shared/TEXT_PLAIN.ts +7 -0
- package/src/lib/shared/abideImportName.ts +44 -0
- package/src/lib/shared/abideLog.ts +38 -0
- package/src/lib/shared/activeCacheStore.ts +20 -0
- package/src/lib/shared/activePage.ts +25 -0
- package/src/lib/shared/appDataDir.ts +34 -0
- package/src/lib/shared/appNameSlot.ts +10 -0
- package/src/lib/shared/basePath.ts +10 -0
- package/src/lib/shared/basePathFromAppUrl.ts +20 -0
- package/src/lib/shared/baseSlot.ts +14 -0
- package/src/lib/shared/binaryDirEnvPath.ts +12 -0
- package/src/lib/shared/browserClientFlags.ts +10 -0
- package/src/lib/shared/buildRpcProxy.ts +39 -0
- package/src/lib/shared/buildRpcRequest.ts +70 -0
- package/src/lib/shared/buildSocketOverChannel.ts +58 -0
- package/src/lib/shared/bundleLayout.ts +36 -0
- package/src/lib/shared/cache.ts +951 -0
- package/src/lib/shared/cacheEntryFromSnapshot.ts +59 -0
- package/src/lib/shared/cacheStoreSlot.ts +16 -0
- package/src/lib/shared/cacheStores.ts +10 -0
- package/src/lib/shared/canonicalJson.ts +63 -0
- package/src/lib/shared/carriesBodyArgs.ts +13 -0
- package/src/lib/shared/clearLastConnection.ts +7 -0
- package/src/lib/shared/commandNameForUrl.ts +17 -0
- package/src/lib/shared/createCacheStore.ts +104 -0
- package/src/lib/shared/createChannelLog.ts +122 -0
- package/src/lib/shared/createLifecycleChannel.ts +56 -0
- package/src/lib/shared/createLivenessWatch.ts +118 -0
- package/src/lib/shared/createPushIterator.ts +127 -0
- package/src/lib/shared/createRemoteFunction.ts +122 -0
- package/src/lib/shared/createSubscriber.ts +55 -0
- package/src/lib/shared/createTraceContext.ts +21 -0
- package/src/lib/shared/dataDirEnvPath.ts +12 -0
- package/src/lib/shared/decodeResponse.ts +47 -0
- package/src/lib/shared/detectTarget.ts +27 -0
- package/src/lib/shared/detectVerbMethod.ts +17 -0
- package/src/lib/shared/emitLogRecord.ts +190 -0
- package/src/lib/shared/exeSuffix.ts +9 -0
- package/src/lib/shared/exitOnBuildFailure.ts +17 -0
- package/src/lib/shared/extraForwardHeaders.ts +16 -0
- package/src/lib/shared/fileStem.ts +9 -0
- package/src/lib/shared/findExportCallSite.ts +476 -0
- package/src/lib/shared/formatTraceparent.ts +6 -0
- package/src/lib/shared/forwardHeaders.ts +44 -0
- package/src/lib/shared/getRemoteMeta.ts +5 -0
- package/src/lib/shared/globalCacheStore.ts +15 -0
- package/src/lib/shared/globalCacheStoreSlot.ts +14 -0
- package/src/lib/shared/health.ts +179 -0
- package/src/lib/shared/healthReadSlot.ts +11 -0
- package/src/lib/shared/healthSeedSlot.ts +12 -0
- package/src/lib/shared/html.ts +38 -0
- package/src/lib/shared/importNamesToStrip.ts +13 -0
- package/src/lib/shared/invalidateEvent.ts +11 -0
- package/src/lib/shared/invalidateTripwire.ts +40 -0
- package/src/lib/shared/isAbideHealthPayload.ts +11 -0
- package/src/lib/shared/isCompileTarget.ts +15 -0
- package/src/lib/shared/isDebugEnabled.ts +26 -0
- package/src/lib/shared/isDebugNegated.ts +19 -0
- package/src/lib/shared/isModuleNotFound.ts +16 -0
- package/src/lib/shared/isReadOnlyMethod.ts +14 -0
- package/src/lib/shared/isReplayableMethod.ts +7 -0
- package/src/lib/shared/isStreamingResponse.ts +11 -0
- package/src/lib/shared/isSubscribable.ts +15 -0
- package/src/lib/shared/jsonSchemaForPromptArguments.ts +29 -0
- package/src/lib/shared/jsonSchemaForSchema.ts +39 -0
- package/src/lib/shared/jsonlErrorFrame.ts +24 -0
- package/src/lib/shared/keyForRemoteCall.ts +29 -0
- package/src/lib/shared/keyMatchesPrefix.ts +9 -0
- package/src/lib/shared/lastConnectionPath.ts +7 -0
- package/src/lib/shared/layoutChainForRoute.ts +22 -0
- package/src/lib/shared/loadEnvFile.ts +17 -0
- package/src/lib/shared/loadEnvFromDataDir.ts +14 -0
- package/src/lib/shared/log.ts +24 -0
- package/src/lib/shared/logClosingRecord.ts +28 -0
- package/src/lib/shared/logTapSlot.ts +13 -0
- package/src/lib/shared/manifestModule.ts +39 -0
- package/src/lib/shared/matchesDebugPattern.ts +16 -0
- package/src/lib/shared/memoizeByKey.ts +32 -0
- package/src/lib/shared/normalizeTarget.ts +10 -0
- package/src/lib/shared/online.ts +51 -0
- package/src/lib/shared/page.ts +30 -0
- package/src/lib/shared/pageSlot.ts +17 -0
- package/src/lib/shared/pageUrlForFile.ts +14 -0
- package/src/lib/shared/parseBoundedEnvInt.ts +20 -0
- package/src/lib/shared/parseDebugPatterns.ts +21 -0
- package/src/lib/shared/parseEnv.ts +30 -0
- package/src/lib/shared/parsePromptMarkdown.ts +35 -0
- package/src/lib/shared/parseRouteSegments.ts +22 -0
- package/src/lib/shared/parseTraceparent.ts +26 -0
- package/src/lib/shared/pending.ts +30 -0
- package/src/lib/shared/prepareRpcModule.ts +59 -0
- package/src/lib/shared/prepareSocketModule.ts +49 -0
- package/src/lib/shared/probeRegistries.ts +68 -0
- package/src/lib/shared/producerKey.ts +32 -0
- package/src/lib/shared/programNameForPackage.ts +14 -0
- package/src/lib/shared/promptNameForFile.ts +10 -0
- package/src/lib/shared/queryStringFromArgs.ts +27 -0
- package/src/lib/shared/randomHexId.ts +14 -0
- package/src/lib/shared/readEnvFile.ts +15 -0
- package/src/lib/shared/readLastConnection.ts +18 -0
- package/src/lib/shared/readPackageJson.ts +9 -0
- package/src/lib/shared/recordRemoteMeta.ts +5 -0
- package/src/lib/shared/refreshing.ts +31 -0
- package/src/lib/shared/remoteMetaStore.ts +16 -0
- package/src/lib/shared/requestScopeSlot.ts +15 -0
- package/src/lib/shared/resolveClientFlags.ts +20 -0
- package/src/lib/shared/responseErrorText.ts +9 -0
- package/src/lib/shared/rpcTimeoutSlot.ts +9 -0
- package/src/lib/shared/rpcUrlForFile.ts +19 -0
- package/src/lib/shared/runningAsStandaloneBinary.ts +13 -0
- package/src/lib/shared/selectorMatcher.ts +68 -0
- package/src/lib/shared/selectorPrefix.ts +39 -0
- package/src/lib/shared/serializeEnv.ts +18 -0
- package/src/lib/shared/setAppName.ts +5 -0
- package/src/lib/shared/setBaseResolver.ts +6 -0
- package/src/lib/shared/setCacheStoreResolver.ts +6 -0
- package/src/lib/shared/setGlobalCacheStoreResolver.ts +6 -0
- package/src/lib/shared/setPageResolver.ts +7 -0
- package/src/lib/shared/setRequestScopeResolver.ts +6 -0
- package/src/lib/shared/snippet.ts +25 -0
- package/src/lib/shared/socketNameForFile.ts +11 -0
- package/src/lib/shared/socketTapSlot.ts +12 -0
- package/src/lib/shared/sseErrorFrame.ts +29 -0
- package/src/lib/shared/streamResponse.ts +169 -0
- package/src/lib/shared/stripImport.ts +27 -0
- package/src/lib/shared/subscribableFromResponse.ts +51 -0
- package/src/lib/shared/tailProbeSlot.ts +16 -0
- package/src/lib/shared/toBunRoutePattern.ts +28 -0
- package/src/lib/shared/toScopeSet.ts +4 -0
- package/src/lib/shared/trace.ts +16 -0
- package/src/lib/shared/types/CacheEntry.ts +84 -0
- package/src/lib/shared/types/CacheInvalidation.ts +9 -0
- package/src/lib/shared/types/CacheOnContext.ts +25 -0
- package/src/lib/shared/types/CacheOptions.ts +39 -0
- package/src/lib/shared/types/CacheSelector.ts +17 -0
- package/src/lib/shared/types/CacheSnapshot.ts +16 -0
- package/src/lib/shared/types/CacheSnapshotEntry.ts +17 -0
- package/src/lib/shared/types/CacheStats.ts +13 -0
- package/src/lib/shared/types/CacheStore.ts +39 -0
- package/src/lib/shared/types/ChannelLog.ts +13 -0
- package/src/lib/shared/types/ClientFlags.ts +11 -0
- package/src/lib/shared/types/CompileTarget.ts +6 -0
- package/src/lib/shared/types/FrameworkLog.ts +13 -0
- package/src/lib/shared/types/HttpVerb.ts +1 -0
- package/src/lib/shared/types/LastConnection.ts +9 -0
- package/src/lib/shared/types/Log.ts +13 -0
- package/src/lib/shared/types/LogRecord.ts +42 -0
- package/src/lib/shared/types/LogVoice.ts +7 -0
- package/src/lib/shared/types/PageSnapshot.ts +14 -0
- package/src/lib/shared/types/PromptArgument.ts +12 -0
- package/src/lib/shared/types/RawRemoteFunction.ts +14 -0
- package/src/lib/shared/types/RemoteCallable.ts +12 -0
- package/src/lib/shared/types/RemoteFunction.ts +47 -0
- package/src/lib/shared/types/ReplayableMethod.ts +7 -0
- package/src/lib/shared/types/RequestScopeInfo.ts +16 -0
- package/src/lib/shared/types/RpcInvoker.ts +6 -0
- package/src/lib/shared/types/SocketChannel.ts +17 -0
- package/src/lib/shared/types/SocketSubCallbacks.ts +13 -0
- package/src/lib/shared/types/StandardSchemaV1.ts +56 -0
- package/src/lib/shared/types/StreamedResolution.ts +10 -0
- package/src/lib/shared/types/Subscribable.ts +26 -0
- package/src/lib/shared/types/TailHooks.ts +12 -0
- package/src/lib/shared/types/TailOptions.ts +10 -0
- package/src/lib/shared/types/TraceContext.ts +17 -0
- package/src/lib/shared/url.ts +118 -0
- package/src/lib/shared/withBase.ts +11 -0
- package/src/lib/shared/withBaseUrl.ts +17 -0
- package/src/lib/shared/withJsonSchema.ts +21 -0
- package/src/lib/shared/writeDts.ts +12 -0
- package/src/lib/shared/writeHealthDts.ts +36 -0
- package/src/lib/shared/writeLastConnection.ts +13 -0
- package/src/lib/shared/writePublicAssetsDts.ts +31 -0
- package/src/lib/shared/writeRoutesDts.ts +73 -0
- package/src/lib/shared/writeRpcDts.ts +49 -0
- package/src/lib/shared/writeTestRpcDts.ts +45 -0
- package/src/lib/shared/writeTestSocketsDts.ts +34 -0
- package/src/lib/test/assertAgentFrameConformance.ts +73 -0
- package/src/lib/test/createScriptedSurface.ts +45 -0
- package/src/lib/test/createTestApp.ts +203 -0
- package/src/lib/test/createTestSocketChannel.ts +142 -0
- package/src/lib/ui/README.md +86 -0
- package/src/lib/ui/compile/SSR_ESCAPE.ts +25 -0
- package/src/lib/ui/compile/UI_RUNTIME_IMPORTS.ts +36 -0
- package/src/lib/ui/compile/VOID_TAGS.ts +21 -0
- package/src/lib/ui/compile/abideUiPlugin.ts +65 -0
- package/src/lib/ui/compile/analyzeComponent.ts +117 -0
- package/src/lib/ui/compile/assetModulesFile.ts +32 -0
- package/src/lib/ui/compile/branchElements.ts +50 -0
- package/src/lib/ui/compile/collectAbideDiagnostics.ts +59 -0
- package/src/lib/ui/compile/compileComponent.ts +20 -0
- package/src/lib/ui/compile/compileModule.ts +116 -0
- package/src/lib/ui/compile/compileSSR.ts +36 -0
- package/src/lib/ui/compile/compileShadow.ts +352 -0
- package/src/lib/ui/compile/createShadowLanguageService.ts +197 -0
- package/src/lib/ui/compile/createShadowProgram.ts +96 -0
- package/src/lib/ui/compile/decodeHtmlEntities.ts +49 -0
- package/src/lib/ui/compile/desugarSignals.ts +133 -0
- package/src/lib/ui/compile/escapeHtml.ts +15 -0
- package/src/lib/ui/compile/generateBuild.ts +638 -0
- package/src/lib/ui/compile/generateSSR.ts +380 -0
- package/src/lib/ui/compile/groupBindParts.ts +28 -0
- package/src/lib/ui/compile/hoistCells.ts +120 -0
- package/src/lib/ui/compile/loadShadowTsConfig.ts +31 -0
- package/src/lib/ui/compile/lowerDocAccess.ts +202 -0
- package/src/lib/ui/compile/nearestProjectRoot.ts +16 -0
- package/src/lib/ui/compile/parseTemplate.ts +396 -0
- package/src/lib/ui/compile/partitionSlots.ts +36 -0
- package/src/lib/ui/compile/prepareNestedScript.ts +42 -0
- package/src/lib/ui/compile/remapShadowDiagnostic.ts +30 -0
- package/src/lib/ui/compile/renameSignalRefs.ts +85 -0
- package/src/lib/ui/compile/resolveAbideImports.ts +29 -0
- package/src/lib/ui/compile/scopeCss.ts +115 -0
- package/src/lib/ui/compile/shadowNaming.ts +11 -0
- package/src/lib/ui/compile/sourceToShadowOffset.ts +24 -0
- package/src/lib/ui/compile/staticAttrValue.ts +13 -0
- package/src/lib/ui/compile/stripEffects.ts +32 -0
- package/src/lib/ui/compile/types/AbideDiagnostic.ts +14 -0
- package/src/lib/ui/compile/types/AnalyzedComponent.ts +25 -0
- package/src/lib/ui/compile/types/CompiledShadow.ts +15 -0
- package/src/lib/ui/compile/types/TemplateAttr.ts +16 -0
- package/src/lib/ui/compile/types/TemplateNode.ts +78 -0
- package/src/lib/ui/compile/types/TextPart.ts +8 -0
- package/src/lib/ui/derived.ts +28 -0
- package/src/lib/ui/doc.ts +15 -0
- package/src/lib/ui/dom/appendSnippet.ts +34 -0
- package/src/lib/ui/dom/appendStatic.ts +27 -0
- package/src/lib/ui/dom/appendText.ts +114 -0
- package/src/lib/ui/dom/applyResolved.ts +72 -0
- package/src/lib/ui/dom/attach.ts +20 -0
- package/src/lib/ui/dom/attr.ts +19 -0
- package/src/lib/ui/dom/awaitBlock.ts +224 -0
- package/src/lib/ui/dom/cloneStatic.ts +52 -0
- package/src/lib/ui/dom/each.ts +115 -0
- package/src/lib/ui/dom/eachAsync.ts +153 -0
- package/src/lib/ui/dom/hydrate.ts +35 -0
- package/src/lib/ui/dom/mount.ts +29 -0
- package/src/lib/ui/dom/mountChild.ts +33 -0
- package/src/lib/ui/dom/on.ts +15 -0
- package/src/lib/ui/dom/openChild.ts +22 -0
- package/src/lib/ui/dom/openRoot.ts +20 -0
- package/src/lib/ui/dom/switchBlock.ts +75 -0
- package/src/lib/ui/dom/text.ts +20 -0
- package/src/lib/ui/dom/tryBlock.ts +112 -0
- package/src/lib/ui/dom/types/EachRow.ts +3 -0
- package/src/lib/ui/dom/types/SwitchCase.ts +6 -0
- package/src/lib/ui/dom/when.ts +73 -0
- package/src/lib/ui/effect.ts +16 -0
- package/src/lib/ui/installHotBridge.ts +73 -0
- package/src/lib/ui/matchRoute.ts +89 -0
- package/src/lib/ui/navigate.ts +17 -0
- package/src/lib/ui/probeNavigation.ts +33 -0
- package/src/lib/ui/remoteProxy.ts +97 -0
- package/src/lib/ui/renderChain.ts +50 -0
- package/src/lib/ui/renderToStream.ts +104 -0
- package/src/lib/ui/router.ts +286 -0
- package/src/lib/ui/runtime/OUTLET_TAG.ts +8 -0
- package/src/lib/ui/runtime/OWNER.ts +8 -0
- package/src/lib/ui/runtime/REACTIVE_CONTEXT.ts +14 -0
- package/src/lib/ui/runtime/RENDER.ts +23 -0
- package/src/lib/ui/runtime/RESUME.ts +16 -0
- package/src/lib/ui/runtime/applyPatchToTree.ts +41 -0
- package/src/lib/ui/runtime/claimChild.ts +10 -0
- package/src/lib/ui/runtime/clientPage.ts +16 -0
- package/src/lib/ui/runtime/createComputedNode.ts +16 -0
- package/src/lib/ui/runtime/createDoc.ts +177 -0
- package/src/lib/ui/runtime/createEffectNode.ts +58 -0
- package/src/lib/ui/runtime/createSignalNode.ts +16 -0
- package/src/lib/ui/runtime/detachLink.ts +21 -0
- package/src/lib/ui/runtime/endTracking.ts +24 -0
- package/src/lib/ui/runtime/enterRenderPass.ts +12 -0
- package/src/lib/ui/runtime/exitRenderPass.ts +7 -0
- package/src/lib/ui/runtime/firstOutlet.ts +22 -0
- package/src/lib/ui/runtime/flushEffects.ts +17 -0
- package/src/lib/ui/runtime/hotInstances.ts +10 -0
- package/src/lib/ui/runtime/hotReloadEnabled.ts +8 -0
- package/src/lib/ui/runtime/hotReplace.ts +25 -0
- package/src/lib/ui/runtime/nextBlockId.ts +11 -0
- package/src/lib/ui/runtime/pathExists.ts +23 -0
- package/src/lib/ui/runtime/readNode.ts +17 -0
- package/src/lib/ui/runtime/registerHotInstance.ts +23 -0
- package/src/lib/ui/runtime/runNode.ts +28 -0
- package/src/lib/ui/runtime/runtimePath.ts +9 -0
- package/src/lib/ui/runtime/scope.ts +24 -0
- package/src/lib/ui/runtime/toTeardown.ts +26 -0
- package/src/lib/ui/runtime/track.ts +58 -0
- package/src/lib/ui/runtime/trigger.ts +44 -0
- package/src/lib/ui/runtime/types/Cell.ts +5 -0
- package/src/lib/ui/runtime/types/Derived.ts +3 -0
- package/src/lib/ui/runtime/types/Doc.ts +19 -0
- package/src/lib/ui/runtime/types/EffectResult.ts +10 -0
- package/src/lib/ui/runtime/types/HotInstance.ts +14 -0
- package/src/lib/ui/runtime/types/NavVerdict.ts +9 -0
- package/src/lib/ui/runtime/types/Patch.ts +11 -0
- package/src/lib/ui/runtime/types/ReactiveLink.ts +21 -0
- package/src/lib/ui/runtime/types/ReactiveNode.ts +25 -0
- package/src/lib/ui/runtime/types/Route.ts +8 -0
- package/src/lib/ui/runtime/types/RouteLoader.ts +7 -0
- package/src/lib/ui/runtime/types/SsrRender.ts +22 -0
- package/src/lib/ui/runtime/types/State.ts +3 -0
- package/src/lib/ui/runtime/types/Teardown.ts +5 -0
- package/src/lib/ui/runtime/types/UiComponent.ts +16 -0
- package/src/lib/ui/runtime/types/UiProps.ts +15 -0
- package/src/lib/ui/runtime/unlinkDeps.ts +20 -0
- package/src/lib/ui/runtime/untrack.ts +20 -0
- package/src/lib/ui/runtime/valueAtPath.ts +18 -0
- package/src/lib/ui/runtime/writeNode.ts +16 -0
- package/src/lib/ui/socketChannel.ts +227 -0
- package/src/lib/ui/socketProxy.ts +25 -0
- package/src/lib/ui/startClient.ts +58 -0
- package/src/lib/ui/state.ts +25 -0
- package/src/lib/ui/tail.ts +324 -0
- package/src/lib/ui/types/Layouts.ts +9 -0
- package/src/lib/ui/types/Pages.ts +8 -0
- package/src/preload.ts +19 -0
- package/src/scaffold.ts +153 -0
- package/src/serverBuildPlugins.ts +19 -0
- package/src/serverEntry.ts +95 -0
- package/template/bunfig.toml +4 -0
- package/template/package.json +18 -0
- package/template/src/app.ts +28 -0
- package/template/src/bundle/icon.png +0 -0
- package/template/src/cli/banner.txt +3 -0
- package/template/src/cli/footer.txt +1 -0
- package/template/src/server/config.ts +17 -0
- package/template/src/server/rpc/getHello.ts +36 -0
- package/template/src/ui/Layout.abide +19 -0
- package/template/src/ui/app.css +21 -0
- package/template/src/ui/app.html +24 -0
- package/template/src/ui/pages/about/page.abide +9 -0
- package/template/src/ui/pages/page.abide +22 -0
- package/template/test/app.test.ts +30 -0
- package/template/tsconfig.json +18 -0
- package/tsconfig.app.json +17 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# abide-ui
|
|
2
|
+
|
|
3
|
+
A from-scratch, single-file UI framework for abide — reactive, with `<script>` +
|
|
4
|
+
template + `<style>` in one `.abide` file. Signal surface, document
|
|
5
|
+
substrate, server-rendered and streamed, with true DOM adoption.
|
|
6
|
+
|
|
7
|
+
abide-ui is the framework's UI runtime: `createUiPageRenderer` renders and streams
|
|
8
|
+
every page, and `.abide` files are the only component format.
|
|
9
|
+
|
|
10
|
+
## A component
|
|
11
|
+
|
|
12
|
+
```html
|
|
13
|
+
<script>
|
|
14
|
+
import Layout from './Layout.abide'
|
|
15
|
+
let count = state(0) // signal
|
|
16
|
+
let items = state([])
|
|
17
|
+
let total = derived(() => items.length) // computed
|
|
18
|
+
function add() { items.push('item ' + (total + 1)) }
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<Layout title="home">
|
|
22
|
+
<button onclick={() => count += 1}>count: {count}</button>
|
|
23
|
+
<button onclick={add}>add ({total})</button>
|
|
24
|
+
<template if={total}>
|
|
25
|
+
<ul>
|
|
26
|
+
<template each={items} as="it" key="it"><li>{it}</li></template>
|
|
27
|
+
</ul>
|
|
28
|
+
<template else><p>empty</p></template>
|
|
29
|
+
</template>
|
|
30
|
+
</Layout>
|
|
31
|
+
|
|
32
|
+
<style>
|
|
33
|
+
button { cursor: pointer } /* scoped to this component */
|
|
34
|
+
</style>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Idioms
|
|
38
|
+
|
|
39
|
+
- **Signals are the surface**: `state(v)`, `derived(fn)`, `effect(fn)`, `prop(name)`.
|
|
40
|
+
You write plain assignment (`count += 1`, `items.push(x)`); the compiler lowers
|
|
41
|
+
it. Templates auto-read (`{count}`); ordering and cross-references compose.
|
|
42
|
+
- **Everything dynamic lives in `{ }`** — `{expr}` text, `name={expr}`,
|
|
43
|
+
`onclick={fn}`, `bind:value={path}`.
|
|
44
|
+
- **Control flow is native `<template>`** (valid HTML, no mustache DSL):
|
|
45
|
+
`<template if>`/`<template else>`, `<template each as key>`,
|
|
46
|
+
`<template await>`/`then`/`catch`, `<template switch>`/`case`/`default`.
|
|
47
|
+
- **Components** are capitalised tags (`<Layout title="…">`); children fill the
|
|
48
|
+
child's `<slot>`. Props are reactive (passed as thunks).
|
|
49
|
+
- **Scoped styles**: a `<style>` block is scoped per component via a
|
|
50
|
+
`[data-b-<hash>]` attribute.
|
|
51
|
+
|
|
52
|
+
## Substrate (why it's fast)
|
|
53
|
+
|
|
54
|
+
State is one mutable document addressed by path; every change is a patch over a
|
|
55
|
+
path. The compiler turns `model.a[i].b` into a path read and `model.x = y` into a
|
|
56
|
+
patch, hoisting static paths to a `cell` resolved once. Reactivity is shape-only
|
|
57
|
+
(a deep field edit wakes only that field, not the list above it). On the
|
|
58
|
+
write-path microbench this runs ~20× faster than a deep-proxy signal baseline.
|
|
59
|
+
|
|
60
|
+
## SSR + streaming + hydration
|
|
61
|
+
|
|
62
|
+
- `compileSSR` renders to an HTML string (byte-identical to the client DOM).
|
|
63
|
+
- `renderToStream` streams: pending shell first, then resolved `<template await>`
|
|
64
|
+
fragments out of order as their promises settle; `applyResolved` swaps them in.
|
|
65
|
+
- `hydrate` adopts the server DOM in place (no re-render) for static-structure
|
|
66
|
+
components — claims existing nodes, splits merged text, wires effects/listeners.
|
|
67
|
+
|
|
68
|
+
## Pipeline
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
.abide → analyzeComponent (split script/style/template, desugar signals → doc,
|
|
72
|
+
lower data access, scope CSS)
|
|
73
|
+
→ generateBuild (client: openChild/appendText/attr/on/each/when/…)
|
|
74
|
+
→ generateSSR (server: HTML-string back-end, await markers)
|
|
75
|
+
→ hoistCells (static paths → cells)
|
|
76
|
+
→ compileModule (ES module: default mount + render() for SSR)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`compile/abideUiPlugin.ts` is the Bun loader for `.abide` files.
|
|
80
|
+
|
|
81
|
+
## Known gaps
|
|
82
|
+
|
|
83
|
+
- Hydration adopts static structure only; control-flow blocks (if/each/await/
|
|
84
|
+
switch) and child components fall back to `mount` (re-render).
|
|
85
|
+
- `compileModule` emits `abide/ui/*` specifiers (a published consumer needs
|
|
86
|
+
`abide/ui/*` or `abideImportName`).
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Source text for the `$esc` / `$attr` / `$text` / `$snip` helpers injected into
|
|
3
|
+
every SSR render body. `$esc` escapes the five HTML-significant characters. `$attr`
|
|
4
|
+
renders a dynamic `{expr}` attribute with the same present/absent semantics the
|
|
5
|
+
client `attr` binding uses: false/null/undefined drops it, true emits the bare
|
|
6
|
+
attribute, anything else emits `name="escaped"`. `$snip` brands a snippet's
|
|
7
|
+
rendered string. `$text` is what `{expr}` interpolations push: a snippet call's
|
|
8
|
+
value is emitted raw between `<!--abide:snippet-->` markers (the client runs its
|
|
9
|
+
builder there to claim the nodes); a `html\`…\`` value raw between `<!--abide:html-->`
|
|
10
|
+
markers; anything else is escaped. The brands are registered Symbols so they match
|
|
11
|
+
across bundles. Emitted inline (not imported) so the generated render module is
|
|
12
|
+
self-contained.
|
|
13
|
+
*/
|
|
14
|
+
export const SSR_ESCAPE =
|
|
15
|
+
'const $esc = (v) => String(v).replace(/[&<>"\']/g, (c) => ' +
|
|
16
|
+
"({ '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' })[c]);\n" +
|
|
17
|
+
'const $attr = (n, v) => (v === false || v === null || v === undefined) ? "" ' +
|
|
18
|
+
': v === true ? (" " + n) : (" " + n + \'="\' + $esc(v) + \'"\');\n' +
|
|
19
|
+
"const $RAW = Symbol.for('abide.rawHtml');\n" +
|
|
20
|
+
"const $SNIP = Symbol.for('abide.snippet');\n" +
|
|
21
|
+
'const $snip = (s) => ({ [$SNIP]: s });\n' +
|
|
22
|
+
'const $text = (v) => (v !== null && typeof v === "object" && $SNIP in v) ' +
|
|
23
|
+
"? ('<!--abide:snippet-->' + v[$SNIP] + '<!--/abide:snippet-->') " +
|
|
24
|
+
': (v !== null && typeof v === "object" && $RAW in v) ' +
|
|
25
|
+
"? ('<!--abide:html-->' + v[$RAW] + '<!--/abide:html-->') : $esc(v);"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*
|
|
2
|
+
The abide-ui runtime names every compiled component module depends on, each
|
|
3
|
+
paired with its package subpath (after the package name). One source of truth so
|
|
4
|
+
three things can't drift: the normal module's import block (`compileModule`), the
|
|
5
|
+
hot module's `window.__abide` destructure (dev component HMR), and the dev bridge
|
|
6
|
+
that populates `window.__abide`. Order is the emit order.
|
|
7
|
+
*/
|
|
8
|
+
export const UI_RUNTIME_IMPORTS: { name: string; specifier: string }[] = [
|
|
9
|
+
{ name: 'html', specifier: 'shared/html' },
|
|
10
|
+
{ name: 'snippet', specifier: 'shared/snippet' },
|
|
11
|
+
{ name: 'doc', specifier: 'ui/doc' },
|
|
12
|
+
{ name: 'state', specifier: 'ui/state' },
|
|
13
|
+
{ name: 'derived', specifier: 'ui/derived' },
|
|
14
|
+
{ name: 'effect', specifier: 'ui/effect' },
|
|
15
|
+
{ name: 'mount', specifier: 'ui/dom/mount' },
|
|
16
|
+
{ name: 'openChild', specifier: 'ui/dom/openChild' },
|
|
17
|
+
{ name: 'openRoot', specifier: 'ui/dom/openRoot' },
|
|
18
|
+
{ name: 'appendText', specifier: 'ui/dom/appendText' },
|
|
19
|
+
{ name: 'appendSnippet', specifier: 'ui/dom/appendSnippet' },
|
|
20
|
+
{ name: 'appendStatic', specifier: 'ui/dom/appendStatic' },
|
|
21
|
+
{ name: 'cloneStatic', specifier: 'ui/dom/cloneStatic' },
|
|
22
|
+
{ name: 'attr', specifier: 'ui/dom/attr' },
|
|
23
|
+
{ name: 'on', specifier: 'ui/dom/on' },
|
|
24
|
+
{ name: 'attach', specifier: 'ui/dom/attach' },
|
|
25
|
+
{ name: 'each', specifier: 'ui/dom/each' },
|
|
26
|
+
{ name: 'eachAsync', specifier: 'ui/dom/eachAsync' },
|
|
27
|
+
{ name: 'when', specifier: 'ui/dom/when' },
|
|
28
|
+
{ name: 'awaitBlock', specifier: 'ui/dom/awaitBlock' },
|
|
29
|
+
{ name: 'tryBlock', specifier: 'ui/dom/tryBlock' },
|
|
30
|
+
{ name: 'switchBlock', specifier: 'ui/dom/switchBlock' },
|
|
31
|
+
{ name: 'mountChild', specifier: 'ui/dom/mountChild' },
|
|
32
|
+
{ name: 'hydrate', specifier: 'ui/dom/hydrate' },
|
|
33
|
+
{ name: 'nextBlockId', specifier: 'ui/runtime/nextBlockId' },
|
|
34
|
+
{ name: 'enterRenderPass', specifier: 'ui/runtime/enterRenderPass' },
|
|
35
|
+
{ name: 'exitRenderPass', specifier: 'ui/runtime/exitRenderPass' },
|
|
36
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*
|
|
2
|
+
HTML void elements — they have no closing tag and no children. Shared by the SSR
|
|
3
|
+
generator and the static-clone skeleton generator so both emit `<img>` not
|
|
4
|
+
`<img></img>`, keeping server markup and the client clone template identical.
|
|
5
|
+
*/
|
|
6
|
+
export const VOID_TAGS: ReadonlySet<string> = new Set([
|
|
7
|
+
'area',
|
|
8
|
+
'base',
|
|
9
|
+
'br',
|
|
10
|
+
'col',
|
|
11
|
+
'embed',
|
|
12
|
+
'hr',
|
|
13
|
+
'img',
|
|
14
|
+
'input',
|
|
15
|
+
'link',
|
|
16
|
+
'meta',
|
|
17
|
+
'param',
|
|
18
|
+
'source',
|
|
19
|
+
'track',
|
|
20
|
+
'wbr',
|
|
21
|
+
])
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { relative } from 'node:path'
|
|
2
|
+
import type { BunPlugin } from 'bun'
|
|
3
|
+
import { analyzeComponent } from './analyzeComponent.ts'
|
|
4
|
+
import { compileModule } from './compileModule.ts'
|
|
5
|
+
import { nearestProjectRoot } from './nearestProjectRoot.ts'
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
Bun plugin that loads `.abide` single-file components: compiles each to the ES
|
|
9
|
+
module `compileModule` emits, so they import and mount like any other module. The
|
|
10
|
+
only UI loader in the dev/build/preload pipeline; the emitted module's
|
|
11
|
+
`abide/ui/*` imports resolve through the package exports.
|
|
12
|
+
|
|
13
|
+
A `layout.abide` compiles as a layout: its `<slot/>` lowers to the router's page
|
|
14
|
+
outlet (`<abide-outlet>`) rather than a passed-children slot — the file's role is
|
|
15
|
+
its name, so the loader flags it from the path stem.
|
|
16
|
+
|
|
17
|
+
The emitted module embeds the component's `<script>` and `{expr}` bodies verbatim,
|
|
18
|
+
so it carries the author's TypeScript (a typed `prop`, an annotated handler). The
|
|
19
|
+
`ts` loader strips those annotations — the generated runtime code is valid TS too —
|
|
20
|
+
keeping `.abide` scripts the TypeScript that `abide check` type-checks them as.
|
|
21
|
+
|
|
22
|
+
A component's scoped `<style>`(s) are bundled, not inlined: in the BROWSER build the
|
|
23
|
+
module imports a virtual `abide-style:` CSS module holding every block's scoped CSS
|
|
24
|
+
concatenated, so Bun folds it into the entry stylesheet (`client.css`, already linked
|
|
25
|
+
by the shell). Server builds (target `bun`) omit the import — SSR styling comes from
|
|
26
|
+
that same linked sheet, so a page renders styled before the client bundle loads, with
|
|
27
|
+
no inlined `<style>`. The elements still carry their `data-a-…` scope attributes
|
|
28
|
+
either way (one per `<style>` covering them — see `analyzeComponent`).
|
|
29
|
+
*/
|
|
30
|
+
// @readme plumbing
|
|
31
|
+
export const abideUiPlugin: BunPlugin = {
|
|
32
|
+
name: 'abide-ui',
|
|
33
|
+
setup(build) {
|
|
34
|
+
const toBrowser = build.config?.target === 'browser'
|
|
35
|
+
/* Scoped CSS keyed by its virtual specifier, filled as each `.abide` loads and
|
|
36
|
+
read back when Bun resolves the matching `abide-style:` import (browser only). */
|
|
37
|
+
const cssByVirtual = new Map<string, string>()
|
|
38
|
+
|
|
39
|
+
build.onLoad({ filter: /\.abide$/ }, async (args) => {
|
|
40
|
+
const source = await Bun.file(args.path).text()
|
|
41
|
+
const moduleId = relative(nearestProjectRoot(args.path, process.cwd()), args.path)
|
|
42
|
+
const isLayout = (args.path.split('/').pop() ?? '') === 'layout.abide'
|
|
43
|
+
const code = compileModule(source, { isLayout, moduleId })
|
|
44
|
+
/* Browser build with `<style>`(s): concatenate every scoped block's CSS and
|
|
45
|
+
pull it into the bundle via one virtual import, keyed by `moduleId` so the
|
|
46
|
+
registry id and the CSS id agree. */
|
|
47
|
+
const styles = toBrowser ? analyzeComponent(source, moduleId).styles : []
|
|
48
|
+
if (styles.length === 0) {
|
|
49
|
+
return { contents: code, loader: 'ts' }
|
|
50
|
+
}
|
|
51
|
+
const virtual = `abide-style:${moduleId}`
|
|
52
|
+
cssByVirtual.set(virtual, styles.map((style) => style.css).join('\n'))
|
|
53
|
+
return { contents: `import ${JSON.stringify(virtual)}\n${code}`, loader: 'ts' }
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
build.onResolve({ filter: /^abide-style:/ }, (args) => ({
|
|
57
|
+
path: args.path,
|
|
58
|
+
namespace: 'abide-style',
|
|
59
|
+
}))
|
|
60
|
+
build.onLoad({ filter: /.*/, namespace: 'abide-style' }, (args) => ({
|
|
61
|
+
contents: cssByVirtual.get(args.path) ?? '',
|
|
62
|
+
loader: 'css',
|
|
63
|
+
}))
|
|
64
|
+
},
|
|
65
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { desugarSignals } from './desugarSignals.ts'
|
|
2
|
+
import { lowerDocAccess } from './lowerDocAccess.ts'
|
|
3
|
+
import { parseTemplate } from './parseTemplate.ts'
|
|
4
|
+
import { scopeCss } from './scopeCss.ts'
|
|
5
|
+
import type { AnalyzedComponent } from './types/AnalyzedComponent.ts'
|
|
6
|
+
import type { TemplateNode } from './types/TemplateNode.ts'
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
The shared compile front-end: splits the leading `<script>` off the template,
|
|
10
|
+
desugars the signal surface to the doc form, lowers the script's data access, and
|
|
11
|
+
parses the template (which keeps each `<style>` as an in-place node). Each `<style>`
|
|
12
|
+
is scoped to its own attribute (`data-a-<hash>`); `annotateScopes` stamps that
|
|
13
|
+
attribute onto every element in the style's sibling subtree, so a top-level
|
|
14
|
+
`<style>` covers the whole component while a nested one covers only the branch it
|
|
15
|
+
sits in. Both client and SSR back-ends read the per-element `scopes`, so the targets
|
|
16
|
+
always agree.
|
|
17
|
+
|
|
18
|
+
`scopeSeed` (the component's stable module id, supplied by the loader) seeds each
|
|
19
|
+
hash — combined with the style's source-order index — so the attribute tracks
|
|
20
|
+
component+position identity, not CSS text: an edit to a `<style>` keeps the same
|
|
21
|
+
`data-a-…`, so the live elements still match and the CSS can hot-swap in place.
|
|
22
|
+
Absent (direct compile calls / tests) it falls back to hashing the style body.
|
|
23
|
+
*/
|
|
24
|
+
export function analyzeComponent(source: string, scopeSeed?: string): AnalyzedComponent {
|
|
25
|
+
/* Only the LEADING `<script>` is the component script; scripts nested in the
|
|
26
|
+
template (scoped reactive blocks) survive into the parsed nodes. The `<style>`
|
|
27
|
+
is left in the template for the parser to extract structurally (below), so a
|
|
28
|
+
`<style>` quoted inside an expression is never mistaken for the component's. */
|
|
29
|
+
const scriptMatch = source.match(/^\s*<script[^>]*>([\s\S]*?)<\/script>/)
|
|
30
|
+
const scriptBody = (scriptMatch?.[1] ?? '').trim()
|
|
31
|
+
const template = source.replace(/^\s*<script[^>]*>[\s\S]*?<\/script>/, '').trim()
|
|
32
|
+
|
|
33
|
+
const { code: desugared, stateNames, derivedNames } = desugarSignals(scriptBody)
|
|
34
|
+
const lowered = desugared.trim() === '' ? '' : lowerDocAccess(desugared, 'model')
|
|
35
|
+
/* Hoist top-level import statements (e.g. child components) out of the script
|
|
36
|
+
so the module wrapper can place them at module scope — they can't live
|
|
37
|
+
inside the mount callback / render function. */
|
|
38
|
+
const imports: string[] = []
|
|
39
|
+
const script = lowered
|
|
40
|
+
.replace(/^[ \t]*import\s[^\n]*$/gm, (line) => {
|
|
41
|
+
imports.push(line.trim())
|
|
42
|
+
return ''
|
|
43
|
+
})
|
|
44
|
+
.replace(/\n{2,}/g, '\n')
|
|
45
|
+
.trim()
|
|
46
|
+
/* The parser keeps each `<style>` as an in-place node (one inside an expression
|
|
47
|
+
is text, never a node). `annotateScopes` mutates the tree — assigning each
|
|
48
|
+
style its scope attribute and stamping covered elements — and returns the
|
|
49
|
+
scoped CSS per block for the bundler. */
|
|
50
|
+
const { nodes } = parseTemplate(template)
|
|
51
|
+
const styles = annotateScopes(nodes, [], scopeSeed, { count: 0 })
|
|
52
|
+
return {
|
|
53
|
+
script,
|
|
54
|
+
imports: imports.join('\n'),
|
|
55
|
+
stateNames,
|
|
56
|
+
derivedNames,
|
|
57
|
+
nodes,
|
|
58
|
+
styles,
|
|
59
|
+
/* Hydration adopts every block in place — including `await`, which resumes
|
|
60
|
+
from the streamed value in the resume manifest (see `runtime/RESUME`). */
|
|
61
|
+
hydratable: true,
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* The children of a control-flow / element / component node, or undefined for a
|
|
66
|
+
leaf (text/script/style). Every children-bearing kind carries `children`. */
|
|
67
|
+
function childrenOf(node: TemplateNode): TemplateNode[] | undefined {
|
|
68
|
+
return 'children' in node ? node.children : undefined
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/*
|
|
72
|
+
Walks `nodes` in source order, scoping each `<style>` to its sibling subtree: a
|
|
73
|
+
style among a sibling list covers every element in that list AND every descendant
|
|
74
|
+
(so its attribute reaches the whole branch it sits in, like the nested-`<script>`
|
|
75
|
+
rule). `inherited` is the scope attributes already active from ancestors; this
|
|
76
|
+
level adds its own styles' attributes, stamps the resulting set onto each element
|
|
77
|
+
here, and recurses with it. `index.count` is the running source-order ordinal that
|
|
78
|
+
(with `scopeSeed`) keeps each attribute stable across CSS edits. Returns the scoped
|
|
79
|
+
CSS for every non-empty style, in source order, for the bundler to concatenate.
|
|
80
|
+
*/
|
|
81
|
+
function annotateScopes(
|
|
82
|
+
nodes: TemplateNode[],
|
|
83
|
+
inherited: string[],
|
|
84
|
+
scopeSeed: string | undefined,
|
|
85
|
+
index: { count: number },
|
|
86
|
+
): { attribute: string; css: string }[] {
|
|
87
|
+
const collected: { attribute: string; css: string }[] = []
|
|
88
|
+
/* This sibling list's own style attributes — active for every element here. */
|
|
89
|
+
const here = [...inherited]
|
|
90
|
+
for (const node of nodes) {
|
|
91
|
+
if (node.kind === 'style' && node.css.trim() !== '') {
|
|
92
|
+
const attribute = `data-a-${hashString(`${scopeSeed ?? node.css}#${index.count}`)}`
|
|
93
|
+
index.count += 1
|
|
94
|
+
collected.push({ attribute, css: scopeCss(node.css, attribute) })
|
|
95
|
+
here.push(attribute)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
for (const node of nodes) {
|
|
99
|
+
if (node.kind === 'element') {
|
|
100
|
+
node.scopes = here
|
|
101
|
+
}
|
|
102
|
+
const children = childrenOf(node)
|
|
103
|
+
if (children !== undefined) {
|
|
104
|
+
collected.push(...annotateScopes(children, here, scopeSeed, index))
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return collected
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Small stable hash (djb2 → base36) for a per-style scope attribute. */
|
|
111
|
+
function hashString(value: string): string {
|
|
112
|
+
let hash = 5381
|
|
113
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
114
|
+
hash = (hash * 33) ^ value.charCodeAt(index)
|
|
115
|
+
}
|
|
116
|
+
return (hash >>> 0).toString(36)
|
|
117
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
A single virtual ambient-declaration file injected into the shadow world so the
|
|
5
|
+
type-checker resolves bundler-handled asset imports instead of erroring "cannot
|
|
6
|
+
find module". Bun bundles a stylesheet import for its side effect and resolves a
|
|
7
|
+
static asset to its URL string; these declarations mirror that. One shared file
|
|
8
|
+
(not a per-component preamble) keeps the wildcard module patterns declared once,
|
|
9
|
+
which TypeScript requires. Used by both the check Program and the LSP service so
|
|
10
|
+
the editor and CLI agree.
|
|
11
|
+
*/
|
|
12
|
+
export function assetModulesFile(cwd: string): { path: string; content: string } {
|
|
13
|
+
return {
|
|
14
|
+
path: resolve(cwd, '__abide_assets__.d.ts'),
|
|
15
|
+
content: [
|
|
16
|
+
"declare module '*.css' {}",
|
|
17
|
+
"declare module '*.scss' {}",
|
|
18
|
+
"declare module '*.sass' {}",
|
|
19
|
+
"declare module '*.less' {}",
|
|
20
|
+
"declare module '*.svg' { const src: string; export default src }",
|
|
21
|
+
"declare module '*.png' { const src: string; export default src }",
|
|
22
|
+
"declare module '*.jpg' { const src: string; export default src }",
|
|
23
|
+
"declare module '*.jpeg' { const src: string; export default src }",
|
|
24
|
+
"declare module '*.gif' { const src: string; export default src }",
|
|
25
|
+
"declare module '*.webp' { const src: string; export default src }",
|
|
26
|
+
"declare module '*.avif' { const src: string; export default src }",
|
|
27
|
+
"declare module '*.woff' { const src: string; export default src }",
|
|
28
|
+
"declare module '*.woff2' { const src: string; export default src }",
|
|
29
|
+
'',
|
|
30
|
+
].join('\n'),
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { TemplateNode } from './types/TemplateNode.ts'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
The element roots of a control-flow branch (`if`/`else`/`switch case`/`await
|
|
5
|
+
then|catch`). A branch may hold one or MORE top-level elements — each becomes a
|
|
6
|
+
root the block tracks as a range. Whitespace-only text between/around them is
|
|
7
|
+
dropped (so SSR and the client build agree on the node set, keeping hydration
|
|
8
|
+
aligned). Any other top-level content — meaningful text, a component, or a nested
|
|
9
|
+
control-flow `<template>` — must be wrapped in an element; it throws a clear error
|
|
10
|
+
rather than silently dropping (full fragment roots are a separate feature).
|
|
11
|
+
|
|
12
|
+
Both back-ends call this, so the server HTML and the client build contain exactly
|
|
13
|
+
the same roots in the same order.
|
|
14
|
+
*/
|
|
15
|
+
type ElementNode = Extract<TemplateNode, { kind: 'element' }>
|
|
16
|
+
|
|
17
|
+
export function branchElements(
|
|
18
|
+
children: TemplateNode[],
|
|
19
|
+
context: string,
|
|
20
|
+
allowEmpty = false,
|
|
21
|
+
): ElementNode[] {
|
|
22
|
+
const elements: ElementNode[] = []
|
|
23
|
+
for (const child of children) {
|
|
24
|
+
if (child.kind === 'element') {
|
|
25
|
+
elements.push(child)
|
|
26
|
+
continue
|
|
27
|
+
}
|
|
28
|
+
/* Whitespace-only text is layout noise between roots — drop it. */
|
|
29
|
+
if (child.kind === 'text' && isWhitespaceOnly(child)) {
|
|
30
|
+
continue
|
|
31
|
+
}
|
|
32
|
+
/* A scoped `<script>` is emitted as code by the back-end, not a root; a
|
|
33
|
+
`<style>` is bundled CSS (its scope already stamped on the roots). */
|
|
34
|
+
if (child.kind === 'script' || child.kind === 'style') {
|
|
35
|
+
continue
|
|
36
|
+
}
|
|
37
|
+
throw new Error(
|
|
38
|
+
`[abide] ${context} content must be element(s); wrap text / components / nested <template> in an element`,
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
if (elements.length === 0 && !allowEmpty) {
|
|
42
|
+
throw new Error(`[abide] ${context} must contain at least one element`)
|
|
43
|
+
}
|
|
44
|
+
return elements
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* A text node whose parts are all whitespace literals (no interpolation). */
|
|
48
|
+
function isWhitespaceOnly(node: Extract<TemplateNode, { kind: 'text' }>): boolean {
|
|
49
|
+
return node.parts.every((part) => part.kind === 'static' && part.value.trim() === '')
|
|
50
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import ts from 'typescript'
|
|
2
|
+
import type { ShadowProgram } from './createShadowProgram.ts'
|
|
3
|
+
import { remapShadowDiagnostic } from './remapShadowDiagnostic.ts'
|
|
4
|
+
import type { AbideDiagnostic } from './types/AbideDiagnostic.ts'
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
Runs the shadow program's type-checker over every `.abide` shadow and relocates
|
|
8
|
+
each diagnostic onto its source component. Only diagnostics that fall inside a
|
|
9
|
+
mapped expression survive (remapShadowDiagnostic drops shadow-internal noise);
|
|
10
|
+
a template that failed to parse contributes a single error at the file head.
|
|
11
|
+
Shared by `abide check` (one-shot render) and the LSP (per-file publish).
|
|
12
|
+
*/
|
|
13
|
+
export function collectAbideDiagnostics(shadow: ShadowProgram): AbideDiagnostic[] {
|
|
14
|
+
const { program, shadows, parseErrors, abidePaths } = shadow
|
|
15
|
+
const diagnostics: AbideDiagnostic[] = []
|
|
16
|
+
for (const abidePath of abidePaths) {
|
|
17
|
+
const parseError = parseErrors.get(abidePath)
|
|
18
|
+
if (parseError !== undefined) {
|
|
19
|
+
diagnostics.push({
|
|
20
|
+
file: abidePath,
|
|
21
|
+
start: 0,
|
|
22
|
+
length: 0,
|
|
23
|
+
message: parseError,
|
|
24
|
+
category: ts.DiagnosticCategory.Error,
|
|
25
|
+
})
|
|
26
|
+
continue
|
|
27
|
+
}
|
|
28
|
+
const sourceFile = program.getSourceFile(`${abidePath}.ts`)
|
|
29
|
+
const mappings = shadows.get(abidePath)?.mappings
|
|
30
|
+
if (sourceFile === undefined || mappings === undefined) {
|
|
31
|
+
continue
|
|
32
|
+
}
|
|
33
|
+
const raw = [
|
|
34
|
+
...program.getSyntacticDiagnostics(sourceFile),
|
|
35
|
+
...program.getSemanticDiagnostics(sourceFile),
|
|
36
|
+
]
|
|
37
|
+
for (const diagnostic of raw) {
|
|
38
|
+
if (diagnostic.start === undefined) {
|
|
39
|
+
continue
|
|
40
|
+
}
|
|
41
|
+
const located = remapShadowDiagnostic(
|
|
42
|
+
mappings,
|
|
43
|
+
diagnostic.start,
|
|
44
|
+
diagnostic.length ?? 0,
|
|
45
|
+
)
|
|
46
|
+
if (located === undefined) {
|
|
47
|
+
continue
|
|
48
|
+
}
|
|
49
|
+
diagnostics.push({
|
|
50
|
+
file: abidePath,
|
|
51
|
+
start: located.start,
|
|
52
|
+
length: located.length,
|
|
53
|
+
message: ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'),
|
|
54
|
+
category: diagnostic.category,
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return diagnostics
|
|
59
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { analyzeComponent } from './analyzeComponent.ts'
|
|
2
|
+
import { generateBuild } from './generateBuild.ts'
|
|
3
|
+
import { hoistCells } from './hoistCells.ts'
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
Compiles a single-file abide component into the body of a client build function.
|
|
7
|
+
Runs the shared front-end (`analyzeComponent`), generates the DOM build from the
|
|
8
|
+
template, and hoists static paths to cells. The returned body runs against a
|
|
9
|
+
`host` element with `doc`/`state`/`derived`/`effect` and the dom bindings in
|
|
10
|
+
scope and defines `model` itself. `compileModule` wraps it (and the SSR body) into
|
|
11
|
+
a real module; tests wrap it with `new Function`.
|
|
12
|
+
*/
|
|
13
|
+
export function compileComponent(source: string, isLayout = false, scopeSeed?: string): string {
|
|
14
|
+
const { script, stateNames, derivedNames, nodes } = analyzeComponent(source, scopeSeed)
|
|
15
|
+
const build = generateBuild(nodes, 'host', stateNames, derivedNames, isLayout)
|
|
16
|
+
/* The scoped CSS is bundled into the entry stylesheet (see `abideUiPlugin`), not
|
|
17
|
+
injected at runtime; the build only needs the `data-a-…` scope attributes on
|
|
18
|
+
elements, which `generateBuild` reads from each node's annotated `scopes`. */
|
|
19
|
+
return `${script}\n${hoistCells(build, 'model')}`
|
|
20
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { ABIDE_PACKAGE_NAME } from '../../shared/ABIDE_PACKAGE_NAME.ts'
|
|
2
|
+
import { analyzeComponent } from './analyzeComponent.ts'
|
|
3
|
+
import { compileComponent } from './compileComponent.ts'
|
|
4
|
+
import { compileSSR } from './compileSSR.ts'
|
|
5
|
+
import { UI_RUNTIME_IMPORTS } from './UI_RUNTIME_IMPORTS.ts'
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
Wraps a component into a complete ES module with two entry points:
|
|
9
|
+
|
|
10
|
+
- default `component(host, $props)` — mounts the client build, returns the
|
|
11
|
+
disposer (`import Counter from './Counter.abide'; const stop = Counter(host)`);
|
|
12
|
+
- `render($props)` — server-renders to `{ html, state, awaits }` for SSR.
|
|
13
|
+
|
|
14
|
+
`render` is also attached to the default export (`component.render`) so a parent
|
|
15
|
+
can server-render a child it imported by its default name. Both entry points share
|
|
16
|
+
the lowered script and template (via the shared front-end), so client and server
|
|
17
|
+
always agree. The `abide/ui/*` imports resolve through the package exports. This is
|
|
18
|
+
what the `.abide` bundler loader emits.
|
|
19
|
+
*/
|
|
20
|
+
export function compileModule(
|
|
21
|
+
source: string,
|
|
22
|
+
options: { isLayout?: boolean; moduleId?: string; hot?: boolean } = {},
|
|
23
|
+
): string {
|
|
24
|
+
const isLayout = options.isLayout ?? false
|
|
25
|
+
/* Component-authored imports (e.g. child components) hoisted to module scope. */
|
|
26
|
+
const analyzed = analyzeComponent(source)
|
|
27
|
+
const userImports = analyzed.imports
|
|
28
|
+
const body = indent(compileComponent(source, isLayout, options.moduleId))
|
|
29
|
+
|
|
30
|
+
/* Hot module (dev component HMR): the same client build, but its runtime comes
|
|
31
|
+
from the live bundle via `window.__abide` — so it shares the one reactive graph
|
|
32
|
+
and instance registry, not fresh copies — and on load it hands the new factory
|
|
33
|
+
to `hotReplace`, which disposes + re-runs every live instance in place. No SSR /
|
|
34
|
+
hydrate / export: it is imported only to replace, never mounted fresh. Supports
|
|
35
|
+
leaf components today; one importing children falls back to a reload (the dev
|
|
36
|
+
layer decides what to hot-swap). */
|
|
37
|
+
if (options.hot) {
|
|
38
|
+
const names = UI_RUNTIME_IMPORTS.map((entry) => entry.name).join(', ')
|
|
39
|
+
const id = JSON.stringify(options.moduleId)
|
|
40
|
+
return `const { ${names}, hotReplace } = window.__abide
|
|
41
|
+
${userImports}
|
|
42
|
+
function component(host, $props) {
|
|
43
|
+
return mount(host, (host) => {
|
|
44
|
+
${body}
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
component.__abideId = ${id}
|
|
48
|
+
if (!hotReplace(${id}, component)) location.reload()
|
|
49
|
+
`
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const ssrBody = indent(compileSSR(source, isLayout, options.moduleId))
|
|
53
|
+
/* Per-component dead-import elimination: emit only the runtime names this module
|
|
54
|
+
actually references. A component that uses no `each`/`await`/`html` shouldn't
|
|
55
|
+
drag those modules into its chunk. The package isn't globally side-effect-free
|
|
56
|
+
(the dev/runtime entries register globals), so a bundler can't tree-shake the
|
|
57
|
+
unused imports for us — but the generated code is the one place that knows
|
|
58
|
+
exactly which names it emitted, so it filters here. A name absent from the body
|
|
59
|
+
is unreferenced; erring toward inclusion (a stray match in user script) only
|
|
60
|
+
keeps a harmless unused import, never drops a needed one. */
|
|
61
|
+
const moduleBody = `export default function component(host, $props) {
|
|
62
|
+
return mount(host, (host) => {
|
|
63
|
+
${body}
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Adopt the server-rendered DOM in place instead of rebuilding it. */
|
|
68
|
+
export function hydrateInto(host, $props) {
|
|
69
|
+
return hydrate(host, (host) => {
|
|
70
|
+
${body}
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function render($props) {
|
|
75
|
+
${ssrBody}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
component.render = render
|
|
79
|
+
component.hydrate = hydrateInto
|
|
80
|
+
component.hydratable = ${analyzed.hydratable}
|
|
81
|
+
${options.moduleId === undefined ? '' : `component.__abideId = ${JSON.stringify(options.moduleId)}\n`}`
|
|
82
|
+
/* Scope each name to the surface that genuinely references it. The SSR body
|
|
83
|
+
carries fixed boilerplate ($attr/$text helpers, `<!--abide:html-->` markers,
|
|
84
|
+
the `{ html, state, awaits }` return shape) whose substrings would falsely
|
|
85
|
+
match value/DOM imports — so client helpers are matched against the client
|
|
86
|
+
build, render-pass helpers against the SSR body, and the two wrapper calls
|
|
87
|
+
(mount/hydrate) are always present. */
|
|
88
|
+
const clientSurface = `${userImports}\n${body}`
|
|
89
|
+
const isReferenced = (entry: { name: string; specifier: string }): boolean => {
|
|
90
|
+
if (entry.name === 'mount' || entry.name === 'hydrate') {
|
|
91
|
+
return true
|
|
92
|
+
}
|
|
93
|
+
/* Render-pass helpers are emitted by both back-ends (e.g. client and server
|
|
94
|
+
await/try blocks both call nextBlockId); their names are distinctive enough
|
|
95
|
+
that scanning both surfaces adds no false match. */
|
|
96
|
+
const surface = entry.specifier.startsWith('ui/runtime/')
|
|
97
|
+
? `${clientSurface}\n${ssrBody}`
|
|
98
|
+
: clientSurface
|
|
99
|
+
return new RegExp(`\\b${entry.name}\\b`).test(surface)
|
|
100
|
+
}
|
|
101
|
+
const importBlock = UI_RUNTIME_IMPORTS.filter(isReferenced)
|
|
102
|
+
.map((entry) => `import { ${entry.name} } from '${ABIDE_PACKAGE_NAME}/${entry.specifier}'`)
|
|
103
|
+
.join('\n')
|
|
104
|
+
return `${importBlock}
|
|
105
|
+
${userImports}
|
|
106
|
+
|
|
107
|
+
${moduleBody}`
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Indents a body block for embedding inside a wrapper function. */
|
|
111
|
+
function indent(body: string): string {
|
|
112
|
+
return body
|
|
113
|
+
.split('\n')
|
|
114
|
+
.map((line) => (line === '' ? line : ` ${line}`))
|
|
115
|
+
.join('\n')
|
|
116
|
+
}
|