Socket
Socket
Sign inDemoInstall

clipanion

Package Overview
Dependencies
Maintainers
1
Versions
84
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

clipanion - npm Package Compare versions

Comparing version 2.0.0-rc.0 to 2.0.0-rc.1

lib/core/builders.d.ts

24

lib/advanced/Cli.d.ts
/// <reference types="node" />
import { Readable, Writable } from 'stream';
import * as core from '../core';
import { Command } from './Command';
export interface Context {
export interface DefaultContext {
stdin: Readable;

@@ -9,3 +10,11 @@ stdout: Writable;

}
export declare class Cli {
interface CommandFactory<Context extends DefaultContext> {
new (): Command<Context>;
compile(): core.Command<(cli: Cli<Context>, context: Context) => Command<Context>>;
}
export interface MiniCli<Context extends DefaultContext> {
process(argv: string[]): Command<Context>;
run(argv: string[], subContext?: Partial<Context>): Promise<number | void>;
}
export declare class Cli<Context extends DefaultContext = DefaultContext> {
private readonly core;

@@ -16,9 +25,10 @@ readonly name?: string;

});
register(command: typeof Command): this;
start(): import("../core/Machine").Machine<Command>;
process(argv: string[]): Command;
run(argv: string[], context?: Partial<Context>): Promise<number>;
runExit(argv: string[], context?: Partial<Context>): Promise<void>;
register(command: CommandFactory<Context>): this;
start(): import("../core/Machine").Machine<(cli: Cli<Context>, context: Context) => Command<Context>>;
process(argv: string[]): (cli: Cli<Context>, context: Context) => Command<Context>;
run(argv: string[], context: Context): Promise<number>;
runExit(argv: string[], context: Context): Promise<void>;
private usage;
private error;
}
export {};

@@ -32,13 +32,8 @@ "use strict";

async run(argv, context) {
const fullContext = Object.assign({
stdin: process.stdin,
stdout: process.stdout,
stderr: process.stderr,
}, context);
const miniApi = {
const miniCli = {
process: (argv) => {
return this.process(argv);
return this.process(argv)(this, context);
},
run: (argv, subContext) => {
return this.run(argv, Object.assign({}, fullContext, subContext));
return this.run(argv, Object.assign({}, context, subContext));
},

@@ -48,3 +43,3 @@ };

try {
command = this.core.process(argv);
command = this.core.process(argv)(miniCli, context);
}

@@ -54,6 +49,6 @@ catch (error) {

error.setBinaryName(this.name);
return this.error(fullContext, error, null);
return this.error(context, error, null);
}
if (command.help) {
fullContext.stdout.write(this.usage(command, true));
context.stdout.write(this.usage(command, true));
return 0;

@@ -63,6 +58,6 @@ }

try {
exitCode = await command.execute(miniApi, fullContext);
exitCode = await command.execute();
}
catch (error) {
return this.error(fullContext, error, command);
return this.error(context, error, command);
}

@@ -69,0 +64,0 @@ if (typeof exitCode === `undefined`)

import * as core from '../core';
import { Cli, Context } from './Cli';
import { Cli, DefaultContext, MiniCli } from './Cli';
export declare type Help = {

@@ -15,10 +15,13 @@ description: string;

};
export declare abstract class Command {
export declare abstract class Command<Context extends DefaultContext = DefaultContext> {
static meta: Meta | undefined;
static getMeta(from?: Command): Meta;
static getMeta<Context extends DefaultContext>(from?: Command<Context>): Meta;
static Validate(schema: any): (klass: any) => void;
static Array(descriptor: string): (prototype: Command, propertyName: string) => void;
static Rest(): (prototype: Command, propertyName: string) => void;
static Proxy(): (prototype: Command, propertyName: string) => void;
static Boolean(descriptor: string): (prototype: Command, propertyName: string) => void;
static Array(descriptor: string): <Context extends DefaultContext>(prototype: Command<Context>, propertyName: string) => void;
static Rest(): PropertyDecorator;
static Rest(opts: {
required: number;
}): PropertyDecorator;
static Proxy(): <Context extends DefaultContext>(prototype: Command<Context>, propertyName: string) => void;
static Boolean(descriptor: string): <Context extends DefaultContext>(prototype: Command<Context>, propertyName: string) => void;
static String(): PropertyDecorator;

@@ -29,8 +32,17 @@ static String(opts: {

static String(descriptor: string): PropertyDecorator;
static Path(...segments: string[]): (prototype: Command, propertyName: "execute") => void;
static Path(...segments: string[]): <Context extends DefaultContext>(prototype: Command<Context>, propertyName: "execute") => void;
static Usage({ description, details }?: Partial<Help>): () => string;
static compile(): core.Command<any>;
static compile<Context extends DefaultContext>(): core.Command<(cli: Cli<Context>, context: Context) => Command<Context>>;
cli: MiniCli<Context>;
context: Context;
help: boolean;
/**
* If defined, must contain a function that returns the string displayed
* when the command help message is generated.
*/
usage: (() => string) | undefined;
abstract execute(cli: Cli, context: Context): Promise<number | void>;
/**
* Executed by Cli#run and Cli#runExit.
*/
abstract execute(): Promise<number | void>;
}

@@ -13,2 +13,4 @@ "use strict";

constructor() {
// This option is automatically added (it needs an extra logic to support
// ignoring the overall syntax of the command)
this.help = false;

@@ -76,6 +78,7 @@ }

}
static Rest() {
static Rest({ required = 0 } = {}) {
return (prototype, propertyName) => {
const { definition, transformers } = prototype.constructor.getMeta();
const index = definition.positionals.maximum;
definition.positionals.minimum += required;
definition.positionals.maximum = Infinity;

@@ -174,6 +177,8 @@ transformers.push((command, parsed) => {

const { definition, transformers } = this.getMeta();
return new core.Command(definition, parsed => {
return new core.Command(definition, parsed => (cli, context) => {
// @ts-ignore: In practice, "this" will be the subclass that
// inherit from Command (and thus not an abstract)
const bag = new this();
bag.cli = cli;
bag.context = context;
for (const transformer of transformers)

@@ -180,0 +185,0 @@ transformer(bag, parsed);

@@ -1,2 +0,2 @@

export { Cli, Context } from './Cli';
export { Cli, DefaultContext } from './Cli';
export { Command } from './Command';
import { Command } from './Command';
import { Machine } from './Machine';
export declare class Cli<T> {
static fromCache<T>(cache?: string): Cli<T>;
private commands;
register(command: Command<T>): this;
register(command: Command<T>): void;
getCache(): string;
start(): Machine<T>;
process(argv: string[]): T;
}

@@ -8,6 +8,33 @@ "use strict";

}
static fromCache(cache) {
const cli = new Cli();
if (typeof cache === `undefined`)
return cli;
const { nodes } = JSON.parse(cache);
cli.register = (command) => {
command.nodes = nodes.shift();
command.compiled = true;
for (const node of command.nodes)
node.transitions = new Map(node.transitions);
cli.commands.push(command);
};
cli.start = () => {
return new Machine_1.Machine(cli.commands);
};
return cli;
}
register(command) {
this.commands.push(command);
return this;
}
getCache() {
return JSON.stringify({
nodes: this.commands.map(command => command.nodes),
}, function (k, v) {
if (v instanceof Map)
return [...v];
if (typeof v === `object` && v != null && v.label)
return Object.assign({}, v, { label: `` });
return v;
});
}
start() {

@@ -14,0 +41,0 @@ const proxyByPaths = new Map();

@@ -1,24 +0,22 @@

import { Parsed, RecursivePartial } from './helpers';
export declare type ParseEntry = {
type: `positional`;
value: string;
} | {
type: `option`;
name: string;
value: any;
};
export declare type Builder = (segment: string) => ParseEntry | ParseEntry[];
import { RecursivePartial } from '../mpl';
import { builders } from './builders';
import { conditions } from './conditions';
import { Parsed } from './helpers';
export declare const HELP_OPTIONS: Set<string>;
export declare const NODE_INITIAL = 0;
export declare const NODE_SUCCESS = 1;
export declare const NODE_ERRORED = 2;
export declare type Node = {
dynamics: {
condition: keyof typeof conditions;
target: number;
builder?: keyof typeof builders;
}[];
label: string;
weight: number;
terminal: boolean;
transitions: Map<string, {
suggested: boolean;
transitions: Map<string | null, {
target: number;
builder?: Builder;
builder?: keyof typeof builders;
}>;
dynamics: {
condition: (segment: string) => boolean;
target: number;
builder?: Builder;
}[];
weight: number;
};

@@ -41,6 +39,3 @@ export declare type Definition = {

nodes: Node[];
isOptionBatch: (segment: string) => boolean;
isUnsupportedOption: (segment: string) => boolean;
isInlineOption: (segment: string) => boolean;
private compiled;
compiled: boolean;
constructor(definition: RecursivePartial<Definition>, transform: (parsed: Parsed) => T);

@@ -50,7 +45,11 @@ compile({ proxyStart }: {

}): void;
createNode(weight: number, label: string): number;
createNode({ weight, label, suggested }: {
weight: number;
label: string;
suggested?: boolean;
}): number;
markTerminal(node: number | null): void;
registerTransition(node: number | null, segment: string, target: number, builder?: Builder): void;
registerDynamicTransition(node: number | null, condition: (segment: string, ...args: any[]) => any, target: number, builder?: Builder): void;
registerTransition(node: number | null, segment: string | null, target: number, builder?: keyof typeof builders): void;
registerDynamicTransition(node: number | null, condition: keyof typeof conditions, target: number, builder?: keyof typeof builders): void;
registerOptions(node: number | null): void;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const helpers_1 = require("./helpers");
exports.HELP_OPTIONS = new Set([`-h`, `--help`]);
exports.NODE_INITIAL = 0;
exports.NODE_SUCCESS = 1;
exports.NODE_ERRORED = 2;
const DEFAULT_COMMAND_OPTIONS = {

@@ -16,89 +20,8 @@ path: [],

};
function isPositionalArgument(segment) {
return !segment.startsWith(`-`);
}
const OPTION_REGEXP = /^-[a-z]|--[a-z]+(-[a-z]+)*$/;
function isOptionLike(segment) {
return OPTION_REGEXP.test(segment);
}
function always() {
return true;
}
const HELP_OPTIONS = new Set([`-h`, `--help`]);
function isNotHelpNorSeparator(segment) {
return !HELP_OPTIONS.has(segment) && segment !== `--`;
}
function isOptionLikeButNotHelp(segment) {
return isOptionLike(segment) && !HELP_OPTIONS.has(segment);
}
const BATCH_REGEXP = /^-[a-z0-9]{2,}$/;
function makeIsOptionBatch(definition) {
return (segment) => {
if (!BATCH_REGEXP.test(segment))
return false;
for (let t = 1; t < segment.length; ++t)
if (!definition.options.simple.has(`-${segment.charAt(t)}`))
return false;
return true;
};
}
function makeIsUnsupportedOption(definition) {
const options = new Set([
...definition.options.simple,
...definition.options.complex,
]);
return function isUnsupportedOption(segment) {
if (isPositionalArgument(segment) || segment === `--`)
return false;
const idx = segment.indexOf(`=`);
const name = idx === -1 ? segment : segment.substr(0, idx);
return !options.has(name);
};
}
function makeIsInlineOption(definition) {
const options = new Set([
...definition.options.simple,
...definition.options.complex,
]);
return function isInlineOption(segment) {
if (isPositionalArgument(segment))
return false;
const idx = segment.indexOf(`=`);
if (idx === -1)
return false;
const name = segment.substr(0, idx);
if (!options.has(name))
return false;
return true;
};
}
function generatePositional(segment) {
return { type: `positional`, value: segment };
}
function generateBoolean(segment) {
return { type: `option`, name: segment, value: true };
}
function generateString(key, segment) {
return { type: `option`, name: key, value: segment };
}
function generateStringFromInline(segment) {
const idx = segment.indexOf(`=`);
return generateString(segment.substr(0, idx), segment.substr(idx + 1));
}
function generateBooleansFromBatch(segment) {
let results = [];
for (let t = 1; t < segment.length; ++t)
results.push(generateBoolean(`-${segment.charAt(t)}`));
return results;
}
class Command {
constructor(definition, transform) {
this.transform = transform;
this.nodes = [];
this.compiled = false;
this.definition = helpers_1.deepMerge({}, DEFAULT_COMMAND_OPTIONS, definition);
this.nodes = [];
this.createNode(0, `initial`);
this.isOptionBatch = makeIsOptionBatch(this.definition);
this.isUnsupportedOption = makeIsUnsupportedOption(this.definition);
this.isInlineOption = makeIsInlineOption(this.definition);
}

@@ -108,10 +31,18 @@ compile({ proxyStart }) {

return;
this.createNode({ weight: 0, label: `initial` });
this.createNode({ weight: 0, label: `success` });
this.createNode({ weight: 0, label: `errored` });
// We can't ever leave the error state, even at the end of the line
this.registerDynamicTransition(exports.NODE_ERRORED, `always`, exports.NODE_ERRORED);
this.registerTransition(exports.NODE_ERRORED, null, exports.NODE_ERRORED);
this.compiled = true;
const initialDD = this.createNode({ weight: 0, label: `initial (no opts)` });
this.registerTransition(0, `--`, initialDD);
const allPathNodes = [];
const allPathNodesDD = [];
let lastPathNode = 0;
let lastPathNodeDD = null;
let lastPathNode = exports.NODE_INITIAL;
let lastPathNodeDD = initialDD;
for (const segment of this.definition.path) {
const currentPathNode = this.createNode(0x100, `consuming path`);
const currentPathNodeDD = this.createNode(0x100, `consuming path (no opts)`);
const currentPathNode = this.createNode({ weight: 0x100, label: `consuming path` });
const currentPathNodeDD = this.createNode({ weight: 0x100, label: `consuming path (no opts)` });
this.registerTransition(lastPathNode, segment, currentPathNode);

@@ -125,36 +56,4 @@ this.registerTransition(lastPathNodeDD, segment, currentPathNodeDD);

}
/* The following block exclusively adds support for -h and --help */ {
// We can't support -h,--help if a proxy starts immediately after the command
if (typeof proxyStart === `undefined` || proxyStart >= 1) {
// This node will allow us to ignore every token coming after -h,--help
const afterHelpNode = this.createNode(0, `consuming after help`);
this.markTerminal(afterHelpNode);
this.registerDynamicTransition(afterHelpNode, always, afterHelpNode);
// Register the transition from the path to the help
for (const optName of HELP_OPTIONS)
this.registerTransition(lastPathNode, optName, afterHelpNode, generateBoolean);
// If there are no proxy we can just consume everything until -h,--help
if (typeof proxyStart === `undefined`) {
const searchHelpNode = this.createNode(0, `looking for -h,--help`);
this.registerDynamicTransition(lastPathNode, isNotHelpNorSeparator, searchHelpNode);
this.registerDynamicTransition(searchHelpNode, isNotHelpNorSeparator, searchHelpNode);
for (const optName of HELP_OPTIONS) {
this.registerTransition(searchHelpNode, optName, afterHelpNode, generateBoolean);
}
// Otherwise we need to count what we eat so that we don't enter the Proxy Zoneā„¢
}
else {
const lookAheadSize = proxyStart - this.definition.path.length - this.definition.positionals.minimum - 1;
let lastHelpNode = lastPathNode;
for (let t = 0; t < lookAheadSize; ++t) {
const currentHelpNode = this.createNode(0, `looking for help (${t + 1}/${proxyStart})`);
this.registerDynamicTransition(lastHelpNode, isPositionalArgument, currentHelpNode);
this.registerDynamicTransition(currentHelpNode, isOptionLikeButNotHelp, currentHelpNode);
for (const optName of HELP_OPTIONS)
this.registerTransition(currentHelpNode, optName, afterHelpNode, generateBoolean);
lastHelpNode = currentHelpNode;
}
}
}
}
if (this.definition.positionals.minimum > 0)
this.registerTransition(lastPathNode, null, exports.NODE_ERRORED, `generateMissingPositionalArgument`);
const allMinNodes = [];

@@ -165,6 +64,8 @@ const allMinNodesDD = [];

for (let t = 0; t < this.definition.positionals.minimum; ++t) {
const currentMinNode = this.createNode(0x1, `consuming required positionals`);
const currentMinNodeDD = this.createNode(0x1, `consuming required positionals (no opts)`);
this.registerDynamicTransition(lastMinNode, isPositionalArgument, currentMinNode, generatePositional);
this.registerDynamicTransition(lastMinNodeDD, always, currentMinNodeDD, generatePositional);
const currentMinNode = this.createNode({ weight: 0x1, label: `consuming required positionals` });
const currentMinNodeDD = this.createNode({ weight: 0x1, label: `consuming required positionals (no opts)` });
this.registerDynamicTransition(lastMinNode, `isPositionalArgument`, currentMinNode, `generatePositional`);
this.registerDynamicTransition(lastMinNodeDD, `always`, currentMinNodeDD, `generatePositional`);
if (t + 1 < this.definition.positionals.minimum)
this.registerTransition(currentMinNode, null, exports.NODE_ERRORED, `generateMissingPositionalArgument`);
this.registerTransition(currentMinNode, `--`, currentMinNodeDD);

@@ -182,16 +83,16 @@ allMinNodes.push(currentMinNode);

if (this.definition.positionals.proxy) {
const proxyNode = this.createNode(0, `consuming everything through a proxy`);
const proxyNode = this.createNode({ weight: 0, label: `consuming everything through a proxy` });
this.markTerminal(proxyNode);
this.registerDynamicTransition(lastMaxNode, isPositionalArgument, proxyNode, generatePositional);
this.registerDynamicTransition(lastMaxNode, this.isUnsupportedOption, proxyNode, generatePositional);
this.registerDynamicTransition(proxyNode, always, proxyNode, generatePositional);
this.registerDynamicTransition(lastMaxNode, `isPositionalArgument`, proxyNode, `generatePositional`);
this.registerDynamicTransition(lastMaxNode, `isUnsupportedOption`, proxyNode, `generatePositional`);
this.registerDynamicTransition(proxyNode, `always`, proxyNode, `generatePositional`);
this.registerTransition(lastMaxNode, `--`, proxyNode);
}
else {
const currentMaxNode = this.createNode(0, `consuming optional positionals`);
const currentMaxNodeDD = this.createNode(0, `consuming optional positionals`);
this.registerDynamicTransition(lastMaxNode, isPositionalArgument, currentMaxNode, generatePositional);
this.registerDynamicTransition(lastMaxNodeDD, always, currentMaxNodeDD, generatePositional);
this.registerDynamicTransition(currentMaxNode, isPositionalArgument, currentMaxNode, generatePositional);
this.registerDynamicTransition(currentMaxNodeDD, always, currentMaxNodeDD, generatePositional);
const currentMaxNode = this.createNode({ weight: 0, label: `consuming optional positionals` });
const currentMaxNodeDD = this.createNode({ weight: 0, label: `consuming optional positionals` });
this.registerDynamicTransition(lastMaxNode, `isPositionalArgument`, currentMaxNode, `generatePositional`);
this.registerDynamicTransition(lastMaxNodeDD, `always`, currentMaxNodeDD, `generatePositional`);
this.registerDynamicTransition(currentMaxNode, `isPositionalArgument`, currentMaxNode, `generatePositional`);
this.registerDynamicTransition(currentMaxNodeDD, `always`, currentMaxNodeDD, `generatePositional`);
this.registerTransition(lastMaxNode, `--`, currentMaxNodeDD);

@@ -206,6 +107,6 @@ allMaxNodes.push(currentMaxNode);

for (let t = this.definition.positionals.minimum; t < this.definition.positionals.maximum; ++t) {
const currentMaxNode = this.createNode(0, `consuming optional positionals`);
const currentMaxNodeDD = this.createNode(0, `consuming optional positionals`);
this.registerDynamicTransition(lastMaxNode, isPositionalArgument, currentMaxNode, generatePositional);
this.registerDynamicTransition(lastMaxNodeDD, always, currentMaxNodeDD, generatePositional);
const currentMaxNode = this.createNode({ weight: 0, label: `consuming optional positionals` });
const currentMaxNodeDD = this.createNode({ weight: 0, label: `consuming optional positionals` });
this.registerDynamicTransition(lastMaxNode, `isPositionalArgument`, currentMaxNode, `generatePositional`);
this.registerDynamicTransition(lastMaxNodeDD, `always`, currentMaxNodeDD, `generatePositional`);
this.registerTransition(lastMaxNode, `--`, currentMaxNodeDD);

@@ -218,2 +119,46 @@ allMaxNodes.push(currentMaxNode);

}
this.registerDynamicTransition(lastMaxNode, `isPositionalArgument`, exports.NODE_ERRORED, `generateExtraneousPositionalArgument`);
this.registerDynamicTransition(lastMaxNodeDD, `always`, exports.NODE_ERRORED, `generateExtraneousPositionalArgument`);
/* The following block exclusively adds support for -h and --help */ {
// We can't support -h,--help if a proxy starts immediately after the command
if (typeof proxyStart === `undefined` || proxyStart >= 1) {
// This node will allow us to ignore every token coming after -h,--help
const afterHelpNode = this.createNode({ weight: 0, label: `consuming after help`, suggested: false });
this.markTerminal(afterHelpNode);
this.registerDynamicTransition(afterHelpNode, `always`, afterHelpNode);
// Register the transition from the path to the help
for (const optName of exports.HELP_OPTIONS)
this.registerTransition(lastPathNode, optName, afterHelpNode, `generateBoolean`);
// Same thing for the mandatory positional arguments, but we give them some weight
for (let t = 0; t < this.definition.positionals.minimum; ++t) {
for (const optName of exports.HELP_OPTIONS) {
// Note that we don't add this transition to allMinNodesDD, since we don't want to find -h,--help if behind --
this.registerTransition(allMinNodes[t], optName, afterHelpNode, `generateBoolean`);
}
}
// If there are no proxy we can just consume everything until -h,--help
if (typeof proxyStart === `undefined`) {
const searchHelpNode = this.createNode({ weight: 0, label: `looking for -h,--help`, suggested: false });
this.registerDynamicTransition(lastMinNode, `isUnsupportedOption`, searchHelpNode);
this.registerDynamicTransition(lastMaxNode, `isPositionalArgument`, searchHelpNode);
this.registerDynamicTransition(searchHelpNode, `isNotHelpNorSeparator`, searchHelpNode);
for (const optName of exports.HELP_OPTIONS) {
this.registerTransition(searchHelpNode, optName, afterHelpNode, `generateBoolean`);
}
// Otherwise we need to count what we eat so that we don't enter the Proxy Zoneā„¢
}
else {
const lookAheadSize = proxyStart - this.definition.path.length - this.definition.positionals.minimum - 1;
let lastHelpNode = lastPathNode;
for (let t = 0; t < lookAheadSize; ++t) {
const currentHelpNode = this.createNode({ weight: 0, label: `looking for help (${t + 1}/${proxyStart})`, suggested: false });
this.registerDynamicTransition(lastHelpNode, `isPositionalArgument`, currentHelpNode);
this.registerDynamicTransition(currentHelpNode, `isOptionLikeButNotHelp`, currentHelpNode);
for (const optName of exports.HELP_OPTIONS)
this.registerTransition(currentHelpNode, optName, afterHelpNode, `generateBoolean`);
lastHelpNode = currentHelpNode;
}
}
}
}
this.registerOptions(lastPathNode);

@@ -232,10 +177,8 @@ this.markTerminal(lastMinNode);

}
createNode(weight, label) {
this.nodes.push({ label, weight, terminal: false, transitions: new Map(), dynamics: [] });
createNode({ weight, label, suggested = true }) {
this.nodes.push({ label, suggested, weight, transitions: new Map(), dynamics: [] });
return this.nodes.length - 1;
}
markTerminal(node) {
if (node !== null) {
this.nodes[node].terminal = true;
}
this.registerTransition(node, null, 1);
}

@@ -255,14 +198,15 @@ registerTransition(node, segment, target, builder) {

return;
this.registerDynamicTransition(node, `isUnsupportedOption`, exports.NODE_ERRORED, `generateUnsupportedOption`);
if (this.definition.options.simple.size > 0) {
this.registerDynamicTransition(node, this.isOptionBatch, node, generateBooleansFromBatch);
this.registerDynamicTransition(node, `isOptionBatch`, node, `generateBooleansFromBatch`);
for (const optName of this.definition.options.simple) {
this.registerTransition(node, optName, node, generateBoolean);
this.registerTransition(node, optName, node, `generateBoolean`);
}
}
if (this.definition.options.complex.size > 0) {
this.registerDynamicTransition(node, this.isInlineOption, node, generateStringFromInline);
this.registerDynamicTransition(node, `isInlineOption`, node, `generateStringFromInline`);
for (const optName of this.definition.options.complex) {
const argNode = this.createNode(0, `consuming argument`);
this.registerDynamicTransition(argNode, isPositionalArgument, node, generateString.bind(null, optName));
this.registerTransition(node, optName, argNode);
const argNode = this.createNode({ weight: 0, label: `consuming argument` });
this.registerDynamicTransition(argNode, `isPositionalArgument`, node, `generateStringValue`);
this.registerTransition(node, optName, argNode, `generateStringKey`);
}

@@ -269,0 +213,0 @@ }

@@ -7,2 +7,8 @@ import { Definition } from './Command';

};
export declare class UnknownSyntaxError extends Error {
readonly definitions: [Definition, string | null][];
clipanion: ErrorMeta;
constructor(definitions: [Definition, string | null][]);
setBinaryName(binaryName: string | undefined): void;
}
export declare class AmbiguousSyntaxError extends Error {

@@ -9,0 +15,0 @@ readonly definitions: Definition[];

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const pretty_1 = require("./pretty");
function getTokenName(name) {
if (name === null) {
return `<eol>`;
}
else {
return `"${name}"`;
}
}
class UnknownSyntaxError extends Error {
constructor(definitions) {
super();
this.definitions = definitions;
this.clipanion = { type: `none` };
this.name = `UnknownSyntaxError`;
this.setBinaryName(undefined);
}
setBinaryName(binaryName) {
if (this.definitions.length > 1) {
this.message = `Command not found; did you mean one of:\n\n${this.definitions.map(([definition], index) => {
return ` ${index}. ${pretty_1.prettyCommand(definition, { binaryName })}`;
}).join(`\n`)}`;
}
else {
const [[definition, reason]] = this.definitions;
this.message = `${reason}\n\n$ ${pretty_1.prettyCommand(definition, { binaryName })}`;
}
}
}
exports.UnknownSyntaxError = UnknownSyntaxError;
class AmbiguousSyntaxError extends Error {

@@ -13,4 +42,4 @@ constructor(definitions) {

setBinaryName(binaryName) {
this.message = `Cannot find who to pick amongst the following alternatives:\n${this.definitions.map((definition, index) => {
return `${index}. ${pretty_1.prettyCommand(definition, { binaryName })}`;
this.message = `Cannot find who to pick amongst the following alternatives:\n\n${this.definitions.map((definition, index) => {
return ` ${index}. ${pretty_1.prettyCommand(definition, { binaryName })}`;
}).join(`\n`)}`;

@@ -17,0 +46,0 @@ }

@@ -1,6 +0,3 @@

import { ParseEntry } from './Command';
import { ParseEntry } from './builders';
export declare const DEBUG: boolean;
export declare type RecursivePartial<T> = {
[P in keyof T]?: T[P] extends (infer U)[] ? RecursivePartial<U>[] : T[P] extends object ? RecursivePartial<T[P]> : T[P];
};
export declare function deepMerge<T extends any>(target: T, ...sources: ({

@@ -7,0 +4,0 @@ [key: string]: any;

@@ -36,2 +36,7 @@ "use strict";

break;
case `patch`:
{
result.options[result.options.length - 1].value = source.value;
}
break;
}

@@ -38,0 +43,0 @@ }

@@ -5,4 +5,5 @@ import { Command } from './Command';

constructor(commands: Command<T>[]);
write(segment: string): void;
write(segment: string): this;
private _write;
digest(): T;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const Command_1 = require("./Command");
const builders_1 = require("./builders");
const conditions_1 = require("./conditions");
const errors_1 = require("./errors");

@@ -15,7 +18,14 @@ const helpers_1 = require("./helpers");

write(segment) {
this._write(segment);
return this;
}
_write(segment) {
if (helpers_1.DEBUG)
console.log(`=== ${segment}`);
for (const state of this.states)
state.write(segment);
let maxWeight = 0;
for (const state of this.states)
maxWeight = Math.max(maxWeight, state.write(segment));
for (const { weight } of state.options)
maxWeight = Math.max(maxWeight, weight);
for (const state of this.states) {

@@ -26,11 +36,12 @@ state.trimLighterBranches(maxWeight);

digest() {
const candidates = [];
this._write(null);
const successes = [];
const failures = [];
for (const state of this.states)
for (const candidate of state.digest())
candidates.push(candidate);
if (candidates.length < 1)
throw new Error(`No matches`);
if (candidates.length > 1)
throw new errors_1.AmbiguousSyntaxError(candidates.map(({ command }) => command.definition));
const [{ command, parsed }] = candidates;
state.digest({ successes, failures });
if (successes.length < 1)
throw new errors_1.UnknownSyntaxError(failures.map(({ command, reason }) => [command.definition, reason]));
if (successes.length > 1)
throw new errors_1.AmbiguousSyntaxError(successes.map(({ command }) => command.definition));
const [{ command, parsed }] = successes;
if (helpers_1.DEBUG)

@@ -49,12 +60,14 @@ console.log(`Selected ${pretty_1.prettyCommand(command.definition)}`);

if (helpers_1.DEBUG)
console.log(` ${pretty_1.prettyCommand(this.command.definition)}`);
console.log(` [${pretty_1.prettyCommand(this.command.definition)}]`);
const options = this.options;
this.options = [];
for (const { weight, node, values } of options) {
const { transitions, dynamics, terminal } = this.command.nodes[node];
const { transitions, dynamics, suggested } = this.command.nodes[node];
const transition = transitions.get(segment);
let transitioned = false;
if (helpers_1.DEBUG)
console.log(` ${this.command.nodes[node].label}`);
if (typeof transition !== `undefined`) {
const nextValues = typeof transition.builder === `undefined` ? values : values.concat(transition.builder(segment));
transitioned = true;
const nextValues = typeof transition.builder === `undefined` ? values : values.concat(builders_1.builders[transition.builder](segment));
this.options.push({ weight: weight + this.command.nodes[transition.target].weight, node: transition.target, values: nextValues });

@@ -65,23 +78,30 @@ if (helpers_1.DEBUG) {

}
for (const { condition, target, builder } of dynamics) {
if (condition(segment)) {
const nextValues = typeof builder === `undefined` ? values : values.concat(builder(segment));
this.options.push({ weight: weight + this.command.nodes[target].weight, node: target, values: nextValues });
if (helpers_1.DEBUG) {
console.log(` -> ${this.command.nodes[target].label} (dynamic, via ${condition.name})`);
if (segment !== null) {
for (const { condition, target, builder } of dynamics) {
if (conditions_1.conditions[condition](segment, this.command.definition)) {
if (this.command.nodes[target].suggested)
transitioned = true;
const nextValues = typeof builder === `undefined` ? values : values.concat(builders_1.builders[builder](segment));
this.options.push({ weight: weight + this.command.nodes[target].weight, node: target, values: nextValues });
if (helpers_1.DEBUG) {
console.log(` -> ${this.command.nodes[target].label} (dynamic, via ${condition})`);
}
}
}
else {
if (helpers_1.DEBUG) {
console.log(` -> doesn't match ${condition.name}`);
else {
if (helpers_1.DEBUG) {
console.log(` -> doesn't match ${condition}`);
}
}
}
}
if (!transitioned && suggested) {
this.options.push({ weight, node: Command_1.NODE_ERRORED, values: values.concat({ reason: `Invalid token "${segment}"` }) });
if (helpers_1.DEBUG) {
console.log(` -> entering an error state`);
}
}
}
if (helpers_1.DEBUG)
console.log(` Went from ${options.length} -> ${this.options.length}`);
let maxWeight = 0;
for (const option of this.options)
maxWeight = Math.max(maxWeight, option.weight);
return maxWeight;
return this.options;
}

@@ -91,9 +111,18 @@ trimLighterBranches(requirement) {

}
digest() {
const candidates = [];
for (const { node, values } of this.options)
if (this.command.nodes[node].terminal)
candidates.push({ command: this.command, parsed: helpers_1.reconciliateValues(values) });
return candidates;
digest({ successes, failures }) {
for (const { node, values } of this.options) {
switch (node) {
case Command_1.NODE_SUCCESS:
{
successes.push({ command: this.command, parsed: helpers_1.reconciliateValues(values) });
}
break;
case Command_1.NODE_ERRORED:
{
failures.push({ command: this.command, reason: values[values.length - 1].reason });
}
break;
}
}
}
}
{
"name": "clipanion",
"version": "2.0.0-rc.0",
"version": "2.0.0-rc.1",
"main": "lib/advanced",

@@ -12,2 +12,3 @@ "license": "MIT",

"@types/chai": "^4.1.7",
"@types/chai-as-promised": "^7.1.0",
"@types/chalk": "^2.2.0",

@@ -18,2 +19,4 @@ "@types/mocha": "^5.2.7",

"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"get-stream": "^5.1.0",
"mocha": "^6.1.4",

@@ -20,0 +23,0 @@ "ts-node": "^8.3.0",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with āš”ļø by Socket Inc