• Stars
    star
    252
  • Rank 161,312 (Top 4 %)
  • Language
    TypeScript
  • Created over 8 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

⌨ The command-line interface framework for TypeScript.

NPM Package Build Status Coverage Status

Clime

The command-line interface framework for TypeScript, fully tested with baseman.

Prerequisites

  • Node.js 6+
  • TypeScript compilation options in tsconfig.json
    • target needs to be set as 'es6' / 'es2015' or higher.
    • experimentalDecorators and emitDecoratorMetadata should both be enabled.

Install

yarn add clime
# or
npm install clime --save

Usage

Here is a basic example, an entry file (usually won't change much among time) and a single command:

src/cli.ts

#!/usr/bin/env node

import * as Path from 'path';
import {CLI, Shim} from 'clime';

// The second parameter is the path to folder that contains command modules.
let cli = new CLI('greet', Path.join(__dirname, 'commands'));

// Clime in its core provides an object-based command-line infrastructure.
// To have it work as a common CLI, a shim needs to be applied:
let shim = new Shim(cli);
shim.execute(process.argv);

src/commands/default.ts

import {Command, command, param} from 'clime';

@command({
  description: 'This is a command for printing a greeting message',
})
export default class extends Command {
  execute(
    @param({
      description: 'Your loud name',
      required: true,
    })
    name: string,
  ) {
    return `Hello, ${name}!`;
  }
}

Features

  • Type and schema based parameters/options casting
  • Object and promise based architecture
  • ☑ File path based multi-level subcommands
  • Automatic usage generating
  • Multiple command roots support New in v0.5

Parameter types and options schema

Clime provides a way in which you can get parameters and options you really want to: typed at compile time and casted at run time.

import {Command, Options, command, option, param, params} from 'clime';

export class SomeOptions extends Options {
  @option({
    flag: 't',
    description: 'timeout that does nothing',
  })
  timeout: number;

  // You can also create methods and properties.
  get timeoutInSeconds(): number {
    return this.timeout / 1000;
  }
}

@command()
export default class extends Command {
  execute(
    @param({
      required: true,
      description: 'required parameter foo',
    })
    foo: string,
    @param({
      description: 'optional parameter bar',
    })
    bar: number,
    @params({
      type: String,
      description: 'extra parameters',
    })
    args: string[],
    options: SomeOptions,
  ) {
    return 'Hello, Clime!';
  }
}

And this is what you get for usage/help information:

USAGE

  command <foo> [bar] [...args] [...options]

  foo  - required parameter foo
  bar  - optional parameter bar
  args - extra parameters

OPTIONS

  -t, --timeout <timeout> - timeout that does nothing

Casting from string

Clime will automatically cast parameters to number, boolean based on their types. It also defines interface StringCastable that allows user-defined classes to be casted from parameters.

Please note that StringCastable is correspondent to the type of constructor instead of instance, so no implements should be present.

For example:

import {CastingContext} from 'clime';

class File {
  constructor(public path: string) {}

  static cast(path: string, context: CastingContext<File>): File {
    return new File(Path.resolve(context.cwd, path));
  }
}

Validators

A validator or validators can be specified for parameters and options validation. A validator can either be an instance that implements interface Validator<T>, a function that matches type ValidatorFunction<T> or a regular expression.

For the validators in forms other than regular expression, it is the casted value that will be tested against. And for regular expression validator, the source string will be tested against instead.

Expected error

A useful way to distinguish expected errors (e.g., errors that might be caused by incorrect user input) from other errors is to throw instances of ExpectedError class or its subclasses. And a validator for example, usually throw instances of ExpectedError.

Preserving metadata without command-line parameters

As TypeScript only emits metadata for target decorated by decorators, if no command-line parameter added, Clime won't be able to know information of options and context parameter. Thus a @metadata decorator that does nothing at run time is provided for preserving these metadata:

@command()
export default class extends Command {
  @metadata
  execute(options: SomeOptions) {
    return 'Hello, Clime!';
  }
}

It is required to have this @metadata decorator if no other decorator is applied to method execute.

Context

Context is an object contains information like current working directory and commands sequence. You can have context passed in by adding the last parameter of execute method with type Context:

@command()
export default class extends Command {
  @metadata
  execute(context: Context) {
    return 'Hello, Clime!';
  }
}

Subcommands

Clime provides an easy way to create subcommands. The default entry of a clime command is default.js (default.ts before compilation of course). Any other .js files under the same folder are considered as subcommand files.

Clime allows multi-level subcommands based on file structures. For three-level commands like below:

command

command foo
command foo biu
command foo yo

command bar
command bar bia
command bar pia

The file structure could be:

- commands
  - default.ts
  - foo.ts
  - foo
    - biu.ts
    - yo.ts
  - bar
    - default.ts
    - bia.ts
    - pia.ts

You may notice that the level-n entry could be either at the same level of the level-(n+1) commands with name default.ts (like default.ts in bar), or at the same level of the folder of level-(n+1) commands (like foo.ts and folder foo).

Command entry with description only

Clime allows an entry of a group of subcommands to provide only descriptions rather than an actual command. Just export description and brief directly from the entry module to do so:

export const description = 'Some detailed description';

// Used when listing as subcommands.
export const brief = 'brief description';

Configuring subcommand definitions using subcommands field

Clime has to load every subcommand modules under a specific command to know their briefs. To avoid this, you may export a subcommands array with subcommand definitions like below:

import {SubcommandDefinition} from 'clime';

export const subcommands: SubcommandDefinition[] = [
  {
    name: 'foo',
    brief: 'A subcommand named foo',
  },
  {
    name: 'bar',
    brief: 'A subcommand named bar',
  },
];

Further more, those definition entries also allow you to add alias or aliases for subcommands:

import {SubcommandDefinition} from 'clime';

export const subcommands: SubcommandDefinition[] = [
  {
    name: 'foo',
    alias: 'f',
    brief: 'A subcommand named foo',
  },
  {
    name: 'bar',
    aliases: ['b', 'bb'],
    brief: 'A subcommand named bar',
  },
];

Multiple command roots support

For some CLI tools, it would be nice to support project specific commands. And Clime has this ability built-in.

For example, you may define the cli object like below to load commands from both CLI tool commands path as well as project path:

let cli = new CLI('greet', [
  Path.join(__dirname, 'commands'),
  'project-commands',
]);

And you can also add different labels for those command directories:

let cli = new CLI('greet', [
  {
    label: 'Built-in',
    path: Path.join(__dirname, 'commands'),
  },
  {
    label: 'Extra',
    path: 'project-commands',
  },
]);

Testable

As the core of Clime is not coupled with stream-based command line, commands written with Clime can be easily tested.

For example:

import {Command, Context, command, metadata} from 'clime';

export class TestContext extends Context {
  promptForQuery(): Promise<string> {
    // Using library like Inquirer.js to interact with user.
    return Promise.resolve('result');
  }
}

@command()
export default class TestCommand extends Command {
  @metadata
  execute(context: TestContext) {
    return context.promptForQuery();
  }
}

To test this command, we just need to extend TestContext, override promptForQuery and call execute with new context.

If this command is meant to stop somewhere and exit the process, we can define a ExitSignal class that implements Printable interface:

import {Printable} from 'clime';

export class ExitSignal implements Printable {
  constructor(public code: number) {}

  print(): void {
    process.exit(this.code);
  }
}

export function exit(code = 0): void {
  throw new ExitSignal(code);
}

Because print method would only be executed by the shim, your test can safely catch the exit signal and assert its correctness.

License

MIT License.

More Repositories

1

typescript-guide

TypeScript 中文指南
278
star
2

cordova-plugin-tts

Cordova Text-to-Speech Plugin (Maintainer WANTED!)
Java
177
star
3

cordova-plugin-wechat

Cordova 微信分享插件
Objective-C
172
star
4

wordsbaking-plus-chrome

词焙+ (WordsBaking+) 是词焙的重要组件, 方便用户把平时浏览网页时遇到的生词收集起来放进词焙生词本. 同时也是一个好用的划词翻译插件. http://wordsbaking.com
JavaScript
71
star
5

a-plus-dictionary

A Chrome extension based on Google Dictionary, provides better UI and shows the meanings in both your language and English.
JavaScript
61
star
6

thenfail

🏳 Just another Promises/A+ implementation written in TypeScript.
TypeScript
49
star
7

vs-force-utf8

Force UTF8 Extension for Visual Studio
C#
43
star
8

drop

Just another MV* framework
TypeScript
35
star
9

deprecated-decorator

A simple decorator for deprecated methods and properties.
TypeScript
32
star
10

magicspace

Toolkit for living boilerplate.
TypeScript
32
star
11

vio

📨 An express "endware" that takes your feelings into consideration.
TypeScript
29
star
12

ruff-home

Home (Web Framework) for Ruff.
TypeScript
28
star
13

vscode-es-quotes

ES Quotes Extension for Visual Studio Code.
TypeScript
26
star
14

entrance-decorator

A minimal solution of dependency injection for projects that scale.
TypeScript
25
star
15

plug2proxy

Transparent Proxy over HTTP2 or QUIC.
Rust
21
star
16

nodemand

Restart Node.js process on required modules change.
JavaScript
20
star
17

villa

🏡 Villa is a set of promise utilities for async-await-ready environment.
TypeScript
19
star
18

memorize-decorator

TypeScript
18
star
19

regex-tools

A simple tool for managing long regular expressions.
TypeScript
17
star
20

promise-pool

A task pool based on Promise (Q).
TypeScript
12
star
21

turning

Automated state transition testing.
TypeScript
10
star
22

vscode-console

Visual Studio Code Extension: Open Console in User-defined Console.
TypeScript
8
star
23

ruff-menu

Awesome Menu for Ruff LCD (lcd1602).
TypeScript
8
star
24

extendable-error

A simple extendable error class that extends Error.
TypeScript
8
star
25

vejis

A "grammer level" framework for JavaScript
JavaScript
8
star
26

x-value

A medium-neutral runtime type validation library.
TypeScript
8
star
27

touch-delegate

A gesture library based on extendable identifiers.
JavaScript
7
star
28

rateman

Rateman is a redis-based rate limiter with multi-window support.
TypeScript
7
star
29

ruff-promise

ES6 Promise for Ruff (https://ruff.io) based on ThenFail v0.4 (https://github.com/vilic/thenfail).
TypeScript
7
star
30

vscode-sensitive-replace

Replace selections while preserving cases.
TypeScript
6
star
31

henge

🗃 Henge generates artifacts for upstream projects and makes them configurable dependencies for downstream projects.
TypeScript
5
star
32

auto-loopback-exempt

Automatically exempt loopback for all and newly added applications.
JavaScript
5
star
33

prever-start

JavaScript
5
star
34

inplate

A command-line tool processing files with in-place template.
JavaScript
5
star
35

vlight

A lightweight syntax highlighter for JavaScript/HTML/CSS
JavaScript
5
star
36

backpage

Naive static HTML streaming based on React for Node.js CLI applications.
TypeScript
5
star
37

vio-demos

Demos for VIO
TypeScript
5
star
38

ruff-fetch

A simplified version of `window.fetch` written for Ruff.
TypeScript
4
star
39

biu-link

A simple URL shorter.
HTML
4
star
40

baseman

Integration test framework for Node.js
TypeScript
4
star
41

unmount-animation-clone

A simple utility component that clones the DOM element for animation before it unmounts.
TypeScript
4
star
42

npm-fork

Publish forks of npm packages with ease.
TypeScript
4
star
43

clime-slack

Shim and utilities for Slack slash commands building upon Clime.
TypeScript
3
star
44

js-operator-overloading

Overload operators in JavaScript (for fun).
JavaScript
3
star
45

gcvs

Git-CVS Workflow Utilities.
Shell
3
star
46

ClassScheduleProxy

C#
3
star
47

typescript-techniques

Hopefully useful techniques for TypeScript in practice.
3
star
48

docheat

A "cheating" tool that generates brief API references for TypeScript libraries with links to source code.
TypeScript
3
star
49

black-object

Blackbox mock with predefined interaction scripts.
TypeScript
3
star
50

typesafe-mongo

TypeSafe utilities for official MongoDB Node.js driver
TypeScript
3
star
51

multikey-map

TypeScript
2
star
52

vts

V-branded TypeScript coding standard
JavaScript
2
star
53

is-typeof-property

Simple utilities for tuple type narrowing...
TypeScript
2
star
54

tag-contacts

Just another simple UI widget for entering emails as contacts (2013).
JavaScript
2
star
55

main-function

A simple wrapper that handles error and return code.
TypeScript
2
star
56

lucky-dns

Lucky DNS, heavily inspired by SinoDNS and ChinaDNS.
TypeScript
1
star
57

hola-code

VS Code utilities for workflow at Hola.
TypeScript
1
star
58

q-retry

A shell for Q to enable retries.
JavaScript
1
star
59

lucky-vpn

Windows-friendly utilities that generate automation scripts for VPN connection.
TypeScript
1
star
60

v-query

A simple selector.
JavaScript
1
star
61

thenfail-core

Core of ThenFail (https://github.com/vilic/thenfail).
TypeScript
1
star
62

ViT

A mobile twitter client
1
star
63

cross-pm

Spawn npm/yarn/pnpm accordingly based on different lock files found in the context.
JavaScript
1
star
64

vilic.github.io

Project index of mine
HTML
1
star
65

ruff-t

T (Testing Framework) for Ruff.
TypeScript
1
star
66

qform

一段黑历史
JavaScript
1
star
67

semver-match

A simple function that conforms npm package version matching behavior.
TypeScript
1
star
68

ClassSchedule

Class Schedule for CQU
C#
1
star
69

Analyzer

AIESEC Form Analyzer
JavaScript
1
star
70

socket-jet

Minimalist package for data packets over socket connections.
TypeScript
1
star
71

get-or-create

A simple utility to get or create nested property and element in place.
TypeScript
1
star
72

boring-cache

TypeScript
1
star
73

air-proxy-enabled-http-request-for-js

A HTTP request implementation based on air.Socket, support HTTP only.
JavaScript
1
star
74

tracked-history

It tracks browser history so that we can restore history stack with snapshots.
TypeScript
1
star
75

super-heavy-launching

Super Heavy Launching Animation
HTML
1
star
76

cordova-plugin-fix-wp-bouncing

An acceptable solution for Windows Phone bouncing issue
C#
1
star
77

vilic

1
star
78

desktop-matters

Add your desktop computer as Matter devices.
TypeScript
1
star