-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathinteractive.ts
94 lines (82 loc) · 2.77 KB
/
interactive.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import * as chalk from 'chalk';
import { prompt } from 'inquirer';
import { resolve } from 'path';
import { WriteStream } from 'tty';
import { Branch, Leaf, Node } from '.';
import { renderToCli } from './lib/markdown';
import { tryPanic } from './lib/try-panic';
import { createTreeInterpreter, TreeInterpreter } from './machine/tree';
import { isBranch, isLeaf } from './machine/tree/nodes';
interface Answer {
name: string;
short: string;
value: number;
}
interface ChosenAnswer {
childIndex: number;
}
const stdout = process.stdout as WriteStream;
const LOADING_MESSAGE = '! Loading...';
const getChoices = (node: Branch): Answer[] =>
node.children.map((child: Node, i) => ({
name: child.label,
short: ' ',
value: i,
}));
export const run = async ({ sourcePath }: { sourcePath: string }) => {
const dataPath = resolve(process.cwd(), sourcePath);
const REQUIRE_ERROR = `Failed to require('${dataPath}');`;
const source = tryPanic(() => require(dataPath), REQUIRE_ERROR);
const GET_DOCUMENT_ERROR = `Failed to call getHelpDocument() from ${dataPath}`;
const tree = await tryPanic(() => source.getHelpDocument(), GET_DOCUMENT_ERROR);
const interpreter = createTreeInterpreter(tree);
start(interpreter);
};
export const start = async (interpreter: TreeInterpreter): Promise<void> => {
const renderChoice = (currentNode: Node) => {
console.log(chalk.green('?'), chalk.bold(currentNode.label));
};
const showLoadingStatus = (currentNode: Node) => {
renderChoice(currentNode);
stdout.write(chalk.yellow(LOADING_MESSAGE));
};
const hideLoadingStatus = () => {
stdout.clearLine(0);
stdout.moveCursor(-LOADING_MESSAGE.length, 0);
stdout.moveCursor(0, -1);
stdout.clearLine(0);
stdout.write('');
};
const listChildNodes = async (branch: Branch) => {
const { childIndex } = await prompt<ChosenAnswer>({
choices: getChoices(branch),
message: branch.label,
name: 'childIndex',
type: 'list',
});
interpreter.send({
type: 'SELECT_CHILD',
childIndex,
});
};
const renderValue = async (leaf: Leaf) => {
console.log('');
console.log(renderToCli(leaf.value));
};
interpreter.onTransition(async ({ context: { currentNode }, event, matches }) => {
if (matches({ resolveBranch: 'loading' })) {
showLoadingStatus(currentNode);
} else if (event.type === 'done.invoke.getChildren') {
hideLoadingStatus();
}
if (matches('renderBranch') && isBranch(currentNode)) {
await listChildNodes(currentNode);
} else if (matches('renderLeaf')) {
renderChoice(currentNode);
interpreter.send({ type: 'FINALISE' });
} else if (matches('renderValue') && isLeaf(currentNode)) {
await renderValue(currentNode);
}
});
interpreter.start();
};