mirror of
https://github.com/tvytlx/ai-agent-deep-dive.git
synced 2026-04-04 16:14:50 +08:00
Add extracted source directory and README navigation
This commit is contained in:
12
extracted-source/node_modules/@inquirer/core/dist/esm/index.mjs
generated
vendored
Normal file
12
extracted-source/node_modules/@inquirer/core/dist/esm/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
export * from './lib/key.mjs';
|
||||
export * from './lib/errors.mjs';
|
||||
export { usePrefix } from './lib/use-prefix.mjs';
|
||||
export { useState } from './lib/use-state.mjs';
|
||||
export { useEffect } from './lib/use-effect.mjs';
|
||||
export { useMemo } from './lib/use-memo.mjs';
|
||||
export { useRef } from './lib/use-ref.mjs';
|
||||
export { useKeypress } from './lib/use-keypress.mjs';
|
||||
export { makeTheme } from './lib/make-theme.mjs';
|
||||
export { usePagination } from './lib/pagination/use-pagination.mjs';
|
||||
export { createPrompt } from './lib/create-prompt.mjs';
|
||||
export { Separator } from './lib/Separator.mjs';
|
||||
21
extracted-source/node_modules/@inquirer/core/dist/esm/lib/Separator.mjs
generated
vendored
Normal file
21
extracted-source/node_modules/@inquirer/core/dist/esm/lib/Separator.mjs
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import colors from 'yoctocolors-cjs';
|
||||
import figures from '@inquirer/figures';
|
||||
/**
|
||||
* Separator object
|
||||
* Used to space/separate choices group
|
||||
*/
|
||||
export class Separator {
|
||||
separator = colors.dim(Array.from({ length: 15 }).join(figures.line));
|
||||
type = 'separator';
|
||||
constructor(separator) {
|
||||
if (separator) {
|
||||
this.separator = separator;
|
||||
}
|
||||
}
|
||||
static isSeparator(choice) {
|
||||
return Boolean(choice &&
|
||||
typeof choice === 'object' &&
|
||||
'type' in choice &&
|
||||
choice.type === 'separator');
|
||||
}
|
||||
}
|
||||
84
extracted-source/node_modules/@inquirer/core/dist/esm/lib/create-prompt.mjs
generated
vendored
Normal file
84
extracted-source/node_modules/@inquirer/core/dist/esm/lib/create-prompt.mjs
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
import * as readline from 'node:readline';
|
||||
import { AsyncResource } from 'node:async_hooks';
|
||||
import MuteStream from 'mute-stream';
|
||||
import { onExit as onSignalExit } from 'signal-exit';
|
||||
import ScreenManager from './screen-manager.mjs';
|
||||
import { PromisePolyfill } from './promise-polyfill.mjs';
|
||||
import { withHooks, effectScheduler } from './hook-engine.mjs';
|
||||
import { AbortPromptError, CancelPromptError, ExitPromptError } from './errors.mjs';
|
||||
export function createPrompt(view) {
|
||||
const prompt = (config, context = {}) => {
|
||||
// Default `input` to stdin
|
||||
const { input = process.stdin, signal } = context;
|
||||
const cleanups = new Set();
|
||||
// Add mute capabilities to the output
|
||||
const output = new MuteStream();
|
||||
output.pipe(context.output ?? process.stdout);
|
||||
const rl = readline.createInterface({
|
||||
terminal: true,
|
||||
input,
|
||||
output,
|
||||
});
|
||||
const screen = new ScreenManager(rl);
|
||||
const { promise, resolve, reject } = PromisePolyfill.withResolver();
|
||||
/** @deprecated pass an AbortSignal in the context options instead. See {@link https://github.com/SBoudrias/Inquirer.js#canceling-prompt} */
|
||||
const cancel = () => reject(new CancelPromptError());
|
||||
if (signal) {
|
||||
const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
|
||||
if (signal.aborted) {
|
||||
abort();
|
||||
return Object.assign(promise, { cancel });
|
||||
}
|
||||
signal.addEventListener('abort', abort);
|
||||
cleanups.add(() => signal.removeEventListener('abort', abort));
|
||||
}
|
||||
cleanups.add(onSignalExit((code, signal) => {
|
||||
reject(new ExitPromptError(`User force closed the prompt with ${code} ${signal}`));
|
||||
}));
|
||||
// Re-renders only happen when the state change; but the readline cursor could change position
|
||||
// and that also requires a re-render (and a manual one because we mute the streams).
|
||||
// We set the listener after the initial workLoop to avoid a double render if render triggered
|
||||
// by a state change sets the cursor to the right position.
|
||||
const checkCursorPos = () => screen.checkCursorPos();
|
||||
rl.input.on('keypress', checkCursorPos);
|
||||
cleanups.add(() => rl.input.removeListener('keypress', checkCursorPos));
|
||||
return withHooks(rl, (cycle) => {
|
||||
// The close event triggers immediately when the user press ctrl+c. SignalExit on the other hand
|
||||
// triggers after the process is done (which happens after timeouts are done triggering.)
|
||||
// We triggers the hooks cleanup phase on rl `close` so active timeouts can be cleared.
|
||||
const hooksCleanup = AsyncResource.bind(() => effectScheduler.clearAll());
|
||||
rl.on('close', hooksCleanup);
|
||||
cleanups.add(() => rl.removeListener('close', hooksCleanup));
|
||||
cycle(() => {
|
||||
try {
|
||||
const nextView = view(config, (value) => {
|
||||
setImmediate(() => resolve(value));
|
||||
});
|
||||
const [content, bottomContent] = typeof nextView === 'string' ? [nextView] : nextView;
|
||||
screen.render(content, bottomContent);
|
||||
effectScheduler.run();
|
||||
}
|
||||
catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
return Object.assign(promise
|
||||
.then((answer) => {
|
||||
effectScheduler.clearAll();
|
||||
return answer;
|
||||
}, (error) => {
|
||||
effectScheduler.clearAll();
|
||||
throw error;
|
||||
})
|
||||
// Wait for the promise to settle, then cleanup.
|
||||
.finally(() => {
|
||||
cleanups.forEach((cleanup) => cleanup());
|
||||
screen.done({ clearContent: Boolean(context?.clearPromptOnDone) });
|
||||
output.end();
|
||||
})
|
||||
// Once cleanup is done, let the expose promise resolve/reject to the internal one.
|
||||
.then(() => promise), { cancel });
|
||||
});
|
||||
};
|
||||
return prompt;
|
||||
}
|
||||
21
extracted-source/node_modules/@inquirer/core/dist/esm/lib/errors.mjs
generated
vendored
Normal file
21
extracted-source/node_modules/@inquirer/core/dist/esm/lib/errors.mjs
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
export class AbortPromptError extends Error {
|
||||
name = 'AbortPromptError';
|
||||
message = 'Prompt was aborted';
|
||||
constructor(options) {
|
||||
super();
|
||||
this.cause = options?.cause;
|
||||
}
|
||||
}
|
||||
export class CancelPromptError extends Error {
|
||||
name = 'CancelPromptError';
|
||||
message = 'Prompt was canceled';
|
||||
}
|
||||
export class ExitPromptError extends Error {
|
||||
name = 'ExitPromptError';
|
||||
}
|
||||
export class HookError extends Error {
|
||||
name = 'HookError';
|
||||
}
|
||||
export class ValidationError extends Error {
|
||||
name = 'ValidationError';
|
||||
}
|
||||
110
extracted-source/node_modules/@inquirer/core/dist/esm/lib/hook-engine.mjs
generated
vendored
Normal file
110
extracted-source/node_modules/@inquirer/core/dist/esm/lib/hook-engine.mjs
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
/* eslint @typescript-eslint/no-explicit-any: ["off"] */
|
||||
import { AsyncLocalStorage, AsyncResource } from 'node:async_hooks';
|
||||
import { HookError, ValidationError } from './errors.mjs';
|
||||
const hookStorage = new AsyncLocalStorage();
|
||||
function createStore(rl) {
|
||||
const store = {
|
||||
rl,
|
||||
hooks: [],
|
||||
hooksCleanup: [],
|
||||
hooksEffect: [],
|
||||
index: 0,
|
||||
handleChange() { },
|
||||
};
|
||||
return store;
|
||||
}
|
||||
// Run callback in with the hook engine setup.
|
||||
export function withHooks(rl, cb) {
|
||||
const store = createStore(rl);
|
||||
return hookStorage.run(store, () => {
|
||||
function cycle(render) {
|
||||
store.handleChange = () => {
|
||||
store.index = 0;
|
||||
render();
|
||||
};
|
||||
store.handleChange();
|
||||
}
|
||||
return cb(cycle);
|
||||
});
|
||||
}
|
||||
// Safe getStore utility that'll return the store or throw if undefined.
|
||||
function getStore() {
|
||||
const store = hookStorage.getStore();
|
||||
if (!store) {
|
||||
throw new HookError('[Inquirer] Hook functions can only be called from within a prompt');
|
||||
}
|
||||
return store;
|
||||
}
|
||||
export function readline() {
|
||||
return getStore().rl;
|
||||
}
|
||||
// Merge state updates happening within the callback function to avoid multiple renders.
|
||||
export function withUpdates(fn) {
|
||||
const wrapped = (...args) => {
|
||||
const store = getStore();
|
||||
let shouldUpdate = false;
|
||||
const oldHandleChange = store.handleChange;
|
||||
store.handleChange = () => {
|
||||
shouldUpdate = true;
|
||||
};
|
||||
const returnValue = fn(...args);
|
||||
if (shouldUpdate) {
|
||||
oldHandleChange();
|
||||
}
|
||||
store.handleChange = oldHandleChange;
|
||||
return returnValue;
|
||||
};
|
||||
return AsyncResource.bind(wrapped);
|
||||
}
|
||||
export function withPointer(cb) {
|
||||
const store = getStore();
|
||||
const { index } = store;
|
||||
const pointer = {
|
||||
get() {
|
||||
return store.hooks[index];
|
||||
},
|
||||
set(value) {
|
||||
store.hooks[index] = value;
|
||||
},
|
||||
initialized: index in store.hooks,
|
||||
};
|
||||
const returnValue = cb(pointer);
|
||||
store.index++;
|
||||
return returnValue;
|
||||
}
|
||||
export function handleChange() {
|
||||
getStore().handleChange();
|
||||
}
|
||||
export const effectScheduler = {
|
||||
queue(cb) {
|
||||
const store = getStore();
|
||||
const { index } = store;
|
||||
store.hooksEffect.push(() => {
|
||||
store.hooksCleanup[index]?.();
|
||||
const cleanFn = cb(readline());
|
||||
if (cleanFn != null && typeof cleanFn !== 'function') {
|
||||
throw new ValidationError('useEffect return value must be a cleanup function or nothing.');
|
||||
}
|
||||
store.hooksCleanup[index] = cleanFn;
|
||||
});
|
||||
},
|
||||
run() {
|
||||
const store = getStore();
|
||||
withUpdates(() => {
|
||||
store.hooksEffect.forEach((effect) => {
|
||||
effect();
|
||||
});
|
||||
// Warning: Clean the hooks before exiting the `withUpdates` block.
|
||||
// Failure to do so means an updates would hit the same effects again.
|
||||
store.hooksEffect.length = 0;
|
||||
})();
|
||||
},
|
||||
clearAll() {
|
||||
const store = getStore();
|
||||
store.hooksCleanup.forEach((cleanFn) => {
|
||||
cleanFn?.();
|
||||
});
|
||||
store.hooksEffect.length = 0;
|
||||
store.hooksCleanup.length = 0;
|
||||
},
|
||||
};
|
||||
18
extracted-source/node_modules/@inquirer/core/dist/esm/lib/key.mjs
generated
vendored
Normal file
18
extracted-source/node_modules/@inquirer/core/dist/esm/lib/key.mjs
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
export const isUpKey = (key) =>
|
||||
// The up key
|
||||
key.name === 'up' ||
|
||||
// Vim keybinding
|
||||
key.name === 'k' ||
|
||||
// Emacs keybinding
|
||||
(key.ctrl && key.name === 'p');
|
||||
export const isDownKey = (key) =>
|
||||
// The down key
|
||||
key.name === 'down' ||
|
||||
// Vim keybinding
|
||||
key.name === 'j' ||
|
||||
// Emacs keybinding
|
||||
(key.ctrl && key.name === 'n');
|
||||
export const isSpaceKey = (key) => key.name === 'space';
|
||||
export const isBackspaceKey = (key) => key.name === 'backspace';
|
||||
export const isNumberKey = (key) => '123456789'.includes(key.name);
|
||||
export const isEnterKey = (key) => key.name === 'enter' || key.name === 'return';
|
||||
30
extracted-source/node_modules/@inquirer/core/dist/esm/lib/make-theme.mjs
generated
vendored
Normal file
30
extracted-source/node_modules/@inquirer/core/dist/esm/lib/make-theme.mjs
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
import { defaultTheme } from './theme.mjs';
|
||||
function isPlainObject(value) {
|
||||
if (typeof value !== 'object' || value === null)
|
||||
return false;
|
||||
let proto = value;
|
||||
while (Object.getPrototypeOf(proto) !== null) {
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
}
|
||||
return Object.getPrototypeOf(value) === proto;
|
||||
}
|
||||
function deepMerge(...objects) {
|
||||
const output = {};
|
||||
for (const obj of objects) {
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
const prevValue = output[key];
|
||||
output[key] =
|
||||
isPlainObject(prevValue) && isPlainObject(value)
|
||||
? deepMerge(prevValue, value)
|
||||
: value;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
export function makeTheme(...themes) {
|
||||
const themesToMerge = [
|
||||
defaultTheme,
|
||||
...themes.filter((theme) => theme != null),
|
||||
];
|
||||
return deepMerge(...themesToMerge);
|
||||
}
|
||||
59
extracted-source/node_modules/@inquirer/core/dist/esm/lib/pagination/lines.mjs
generated
vendored
Normal file
59
extracted-source/node_modules/@inquirer/core/dist/esm/lib/pagination/lines.mjs
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
import { breakLines } from '../utils.mjs';
|
||||
function split(content, width) {
|
||||
return breakLines(content, width).split('\n');
|
||||
}
|
||||
/**
|
||||
* Rotates an array of items by an integer number of positions.
|
||||
* @param {number} count The number of positions to rotate by
|
||||
* @param {T[]} items The items to rotate
|
||||
*/
|
||||
function rotate(count, items) {
|
||||
const max = items.length;
|
||||
const offset = ((count % max) + max) % max;
|
||||
return [...items.slice(offset), ...items.slice(0, offset)];
|
||||
}
|
||||
/**
|
||||
* Renders a page of items as lines that fit within the given width ensuring
|
||||
* that the number of lines is not greater than the page size, and the active
|
||||
* item renders at the provided position, while prioritizing that as many lines
|
||||
* of the active item get rendered as possible.
|
||||
*/
|
||||
export function lines({ items, width, renderItem, active, position: requested, pageSize, }) {
|
||||
const layouts = items.map((item, index) => ({
|
||||
item,
|
||||
index,
|
||||
isActive: index === active,
|
||||
}));
|
||||
const layoutsInPage = rotate(active - requested, layouts).slice(0, pageSize);
|
||||
const renderItemAt = (index) => layoutsInPage[index] == null ? [] : split(renderItem(layoutsInPage[index]), width);
|
||||
// Create a blank array of lines for the page
|
||||
const pageBuffer = Array.from({ length: pageSize });
|
||||
// Render the active item to decide the position
|
||||
const activeItem = renderItemAt(requested).slice(0, pageSize);
|
||||
const position = requested + activeItem.length <= pageSize ? requested : pageSize - activeItem.length;
|
||||
// Add the lines of the active item into the page
|
||||
pageBuffer.splice(position, activeItem.length, ...activeItem);
|
||||
// Fill the page under the active item
|
||||
let bufferPointer = position + activeItem.length;
|
||||
let layoutPointer = requested + 1;
|
||||
while (bufferPointer < pageSize && layoutPointer < layoutsInPage.length) {
|
||||
for (const line of renderItemAt(layoutPointer)) {
|
||||
pageBuffer[bufferPointer++] = line;
|
||||
if (bufferPointer >= pageSize)
|
||||
break;
|
||||
}
|
||||
layoutPointer++;
|
||||
}
|
||||
// Fill the page over the active item
|
||||
bufferPointer = position - 1;
|
||||
layoutPointer = requested - 1;
|
||||
while (bufferPointer >= 0 && layoutPointer >= 0) {
|
||||
for (const line of renderItemAt(layoutPointer).reverse()) {
|
||||
pageBuffer[bufferPointer--] = line;
|
||||
if (bufferPointer < 0)
|
||||
break;
|
||||
}
|
||||
layoutPointer--;
|
||||
}
|
||||
return pageBuffer.filter((line) => typeof line === 'string');
|
||||
}
|
||||
27
extracted-source/node_modules/@inquirer/core/dist/esm/lib/pagination/position.mjs
generated
vendored
Normal file
27
extracted-source/node_modules/@inquirer/core/dist/esm/lib/pagination/position.mjs
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Creates the next position for the active item considering a finite list of
|
||||
* items to be rendered on a page.
|
||||
*/
|
||||
export function finite({ active, pageSize, total, }) {
|
||||
const middle = Math.floor(pageSize / 2);
|
||||
if (total <= pageSize || active < middle)
|
||||
return active;
|
||||
if (active >= total - middle)
|
||||
return active + pageSize - total;
|
||||
return middle;
|
||||
}
|
||||
/**
|
||||
* Creates the next position for the active item considering an infinitely
|
||||
* looping list of items to be rendered on the page.
|
||||
*/
|
||||
export function infinite({ active, lastActive, total, pageSize, pointer, }) {
|
||||
if (total <= pageSize)
|
||||
return active;
|
||||
// Move the position only when the user moves down, and when the
|
||||
// navigation fits within a single page
|
||||
if (lastActive < active && active - lastActive < pageSize) {
|
||||
// Limit it to the middle of the list
|
||||
return Math.min(Math.floor(pageSize / 2), pointer + active - lastActive);
|
||||
}
|
||||
return pointer;
|
||||
}
|
||||
30
extracted-source/node_modules/@inquirer/core/dist/esm/lib/pagination/use-pagination.mjs
generated
vendored
Normal file
30
extracted-source/node_modules/@inquirer/core/dist/esm/lib/pagination/use-pagination.mjs
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
import { useRef } from '../use-ref.mjs';
|
||||
import { readlineWidth } from '../utils.mjs';
|
||||
import { lines } from './lines.mjs';
|
||||
import { finite, infinite } from './position.mjs';
|
||||
export function usePagination({ items, active, renderItem, pageSize, loop = true, }) {
|
||||
const state = useRef({ position: 0, lastActive: 0 });
|
||||
const position = loop
|
||||
? infinite({
|
||||
active,
|
||||
lastActive: state.current.lastActive,
|
||||
total: items.length,
|
||||
pageSize,
|
||||
pointer: state.current.position,
|
||||
})
|
||||
: finite({
|
||||
active,
|
||||
total: items.length,
|
||||
pageSize,
|
||||
});
|
||||
state.current.position = position;
|
||||
state.current.lastActive = active;
|
||||
return lines({
|
||||
items,
|
||||
width: readlineWidth(),
|
||||
renderItem,
|
||||
active,
|
||||
position,
|
||||
pageSize,
|
||||
}).join('\n');
|
||||
}
|
||||
14
extracted-source/node_modules/@inquirer/core/dist/esm/lib/promise-polyfill.mjs
generated
vendored
Normal file
14
extracted-source/node_modules/@inquirer/core/dist/esm/lib/promise-polyfill.mjs
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// TODO: Remove this class once Node 22 becomes the minimum supported version.
|
||||
export class PromisePolyfill extends Promise {
|
||||
// Available starting from Node 22
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
|
||||
static withResolver() {
|
||||
let resolve;
|
||||
let reject;
|
||||
const promise = new Promise((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
return { promise, resolve: resolve, reject: reject };
|
||||
}
|
||||
}
|
||||
85
extracted-source/node_modules/@inquirer/core/dist/esm/lib/screen-manager.mjs
generated
vendored
Normal file
85
extracted-source/node_modules/@inquirer/core/dist/esm/lib/screen-manager.mjs
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
import stripAnsi from 'strip-ansi';
|
||||
import ansiEscapes from 'ansi-escapes';
|
||||
import { breakLines, readlineWidth } from './utils.mjs';
|
||||
const height = (content) => content.split('\n').length;
|
||||
const lastLine = (content) => content.split('\n').pop() ?? '';
|
||||
function cursorDown(n) {
|
||||
return n > 0 ? ansiEscapes.cursorDown(n) : '';
|
||||
}
|
||||
export default class ScreenManager {
|
||||
rl;
|
||||
// These variables are keeping information to allow correct prompt re-rendering
|
||||
height = 0;
|
||||
extraLinesUnderPrompt = 0;
|
||||
cursorPos;
|
||||
constructor(rl) {
|
||||
this.rl = rl;
|
||||
this.rl = rl;
|
||||
this.cursorPos = rl.getCursorPos();
|
||||
}
|
||||
write(content) {
|
||||
this.rl.output.unmute();
|
||||
this.rl.output.write(content);
|
||||
this.rl.output.mute();
|
||||
}
|
||||
render(content, bottomContent = '') {
|
||||
// Write message to screen and setPrompt to control backspace
|
||||
const promptLine = lastLine(content);
|
||||
const rawPromptLine = stripAnsi(promptLine);
|
||||
// Remove the rl.line from our prompt. We can't rely on the content of
|
||||
// rl.line (mainly because of the password prompt), so just rely on it's
|
||||
// length.
|
||||
let prompt = rawPromptLine;
|
||||
if (this.rl.line.length > 0) {
|
||||
prompt = prompt.slice(0, -this.rl.line.length);
|
||||
}
|
||||
this.rl.setPrompt(prompt);
|
||||
// SetPrompt will change cursor position, now we can get correct value
|
||||
this.cursorPos = this.rl.getCursorPos();
|
||||
const width = readlineWidth();
|
||||
content = breakLines(content, width);
|
||||
bottomContent = breakLines(bottomContent, width);
|
||||
// Manually insert an extra line if we're at the end of the line.
|
||||
// This prevent the cursor from appearing at the beginning of the
|
||||
// current line.
|
||||
if (rawPromptLine.length % width === 0) {
|
||||
content += '\n';
|
||||
}
|
||||
let output = content + (bottomContent ? '\n' + bottomContent : '');
|
||||
/**
|
||||
* Re-adjust the cursor at the correct position.
|
||||
*/
|
||||
// We need to consider parts of the prompt under the cursor as part of the bottom
|
||||
// content in order to correctly cleanup and re-render.
|
||||
const promptLineUpDiff = Math.floor(rawPromptLine.length / width) - this.cursorPos.rows;
|
||||
const bottomContentHeight = promptLineUpDiff + (bottomContent ? height(bottomContent) : 0);
|
||||
// Return cursor to the input position (on top of the bottomContent)
|
||||
if (bottomContentHeight > 0)
|
||||
output += ansiEscapes.cursorUp(bottomContentHeight);
|
||||
// Return cursor to the initial left offset.
|
||||
output += ansiEscapes.cursorTo(this.cursorPos.cols);
|
||||
/**
|
||||
* Render and store state for future re-rendering
|
||||
*/
|
||||
this.write(cursorDown(this.extraLinesUnderPrompt) +
|
||||
ansiEscapes.eraseLines(this.height) +
|
||||
output);
|
||||
this.extraLinesUnderPrompt = bottomContentHeight;
|
||||
this.height = height(output);
|
||||
}
|
||||
checkCursorPos() {
|
||||
const cursorPos = this.rl.getCursorPos();
|
||||
if (cursorPos.cols !== this.cursorPos.cols) {
|
||||
this.write(ansiEscapes.cursorTo(cursorPos.cols));
|
||||
this.cursorPos = cursorPos;
|
||||
}
|
||||
}
|
||||
done({ clearContent }) {
|
||||
this.rl.setPrompt('');
|
||||
let output = cursorDown(this.extraLinesUnderPrompt);
|
||||
output += clearContent ? ansiEscapes.eraseLines(this.height) : '\n';
|
||||
output += ansiEscapes.cursorShow;
|
||||
this.write(output);
|
||||
this.rl.close();
|
||||
}
|
||||
}
|
||||
22
extracted-source/node_modules/@inquirer/core/dist/esm/lib/theme.mjs
generated
vendored
Normal file
22
extracted-source/node_modules/@inquirer/core/dist/esm/lib/theme.mjs
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import colors from 'yoctocolors-cjs';
|
||||
import figures from '@inquirer/figures';
|
||||
export const defaultTheme = {
|
||||
prefix: {
|
||||
idle: colors.blue('?'),
|
||||
// TODO: use figure
|
||||
done: colors.green(figures.tick),
|
||||
},
|
||||
spinner: {
|
||||
interval: 80,
|
||||
frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'].map((frame) => colors.yellow(frame)),
|
||||
},
|
||||
style: {
|
||||
answer: colors.cyan,
|
||||
message: colors.bold,
|
||||
error: (text) => colors.red(`> ${text}`),
|
||||
defaultAnswer: (text) => colors.dim(`(${text})`),
|
||||
help: colors.dim,
|
||||
highlight: colors.cyan,
|
||||
key: (text) => colors.cyan(colors.bold(`<${text}>`)),
|
||||
},
|
||||
};
|
||||
11
extracted-source/node_modules/@inquirer/core/dist/esm/lib/use-effect.mjs
generated
vendored
Normal file
11
extracted-source/node_modules/@inquirer/core/dist/esm/lib/use-effect.mjs
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import { withPointer, effectScheduler } from './hook-engine.mjs';
|
||||
export function useEffect(cb, depArray) {
|
||||
withPointer((pointer) => {
|
||||
const oldDeps = pointer.get();
|
||||
const hasChanged = !Array.isArray(oldDeps) || depArray.some((dep, i) => !Object.is(dep, oldDeps[i]));
|
||||
if (hasChanged) {
|
||||
effectScheduler.queue(cb);
|
||||
}
|
||||
pointer.set(depArray);
|
||||
});
|
||||
}
|
||||
20
extracted-source/node_modules/@inquirer/core/dist/esm/lib/use-keypress.mjs
generated
vendored
Normal file
20
extracted-source/node_modules/@inquirer/core/dist/esm/lib/use-keypress.mjs
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import { useRef } from './use-ref.mjs';
|
||||
import { useEffect } from './use-effect.mjs';
|
||||
import { withUpdates } from './hook-engine.mjs';
|
||||
export function useKeypress(userHandler) {
|
||||
const signal = useRef(userHandler);
|
||||
signal.current = userHandler;
|
||||
useEffect((rl) => {
|
||||
let ignore = false;
|
||||
const handler = withUpdates((_input, event) => {
|
||||
if (ignore)
|
||||
return;
|
||||
void signal.current(event, rl);
|
||||
});
|
||||
rl.input.on('keypress', handler);
|
||||
return () => {
|
||||
ignore = true;
|
||||
rl.input.removeListener('keypress', handler);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
14
extracted-source/node_modules/@inquirer/core/dist/esm/lib/use-memo.mjs
generated
vendored
Normal file
14
extracted-source/node_modules/@inquirer/core/dist/esm/lib/use-memo.mjs
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import { withPointer } from './hook-engine.mjs';
|
||||
export function useMemo(fn, dependencies) {
|
||||
return withPointer((pointer) => {
|
||||
const prev = pointer.get();
|
||||
if (!prev ||
|
||||
prev.dependencies.length !== dependencies.length ||
|
||||
prev.dependencies.some((dep, i) => dep !== dependencies[i])) {
|
||||
const value = fn();
|
||||
pointer.set({ value, dependencies });
|
||||
return value;
|
||||
}
|
||||
return prev.value;
|
||||
});
|
||||
}
|
||||
36
extracted-source/node_modules/@inquirer/core/dist/esm/lib/use-prefix.mjs
generated
vendored
Normal file
36
extracted-source/node_modules/@inquirer/core/dist/esm/lib/use-prefix.mjs
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
import { AsyncResource } from 'node:async_hooks';
|
||||
import { useState } from './use-state.mjs';
|
||||
import { useEffect } from './use-effect.mjs';
|
||||
import { makeTheme } from './make-theme.mjs';
|
||||
export function usePrefix({ status = 'idle', theme, }) {
|
||||
const [showLoader, setShowLoader] = useState(false);
|
||||
const [tick, setTick] = useState(0);
|
||||
const { prefix, spinner } = makeTheme(theme);
|
||||
useEffect(() => {
|
||||
if (status === 'loading') {
|
||||
let tickInterval;
|
||||
let inc = -1;
|
||||
// Delay displaying spinner by 300ms, to avoid flickering
|
||||
const delayTimeout = setTimeout(AsyncResource.bind(() => {
|
||||
setShowLoader(true);
|
||||
tickInterval = setInterval(AsyncResource.bind(() => {
|
||||
inc = inc + 1;
|
||||
setTick(inc % spinner.frames.length);
|
||||
}), spinner.interval);
|
||||
}), 300);
|
||||
return () => {
|
||||
clearTimeout(delayTimeout);
|
||||
clearInterval(tickInterval);
|
||||
};
|
||||
}
|
||||
else {
|
||||
setShowLoader(false);
|
||||
}
|
||||
}, [status]);
|
||||
if (showLoader) {
|
||||
return spinner.frames[tick];
|
||||
}
|
||||
// There's a delay before we show the loader. So we want to ignore `loading` here, and pass idle instead.
|
||||
const iconName = status === 'loading' ? 'idle' : status;
|
||||
return typeof prefix === 'string' ? prefix : prefix[iconName];
|
||||
}
|
||||
4
extracted-source/node_modules/@inquirer/core/dist/esm/lib/use-ref.mjs
generated
vendored
Normal file
4
extracted-source/node_modules/@inquirer/core/dist/esm/lib/use-ref.mjs
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { useState } from './use-state.mjs';
|
||||
export function useRef(val) {
|
||||
return useState({ current: val })[0];
|
||||
}
|
||||
19
extracted-source/node_modules/@inquirer/core/dist/esm/lib/use-state.mjs
generated
vendored
Normal file
19
extracted-source/node_modules/@inquirer/core/dist/esm/lib/use-state.mjs
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import { withPointer, handleChange } from './hook-engine.mjs';
|
||||
export function useState(defaultValue) {
|
||||
return withPointer((pointer) => {
|
||||
const setFn = (newValue) => {
|
||||
// Noop if the value is still the same.
|
||||
if (pointer.get() !== newValue) {
|
||||
pointer.set(newValue);
|
||||
// Trigger re-render
|
||||
handleChange();
|
||||
}
|
||||
};
|
||||
if (pointer.initialized) {
|
||||
return [pointer.get(), setFn];
|
||||
}
|
||||
const value = typeof defaultValue === 'function' ? defaultValue() : defaultValue;
|
||||
pointer.set(value);
|
||||
return [value, setFn];
|
||||
});
|
||||
}
|
||||
25
extracted-source/node_modules/@inquirer/core/dist/esm/lib/utils.mjs
generated
vendored
Normal file
25
extracted-source/node_modules/@inquirer/core/dist/esm/lib/utils.mjs
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import cliWidth from 'cli-width';
|
||||
import wrapAnsi from 'wrap-ansi';
|
||||
import { readline } from './hook-engine.mjs';
|
||||
/**
|
||||
* Force line returns at specific width. This function is ANSI code friendly and it'll
|
||||
* ignore invisible codes during width calculation.
|
||||
* @param {string} content
|
||||
* @param {number} width
|
||||
* @return {string}
|
||||
*/
|
||||
export function breakLines(content, width) {
|
||||
return content
|
||||
.split('\n')
|
||||
.flatMap((line) => wrapAnsi(line, width, { trim: false, hard: true })
|
||||
.split('\n')
|
||||
.map((str) => str.trimEnd()))
|
||||
.join('\n');
|
||||
}
|
||||
/**
|
||||
* Returns the width of the active readline, or 80 as default value.
|
||||
* @returns {number}
|
||||
*/
|
||||
export function readlineWidth() {
|
||||
return cliWidth({ defaultWidth: 80, output: readline().output });
|
||||
}
|
||||
157
extracted-source/node_modules/@inquirer/core/node_modules/ansi-escapes/index.js
generated
vendored
Normal file
157
extracted-source/node_modules/@inquirer/core/node_modules/ansi-escapes/index.js
generated
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
'use strict';
|
||||
const ansiEscapes = module.exports;
|
||||
// TODO: remove this in the next major version
|
||||
module.exports.default = ansiEscapes;
|
||||
|
||||
const ESC = '\u001B[';
|
||||
const OSC = '\u001B]';
|
||||
const BEL = '\u0007';
|
||||
const SEP = ';';
|
||||
const isTerminalApp = process.env.TERM_PROGRAM === 'Apple_Terminal';
|
||||
|
||||
ansiEscapes.cursorTo = (x, y) => {
|
||||
if (typeof x !== 'number') {
|
||||
throw new TypeError('The `x` argument is required');
|
||||
}
|
||||
|
||||
if (typeof y !== 'number') {
|
||||
return ESC + (x + 1) + 'G';
|
||||
}
|
||||
|
||||
return ESC + (y + 1) + ';' + (x + 1) + 'H';
|
||||
};
|
||||
|
||||
ansiEscapes.cursorMove = (x, y) => {
|
||||
if (typeof x !== 'number') {
|
||||
throw new TypeError('The `x` argument is required');
|
||||
}
|
||||
|
||||
let ret = '';
|
||||
|
||||
if (x < 0) {
|
||||
ret += ESC + (-x) + 'D';
|
||||
} else if (x > 0) {
|
||||
ret += ESC + x + 'C';
|
||||
}
|
||||
|
||||
if (y < 0) {
|
||||
ret += ESC + (-y) + 'A';
|
||||
} else if (y > 0) {
|
||||
ret += ESC + y + 'B';
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
ansiEscapes.cursorUp = (count = 1) => ESC + count + 'A';
|
||||
ansiEscapes.cursorDown = (count = 1) => ESC + count + 'B';
|
||||
ansiEscapes.cursorForward = (count = 1) => ESC + count + 'C';
|
||||
ansiEscapes.cursorBackward = (count = 1) => ESC + count + 'D';
|
||||
|
||||
ansiEscapes.cursorLeft = ESC + 'G';
|
||||
ansiEscapes.cursorSavePosition = isTerminalApp ? '\u001B7' : ESC + 's';
|
||||
ansiEscapes.cursorRestorePosition = isTerminalApp ? '\u001B8' : ESC + 'u';
|
||||
ansiEscapes.cursorGetPosition = ESC + '6n';
|
||||
ansiEscapes.cursorNextLine = ESC + 'E';
|
||||
ansiEscapes.cursorPrevLine = ESC + 'F';
|
||||
ansiEscapes.cursorHide = ESC + '?25l';
|
||||
ansiEscapes.cursorShow = ESC + '?25h';
|
||||
|
||||
ansiEscapes.eraseLines = count => {
|
||||
let clear = '';
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
clear += ansiEscapes.eraseLine + (i < count - 1 ? ansiEscapes.cursorUp() : '');
|
||||
}
|
||||
|
||||
if (count) {
|
||||
clear += ansiEscapes.cursorLeft;
|
||||
}
|
||||
|
||||
return clear;
|
||||
};
|
||||
|
||||
ansiEscapes.eraseEndLine = ESC + 'K';
|
||||
ansiEscapes.eraseStartLine = ESC + '1K';
|
||||
ansiEscapes.eraseLine = ESC + '2K';
|
||||
ansiEscapes.eraseDown = ESC + 'J';
|
||||
ansiEscapes.eraseUp = ESC + '1J';
|
||||
ansiEscapes.eraseScreen = ESC + '2J';
|
||||
ansiEscapes.scrollUp = ESC + 'S';
|
||||
ansiEscapes.scrollDown = ESC + 'T';
|
||||
|
||||
ansiEscapes.clearScreen = '\u001Bc';
|
||||
|
||||
ansiEscapes.clearTerminal = process.platform === 'win32' ?
|
||||
`${ansiEscapes.eraseScreen}${ESC}0f` :
|
||||
// 1. Erases the screen (Only done in case `2` is not supported)
|
||||
// 2. Erases the whole screen including scrollback buffer
|
||||
// 3. Moves cursor to the top-left position
|
||||
// More info: https://www.real-world-systems.com/docs/ANSIcode.html
|
||||
`${ansiEscapes.eraseScreen}${ESC}3J${ESC}H`;
|
||||
|
||||
ansiEscapes.beep = BEL;
|
||||
|
||||
ansiEscapes.link = (text, url) => {
|
||||
return [
|
||||
OSC,
|
||||
'8',
|
||||
SEP,
|
||||
SEP,
|
||||
url,
|
||||
BEL,
|
||||
text,
|
||||
OSC,
|
||||
'8',
|
||||
SEP,
|
||||
SEP,
|
||||
BEL
|
||||
].join('');
|
||||
};
|
||||
|
||||
ansiEscapes.image = (buffer, options = {}) => {
|
||||
let ret = `${OSC}1337;File=inline=1`;
|
||||
|
||||
if (options.width) {
|
||||
ret += `;width=${options.width}`;
|
||||
}
|
||||
|
||||
if (options.height) {
|
||||
ret += `;height=${options.height}`;
|
||||
}
|
||||
|
||||
if (options.preserveAspectRatio === false) {
|
||||
ret += ';preserveAspectRatio=0';
|
||||
}
|
||||
|
||||
return ret + ':' + buffer.toString('base64') + BEL;
|
||||
};
|
||||
|
||||
ansiEscapes.iTerm = {
|
||||
setCwd: (cwd = process.cwd()) => `${OSC}50;CurrentDir=${cwd}${BEL}`,
|
||||
|
||||
annotation: (message, options = {}) => {
|
||||
let ret = `${OSC}1337;`;
|
||||
|
||||
const hasX = typeof options.x !== 'undefined';
|
||||
const hasY = typeof options.y !== 'undefined';
|
||||
if ((hasX || hasY) && !(hasX && hasY && typeof options.length !== 'undefined')) {
|
||||
throw new Error('`x`, `y` and `length` must be defined when `x` or `y` is defined');
|
||||
}
|
||||
|
||||
message = message.replace(/\|/g, '');
|
||||
|
||||
ret += options.isHidden ? 'AddHiddenAnnotation=' : 'AddAnnotation=';
|
||||
|
||||
if (options.length > 0) {
|
||||
ret +=
|
||||
(hasX ?
|
||||
[message, options.length, options.x, options.y] :
|
||||
[options.length, message]).join('|');
|
||||
} else {
|
||||
ret += message;
|
||||
}
|
||||
|
||||
return ret + BEL;
|
||||
}
|
||||
};
|
||||
142
extracted-source/node_modules/@inquirer/core/node_modules/mute-stream/lib/index.js
generated
vendored
Normal file
142
extracted-source/node_modules/@inquirer/core/node_modules/mute-stream/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
const Stream = require('stream')
|
||||
|
||||
class MuteStream extends Stream {
|
||||
#isTTY = null
|
||||
|
||||
constructor (opts = {}) {
|
||||
super(opts)
|
||||
this.writable = this.readable = true
|
||||
this.muted = false
|
||||
this.on('pipe', this._onpipe)
|
||||
this.replace = opts.replace
|
||||
|
||||
// For readline-type situations
|
||||
// This much at the start of a line being redrawn after a ctrl char
|
||||
// is seen (such as backspace) won't be redrawn as the replacement
|
||||
this._prompt = opts.prompt || null
|
||||
this._hadControl = false
|
||||
}
|
||||
|
||||
#destSrc (key, def) {
|
||||
if (this._dest) {
|
||||
return this._dest[key]
|
||||
}
|
||||
if (this._src) {
|
||||
return this._src[key]
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
#proxy (method, ...args) {
|
||||
if (typeof this._dest?.[method] === 'function') {
|
||||
this._dest[method](...args)
|
||||
}
|
||||
if (typeof this._src?.[method] === 'function') {
|
||||
this._src[method](...args)
|
||||
}
|
||||
}
|
||||
|
||||
get isTTY () {
|
||||
if (this.#isTTY !== null) {
|
||||
return this.#isTTY
|
||||
}
|
||||
return this.#destSrc('isTTY', false)
|
||||
}
|
||||
|
||||
// basically just get replace the getter/setter with a regular value
|
||||
set isTTY (val) {
|
||||
this.#isTTY = val
|
||||
}
|
||||
|
||||
get rows () {
|
||||
return this.#destSrc('rows')
|
||||
}
|
||||
|
||||
get columns () {
|
||||
return this.#destSrc('columns')
|
||||
}
|
||||
|
||||
mute () {
|
||||
this.muted = true
|
||||
}
|
||||
|
||||
unmute () {
|
||||
this.muted = false
|
||||
}
|
||||
|
||||
_onpipe (src) {
|
||||
this._src = src
|
||||
}
|
||||
|
||||
pipe (dest, options) {
|
||||
this._dest = dest
|
||||
return super.pipe(dest, options)
|
||||
}
|
||||
|
||||
pause () {
|
||||
if (this._src) {
|
||||
return this._src.pause()
|
||||
}
|
||||
}
|
||||
|
||||
resume () {
|
||||
if (this._src) {
|
||||
return this._src.resume()
|
||||
}
|
||||
}
|
||||
|
||||
write (c) {
|
||||
if (this.muted) {
|
||||
if (!this.replace) {
|
||||
return true
|
||||
}
|
||||
// eslint-disable-next-line no-control-regex
|
||||
if (c.match(/^\u001b/)) {
|
||||
if (c.indexOf(this._prompt) === 0) {
|
||||
c = c.slice(this._prompt.length)
|
||||
c = c.replace(/./g, this.replace)
|
||||
c = this._prompt + c
|
||||
}
|
||||
this._hadControl = true
|
||||
return this.emit('data', c)
|
||||
} else {
|
||||
if (this._prompt && this._hadControl &&
|
||||
c.indexOf(this._prompt) === 0) {
|
||||
this._hadControl = false
|
||||
this.emit('data', this._prompt)
|
||||
c = c.slice(this._prompt.length)
|
||||
}
|
||||
c = c.toString().replace(/./g, this.replace)
|
||||
}
|
||||
}
|
||||
this.emit('data', c)
|
||||
}
|
||||
|
||||
end (c) {
|
||||
if (this.muted) {
|
||||
if (c && this.replace) {
|
||||
c = c.toString().replace(/./g, this.replace)
|
||||
} else {
|
||||
c = null
|
||||
}
|
||||
}
|
||||
if (c) {
|
||||
this.emit('data', c)
|
||||
}
|
||||
this.emit('end')
|
||||
}
|
||||
|
||||
destroy (...args) {
|
||||
return this.#proxy('destroy', ...args)
|
||||
}
|
||||
|
||||
destroySoon (...args) {
|
||||
return this.#proxy('destroySoon', ...args)
|
||||
}
|
||||
|
||||
close (...args) {
|
||||
return this.#proxy('close', ...args)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MuteStream
|
||||
4
extracted-source/node_modules/@inquirer/core/node_modules/strip-ansi/index.js
generated
vendored
Normal file
4
extracted-source/node_modules/@inquirer/core/node_modules/strip-ansi/index.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
'use strict';
|
||||
const ansiRegex = require('ansi-regex');
|
||||
|
||||
module.exports = string => typeof string === 'string' ? string.replace(ansiRegex(), '') : string;
|
||||
10
extracted-source/node_modules/@inquirer/core/node_modules/strip-ansi/node_modules/ansi-regex/index.js
generated
vendored
Normal file
10
extracted-source/node_modules/@inquirer/core/node_modules/strip-ansi/node_modules/ansi-regex/index.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = ({onlyFirst = false} = {}) => {
|
||||
const pattern = [
|
||||
'[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
|
||||
'(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))'
|
||||
].join('|');
|
||||
|
||||
return new RegExp(pattern, onlyFirst ? undefined : 'g');
|
||||
};
|
||||
186
extracted-source/node_modules/@inquirer/core/node_modules/wrap-ansi/index.js
generated
vendored
Normal file
186
extracted-source/node_modules/@inquirer/core/node_modules/wrap-ansi/index.js
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
'use strict';
|
||||
const stringWidth = require('string-width');
|
||||
const stripAnsi = require('strip-ansi');
|
||||
const ansiStyles = require('ansi-styles');
|
||||
|
||||
const ESCAPES = new Set([
|
||||
'\u001B',
|
||||
'\u009B'
|
||||
]);
|
||||
|
||||
const END_CODE = 39;
|
||||
|
||||
const wrapAnsi = code => `${ESCAPES.values().next().value}[${code}m`;
|
||||
|
||||
// Calculate the length of words split on ' ', ignoring
|
||||
// the extra characters added by ansi escape codes
|
||||
const wordLengths = string => string.split(' ').map(character => stringWidth(character));
|
||||
|
||||
// Wrap a long word across multiple rows
|
||||
// Ansi escape codes do not count towards length
|
||||
const wrapWord = (rows, word, columns) => {
|
||||
const characters = [...word];
|
||||
|
||||
let isInsideEscape = false;
|
||||
let visible = stringWidth(stripAnsi(rows[rows.length - 1]));
|
||||
|
||||
for (const [index, character] of characters.entries()) {
|
||||
const characterLength = stringWidth(character);
|
||||
|
||||
if (visible + characterLength <= columns) {
|
||||
rows[rows.length - 1] += character;
|
||||
} else {
|
||||
rows.push(character);
|
||||
visible = 0;
|
||||
}
|
||||
|
||||
if (ESCAPES.has(character)) {
|
||||
isInsideEscape = true;
|
||||
} else if (isInsideEscape && character === 'm') {
|
||||
isInsideEscape = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isInsideEscape) {
|
||||
continue;
|
||||
}
|
||||
|
||||
visible += characterLength;
|
||||
|
||||
if (visible === columns && index < characters.length - 1) {
|
||||
rows.push('');
|
||||
visible = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// It's possible that the last row we copy over is only
|
||||
// ansi escape characters, handle this edge-case
|
||||
if (!visible && rows[rows.length - 1].length > 0 && rows.length > 1) {
|
||||
rows[rows.length - 2] += rows.pop();
|
||||
}
|
||||
};
|
||||
|
||||
// Trims spaces from a string ignoring invisible sequences
|
||||
const stringVisibleTrimSpacesRight = str => {
|
||||
const words = str.split(' ');
|
||||
let last = words.length;
|
||||
|
||||
while (last > 0) {
|
||||
if (stringWidth(words[last - 1]) > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
last--;
|
||||
}
|
||||
|
||||
if (last === words.length) {
|
||||
return str;
|
||||
}
|
||||
|
||||
return words.slice(0, last).join(' ') + words.slice(last).join('');
|
||||
};
|
||||
|
||||
// The wrap-ansi module can be invoked in either 'hard' or 'soft' wrap mode
|
||||
//
|
||||
// 'hard' will never allow a string to take up more than columns characters
|
||||
//
|
||||
// 'soft' allows long words to expand past the column length
|
||||
const exec = (string, columns, options = {}) => {
|
||||
if (options.trim !== false && string.trim() === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
let pre = '';
|
||||
let ret = '';
|
||||
let escapeCode;
|
||||
|
||||
const lengths = wordLengths(string);
|
||||
let rows = [''];
|
||||
|
||||
for (const [index, word] of string.split(' ').entries()) {
|
||||
if (options.trim !== false) {
|
||||
rows[rows.length - 1] = rows[rows.length - 1].trimLeft();
|
||||
}
|
||||
|
||||
let rowLength = stringWidth(rows[rows.length - 1]);
|
||||
|
||||
if (index !== 0) {
|
||||
if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
|
||||
// If we start with a new word but the current row length equals the length of the columns, add a new row
|
||||
rows.push('');
|
||||
rowLength = 0;
|
||||
}
|
||||
|
||||
if (rowLength > 0 || options.trim === false) {
|
||||
rows[rows.length - 1] += ' ';
|
||||
rowLength++;
|
||||
}
|
||||
}
|
||||
|
||||
// In 'hard' wrap mode, the length of a line is never allowed to extend past 'columns'
|
||||
if (options.hard && lengths[index] > columns) {
|
||||
const remainingColumns = (columns - rowLength);
|
||||
const breaksStartingThisLine = 1 + Math.floor((lengths[index] - remainingColumns - 1) / columns);
|
||||
const breaksStartingNextLine = Math.floor((lengths[index] - 1) / columns);
|
||||
if (breaksStartingNextLine < breaksStartingThisLine) {
|
||||
rows.push('');
|
||||
}
|
||||
|
||||
wrapWord(rows, word, columns);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rowLength + lengths[index] > columns && rowLength > 0 && lengths[index] > 0) {
|
||||
if (options.wordWrap === false && rowLength < columns) {
|
||||
wrapWord(rows, word, columns);
|
||||
continue;
|
||||
}
|
||||
|
||||
rows.push('');
|
||||
}
|
||||
|
||||
if (rowLength + lengths[index] > columns && options.wordWrap === false) {
|
||||
wrapWord(rows, word, columns);
|
||||
continue;
|
||||
}
|
||||
|
||||
rows[rows.length - 1] += word;
|
||||
}
|
||||
|
||||
if (options.trim !== false) {
|
||||
rows = rows.map(stringVisibleTrimSpacesRight);
|
||||
}
|
||||
|
||||
pre = rows.join('\n');
|
||||
|
||||
for (const [index, character] of [...pre].entries()) {
|
||||
ret += character;
|
||||
|
||||
if (ESCAPES.has(character)) {
|
||||
const code = parseFloat(/\d[^m]*/.exec(pre.slice(index, index + 4)));
|
||||
escapeCode = code === END_CODE ? null : code;
|
||||
}
|
||||
|
||||
const code = ansiStyles.codes.get(Number(escapeCode));
|
||||
|
||||
if (escapeCode && code) {
|
||||
if (pre[index + 1] === '\n') {
|
||||
ret += wrapAnsi(code);
|
||||
} else if (character === '\n') {
|
||||
ret += wrapAnsi(escapeCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
// For each newline, invoke the method separately
|
||||
module.exports = (string, columns, options) => {
|
||||
return String(string)
|
||||
.normalize()
|
||||
.replace(/\r\n/g, '\n')
|
||||
.split('\n')
|
||||
.map(line => exec(line, columns, options))
|
||||
.join('\n');
|
||||
};
|
||||
163
extracted-source/node_modules/@inquirer/core/node_modules/wrap-ansi/node_modules/ansi-styles/index.js
generated
vendored
Normal file
163
extracted-source/node_modules/@inquirer/core/node_modules/wrap-ansi/node_modules/ansi-styles/index.js
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
'use strict';
|
||||
|
||||
const wrapAnsi16 = (fn, offset) => (...args) => {
|
||||
const code = fn(...args);
|
||||
return `\u001B[${code + offset}m`;
|
||||
};
|
||||
|
||||
const wrapAnsi256 = (fn, offset) => (...args) => {
|
||||
const code = fn(...args);
|
||||
return `\u001B[${38 + offset};5;${code}m`;
|
||||
};
|
||||
|
||||
const wrapAnsi16m = (fn, offset) => (...args) => {
|
||||
const rgb = fn(...args);
|
||||
return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`;
|
||||
};
|
||||
|
||||
const ansi2ansi = n => n;
|
||||
const rgb2rgb = (r, g, b) => [r, g, b];
|
||||
|
||||
const setLazyProperty = (object, property, get) => {
|
||||
Object.defineProperty(object, property, {
|
||||
get: () => {
|
||||
const value = get();
|
||||
|
||||
Object.defineProperty(object, property, {
|
||||
value,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
|
||||
return value;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
};
|
||||
|
||||
/** @type {typeof import('color-convert')} */
|
||||
let colorConvert;
|
||||
const makeDynamicStyles = (wrap, targetSpace, identity, isBackground) => {
|
||||
if (colorConvert === undefined) {
|
||||
colorConvert = require('color-convert');
|
||||
}
|
||||
|
||||
const offset = isBackground ? 10 : 0;
|
||||
const styles = {};
|
||||
|
||||
for (const [sourceSpace, suite] of Object.entries(colorConvert)) {
|
||||
const name = sourceSpace === 'ansi16' ? 'ansi' : sourceSpace;
|
||||
if (sourceSpace === targetSpace) {
|
||||
styles[name] = wrap(identity, offset);
|
||||
} else if (typeof suite === 'object') {
|
||||
styles[name] = wrap(suite[targetSpace], offset);
|
||||
}
|
||||
}
|
||||
|
||||
return styles;
|
||||
};
|
||||
|
||||
function assembleStyles() {
|
||||
const codes = new Map();
|
||||
const styles = {
|
||||
modifier: {
|
||||
reset: [0, 0],
|
||||
// 21 isn't widely supported and 22 does the same thing
|
||||
bold: [1, 22],
|
||||
dim: [2, 22],
|
||||
italic: [3, 23],
|
||||
underline: [4, 24],
|
||||
inverse: [7, 27],
|
||||
hidden: [8, 28],
|
||||
strikethrough: [9, 29]
|
||||
},
|
||||
color: {
|
||||
black: [30, 39],
|
||||
red: [31, 39],
|
||||
green: [32, 39],
|
||||
yellow: [33, 39],
|
||||
blue: [34, 39],
|
||||
magenta: [35, 39],
|
||||
cyan: [36, 39],
|
||||
white: [37, 39],
|
||||
|
||||
// Bright color
|
||||
blackBright: [90, 39],
|
||||
redBright: [91, 39],
|
||||
greenBright: [92, 39],
|
||||
yellowBright: [93, 39],
|
||||
blueBright: [94, 39],
|
||||
magentaBright: [95, 39],
|
||||
cyanBright: [96, 39],
|
||||
whiteBright: [97, 39]
|
||||
},
|
||||
bgColor: {
|
||||
bgBlack: [40, 49],
|
||||
bgRed: [41, 49],
|
||||
bgGreen: [42, 49],
|
||||
bgYellow: [43, 49],
|
||||
bgBlue: [44, 49],
|
||||
bgMagenta: [45, 49],
|
||||
bgCyan: [46, 49],
|
||||
bgWhite: [47, 49],
|
||||
|
||||
// Bright color
|
||||
bgBlackBright: [100, 49],
|
||||
bgRedBright: [101, 49],
|
||||
bgGreenBright: [102, 49],
|
||||
bgYellowBright: [103, 49],
|
||||
bgBlueBright: [104, 49],
|
||||
bgMagentaBright: [105, 49],
|
||||
bgCyanBright: [106, 49],
|
||||
bgWhiteBright: [107, 49]
|
||||
}
|
||||
};
|
||||
|
||||
// Alias bright black as gray (and grey)
|
||||
styles.color.gray = styles.color.blackBright;
|
||||
styles.bgColor.bgGray = styles.bgColor.bgBlackBright;
|
||||
styles.color.grey = styles.color.blackBright;
|
||||
styles.bgColor.bgGrey = styles.bgColor.bgBlackBright;
|
||||
|
||||
for (const [groupName, group] of Object.entries(styles)) {
|
||||
for (const [styleName, style] of Object.entries(group)) {
|
||||
styles[styleName] = {
|
||||
open: `\u001B[${style[0]}m`,
|
||||
close: `\u001B[${style[1]}m`
|
||||
};
|
||||
|
||||
group[styleName] = styles[styleName];
|
||||
|
||||
codes.set(style[0], style[1]);
|
||||
}
|
||||
|
||||
Object.defineProperty(styles, groupName, {
|
||||
value: group,
|
||||
enumerable: false
|
||||
});
|
||||
}
|
||||
|
||||
Object.defineProperty(styles, 'codes', {
|
||||
value: codes,
|
||||
enumerable: false
|
||||
});
|
||||
|
||||
styles.color.close = '\u001B[39m';
|
||||
styles.bgColor.close = '\u001B[49m';
|
||||
|
||||
setLazyProperty(styles.color, 'ansi', () => makeDynamicStyles(wrapAnsi16, 'ansi16', ansi2ansi, false));
|
||||
setLazyProperty(styles.color, 'ansi256', () => makeDynamicStyles(wrapAnsi256, 'ansi256', ansi2ansi, false));
|
||||
setLazyProperty(styles.color, 'ansi16m', () => makeDynamicStyles(wrapAnsi16m, 'rgb', rgb2rgb, false));
|
||||
setLazyProperty(styles.bgColor, 'ansi', () => makeDynamicStyles(wrapAnsi16, 'ansi16', ansi2ansi, true));
|
||||
setLazyProperty(styles.bgColor, 'ansi256', () => makeDynamicStyles(wrapAnsi256, 'ansi256', ansi2ansi, true));
|
||||
setLazyProperty(styles.bgColor, 'ansi16m', () => makeDynamicStyles(wrapAnsi16m, 'rgb', rgb2rgb, true));
|
||||
|
||||
return styles;
|
||||
}
|
||||
|
||||
// Make the export immutable
|
||||
Object.defineProperty(module, 'exports', {
|
||||
enumerable: true,
|
||||
get: assembleStyles
|
||||
});
|
||||
Reference in New Issue
Block a user