Giter VIP home page Giter VIP logo

citty's People

Contributors

autofix-ci[bot] avatar barbapapazes avatar danielroe avatar eskydar avatar k-sato1995 avatar mandarini avatar muhammadm1998 avatar peterroe avatar pi0 avatar renovate[bot] avatar so1ve avatar sxzz avatar yidingww avatar zuixinwang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

citty's Issues

CLI format utils

We might export utils (as subpath) for formatting output. Also things like banners.

For general logging, consola is probably best but minor output formatting could be more integrated from CLI builder.

This might eventually be extracted to a standalone package.

๐Ÿ“’ Documentation

Describe the feature

Hi ๐Ÿ‘‹๐Ÿป

I'm fan of creating CLI application. I have typer library that does really good job in python. In JS, I plan to use citty but there's lack of documentation for me & my colleagues to get started and fully leverage it.

Can we have a dedicated documentation site for citty like unstorage & others?

P.S. Some of the unjs projects don't have enough docs to understand the value it provides ๐Ÿ˜ž

Additional information

  • Would you be willing to help implement this feature?

Process utils

CLIs often need utils for forking or exec.

We might reexport execa async utils (with dynamic import for CJS compact)

For on/off execa is perfect. Still not sure about forking. Execa supports execaNode too that supports IPC channel. However I'm not sure if gives enough flexibility for things like dev server (#7) or not. Still worth to try.

Add support for custom error handling

Describe the feature

When using subcommands, it would be nice to have error handling bubble up, much like setup and cleanup

Additional information

  • Would you be willing to help implement this feature?

Positional arguments not properly parsed

Environment

Node: v19.8.1
citty: 0.1.0

Reproduction

Run the following command: pnpm play build --dir="directory" entryArg dstArg

Describe the bug

The expected behavior is that the entryArg and dstArg arguments are parsed and returned by order of their position.
The actual behavior is an error message: EARG Missing required positional argument: ENTRY.

Additional context

No response

Logs

No response

(dev)server support

Making a dev server (like for nuxt, nitro, ipx, etc) often has many shared requirements. I'm thinking to expose a node-native util that makes it possible and instructions to opt-in to listhen for more elegancy.

Subcommand matching logic error

Environment

18.16.0

Reproduction

I have added a new subcommand named undefined in playground/cli.ts. Still, when I execute pnpm play without extra parameters, the console does not prompt that the command was not found but instead executes the undefined subcommand I defined.

I have checked the source code and am not sure why the "&& !cmd.run" condition is required here

Describe the bug

I have added a new subcommand named undefined in playground/cli.ts. Still, when I execute pnpm play without extra parameters, the console does not prompt that the command was not found but instead executes the undefined subcommand I defined.

I have checked the source code and am not sure why the "&& !cmd.run" condition is required here

Additional context

No response

Logs

No response

Support `createMain(command)` return value from `run` method

Describe the feature

import { createMain, defineCommand } from 'citty'

const command = defineCommand({
	//...
	async run() {
		return Promise.resolve("hello")
	}
})

const apiCommand = createMain(_rDefault(command))
 
const value = await apiCommand({
	rawArgs: []
})
console.log(value) //=> "hello"

Additional information

  • Would you be willing to help implement this feature?

`cleanup` is just a type

Hello,

In the types, you define a cleanup function but in the code, you never call a cleanup function.

image

default output should show command descriptions

Describe the feature

The descriptions of each command should be shown next to their label. So instead of this:

ving v1.0.0
ving CLI

USAGE: ving cache|drizzle|record|schema|user

COMMANDS:

    cache    
  drizzle    
   record    
   schema    
     user    

Use `ving <command> --help` for more information about a command.

You'd get this:

ving v1.0.0
ving CLI

USAGE: ving cache|drizzle|record|schema|user

COMMANDS:

    cache    Redis cache entries
  drizzle    Drizzle ORM code generation and migrations
   record    Ving Record code generation
   schema    Ving Schema code generation
     user    Manage users

Use `ving <command> --help` for more information about a command.

Additional information

  • Would you be willing to help implement this feature?

Support multiple (wildcard) positional args

Currently only speficic named positional args can be defined and multiple is not possible (workaround is to use ctx.args._ to access them all!). For this, we might introduce a new type multiPositional

Support hooks befor/after execute run func

Describe the feature

Add defs in defineCommand function like interceptors or middlewares

example:

const customInterceptor1 = (ctx: CommandContext) => false
const customInterceptor2 = (ctx: CommandContext) => console.log('before run.')

defineCommand({
  meta: {
    name: "hello",
    version: "1.0.0",
    description: "My Awesome CLI App",
  },
  interceptors: [customInterceptor1, customInterceptor2]
  run({ args }) {
    // output: before run.
    // and this code will not be execute
    console.log(`${args.friendly ? "Hi" : "Greetings"} ${args.name}!`);
  },
})

Additional information

  • Would you be willing to help implement this feature?

Passing custom usage/help method

Describe the feature

Currently, the generated usage is helpful but limited.

In our situation we would like to be able to display something like a prompt select to allow the user to run a command directly.

Additional information

  • Would you be willing to help implement this feature?

[Question] Process exit dont exit the terminal.

OS: Windows 11 Home latest
terminal: Windows Terminal latest
citty: version latest
node: v20.11.1
electron: v28.2.6

I have an electron app and I try to use citty for some simple commands but when I run the .exe file all works perfect but on in the end the process dont exit. I ask because maybe is my fault. Add process.exit in the run (maybe unnecessary), tell me if is wrong.

Code I use:

const main = defineCommand({
  meta: {
    name: "hello",
    version: "1.0.0",
    description: "My Awesome CLI App",
  },
  args: {
    name: {
      type: "positional",
      description: "Your name",
      required: true,
    },
    friendly: {
      type: "boolean",
      description: "Use friendly greeting",
    },
  },
  run({ args }) {
    console.log(`${args.friendly ? "Hi" : "Greetings"} ${args.name}!`)
    process.exit(0)
  }
})

runMain(main)

Edit: The weird thing... check how the terminal behaves...

C:\{path_to_the_project}>YourAppName.exe hello MyName

C:\{path_to_the_project}>
Greetings MyName!
(now terminal stuck)


(I press `enter` and then normal)
C:\{path_to_the_project}>

What behavior I expect:

C:\{path_to_the_project}>YourAppName.exe hello MyName
Greetings MyName!

C:\{path_to_the_project}>    (no stuck just exit)

Typescript bug when enable { strict: true }

Environment

citty 0.1.11
nodejs 16
pnpm 8

Reproduction

https://stackblitz.com/edit/stackblitz-starters-kvn1gq?file=src%2Findex.ts

Describe the bug

Type 'ParsedArgs<ArgsDef>' is not assignable to type 'Record<"blah", string>'

image

TS config:

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "Node",
    "esModuleInterop": true,
    "strict": true
  },
  "include": ["src"]
}

Additional context

The ts error is gone when i set strict to false in tsconfig.json

Logs

No response

Update checker

A simple fetch to npm registry probably does the trick for MVP.

We might support disk caching for faster responses later.

Optional: #9 for usage

Depends on #5 for banner format

Support multiple optional positional args

Describe the feature

When using lint-staged, the default behaviour is to pass filenames as positional arguments to linting CLIs, e.g.: your-cmd file1.ext file2.ext

AFAIK there's no way to support positional arguments in this way in citty.
So, if I want to be able to support multiple positional arguments in my Citty CLI commands, I can't do it right now (or, at least, it's unclear if there is a way to do so).

Additional information

  • Would you be willing to help implement this feature?

Doesn't work as a binary

Environment

node: v21.6.2
citty: ^0.1.6

Reproduction

https://github.com/malezjaa/elmen/blob/main/src/index.ts#L71

Describe the bug

I have a string argument called name:
image

It works fine when running locally:
image

But when i upload the package to npm and download it, it says Cannot access properties of null (reading name) even though args object contains the name:
image

Additional context

No response

Logs

No response

Support `enum` type for args

Describe the feature

Hello,

Having enum could help user for completing args!

Additional information

  • Would you be willing to help implement this feature?

Support auto case transformation for arguments

Describe the feature

Hello,

Imagine having an argument named 'joinGlue', I would love that the CLI support both joinGlue and join-glue.

Additional information

  • Would you be willing to help implement this feature?

citty if fantastic

I just wanted to give you kudos. citty is absolutely fantastic. Probably the best CLI builder DX I've had in my 30 years of code!

Feat: return usage as data instead of just a string

Describe the feature

We already have the feature of overriding the showUsage function on runMain, but the only way you cen compute the usage is as a string using the renderUsage function.

That means that if you wanted to enrich the usage output you have to recreate the renderUsage function locally and apply changes.

https://github.com/unjs/citty/blob/main/src/usage.ts#L18-L124

The downsides to this, is that it's fragile to new changes that may occur in commands and it's structure in the future.

I suggest that it should be considered to rethink the renderUsage method.

It could be great to either create some utils functions or class implementation for getting the usage as data that you can then manipulate.

The renderUsage method could then receive a implementation of a "render template" from which it can generate the string.

Use cases could be to group commands like:

โšก๏ธ My Awesome CLI Experience (foo v1.0.0)                                                                                                                                                                                                                                               7:51:33 AM

USAGE awesome init|dev|test|build|info|deploy|start

COMMANDS

    Development 
           init    Create a new awesome file.                                          
            dev    Run awsome dev server
           test    Run tests                                                            

     Production           
          build    Build a awesome file
           info    Get information about your awesome bundle                                   

     Deployment
         deploy    Deploy your awesome file to your server
          start    Launches your awesome file

Use nuxi <command> --help for more information about a command.

Or what ever makes a good documented cli for different use case.

The main topic here is to add the opt-it feature of defining your own render usage "template".

What do you guys think? ๐Ÿ™‚

Additional information

  • Would you be willing to help implement this feature?

Support `setup` to return data

Describe the feature

export default defineCommand({
    meta: {
        name: 'test',
        description: 'Test command',
    },
    async setup(context) {
        const data = someComputed(context)
		return { data }
    },
    async run({ args }, { data }) {
		console.log(data)
	}
})

Reason

The return value of setup could be useful, in addition to some initialization behavior, it could potentially produce different values depending on the context, which could be used in setup and passed to all subcommands in the run method arguments!

Of course, I may not have thought this through completely, does anyone else have a better suggestion?

Additional information

  • Would you be willing to help implement this feature?

Hiding internal commands

Describe the feature

Being able to ship and expose internal commands but not showing it to users.

Additional information

  • Would you be willing to help implement this feature?

test: improve test coverage

Describe the feature

I found that Citty has no test at the moment.
It's better to have at least unit tests so that we can accept new features and bug fixes from the community as well as unjs members.

I created this issue just for making the situation clear and trackable.

@pi0

Perhaps, are you postponing test implementation based one some thoughts?
If not, I will start working on this issue from adding unit tests.

Additional information

  • Would you be willing to help implement this feature?

Support `transformCommandToApi` util

Describe the feature

// build.ts
export default defineCommand({
  meta: {
    name: 'build',
    description: 'build command',
  },
  args: {
    minify: {
      type: 'boolean',
      description: 'minify file size',
    },
    mode: {
      type: 'string',
      description: 'environment variable'
    }
  }
})
// api/index.ts

import build from './build'
import { transformCommandToApi } from 'citty'

export const apiBuild = transformCommandToApi(build)
// test.ts

import { apiBuild } from './api'

apiBuild({  // directly invoke with api
  minify: true,
  mode: false
})

Reason

Because defineCommand already defines all the information related to a command, it is very easy to convert it into a direct call to API.

Additional information

  • Would you be willing to help implement this feature?

Update documentation to reflect more the current API

related to #46

Hello,

This issue will be used to track documentation update that we need to provide.

PR welcomes to help! (and do not hesitate to comment if you have more idea)

Tasks

Using citty with bun results in "Import named 'formatWithOptions' not found in module 'node:util'."

Environment

"citty": "^0.1.2",
node: 19.9.0
bun: 0.7.3
os: ubuntu 22.04 LTS

Reproduction

https://github.com/emdahlstrom/citty-formatWithOptions

Describe the bug

Trying to run the citty readme example code with bun leads to an error:

SyntaxError: Import named 'formatWithOptions' not found in module 'node:util'.

Additional context

  • I understand that this is likely an issue with bun node compatibility and that it simply might not be your problem.
  • I haven't found any references to the error or bun documentation about this part of the node api.
  • I got the same error using just consola
  • โค๏ธ

Logs

em@silverbook:~/code/reproductions/citty-formatWithOptions$ bun start
$ bun run index.ts
SyntaxError: Import named 'formatWithOptions' not found in module 'node:util'.
error: script "start" exited with code 1 (SIGHUP)

CLI Plugins

inspired from #98 (comment) by @jgoux

With plugins, we can allow them to intercept to different hooks but also preserve their context. We can extend to more hooks if needed.

Example:

const telemetryPlugin = defineCittyPlugin(() => {
  const telemetry = new TelemetryClient();

  return {
    name: 'telemetry',
    async setup() {
      telemetry.init();
      await telemetry.captureEvent(`$command:${ctx.cmd.meta.name}:start`); 
    },
    async cleanup() {
      await telemetry.captureEvent(`$command:${ctx.cmd.meta.name}:end`);
      telemetry.flush();
    }
  }
})

defineCommand({
  meta: {
    name: "hello",
    version: "1.0.0",
    description: "My Awesome CLI App",
  },
  plugins: [telemetryPlugin],
  run({ args }) {
    console.log(`${args.friendly ? "Hi" : "Greetings"} ${args.name}!`);
  },
})

cache async results

Describe the feature

Caching the results after calling the resolveValue function

Additional information

  • Would you be willing to help implement this feature?

Missing `-v` or `--version` flag

Describe the feature

Hello,

Since Citty automatically support -h or --help, we could natively support -v --version.

Additional information

  • Would you be willing to help implement this feature?

Undefined value of subcommand argument of run method

Environment

node.js 21.0.0 LTS

Reproduction

just try the code

usage/output:

$ node test_citty.js format
Formatting!
undefined
This is the main command. Use 'format' or 'help'.
import { defineCommand, runMain } from "citty";

const formatCommand = defineCommand({
  meta: {
    name: "format",
    description: "Format something",
  },
  run() {
    console.log("Formatting!");
  },
});

const helpCommand = defineCommand({
  meta: {
    name: "help",
    description: "Display help information",
  },
  run() {
    console.log("Look at this!");
  },
});

const mainCommand = defineCommand({
  meta: {
    name: "main.js",
    version: "1.0.0",
    description: "CLI with 'format' and 'help' commands",
  },
  subCommands: {
    format: formatCommand,
    help: helpCommand,
  },
  run({subCommand}) {
    console.log(subCommand)
    console.log("This is the main command. Use 'format' or 'help'.");
  },
});

runMain(mainCommand);

Describe the bug

I expect it to have all properties like meta, args, and stuff of subcommand currently runned

Additional context

No response

Logs

No response

Support `multiple` in `ArgType`

Describe the feature

Feature to solve: #80

export default defineCommand({
  meta: {
    name: "lint",
    description: "A test command",
  },
  args: {
    files: {
      type: "multiple",
      description: "Files need be lint",
    },
  },
  run({ args }) {
	// lint fileA.ts fileB.ts
	console.log(args.files) //=> ['fileA.ts', 'fileB.ts]
  },
});

Additional information

  • Would you be willing to help implement this feature?

Setup function support

Apart from run, we usually have common setup parts for cli and cli-sub commands handling global things like registering consola or start update checker in background.

number type

Describe the feature

Would be really cool if you could set an input as type number and have it cast as such automatically.

Additional information

  • Would you be willing to help implement this feature?

Support `validator` in args definition

Describe the feature

export default defineCommand({
  meta: {
    name: "Test",
    description: "A test command",
  },
  args: {
    len: {
      type: "string",
      description: "Limit len",
      validator(value) {
        return Number(value) > 24 & Number(value) < 999 ? true : "Len must more than 24 and less than 999 ";
      }
    },
  },
  run({ args }) {
  },
});

Additional information

  • Would you be willing to help implement this feature?

Expose `createMain`

Expose a wrapper for runMain to create a runMain with bonded main command.

Support argument normalizer/validator

Describe the feature

I am using citty in my project, And I think it's maybe a good idea to support it. ๐Ÿ‘€

This is my source code:

export default defineCommand({
    meta: {
        name: 'create',
        description: 'Generate new project from template'
    },
    args: {
        projectPath: {
            type: 'string',
            description: 'Project path to create',
            valueHint: "PWD",
            default: process.cwd()
        },
	},
	setup({ args }) {
        args.projectPath = path.resolve(args.projectPath)
    },
	run() {}
}

And support formatter attribute in args definition, then we can do like this:

export default defineCommand({
    meta: {
        name: 'create',
        description: 'Generate new project from template'
    },
    args: {
        projectPath: {
            type: 'string',
            description: 'Project path to create',
            valueHint: "PWD",
            default: process.cwd(),
+			formatter: (inputPath) => path.resolve(inputPath)
        },
	},
-	setup({ args }) {
-        args.projectPath = path.resolve(inputPath)
-    },
	run() {}
}

Additional information

  • Would you be willing to help implement this feature?

`--flag` with a default value of `true` does not match the description

Environment

nodejs v16.14.0

Reproduction

--flag with a default value of true does not match the description because of the auto-generated --no-flag options usage

I am migrating the unjs/mkdist CLI to unjs/citty, here is the link

here is the Reproduction link
1686489628835

Describe the bug

--flag with a default value of true does not match the description because of the auto-generated --no-flag options usage

I am migrating the unjs/mkdist CLI to unjs/citty, here is the link

here is the Reproduction link

Additional context

Or describe an opposite meaning?๐Ÿ‘€

Logs

No response

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Awaiting Schedule

These updates are awaiting their schedule. Click on a checkbox to get an update now.

  • chore(deps): update all non-major dependencies (@types/node, @vitest/coverage-v8, eslint-config-unjs, vitest)

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

github-actions
.github/workflows/autofix.yml
  • actions/checkout v4
  • actions/setup-node v4
  • autofix-ci/action ea32e3a12414e6d3183163c3424a7d7a8631ad84
.github/workflows/ci.yml
  • actions/checkout v4
  • actions/setup-node v4
  • codecov/codecov-action v4
npm
package.json
  • consola ^3.2.3
  • @types/node ^20.12.7
  • @vitest/coverage-v8 ^1.5.2
  • automd ^0.3.7
  • changelogen ^0.5.5
  • eslint ^8.57.0
  • eslint-config-unjs ^0.2.1
  • jiti ^1.21.0
  • prettier ^3.2.5
  • scule ^1.3.0
  • typescript ^5.4.5
  • unbuild ^2.0.0
  • vitest ^1.5.2
  • pnpm 9.0.6

  • Check this box to trigger a request for Renovate to run again on this repository

Disabling Glob Pattern Parsing

Describe the feature

Hi there! Just in the process of using Citty to build a cli and I'm really liking it so far.

I've hit a bit of a snag though regarding glob patterns in string arguments.

Is there a way to disable glob pattern parsing of arguments? I'm noticing for string args, if I pass in a glob pattern, the args and rawArgs passed into the run function are processed into file paths. I need to disable this as I'm processing the glob patterns separately.

Thanks!
Brett

Additional information

  • Would you be willing to help implement this feature?

unbuild preset and build instructions

Defining commands is one part of building a good CLI.

Bundling it properly is another part! An unbuild preset can be specifically useful to build a (main cli) and pluggable CLI.

Support direct execution by ignoring `subCommands ` when `run` has been set

Describe the feature

// A.ts
export default defineCommand({
    meta: {
        name: 'A',
        description: 'Test command',
    },
    async run({ args }) {
		console.log("A execute")
    }
})
// B.ts
export default defineCommand({
    meta: {
        name: 'B',
        description: 'Test command',
    },
    async run({ args }) {
		console.log("B execute")
    }
})
// main.ts
export default defineCommand({
    meta: {
        name: 'main',
        description: 'Test command',
    },
	subCommands: {
        A: () => import('./A').then(r => r.default),
        B: () => import('./B').then(r => r.default),
    },
    async run({ args }) {
		console.log("Main execute")
    }
})

Expected behavior

$ main A
A execute
$ main B
B execute
$ main
Main execute

Actual behavior

$ main A
A execute
$ main B
B execute
$ main
ERROR  No command specified.  # can's support direct exec

Additional information

  • Would you be willing to help implement this feature?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.