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