Add TypeScript twoslash support to docs code blocks#729
Add TypeScript twoslash support to docs code blocks#729IEvangelist merged 13 commits intomicrosoft:mainfrom
Conversation
Wires up expressive-code-twoslash with a generated Aspire SDK .d.ts
so TS samples get hover types. Adds the `twoslash` meta to TS code
blocks across docs and the homepage AppHostBuilder component. Also
fixes nav bar / mobile TOC stacking at ≥72rem where expressive-code's
`:root .main-pane { z-index: 1 }` was trapping the TOC below content.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Inherit class baseType from src/data/pkgs/*.json so subclasses like ViteAppResource/NodeAppResource/PythonAppResource pick up methods defined on their parent class (publishAsDockerFile, publishAsHostedAgent). Fix misaligned samples (withVolume args, withHostPort, publishAsExisting, userNameParameter/passwordParameter, executionContext.isRunMode, redis host/port accessors). Drop twoslash marker from the hypothetical user-integration example where types don't resolve by design. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Remove overflow:hidden from the outer .container so the popup (positioned by floating-ui into the expressive-code wrapper) can extend past the bottom edge. Top-corner rounding moves to .header to preserve the visual against the container's rounded border. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds Twoslash-powered TypeScript hovers to the docs site by generating a virtual Aspire TypeScript SDK type bundle at build time and enabling the expressive-code-twoslash plugin, then opting TypeScript code blocks into twoslash across the docs.
Changes:
- Add
expressive-code-twoslashintegration and configure it to only run on TS fences marked withtwoslash, backed by a generated virtual./.modules/aspire.jstyping file. - Introduce a build-time script to generate
.twoslash-types/aspire.d.tsfrom the existingsrc/data/ts-modules/*.jsonAPI snapshots. - Update many TypeScript docs code fences to opt into
twoslash, plus a few snippet adjustments to match current TS API shapes and some stacking-context CSS/workarounds for hover popups.
Reviewed changes
Copilot reviewed 39 out of 41 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/frontend/src/styles/site.css | Adjust stacking order at ≥72rem to keep TOC/sidebar painting correctly alongside expressive-code. |
| src/frontend/src/content/docs/whats-new/aspire-13-2.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/content/docs/ja/get-started/what-is-aspire.mdx | Enable twoslash on TypeScript snippet. |
| src/frontend/src/content/docs/integrations/databases/postgres/postgres-host.mdx | Enable twoslash on TypeScript snippets and update PgAdmin host port call style. |
| src/frontend/src/content/docs/integrations/databases/postgres/postgres-get-started.mdx | Enable twoslash on TypeScript snippet. |
| src/frontend/src/content/docs/integrations/databases/postgres/postgres-connect.mdx | Enable twoslash and update Postgres env var binding to parameter properties. |
| src/frontend/src/content/docs/integrations/cloud/azure/customize-resources.mdx | Enable twoslash and update publishAsExisting call shape. |
| src/frontend/src/content/docs/get-started/what-is-aspire.mdx | Enable twoslash on TypeScript snippet. |
| src/frontend/src/content/docs/get-started/resource-mcp-servers.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/content/docs/get-started/first-app.mdx | Enable twoslash on TypeScript snippet. |
| src/frontend/src/content/docs/get-started/deploy-first-app.mdx | Enable twoslash on TypeScript snippets with line highlighting. |
| src/frontend/src/content/docs/get-started/aspire-mcp-server.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/content/docs/get-started/add-aspire-existing-app.mdx | Enable twoslash on multiple TypeScript snippets (incl. showLineNumbers case). |
| src/frontend/src/content/docs/extensibility/multi-language-integration-authoring.mdx | Fix a malformed closing fence and enable twoslash on a TypeScript snippet. |
| src/frontend/src/content/docs/deployment/overview.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/content/docs/deployment/kubernetes.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/content/docs/deployment/javascript-apps.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/content/docs/deployment/environments.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/content/docs/deployment/docker-compose.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/content/docs/deployment/azure/container-apps.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/content/docs/deployment/azure/azure-security-best-practices.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/content/docs/deployment/azure/azure-developer-cli.mdx | Enable twoslash on TypeScript snippet. |
| src/frontend/src/content/docs/deployment/azure/app-service.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/content/docs/community/contributor-guide.mdx | Enable twoslash on TypeScript snippet. |
| src/frontend/src/content/docs/app-host/withdockerfile.mdx | Enable twoslash and adjust TS executionContext usage in snippet. |
| src/frontend/src/content/docs/app-host/typescript-apphost.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/content/docs/app-host/persistent-containers.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx | Enable twoslash and update TS volume API usage in snippet. |
| src/frontend/src/content/docs/app-host/executable-resources.mdx | Enable twoslash and update Redis env var sample to use typed properties. |
| src/frontend/src/content/docs/app-host/eventing.mdx | Enable twoslash on TypeScript snippet. |
| src/frontend/src/content/docs/app-host/container-registry.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/content/docs/app-host/container-files.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/content/docs/app-host/certificate-configuration.mdx | Enable twoslash on TypeScript snippets. |
| src/frontend/src/components/starlight/PageTitle.astro | Adjust stacking context strategy for the actions dropdown without elevating above fixed nav. |
| src/frontend/src/components/starlight/Head.astro | Add runtime workaround script for twoslash hover popup behavior/positioning. |
| src/frontend/src/components/AppHostBuilder.astro | Opt AppHostBuilder TS samples into twoslash and adjust container styling to avoid clipping. |
| src/frontend/scripts/generate-twoslash-types.ts | New generator that emits .twoslash-types/aspire.d.ts from API JSON snapshots. |
| src/frontend/pnpm-lock.yaml | Add/lock new dependencies for twoslash integration and TypeScript version changes. |
| src/frontend/package.json | Add twoslash generator script and dependencies (expressive-code-twoslash, typescript), and wire generation into dev/build. |
| src/frontend/ec.config.mjs | Configure expressive-code to run twoslash only when explicitly triggered and provide virtual Aspire SDK types. |
| .gitignore | Ignore .twoslash-types/ output directory. |
Files not reviewed (1)
- src/frontend/pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Add fallback value to --sl-z-index-toc var in site.css so the right-sidebar z-index still resolves when the CSS variable is absent - Guard the twoslash popup-fix IIFE with window.__aspireTwoslashFixInitialized so document-level listeners only register once across Astro view transitions - Downgrade typescript to ^5.9.3 to stay within the peer range declared by expressive-code-twoslash (^5.5.0) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 39 out of 41 changed files in this pull request and generated 3 comments.
Files not reviewed (1)
- src/frontend/pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- postgres-host.mdx: pass port directly to withHostPort(5050); the TS SDK signature takes a number, not an object - ec.config.mjs: use canonical lib name 'es2022' instead of the filename 'lib.es2022.d.ts' so TypeScript loads the standard library correctly during twoslash compilation - ec.config.mjs: point the missing-types warning at the 'pnpm twoslash-types' script rather than the raw tsx invocation Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
IEvangelist
left a comment
There was a problem hiding this comment.
This is awesome, thank you @slang25! It still needs a bit of work, but I do want this for sure. And I'd love it for all languages we will eventually support, C# next though for sure.
| // Virtual files merged into the Twoslash VFS. The Aspire SDK types | ||
| // are declared at `.modules/aspire.ts` so docs samples that import | ||
| // `'./.modules/aspire.js'` resolve against the real API surface. | ||
| extraFiles: { |
| .withEnvironment("REDIS_HOST", redis.host) | ||
| .withEnvironment("REDIS_PORT", redis.port); |
There was a problem hiding this comment.
This is wrong, but to be fair - the code that was there before was actually also wrong. 🤣 I'm happy this is surfacing some other issues as well.
…egration-authoring.mdx Co-authored-by: David Pine <david.pine@microsoft.com>
…pose.mdx Co-authored-by: David Pine <david.pine@microsoft.com>
…pose.mdx Co-authored-by: David Pine <david.pine@microsoft.com>
|
Hey @slang25 are you on our discord? I wanted to chat about something with you and figured that might be faster, if not - no big deal? |
I sure am, ping me when you are free, I'll be off by the end of the hour |
- generate-twoslash-types.ts: type the JSON.parse results so the @typescript-eslint/no-unsafe-* rules pass (previously failed CI) - Add tests/unit/twoslash-types-generator.vitest.test.ts covering the key shape of aspire.d.ts (createBuilder, IDistributedApplicationBuilder, class inheritance from pkgs/, camelCasing, options-object overloads) and wire test:unit:twoslash-types into the test:unit pipeline - ec.config.mjs: drop the explicit `lib` array — twoslash's VFS only loads the lib files literally named in `lib`, so triple-slash references inside lib.es2022.d.ts (es5 → Date, dom → URL, etc.) were silently dropped. Letting `target: ESNext` pick lib.esnext.full.d.ts restores the full standard library. Also remove the now-redundant console.d.ts shim - multi-language-integration-authoring.mdx: drop `twoslash` flag from the apphost.ts sample — the article shows authoring custom exported APIs that aren't part of the generated .d.ts, so the sample correctly uses hypothetical types - executable-resources.mdx: publishAsDockerFile() takes no args - migrate-from-docker-compose.mdx: switch withVolume() calls to the options-object overload as suggested Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
execFileSync('pnpm', ...) fails on Windows with ENOENT because spawn doesn't resolve .cmd shims. Invoke tsx directly via node instead, which also sidesteps the DEP0190 warning from shell:true.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tests were flaking in CI (4-5 flaky + 1 failed each run) because playwright's webServer was running astro dev, and this PR's twoslash processing makes first-request page loads expensive. Under 2 parallel workers, concurrent requests for twoslash pages pegged the dev server, causing unrelated page.goto calls (e.g. on / and /get-started/install-cli/) to exceed the 30s test timeout. Switch CI to astro preview (dist/ already exists from the Build frontend step) so pages are served as static files. Kept astro dev for local dev so interactive work doesn't require a rebuild. Also bumped per-test timeout to 60s as a safety net against any residual slow pages. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
After switching CI's playwright webServer to astro preview, the 6 cookie-consent e2e tests began failing because hideFromBots in config/cookie.config.ts is evaluated at build time (read by astro.config.mjs at static build). Previously astro dev was started by playwright with E2E_TESTS=1 set, so the flag flipped correctly; under preview, the env has to be set during the preceding build step. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Summary
This adds Twoslash to the TypeScript snippets, which provides hovers on TypeScript snippets. The type information is generated at build time with a little script.
This provides extra context for developers looking at the functions because they can more easily discover what additional parameters can be provided, or more generally "what am I looking at here".
It's also useful because it helps keep the code snippets honest, if the code snippet and actual APIs don't align, then you get an error.
I am playing around with my own side-project to create a similar thing for C# code, but it is far from ready. If I get to a point where I am satisfied with a 1.0 release then I can also look to integrate this for the C# code.