cli-kiss 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +57 -42
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/Command.ts +36 -38
- package/src/lib/Execution.ts +10 -13
- package/src/lib/Grid.ts +6 -2
- package/src/lib/Option.ts +2 -0
- package/src/lib/Reader.ts +4 -4
- package/src/lib/Run.ts +65 -50
- package/src/lib/Type.ts +27 -2
- package/src/lib/Typo.ts +21 -9
- package/src/lib/Usage.ts +63 -59
- package/tests/{unit.command.run.ts → unit.command.execute.ts} +26 -16
- package/tests/unit.command.usage.ts +81 -74
package/src/lib/Command.ts
CHANGED
|
@@ -4,58 +4,58 @@ import { OptionUsage } from "./Option";
|
|
|
4
4
|
import { ReaderTokenizer } from "./Reader";
|
|
5
5
|
|
|
6
6
|
export type Command<Context, Result> = {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
getDescription(): string | undefined;
|
|
8
|
+
buildInterpreter(
|
|
9
9
|
readerTokenizer: ReaderTokenizer,
|
|
10
|
-
):
|
|
10
|
+
): CommandInterpreter<Context, Result>;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
export type
|
|
13
|
+
export type CommandMetadata = {
|
|
14
|
+
description: string;
|
|
15
|
+
details?: Array<string>;
|
|
16
|
+
// TODO - printable examples ?
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type CommandInterpreter<Context, Result> = {
|
|
14
20
|
computeUsage(): CommandUsage;
|
|
15
21
|
execute(context: Context): Promise<Result>;
|
|
16
22
|
};
|
|
17
23
|
|
|
18
24
|
export type CommandUsage = {
|
|
19
25
|
breadcrumbs: Array<CommandUsageBreadcrumb>;
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
description: string;
|
|
27
|
+
details: Array<string> | undefined;
|
|
22
28
|
options: Array<OptionUsage>;
|
|
23
29
|
arguments: Array<ArgumentUsage>;
|
|
24
|
-
subcommands: Array<{ name: string;
|
|
30
|
+
subcommands: Array<{ name: string; description: string | undefined }>;
|
|
25
31
|
};
|
|
26
32
|
|
|
27
|
-
export type CommandUsageBreadcrumb = {
|
|
28
|
-
kind: "command" | "argument";
|
|
29
|
-
value: string;
|
|
30
|
-
};
|
|
33
|
+
export type CommandUsageBreadcrumb = { argument: string } | { command: string };
|
|
31
34
|
|
|
32
35
|
export function command<Context, Result>(
|
|
33
|
-
metadata:
|
|
34
|
-
title: string;
|
|
35
|
-
description?: Array<string>;
|
|
36
|
-
},
|
|
36
|
+
metadata: CommandMetadata,
|
|
37
37
|
execution: Execution<Context, Result>,
|
|
38
38
|
): Command<Context, Result> {
|
|
39
39
|
return {
|
|
40
|
-
|
|
41
|
-
return metadata.
|
|
40
|
+
getDescription() {
|
|
41
|
+
return metadata.description;
|
|
42
42
|
},
|
|
43
|
-
|
|
43
|
+
buildInterpreter(readerTokenizer: ReaderTokenizer) {
|
|
44
44
|
function computeUsage(): CommandUsage {
|
|
45
45
|
const executionUsage = execution.computeUsage();
|
|
46
46
|
return {
|
|
47
47
|
breadcrumbs: executionUsage.arguments.map((argument) =>
|
|
48
48
|
breadcrumbArgument(argument.label),
|
|
49
49
|
),
|
|
50
|
-
title: metadata.title,
|
|
51
50
|
description: metadata.description,
|
|
51
|
+
details: metadata.details,
|
|
52
52
|
options: executionUsage.options,
|
|
53
53
|
arguments: executionUsage.arguments,
|
|
54
54
|
subcommands: [],
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
57
|
try {
|
|
58
|
-
const executionResolver = execution.
|
|
58
|
+
const executionResolver = execution.createResolver(readerTokenizer);
|
|
59
59
|
const lastPositional = readerTokenizer.consumePositional();
|
|
60
60
|
if (lastPositional !== undefined) {
|
|
61
61
|
throw Error(`Unprocessed positional: ${lastPositional}`);
|
|
@@ -80,20 +80,17 @@ export function command<Context, Result>(
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
export function commandWithSubcommands<Context, Payload, Result>(
|
|
83
|
-
metadata:
|
|
84
|
-
title: string;
|
|
85
|
-
description?: Array<string>;
|
|
86
|
-
},
|
|
83
|
+
metadata: CommandMetadata,
|
|
87
84
|
execution: Execution<Context, Payload>,
|
|
88
85
|
subcommands: { [subcommand: Lowercase<string>]: Command<Payload, Result> },
|
|
89
86
|
): Command<Context, Result> {
|
|
90
87
|
return {
|
|
91
|
-
|
|
92
|
-
return metadata.
|
|
88
|
+
getDescription() {
|
|
89
|
+
return metadata.description;
|
|
93
90
|
},
|
|
94
|
-
|
|
91
|
+
buildInterpreter(readerTokenizer: ReaderTokenizer) {
|
|
95
92
|
try {
|
|
96
|
-
const executionResolver = execution.
|
|
93
|
+
const executionResolver = execution.createResolver(readerTokenizer);
|
|
97
94
|
const subcommandName = readerTokenizer.consumePositional();
|
|
98
95
|
if (subcommandName === undefined) {
|
|
99
96
|
throw new Error("Expected a subcommand");
|
|
@@ -103,19 +100,20 @@ export function commandWithSubcommands<Context, Payload, Result>(
|
|
|
103
100
|
if (subcommandInput === undefined) {
|
|
104
101
|
throw new Error(`Unknown subcommand: ${subcommandName}`);
|
|
105
102
|
}
|
|
106
|
-
const
|
|
103
|
+
const subcommandInterpreter =
|
|
104
|
+
subcommandInput.buildInterpreter(readerTokenizer);
|
|
107
105
|
const executionCallback = executionResolver();
|
|
108
106
|
return {
|
|
109
107
|
computeUsage() {
|
|
110
108
|
const executionUsage = execution.computeUsage();
|
|
111
|
-
const subcommandUsage =
|
|
109
|
+
const subcommandUsage = subcommandInterpreter.computeUsage();
|
|
112
110
|
return {
|
|
113
111
|
breadcrumbs: executionUsage.arguments
|
|
114
112
|
.map((argument) => breadcrumbArgument(argument.label))
|
|
115
113
|
.concat([breadcrumbCommand(subcommandName)])
|
|
116
114
|
.concat(subcommandUsage.breadcrumbs),
|
|
117
|
-
title: subcommandUsage.title,
|
|
118
115
|
description: subcommandUsage.description,
|
|
116
|
+
details: subcommandUsage.details,
|
|
119
117
|
options: executionUsage.options.concat(subcommandUsage.options),
|
|
120
118
|
arguments: executionUsage.arguments.concat(
|
|
121
119
|
subcommandUsage.arguments,
|
|
@@ -125,7 +123,7 @@ export function commandWithSubcommands<Context, Payload, Result>(
|
|
|
125
123
|
},
|
|
126
124
|
async execute(context: Context) {
|
|
127
125
|
const payload = await executionCallback(context);
|
|
128
|
-
return await
|
|
126
|
+
return await subcommandInterpreter.execute(payload);
|
|
129
127
|
},
|
|
130
128
|
};
|
|
131
129
|
} catch (error) {
|
|
@@ -136,14 +134,14 @@ export function commandWithSubcommands<Context, Payload, Result>(
|
|
|
136
134
|
breadcrumbs: executionUsage.arguments
|
|
137
135
|
.map((argument) => breadcrumbArgument(argument.label))
|
|
138
136
|
.concat([breadcrumbCommand("<SUBCOMMAND>")]),
|
|
139
|
-
title: metadata.title,
|
|
140
137
|
description: metadata.description,
|
|
138
|
+
details: metadata.details,
|
|
141
139
|
options: executionUsage.options,
|
|
142
140
|
arguments: executionUsage.arguments,
|
|
143
141
|
subcommands: Object.entries(subcommands).map(
|
|
144
142
|
([name, subcommand]) => ({
|
|
145
143
|
name,
|
|
146
|
-
|
|
144
|
+
description: subcommand.getDescription(),
|
|
147
145
|
}),
|
|
148
146
|
),
|
|
149
147
|
};
|
|
@@ -157,10 +155,10 @@ export function commandWithSubcommands<Context, Payload, Result>(
|
|
|
157
155
|
};
|
|
158
156
|
}
|
|
159
157
|
|
|
160
|
-
function breadcrumbArgument(
|
|
161
|
-
return {
|
|
158
|
+
function breadcrumbArgument(value: string): CommandUsageBreadcrumb {
|
|
159
|
+
return { argument: value };
|
|
162
160
|
}
|
|
163
161
|
|
|
164
|
-
function breadcrumbCommand(
|
|
165
|
-
return {
|
|
162
|
+
function breadcrumbCommand(value: string): CommandUsageBreadcrumb {
|
|
163
|
+
return { command: value };
|
|
166
164
|
}
|
package/src/lib/Execution.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { ReaderTokenizer } from "./Reader";
|
|
|
4
4
|
|
|
5
5
|
export type Execution<Context, Result> = {
|
|
6
6
|
computeUsage(): ExecutionUsage;
|
|
7
|
-
|
|
7
|
+
createResolver(
|
|
8
8
|
readerTokenizer: ReaderTokenizer,
|
|
9
9
|
): ExecutionResolver<Context, Result>;
|
|
10
10
|
};
|
|
@@ -26,21 +26,18 @@ export type ExecutionUsage = {
|
|
|
26
26
|
export function execution<
|
|
27
27
|
Context,
|
|
28
28
|
Result,
|
|
29
|
-
Options extends { [option: string]:
|
|
30
|
-
const Arguments extends Array<
|
|
29
|
+
Options extends { [option: string]: any },
|
|
30
|
+
const Arguments extends Array<any>,
|
|
31
31
|
>(
|
|
32
|
-
inputs: {
|
|
32
|
+
inputs: {
|
|
33
|
+
options: { [K in keyof Options]: Option<Options[K]> };
|
|
34
|
+
arguments: { [K in keyof Arguments]: Argument<Arguments[K]> };
|
|
35
|
+
},
|
|
33
36
|
handler: (
|
|
34
37
|
context: Context,
|
|
35
38
|
inputs: {
|
|
36
|
-
options:
|
|
37
|
-
|
|
38
|
-
ReturnType<Options[K]["prepareConsumer"]>
|
|
39
|
-
>;
|
|
40
|
-
};
|
|
41
|
-
arguments: {
|
|
42
|
-
[K in keyof Arguments]: ReturnType<Arguments[K]["consumeValue"]>;
|
|
43
|
-
};
|
|
39
|
+
options: Options;
|
|
40
|
+
arguments: Arguments;
|
|
44
41
|
},
|
|
45
42
|
) => Promise<Result>,
|
|
46
43
|
): Execution<Context, Result> {
|
|
@@ -57,7 +54,7 @@ export function execution<
|
|
|
57
54
|
}
|
|
58
55
|
return { options: optionsUsage, arguments: argumentsUsage };
|
|
59
56
|
},
|
|
60
|
-
|
|
57
|
+
createResolver(readerTokenizer: ReaderTokenizer) {
|
|
61
58
|
const optionsConsumers: any = {};
|
|
62
59
|
for (const optionKey in inputs.options) {
|
|
63
60
|
const optionInput = inputs.options[optionKey]!;
|
package/src/lib/Grid.ts
CHANGED
|
@@ -4,7 +4,11 @@ export type Grid = Array<GridRow>;
|
|
|
4
4
|
export type GridRow = Array<GridCell>;
|
|
5
5
|
export type GridCell = Array<TypoText>;
|
|
6
6
|
|
|
7
|
-
export function gridToPrintableLines(
|
|
7
|
+
export function gridToPrintableLines(
|
|
8
|
+
grid: Grid,
|
|
9
|
+
typoSupport: TypoSupport,
|
|
10
|
+
delimiter: string = "",
|
|
11
|
+
): Array<string> {
|
|
8
12
|
const lines = new Array<string>();
|
|
9
13
|
const gridWidths = new Array<number>();
|
|
10
14
|
for (const gridRow of grid) {
|
|
@@ -42,7 +46,7 @@ export function gridToPrintableLines(grid: Grid, typoSupport: TypoSupport) {
|
|
|
42
46
|
lineColumns.push(parts.join(""));
|
|
43
47
|
}
|
|
44
48
|
}
|
|
45
|
-
lines.push(lineColumns.join(
|
|
49
|
+
lines.push(lineColumns.join(delimiter));
|
|
46
50
|
}
|
|
47
51
|
return lines;
|
|
48
52
|
}
|
package/src/lib/Option.ts
CHANGED
|
@@ -11,6 +11,7 @@ export type OptionUsage = {
|
|
|
11
11
|
long: Lowercase<string>; // TODO - better type for long option names ?
|
|
12
12
|
short: string | undefined;
|
|
13
13
|
label: Uppercase<string> | undefined;
|
|
14
|
+
// TODO - default value for usage ? but it can be dynamic, so maybe not
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
export type OptionConsumer<Value> = () => Value;
|
|
@@ -65,6 +66,7 @@ export function optionRepeatable<Value>(definition: {
|
|
|
65
66
|
}): Option<Array<Value>> {
|
|
66
67
|
return {
|
|
67
68
|
generateUsage() {
|
|
69
|
+
// TODO - showcase that it can be repeated ?
|
|
68
70
|
return {
|
|
69
71
|
description: definition.description,
|
|
70
72
|
long: definition.long,
|
package/src/lib/Reader.ts
CHANGED
|
@@ -3,7 +3,7 @@ export type ReaderPositionals = {
|
|
|
3
3
|
};
|
|
4
4
|
|
|
5
5
|
export class ReaderTokenizer {
|
|
6
|
-
#
|
|
6
|
+
#parsedArgs: Array<string>;
|
|
7
7
|
#parsedIndex: number;
|
|
8
8
|
#parsedDouble: boolean;
|
|
9
9
|
|
|
@@ -17,8 +17,8 @@ export class ReaderTokenizer {
|
|
|
17
17
|
#optionInfoByKey: Map<string, {}>; // TODO - what dis for
|
|
18
18
|
#optionResultByKey: Map<string, Array<string> | null>;
|
|
19
19
|
|
|
20
|
-
constructor(
|
|
21
|
-
this.#
|
|
20
|
+
constructor(args: Array<string>) {
|
|
21
|
+
this.#parsedArgs = args;
|
|
22
22
|
this.#parsedIndex = 0;
|
|
23
23
|
this.#parsedDouble = false;
|
|
24
24
|
|
|
@@ -116,7 +116,7 @@ export class ReaderTokenizer {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
#consumeArg(): string | null {
|
|
119
|
-
const arg = this.#
|
|
119
|
+
const arg = this.#parsedArgs[this.#parsedIndex];
|
|
120
120
|
if (arg === undefined) {
|
|
121
121
|
return null;
|
|
122
122
|
}
|
package/src/lib/Run.ts
CHANGED
|
@@ -1,32 +1,38 @@
|
|
|
1
|
-
import { Command } from "./Command";
|
|
1
|
+
import { Command, CommandInterpreter } from "./Command";
|
|
2
2
|
import { ReaderTokenizer } from "./Reader";
|
|
3
|
-
import {
|
|
3
|
+
import { typoInferProcessSupport, TypoSupport } from "./Typo";
|
|
4
4
|
import { usageToPrintableLines } from "./Usage";
|
|
5
5
|
|
|
6
|
-
export async function
|
|
7
|
-
|
|
6
|
+
export async function runAndExit<Context>(
|
|
7
|
+
cliName: Lowercase<string>,
|
|
8
|
+
cliArgs: Array<string>,
|
|
8
9
|
context: Context,
|
|
9
|
-
command: Command<Context,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
command: Command<Context, void>,
|
|
11
|
+
application?: {
|
|
12
|
+
usageOnError?: boolean;
|
|
13
|
+
usageOnHelp?: boolean;
|
|
14
|
+
buildVersion?: string;
|
|
15
|
+
useColors?: boolean;
|
|
16
|
+
onMessage?: (message: string) => void;
|
|
17
|
+
onError?: (error: any) => void;
|
|
18
|
+
onExit?: (code: number) => never;
|
|
14
19
|
},
|
|
15
|
-
): Promise<
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
if (cliInfo?.version) {
|
|
20
|
+
): Promise<never> {
|
|
21
|
+
const readerTokenizer = new ReaderTokenizer(cliArgs);
|
|
22
|
+
if (application?.buildVersion) {
|
|
19
23
|
readerTokenizer.registerFlag({
|
|
20
24
|
key: "version",
|
|
21
25
|
shorts: [],
|
|
22
26
|
longs: ["version"],
|
|
23
27
|
});
|
|
24
28
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
if (application?.usageOnHelp ?? true) {
|
|
30
|
+
readerTokenizer.registerFlag({
|
|
31
|
+
key: "help",
|
|
32
|
+
shorts: [],
|
|
33
|
+
longs: ["help"],
|
|
34
|
+
});
|
|
35
|
+
}
|
|
30
36
|
/*
|
|
31
37
|
// TODO - handle completions ?
|
|
32
38
|
readerTokenizer.registerFlag({
|
|
@@ -35,41 +41,50 @@ export async function runWithArgv<Context, Result>(
|
|
|
35
41
|
longs: ["completion"],
|
|
36
42
|
});
|
|
37
43
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
process.exit(0);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
if (readerTokenizer.consumeFlag("help")) {
|
|
47
|
-
console.log(
|
|
48
|
-
usageToPrintableLines({
|
|
49
|
-
cliName,
|
|
50
|
-
commandUsage: commandRunner.computeUsage(),
|
|
51
|
-
typoSupport: typoInferSupport(),
|
|
52
|
-
}).join("\n"),
|
|
44
|
+
const commandInterpreter = command.buildInterpreter(readerTokenizer);
|
|
45
|
+
if (application?.buildVersion) {
|
|
46
|
+
if (readerTokenizer.consumeFlag("version")) {
|
|
47
|
+
(application?.onMessage ?? console.log)(
|
|
48
|
+
[cliName, application.buildVersion].join(" "),
|
|
53
49
|
);
|
|
54
|
-
process.exit(0);
|
|
50
|
+
return (application?.onExit ?? process.exit)(0);
|
|
55
51
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
usageToPrintableLines({
|
|
62
|
-
cliName,
|
|
63
|
-
commandUsage: commandRunner.computeUsage(),
|
|
64
|
-
typoSupport: typoInferSupport(),
|
|
65
|
-
}).join("\n"),
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
console.error(error);
|
|
69
|
-
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
if (application?.usageOnHelp ?? true) {
|
|
54
|
+
if (readerTokenizer.consumeFlag("help")) {
|
|
55
|
+
logUsageMessage(cliName, commandInterpreter, application);
|
|
56
|
+
return (application?.onExit ?? process.exit)(0);
|
|
70
57
|
}
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
await commandInterpreter.execute(context);
|
|
61
|
+
return (application?.onExit ?? process.exit)(0);
|
|
71
62
|
} catch (error) {
|
|
72
|
-
|
|
73
|
-
|
|
63
|
+
if (application?.usageOnError ?? true) {
|
|
64
|
+
logUsageMessage(cliName, commandInterpreter, application);
|
|
65
|
+
}
|
|
66
|
+
(application?.onError ?? console.error)(error);
|
|
67
|
+
return (application?.onExit ?? process.exit)(1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function logUsageMessage<Context, Result>(
|
|
72
|
+
cliName: Lowercase<string>,
|
|
73
|
+
commandInterpreter: CommandInterpreter<Context, Result>,
|
|
74
|
+
application?: { useColors?: boolean; onMessage?: (message: string) => void },
|
|
75
|
+
) {
|
|
76
|
+
(application?.onMessage ?? console.log)(
|
|
77
|
+
usageToPrintableLines({
|
|
78
|
+
cliName,
|
|
79
|
+
commandUsage: commandInterpreter.computeUsage(),
|
|
80
|
+
typoSupport: chooseTypoSupport(application?.useColors),
|
|
81
|
+
}).join("\n"),
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function chooseTypoSupport(useColors?: boolean): TypoSupport {
|
|
86
|
+
if (useColors === undefined) {
|
|
87
|
+
return typoInferProcessSupport();
|
|
74
88
|
}
|
|
89
|
+
return useColors ? "tty" : "none";
|
|
75
90
|
}
|
package/src/lib/Type.ts
CHANGED
|
@@ -48,10 +48,35 @@ export const typeBigInt: Type<bigint> = {
|
|
|
48
48
|
},
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
export function
|
|
51
|
+
export function typeCommaTuple<
|
|
52
|
+
const Elements extends Array<any>,
|
|
53
|
+
>(elementTypes: {
|
|
54
|
+
[K in keyof Elements]: Type<Elements[K]>;
|
|
55
|
+
}): Type<Elements> {
|
|
56
|
+
return {
|
|
57
|
+
label: elementTypes
|
|
58
|
+
.map((elementType) => elementType.label)
|
|
59
|
+
.join(",") as Uppercase<string>,
|
|
60
|
+
decoder(value: string) {
|
|
61
|
+
const parts = value.split(",", elementTypes.length);
|
|
62
|
+
if (parts.length !== elementTypes.length) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`Invalid tuple value: ${value}, expected ${elementTypes.length} parts`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
return parts.map((part, index) =>
|
|
68
|
+
elementTypes[index]!.decoder(part),
|
|
69
|
+
) as Elements;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function typeCommaList<Value>(
|
|
75
|
+
elementType: Type<Value>,
|
|
76
|
+
): Type<Array<Value>> {
|
|
52
77
|
return {
|
|
53
78
|
label:
|
|
54
|
-
`${elementType.label}[
|
|
79
|
+
`${elementType.label}[,${elementType.label}...]` as Uppercase<string>,
|
|
55
80
|
decoder(value: string) {
|
|
56
81
|
return value.split(",").map(elementType.decoder);
|
|
57
82
|
},
|
package/src/lib/Typo.ts
CHANGED
|
@@ -42,7 +42,10 @@ export function typoPrintableString(
|
|
|
42
42
|
throw new Error(`Unknown typo support: ${typoSupport}`);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
export function
|
|
45
|
+
export function typoInferProcessSupport(): TypoSupport {
|
|
46
|
+
if (!process) {
|
|
47
|
+
return "none";
|
|
48
|
+
}
|
|
46
49
|
if (process.env) {
|
|
47
50
|
if (process.env["FORCE_COLOR"] === "0") {
|
|
48
51
|
return "none";
|
|
@@ -54,7 +57,7 @@ export function typoInferSupport(): TypoSupport {
|
|
|
54
57
|
return "none";
|
|
55
58
|
}
|
|
56
59
|
}
|
|
57
|
-
if (!process
|
|
60
|
+
if (!process.stdout || !process.stdout.isTTY) {
|
|
58
61
|
return "none";
|
|
59
62
|
}
|
|
60
63
|
return "tty";
|
|
@@ -63,11 +66,20 @@ export function typoInferSupport(): TypoSupport {
|
|
|
63
66
|
const resetCode = "\x1b[0m";
|
|
64
67
|
const boldCode = "\x1b[1m";
|
|
65
68
|
const colorCodes = {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
darkBlack: "\x1b[30m",
|
|
70
|
+
darkRed: "\x1b[31m",
|
|
71
|
+
darkGreen: "\x1b[32m",
|
|
72
|
+
darkYellow: "\x1b[33m",
|
|
73
|
+
darkBlue: "\x1b[34m",
|
|
74
|
+
darkMagenta: "\x1b[35m",
|
|
75
|
+
darkCyan: "\x1b[36m",
|
|
76
|
+
darkWhite: "\x1b[37m",
|
|
77
|
+
brightBlack: "\x1b[90m",
|
|
78
|
+
brightRed: "\x1b[91m",
|
|
79
|
+
brightGreen: "\x1b[92m",
|
|
80
|
+
brightYellow: "\x1b[93m",
|
|
81
|
+
brightBlue: "\x1b[94m",
|
|
82
|
+
brightMagenta: "\x1b[95m",
|
|
83
|
+
brightCyan: "\x1b[96m",
|
|
84
|
+
brightWhite: "\x1b[97m",
|
|
73
85
|
};
|