| File: DenoCommandLineAnnotation.cs | Web Access |
| Project: src\src\Aspire.Hosting.JavaScript\Aspire.Hosting.JavaScript.csproj (Aspire.Hosting.JavaScript) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #pragma warning disable ASPIREDENO001 // Deno APIs use this implementation type internally using System.Diagnostics.CodeAnalysis; using Aspire.Hosting.ApplicationModel; namespace Aspire.Hosting.JavaScript; /// <summary> /// The Deno sub-command a <see cref="DenoAppResource"/> is launched with. /// </summary> internal enum DenoCommandMode { /// <summary>Execute a script entrypoint with <c>deno run</c>.</summary> Run, /// <summary>Execute a named task from <c>deno.json</c> with <c>deno task</c>.</summary> Task, /// <summary>Serve an HTTP entrypoint with <c>deno serve</c>.</summary> Serve, } /// <summary> /// The Deno inspector flavor. /// </summary> [Experimental("ASPIREDENO001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] public enum DenoInspectMode { /// <summary><c>--inspect</c> — attach a debugger; execution starts immediately.</summary> Inspect, /// <summary><c>--inspect-brk</c> — attach a debugger and break on the first statement.</summary> InspectBrk, /// <summary><c>--inspect-wait</c> — wait for a debugger to attach before running any code.</summary> InspectWait, } /// <summary> /// Controls how Deno manages a local <c>node_modules</c> directory. /// </summary> [Experimental("ASPIREDENO001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] public enum DenoNodeModulesDirMode { /// <summary>Do not use a local <c>node_modules</c> directory.</summary> None, /// <summary>Automatically manage a local <c>node_modules</c> directory when packages require it.</summary> Auto, /// <summary>Use a manually managed local <c>node_modules</c> directory.</summary> Manual, } /// <summary> /// A granular Deno permission grant/denial (for example <c>--allow-net</c> or <c>--deny-read</c>). /// </summary> [Experimental("ASPIREDENO001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] public enum DenoPermissionKind { /// <summary>Network access controlled by <c>--allow-net</c> or <c>--deny-net</c>.</summary> Net, /// <summary>File-system read access controlled by <c>--allow-read</c> or <c>--deny-read</c>.</summary> Read, /// <summary>File-system write access controlled by <c>--allow-write</c> or <c>--deny-write</c>.</summary> Write, /// <summary>Subprocess execution controlled by <c>--allow-run</c> or <c>--deny-run</c>.</summary> Run, /// <summary>Environment-variable access controlled by <c>--allow-env</c> or <c>--deny-env</c>.</summary> Env, /// <summary>Remote import access controlled by <c>--allow-import</c> or <c>--deny-import</c>.</summary> Import, /// <summary>System-information access controlled by <c>--allow-sys</c> or <c>--deny-sys</c>.</summary> Sys, /// <summary>Foreign-function-interface access controlled by <c>--allow-ffi</c> or <c>--deny-ffi</c>.</summary> Ffi, } /// <summary> /// A single granular Deno permission flag with an optional comma-separated value list. /// </summary> internal sealed class DenoPermission { public required DenoPermissionKind Kind { get; init; } public required bool Deny { get; init; } public IReadOnlyList<string> Values { get; init; } = []; /// <summary> /// The flag name segment used to build <c>--allow-{name}</c>/<c>--deny-{name}</c>. /// </summary> public string Name => Kind switch { DenoPermissionKind.Net => "net", DenoPermissionKind.Read => "read", DenoPermissionKind.Write => "write", DenoPermissionKind.Run => "run", DenoPermissionKind.Env => "env", DenoPermissionKind.Import => "import", DenoPermissionKind.Sys => "sys", DenoPermissionKind.Ffi => "ffi", _ => Kind.ToString().ToLowerInvariant(), }; } /// <summary> /// Captures the full Deno command-line surface for a <see cref="DenoAppResource"/>. /// </summary> /// <remarks> /// When present on a Deno resource this annotation fully controls the emitted argument list, replacing the /// default <c>deno run -A <script></c> form. The fluent <c>WithDeno*</c> extension methods mutate a single /// instance of this annotation so flags compose predictably regardless of call order, and the resulting args are /// emitted in valid Deno CLI order: <c>deno <mode> [runtime-flags] <entrypoint> [script-args]</c>. /// </remarks> internal sealed class DenoCommandLineAnnotation : IResourceAnnotation { /// <summary>The sub-command mode (<c>run</c>, <c>task</c>, or <c>serve</c>). Defaults to <c>run</c>.</summary> public DenoCommandMode Mode { get; set; } = DenoCommandMode.Run; /// <summary>Whether a fluent mode method explicitly selected <see cref="Mode"/>.</summary> public bool ModeSet { get; set; } /// <summary> /// The HTTP endpoint used by <c>WithDenoServe</c>. /// </summary> public EndpointAnnotation? ServeEndpoint { get; set; } /// <summary>Whether <see cref="ServeEndpoint"/> was created by <c>WithDenoServe</c>.</summary> public bool ServeEndpointCreated { get; set; } /// <summary> /// The environment callback created when <c>WithDenoServe</c> maps the endpoint target port to <c>PORT</c>. /// </summary> public EnvironmentCallbackAnnotation? ServeEnvironmentCallback { get; set; } /// <summary>The publish target port assigned by <c>WithDenoServe</c>, if it supplied one.</summary> public int? ServeAssignedTargetPort { get; set; } /// <summary>The task name to invoke when <see cref="Mode"/> is <see cref="DenoCommandMode.Task"/>.</summary> public string? TaskName { get; set; } /// <summary> /// Tri-state <c>-A</c>/<c>--allow-all</c> control. <see langword="null"/> means "default": emit <c>-A</c> /// only when no granular allow permission has been configured (preserving backward-compatible behavior). /// </summary> public bool? AllowAll { get; set; } /// <summary>Granular permission grants/denials.</summary> public List<DenoPermission> Permissions { get; } = []; /// <summary><c>--config <file></c>.</summary> public string? ConfigFile { get; set; } /// <summary><c>--import-map <file></c>.</summary> public string? ImportMap { get; set; } /// <summary><c>--lock <file></c>.</summary> public string? Lock { get; set; } /// <summary><c>--no-lock</c>.</summary> public bool NoLock { get; set; } /// <summary>Whether <c>--node-modules-dir</c> was requested.</summary> public bool NodeModulesDirSet { get; set; } /// <summary>Optional mode for <c>--node-modules-dir=<mode></c>.</summary> public DenoNodeModulesDirMode? NodeModulesDirMode { get; set; } /// <summary>Fully-formed <c>--unstable-*</c> flags.</summary> public List<string> UnstableFlags { get; } = []; /// <summary><c>--watch</c>.</summary> public bool Watch { get; set; } /// <summary><c>--watch-hmr</c>.</summary> public bool WatchHmr { get; set; } /// <summary>The inspector flavor, if any.</summary> public DenoInspectMode? Inspect { get; set; } /// <summary>Optional <c>host:port</c> for the inspector flag.</summary> public string? InspectHostPort { get; set; } /// <summary>Raw runtime args injected verbatim BEFORE the entrypoint (escape hatch / AddExecutable parity).</summary> public List<string> RuntimeArgs { get; } = []; /// <summary>Args passed to the script AFTER the entrypoint.</summary> public List<string> ScriptArgs { get; } = []; }