Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

...

NotificationsYou must be signed in to change notification settings

streamich/json-type-cli

Repository files navigation

JSON Type CLI is a powerful Node.js package for building command-line interface (CLI) utilities that implement the JSON Rx RPC protocol. It uses JSON as the primary data format and provides request/response communication pattern where each CLI interaction is a request that produces a response.

Overview

This package enables you to build type-safe CLI tools where:

  • Each CLI command is amethod with typed input/output schemas
  • Input data forms therequest payload (following JSON Rx RPC)
  • Output data is theresponse payload
  • Multiple input sources can be composed together
  • Multiple output formats are supported (JSON, CBOR, MessagePack, etc.)

The library implements theJSON Rx RPC protocol, where each CLI interaction follows the request/response pattern. You define methods with typed schemas using the JSON Type system, and the CLI handles parsing, validation, method calling, and response formatting automatically.

Quick Start

Installation

npm install json-type-cli

Basic Usage

import{createCli}from'json-type-cli';import{ObjectValue}from'@jsonjoy.com/json-type/lib/value/ObjectValue';// Create a router with your methodsconstrouter=ObjectValue.create().prop('greet',t.Function(t.Object(t.prop('name',t.str)),// Request schemat.Object(t.prop('message',t.str))// Response schema).options({title:'Greet a person',description:'Returns a greeting message for the given name'}),async({ name})=>({message:`Hello,${name}!`}));// Create and run CLIconstcli=createCli({  router,version:'v1.0.0',cmd:'my-cli'});cli.run();

Save this asmy-cli.js and run:

node my-cli.js greet'{"name": "World"}'# Output: {"message": "Hello, World!"}node my-cli.js greet --str/name=Alice# Output: {"message": "Hello, Alice!"}

JSON Rx RPC Protocol Implementation

This CLI tool implements the JSON Rx RPC protocol with the following characteristics:

Request/Response Pattern

  • Each CLI command is amethod call in JSON Rx RPC terms
  • The method name is the first positional argument:my-cli <method> ...
  • Request data is composed from multiple sources (seeInput Sources)
  • Response data is returned to STDOUT in the specified format

JSON Rx RPC Message Flow

  1. Request Composition: CLI parses arguments and builds request payload
  2. Method Invocation: Calls the specified method with the request data
  3. Response Generation: Method returns response payload
  4. Response Encoding: Encodes response in the specified format (JSON, CBOR, etc.)

This follows the JSON Rx RPCRequest Complete message pattern where the client (CLI) sends a complete request and receives a complete response.

Building CLI Tools

Defining Methods

Methods are defined using the JSON Type system and added to a router:

import{createCli}from'json-type-cli';import{ObjectValue}from'@jsonjoy.com/json-type/lib/value/ObjectValue';constrouter=ObjectValue.create();const{ t}=router;// Simple echo methodrouter.prop('echo',t.Function(t.any,t.any).options({title:'Echo input',description:'Returns the input unchanged'}),async(input)=>input);// Math operationsrouter.prop('math.add',t.Function(t.Object(t.prop('a',t.num),t.prop('b',t.num)),t.Object(t.prop('result',t.num))).options({title:'Add two numbers',description:'Adds two numbers and returns the result'}),async({ a, b})=>({result:a+b}));// File processingrouter.prop('file.process',t.Function(t.Object(t.prop('filename',t.str),t.propOpt('encoding',t.str)),t.Object(t.prop('size',t.num),t.prop('content',t.str))).options({title:'Process a file',description:'Reads and processes a file'}),async({ filename, encoding='utf8'})=>{constfs=require('fs');constcontent=fs.readFileSync(filename,encoding);return{size:content.length,content:content};});

Organizing Routes

For larger applications, organize routes into modules:

// routes/user.tsexportconstdefineUserRoutes=<RoutesextendsObjectType<any>>(r:ObjectValue<Routes>)=>{returnr.extend((t,r)=>[r('user.create',t.Function(t.Object(t.prop('name',t.str),t.prop('email',t.str)),t.Object(t.prop('id',t.str),t.prop('name',t.str),t.prop('email',t.str))).options({title:'Create a user',description:'Creates a new user account'}),async({ name, email})=>({id:generateId(),        name,        email})),r('user.get',t.Function(t.Object(t.prop('id',t.str)),t.Object(t.prop('id',t.str),t.prop('name',t.str),t.prop('email',t.str))).options({title:'Get user by ID',description:'Retrieves user information by ID'}),async({ id})=>getUserById(id))]);};// main.tsimport{defineUserRoutes}from'./routes/user';constrouter=defineUserRoutes(ObjectValue.create());constcli=createCli({ router});

Input Sources (Request Composition)

The CLI composes request data from three sources in this priority order:

1. Command Line JSON Parameter

Provide JSON directly as the second argument:

my-cli greet'{"name": "Alice", "age": 30}'my-cli math.add'{"a": 5, "b": 3}'

2. STDIN Input

Pipe JSON data to the CLI:

echo'{"name": "Bob"}'| my-cli greetcat user.json| my-cli user.createcurl -s api.example.com/data.json| my-cli process.data

3. Command Line Options

Use typed parameters to build the request object:

# String valuesmy-cli greet --str/name=Alice --str/title="Ms."# Numeric valuesmy-cli math.add --num/a=10 --num/b=20# Boolean valuesmy-cli user.update --bool/active=true --bool/verified=false# JSON valuesmy-cli config.set --json/settings='{"theme": "dark", "lang": "en"}'# Nested paths using JSON Pointer (requires parent structure to exist)my-cli user.update'{"profile": {}}' --str/profile/name="Alice" --num/profile/age=25# To create nested structures, provide the base structure firstmy-cli config.set'{"database": {}}' --str/database/host=localhost --num/database/port=5432

Combining Input Sources

All sources can be combined. Command line options override STDIN data, which overrides the JSON parameter:

echo'{"name": "Default", "age": 0}'| my-cli greet --str/name=Alice --num/age=30# Result: {"name": "Alice", "age": 30}

Output Formats (Response Encoding)

Supported Codecs

The CLI supports multiple output formats through codecs:

CodecDescriptionUse Case
jsonStandard JSON (default)Human-readable, web APIs
json2Pretty JSON (2 spaces)Development, debugging
json4Pretty JSON (4 spaces)Documentation, config files
cborCBOR binary formatCompact binary, IoT
msgpackMessagePack binaryHigh performance, caching
ubjsonUniversal Binary JSONCross-platform binary
textFormatted text outputHuman-readable reports
treeTree visualizationDebugging, data exploration
rawRaw data outputBinary data, strings

Using Output Formats

# Default JSON outputmy-cli user.get'{"id": "123"}'# Pretty-printed JSONmy-cli user.get'{"id": "123"}' --format=json4# Binary formatsmy-cli data.export --format=cbor> data.cbormy-cli data.export --format=msgpack> data.msgpack# Text visualizationmy-cli config.get --format=treemy-cli config.get --format=text# Different input/output formatscat data.cbor| my-cli process.data --format=cbor:jsonecho'{"test": 123}'| my-cliecho --format=json:tree

Extracting Response Data

Use the--stdout or--out parameter to extract specific parts of the response:

# Extract specific fieldmy-cli user.get'{"id": "123"}' --out=/user/name# Extract nested datamy-cli api.fetch'{"url": "example.com"}' --out=/response/data/items# Combine with format conversionmy-cli data.complex --out=/results/summary --format=json:text

Command Line Parameters

All parameter paths useJSON Pointer syntax as defined inRFC 6901. JSON Pointers provide a standardized way to reference specific values within JSON documents using slash-separated paths.

When a path doesn't exist in the target object, the CLI automatically creates the necessary nested structure. For example,--str/database/host=localhost will create the object{"database": {"host": "localhost"}} even if neitherdatabase norhost existed previously.

Data Type Parameters

String Values (--str or--s)

my-cli greet --str/name=Alicemy-cli config.set --s/database/host=localhost --s/database/name=mydb

Numeric Values (--num or--n)

my-cli math.add --num/a=10 --num/b=20my-cli server.start --n/port=3000 --n/workers=4

Boolean Values (--bool or--b)

my-cli user.update --bool/active=truemy-cli feature.toggle --b/enabled=false

JSON Values (--json or--j)

my-cli config.merge --json/settings='{"theme": "dark"}'my-cli api.call --j/payload='[1,2,3]'

Undefined Values (--und)

my-cli optional.field --und/optionalParam

File Input (--file or--f)

Read values from files with optional format and path extraction:

# Read JSON filemy-cli process.data --file/input=data.json# Read with specific codecmy-cli import.data --f/data=data.cbor:cbor# Extract path from filemy-cli user.create --f/profile=user.json:json:/personalInfo# Chain: file -> codec -> pathmy-cli complex.import --f/config=settings.msgpack:msgpack:/database/credentials

Command Execution (--cmd or--c)

Execute commands and use their output as values:

# Use command output as stringmy-cli log.write --cmd/message='(echo "Current time: $(date)"):text'# Use command output as JSONmy-cli api.send --c/data='(curl -s api.example.com/data):json'# Extract path from command outputmy-cli process.status --c/info='(ps aux | grep node):json:/0/pid'

Format Control (--format or--fmt)

Control input and output encoding:

# Single format (for both input and output)my-cliecho --format=cbor# Separate input and output formatsmy-cli convert --format=cbor:jsonmy-cli transform --fmt=json:tree

STDIN Control (--stdin or--in)

Explicitly control STDIN data mapping:

# Use all STDIN dataecho'{"name": "Alice"}'| my-cli greet --stdin# Map STDIN to specific pathecho'{"users": [...]}'| my-cli process.users --in/data=/users# Map with path extractionecho'{"response": {"users": [...]}}'| my-cli save.users --in/users=/response/users

Output Control (--stdout or--out)

Extract specific parts of the response:

# Extract single fieldmy-cli user.get'{"id": "123"}' --out=/name# Extract nested objectmy-cli api.fetch --out=/response/data# Use with format conversionmy-cli complex.data --out=/results --format=json:tree

Utility Parameters

Help (--help or--h)

my-cli --help# General helpmy-cli method.name --help# Method-specific help

Version (--version or--v)

my-cli --version

Execution Plan (--plan)

my-cli complex.operation --plan# Show what would be executed

Advanced Features

Type Introspection

Get information about available methods and their schemas:

# List all methodsmy-cli .type# Get method schemamy-cli .type --out=/methodNamemy-cli .type --out=/user.create/req --format=treemy-cli .type --out=/user.create/res --format=json4

Binary Data Handling

The CLI supports binary data through various codecs:

# Process binary datacat image.jpg| my-cli image.process --format=raw:json# Convert between binary formatscat data.cbor| my-cli convert --format=cbor:msgpack> data.msgpack# Encode JSON as binarymy-cli data.export'{"large": "dataset"}' --format=json:cbor> export.cbor

Error Handling

Errors follow JSON Rx RPC error format and are sent to STDERR:

my-cli invalid.method2>errors.logmy-cli user.get'{"invalid": "data"}'2>validation-errors.json

Error objects include:

  • message: Human-readable error description
  • code: Stable error code for programmatic handling
  • errno: Numeric error code
  • errorId: Unique error identifier for logging
  • meta: Additional error metadata (stack traces, etc.)

Performance Optimization

For high-performance scenarios:

# Use binary formats for large datamy-cli large.dataset --format=msgpack# Use raw format for simple string/binary outputmy-cli get.file.content --format=raw# Stream processing with STDIN/STDOUTcat large-file.json| my-cli process.stream --format=json:cbor| my-cli save.processed --format=cbor

Complete Example

Here's a complete example building a file processing CLI:

import{createCli}from'@jsonjoy.com/json-type-cli';import{ObjectValue}from'@jsonjoy.com/json-type/lib/value/ObjectValue';import*asfsfrom'fs';import*aspathfrom'path';constrouter=ObjectValue.create();const{ t}=router;// File operationsrouter.prop('file.read',t.Function(t.Object(t.prop('path',t.str),t.propOpt('encoding',t.str)),t.Object(t.prop('content',t.str),t.prop('size',t.num))).options({title:'Read file content',description:'Reads a file and returns its content and size'}),async({path:filePath, encoding='utf8'})=>{constcontent=fs.readFileSync(filePath,encoding);return{        content,size:content.length};}).prop('file.write',t.Function(t.Object(t.prop('path',t.str),t.prop('content',t.str),t.propOpt('encoding',t.str)),t.Object(t.prop('success',t.bool),t.prop('bytesWritten',t.num))).options({title:'Write file content',description:'Writes content to a file'}),async({path:filePath, content, encoding='utf8'})=>{fs.writeFileSync(filePath,content,encoding);return{success:true,bytesWritten:Buffer.from(content,encoding).length};}).prop('file.list',t.Function(t.Object(t.prop('directory',t.str),t.propOpt('pattern',t.str)),t.Object(t.prop('files',t.Array(t.str)),t.prop('count',t.num))).options({title:'List directory files',description:'Lists files in a directory, optionally filtered by pattern'}),async({ directory, pattern})=>{letfiles=fs.readdirSync(directory);if(pattern){constregex=newRegExp(pattern);files=files.filter(file=>regex.test(file));}return{        files,count:files.length};});constcli=createCli({  router,version:'v1.0.0',cmd:'file-cli'});cli.run();

Usage examples:

# Read a filefile-cli file.read --str/path=package.json --format=json4# Write content from STDINecho"Hello World"| file-cli file.write --str/path=output.txt --in/content# List JavaScript filesfile-cli file.list --str/directory=src --str/pattern='\\.js$' --out=/files# Chain operations: read -> transform -> writefile-cli file.read --str/path=input.json|   file-cli transform.data|   file-cli file.write --str/path=output.json --in/content --format=json:raw

This example demonstrates the full power of JSON Type CLI for building robust, type-safe command-line tools that implement the JSON Rx RPC protocol with rich input/output capabilities.

About

...

Resources

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published

Contributors3

  •  
  •  
  •  

[8]ページ先頭

©2009-2025 Movatter.jp