@avandar/acclimate 0.2.1 → 0.3.0
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.cjs +302 -105
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +302 -105
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var changeCase = require('change-case');
|
|
4
4
|
var tsPattern = require('ts-pattern');
|
|
5
|
+
var process$1 = require('process');
|
|
6
|
+
var promises = require('readline/promises');
|
|
5
7
|
|
|
6
8
|
// src/CLIError.ts
|
|
7
9
|
var CLIError = class _CLIError extends Error {
|
|
@@ -174,14 +176,224 @@ var defaultCLIState = {
|
|
|
174
176
|
positionalArgs: [],
|
|
175
177
|
optionArgs: {},
|
|
176
178
|
globalOptionArgs: {},
|
|
177
|
-
action:
|
|
178
|
-
}
|
|
179
|
+
action: void 0
|
|
179
180
|
};
|
|
180
181
|
|
|
181
182
|
// src/AcclimateCLI/createCLI/createCLI.ts
|
|
182
183
|
function createCLI(name) {
|
|
183
184
|
return AcclimateCLI({ ...defaultCLIState, name });
|
|
184
185
|
}
|
|
186
|
+
|
|
187
|
+
// src/generateTerminalMessage/generateTerminalMessage.ts
|
|
188
|
+
var COLOR_CODES = {
|
|
189
|
+
reset: "\x1B[0m",
|
|
190
|
+
black: "\x1B[30m",
|
|
191
|
+
red: "\x1B[31m",
|
|
192
|
+
green: "\x1B[32m",
|
|
193
|
+
yellow: "\x1B[33m",
|
|
194
|
+
blue: "\x1B[34m",
|
|
195
|
+
magenta: "\x1B[35m",
|
|
196
|
+
cyan: "\x1B[36m",
|
|
197
|
+
white: "\x1B[37m",
|
|
198
|
+
bright_black: "\x1B[90m",
|
|
199
|
+
gray: "\x1B[90m",
|
|
200
|
+
grey: "\x1B[90m",
|
|
201
|
+
bright_red: "\x1B[91m",
|
|
202
|
+
bright_green: "\x1B[92m",
|
|
203
|
+
bright_yellow: "\x1B[93m",
|
|
204
|
+
bright_blue: "\x1B[94m",
|
|
205
|
+
bright_magenta: "\x1B[95m",
|
|
206
|
+
bright_cyan: "\x1B[96m",
|
|
207
|
+
bright_white: "\x1B[97m"
|
|
208
|
+
};
|
|
209
|
+
var PARAM_TOKEN_REGEX = /\$([a-zA-Z0-9_]+)\$/g;
|
|
210
|
+
var COLOR_TOKEN_REGEX = /\|([a-zA-Z_]+)\|/g;
|
|
211
|
+
function interpolateParams(message, params) {
|
|
212
|
+
return message.replace(PARAM_TOKEN_REGEX, (match2, key) => {
|
|
213
|
+
const value = params[key];
|
|
214
|
+
if (value === void 0) {
|
|
215
|
+
return "";
|
|
216
|
+
}
|
|
217
|
+
return value;
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
function applyColors(message) {
|
|
221
|
+
return message.replace(COLOR_TOKEN_REGEX, (match2, colorName) => {
|
|
222
|
+
const code = COLOR_CODES[colorName.toLowerCase()];
|
|
223
|
+
return code ?? match2;
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
function generateTerminalMessage(message, params = {}) {
|
|
227
|
+
const hasColorToken = Boolean(message.match(COLOR_TOKEN_REGEX));
|
|
228
|
+
const endsWithReset = message.trimEnd().endsWith("|reset|");
|
|
229
|
+
const withReset = hasColorToken && !endsWithReset ? `${message}|reset|` : message;
|
|
230
|
+
const interpolated = interpolateParams(withReset, params);
|
|
231
|
+
return applyColors(interpolated);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// src/AcclimateCLI/generateHelpText/generateHelpText.ts
|
|
235
|
+
function formatSectionTitle(title) {
|
|
236
|
+
return `|bright_yellow|${title}|reset|`;
|
|
237
|
+
}
|
|
238
|
+
function formatNoneLine() {
|
|
239
|
+
return " |gray|None|reset|";
|
|
240
|
+
}
|
|
241
|
+
function formatDefaultValue(value) {
|
|
242
|
+
return `|gray|[default: ${JSON.stringify(value)}]|reset|`;
|
|
243
|
+
}
|
|
244
|
+
function formatParamLine(param) {
|
|
245
|
+
const description = param.description ?? "No description";
|
|
246
|
+
const requiredLabel = param.required ? "|red|required|reset|" : "|gray|optional|reset|";
|
|
247
|
+
const defaultLabel = param.defaultValue !== void 0 ? formatDefaultValue(param.defaultValue) : void 0;
|
|
248
|
+
const aliasList = param.aliases && param.aliases.length > 0 ? param.aliases.join(", ") : "";
|
|
249
|
+
const displayName = aliasList ? `${param.name}, ${aliasList}` : param.name;
|
|
250
|
+
const segments = [
|
|
251
|
+
` |bright_white|${displayName}|reset|`,
|
|
252
|
+
`(${param.type})|reset| ${requiredLabel}`,
|
|
253
|
+
`- |gray|${description}|reset|`,
|
|
254
|
+
defaultLabel
|
|
255
|
+
].filter(Boolean);
|
|
256
|
+
return segments.join(" ");
|
|
257
|
+
}
|
|
258
|
+
function formatSection(title, params) {
|
|
259
|
+
if (params.length === 0) {
|
|
260
|
+
return [formatSectionTitle(title), formatNoneLine()];
|
|
261
|
+
}
|
|
262
|
+
return [formatSectionTitle(title), ...params.map(formatParamLine)];
|
|
263
|
+
}
|
|
264
|
+
function formatCommandLine(options) {
|
|
265
|
+
const { name, description } = options;
|
|
266
|
+
const label = description ?? "No description";
|
|
267
|
+
return ` |bright_white|${name}|reset| - |gray|${label}|reset|`;
|
|
268
|
+
}
|
|
269
|
+
function formatAvailableCommandsLine(commands) {
|
|
270
|
+
const label = commands.length === 0 ? "None" : commands.map((cmd) => {
|
|
271
|
+
return cmd;
|
|
272
|
+
}).join(", ");
|
|
273
|
+
return `|bright_yellow|Available Commands:|reset| |gray|${label}|reset|`;
|
|
274
|
+
}
|
|
275
|
+
function _generateHelpTextHelper(cli, options) {
|
|
276
|
+
const name = cli.getName();
|
|
277
|
+
const description = cli.state.description;
|
|
278
|
+
const level = Number(options.level);
|
|
279
|
+
const positionalParams = cli.state.positionalArgs;
|
|
280
|
+
const optionParams = Object.values(
|
|
281
|
+
cli.state.optionArgs
|
|
282
|
+
);
|
|
283
|
+
const globalOptionParams = Object.values(
|
|
284
|
+
cli.state.globalOptionArgs
|
|
285
|
+
);
|
|
286
|
+
const sortedCommands = Object.entries(cli.state.commands).sort(([a], [b]) => {
|
|
287
|
+
return a.localeCompare(b);
|
|
288
|
+
});
|
|
289
|
+
const commandNames = sortedCommands.map(([commandName]) => {
|
|
290
|
+
return commandName;
|
|
291
|
+
});
|
|
292
|
+
const headerLines = [`|bright_cyan|${name}|reset|`];
|
|
293
|
+
if (description !== void 0) {
|
|
294
|
+
headerLines.push(` |gray|${description}|reset|`);
|
|
295
|
+
}
|
|
296
|
+
let commandSection;
|
|
297
|
+
if (level === 2) {
|
|
298
|
+
commandSection = [
|
|
299
|
+
formatSectionTitle("Commands"),
|
|
300
|
+
` ${formatAvailableCommandsLine(commandNames)}`
|
|
301
|
+
];
|
|
302
|
+
} else if (sortedCommands.length === 0) {
|
|
303
|
+
commandSection = [formatSectionTitle("Commands"), formatNoneLine()];
|
|
304
|
+
} else {
|
|
305
|
+
commandSection = [
|
|
306
|
+
formatSectionTitle("Commands"),
|
|
307
|
+
...sortedCommands.map(([commandName, commandCLI]) => {
|
|
308
|
+
return formatCommandLine({
|
|
309
|
+
name: commandName,
|
|
310
|
+
description: commandCLI.state.description
|
|
311
|
+
});
|
|
312
|
+
})
|
|
313
|
+
];
|
|
314
|
+
}
|
|
315
|
+
const sections = [
|
|
316
|
+
formatSection("Positional Arguments", positionalParams),
|
|
317
|
+
formatSection("Options", optionParams),
|
|
318
|
+
formatSection("Global Options", globalOptionParams),
|
|
319
|
+
commandSection
|
|
320
|
+
];
|
|
321
|
+
const lines = [...headerLines, ""];
|
|
322
|
+
sections.forEach((section, idx) => {
|
|
323
|
+
lines.push(...section);
|
|
324
|
+
if (idx < sections.length - 1) {
|
|
325
|
+
lines.push("");
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
if (level === 1) {
|
|
329
|
+
const subCommandHelpText = sortedCommands.map(([, commandCLI]) => {
|
|
330
|
+
return _generateHelpTextHelper(commandCLI, { level: 2 });
|
|
331
|
+
});
|
|
332
|
+
if (subCommandHelpText.length > 0) {
|
|
333
|
+
subCommandHelpText.forEach((text) => {
|
|
334
|
+
lines.push("", ...text.split("\n"));
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
const indent = " ".repeat(Math.max(0, level - 1));
|
|
339
|
+
return lines.map((line) => {
|
|
340
|
+
return line === "" ? "" : `${indent}${line}`;
|
|
341
|
+
}).join("\n");
|
|
342
|
+
}
|
|
343
|
+
function generateHelpText(cli) {
|
|
344
|
+
return generateTerminalMessage(_generateHelpTextHelper(cli, { level: 1 }));
|
|
345
|
+
}
|
|
346
|
+
var COLOR_TOKEN_REGEX2 = /\|[a-zA-Z_]+\|/g;
|
|
347
|
+
function messageHasPunctuation(message) {
|
|
348
|
+
const stripped = message.replace(COLOR_TOKEN_REGEX2, "").trimEnd();
|
|
349
|
+
return stripped.endsWith(":") || stripped.endsWith("?");
|
|
350
|
+
}
|
|
351
|
+
async function requestTerminalInput(options) {
|
|
352
|
+
const { message, params, options: promptOptions } = options;
|
|
353
|
+
const notice = promptOptions.required ? "" : " |gray|(press Enter to leave empty)|reset|";
|
|
354
|
+
const booleanNotice = promptOptions.type === "boolean" ? " |reset|(y/n)" : "";
|
|
355
|
+
const promptMessage = `${message}${booleanNotice}${notice}`;
|
|
356
|
+
const promptText = messageHasPunctuation(message) ? `${promptMessage} ` : `${promptMessage}: `;
|
|
357
|
+
const prompt = generateTerminalMessage(promptText, params);
|
|
358
|
+
const rl = promises.createInterface({ input: process$1.stdin, output: process$1.stdout });
|
|
359
|
+
try {
|
|
360
|
+
while (true) {
|
|
361
|
+
const answer = await rl.question(prompt);
|
|
362
|
+
const trimmed = answer.trim();
|
|
363
|
+
if (trimmed.length === 0) {
|
|
364
|
+
if (promptOptions.required) {
|
|
365
|
+
process$1.stdout.write(
|
|
366
|
+
generateTerminalMessage(
|
|
367
|
+
"|red|This value is required.|reset| Please enter a value.\n"
|
|
368
|
+
)
|
|
369
|
+
);
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
return void 0;
|
|
373
|
+
}
|
|
374
|
+
if (promptOptions.type === "boolean") {
|
|
375
|
+
const normalized = trimmed.toLowerCase();
|
|
376
|
+
if (normalized === "y" || normalized === "yes") {
|
|
377
|
+
return "true";
|
|
378
|
+
}
|
|
379
|
+
if (normalized === "n" || normalized === "no") {
|
|
380
|
+
return "false";
|
|
381
|
+
}
|
|
382
|
+
process$1.stdout.write(
|
|
383
|
+
generateTerminalMessage(
|
|
384
|
+
"|red|That was not a valid response.|reset| Please enter y or n.\n"
|
|
385
|
+
)
|
|
386
|
+
);
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
return answer;
|
|
390
|
+
}
|
|
391
|
+
} finally {
|
|
392
|
+
rl.close();
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// src/AcclimateCLI/runCLI/runCLI.ts
|
|
185
397
|
function _isValidFullOptionName(name) {
|
|
186
398
|
return name.startsWith("--");
|
|
187
399
|
}
|
|
@@ -250,7 +462,19 @@ function _replaceAliases({
|
|
|
250
462
|
{}
|
|
251
463
|
);
|
|
252
464
|
}
|
|
253
|
-
function
|
|
465
|
+
async function askForValue(options) {
|
|
466
|
+
const { argConfig } = options;
|
|
467
|
+
const askIfEmpty = argConfig.askIfEmpty;
|
|
468
|
+
const description = argConfig.description ? ` (${argConfig.description})` : "";
|
|
469
|
+
const baseMessage = typeof askIfEmpty === "object" ? askIfEmpty.message : `Please enter a value for ${argConfig.name}${description}`;
|
|
470
|
+
const coloredMessage = `|bright_cyan|${baseMessage}|reset|`;
|
|
471
|
+
return requestTerminalInput({
|
|
472
|
+
message: coloredMessage,
|
|
473
|
+
params: {},
|
|
474
|
+
options: { required: argConfig.required, type: argConfig.type }
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
async function _runCLIHelper(options) {
|
|
254
478
|
const { rawGlobalOptionArgs, rawOptionArgs, rawPositionalArgs, cli } = {
|
|
255
479
|
...options,
|
|
256
480
|
rawGlobalOptionArgs: _replaceAliases({
|
|
@@ -287,74 +511,79 @@ function _runCLIHelper(options) {
|
|
|
287
511
|
count: rawPositionalArgs.length
|
|
288
512
|
});
|
|
289
513
|
}
|
|
290
|
-
const parsedPositionalArgs =
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
299
|
-
acc[argConfig.name] = _parseAndValidateValue({
|
|
514
|
+
const parsedPositionalArgs = {};
|
|
515
|
+
for (const [idx, argConfig] of cli.state.positionalArgs.entries()) {
|
|
516
|
+
let rawVal = rawPositionalArgs[idx];
|
|
517
|
+
if (argConfig.askIfEmpty && rawVal === void 0) {
|
|
518
|
+
rawVal = await askForValue({ argConfig });
|
|
519
|
+
}
|
|
520
|
+
if (argConfig.required && rawVal === void 0) {
|
|
521
|
+
throw CLIError.missingRequiredPositionalArg({
|
|
300
522
|
cliName,
|
|
301
|
-
|
|
302
|
-
defaultValue: argConfig.defaultValue,
|
|
303
|
-
paramConfig: argConfig
|
|
523
|
+
positionalArgName: argConfig.name
|
|
304
524
|
});
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
525
|
+
}
|
|
526
|
+
parsedPositionalArgs[argConfig.name] = _parseAndValidateValue({
|
|
527
|
+
cliName,
|
|
528
|
+
inputValue: rawVal,
|
|
529
|
+
defaultValue: argConfig.defaultValue,
|
|
530
|
+
paramConfig: argConfig
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
const parsedOptionArgs = {};
|
|
534
|
+
for (const argConfig of Object.values(
|
|
310
535
|
cli.state.optionArgs
|
|
311
|
-
)
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
acc[changeCase.camelCase(argConfig.name)] = _parseAndValidateValue({
|
|
536
|
+
)) {
|
|
537
|
+
let rawVal = rawOptionArgs[argConfig.name];
|
|
538
|
+
if (argConfig.askIfEmpty && rawVal === void 0) {
|
|
539
|
+
rawVal = await askForValue({ argConfig });
|
|
540
|
+
}
|
|
541
|
+
if (argConfig.required && rawVal === void 0) {
|
|
542
|
+
throw CLIError.missingRequiredOption({
|
|
321
543
|
cliName,
|
|
322
|
-
|
|
323
|
-
defaultValue: argConfig.defaultValue,
|
|
324
|
-
paramConfig: argConfig
|
|
544
|
+
optionName: argConfig.name
|
|
325
545
|
});
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
546
|
+
}
|
|
547
|
+
parsedOptionArgs[changeCase.camelCase(argConfig.name)] = _parseAndValidateValue({
|
|
548
|
+
cliName,
|
|
549
|
+
inputValue: rawVal,
|
|
550
|
+
defaultValue: argConfig.defaultValue,
|
|
551
|
+
paramConfig: argConfig
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
const parsedGlobalOptionArgs = {};
|
|
555
|
+
for (const argConfig of Object.values(
|
|
331
556
|
cli.state.globalOptionArgs
|
|
332
|
-
)
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
acc[changeCase.camelCase(argConfig.name)] = _parseAndValidateValue({
|
|
557
|
+
)) {
|
|
558
|
+
let rawVal = rawGlobalOptionArgs[argConfig.name];
|
|
559
|
+
if (argConfig.askIfEmpty && rawVal === void 0) {
|
|
560
|
+
rawVal = await askForValue({ argConfig });
|
|
561
|
+
}
|
|
562
|
+
if (argConfig.required && rawVal === void 0) {
|
|
563
|
+
throw CLIError.missingRequiredOption({
|
|
342
564
|
cliName,
|
|
343
|
-
|
|
344
|
-
defaultValue: argConfig.defaultValue,
|
|
345
|
-
paramConfig: argConfig
|
|
565
|
+
optionName: argConfig.name
|
|
346
566
|
});
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
567
|
+
}
|
|
568
|
+
parsedGlobalOptionArgs[changeCase.camelCase(argConfig.name)] = _parseAndValidateValue({
|
|
569
|
+
cliName,
|
|
570
|
+
inputValue: rawVal,
|
|
571
|
+
defaultValue: argConfig.defaultValue,
|
|
572
|
+
paramConfig: argConfig
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
const action = cli.state.action;
|
|
576
|
+
if (action) {
|
|
577
|
+
action({
|
|
578
|
+
...parsedPositionalArgs,
|
|
579
|
+
...parsedOptionArgs,
|
|
580
|
+
...parsedGlobalOptionArgs
|
|
581
|
+
});
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
console.log(generateHelpText(cli));
|
|
356
585
|
}
|
|
357
|
-
function runCLI(options) {
|
|
586
|
+
async function runCLI(options) {
|
|
358
587
|
const { input, cli } = options;
|
|
359
588
|
const firstOptionIdx = input.findIndex((token) => {
|
|
360
589
|
return token.startsWith("-");
|
|
@@ -382,57 +611,25 @@ function runCLI(options) {
|
|
|
382
611
|
currentVals.push(argVal);
|
|
383
612
|
}
|
|
384
613
|
}
|
|
385
|
-
_runCLIHelper({
|
|
614
|
+
await _runCLIHelper({
|
|
615
|
+
rawPositionalArgs,
|
|
616
|
+
rawOptionArgs,
|
|
617
|
+
rawGlobalOptionArgs,
|
|
618
|
+
cli
|
|
619
|
+
});
|
|
386
620
|
}
|
|
387
621
|
|
|
388
622
|
// src/Acclimate.ts
|
|
389
|
-
var COLOR_CODES = {
|
|
390
|
-
reset: "\x1B[0m",
|
|
391
|
-
black: "\x1B[30m",
|
|
392
|
-
red: "\x1B[31m",
|
|
393
|
-
green: "\x1B[32m",
|
|
394
|
-
yellow: "\x1B[33m",
|
|
395
|
-
blue: "\x1B[34m",
|
|
396
|
-
magenta: "\x1B[35m",
|
|
397
|
-
cyan: "\x1B[36m",
|
|
398
|
-
white: "\x1B[37m",
|
|
399
|
-
bright_black: "\x1B[90m",
|
|
400
|
-
gray: "\x1B[90m",
|
|
401
|
-
grey: "\x1B[90m",
|
|
402
|
-
bright_red: "\x1B[91m",
|
|
403
|
-
bright_green: "\x1B[92m",
|
|
404
|
-
bright_yellow: "\x1B[93m",
|
|
405
|
-
bright_blue: "\x1B[94m",
|
|
406
|
-
bright_magenta: "\x1B[95m",
|
|
407
|
-
bright_cyan: "\x1B[96m",
|
|
408
|
-
bright_white: "\x1B[97m"
|
|
409
|
-
};
|
|
410
|
-
var PARAM_TOKEN_REGEX = /\$([a-zA-Z0-9_]+)\$/g;
|
|
411
|
-
var COLOR_TOKEN_REGEX = /\|([a-zA-Z_]+)\|/g;
|
|
412
|
-
function interpolateParams(message, params) {
|
|
413
|
-
return message.replace(PARAM_TOKEN_REGEX, (match2, key) => {
|
|
414
|
-
const value = params[key];
|
|
415
|
-
return value ?? match2;
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
function applyColors(message) {
|
|
419
|
-
return message.replace(COLOR_TOKEN_REGEX, (match2, colorName) => {
|
|
420
|
-
const code = COLOR_CODES[colorName.toLowerCase()];
|
|
421
|
-
return code ?? match2;
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
623
|
var Acclimate = {
|
|
425
624
|
createCLI,
|
|
426
625
|
run: (cli) => {
|
|
427
|
-
runCLI({ cli, input: process.argv.slice(2) });
|
|
626
|
+
void runCLI({ cli, input: process.argv.slice(2) });
|
|
428
627
|
},
|
|
429
628
|
log: (message, params = {}) => {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
const colorized = applyColors(interpolated);
|
|
435
|
-
console.log(colorized);
|
|
629
|
+
console.log(generateTerminalMessage(message, params));
|
|
630
|
+
},
|
|
631
|
+
requestInput: (options) => {
|
|
632
|
+
return requestTerminalInput(options);
|
|
436
633
|
}
|
|
437
634
|
};
|
|
438
635
|
|