Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

commander-jsx

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

commander-jsx - npm Package Compare versions

Comparing version
0.6.9
to
0.7.0
+22
jsx-dev-runtime.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Fragment = exports.jsxDEV = exports.jsxs = exports.jsx = void 0;
const tslib_1 = require("tslib");
const web_utility_1 = require("web-utility");
/**
* JSX runtime for CommanderJSX
* @see {@link https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md}
* @see {@link https://babeljs.io/docs/babel-plugin-transform-react-jsx}
*/
const jsx = (type, _a) => {
var { children } = _a, props = tslib_1.__rest(_a, ["children"]);
return new type(Object.assign(Object.assign({}, props), { children: (0, web_utility_1.makeArray)(children) }));
};
exports.jsx = jsx;
exports.jsxs = exports.jsx;
exports.jsxDEV = exports.jsx;
/**
* Fragment support (not typically used in CommanderJSX, but required by JSX runtime)
*/
const Fragment = ({ children }) => (0, web_utility_1.makeArray)(children);
exports.Fragment = Fragment;
import { Command, CommandChildren, CommandMeta } from './dist/Command';
declare global {
namespace JSX {
interface ElementType<T = any> {
new (meta: CommandMeta<T>): Command<T>;
}
interface Element extends Command<any> {
}
interface IntrinsicAttributes {
children?: CommandChildren;
}
}
}
/**
* JSX runtime for CommanderJSX
* @see {@link https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md}
* @see {@link https://babeljs.io/docs/babel-plugin-transform-react-jsx}
*/
export declare const jsx: <T>(type: {
new (meta: CommandMeta<T>): Command<T>;
}, { children, ...props }: CommandMeta<T> & {
children?: CommandChildren<T>;
}) => Command<T>;
export declare const jsxs: <T>(type: {
new (meta: CommandMeta<T>): Command<T>;
}, { children, ...props }: CommandMeta<T> & {
children?: CommandChildren<T>;
}) => Command<T>;
export declare const jsxDEV: <T>(type: {
new (meta: CommandMeta<T>): Command<T>;
}, { children, ...props }: CommandMeta<T> & {
children?: CommandChildren<T>;
}) => Command<T>;
/**
* Fragment support (not typically used in CommanderJSX, but required by JSX runtime)
*/
export declare const Fragment: ({ children }: JSX.IntrinsicAttributes) => Command<any>[] | CommandChildren<any>[];
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Fragment = exports.jsxDEV = exports.jsxs = exports.jsx = void 0;
const tslib_1 = require("tslib");
const web_utility_1 = require("web-utility");
/**
* JSX runtime for CommanderJSX
* @see {@link https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md}
* @see {@link https://babeljs.io/docs/babel-plugin-transform-react-jsx}
*/
const jsx = (type, _a) => {
var { children } = _a, props = tslib_1.__rest(_a, ["children"]);
return new type(Object.assign(Object.assign({}, props), { children: (0, web_utility_1.makeArray)(children) }));
};
exports.jsx = jsx;
exports.jsxs = exports.jsx;
exports.jsxDEV = exports.jsx;
/**
* Fragment support (not typically used in CommanderJSX, but required by JSX runtime)
*/
const Fragment = ({ children }) => (0, web_utility_1.makeArray)(children);
exports.Fragment = Fragment;
import { packageOf } from '@tech_query/node-toolkit';
import { OptionData, Data, parseArguments } from './parser';
import { createTable } from './creator';
export interface Option {
shortcut?: string;
parameters?: string;
pattern?: RegExp;
description?: string;
}
export type Options<T> = Record<keyof T, Option>;
export type Executor<T> = (options: OptionData<T>, ...data: Data[]) => any;
export type CommandChildren<T = any> = Command<T> | Array<CommandChildren<T>>;
export interface CommandMeta<T> extends Option {
name?: string;
version?: string;
options?: Options<T>;
children?: CommandChildren<T>;
executor?: Executor<T>;
}
const PresetOption = {
version: { shortcut: 'v', description: 'show Version number' },
help: { shortcut: 'h', description: 'show Help information' }
};
export class Command<T = any> implements CommandMeta<T> {
name = '';
parameters = '';
description = '';
version = '';
options: Options<T> = {} as Options<T>;
parent?: Command<T>;
children: Command<T>[] = [];
executor?: Executor<T>;
constructor(meta: CommandMeta<T>) {
Object.assign(this, meta);
for (const command of this.children) command.parent = this;
this.addPreset();
}
static nameOf(meta: Record<string, any>, commandPath: string) {
if (typeof meta.bin != 'object') return meta.name as string;
commandPath = commandPath.replaceAll('\\', '/');
return Object.entries(meta.bin as Record<string, string>).find(([name, path]) =>
commandPath.endsWith(path.replace(/^\.\//, ''))
)?.[0];
}
static execute<T>(command: Command<T>, args: string[]) {
const { data, options } = parseArguments<T>(args);
if (!command.parent && (!command.name || !command.version || !command.description)) {
const [_, commandPath] = process.argv;
const { meta } = packageOf(commandPath);
command.name ||= this.nameOf(meta, commandPath) || '';
command.description ||= meta.description || '';
if ((command.version ||= meta.version || ''))
(command.options as Record<keyof typeof PresetOption, any>).version =
PresetOption.version;
}
command.execute(options as OptionData<T>, ...data);
}
execute(options: OptionData<T>, ...data: Data[]): void {
const command = this.children.find(({ name }) => name === data[0]);
if (command instanceof Command) return command.execute(options, ...data.slice(1));
options = this.checkPattern(this.replaceShortcut(options));
if ('version' in options) {
console.log(this.version);
} else if ('help' in options) {
this.showHelp();
} else if (this.executor instanceof Function) {
this.executor(options, ...data);
} else {
throw ReferenceError(`Unknown "${data[0]}" command`);
}
}
protected replaceShortcut(options: OptionData<T>) {
const map: Record<string, keyof T> = Object.fromEntries(
Object.entries<Option>(this.options).map(([key, { shortcut }]) => [shortcut, key])
),
data: OptionData<T> = {} as OptionData<T>;
for (const key in options)
if (key in map) data[map[key]] = options[key];
else data[key] = options[key];
return data;
}
protected checkPattern(options: OptionData<T>) {
for (const key in options) {
const option = this.options[key];
if (!option) throw ReferenceError(`Unknown "${key}" option`);
if (option.pattern?.test(options[key] + '') === false)
throw SyntaxError(`"${key}=${options[key]}" doesn't match ${option.pattern}`);
}
return options;
}
protected addPreset() {
const { name, options, children } = this,
{ version, help } = PresetOption;
Object.assign(this.options, {
...(this.version ? { version } : {}),
help,
...options
});
if (name !== 'help' && !children.find(({ name }) => name === 'help'))
children.push(
new Command({
name: 'help',
...help,
parameters: '[command]',
executor: (_, command) => this.showHelp(command as string)
})
);
}
showHelp(command?: string) {
if (!command) return console.log(this + '');
const that = this.children.find(({ name }) => name === command);
if (that) console.log(that + '');
}
*getParentNames() {
let that: Command | undefined = this;
while ((that = that.parent)) yield that.name;
}
toString() {
const result = [
[this.parameters, this.name, ...this.getParentNames()].reverse().join(' ').trim(),
this.description,
'Options:\n' + this.toOptionString()
];
if (this.children[0]) result.push('Commands:\n' + this.toChildrenString());
return result.join('\n\n');
}
toOptionString() {
return createTable(
Object.entries<Option>(this.options as Options<T>)
.sort(([A], [B]) => A.localeCompare(B))
.map(([name, { shortcut, parameters = '', description = '' }]) => [
'',
`${shortcut ? `-${shortcut}, ` : ''}${name[1] ? '-' : ''}-${name}`,
parameters,
description
])
);
}
toChildrenString() {
return createTable(
this.children
.sort(({ name: A }, { name: B }) => A.localeCompare(B))
.map(({ name, parameters = '', description = '' }) => [
'',
name,
parameters,
description
])
);
}
}
export function createTable(list: string[][]) {
const counts = list.reduce((counts, row) => {
for (const [index, { length }] of row.entries())
if (index + 1 < row.length) counts[index] = Math.max(counts[index], length);
return counts;
}, Array(list[0].length).fill(0));
return list
.map(row =>
row
.map((column, index) => column.padEnd(counts[index], ' '))
.join(' ')
.trimEnd()
)
.join('\n');
}
export * from './parser';
export * from './Command';
export * from './creator';
export type PrimitiveData = string | number | boolean | null;
export type Data = PrimitiveData | Record<string, PrimitiveData> | PrimitiveData[];
export function parseData(raw: string): Data {
try {
return JSON.parse((raw = raw.trim()));
} catch {
return raw.includes(',') ? (raw.split(',').map(parseData) as PrimitiveData[]) : raw;
}
}
export type OptionData<T> = Record<keyof T, Data>;
export function parseArguments<T>(list: string[]) {
const options: OptionData<T> = {} as OptionData<T>,
data: Data[] = [];
let lastKey = '';
for (const item of list)
if (item.startsWith('--')) {
lastKey = item.slice(2);
options[lastKey as keyof T] = true;
} else if (item.startsWith('-')) {
if (item[2]) for (const k of item.slice(1)) options[k as keyof T] = true;
else {
lastKey = item[1];
options[lastKey as keyof T] = true;
}
} else if (lastKey) {
options[lastKey as keyof T] = parseData(item);
lastKey = '';
} else {
data.push(parseData(item));
}
return { options, data };
}
import { makeArray } from 'web-utility';
import { Command, CommandChildren, CommandMeta } from './dist/Command';
declare global {
namespace JSX {
interface ElementType<T = any> {
new (meta: CommandMeta<T>): Command<T>;
}
interface Element extends Command<any> {}
interface IntrinsicAttributes {
children?: CommandChildren;
}
}
}
/**
* JSX runtime for CommanderJSX
* @see {@link https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md}
* @see {@link https://babeljs.io/docs/babel-plugin-transform-react-jsx}
*/
export const jsx = <T>(
type: { new (meta: CommandMeta<T>): Command<T> },
{ children, ...props }: CommandMeta<T> & { children?: CommandChildren<T> }
): Command<T> =>
new type({
...props,
children: makeArray(children)
} as CommandMeta<T>);
export const jsxs = jsx;
export const jsxDEV = jsx;
/**
* Fragment support (not typically used in CommanderJSX, but required by JSX runtime)
*/
export const Fragment = ({ children }: JSX.IntrinsicAttributes) => makeArray(children);
+2
-1

@@ -10,2 +10,3 @@ import { OptionData, Data } from './parser';

export type Executor<T> = (options: OptionData<T>, ...data: Data[]) => any;
export type CommandChildren<T = any> = Command<T> | Array<CommandChildren<T>>;
export interface CommandMeta<T> extends Option {

@@ -15,3 +16,3 @@ name?: string;

options?: Options<T>;
children?: Command<T>[];
children?: CommandChildren<T>;
executor?: Executor<T>;

@@ -18,0 +19,0 @@ }

@@ -33,4 +33,3 @@ "use strict";

const { data, options } = (0, parser_1.parseArguments)(args);
if (!command.parent &&
(!command.name || !command.version || !command.description)) {
if (!command.parent && (!command.name || !command.version || !command.description)) {
const [_, commandPath] = process.argv;

@@ -41,3 +40,4 @@ const { meta } = (0, node_toolkit_1.packageOf)(commandPath);

if ((command.version || (command.version = meta.version || '')))
command.options.version = PresetOption.version;
command.options.version =
PresetOption.version;
}

@@ -104,6 +104,3 @@ command.execute(options, ...data);

const result = [
[this.parameters, this.name, ...this.getParentNames()]
.reverse()
.join(' ')
.trim(),
[this.parameters, this.name, ...this.getParentNames()].reverse().join(' ').trim(),
this.description,

@@ -110,0 +107,0 @@ 'Options:\n' + this.toOptionString()

@@ -1,12 +0,1 @@

import { Command, CommandMeta } from './Command';
declare global {
namespace JSX {
interface IntrinsicElements<T> {
[key: string]: Command<T>;
}
}
}
export declare function createCommand<T>(component: {
new (meta: CommandMeta<T>): Command<T>;
}, props: CommandMeta<T>, ...children: Command<T>[]): Command<T>;
export declare function createTable(list: string[][]): string;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTable = exports.createCommand = void 0;
function createCommand(component, props, ...children) {
return new component(Object.assign(Object.assign({}, props), { children }));
}
exports.createCommand = createCommand;
exports.createTable = createTable;
function createTable(list) {

@@ -22,2 +18,1 @@ const counts = list.reduce((counts, row) => {

}
exports.createTable = createTable;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseArguments = exports.parseData = void 0;
exports.parseData = parseData;
exports.parseArguments = parseArguments;
function parseData(raw) {

@@ -9,8 +10,5 @@ try {

catch (_a) {
return raw.includes(',')
? raw.split(',').map(parseData)
: raw;
return raw.includes(',') ? raw.split(',').map(parseData) : raw;
}
}
exports.parseData = parseData;
function parseArguments(list) {

@@ -42,2 +40,1 @@ const options = {}, data = [];

}
exports.parseArguments = parseArguments;
{
"name": "commander-jsx",
"version": "0.6.9",
"version": "0.7.0",
"license": "LGPL-3.0",

@@ -24,24 +24,26 @@ "description": "Command-line Arguments Parser with JSX support",

"main": "dist/index.js",
"module": "source/index.ts",
"source": "source/dist/index.ts",
"types": "dist/index.d.ts",
"dependencies": {
"@tech_query/node-toolkit": "^1.2.1",
"tslib": "^2.6.1"
"@tech_query/node-toolkit": "2.0.0-alpha.0",
"tslib": "^2.8.1",
"web-utility": "^4.6.3"
},
"devDependencies": {
"@types/jest": "^29.5.3",
"@types/node": "^18.17.5",
"husky": "^8.0.3",
"jest": "^29.6.2",
"lint-staged": "^14.0.0",
"open-cli": "^7.2.0",
"prettier": "^3.0.2",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"typedoc": "^0.24.8",
"typedoc-plugin-mdn-links": "^3.0.3",
"typescript": "~5.1.6"
"@types/jest": "^29.5.14",
"@types/node": "^22.18.13",
"husky": "^9.1.7",
"jest": "^29.7.0",
"lint-staged": "^16.2.6",
"open-cli": "^8.0.0",
"prettier": "^3.6.2",
"ts-jest": "^29.4.5",
"ts-node": "^10.9.2",
"typedoc": "^0.28.14",
"typedoc-plugin-mdn-links": "^5.0.10",
"typescript": "~5.9.3"
},
"prettier": {
"tabWidth": 4,
"printWidth": 100,
"trailingComma": "none",

@@ -58,5 +60,6 @@ "arrowParens": "avoid",

"scripts": {
"prepare": "husky install",
"prepare": "husky",
"test": "lint-staged && jest",
"build": "rm -rf dist/ docs/ && tsc && typedoc source/",
"parcel": "tsc && mv dist/jsx-runtime.* . && cp jsx-runtime.js jsx-dev-runtime.js && mv dist/dist/* dist/ && rm -rf dist/dist",
"build": "rm -rf dist/ docs/ && npm run parcel && typedoc",
"start": "typedoc source/ && open-cli docs/index.html",

@@ -63,0 +66,0 @@ "prepublishOnly": "npm test && npm run build"

@@ -10,8 +10,15 @@ # CommanderJSX

## Versions
| SemVer | status | JSX |
| :-----: | :----------: | :--------------: |
| `>=0.7` | ✅developing | import source |
| `<0.7` | ❌deprecated | factory function |
## Example
`index.tsx`
### `index.tsx`
```JavaScript
import { Command, createCommand } from 'commander-jsx';
import { Command } from 'commander-jsx';

@@ -48,3 +55,3 @@ Command.execute(

`tsconfig.json`
### `tsconfig.json`

@@ -56,4 +63,4 @@ ```JSON

"moduleResolution": "Node",
"jsx": "react",
"jsxFactory": "createCommand",
"jsx": "react-jsx",
"jsxImportSource": "commander-jsx",
"target": "ES2017",

@@ -65,4 +72,6 @@ "outDir": "dist/"

Then, run `git help` in your terminal, it'll outputs:
## Usage
Run `git help` in your terminal, it'll outputs:
```text

@@ -82,2 +91,9 @@ git [command] [options]

## Typical cases
1. https://github.com/idea2app/Git-utility
2. https://github.com/TechQuery/Web-fetch
3. https://github.com/TechQuery/KoApache
4. https://github.com/TechQuery/fs-match
[1]: https://facebook.github.io/jsx/

@@ -84,0 +100,0 @@ [2]: https://libraries.io/npm/commander-jsx

@@ -6,4 +6,4 @@ {

"esModuleInterop": true,
"jsx": "react",
"jsxFactory": "createCommand",
"jsx": "react-jsx",
"jsxImportSource": "../source",
"strict": true,

@@ -16,3 +16,3 @@ "target": "ES2017",

},
"include": ["source/*.ts"],
"include": ["source/**/*.ts"],
"typedocOptions": {

@@ -23,4 +23,5 @@ "name": "CommanderJSX",

"readme": "./ReadMe.md",
"entryPoints": ["source/dist/index.ts", "source/jsx-runtime.ts"],
"plugin": ["typedoc-plugin-mdn-links"]
}
}
import { packageOf } from '@tech_query/node-toolkit';
import { OptionData, Data, parseArguments } from './parser';
import { createTable } from './creator';
export interface Option {
shortcut?: string;
parameters?: string;
pattern?: RegExp;
description?: string;
}
export type Options<T> = Record<keyof T, Option>;
export type Executor<T> = (options: OptionData<T>, ...data: Data[]) => any;
export interface CommandMeta<T> extends Option {
name?: string;
version?: string;
options?: Options<T>;
children?: Command<T>[];
executor?: Executor<T>;
}
const PresetOption = {
version: { shortcut: 'v', description: 'show Version number' },
help: { shortcut: 'h', description: 'show Help information' }
};
export class Command<T = any> implements CommandMeta<T> {
name = '';
parameters = '';
description = '';
version = '';
options: Options<T> = {} as Options<T>;
parent?: Command<T>;
children: Command<T>[] = [];
executor?: Executor<T>;
constructor(meta: CommandMeta<T>) {
Object.assign(this, meta);
for (const command of this.children) command.parent = this;
this.addPreset();
}
static nameOf(meta: Record<string, any>, commandPath: string) {
if (typeof meta.bin != 'object') return meta.name as string;
commandPath = commandPath.replaceAll('\\', '/');
return Object.entries(meta.bin as Record<string, string>).find(
([name, path]) => commandPath.endsWith(path.replace(/^\.\//, ''))
)?.[0];
}
static execute<T>(command: Command<T>, args: string[]) {
const { data, options } = parseArguments<T>(args);
if (
!command.parent &&
(!command.name || !command.version || !command.description)
) {
const [_, commandPath] = process.argv;
const { meta } = packageOf(commandPath);
command.name ||= this.nameOf(meta, commandPath) || '';
command.description ||= meta.description || '';
if ((command.version ||= meta.version || ''))
(
command.options as Record<keyof typeof PresetOption, any>
).version = PresetOption.version;
}
command.execute(options as OptionData<T>, ...data);
}
execute(options: OptionData<T>, ...data: Data[]): void {
const command = this.children.find(({ name }) => name === data[0]);
if (command instanceof Command)
return command.execute(options, ...data.slice(1));
options = this.checkPattern(this.replaceShortcut(options));
if ('version' in options) {
console.log(this.version);
} else if ('help' in options) {
this.showHelp();
} else if (this.executor instanceof Function) {
this.executor(options, ...data);
} else {
throw ReferenceError(`Unknown "${data[0]}" command`);
}
}
protected replaceShortcut(options: OptionData<T>) {
const map: Record<string, keyof T> = Object.fromEntries(
Object.entries<Option>(this.options).map(
([key, { shortcut }]) => [shortcut, key]
)
),
data: OptionData<T> = {} as OptionData<T>;
for (const key in options)
if (key in map) data[map[key]] = options[key];
else data[key] = options[key];
return data;
}
protected checkPattern(options: OptionData<T>) {
for (const key in options) {
const option = this.options[key];
if (!option) throw ReferenceError(`Unknown "${key}" option`);
if (option.pattern?.test(options[key] + '') === false)
throw SyntaxError(
`"${key}=${options[key]}" doesn't match ${option.pattern}`
);
}
return options;
}
protected addPreset() {
const { name, options, children } = this,
{ version, help } = PresetOption;
Object.assign(this.options, {
...(this.version ? { version } : {}),
help,
...options
});
if (name !== 'help' && !children.find(({ name }) => name === 'help'))
children.push(
new Command({
name: 'help',
...help,
parameters: '[command]',
executor: (_, command) => this.showHelp(command as string)
})
);
}
showHelp(command?: string) {
if (!command) return console.log(this + '');
const that = this.children.find(({ name }) => name === command);
if (that) console.log(that + '');
}
*getParentNames() {
let that: Command | undefined = this;
while ((that = that.parent)) yield that.name;
}
toString() {
const result = [
[this.parameters, this.name, ...this.getParentNames()]
.reverse()
.join(' ')
.trim(),
this.description,
'Options:\n' + this.toOptionString()
];
if (this.children[0])
result.push('Commands:\n' + this.toChildrenString());
return result.join('\n\n');
}
toOptionString() {
return createTable(
Object.entries<Option>(this.options as Options<T>)
.sort(([A], [B]) => A.localeCompare(B))
.map(
([
name,
{ shortcut, parameters = '', description = '' }
]) => [
'',
`${shortcut ? `-${shortcut}, ` : ''}${
name[1] ? '-' : ''
}-${name}`,
parameters,
description
]
)
);
}
toChildrenString() {
return createTable(
this.children
.sort(({ name: A }, { name: B }) => A.localeCompare(B))
.map(({ name, parameters = '', description = '' }) => [
'',
name,
parameters,
description
])
);
}
}
import { Command, CommandMeta } from './Command';
declare global {
namespace JSX {
interface IntrinsicElements<T> {
[key: string]: Command<T>;
}
}
}
export function createCommand<T>(
component: { new (meta: CommandMeta<T>): Command<T> },
props: CommandMeta<T>,
...children: Command<T>[]
) {
return new component({ ...props, children });
}
export function createTable(list: string[][]) {
const counts = list.reduce((counts, row) => {
for (const [index, { length }] of row.entries())
if (index + 1 < row.length)
counts[index] = Math.max(counts[index], length);
return counts;
}, Array(list[0].length).fill(0));
return list
.map(row =>
row
.map((column, index) => column.padEnd(counts[index], ' '))
.join(' ')
.trimEnd()
)
.join('\n');
}
export * from './parser';
export * from './Command';
export * from './creator';
export type PrimitiveData = string | number | boolean | null;
export type Data =
| PrimitiveData
| Record<string, PrimitiveData>
| PrimitiveData[];
export function parseData(raw: string): Data {
try {
return JSON.parse((raw = raw.trim()));
} catch {
return raw.includes(',')
? (raw.split(',').map(parseData) as PrimitiveData[])
: raw;
}
}
export type OptionData<T> = Record<keyof T, Data>;
export function parseArguments<T>(list: string[]) {
const options: OptionData<T> = {} as OptionData<T>,
data: Data[] = [];
let lastKey = '';
for (const item of list)
if (item.startsWith('--')) {
lastKey = item.slice(2);
options[lastKey as keyof T] = true;
} else if (item.startsWith('-')) {
if (item[2])
for (const k of item.slice(1)) options[k as keyof T] = true;
else {
lastKey = item[1];
options[lastKey as keyof T] = true;
}
} else if (lastKey) {
options[lastKey as keyof T] = parseData(item);
lastKey = '';
} else {
data.push(parseData(item));
}
return { options, data };
}