diff --git a/package.json b/package.json index 75bf57e0aa..8f197ed509 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "devDependencies": { "@azure/functions": "^3.5.1", "@azure/static-web-apps-cli": "^2.0.7", + "@bomb.sh/tab": "^0.0.9", "@cloudflare/workers-types": "^4.20251008.0", "@deno/types": "^0.0.1", "@netlify/edge-functions": "^2.18.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c8ae3bc981..2133891750 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -73,6 +73,9 @@ importers: '@azure/static-web-apps-cli': specifier: ^2.0.7 version: 2.0.7 + '@bomb.sh/tab': + specifier: ^0.0.9 + version: 0.0.9(cac@6.7.14)(citty@0.1.6) '@cloudflare/workers-types': specifier: ^4.20251008.0 version: 4.20251008.0 @@ -534,6 +537,21 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} + '@bomb.sh/tab@0.0.9': + resolution: {integrity: sha512-HUJ0b+LkZpLsyn0u7G/H5aJioAdSLqWMWX5ryuFS6n70MOEFu+SGrF8d8u6HzI1gINVQTvsfoxDLcjWkmI0AWg==} + hasBin: true + peerDependencies: + cac: ^6.7.14 + citty: ^0.1.6 + commander: ^13.1.0 + peerDependenciesMeta: + cac: + optional: true + citty: + optional: true + commander: + optional: true + '@cloudflare/kv-asset-handler@0.4.0': resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==} engines: {node: '>=18.0.0'} @@ -6785,6 +6803,11 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} + '@bomb.sh/tab@0.0.9(cac@6.7.14)(citty@0.1.6)': + optionalDependencies: + cac: 6.7.14 + citty: 0.1.6 + '@cloudflare/kv-asset-handler@0.4.0': dependencies: mime: 3.0.0 diff --git a/src/cli/completions.ts b/src/cli/completions.ts new file mode 100644 index 0000000000..d98b98af28 --- /dev/null +++ b/src/cli/completions.ts @@ -0,0 +1,148 @@ +import type { ArgsDef, CommandDef } from "citty"; +import tab from "@bomb.sh/tab/citty"; + +export async function initCompletions( + command: CommandDef +) { + const completion = await tab(command); + + const devCommand = completion.commands.get("dev"); + if (devCommand) { + const portOption = devCommand.options.get("port"); + if (portOption) { + portOption.handler = (complete) => { + complete("3000", "Default development port"); + complete("3001", "Alternative port"); + complete("8080", "Common alternative port"); + complete("4000", "Another common port"); + }; + } + + const hostOption = devCommand.options.get("host"); + if (hostOption) { + hostOption.handler = (complete) => { + complete("localhost", "Local development"); + complete("0.0.0.0", "Listen on all interfaces"); + complete("127.0.0.1", "Loopback address"); + }; + } + + const dirOption = devCommand.options.get("dir"); + if (dirOption) { + dirOption.handler = (complete) => { + complete(".", "Current directory"); + }; + } + } + + const buildCommand = completion.commands.get("build"); + if (buildCommand) { + const presetOption = buildCommand.options.get("preset"); + if (presetOption) { + presetOption.handler = (complete) => { + complete("node-server", "Node.js server"); + complete("node-middleware", "Node.js middleware"); + complete("node-cluster", "Node.js cluster mode"); + + // Static presets + complete("static", "Static hosting"); + complete("github-pages", "GitHub Pages"); + complete("gitlab-pages", "GitLab Pages"); + + complete("cloudflare-pages", "Cloudflare Pages"); + complete("cloudflare-pages-static", "Cloudflare Pages (static)"); + complete("cloudflare-module", "Cloudflare Workers (module)"); + complete("cloudflare-durable", "Cloudflare Durable Objects"); + complete("vercel", "Vercel"); + complete("vercel-static", "Vercel (static)"); + complete("netlify", "Netlify"); + complete("netlify-edge", "Netlify Edge Functions"); + complete("netlify-static", "Netlify (static)"); + + complete("aws-lambda", "AWS Lambda"); + complete("aws-amplify", "AWS Amplify"); + + complete("azure-swa", "Azure Static Web Apps"); + + complete("firebase-app-hosting", "Firebase App Hosting"); + complete("deno-deploy", "Deno Deploy"); + complete("deno-server", "Deno Server"); + complete("bun", "Bun runtime"); + complete("digital-ocean", "DigitalOcean"); + complete("heroku", "Heroku"); + complete("render-com", "Render.com"); + complete("zeabur", "Zeabur"); + complete("zeabur-static", "Zeabur (static)"); + complete("zerops", "Zerops"); + complete("zerops-static", "Zerops (static)"); + complete("koyeb", "Koyeb"); + complete("platform-sh", "Platform.sh"); + complete("flight-control", "FlightControl"); + complete("cleavr", "Cleavr"); + complete("stormkit", "Stormkit"); + complete("genezio", "Genezio"); + complete("alwaysdata", "AlwaysData"); + + complete("iis-handler", "IIS Handler"); + complete("iis-node", "IIS Node"); + complete("winterjs", "WinterJS"); + complete("standard", "Standard runtime"); + }; + } + + const minifyOption = buildCommand.options.get("minify"); + if (minifyOption) { + minifyOption.handler = (complete) => { + complete("true", "Enable minification"); + complete("false", "Disable minification"); + }; + } + + const dirOption = buildCommand.options.get("dir"); + if (dirOption) { + dirOption.handler = (complete) => { + complete(".", "Current directory"); + }; + } + } + + const prepareCommand = completion.commands.get("prepare"); + if (prepareCommand) { + const dirOption = prepareCommand.options.get("dir"); + if (dirOption) { + dirOption.handler = (complete) => { + complete(".", "Current directory"); + }; + } + } + + const taskListCommand = completion.commands.get("task list"); + if (taskListCommand) { + const dirOption = taskListCommand.options.get("dir"); + if (dirOption) { + dirOption.handler = (complete: (value: string, description: string) => void) => { + complete(".", "Current directory"); + }; + } + } + + const taskRunCommand = completion.commands.get("task run"); + if (taskRunCommand) { + const dirOption = taskRunCommand.options.get("dir"); + if (dirOption) { + dirOption.handler = (complete: (value: string, description: string) => void) => { + complete(".", "Current directory"); + }; + } + + const payloadOption = taskRunCommand.options.get("payload"); + if (payloadOption) { + payloadOption.handler = (complete: (value: string, description: string) => void) => { + complete("{}", ""); + }; + } + } + + return completion; +} + diff --git a/src/cli/index.ts b/src/cli/index.ts index bc3f21d7bb..7b1553bdb3 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -1,6 +1,7 @@ #!/usr/bin/env node -import { defineCommand, runMain } from "citty"; +import { defineCommand, runMain as _runMain } from "citty"; import { version as nitroVersion } from "nitro/meta"; +import { initCompletions } from "./completions"; const main = defineCommand({ meta: { @@ -16,4 +17,9 @@ const main = defineCommand({ }, }); -runMain(main); +async function runMain() { + await initCompletions(main); + return _runMain(main); +} + +runMain();