Skip to content

manolo-in/mcmd

Repository files navigation

cover

MCMD - A Meta framework for building CLIs tools

MCMD short name for Meta Framework for Command. Inspired from Next.JS (Meta Framework for React.JS)

Enjoy the DX of File Based Routing for CLI development with zod validation and TypeScript support out of the box.

Usage

Install MCMD package from NPM

Or clone the ready-made template from MCMD github repository

npx create mcmd-app --name my-cli
bun create mcmd-app --name my-cli

Install MCMD skill (skills.sh)

You can install the MCMD skill files from this repository using the Skills CLI:

npx skills add manolo-in/mcmd

This pulls the repository skill collection (including mcmd-cli) so developers can use the same guidance in their own projects.

Folder Structure

root
 ├── .mcmd
 ├── node_modules
 │
 ├─┬ app
 │ ├── index.ts          # npx my-cli
 │ ├── config.ts         # config file
 │ ├─┬ init
 │ │ ├── something.ts    # npx my-cli init something
 │ │ └── index.ts        # npx my-cli init
 │ └── login.ts          # npx my-cli login
 │
 ├── package.json
 ├── .gitignore
 ├── README.md
 ├── tsconfig.json
 └── tsdown.config.ts    # default bundler

Coding

Don't need to import zod or Command, we'll handle everything for you.

// app/index.ts

export const options = z.object({
	name: z.string(),
});

export default Command((data) => {
	const { name } = data;
	Console.log("Hi", name);
});

// npx my-cli --name Rajat
// app/init.ts

export default () => {
	// a custom console with colors and prompts support
	Console.log("Done Init");
};

// npx my-cli init

Usage

Transpile the code (dev mode)

npx mcmd transpile

Run the CLI before converting to javascript

node ./.mcmd/cli.ts --name Rajat

# or
tsx ./.mcmd/cli.ts --name Rajat
bun run ./.mcmd/cli.ts --name Rajat

Build the CLI

npx mcmd build

Run the CLI after converting to javascript

node ./dist/cli.js --name Rajat

# or
bun run ./dist/cli.js --name Rajat

Final Build

npx mcmd build

# or, split the work
npx mcmd transpile
npx tsdown

Important

Make sure to have a bundler config file for tsdown before building

// tsdown.config.ts

import { defineConfig } from "tsdown";

export default defineConfig([
	{
		entry: ["./.mcmd/cli.ts"],
		format: ["esm"],
		outDir: "bin",
		dts: false,
		banner: {
			js: "#!/usr/bin/env node",
		},
	},
]);

Publish CLI

// package.json
{
    "name": "my-cli",
    "version": "0.0.0",
    "bin": "./dist/cli.js",
    "files": ["dist/**/*"],
    ...
}
npm login
npm publish

Enjoy CLI

bunx my-cli --name Rajat

# or
npx my-cli --name Rajat

TypeScript Support

Extends you tsconfig.json with mcmd/base.json

{
	// tsconfig.json
	"compilerOptions": {},
	"extends": ["mcmd/base.json"]
}

Or directly use mcmd/type in tsconfig.json

{
	// tsconfig.json
	"compilerOptions": {
		"types": ["mcmd/type"]
	}
}

Or paste this code to ./type.d.ts

// Don't remove this.
// This helps for automatic type assigning for MCMD.
/// <reference types="mcmd/type" />

Follow this code to get full TypeScript support

// app/index.ts
export const options = z.object({
	name: z.string(),
});

export default Command<typeof options, {}>((data, beforeData) => {
	const { name } = data;
	Console.log("Hi", name);
});

Configuration

Create the file config.ts inside the app folder and paste this.

export default defineConfig({
	// paste your parser config here
	// eg
	parser: {
		string: ["bar"],
		configuration: {
			"boolean-negation": false,
		},
	},
	// custom hook for before and after running the command
	hook: {
		// before, but after parsing the arguments
		before: async (commands, data) => {
			return beforeData; // access this ↴
		},
		// export default Command((data, beforeData) => {})

		extra: async (commands, data) => {
			return extraData; // access this ↴
		},

		after: async (commands, dataWithExtraData) => {},
	},
});

BYOB - Bring Your Own Bundler

By default, mcmd do the transpiling and tsdown take care of final bundling.

You can customize it by bringing your own bundler like tsup or unbuild

npx mcmd transpile
// tsup.config.ts

import { defineConfig } from "tsup";

export default defineConfig({
	entry: ["./.mcmd/cli.ts"], // entry point of mcmd
	format: ["esm"],
	outDir: "bin",
	dts: false,
	banner: {
		js: "#!/usr/bin/env node",
	},
});
npx tsup

References

MCMD is built on top of some amazing libraries, you can directly use them in your code without installing them separately.

About

A meta framework for building CLI tools

Topics

Resources

Stars

6 stars

Watchers

0 watching

Forks

Contributors