Add Deno support to the TypeScript AppHost toolchain resolver#18627
Add Deno support to the TypeScript AppHost toolchain resolver#18627rickylabs wants to merge 2 commits into
Conversation
Extends the CLI TypeScript AppHost toolchain resolver to detect and drive
a Deno toolchain, mirroring the existing npm/bun/yarn/pnpm support.
- Detect Deno via a `packageManager: "deno@x"` hint or deno.lock/deno.json/
deno.jsonc markers (before the npm package-lock fallback).
- Generate `deno install`, `deno check {appHostFile}` (native no-emit
type-check), `deno run -A {appHostFile}`, and `deno run -A --check --watch
{appHostFile}`. Deno is not permissive for package.json projects, so `-A`
grants the host access the AppHost needs; `--check` makes each watch restart
type-check to match the nodemon "typecheck && run" behavior. The native
watcher replaces nodemon.
- Root delegate scripts use `deno task --cwd <dir> <script>` (Deno has no
`run <script>` for package.json scripts).
- Register deno in CommandPathResolver, the missing-tool warning, and the E2E
toolchain helpers; make the watch-mode banner assertion toolchain-aware
(Deno prints "Watcher Process started." instead of nodemon's banner).
- Install a pinned Deno 2.9.0 in the e2e and polyglot-base Docker images.
The doctor tooling check needs no change as it drives off the resolver and
CommandPathResolver.
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 18627Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 18627" |
|
@microsoft-github-policy-service agree |
There was a problem hiding this comment.
Pull request overview
This PR adds Deno as a supported runtime/package-manager to the CLI's TypeScript AppHost toolchain resolver (TypeScriptAppHostToolchainResolver), slotting a Deno branch alongside the existing npm/Bun/Yarn/pnpm cases. It is the CLI/toolchain half of Deno support tracked by issue #16218, and is designed to be additive and independently shippable (no AddDenoApp hosting resource). Detection keys on packageManager: "deno@…", deno.lock, deno.json, and deno.jsonc; command vectors are deno install, deno check {file}, deno run -A {file}, deno run -A --check --watch {file}, and deno task --cwd <dir> <script> for root delegate scripts.
I verified against the official Deno release notes that the command vectors are correct: deno install (no args) installs dependencies from package.json/deno.json (Deno 2.0+), deno task runs package.json scripts and supports --cwd (Deno 2.1+), and the runtime preserves the existing node extension launch capability (matching the issue's "reuse V8 inspector for a first pass" guidance).
Changes:
- Add
Denotoolchain (enum,packageManagerparsing,deno.lock/deno.json/deno.jsoncdetection, install/type-check/execute/watch/delegate command vectors). - Wire Deno into doctor/missing-tool handling (
CommandPathResolver,MissingJavaScriptToolWarning) and add unit/E2E test coverage. - Install Deno v2.9.0 in the two E2E Docker images.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/Aspire.Cli/Projects/TypeScriptAppHostToolchainResolver.cs |
Core change: Deno enum value, detection markers, and install/check/run/watch command vectors. |
src/Aspire.Cli/Scaffolding/ScaffoldingService.cs |
Adds deno task --cwd root delegate script for nested brownfield AppHosts. |
src/Aspire.Cli/Utils/CommandPathResolver.cs |
Adds Deno install display name + link metadata. |
src/Aspire.Cli/Utils/MissingJavaScriptToolWarning.cs |
Adds the Deno missing-tool warning prefix. |
tests/Aspire.Cli.Tests/Projects/TypeScriptAppHostToolchainResolverTests.cs |
Resolver detection + runtime-spec tests for Deno (missing a deno.jsonc case). |
tests/Aspire.Cli.Tests/Commands/TypeScriptAppHostToolingCheckTests.cs |
Doctor availability/missing-link Deno cases. |
tests/Aspire.Cli.Tests/Utils/CommandPathResolverTests.cs |
Deno install message/link assertions. |
tests/Aspire.Cli.Tests/Utils/MissingJavaScriptToolWarningTests.cs |
Deno missing-tool match assertion. |
tests/Aspire.Cli.EndToEnd.Tests/TypeScriptPolyglotTests.cs |
Adds Deno to the toolchain matrix; uses helper for watch-ready text. |
tests/Aspire.Cli.EndToEnd.Tests/Helpers/TypeScriptAppHostToolchainTestHelpers.cs |
Deno command/metadata helpers; introduces GetWatchModeReadyText (Deno value appears mismatched). |
tests/Shared/Docker/Dockerfile.e2e / Dockerfile.e2e-polyglot-base |
Install Deno v2.9.0 for E2E. |
Key findings:
- Moderate: In the E2E helper,
GetWatchModeReadyText("deno")returns"Watcher Process started.", but the watch test runsdeno task aspire:dev, andaspire:devistsc --watchfor all toolchains — which emits"Watching for file changes.". The Deno-native banner is never produced by that script, so the watch assertion will time out. - Nit:
deno.jsoncdetection has no resolution test, unlikedeno.lockanddeno.json.
| /// <summary> | ||
| /// Gets the console text that indicates watch mode is active for a toolchain. | ||
| /// Node-based toolchains use nodemon; Deno uses its native file watcher, which prints | ||
| /// a different banner. | ||
| /// </summary> | ||
| internal static string GetWatchModeReadyText(string toolchain) => | ||
| NormalizeToolchain(toolchain) switch | ||
| { | ||
| "deno" => "Watcher Process started.", | ||
| _ => "Watching for file changes." | ||
| }; |
|
|
||
| Assert.Equal(TypeScriptAppHostToolchain.Deno, resolution.Toolchain); | ||
| Assert.Equal($"deno.json found in {workspace.WorkspaceRoot.FullName}", resolution.Reason); | ||
| } |
| internal static string GetWatchModeReadyText(string toolchain) => | ||
| NormalizeToolchain(toolchain) switch | ||
| { | ||
| "deno" => "Watcher Process started.", |
There was a problem hiding this comment.
I’m going to fix this before approval: the test calls deno task aspire:dev, which runs the scaffolded tsc --watch script, so it should wait for TypeScript’s Watching for file changes. banner instead of Deno’s native watcher text. I’ll update the helper/coverage and run the focused Deno validation.
The E2E watch path runs deno task aspire:dev, which executes the scaffolded tsc --watch script. Wait for the TypeScript compiler watch banner instead of Deno's native watcher banner. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Add Deno support to the TypeScript AppHost toolchain resolver
Closes #16218.
What
Adds a Deno branch to the CLI's TypeScript-AppHost toolchain resolver
(
src/Aspire.Cli/Projects/TypeScriptAppHostToolchainResolver.cs), so anapphost.mtscan run underthe Deno runtime exactly the way Bun already does today. This is the CLI/toolchain half of Deno
support — the counterpart to
#16218's tracked scope (toolchain resolution, CLI dependency handling,scaffolding, debugging).
Detection keys on
deno.lock/deno.json(c)(not thepackageManagerfield). Command vectors:deno installdeno check {file}deno run -A {file}deno run -A --check --watch {file}deno task --cwd <dir> <script>Diff is small and additive: +47 / -1 lines vs
main— it slots a Deno case alongside theexisting Bun/Node cases in the same resolver. No new architectural surface.
Why (precedent + demand)
main's resolver handles"Bun"/"bun"but has noDeno branch; this PR adds it. Deno mirrors Bun one-for-one and exceeds it on two vectors:
type-check is native
deno check {file}(vs Bun'sbun run tsc --noEmit) and watch is nativedeno run -A --check --watch(vs Bun's nodemon wrapper — no nodemon dependency). Resolver testcoverage parallels the Bun cases (18 Deno-specific tests).
.ts/.mtsdirectly, so the AppHost isdeno checked anddeno rund with no transpile step — something a Node AppHost cannot matchwithout a bundler.
#16218("Track Deno support for TypeScript AppHosts") isopen on milestone 13.5, split from
#15812("Support alternative JavaScript runtimes (Bun, Deno)").This PR is precisely that tracked work.
Independence
This PR is independently shippable and does not depend on Deno hosting (
AddDenoApp, trackedseparately). Ship this first to close #16218; the hosting resource can follow.
Proof (dogfooded against a real framework)
Verified end-to-end against the full NetScript framework (a heavy polyglot Aspire app): its
apphost.mtsruns under this resolver (deno checkexit 0; the CLI reports the running AppHost underthe fork build). Dogfood-proof record and re-runnable harness:
rickylabs/netscript#295 (umbrella) and the Layer-A tracking issue.
Test plan
Deno-specific tests).
deno.json-based AppHost, confirmaspire runselects the Deno toolchain andapphost.mtsboots.Checklist
+47/-1), no new public surface.deno run -Abecause Deno isdeny-by-default and the AppHost needs host access; this mirrors how the Bun/Node cases invoke their
runtimes. No threat model beyond that runtime-permission note.
🤖 Generated with Claude Code